教你用TensorFlow和自编码器模型生成手写数字(附代码)

简介:

自编码器是一种能够用来学习对输入数据高效编码的神经网络。若给定一些输入,神经网络首先会使用一系列的变换来将数据映射到低维空间,这部分神经网络就被称为编码器。

然后,网络会使用被编码的低维数据去尝试重建输入,这部分网络称之为解码器。我们可以使用编码器将数据压缩为神经网络可以理解的类型。然而自编码器很少用做这个目的,因为通常存在比它更为有效的手工编写的算法(例如 jpg 压缩)。

此外,自编码器还被经常用来执行降噪任务,它能够学会如何重建原始图像。

什么是变分自编码器?

有很多与自编码器相关的有趣应用。

其中之一被称为变分自编码器(variational autoencoder)。使用变分自编码器不仅可以压缩数据--还能生成自编码器曾经遇到过的新对象。

使用通用自编码器的时候,我们根本不知道网络所生成的编码具体是什么。虽然我们可以对比不同的编码对象,但是要理解它内部编码的方式几乎是不可能的。这也就意味着我们不能使用编码器来生成新的对象。我们甚至连输入应该是什么样子的都不知道。

而我们用相反的方法使用变分自编码器。我们不会尝试着去关注隐含向量所服从的分布,只需要告诉网络我们想让这个分布转换为什么样子就行了。

通常情况,我们会限制网络来生成具有单位正态分布性质的隐含向量。然后,在尝试生成数据的时候,我们只需要从这种分布中进行采样,然后把样本喂给解码器就行,解码器会返回新的对象,看上去就和我们用来训练网络的对象一样。

下面我们将介绍如何使用 Python 和 TensorFlow 实现这一过程,我们要教会我们的网络来画 MNIST 字符。

第一步加载训练数据

首先我们来执行一些基本的导入操作。TensorFlow 具有非常便利的函数来让我们能够很容易地访问 MNIST 数据集。

import tensorflow as tfimport numpy as npimport matplotlib.pyplot as plt
%matplotlib inlinefrom tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data')

定义输入数据和输出数据

MNIST 图像的维度是 28*28 像素,只有单色通道。我们的输入数据 X_in 是一批一批的 MNIST 字符,网络会学习如何重建它们。然后在一个占位符 Y 中输出它们,输出和输入具有相同的维度。

Y_flat 将会在后面计算损失函数的时候用到,keep_prob 将会在应用 dropout 的时候用到(作为一种正则化的方法)。在训练的过程中,它的值会设为 0.8,当生成新数据的时候,我们不使用 dropout,所以它的值会变成 1。

lrelu 函数需要自及定义,因为 TensorFlow 中并没有预定义一个 Leaky ReLU 函数。

tf.reset_default_graph()

batch_size = 64X_in = tf.placeholder(dtype=tf.float32, shape=[None, 28, 28], name='X')
Y    = tf.placeholder(dtype=tf.float32, shape=[None, 28, 28], name='Y')
Y_flat = tf.reshape(Y, shape=[-1, 28 * 28])
keep_prob = tf.placeholder(dtype=tf.float32, shape=(), name='keep_prob')

dec_in_channels = 1n_latent = 8reshaped_dim = [-1, 7, 7, dec_in_channels]
inputs_decoder = 49 * dec_in_channels / 2def lrelu(x, alpha=0.3):    return tf.maximum(x, tf.multiply(x, alpha))

定义编码器

因为我们的输入是图像,所以使用一些卷积变换会更加合理。最值得注意的是我们在编码器中创建了两个向量,因为编码器应该创建服从高斯分布的对象。

  • 一个是均值向量
  • 一个是标准差向量

在后面你会看到,我们是如何「强制」编码器来保证它确实生成 了服从正态分布的数据点,我们可以把将会被输入到解码器中的编码值表示为 z。在计算损失函数的时候,我们会需要我们所选分布的均值和标准差。

