import tensorflow as tf import numpy as np import matplotlib.pyplot as plt %matplotlib inline
加载手写数据集 1 (train_image,_),_ = tf.keras.datasets.mnist.load_data()
模型架构 1.编码器 -> u,var
2.u,var -> 隐含变量
3.隐含变量 -> 重构图像
数据归一化 1 train_image = train_image/255
数据shape 1 2 train_image.shape (60000, 28, 28)
数据扁平化 1 train_image = train_image.reshape(-1,28*28)#扁平化
数据shape 1 2 train_image.shape (60000, 784)
转换数据类型 1 train_image = train_image.astype(np.float32)#转换类型
创建dataset 1 dataset = tf.data.Dataset.from_tensor_slices(train_image)
数据shuffle,batch 1 dataset = dataset.shuffle(len(dataset)).batch(128)
创建VAE模型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class VAE_model(tf.keras.Model): def __init__(self): super(VAE_model,self).__init__() self.lin_1 = tf.keras.layers.Dense(400)#784取中间值 self.lin_2 = tf.keras.layers.Dense(20) self.lin_3 = tf.keras.layers.Dense(20) self.lin_4 = tf.keras.layers.Dense(400) self.lin_5 = tf.keras.layers.Dense(784) def encode(self,x):# 编码器 h1 = tf.nn.relu(self.lin_1(x)) return self.lin_2(h1),self.lin_3(h1) # u ,log(var*var)方差的对数 def reparameters(self,mu,logvar): std = tf.math.exp(0.5*logvar)#幂运算 e的幂运算 exp() 方法返回x的指数,ex eps = tf.random.normal(std.shape,mean=0.0,stddev=1.0)#默认生成标准正态分布 return eps*std + mu#均值为mu 方差为std的正态分布 def decode(self,z): h4 = tf.nn.relu(self.lin_4(z))#得到解码器的中间变量 return tf.sigmoid(self.lin_5(h4))#输入图像取值范围0~1,所以输出图像要0~1即sigmoid激活 def call(self,x): mu,logvar = self.encode(x)#对输入进行编码得到mu、logvar z = self.reparameters(mu,logvar)#得到隐含变量z return self.decode(z),mu,logvar# 进行界面
exp() 方法返回x的指数:$$e^x$$
创建损失函数 1 2 3 4 def loss_fn(recon_x,x,mu,logvar): BCE_loss = tf.keras.losses.binary_crossentropy(x,recon_x)#计算逻辑回归损失值,交叉熵损失 KLD_loss = -0.5*tf.reduce_sum(1 + logvar - tf.pow(mu,2) - tf.exp(logvar)) return BCE_loss+0.0001*KLD_loss #BCE_loss重建损失,比重大生成图像接近原图越清晰 KLD_loss 越大越接近正态分布损失,生产效果越差
创建optimizers 1 opt = tf.optimizers.Adam(learning_rate=0.0001)
创建metrics.Mean 1 epoch_loss_avg = tf.keras.metrics.Mean('train_loss')
设置训练每步 1 2 3 4 5 6 7 8 def train_step(model,images): with tf.GradientTape() as t: pred_img,mu,logvar = model(images) loss_step = loss_fn(pred_img,images,mu,logvar)#计算预测与真实值之间的交叉熵 参数:(正确,预测) from_logits默认为False,输出没有激活则True grads = t.gradient(loss_step,model.trainable_variables)#t.gradient:梯度(计算损失值与可训练参数之间的梯度) 参数:(loss,可训练参数) opt.apply_gradients(zip(grads,model.trainable_variables))#根据计算损失值与可训练参数之间的梯度来优化可训练参数 epoch_loss_avg(loss_step) return pred_img
模型训练 创建VAE模型对象
创建train_loss_results列表
设置epochs
训练 1 2 3 4 5 6 7 8 9 10 11 12 13 14 for epoch in range(num_epochs): for imgs in dataset: gen_imgs = train_step(model,imgs) print(epoch) train_loss_results.append(epoch_loss_avg.result()) print('Epoch:{}:loss:{:.3f}'.format(epoch+1,epoch_loss_avg.result())) epoch_loss_avg.reset_states() for i in range(64): plt.subplot(8,8,i+1) plt.imshow(gen_imgs[i].numpy().reshape(28,28),cmap='gray') plt.xticks([]) plt.yticks([]) plt.axis=('off') plt.show()
应用VAE 随机生成数据 1 2 test_mu = np.linspace(-0.9,0.9,2000).reshape(100,20).astype(np.float32)#随机生成[-0.9~0.9]的2000条数据 test_logvar = np.linspace(-0.9,0.9,2000).reshape(100,20).astype(np.float32)
编码 1 2 3 4 test_img = model.decode(model.reparameters(test_mu,test_logvar)) test_img.shape #TensorShape([100, 784]) test_img = test_img.numpy().reshape(-1,28,28) test_img.shape #(100, 28, 28)
绘制图片 1 2 3 4 5 6 7 plt.figure(figsize=(6,6)) for i in range(100): plt.subplot(10,10,i+1) plt.imshow(test_img[i],cmap='gray') plt.xticks([]) plt.yticks([]) plt.axis=('off')