Tensorflow自编码器入门:图片重建FashionMINIST

25 篇文章 0 订阅
7 篇文章 1 订阅

数据集 :FashionMNIST数据集,包含10种不同类型的衣服、鞋子、包等灰度图片,图片大小为28*28.其中有60000张训练集,10000张测试集。

加载FashionMINST数据集

利用keras.datasets.fashion_mnist.load_data()可以下载FashionMINST数据集:

from tensorflow import keras
import numpy as np
import tensorflow as tf
import os   
os.environ["TF_CPP_MIN_LOG_LEVEL"]='2'


batchsz = 50
#下载FashionMINST数据集
(x_train, y_train), (x_test, y_test) = keras.datasets.fashion_mnist.load_data()
#归一化
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)

构建自编码网络(AE)

编码网络encoder和解码网络decoder分别由三层全连接构成;节点数分别为encoder(256,128,20)和decoder(128,256,784),其中784是将输入的28*28图片打平成列向量的长度。

class AE(Model):
    def __init__(self):
        super(AE, self).__init__()
        #创建Encoder网络
        self.encoder = Sequential([
            Dense(256, activation=tf.nn.relu),
            Dense(128, activation=tf.nn.relu),
            Dense(20)
        ])
        #创建Decoder网络
        self.decoder = Sequential([
            Dense(128, activation=tf.nn.relu),
            Dense(256, activation=tf.nn.relu),
            Dense(784)
        ])
    def call(self, inputs, training=None, mask=None):
        #前向传播函数
        #编码获得隐藏向量h,其中[b, 784]->[b, 20]
        h = self.encoder(inputs)
        #解码获得重建图片x_hat,其中[b, 20]->[b, 784]
        x_hat = self.decoder(h)
        return x_hat

训练AE

优化器:Adam,学习率:0.01;
损失函数:tf.nn.sigmoid_cross_entropy_with_logits()

if __name__=="__main__":
	#创建网络对象
    model = AE()
    #指定输入大小
    model.build(input_shape = (4, 784))
    #打印网络信息
    model.summary()
    #创建优化器,此处学习率lr=0.01
    optimizer = optimizers.Adam(lr=0.01)
    for epoch in range(10):                        # 训练
        for step, x in enumerate(train_db):
            #输入图片拉成一个向量(打平),[b, 28*28]->[b, 784]
            x = tf.reshape(x, [-1, 784])
            #构建梯度记录器
            with tf.GradientTape() as tape:
                #前向计算获得重建的图片
                x_rec_logits = model(x)
                #计算重建图片与输入之间的损失函数
                rec_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=x, logits=x_rec_logits)
                #计算均值
                rec_loss = tf.reduce_mean(rec_loss)
            #自动求导2个子网络的梯度
            grads = tape.gradient(rec_loss, model.trainable_variables)
			#自动跟新,更新两个自网络的参数
            optimizer.apply_gradients(zip(grads, model.trainable_variables))
			#每隔100次打印一次训练误差
            if step & 100 == 0:
                print(epoch, step, float(rec_loss))

测试AE:重建图片

测试集选择50张图片进行重建。

	#重建图片,从测试集采样一批图片
	x = next(iter(test_db))                # 测试
    #图片拉成列向量送入AE进行重建
    logits = model(tf.reshape(x, [-1, 784]))
    #将输出转换为像素值,使用sigmoid函数
    x_hat = tf.sigmoid(logits)
    #将列向量reshape成图片
    x_hat = tf.reshape(x_hat, [-1, 28, 28])
    #拼接前50张原图+重建的前50张原图
    x_concat = tf.concat([x[:50], x_hat[:50]], axis=0)
    #恢复为0~255
    x_concat = x_concat.numpy()*255.
    #转换为整型
    x_concat = x_concat.astype(np.uint8)
    #保存图片
    save_images(x_concat, 'ae_images/dense_rec_epoch_%d.png' % epoch)

其中save_images()函数如下:

from PIL import Image
import numpy as np

def save_images(imgs, name):
    new_im = Image.new('L', (280, 280))
    index = 0
    for i in range(0, 280, 28):
        for j in range(0, 280, 28):
            im = imgs[index]
            im = Image.fromarray(im, mode='L')
            new_im.paste(im, (i, j))
            index += 1
    new_im.save(name)

重建结果