def encoder(X_in, keep_prob):
    activation = lrelu    with tf.variable_scope("encoder", reuse=None):
        X = tf.reshape(X_in, shape=[-1, 28, 28, 1])
        x = tf.layers.conv2d(X, filters=64, kernel_size=4, strides=2, padding='same', activation=activation)
        x = tf.nn.dropout(x, keep_prob)
        x = tf.layers.conv2d(x, filters=64, kernel_size=4, strides=2, padding='same', activation=activation)
        x = tf.nn.dropout(x, keep_prob)
        x = tf.layers.conv2d(x, filters=64, kernel_size=4, strides=1, padding='same', activation=activation)
        x = tf.nn.dropout(x, keep_prob)
        x = tf.contrib.layers.flatten(x)
        mn = tf.layers.dense(x, units=n_latent)
        sd       = 0.5 * tf.layers.dense(x, units=n_latent)            
        epsilon = tf.random_normal(tf.stack([tf.shape(x)[0], n_latent])) 
        z  = mn + tf.multiply(epsilon, tf.exp(sd))        
        return z, mn, sd

定义解码器

解码器不会关心输入值是不是从我们定义的某个特定分布中采样得到的。它仅仅会尝试重建输入图像。最后,我们使用了一系列的转置卷积(transpose convolution)。

def decoder(sampled_z, keep_prob):    with tf.variable_scope("decoder", reuse=None):
        x = tf.layers.dense(sampled_z, units=inputs_decoder, activation=lrelu)
        x = tf.layers.dense(x, units=inputs_decoder * 2 + 1, activation=lrelu)
        x = tf.reshape(x, reshaped_dim)
        x = tf.layers.conv2d_transpose(x, filters=64, kernel_size=4, strides=2, padding='same', activation=tf.nn.relu)
        x = tf.nn.dropout(x, keep_prob)
        x = tf.layers.conv2d_transpose(x, filters=64, kernel_size=4, strides=1, padding='same', activation=tf.nn.relu)
        x = tf.nn.dropout(x, keep_prob)
        x = tf.layers.conv2d_transpose(x, filters=64, kernel_size=4, strides=1, padding='same', activation=tf.nn.relu)
        
        x = tf.contrib.layers.flatten(x)
        x = tf.layers.dense(x, units=28*28, activation=tf.nn.sigmoid)
        img = tf.reshape(x, shape=[-1, 28, 28])        return img

现在,我们将两部分连在一起。

sampled, mn, sd = encoder(X_in, keep_prob)
dec = decoder(sampled, keep_prob)

计算损失函数,并实施一个高斯隐藏分布

