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

2024-04-14 01:38

本文主要是介绍教你用TensorFlow和自编码器模型生成手写数字(附代码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


来源:机器之心

本文长度为1876字,建议阅读4分钟

本文介绍了如何使用 TensorFlow 实现变分自编码器(VAE)模型,并通过简单的手写数字生成案例一步步引导读者实现这一强大的生成模型。


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


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


一些自动生成的字符


总结


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


全部 VAE 代码:

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

原文链接:

https://medium.com/towards-data-science/teaching-a-variational-autoencoder-vae-to-draw-mnist-characters-978675c95776


编辑:王璇

这篇关于教你用TensorFlow和自编码器模型生成手写数字(附代码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/901773

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

从去中心化到智能化:Web3如何与AI共同塑造数字生态

在数字时代的演进中,Web3和人工智能(AI)正成为塑造未来互联网的两大核心力量。Web3的去中心化理念与AI的智能化技术,正相互交织,共同推动数字生态的变革。本文将探讨Web3与AI的融合如何改变数字世界,并展望这一新兴组合如何重塑我们的在线体验。 Web3的去中心化愿景 Web3代表了互联网的第三代发展,它基于去中心化的区块链技术,旨在创建一个开放、透明且用户主导的数字生态。不同于传统

AI一键生成 PPT

AI一键生成 PPT 操作步骤 作为一名打工人,是不是经常需要制作各种PPT来分享我的生活和想法。但是,你们知道,有时候灵感来了,时间却不够用了!😩直到我发现了Kimi AI——一个能够自动生成PPT的神奇助手!🌟 什么是Kimi? 一款月之暗面科技有限公司开发的AI办公工具,帮助用户快速生成高质量的演示文稿。 无论你是职场人士、学生还是教师,Kimi都能够为你的办公文

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

usaco 1.2 Name That Number(数字字母转化)

巧妙的利用code[b[0]-'A'] 将字符ABC...Z转换为数字 需要注意的是重新开一个数组 c [ ] 存储字符串 应人为的在末尾附上 ‘ \ 0 ’ 详见代码: /*ID: who jayLANG: C++TASK: namenum*/#include<stdio.h>#include<string.h>int main(){FILE *fin = fopen (

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];