VAE代码-全连接-fashion mnist

import numpy as np
import tensorflow as tf

import tensorflow.keras as keras
import tensorflow.keras.layers as layers
import tensorflow.keras.optimizers as optimizers
import tensorflow.keras.metrics as metrics
import tensorflow.keras.datasets as datasets
from tensorflow.keras import Sequential

import matplotlib.pyplot as plt
from PIL import Image
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pandas as pd
import os



tf.random.set_seed(22)
np.random.seed(22)
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
assert tf.__version__.startswith('2.')

#保存一张画布-画布中图片的数量可自行设置
def save_images(imgs, name):
    #设置画布大小-控制要可视化的结果图片的数量
    new_im = Image.new('L', (448, 896))
    #遍历输入图片的索引
    index = 0
    #将图片填入画布(i,j)代表位置
    for i in range(0, 448, 28):
        for j in range(0,896, 28):
            #选取图片
            im = imgs[index]
            #将张量转换成图片
            im = Image.fromarray(im, mode='L')
            #放入画布中的位置
            new_im.paste(im, (i, j))
            #继续遍历下一张图片
            index += 1
    #保存到本地,name为文件名
    new_im.save(name)

batchsz = 512
lr = 1e-3
#均值和方差向量长度-提取内部特征的个数-10就相当于从训练集中提取10个内部特征
z_dim = 10
#加载数据集
(x_train, y_train), (x_test, y_test) = keras.datasets.fashion_mnist.load_data()
#查看返回的对象:numpy.ndarray
print('x_train type:\n',type(x_train))
#查看返回的对象形状:(60000,28,28)-60000张训练图片 单通道
print('x_train shape:\n',x_train.shape)
#用numpy转换数据类型并归一化
x_train, x_test = x_train.astype(np.float32) / 255., x_test.astype(np.float32) / 255.
#构建数据集对象-只用到特征值不用标签
train_db = tf.data.Dataset.from_tensor_slices(x_train)
#随机打散+批训练
train_db = train_db.shuffle(batchsz * 5).batch(batchsz)
test_db = tf.data.Dataset.from_tensor_slices(x_test)
test_db = test_db.batch(batchsz)


class VAE(keras.Model):

    def __init__(self):
        super(VAE, self).__init__()

        # Encoder
        self.fc1 = layers.Dense(128)
        self.fc2 = layers.Dense(z_dim) # get mean prediction
        self.fc3 = layers.Dense(z_dim)

        # Decoder
        self.fc4 = layers.Dense(128)
        self.fc5 = layers.Dense(784)

    def encoder(self, x):

        h = tf.nn.relu(self.fc1(x))
        print('公共层输出的形状:\n',h.shape)
        # get mean
        mu = self.fc2(h)
        print('均值的形状:\n',mu.shape)
        print('均值的值:\n',mu)
        # get variance
        log_var = self.fc3(h)
        print('方差的形状:\n',log_var.shape)
        print('方差的值:\n',log_var)
        return mu, log_var

    def decoder(self, z):

        out = tf.nn.relu(self.fc4(z))
        print('解码器第一层经过relu后的形状:\n',out.shape)
        print('解码器第一层经过relu后的值:\n',out)
        out = self.fc5(out)
        print('解码器第二层输出的形状:\n',out.shape)
        print('解码器第二层输出的值:\n',out)
        return out

    def reparameterize(self, mu, log_var):
        #获取标准正太分布
        eps = tf.random.normal(log_var.shape)
        print('标准正态分布的形状:\n',eps.shape)
        print('标准正态分布的值:\n',eps)

        std = tf.exp(log_var*0.5)
        print('重参数后的方差形状:\n',std.shape)
        print('重参数后的方差值:\n',std)
        z = mu + std * eps
        print('重参数后的z的形状:\n',z.shape)
        print('重参数后的z的值:\n',z)
        return z

    def call(self, inputs, training=None):

        # [b, 784] => [b, z_dim], [b, z_dim]
        mu, log_var = self.encoder(inputs)
        # reparameterization trick
        z = self.reparameterize(mu, log_var)

        x_hat = self.decoder(z)

        return x_hat, mu, log_var


model = VAE()
model.build(input_shape=(4, 784))
optimizer = keras.optimizers.Adam(lr)

for epoch in range(1):

    for step, x in enumerate(train_db):
        #将一个batch展平:(512,28,28)->(512,784)
        x = tf.reshape(x, [-1, 784])
        #创建梯度环境
        with tf.GradientTape() as tape:
            #获得重建样本 均值和方差 每个样本都对应一个均值和方差向量 长度都为10 重建损失也是一个样本一个样本计算的,最后在 整个batch上计算重建损失的平均值以及每个样本KL散度的平均值

            x_rec_logits, mu, log_var = model(x)
            #重建损失
            rec_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=x, logits=x_rec_logits)
            rec_loss = tf.reduce_sum(rec_loss) / x.shape[0]

            # compute kl divergence (mu, var) ~ N (0, 1)
            # https://stats.stackexchange.com/questions/7440/kl-divergence-between-two-univariate-gaussians
            kl_div = -0.5 * (log_var + 1 - mu**2 - tf.exp(log_var))
            kl_div = tf.reduce_sum(kl_div) / x.shape[0]
            #总loss
            loss = rec_loss + 1. * kl_div
        #计算梯度
        grads = tape.gradient(loss, model.trainable_variables)
        #更新梯度
        optimizer.apply_gradients(zip(grads, model.trainable_variables))

        #每10个step输出信息
        if step % 10 == 0:
            print(epoch, step, 'kl div:', float(kl_div), 'rec loss:', float(rec_loss))
#-----------------每一次epoch训练后都测试一次----------------、
    #用测试测试集测试-只测试一个batch的数据-512张图片-分布到32*16的画布上 注意训练时一个epoch的所有batch都参与训练 测试时只选取了测试数据集10000/512->向上取整=20个batch中的其中一个
    #用测试集是获取模型的最终输出,其中会有用重参数化采样隐变量z的中间过程,都封装在整个模型中的前向传播中了,下面那个方法是直接从标准正太分布中采样隐变量,它完全空白的,而测试集有了一个编码器生成隐变量的过程,相当于训练得到了正确的和原始数据对应的内部特征分布,所以重参数采样它采样到的到部分是正确的特征,所以恢复(重建)的图片和原始图片是相近的
    x = next(iter(test_db))
    x = tf.reshape(x, [-1, 784])
    x_hat_logits, _, _ = model(x)
    x_hat = tf.sigmoid(x_hat_logits)
    x_hat = tf.reshape(x_hat, [-1, 28, 28]).numpy() * 255.
    x_hat = x_hat.astype(np.uint8)
    save_images(x_hat, 'vae_images2/rec_epoch%d.png' % epoch)
#从正态分布中直接采样,直接使用生成模型生成样本、

    # evaluation
    z = tf.random.normal((batchsz, z_dim))
    logits = model.decoder(z)
    x_hat = tf.sigmoid(logits)
    #恢复形状和反归一化
    x_hat = tf.reshape(x_hat, [-1, 28, 28]).numpy() *255.
    #恢复整型数据类型
    x_hat = x_hat.astype(np.uint8)
    #保存
    save_images(x_hat, 'vae_images2/sampled_epoch%d.png'%epoch)




print语句可以忽略

测试集重建图片:

epoch0

epoch10

epoch100

epoch199

 

生成图片:

epoch10

epoch100

epoch199

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值