左侧五列为原始图片,右侧五列为重建图片。
在这里插入图片描述
上面是将原始图像拉成一个列向量进行训练和测试,下面采用原始图像进行训练和测试

构建卷积自编码

编码网络和解码网络分别采用三层卷积层的操作,进行网络构建。

class AE(Model):
    def __init__(self):
        super(AE, self).__init__()
        self.encoder = Sequential([
            Conv2D(filters=3, kernel_size=3, padding='same', activation=relu),
            Conv2D(filters=6, kernel_size=3, padding='same', activation=relu),
            Conv2D(filters=9, kernel_size=3, padding='same')
        ])
        self.decoder = Sequential([
            Conv2D(filters=6, kernel_size=3, padding='same', activation=relu),
            Conv2D(filters=3, kernel_size=3, padding='same', activation=relu),
            Conv2D(filters=1, kernel_size=3, padding='same')
        ])
    def call(self, inputs, training=None, mask=None):
        h = self.encoder(inputs)
        output = self.decoder(h)
        return output

训练卷积自编码

直接输入图片,不用拉伸为列向量。

if __name__=="__main__":
    model = AE()
    optimizer = optimizers.Adam(lr=0.01)
    for epoch in range(2):                        # 训练
        for step, x in enumerate(train_db):
            x = np.expand_dims(x, axis=-1)

            with tf.GradientTape() as tape:
                x_rec_logits = model(x)
                rec_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=x, logits=x_rec_logits)
                rec_loss = tf.reduce_mean(rec_loss)
            grads = tape.gradient(rec_loss, model.trainable_variables)

            optimizer.apply_gradients(zip(grads, model.trainable_variables))

            if step & 100 == 0:
                print(epoch, step, float(rec_loss))

测试卷积AE:重建图片

x = next(iter(test_db))                         # 测试
    x = np.expand_dims(x, axis=-1)
    logits = model(x)
    x, logits = np.squeeze(x), np.squeeze(logits)
    x_hat = tf.sigmoid(logits)
    x_concat = tf.concat([x[:50], x_hat[:50]], axis=0)
    x_concat = x_concat.numpy()*255.
    x_concat = x_concat.astype(np.uint8)
    save_images(x_concat, 'ae_images/cnn_rec_epoch_%d.png' % epoch)

两种自编码的方式略有不同,仅供参考。
参考书籍:《TensorFlow深度学习——深入理解人工智能算法设计》 作者:龙良曲

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
正则自编码器是一种基于正则化的自编码器,它在自编码器的基础上加入了正则化项以控制模型的复杂度,从而避免过拟合。在tensorflow中,可以通过定义损失函数来实现正则自编码器。 下面是一个简单的正则自编码器tensorflow实现: ```python import tensorflow as tf # 定义输入数据维度 input_dim = 784 # 定义隐藏层维度 hidden_dim = 128 # 定义正则化系数 lambda_reg = 0.01 # 定义输入数据占位符 input_x = tf.placeholder(dtype=tf.float32, shape=[None, input_dim], name='input_x') # 定义编码器 encoder = tf.layers.dense(inputs=input_x, units=hidden_dim, activation=tf.nn.relu) # 定义解码器 decoder = tf.layers.dense(inputs=encoder, units=input_dim, activation=tf.nn.sigmoid) # 定义重构误差 reconstruction_loss = tf.reduce_mean(tf.square(input_x - decoder)) # 定义正则化项 regularization_loss = tf.reduce_sum(tf.abs(encoder)) # 定义总损失 total_loss = reconstruction_loss + lambda_reg * regularization_loss # 定义优化器 optimizer = tf.train.AdamOptimizer(learning_rate=0.001) # 定义训练操作 train_op = optimizer.minimize(total_loss) # 开始训练 with tf.Session() as sess: # 初始化变量 sess.run(tf.global_variables_initializer()) # 训练1000个epoch for epoch in range(1000): # 执行训练操作 _, loss = sess.run([train_op, total_loss], feed_dict={input_x: input_data}) # 每100个epoch打印一次损失 if epoch % 100 == 0: print("Epoch: {}, Loss: {:.4f}".format(epoch, loss)) ``` 在这个例子中,我们使用了一个单隐藏层的自编码器,并加入了一个L1正则化项控制模型复杂度。训练过程中,我们使用Adam优化器来最小化总损失。每100个epoch打印一次损失,可以看到损失逐渐减小,说明模型逐渐学习到了数据的特征。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值