为了计算图像重构的损失函数,我们简单地使用了平方差(这有时候会使图像变得有些模糊)。这个损失函数还结合了 KL 散度,这确保了我们的隐藏值将会从一个标准分布中采样。关于这个主题,如果想要了解更多,可以看一下这篇文章(https://jaan.io/what-is-variational-autoencoder-vae-tutorial/)

unreshaped = tf.reshape(dec, [-1, 28*28])
img_loss = tf.reduce_sum(tf.squared_difference(unreshaped, Y_flat), 1)
latent_loss = -0.5 * tf.reduce_sum(1.0 + 2.0 * sd - tf.square(mn) - tf.exp(2.0 * sd), 1)
loss = tf.reduce_mean(img_loss + latent_loss)
optimizer = tf.train.AdamOptimizer(0.0005).minimize(loss)
sess = tf.Session()
sess.run(tf.global_variables_initializer())

训练网络

现在我们终于可以训练我们的 VAE 了!

每隔 200 步,我们会看一下当前的重建是什么样子的。大约在处理了 2000 次迭代后,大多数重建看上去是挺合理的。

for i in range(30000):
    batch = [np.reshape(b, [28, 28]) for b in mnist.train.next_batch(batch_size=batch_size)[0]]
    sess.run(optimizer, feed_dict = {X_in: batch, Y: batch, keep_prob: 0.8})        
    if not i % 200:
        ls, d, i_ls, d_ls, mu, sigm = sess.run([loss, dec, img_loss, dst_loss, mn, sd], feed_dict = {X_in: batch, Y: batch, keep_prob: 1.0})
        plt.imshow(np.reshape(batch[0], [28, 28]), cmap='gray')
        plt.show()
        plt.imshow(d[0], cmap='gray')
        plt.show()
        print(i, ls, np.mean(i_ls), np.mean(d_ls))

生成新数据

最惊人的是我们现在可以生成新的字符了。最后,我们仅仅是从一个单位正态分布里面采集了一个值,输入到解码器。生成的大多数字符都和人类手写的是一样的。

randoms = [np.random.normal(0, 1, n_latent) for _ in range(10)]
imgs = sess.run(dec, feed_dict = {sampled: randoms, keep_prob: 1.0})
imgs = [np.reshape(imgs[i], [28, 28]) for i in range(len(imgs))]for img in imgs:
    plt.figure(figsize=(1,1))
    plt.axis('off')
    plt.imshow(img, cmap='gray')

e23369aa9ec9f482f5e51e8ee3b813e209a1e763

一些自动生成的字符

总结

这是关于 VAE 应用一个相当简单的例子。但是可以想象一下更多的可能性!神经网络可以学习谱写音乐,它们可以自动地创建对书籍、游戏的描述。借用创新思维,VAE 可以为一些新颖的项目开创空间。

全部 VAE 代码:

https://github.com/FelixMohr/Deep-learning-with-Python/blob/master/VAE.ipynb


原文发布时间为:2017-11-21

本文来自云栖社区合作伙伴“数据派THU”,了解相关信息可以关注“数据派THU”微信公众号

相关文章
|
3月前
|
机器学习/深度学习 TensorFlow 算法框架/工具
深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
将Keras训练好的.hdf5模型转换为TensorFlow的.pb模型,然后再转换为TensorRT支持的.uff格式,并提供了转换代码和测试步骤。
113 3
深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
|
2月前
|
机器学习/深度学习 数据采集 数据可视化
TensorFlow,一款由谷歌开发的开源深度学习框架,详细讲解了使用 TensorFlow 构建深度学习模型的步骤
本文介绍了 TensorFlow,一款由谷歌开发的开源深度学习框架,详细讲解了使用 TensorFlow 构建深度学习模型的步骤,包括数据准备、模型定义、损失函数与优化器选择、模型训练与评估、模型保存与部署,并展示了构建全连接神经网络的具体示例。此外,还探讨了 TensorFlow 的高级特性,如自动微分、模型可视化和分布式训练,以及其在未来的发展前景。
131 5
|
2月前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
108 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
2月前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
108 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
2月前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
104 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
4月前
|
机器学习/深度学习 人工智能 算法
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网页端操作界面,实现用户上传一张鸟类图像,识别其名称。
133 12
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
|
3月前
|
机器学习/深度学习 移动开发 TensorFlow
深度学习之格式转换笔记(四):Keras(.h5)模型转化为TensorFlow(.pb)模型
本文介绍了如何使用Python脚本将Keras模型转换为TensorFlow的.pb格式模型,包括加载模型、重命名输出节点和量化等步骤,以便在TensorFlow中进行部署和推理。
143 0
|
5月前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
97 0
|
5月前
|
C# 开发者 前端开发
揭秘混合开发新趋势:Uno Platform携手Blazor,教你一步到位实现跨平台应用,代码复用不再是梦!
【8月更文挑战第31天】随着前端技术的发展,混合开发日益受到开发者青睐。本文详述了如何结合.NET生态下的两大框架——Uno Platform与Blazor,进行高效混合开发。Uno Platform基于WebAssembly和WebGL技术,支持跨平台应用构建;Blazor则让C#成为可能的前端开发语言,实现了客户端与服务器端逻辑共享。二者结合不仅提升了代码复用率与跨平台能力,还简化了项目维护并增强了Web应用性能。文中提供了从环境搭建到示例代码的具体步骤,并展示了如何创建一个简单的计数器应用,帮助读者快速上手混合开发。
118 0
|
5月前
|
开发者 算法 虚拟化
惊爆!Uno Platform 调试与性能分析终极攻略,从工具运用到代码优化,带你攻克开发难题成就完美应用
【8月更文挑战第31天】在 Uno Platform 中,调试可通过 Visual Studio 设置断点和逐步执行代码实现,同时浏览器开发者工具有助于 Web 版本调试。性能分析则利用 Visual Studio 的性能分析器检查 CPU 和内存使用情况,还可通过记录时间戳进行简单分析。优化性能涉及代码逻辑优化、资源管理和用户界面简化,综合利用平台提供的工具和技术,确保应用高效稳定运行。
112 0