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模型对象

1
model = VAE_model()

创建train_loss_results列表

1
train_loss_results = []

设置epochs

1
num_epochs = 30

训练

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
test_mu.shape
(100, 20)

编码

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')