无监督学习是机器学习的重要分支,其目标是从未标注的数据中发现模式和结构。生成模型是无监督学习的一种方法,它试图捕捉数据的分布,并生成类似的样本。在这篇文章中,我们将探讨Python中无监督生成模型的概念、方法和实现,并展示一些示例代码。
一、无监督生成模型概述
无监督生成模型通过学习数据的分布,能够生成与训练数据相似的新样本。常见的无监督生成模型包括:
- 生成对抗网络(GANs)
- 变分自编码器(VAEs)
- 自回归模型(Autoregressive Models)
1. 生成对抗网络(GANs)
GANs由生成器(Generator)和判别器(Discriminator)组成,两个网络通过对抗训练,共同进步。生成器试图生成逼真的样本,而判别器则试图区分真实样本和生成样本。
2. 变分自编码器(VAEs)
VAEs通过编码器将数据编码到潜在空间,再通过解码器从潜在空间重建数据。VAE的目标是最大化似然函数,同时最小化潜在变量的分布与标准正态分布的KL散度。
3. 自回归模型
自回归模型通过将每个数据点作为条件生成下一个数据点来建模整个数据分布。常见的自回归模型有PixelRNN、PixelCNN等。
二、生成对抗网络(GANs)实现
以下是一个使用TensorFlow实现简单GAN的示例代码,该GAN生成MNIST手写数字。
1. 导入库
import tensorflow as tf
from tensorflow.keras.layers import Dense, Reshape, Flatten, LeakyReLU, BatchNormalization
from tensorflow.keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt
2. 数据预处理
(x_train, _), (_, _) = mnist.load_data()
x_train = x_train / 127.5 - 1.0 # Normalize to [-1, 1]
x_train = np.expand_dims(x_train, axis=-1)
3. 构建生成器
def build_generator():
model = tf.keras.Sequential()
model.add(Dense(256, input_dim=100))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
model.add(Dense(512))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
model.add(Dense(1024))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
model.add(Dense(28 * 28 * 1, activation='tanh'))
model.add(Reshape((28, 28, 1)))
return model
4. 构建判别器
def build_discriminator():
model = tf.keras.Sequential()
model.add(Flatten(input_shape=(28, 28, 1)))
model.add(Dense(512))
model.add(LeakyReLU(alpha=0.2))
model.add(Dense(256))
model.add(LeakyReLU(alpha=0.2))
model.add(Dense(1, activation='sigmoid'))
return model
5. 编译模型
def compile_gan(generator, discriminator):
discriminator.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
discriminator.trainable = False
gan_input = tf.keras.Input(shape=(100,))
generated_image = generator(gan_input)
gan_output = discriminator(generated_image)
gan = tf.keras.Model(gan_input, gan_output)
gan.compile(loss='binary_crossentropy', optimizer='adam')
return gan
6. 训练模型
def train_gan(generator, discriminator, gan, epochs, batch_size=128):
(x_train, _), (_, _) = mnist.load_data()
x_train = (x_train.astype(np.float32) - 127.5) / 127.5
x_train = np.expand_dims(x_train, axis=-1)
valid = np.ones((batch_size, 1))
fake = np.zeros((batch_size, 1))
for epoch in range(epochs):
idx = np.random.randint(0, x_train.shape[0], batch_size)
real_images = x_train[idx]
noise = np.random.normal(0, 1, (batch_size, 100))
generated_images = generator.predict(noise)
d_loss_real = discriminator.train_on_batch(real_images, valid)
d_loss_fake = discriminator.train_on_batch(generated_images, fake)
d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)
noise = np.random.normal(0, 1, (batch_size, 100))
g_loss = gan.train_on_batch(noise, valid)
if epoch % 1000 == 0:
print(f"{epoch} [D loss: {d_loss[0]} | D accuracy: {d_loss[1]}] [G loss: {g_loss}]")
save_images(generator, epoch)
def save_images(generator, epoch, examples=100, dim=(10, 10), figsize=(10, 10)):
noise = np.random.normal(0, 1, (examples, 100))
generated_images = generator.predict(noise)
generated_images = 0.5 * generated_images + 0.5
plt.figure(figsize=figsize)
for i in range(examples):
plt.subplot(dim[0], dim[1], i+1)
plt.imshow(generated_images[i, :, :, 0], cmap='gray')
plt.axis('off')
plt.tight_layout()
plt.savefig(f"gan_generated_image_epoch_{epoch}.png")
plt.close()
7. 主函数
if __name__ == "__main__":
generator = build_generator()
discriminator = build_discriminator()
gan = compile_gan(generator, discriminator)
train_gan(generator, discriminator, gan, epochs=10000, batch_size=64)
三、变分自编码器(VAEs)实现
以下是一个使用TensorFlow实现简单VAE的示例代码,该VAE重建MNIST手写数字。
1. 导入库
import tensorflow as tf
from tensorflow.keras.layers import Dense, Flatten, Reshape, Input, Lambda
from tensorflow.keras.models import Model
from tensorflow.keras.losses import binary_crossentropy
from tensorflow.keras import backend as K
import numpy as np
2. 数据预处理
(x_train, _), (x_test, _) = tf.keras.datasets.mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
3. 构建编码器和解码器
latent_dim = 2
def sampling(args):
z_mean, z_log_var = args
batch = K.shape(z_mean)[0]
dim = K.int_shape(z_mean)[1]
epsilon = K.random_normal(shape=(batch, dim))
return z_mean + K.exp(0.5 * z_log_var) * epsilon
inputs = Input(shape=(28, 28, 1), name='encoder_input')
x = Flatten()(inputs)
x = Dense(512, activation='relu')(x)
x = Dense(256, activation='relu')(x)
z_mean = Dense(latent_dim, name='z_mean')(x)
z_log_var = Dense(latent_dim, name='z_log_var')(x)
z = Lambda(sampling, output_shape=(latent_dim,), name='z')([z_mean, z_log_var])
encoder = Model(inputs, [z_mean, z_log_var, z], name='encoder')
latent_inputs = Input(shape=(latent_dim,), name='z_sampling')
x = Dense(256, activation='relu')(latent_inputs)
x = Dense(512, activation='relu')(x)
x = Dense(28 * 28, activation='sigmoid')(x)
outputs = Reshape((28, 28, 1))(x)
decoder = Model(latent_inputs, outputs, name='decoder')
outputs = decoder(encoder(inputs)[2])
vae = Model(inputs, outputs, name='vae_mlp')
4. 定义VAE的损失函数
reconstruction_loss = binary_crossentropy(K.flatten(inputs), K.flatten(outputs))
reconstruction_loss *= 28 * 28
kl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)
kl_loss = K.sum(kl_loss, axis=-1)
kl_loss *= -0.5
vae_loss = K.mean(reconstruction_loss + kl_loss)
vae.add_loss(vae_loss)
vae.compile(optimizer='adam')
5. 训练模型
vae.fit(x
_train, epochs=50, batch_size=128, validation_data=(x_test, None))
6. 生成新样本
import matplotlib.pyplot as plt
def plot_results(models, data, batch_size=128, model_name="vae_mnist"):
encoder, decoder = models
x_test, y_test = data
z_mean, _, _ = encoder.predict(x_test, batch_size=batch_size)
plt.figure(figsize=(12, 10))
plt.scatter(z_mean[:, 0], z_mean[:, 1], c=y_test)
plt.colorbar()
plt.xlabel("z[0]")
plt.ylabel("z[1]")
plt.show()
n = 15
digit_size = 28
figure = np.zeros((digit_size * n, digit_size * n))
grid_x = np.linspace(-4, 4, n)
grid_y = np.linspace(-4, 4, n)[::-1]
for i, yi in enumerate(grid_y):
for j, xi in enumerate(grid_x):
z_sample = np.array([[xi, yi]])
x_decoded = decoder.predict(z_sample)
digit = x_decoded[0].reshape(digit_size, digit_size)
figure[i * digit_size: (i + 1) * digit_size,
j * digit_size: (j + 1) * digit_size] = digit
plt.figure(figsize=(10, 10))
plt.imshow(figure, cmap='Greys_r')
plt.show()
plot_results((encoder, decoder), (x_test, _))
四、总结
无监督生成模型在无标签数据的处理中具有重要意义。通过GANs和VAEs等模型,我们可以生成与训练数据类似的新样本,并在许多应用中取得了显著效果。本文展示了如何在Python中实现这些模型,并提供了相关的代码示例,希望能对读者有所帮助。