原文:TensorFlow 1.x Deep Learning Cookbook

协议:CC BY-NC-SA 4.0

译者:飞龙

本文来自【ApacheCN 深度学习 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。

不要担心自己的形象,只关心如何实现目标。——《原则》,生活原则 2.3.c

十一、生成模型和 CapsNet

在本章中,我们将介绍一些用于以下方面的方法:

  • 学习使用简单 GAN 伪造 MNIST 图像
  • 学习使用 DCGAN 伪造 MNIST 图像
  • 学习使用 DCGAN 伪造名人面孔和其他数据集
  • 实现变分自编码器
  • 通过胶囊网络学习击败 MNIST 的最新结果

介绍

在本章中,我们将讨论如何将生成对抗网络GAN)用于深度学习领域,其中关键方法是训练图像生成器来挑战鉴别器,并同时训练鉴别器来改进生成器。 可以将相同的方法应用于不同于图像领域。 另外,我们将讨论变分自编码器。

GAN 已被深度学习之父之一 Yann LeCun 定义为“这是深度学习的突破”。 GAN 能够学习如何再现看起来真实的合成数据。 例如,计算机可以学习如何绘制和创建逼真的图像。 这个想法最初是由与蒙特利尔大学 Google Brain 合作的 Ian Goodfellow 提出的,最近由 OpenAI 提出。

那么,GAN 是什么?

通过将其视为类似于艺术伪造的方式,可以很容易地理解 GAN 的关键过程,这是创作被误认为其他人(通常是更著名的艺术家)的艺术品的过程。 GAN 同时训练两个神经网络。

生成器G(Z)是生成赝品,而鉴别器D(Y)可以根据对真实艺术品和复制品的观察来判断复制品的逼真度。 D(Y)接受输入 Y(例如图像),并投票决定输入的真实程度。 通常,接近零的值表示真实,而接近一的值表示伪造G(Z)从随机噪声Z中获取输入,并训练自己以欺骗 D 认为G(Z)产生的任何东西都是真实的。 因此,训练鉴别器D(Y)的目标是,从为每个来自真实数据分布的图像最大化D(Y),并为每个不来自真实数组的图像最小化D(Y),而不是来自真实数据分布的每个图像。 因此,G 和 D 扮演相反的游戏:因此称为对抗训练。 请注意,我们以交替的方式训练 G 和 D,其中它们的每个目标都表示为通过梯度下降优化的损失函数。 生成模型学习如何越来越好地进行伪造,而鉴别模型学习如何越来越好地识别伪造。

鉴别器网络(通常是标准卷积神经网络)试图对输入图像是真实的还是生成的进行分类。 一个重要的新思想是反向传播鉴别器和生成器,以调整生成器的参数,以使生成器可以学习如何在越来越多的情况下欺骗鉴别器。 最后,生成器将学习如何生成与真实图像无法区分的图像:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7J7LVuc8-1681565377458)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/7c949720-9d74-4438-b62f-1e34e72c2ece.png)]

生成器(伪造)- 鉴别器(判断)模型的示例。 鉴别器接收伪造的真实图像

当然,GAN 可以在有两名玩家的游戏中找到平衡点。 为了有效学习,如果一个玩家在下一轮更新中成功下坡,那么相同的更新也必须使另一个玩家也下坡。 想想看! 如果伪造者每次都学会如何愚弄法官,那么伪造者本人就没什么可学的了。 有时,两个玩家最终会达到平衡,但这并不总是可以保证的,因此两个玩家可以长时间继续比赛。 下图提供了双方的示例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hgno7Bli-1681565377459)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/e58a4195-d083-46fb-85e5-7495cee19173.png)]

生成器和鉴别器的收敛示例

一些很酷的 GAN 应用

我们已经确定生成器学习如何伪造数据。 这意味着它将学习如何创建由网络创建的新合成数据,并且看起来是真实的并且由人类创建。 在讨论有关 GAN 代码的详细信息之前,我想分享使用 GAN 的最新论文(代码可在线获得)的结果。 从文本描述开始合成伪造的图像。 结果令人印象深刻。 第一列是测试集中的真实图像,其他所有列都是从 StackGAN 的 Stage-I 和 Stage-II 中相同的文本描述生成的图像。 YouTube 上有更多示例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ImMGtZjV-1681565377460)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/60422def-cdf2-489b-8974-49708350aea0.png)]

现在,让我们看看 GAN 如何学习伪造 MNIST 数据集。 在这种情况下,它是用于生成器和鉴别器网络的 GAN 和卷积网络的组合。 最初,生成器不会产生任何可理解的东西,但是经过几次迭代,合成的伪造数字变得越来越清晰。 在下图中,通过增加训练时期来对面板进行排序,您可以看到面板之间的质量改进:

改进后的图像如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SAJ9h1o4-1681565377461)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/e716e40e-9737-44bd-abc2-d6cc7b240339.png)]

我们可以在下图中看到进一步的改进:

GAN 最酷的用途之一是对生成器向量Z的面部进行算术。换句话说,如果我们停留在合成伪造图像的空间中,则可能会看到类似以下内容:[微笑的女人]-[中性的女人] + [中性的男人] = [微笑的男人],或类似这样:[戴眼镜的男人] - [戴眼镜的男人] + [戴眼镜的女人] = [戴眼镜的女人]。 下图取自:《深度卷积生成对抗网络的无监督表示学习》(Alec Radford,Luke Metz,Soumith Chintala,2016)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jX9gEmwS-1681565377461)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/01744226-effd-46ec-9e04-f7668a1379aa.png)]

这个链接提供了 GAN 的其他出色示例。 本文中所有图像均由神经网络生成。 他们不是真实的。 全文可在此处找到。

卧室:经过五个时期的训练后生成的卧室:

生成卧室的示例

专辑封面:这些图像不是真实的,而是由 GAN 生成的。 专辑封面看起来很真实:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UTeNlz40-1681565377462)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/3f94861f-9f24-4b33-92d1-44b413fb0408.png)]

生成专辑封面的示例

学习使用简单的 GAN 伪造 MNIST 图像

Ian J.Goodfellow,Jean Pouget-Abadie,Mehdi Mirza,Bing Xu,David Warde-Farley,Sherjil Ozair,Aaron Courville,Yoshua Bengio 等人撰写的 Generative Adversarial Networks(2014)是更好地理解 GAN 的好论文。 在本秘籍中,我们将学习如何使用以 Generator-Discriminator 架构组织的全连接层网络来伪造 MNIST 手写数字。

准备

此秘籍基于这个页面上可用的代码。

操作步骤

我们按以下步骤进行:

  1. 从 github 克隆代码:
git clone https://github.com/TengdaHan/GAN-TensorFlow
  1. 定义 Xavier 初始化器,如论文Understanding the difficulty of training deep feedforward neural networks (2009) by Xavier Glorot, Yoshua Bengio, http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.207.2059&rep=rep1&type=pdf中所述。事实证明,初始化器可让 GAN 更好地收敛:
def xavier_init(size):in_dim = size[0]xavier_stddev = 1\. / tf.sqrt(in_dim / 2.)return xavier_stddev
  1. 定义输入X的生成器。首先,我们定义尺寸为[100, K = 128]的矩阵W1,并根据正态分布对其进行初始化。 注意 100 是Z的任意值,Z是我们的生成器使用的初始噪声。 然后,我们定义尺寸为[K = 256]的偏差B1。 类似地,我们定义尺寸为[K=128, L=784]的矩阵W2和尺寸为[L = 784]的偏置B2。 使用步骤 1 中定义的xavier_init初始化两个矩阵W1W2,而使用tf.constant_initializer()初始化B1B2。 之后,我们计算矩阵X * W1之间的乘法,求和B1的偏差,然后将其传递给 RELU 激活函数以获得fc1。 然后将该密集层与下一个密集层连接,该密集层是通过将矩阵fc1W2相乘并求和B2的偏差而创建的。 然后将结果通过 Sigmoid 函数传递。 这些步骤用于定义用于生成器的两层神经网络:
def generator(X):with tf.variable_scope('generator'): K = 128L = 784W1 = tf.get_variable('G_W1', [100, K],initializer=tf.random_normal_initializer(stddev=xavier_init([100,   K])))B1 = tf.get_variable('G_B1', [K],       initializer=tf.constant_initializer())W2 = tf.get_variable('G_W2', [K, L],initializer=tf.random_normal_initializer(stddev=xavier_init([K,   L])))B2 = tf.get_variable('G_B2', [L],    initializer=tf.constant_initializer())# summarytf.summary.histogram('weight1', W1)tf.summary.histogram('weight2', W2)tf.summary.histogram('biases1', B1)tf.summary.histogram('biases2', B2)fc1 = tf.nn.relu((tf.matmul(X, W1) + B1))fc2 = tf.matmul(fc1, W2) + B2prob = tf.nn.sigmoid(fc2)return prob
  1. 定义输入X的鉴别器。原则上,这与生成器非常相似。 主要区别在于,如果参数重用为true,则调用scope.reuse_variables()触发重用。 然后我们定义两个密集层。 第一层使用尺寸为[J=784, K=128]的矩阵W1,尺寸为[K=128]的偏差B1,并且它基于XW1的标准乘积。 将该结果添加到B1并传递给 RELU 激活函数以获取结果fc1。 第二个矩阵使用尺寸为[K=128, L=1]的矩阵W2和尺寸为[L=1]的偏差B2,它基于fc1W2的标准乘积。 将此结果添加到B2并传递给 Sigmoid 函数:
def discriminator(X, reuse=False):with tf.variable_scope('discriminator'):if reuse:tf.get_variable_scope().reuse_variables()J = 784K = 128L = 1W1 = tf.get_variable('D_W1', [J, K],initializer=tf.random_normal_initializer(stddev=xavier_init([J,  K])))B1 = tf.get_variable('D_B1', [K],    initializer=tf.constant_initializer())W2 = tf.get_variable('D_W2', [K, L],
initializer=tf.random_normal_initializer(stddev=xavier_init([K, L])))B2 = tf.get_variable('D_B2', [L],  initializer=tf.constant_initializer())# summarytf.summary.histogram('weight1', W1)tf.summary.histogram('weight2', W2)tf.summary.histogram('biases1', B1)tf.summary.histogram('biases2', B2)fc1 = tf.nn.relu((tf.matmul(X, W1) + B1))logits = tf.matmul(fc1, W2) + B2prob = tf.nn.sigmoid(logits)return prob, logits
  1. 现在让我们定义一些有用的附加函数。 首先,我们导入一堆标准模块:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import os
import argparse
  1. 然后,我们从 MNIST 数据集中读取数据,并定义了用于绘制样本的辅助函数:
def read_data():from tensorflow.examples.tutorials.mnist import input_datamnist = input_data.read_data_sets("../MNIST_data/", one_hot=True)return mnistdef plot(samples):fig = plt.figure(figsize=(8, 8))gs = gridspec.GridSpec(8, 8)gs.update(wspace=0.05, hspace=0.05)for i, sample in enumerate(samples):ax = plt.subplot(gs[i])plt.axis('off')ax.set_xticklabels([])ax.set_yticklabels([])ax.set_aspect('equal')plt.imshow(sample.reshape(28, 28), cmap='Greys_r')return fig
  1. 现在让我们定义训练函数。 首先,让我们读取 MNIST 数据,然后定义一个具有一个用于标准 MNIST 手写字符的通道的28 x 28形状的矩阵X。 然后,让我们定义大小为 100 的z噪声向量,这是 GAN 论文中提出的一个常见选择。 下一步是在z上调用生成器,然后将结果分配给G。之后,我们将X传递给鉴别器,而无需重用。 然后,我们将伪造/伪造的G结果传递给鉴别器,从而重用学习到的权重。 这方面的一个重要方面是我们如何选择鉴别器的损失函数,该函数是两个交叉熵的和:一个交叉熵,一个用于实字符,其中所有真实 MNIST 字符的标签都设置为一个,另一个用于伪造的字符,其中所有伪造的字符的标签都设置为零。 鉴别器和生成器以交替顺序运行 100,000 步。 每 500 步,会从学习到的分布中抽取一个样本,以打印该生成器到目前为止所学的内容。 这就是定义新周期的条件,结果将在下一节中显示。 让我们看看实现我们刚刚描述的代码片段。
def train(logdir, batch_size):from model_fc import discriminator, generatormnist = read_data()with tf.variable_scope('placeholder'):# Raw imageX = tf.placeholder(tf.float32, [None, 784])tf.summary.image('raw image', tf.reshape(X, [-1, 28, 28, 1]), 3)# Noisez = tf.placeholder(tf.float32, [None, 100]) # noisetf.summary.histogram('Noise', z)with tf.variable_scope('GAN'):G = generator(z)D_real, D_real_logits = discriminator(X, reuse=False)D_fake, D_fake_logits = discriminator(G, reuse=True)tf.summary.image('generated image', tf.reshape(G, [-1, 28, 28, 1]), 3)with tf.variable_scope('Prediction'):tf.summary.histogram('real', D_real) tf.summary.histogram('fake', D_fake)with tf.variable_scope('D_loss'):d_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_real_logits, labels=tf.ones_like(D_real_logits)))d_loss_fake = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_fake_logits, labels=tf.zeros_like(D_fake_logits)))d_loss = d_loss_real + d_loss_faketf.summary.scalar('d_loss_real', d_loss_real)tf.summary.scalar('d_loss_fake', d_loss_fake)tf.summary.scalar('d_loss', d_loss)with tf.name_scope('G_loss'):g_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_fake_logits, labels=tf.ones_like(D_fake_logits)))tf.summary.scalar('g_loss', g_loss)tvar = tf.trainable_variables()dvar = [var for var in tvar if 'discriminator' in var.name]gvar = [var for var in tvar if 'generator' in var.name]with tf.name_scope('train'):d_train_step = tf.train.AdamOptimizer().minimize(d_loss,   var_list=dvar)g_train_step = tf.train.AdamOptimizer().minimize(g_loss,  var_list=gvar)sess = tf.Session()init = tf.global_variables_initializer()sess.run(init)merged_summary = tf.summary.merge_all()writer = tf.summary.FileWriter('tmp/mnist/'+logdir)writer.add_graph(sess.graph)num_img = 0if not os.path.exists('output/'):os.makedirs('output/')for i in range(100000):batch_X, _ = mnist.train.next_batch(batch_size)batch_noise = np.random.uniform(-1., 1., [batch_size, 100])if i % 500 == 0:samples = sess.run(G, feed_dict={z: np.random.uniform(-1., 1., [64, 100])})fig = plot(samples)plt.savefig('output/%s.png' % str(num_img).zfill(3),    bbox_inches='tight')num_img += 1plt.close(fig)_, d_loss_print = sess.run([d_train_step, d_loss],
feed_dict={X: batch_X, z: batch_noise})_, g_loss_print = sess.run([g_train_step, g_loss],feed_dict={z: batch_noise})if i % 100 == 0:s = sess.run(merged_summary, feed_dict={X: batch_X, z: batch_noise})writer.add_summary(s, i)print('epoch:%d g_loss:%f d_loss:%f' % (i, g_loss_print, d_loss_print))if __name__ == '__main__':parser = argparse.ArgumentParser(description='Train vanila GAN using fully-connected layers networks')parser.add_argument('--logdir', type=str, default='1', help='logdir for Tensorboard, give a string')parser.add_argument('--batch_size', type=int, default=64, help='batch size: give a int')args = parser.parse_args()train(logdir=args.logdir, batch_size=args.batch_size)

工作原理

在每个时期,生成器都会进行许多预测(它会生成伪造的 MNIST 图像),鉴别器会在将预测与实际 MNIST 图像混合后尝试学习如何生成伪造的图像。 在 32 个周期之后,生成器学习伪造这组手写数字。 没有人对机器进行编程来编写,但是它学会了如何编写与人类所写的数字没有区别的数字。 请注意,训练 GAN 可能非常困难,因为有必要在两个参与者之间找到平衡。 如果您对该主题感兴趣,我建议您看看从业者收集的一系列技巧。

让我们看一下不同时期的许多实际示例,以了解机器将如何学习以改善其编写过程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GrTSFPgO-1681565377462)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/62be9039-67e4-474a-a4d3-1b5a5f22f9f6.png)]
周期 0 周期 2 周期 4
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IrKjAPc7-1681565377463)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/dce02074-88d4-426f-8fb6-3a7af718befd.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0VH5JjJz-1681565377463)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/fe7664aa-20b2-491e-879b-bad57a38c38f.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rck5iSTX-1681565377463)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/64bbaff9-829c-4591-bbcd-cf8d5cfd915c.png)]
周期 8 周期 16 周期 32
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1U0BmKrQ-1681565377464)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/acc43ab3-a2c3-460b-bcac-58d579da5951.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YIx4v40V-1681565377464)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/47e5390f-e506-4e24-b024-c36dbf67b0d8.png)]
周期 64 周期 128 周期 200

Example of forged MNIST-like characters with a GAN

学习使用 DCGAN 伪造 MNIST 图像

在本秘籍中,我们将使用一个简单的 GAN,它使用 CNN 来学习如何伪造 MNIST 图像并创建不属于原始数据集的新图像。 这个想法是 CNN 与 GAN 一起使用将提高处理图像数据集的能力。 请注意,先前的方法是将 GAN 与完全连接的网络一起使用,而在此我们重点介绍 CNN。

准备

此秘籍基于这个页面上可用的代码。

操作步骤

我们按以下步骤进行:

  1. 从 github 克隆代码:
git clone https://github.com/TengdaHan/GAN-TensorFlow
  1. 定义 Xavier 初始化器,如论文Understanding the difficulty of training deep feedforward neural networks (2009) by Xavier Glorot, Yoshua Bengio, http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.207.2059&rep=rep1&type=pdf中所述。事实证明,初始化器可让 GAN 更好地收敛:
def xavier_init(size):in_dim = size[0]xavier_stddev = 1\. / tf.sqrt(in_dim / 2.)# return tf.random_normal(shape=size, stddev=xavier_stddev)return xavier_stddev
  1. 为给定输入x,权重w,偏差b和给定步幅定义卷积运算。 我们的代码使用标准的tf.nn.conv2d(...)模块。 请注意,我们使用第 4 章中定义的SAME填充:
def conv(x, w, b, stride, name):with tf.variable_scope('conv'):tf.summary.histogram('weight', w)tf.summary.histogram('biases', b)return tf.nn.conv2d(x,filter=w,strides=[1, stride, stride, 1],padding='SAME',name=name) + b
  1. 为给定输入x,权重w,偏差b和给定步幅定义反卷积运算。 我们的代码使用标准的tf.nn.conv2d_transpose(...)模块。 同样,我们使用'SAME'填充。
def deconv(x, w, b, shape, stride, name):with tf.variable_scope('deconv'):tf.summary.histogram('weight', w)tf.summary.histogram('biases', b)return tf.nn.conv2d_transpose(x,filter=w,output_shape=shape,strides=[1, stride, stride, 1],padding='SAME',name=name) + b
  1. 定义一个标准LeakyReLU,这对于 GAN 是非常有效的激活函数:
def lrelu(x, alpha=0.2):with tf.variable_scope('leakyReLU'):return tf.maximum(x, alpha * x)
  1. 定义生成器。 首先,我们定义输入大小为 100(Z 的任意大小,即生成器使用的初始噪声)的完全连接层。 全连接层由尺寸为[100, 7 * 7 * 256]且根据正态分布初始化的矩阵W1和尺寸为[7 * 7 * 256]的偏置B1组成。 该层使用 ReLu 作为激活函数。 在完全连接的层之后,生成器将应用两个反卷积运算 deconv1 和 deconv2,两者的步幅均为 2。 完成第一个 deconv1 操作后,将结果批量标准化。 请注意,第二次反卷积运算之前会出现丢弃,概率为 40%。 最后一个阶段是一个 Sigmoid,用作非线性激活,如下面的代码片段所示:
def generator(X, batch_size=64):with tf.variable_scope('generator'):K = 256L = 128M = 64W1 = tf.get_variable('G_W1', [100, 7*7*K],    initializer=tf.random_normal_initializer(stddev=0.1))B1 = tf.get_variable('G_B1', [7*7*K], initializer=tf.constant_initializer())W2 = tf.get_variable('G_W2', [4, 4, M, K], initializer=tf.random_normal_initializer(stddev=0.1))B2 = tf.get_variable('G_B2', [M], initializer=tf.constant_initializer())W3 = tf.get_variable('G_W3', [4, 4, 1, M], initializer=tf.random_normal_initializer(stddev=0.1))B3 = tf.get_variable('G_B3', [1], initializer=tf.constant_initializer())X = lrelu(tf.matmul(X, W1) + B1)X = tf.reshape(X, [batch_size, 7, 7, K])deconv1 = deconv(X, W2, B2, shape=[batch_size, 14, 14, M], stride=2, name='deconv1')bn1 = tf.contrib.layers.batch_norm(deconv1)deconv2 = deconv(tf.nn.dropout(lrelu(bn1), 0.4), W3, B3, shape=[batch_size, 28, 28, 1], stride=2, name='deconv2')XX = tf.reshape(deconv2, [-1, 28*28], 'reshape')return tf.nn.sigmoid(XX)
  1. 定义鉴别器。 与前面的秘籍一样,如果参数重用为true,则调用scope.reuse_variables()触发重用。 鉴别器使用两个卷积层。 第一个是批量归一化,而第二个是概率为 40% 的丢弃,然后是批量归一化步骤。 之后,我们得到了一个具有激活函数 ReLU 的致密层,然后是另一个具有基于 Sigmoid 激活函数的致密层:
def discriminator(X, reuse=False):with tf.variable_scope('discriminator'):if reuse:tf.get_variable_scope().reuse_variables()K = 64M = 128N = 256W1 = tf.get_variable('D_W1', [4, 4, 1, K],   initializer=tf.random_normal_initializer(stddev=0.1))B1 = tf.get_variable('D_B1', [K], initializer=tf.constant_initializer())W2 = tf.get_variable('D_W2', [4, 4, K, M], initializer=tf.random_normal_initializer(stddev=0.1))B2 = tf.get_variable('D_B2', [M], initializer=tf.constant_initializer())W3 = tf.get_variable('D_W3', [7*7*M, N], initializer=tf.random_normal_initializer(stddev=0.1))B3 = tf.get_variable('D_B3', [N], initializer=tf.constant_initializer())W4 = tf.get_variable('D_W4', [N, 1], initializer=tf.random_normal_initializer(stddev=0.1))B4 = tf.get_variable('D_B4', [1], initializer=tf.constant_initializer())X = tf.reshape(X, [-1, 28, 28, 1], 'reshape')conv1 = conv(X, W1, B1, stride=2, name='conv1')bn1 = tf.contrib.layers.batch_norm(conv1)conv2 = conv(tf.nn.dropout(lrelu(bn1), 0.4), W2, B2, stride=2, name='conv2')bn2 = tf.contrib.layers.batch_norm(conv2)flat = tf.reshape(tf.nn.dropout(lrelu(bn2), 0.4), [-1, 7*7*M], name='flat')dense = lrelu(tf.matmul(flat, W3) + B3)logits = tf.matmul(dense, W4) + B4prob = tf.nn.sigmoid(logits)return prob, logits
  1. 然后,我们从 MNIST 数据集中读取数据,并定义用于绘制样本的辅助函数:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import os
import argparsedef read_data():from tensorflow.examples.tutorials.mnist import input_datamnist = input_data.read_data_sets("../MNIST_data/", one_hot=True)return mnistdef plot(samples):fig = plt.figure(figsize=(8, 8))gs = gridspec.GridSpec(8, 8)gs.update(wspace=0.05, hspace=0.05)for i, sample in enumerate(samples):ax = plt.subplot(gs[i])plt.axis('off')ax.set_xticklabels([])ax.set_yticklabels([])ax.set_aspect('equal')plt.imshow(sample.reshape(28, 28), cmap='Greys_r')return fig
  1. 现在让我们定义训练函数。 首先,让我们读取 MNIST 数据,然后定义一个具有一个用于标准 MNIST 手写字符的通道的28 x 28形状的矩阵X。 然后,让我们定义大小为 100 的z噪声向量,这是 GAN 论文中提出的一个常见选择。 下一步是在z上调用生成器,然后将结果分配给G。之后,我们将X传递给鉴别器,而无需重用。 然后,我们将伪造/伪造的G结果传递给鉴别器,从而重用学习到的权重。 这方面的一个重要方面是我们如何选择鉴别函数的损失函数,该函数是两个交叉熵的和:一个用于实字符,其中所有真实 MNIST 字符的标号都设置为 1,一个用于遗忘字符,其中所有伪造的字符的标签设置为零。 鉴别器和生成器以交替顺序运行 100,000 步。 每 500 步,会从学习到的分布中抽取一个样本,以打印该生成器到目前为止所学的内容。 这就是定义新周期的条件,结果将在下一部分中显示。 训练函数代码段报告如下
def train(logdir, batch_size):from model_conv import discriminator, generatormnist = read_data()with tf.variable_scope('placeholder'):# Raw imageX = tf.placeholder(tf.float32, [None, 784])tf.summary.image('raw image', tf.reshape(X, [-1, 28, 28, 1]), 3)# Noisez = tf.placeholder(tf.float32, [None, 100]) # noisetf.summary.histogram('Noise', z)with tf.variable_scope('GAN'):G = generator(z, batch_size)D_real, D_real_logits = discriminator(X, reuse=False)D_fake, D_fake_logits = discriminator(G, reuse=True)tf.summary.image('generated image', tf.reshape(G, [-1, 28, 28, 1]), 3)with tf.variable_scope('Prediction'):tf.summary.histogram('real', D_real)tf.summary.histogram('fake', D_fake)with tf.variable_scope('D_loss'):d_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(
logits=D_real_logits, labels=tf.ones_like(D_real_logits)))d_loss_fake = tf.reduce_mean(
tf.nn.sigmoid_cross_entropy_with_logits(
logits=D_fake_logits, labels=tf.zeros_like(D_fake_logits)))d_loss = d_loss_real + d_loss_faketf.summary.scalar('d_loss_real', d_loss_real)tf.summary.scalar('d_loss_fake', d_loss_fake)tf.summary.scalar('d_loss', d_loss)with tf.name_scope('G_loss'):g_loss =   tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits
(logits=D_fake_logits, labels=tf.ones_like(D_fake_logits)))tf.summary.scalar('g_loss', g_loss)tvar = tf.trainable_variables()dvar = [var for var in tvar if 'discriminator' in var.name]gvar = [var for var in tvar if 'generator' in var.name]with tf.name_scope('train'):d_train_step = tf.train.AdamOptimizer().minimize(d_loss, var_list=dvar)g_train_step = tf.train.AdamOptimizer().minimize(g_loss, var_list=gvar)sess = tf.Session()init = tf.global_variables_initializer()sess.run(init)merged_summary = tf.summary.merge_all()writer = tf.summary.FileWriter('tmp/'+'gan_conv_'+logdir)writer.add_graph(sess.graph)num_img = 0if not os.path.exists('output/'):os.makedirs('output/')for i in range(100000):batch_X, _ = mnist.train.next_batch(batch_size)batch_noise = np.random.uniform(-1., 1., [batch_size, 100])if i % 500 == 0:samples = sess.run(G, feed_dict={z: np.random.uniform(-1., 1., [64, 100])})fig = plot(samples)plt.savefig('output/%s.png' % str(num_img).zfill(3), bbox_inches='tight')num_img += 1plt.close(fig)_, d_loss_print = sess.run([d_train_step, d_loss],
feed_dict={X: batch_X, z: batch_noise})_, g_loss_print = sess.run([g_train_step, g_loss],
feed_dict={z: batch_noise})if i % 100 == 0:s = sess.run(merged_summary, feed_dict={X: batch_X, z: batch_noise})writer.add_summary(s, i)print('epoch:%d g_loss:%f d_loss:%f' % (i, g_loss_print, d_loss_print))if __name__ == '__main__':parser = argparse.ArgumentParser(description='Train vanila GAN using convolutional networks')parser.add_argument('--logdir', type=str, default='1', help='logdir for Tensorboard, give a string')parser.add_argument('--batch_size', type=int, default=64, help='batch size: give a int')args = parser.parse_args()train(logdir=args.logdir, batch_size=args.batch_size)

工作原理

将 CNN 与 GAN 一起使用可提高学习能力。 让我们看一下不同时期的许多实际示例,以了解机器将如何学习以改善其编写过程。 例如,将以下秘籍中的四次迭代后获得的结果与先前秘籍中的四次迭代后获得的结果进行比较。 你看得到差别吗? 我希望自己可以学习这种艺术!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tX3xoW8y-1681565377465)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/cdd533f8-38c3-47cc-b13b-732c76f9b3f4.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TPZCZf1a-1681565377465)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/f7a2ca78-99d9-4bdd-add9-5edca6c93c43.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GEorEh6Z-1681565377465)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/5e84bb49-e14c-4257-a48f-b8b1d5c37197.png)]
周期 0 周期 2 周期 4
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rHdBa2wI-1681565377465)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/5d6e7413-f565-4d12-9fa7-d2a0dfadd338.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4VHLt0id-1681565377465)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/ef066e7c-f6f7-45e9-8887-8e3c6dad0911.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rlyMiUiv-1681565377466)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/fb8753c2-fdfd-428d-95b5-e4561e7bafd3.png)]
周期 8 周期 16 周期 32
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WZwAUp5i-1681565377466)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/91c50bd6-ae61-45aa-b8ca-96848c6d6c7c.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YUu39o1P-1681565377466)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/bb7d6347-a6ad-491e-9b3e-e424eb7b95c1.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z2Bl7BJt-1681565377466)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/b6d45453-6794-4503-a35e-51498160dcc2.png)]
周期 64 周期 128 周期 200

Example of forged MNIST-like with DCGAN

学习使用 DCGAN 伪造名人人脸和其他数据集

用于伪造 MNIST 图像的相同思想可以应用于其他图像域。 在本秘籍中,您将学习如何使用位于这个链接的包在不同的数据集上训练 DCGAN 模型。 这项工作基于论文《深度卷积生成对抗网络的无监督表示学习》(Alec Radford,Luke Metz,Soumith Chintal,2015 年)。引用摘要:

近年来,通过卷积网络(CNN)进行监督学习已在计算机视觉应用中得到了广泛采用。 相比之下,CNN 的无监督学习受到的关注较少。 在这项工作中,我们希望帮助弥合CNN在有监督学习的成功与无监督学习之间的差距。 我们介绍了一种称为深度卷积生成对抗网络(DCGAN)的 CNN,它们具有一定的架构约束,并证明它们是无监督学习的强大候选者。 在各种图像数据集上进行训练,我们显示出令人信服的证据,即我们深厚的卷积对抗对在生成器和鉴别器中学习了从对象部分到场景的表示层次。 此外,我们将学习到的特征用于新颖的任务-展示了它们作为一般图像表示形式的适用性。

请注意,生成器具有下图所示的架构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rH2lWNUw-1681565377467)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/7aa964c6-fb7f-4d74-8578-efcc5b36b500.png)]

请注意,在包装中,相对于原始纸张进行了更改,以避免D(鉴别器)网络快速收敛,G(生成器)网络每次D网络更新都会更新两次。

准备

此秘籍基于这个页面上提供的代码。

操作步骤

我们按以下步骤进行:

  1. 从 Github 克隆代码:
git clone https://github.com/carpedm20/DCGAN-tensorflow
  1. 使用以下命令下载数据集:
python download.py mnist celebA
  1. 要使用下载的数据集训练模型,请使用以下命令:
python main.py --dataset celebA --input_height=108 --train --crop
  1. 要使用现有模型对其进行测试,请使用以下命令:
python main.py --dataset celebA --input_height=108 --crop
  1. 另外,您可以通过执行以下操作来使用自己的数据集:
$ mkdir data/DATASET_NAME... add images to data/DATASET_NAME ...$ python main.py --dataset DATASET_NAME --train$ python main.py --dataset DATASET_NAME$ # example$ python main.py --dataset=eyes --input_fname_pattern="*_cropped.png" --train

工作原理

生成器学习如何生成名人的伪造图像,鉴别器学习如何将伪造的图像与真实的图像区分开。 两个网络中的每个周期都在竞争以改善和减少损失。 下表报告了前五个时期:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kQMSvXNh-1681565377467)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/fa0f7ae3-102e-4548-91d4-5c2e65a26a4b.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nrs0g4o4-1681565377467)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/fa448cc9-f71f-4c31-b71c-a221ca64ae88.png)]
周期 0 周期 1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iSnP1EBy-1681565377467)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/3984c5eb-70b6-4164-8d7e-e663a9496d61.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uHnisSE2-1681565377468)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/565f6241-3041-41c6-b457-0cadcf580ca4.png)]
周期 2 周期 3
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eweDMuHm-1681565377468)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/6da758f7-ce4b-4052-ab3f-5a267c45bfec.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EE6t9r4Y-1681565377468)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/778937bc-080a-41e3-800e-e5aa6c8a144b.png)]
周期 4 周期 5

Example of forged celebrities with a DCGAN

更多

内容感知填充是摄影师使用的一种工具,用于填充不需要的或丢失的图像部分。论文《具有感知和上下文损失的语义图像修复》使用 DCGAN 进行图像补全,并学习如何填充部分图像。

实现变分自编码器

变分自编码器VAE)是神经网络和贝叶斯推理两者的最佳结合。 它们是最酷的神经网络,并已成为无监督学习的流行方法之一。 它们是自编码器。 与传统的编码器和自编码器的解码器网络(请参阅第 8 章“自编码器”)一起,它们还具有其他随机层。 编码器网络之后的随机层使用高斯分布对数据进行采样,解码器网络之后的随机层使用伯努利分布对数据进行采样。 像 GAN 一样,可以使用变分自编码器根据经过训练的分布来生成图像和图形。 VAE 允许人们设置潜在的复杂先验,从而学习强大的潜在表示。

下图描述了 VAE。 编码器网络qᵩ(z | x)逼近真实但棘手的后验分布p(z | x),其中x是 VAE 的输入,z是潜在表示。 解码器网络p[ϴ](x | z)d维潜在变量(也称为潜在空间)作为其输入,并且分布与P(x)相同。 从z | x ~ N(μ[z|x], Σ[z|x])中采样潜在表示z,解码器网络的输出从x | z ~ N(μ[x|z], Σ[x|z])中采样x | z

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-od5zL3w9-1681565377468)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/cc5ebb49-22fd-4e57-9992-6643c79fee21.png)]

自动编码器的编码器-解码器示例。

准备

既然我们已经掌握了 VAE 的基本架构,那么就出现了一个问题,即如何对它们进行训练,因为训练数据的最大可能性和后验密度是很难解决的? 通过最大化日志数据可能性的下限来训练网络。 因此,损耗项包括两个部分:生成损耗,它是通过解码器网络通过采样获得的;以及 KL 发散项,也称为潜在损耗。

生成损失确保解码器生成的图像和用于训练网络的图像相同,而潜在损失确保后验分布qᵩ(z | x)接近先前的p[ϴ](z)。 由于编码器使用高斯分布进行采样,因此潜在损失可以衡量潜在变量与单位高斯的匹配程度。

对 VAE 进行训练后,我们只能使用解码器网络来生成新图像。

操作步骤

此处的代码基于 Kingma 和 Welling 的论文自动编码变分贝叶斯,并改编自 GitHub。

  1. 第一步是始终导入必要的模块。 对于此秘籍,我们将需要 Numpy,Matplolib 和 TensorFlow:
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
%matplotlib inline
  1. 接下来,我们定义VariationalAutoencoder类。 class __init__ method定义了超参数,例如学习率,批量大小,输入的占位符以及编码器和解码器网络的权重和偏差变量。 它还根据 VAE 的网络架构构建计算图。 在此秘籍中,我们使用 Xavier 初始化来初始化权重。 我们没有定义自己的 Xavier 初始化方法,而是使用tf.contrib.layers.xavier_initializer() TensorFlow 来完成任务。 最后,我们定义损失(生成和潜在)和优化器操作:
class VariationalAutoencoder(object):def __init__(self, network_architecture,   transfer_fct=tf.nn.softplus,
learning_rate=0.001, batch_size=100):self.network_architecture = network_architectureself.transfer_fct = transfer_fctself.learning_rate = learning_rateself.batch_size = batch_size# Place holder for the inputself.x = tf.placeholder(tf.float32, [None,    network_architecture["n_input"]])# Define weights and biasesnetwork_weights = self._initialize_weights(**self.network_architecture)# Create autoencoder network# Use Encoder Network to determine mean and# (log) variance of Gaussian distribution in latent# spaceself.z_mean, self.z_log_sigma_sq = \self._encoder_network(network_weights["weights_encoder"],network_weights["biases_encoder"])# Draw one sample z from Gaussian distributionn_z = self.network_architecture["n_z"]eps = tf.random_normal((self.batch_size, n_z), 0, 1, dtype=tf.float32)# z = mu + sigma*epsilonself.z =       tf.add(self.z_mean,tf.multiply(tf.sqrt(tf.exp(self.z_log_sigma_sq)), eps))# Use Decoder network to determine mean of# Bernoulli distribution of reconstructed inputself.x_reconstr_mean = \self._decoder_network(network_weights["weights_decoder"],network_weights["biases_decoder"])# Define loss function based variational upper-bound and # corresponding optimizer# define generation lossgeneration_loss = \-tf.reduce_sum(self.x * tf.log(1e-10 + self.x_reconstr_mean)
+ (1-self.x) * tf.log(1e-10 + 1 - self.x_reconstr_mean), 1)latent_loss = -0.5 * tf.reduce_sum(1 + self.z_log_sigma_sq
- tf.square(self.z_mean)- tf.exp(self.z_log_sigma_sq), 1)self.cost = tf.reduce_mean(generation_loss + latent_loss)       #    average over batch# Define the optimizerself.optimizer = \tf.train.AdamOptimizer(learning_rate=self.learning_rate).minimize(self.cost)# Initializing the tensor flow variablesinit = tf.global_variables_initializer()# Launch the sessionself.sess = tf.InteractiveSession()self.sess.run(init)def _initialize_weights(self, n_hidden_recog_1, n_hidden_recog_2,
n_hidden_gener_1, n_hidden_gener_2,
n_input, n_z):initializer = tf.contrib.layers.xavier_initializer()all_weights = dict()all_weights['weights_encoder'] = {'h1': tf.Variable(initializer(shape=(n_input, n_hidden_recog_1))),'h2': tf.Variable(initializer(shape=(n_hidden_recog_1, n_hidden_recog_2))),'out_mean': tf.Variable(initializer(shape=(n_hidden_recog_2, n_z))),'out_log_sigma': tf.Variable(initializer(shape=(n_hidden_recog_2, n_z)))}all_weights['biases_encoder'] = {'b1': tf.Variable(tf.zeros([n_hidden_recog_1], dtype=tf.float32)),'b2': tf.Variable(tf.zeros([n_hidden_recog_2], dtype=tf.float32)),'out_mean': tf.Variable(tf.zeros([n_z], dtype=tf.float32)),'out_log_sigma': tf.Variable(tf.zeros([n_z], dtype=tf.float32))}all_weights['weights_decoder'] = {'h1': tf.Variable(initializer(shape=(n_z, n_hidden_gener_1))),'h2': tf.Variable(initializer(shape=(n_hidden_gener_1, n_hidden_gener_2))),'out_mean': tf.Variable(initializer(shape=(n_hidden_gener_2, n_input))),'out_log_sigma': tf.Variable(initializer(shape=(n_hidden_gener_2, n_input)))}all_weights['biases_decoder'] = {'b1': tf.Variable(tf.zeros([n_hidden_gener_1],    dtype=tf.float32)),'b2': tf.Variable(tf.zeros([n_hidden_gener_2], dtype=tf.float32)),'out_mean': tf.Variable(tf.zeros([n_input], dtype=tf.float32)),'out_log_sigma': tf.Variable(tf.zeros([n_input], dtype=tf.float32))}return all_weights
  1. 我们建立编码器网络和解码器网络。 编码器网络的第一层正在获取输入并生成输入的简化的潜在表示。 第二层将输入映射到高斯分布。 网络学习了以下转换:
def _encoder_network(self, weights, biases):# Generate probabilistic encoder (recognition network), which# maps inputs onto a normal distribution in latent space.# The transformation is parametrized and can be learned.layer_1 = self.transfer_fct(tf.add(tf.matmul(self.x,     weights['h1']),
biases['b1']))layer_2 = self.transfer_fct(tf.add(tf.matmul(layer_1,   weights['h2']),
biases['b2']))z_mean = tf.add(tf.matmul(layer_2, weights['out_mean']),
biases['out_mean'])z_log_sigma_sq = \
tf.add(tf.matmul(layer_2, weights['out_log_sigma']),
biases['out_log_sigma'])return (z_mean, z_log_sigma_sq)def _decoder_network(self, weights, biases):# Generate probabilistic decoder (decoder network), which# maps points in latent space onto a Bernoulli distribution in data space.# The transformation is parametrized and can be learned.layer_1 = self.transfer_fct(tf.add(tf.matmul(self.z, weights['h1']),
biases['b1']))layer_2 = self.transfer_fct(tf.add(tf.matmul(layer_1, weights['h2']),
biases['b2']))x_reconstr_mean = \
tf.nn.sigmoid(tf.add(tf.matmul(layer_2, weights['out_mean']),biases['out_mean']))return x_reconstr_mean
  1. VariationalAutoencoder类还包含一些辅助函数,用于生成和重建数据并适合 VAE:
def fit(self, X):opt, cost = self.sess.run((self.optimizer, self.cost),feed_dict={self.x: X})return costdef generate(self, z_mu=None):
""" Generate data by sampling from latent space.
If z_mu is not None, data for this point in latent space is
generated. Otherwise, z_mu is drawn from prior in latent
space.
"""if z_mu is None:z_mu = np.random.normal(size=self.network_architecture["n_z"])
# Note: This maps to mean of distribution, we could alternatively
# sample from Gaussian distributionreturn self.sess.run(self.x_reconstr_mean,feed_dict={self.z: z_mu})def reconstruct(self, X):
""" Use VAE to reconstruct given data. """return self.sess.run(self.x_reconstr_mean,feed_dict={self.x: X})
  1. 一旦完成了 VAE 类,我们就定义了一个训练函数,它使用 VAE 类对象并为给定数据训练它。
def train(network_architecture, learning_rate=0.001,
batch_size=100, training_epochs=10, display_step=5):vae = VariationalAutoencoder(network_architecture,learning_rate=learning_rate,batch_size=batch_size)# Training cyclefor epoch in range(training_epochs):avg_cost = 0.total_batch = int(n_samples / batch_size)# Loop over all batchesfor i in range(total_batch):batch_xs, _ = mnist.train.next_batch(batch_size)# Fit training using batch datacost = vae.fit(batch_xs)# Compute average lossavg_cost += cost / n_samples * batch_size# Display logs per epoch stepif epoch % display_step == 0:print("Epoch:", '%04d' % (epoch+1), "cost=", "{:.9f}".format(avg_cost))return vae
  1. 现在让我们使用 VAE 类和训练函数。 我们将 VAE 用于我们最喜欢的 MNIST 数据集:
# Load MNIST data in a format suited for tensorflow.
# The script input_data is available under this URL:
#https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/tutorials/mnist/input_data.pyfrom tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
n_samples = mnist.train.num_examples
  1. 我们定义网络架构,并在 MNIST 数据集上进行 VAE 训练。 在这种情况下,为简单起见,我们保留潜在尺寸 2。
network_architecture = \
dict(n_hidden_recog_1=500, # 1st layer encoder neurons
n_hidden_recog_2=500, # 2nd layer encoder neurons
n_hidden_gener_1=500, # 1st layer decoder neurons
n_hidden_gener_2=500, # 2nd layer decoder neurons
n_input=784, # MNIST data input (img shape: 28*28)
n_z=2) # dimensionality of latent space
vae = train(network_architecture, training_epochs=75)
  1. 现在让我们看看 VAE 是否真正重建了输入。 输出结果表明确实可以重建数字,并且由于我们使用了 2D 潜在空间,因此图像明显模糊:
x_sample = mnist.test.next_batch(100)[0]
x_reconstruct = vae.reconstruct(x_sample)
plt.figure(figsize=(8, 12))
for i in range(5):plt.subplot(5, 2, 2*i + 1)plt.imshow(x_sample[i].reshape(28, 28),  vmin=0, vmax=1, cmap="gray")plt.title("Test input")plt.colorbar()plt.subplot(5, 2, 2*i + 2)plt.imshow(x_reconstruct[i].reshape(28, 28), vmin=0, vmax=1, cmap="gray")plt.title("Reconstruction")plt.colorbar()plt.tight_layout()

以下是上述代码的输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h3n2Eksf-1681565377469)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/c31805df-525c-4d4d-aa6f-4e8f3b2d2037.png)]

MNIST 重建字符的示例

  1. 以下是使用经过训练的 VAE 生成的手写数字示例:
nx = ny = 20
x_values = np.linspace(-3, 3, nx)
y_values = np.linspace(-3, 3, ny)
canvas = np.empty((28*ny, 28*nx))
for i, yi in enumerate(x_values):for j, xi in enumerate(y_values):z_mu = np.array([[xi, yi]]*vae.batch_size)x_mean = vae.generate(z_mu)canvas[(nx-i-1)*28:(nx-i)*28, j*28:(j+1)*28] = x_mean[0].reshape(28, 28)
plt.figure(figsize=(8, 10))
Xi, Yi = np.meshgrid(x_values, y_values)
plt.imshow(canvas, origin="upper", cmap="gray")
plt.tight_layout()

以下是自编码器生成的 MNIST 类字符的范围:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8dRJKnJc-1681565377469)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/a797224e-349b-4e69-864c-5beae8fe0092.png)]

由自动编码器生成的一系列 MNIST 字符

工作原理

VAE 学会重建并同时生成新图像。 生成的图像取决于潜在空间。 生成的图像与训练的数据集具有相同的分布。

我们还可以通过在VariationalAutoencoder类中定义一个转换函数来查看潜在空间中的数据:

def transform(self, X):"""Transform data by mapping it into the latent space."""# Note: This maps to mean of distribution, we could alternatively sample from Gaussian distributionreturn self.sess.run(self.z_mean,   feed_dict={self.x: X})

使用转换函数的 MNIST 数据集的潜在表示如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s5Zn0ESU-1681565377469)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/2bb795f1-19cc-4f46-8c1f-d896d3b0e01c.png)]

更多

VAE 的生成图像取决于潜在空间尺寸。 模糊减少了潜在空间的尺寸,增加了。 分别针对 5 维,10 维和 20 维潜在维度的重构图像如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e04s6cH6-1681565377469)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/7619532a-5c71-4c3f-9a89-4093fede393a.png)]

另见

Kingma 和 Welling 的论文是该领域的开创性论文。 他们会经历完整的架构思维过程以及优雅的数学运算。 对于对 VAE 感兴趣的任何人,必须阅读。

另一个有趣的读物是 Carl Doersch 的论文,变分编码器教程。

Github 链接包含 VAE 的另一种实现,以及来自 Kingma 和 Welling 论文的图像再现。

通过胶囊网络学习击败 MNIST 的最新结果

胶囊网络(或 CapsNets)是一种非常新颖的深度学习网络。 这项技术是在 2017 年 10 月底由 Sara Sabour,Nicholas Frost 和 Geoffrey Hinton 发表的名为《胶囊之间的动态路由》的开创性论文中引入的。 欣顿(Hinton)是深度学习之父之一,因此,整个深度学习社区很高兴看到胶囊技术取得的进步。 确实,CapsNets 已经在 MNIST 分类中击败了最好的 CNN,这真是……令人印象深刻!

那么 CNN 有什么问题? 在 CNN 中,每一层都会以渐进的粒度理解图像。 正如我们在多种秘籍中讨论的那样,第一层将最有可能识别直线或简单的曲线和边缘,而随后的层将开始理解更复杂的形状(例如矩形)和复杂的形式(例如人脸)。

现在,用于 CNN 的一项关键操作是池化。 池化旨在创建位置不变性,通常在每个 CNN 层之后使用它来使任何问题在计算上易于处理。 但是,合并会带来一个严重的问题,因为它迫使我们丢失所有位置数据。 不是很好。 考虑一下脸:它由两只眼睛,一张嘴和一只鼻子组成,重要的是这些部分之间存在空间关系(嘴在鼻子下方,通常在眼睛下方)。 确实,欣顿说:

卷积神经网络中使用的池化操作是一个很大的错误,它运行良好的事实是一场灾难。

从技术上讲,我们不需要位置不变。 相反,我们需要等方差。 等方差是一个奇特的术语,表示我们想了解图像中的旋转或比例变化,并且我们要相应地调整网络。 这样,图像中不同成分的空间定位不会丢失。

那么胶囊网络有什么新功能? 据作者说,我们的大脑有称为胶囊的模块,每个胶囊专门处理特定类型的信息。 尤其是,有些胶囊对于理解位置的概念,尺寸的概念,方向的概念,变形的概念,纹理等非常有用。 除此之外,这组作者还建议我们的大脑具有特别有效的机制,可以将每条信息动态路由到胶囊,这被认为最适合处理特定类型的信息。

因此,CNN 和 CapsNets 之间的主要区别在于,使用 CNN 时,您会不断添加用于创建深度网络的层,而使用 CapsNet 时,您会在另一个内部嵌套神经层。 胶囊是一组神经元,可在网络中引入更多结构。 它产生一个向量来表示图像中实体的存在。 尤其是,欣顿使用活动向量的长度来表示实体存在的概率,并使用其方向来表示实例化参数。 当多个预测结果一致时,更高级别的胶囊就会生效。 对于每个可能的父项,胶囊产生一个额外的预测向量。

现在有了第二项创新:我们将使用跨胶囊的动态路由,并且不再使用池化的原始思想。 较低级别的容器倾向于将其输出发送到较高级别的容器,并且活动向量的标量积很大,而预测来自较低级别的容器。 标量预测向量乘积最大的亲本会增加胶囊键。 所有其他父项都减少了联系。 换句话说,这种想法是,如果较高级别的胶囊同意较低级别的胶囊,则它将要求发送更多该类型的信息。 如果没有协议,它将要求发送更少的协议。 使用协定方法的这种动态路由优于当前的机制(例如最大池),并且根据 Hinton 的说法,路由最终是解析图像的一种方法。 实际上,最大池化忽略了除最大值以外的任何东西,而动态路由根据较低层和较高层之间的协议选择性地传播信息。

第三个差异是引入了新的非线性激活函数。 CapsNet 并未像在 CNN 中那样向每个层添加挤压函数,而是向嵌套的一组层添加了挤压函数。 下图表示了非线性激活函数,它被称为挤压函数(方程式 1):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7b8K4Bo5-1681565377469)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/8458f4ff-3e07-4dc7-999c-f7c2a45ba811.png)]

如欣顿的开创性论文中所示的压缩函数

此外,Hinton 等人表明,经过判别训练的多层胶囊系统在 MNIST 上达到了最先进的表现,并且在识别高度重叠的数字方面比卷积网络要好得多。

论文《胶囊之间的动态路由》向我们展示了简单的 CapsNet 架构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7AD6UN2i-1681565377470)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/606af41e-dc21-4840-8303-ecbd138d170c.png)]

简单的 CapsNet 架构

该架构很浅,只有两个卷积层和一个完全连接的层。 Conv1 具有 256 个9×9卷积核,步幅为 1,并具有 ReLU 激活函数。 该层的作用是将像素强度转换为局部特征检测器的活动,然后将其用作主胶囊的输入。 PrimaryCapsules 是具有 32 个通道的卷积胶囊层。 每个主胶囊包含 8 个卷积单元,其内核为9×9,步幅为 2。 总计,PrimaryCapsules 具有[32, 6, 6]胶囊输出(每个输出是 8D 向量),并且[6, 6]网格中的每个胶囊彼此共享权重。 最后一层(DigitCaps)每位数字类具有一个 16D 胶囊,这些胶囊中的每个胶囊都接收来自下一层中所有其他胶囊的输入。 路由仅发生在两个连续的胶囊层之间(例如 PrimaryCapsules 和 DigitCaps)。

准备

此秘籍基于这个页面上提供的代码,而该代码又基于这个页面。

操作步骤

这是我们如何进行秘籍的方法:

  1. 在 Apache Licence 下从 github 克隆代码:
git clone https://github.com/naturomics/CapsNet-Tensorflow.git$ cd CapsNet-Tensorflow
  1. 下载 MNIST 并创建适当的结构:
mkdir -p data/mnist
wget -c -P data/mnist \\
http://yann.lecun.com/exdb/mnist/{train-images-idx3-ubyte.gz,train-labels-idx1-ubyte.gz,t10k-images-idx3-ubyte.gz,t10k-labels-idx1-ubyte.gz}
gunzip data/mnist/*.gz
  1. 开始训练过程:
python main.py
  1. 让我们看看用于定义胶囊的代码。 每个胶囊将 4D 张量作为输入并返回 4D 张量。 可以将胶囊定义为完全连接的网络(DigiCaps)或卷积网络(主胶囊)。 请注意,Primary 是卷积网络的集合,在它们之后应用了非线性压缩函数。 主胶囊将通过动态路由与 DigiCaps 通信:
# capsLayer.py
#
import numpy as np
import tensorflow as tf
from config import cfg
epsilon = 1e-9
class CapsLayer(object):
''' Capsule layer.
Args:
input: A 4-D tensor.
num_outputs: the number of capsule in this layer.
vec_len: integer, the length of the output vector of a capsule.
layer_type: string, one of 'FC' or "CONV", the type of this layer,
fully connected or convolution, for the future expansion capability
with_routing: boolean, this capsule is routing with the
lower-level layer capsule.
Returns:
A 4-D tensor.
'''
def __init__(self, num_outputs, vec_len, with_routing=True, layer_type='FC'):self.num_outputs = num_outputsself.vec_len = vec_lenself.with_routing = with_routingself.layer_type = layer_typedef __call__(self, input, kernel_size=None, stride=None):
'''
The parameters 'kernel_size' and 'stride' will be used while 'layer_type' equal 'CONV'
'''if self.layer_type == 'CONV':self.kernel_size = kernel_sizeself.stride = strideif not self.with_routing:# the PrimaryCaps layer, a convolutional layer# input: [batch_size, 20, 20, 256]assert input.get_shape() ==  [cfg.batch_size, 20, 20, 256]capsules = []for i in range(self.vec_len):# each capsule i: [batch_size, 6, 6, 32]with tf.variable_scope('ConvUnit_' + str(i)):caps_i = tf.contrib.layers.conv2d(input,      self.num_outputs,
self.kernel_size, self.stride,
padding="VALID")caps_i = tf.reshape(caps_i, shape=(cfg.batch_size, -1, 1, 1))capsules.append(caps_i)assert capsules[0].get_shape() == [cfg.batch_size, 1152, 1, 1]
# [batch_size, 1152, 8, 1]capsules = tf.concat(capsules, axis=2)capsules = squash(capsules)assert capsules.get_shape() == [cfg.batch_size, 1152, 8, 1]return(capsules)if self.layer_type == 'FC':if self.with_routing:# the DigitCaps layer, a fully connected layer# Reshape the input into [batch_size, 1152, 1, 8, 1]self.input = tf.reshape(input, shape=(cfg.batch_size, -1, 1, input.shape[-2].value, 1))with tf.variable_scope('routing'):# b_IJ: [1, num_caps_l, num_caps_l_plus_1, 1, 1]b_IJ = tf.constant(np.zeros([1, input.shape[1].value,    self.num_outputs, 1, 1], dtype=np.float32))capsules = routing(self.input, b_IJ)capsules = tf.squeeze(capsules, axis=1)return(capsules)
  1. 论文《胶囊之间的动态路由》介绍了路由算法,相关章节中定义了等式 2 和等式 3。该路由算法的目标是将信息从较低层的胶囊传递到较高层的胶囊,并且了解哪里有一致性。 通过简单地使用上层中每个胶囊j的当前输出v[j],和胶囊i得出的预测u_hat[j|i]的标量乘积,即可计算出一致性:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K8fXMYOY-1681565377470)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/3e855c22-8c24-4f2c-a2c2-2ec2abe382ae.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NTSWqzIX-1681565377470)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/ba247207-8cba-4016-9519-5623712ac87e.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UhBarhnz-1681565377470)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/ae5aab27-b9ef-49d7-aa4f-6de8cbd86bfa.png)]

以下方法实现了前面图像中过程 1 中描述的步骤。 注意,输入是来自l层中 1,152 个胶囊的 4D 张量。 输出是形状为[batch_size, 1, length(v_j)=16, 1]的张量,表示层l + 1中胶囊j的向量输出v[j]

def routing(input, b_IJ):
''' The routing algorithm.
Args:
input: A Tensor with [batch_size, num_caps_l=1152, 1, length(u_i)=8, 1]
shape, num_caps_l meaning the number of capsule in the layer l.
Returns:
A Tensor of shape [batch_size, num_caps_l_plus_1, length(v_j)=16, 1]
representing the vector output `v_j` in the layer l+1
Notes:
u_i represents the vector output of capsule i in the layer l, and
v_j the vector output of capsule j in the layer l+1.
'''# W: [num_caps_j, num_caps_i, len_u_i, len_v_j]W = tf.get_variable('Weight', shape=(1, 1152, 10, 8, 16), dtype=tf.float32,initializer=tf.random_normal_initializer(stddev=cfg.stddev))# Eq.2, calc u_hat# do tiling for input and W before matmul# input => [batch_size, 1152, 10, 8, 1]# W => [batch_size, 1152, 10, 8, 16]input = tf.tile(input, [1, 1, 10, 1, 1])W = tf.tile(W, [cfg.batch_size, 1, 1, 1, 1])assert input.get_shape() == [cfg.batch_size, 1152, 10, 8, 1]# in last 2 dims:# [8, 16].T x [8, 1] => [16, 1] => [batch_size, 1152, 10, 16, 1]u_hat = tf.matmul(W, input, transpose_a=True)assert u_hat.get_shape() == [cfg.batch_size, 1152, 10, 16, 1]# line 3,for r iterations dofor r_iter in range(cfg.iter_routing):with tf.variable_scope('iter_' + str(r_iter)):# line 4:# => [1, 1152, 10, 1, 1]c_IJ = tf.nn.softmax(b_IJ, dim=2)c_IJ = tf.tile(c_IJ, [cfg.batch_size, 1, 1, 1, 1])assert c_IJ.get_shape() == [cfg.batch_size, 1152, 10, 1, 1]# line 5:# weighting u_hat with c_IJ, element-wise in the last two dims# => [batch_size, 1152, 10, 16, 1]s_J = tf.multiply(c_IJ, u_hat)# then sum in the second dim, resulting in [batch_size, 1, 10, 16, 1]s_J = tf.reduce_sum(s_J, axis=1, keep_dims=True)assert s_J.get_shape() == [cfg.batch_size, 1, 10, 16, 16# line 6:# squash using Eq.1,v_J = squash(s_J)assert v_J.get_shape() == [cfg.batch_size, 1, 10, 16, 1]# line 7:# reshape & tile v_j from [batch_size ,1, 10, 16, 1] to [batch_size, 10, 1152, 16, 1]# then matmul in the last tow dim: [16, 1].T x [16, 1] => [1, 1], reduce mean in the# batch_size dim, resulting in [1, 1152, 10, 1, 1]v_J_tiled = tf.tile(v_J, [1, 1152, 1, 1, 1])u_produce_v = tf.matmul(u_hat, v_J_tiled, transpose_a=True)assert u_produce_v.get_shape() == [cfg.batch_size, 1152, 10, 1, 1]b_IJ += tf.reduce_sum(u_produce_v, axis=0, keep_dims=True)return(v_J)
  1. 现在让我们回顾一下非线性激活压缩函数。 输入是具有[batch_size, num_caps, vec_len, 1]形状的 4D 向量,输出是具有与向量相同形状但被压缩在第三维和第四维中的 4-D 张量。 给定一个向量输入,目标是计算公式 1 中表示的值,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R9iNjHMu-1681565377471)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/5f34ce65-7b14-49ba-8306-4363f511eeba.png)]

def squash(vector):
'''Squashing function corresponding to Eq. 1
Args:
vector: A 5-D tensor with shape [batch_size, 1, num_caps, vec_len, 1],
Returns:
A 5-D tensor with the same shape as vector but squashed in 4rd and 5th dimensions.
'''vec_squared_norm = tf.reduce_sum(tf.square(vector), -2, keep_dims=True)scalar_factor = vec_squared_norm / (1 + vec_squared_norm) / tf.sqrt(vec_squared_norm + epsilon)vec_squashed = scalar_factor * vector # element-wise
return(vec_squashed)
  1. 在前面的步骤中,我们定义了什么是胶囊,胶囊之间的动态路由算法,以及非线性压缩函数。 现在我们可以定义适当的 CapsNet。 构建损失函数以进行训练,并选择了 Adam 优化器。 方法build_arch(...)定义了 CapsNet,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3EfA0bAx-1681565377471)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/23a91cd5-8c50-4e92-82bd-7af58ec34e02.png)]

请注意,本文将重构技术描述为一种正则化方法。 从本文:

我们使用额外的重建损失来鼓励数字囊对输入数字的实例化参数进行编码。 在训练过程中,我们会掩盖除正确数字胶囊外的所有活动向量。

然后,我们使用此活动向量进行重构。

数字胶囊的输出被馈送到解码器,该解码器由三个完全连接的层组成,这些层对像素强度进行建模,如图 2 所示。我们将逻辑单元的输出与像素强度之间的平方差之和最小化。 我们将这种重建损失降低了 0.0005,以使其在训练过程中不会控制保证金损失。 如下实现的方法build_arch(..)也用于创建解码器:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-POhgRqwc-1681565377471)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/10c4db98-f00c-4813-8452-4fcc86fc5d61.png)]

#capsNet.py
#
import tensorflow as tf
from config import cfg
from utils import get_batch_data
from capsLayer import CapsLayer
epsilon = 1e-9class CapsNet(object):def __init__(self, is_training=True):self.graph = tf.Graph()with self.graph.as_default():if is_training:self.X, self.labels = get_batch_data()self.Y = tf.one_hot(self.labels, depth=10, axis=1, dtype=tf.float32)self.build_arch()self.loss()self._summary()# t_vars = tf.trainable_variables()self.global_step = tf.Variable(0, name='global_step', trainable=False)self.optimizer = tf.train.AdamOptimizer()self.train_op =    self.optimizer.minimize(self.total_loss, global_step=self.global_step) # var_list=t_vars)elif cfg.mask_with_y:self.X = tf.placeholder(tf.float32,shape=(cfg.batch_size, 28, 28, 1))self.Y = tf.placeholder(tf.float32, shape=(cfg.batch_size, 10, 1))self.build_arch()else:self.X = tf.placeholder(tf.float32,shape=(cfg.batch_size, 28, 28, 1))self.build_arch()tf.logging.info('Setting up the main structure')def build_arch(self):with tf.variable_scope('Conv1_layer'):# Conv1, [batch_size, 20, 20, 256]conv1 = tf.contrib.layers.conv2d(self.X, num_outputs=256,kernel_size=9, stride=1, padding='VALID')assert conv1.get_shape() == [cfg.batch_size, 20, 20, 256]# Primary Capsules layer, return [batch_size, 1152, 8, 1]with tf.variable_scope('PrimaryCaps_layer'):primaryCaps = CapsLayer(num_outputs=32, vec_len=8,   with_routing=False, layer_type='CONV')caps1 = primaryCaps(conv1, kernel_size=9, stride=2)assert caps1.get_shape() == [cfg.batch_size, 1152, 8, 1]# DigitCaps layer, return [batch_size, 10, 16, 1]with tf.variable_scope('DigitCaps_layer'):digitCaps = CapsLayer(num_outputs=10, vec_len=16,   with_routing=True, layer_type='FC')self.caps2 = digitCaps(caps1)# Decoder structure in Fig. 2# 1\. Do masking, how:with tf.variable_scope('Masking'):# a). calc ||v_c||, then do softmax(||v_c||)# [batch_size, 10, 16, 1] => [batch_size, 10, 1, 1]self.v_length = tf.sqrt(tf.reduce_sum(tf.square(self.caps2),
axis=2, keep_dims=True) + epsilon)self.softmax_v = tf.nn.softmax(self.v_length, dim=1)assert self.softmax_v.get_shape() == [cfg.batch_size, 10, 1, 1]# b). pick out the index of max softmax val of the 10 caps# [batch_size, 10, 1, 1] => [batch_size] (index)self.argmax_idx = tf.to_int32(tf.argmax(self.softmax_v, axis=1))assert self.argmax_idx.get_shape() == [cfg.batch_size, 1, 1]self.argmax_idx = tf.reshape(self.argmax_idx, shape=(cfg.batch_size, )) .  # Method 1.if not cfg.mask_with_y:# c). indexing# It's not easy to understand the indexing process with  argmax_idx# as we are 3-dim animalmasked_v = []for batch_size in range(cfg.batch_size):v = self.caps2[batch_size][self.argmax_idx[batch_size], :]masked_v.append(tf.reshape(v, shape=(1, 1, 16, 1)))self.masked_v = tf.concat(masked_v, axis=0)assert self.masked_v.get_shape() == [cfg.batch_size, 1, 16, 1]# Method 2\. masking with true label, default modeelse:self.masked_v = tf.matmul(tf.squeeze(self.caps2), tf.reshape(self.Y, (-1, 10, 1)), transpose_a=True)self.v_length = tf.sqrt(tf.reduce_sum(tf.square(self.caps2), axis=2, keep_dims=True) + epsilon)# 2\. Reconstruct the MNIST images with 3 FC layers# [batch_size, 1, 16, 1] => [batch_size, 16] => [batch_size, 512] with tf.variable_scope('Decoder'):vector_j = tf.reshape(self.masked_v, shape=(cfg.batch_size, -1))fc1 = tf.contrib.layers.fully_connected(vector_j, num_outputs=512)assert fc1.get_shape() == [cfg.batch_size, 512]fc2 = tf.contrib.layers.fully_connected(fc1, num_outputs=1024)assert fc2.get_shape() == [cfg.batch_size, 1024]self.decoded = tf.contrib.layers.fully_connected(fc2, num_outputs=784, activation_fn=tf.sigmoid)
  1. 本文中定义的另一个重要部分是保证金损失函数。 这在下面的论文(等式 4)的摘录引用中进行了说明,并在loss(..)方法中实现,该方法包括三个损失,即边际损失,重建损失和总损失:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TgYDAQjf-1681565377472)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/20736fea-ef6c-43ae-9106-602a15f34251.png)]

def loss(self):# 1\. The margin loss# [batch_size, 10, 1, 1]# max_l = max(0, m_plus-||v_c||)^2max_l = tf.square(tf.maximum(0., cfg.m_plus - self.v_length))# max_r = max(0, ||v_c||-m_minus)^2max_r = tf.square(tf.maximum(0., self.v_length - cfg.m_minus))assert max_l.get_shape() == [cfg.batch_size, 10, 1, 1]# reshape: [batch_size, 10, 1, 1] => [batch_size, 10]max_l = tf.reshape(max_l, shape=(cfg.batch_size, -1))max_r = tf.reshape(max_r, shape=(cfg.batch_size, -1))# calc T_c: [batch_size, 10]T_c = self.Y# [batch_size, 10], element-wise multiplyL_c = T_c * max_l + cfg.lambda_val * (1 - T_c) * max_rself.margin_loss = tf.reduce_mean(tf.reduce_sum(L_c, axis=1))# 2\. The reconstruction lossorgin = tf.reshape(self.X, shape=(cfg.batch_size, -1))squared = tf.square(self.decoded - orgin)self.reconstruction_err = tf.reduce_mean(squared)# 3\. Total loss# The paper uses sum of squared error as reconstruction   error, but we# have used reduce_mean in `# 2 The reconstruction loss` to calculate# mean squared error. In order to keep in line with the paper,the# regularization scale should be 0.0005*784=0.392self.total_loss = self.margin_loss + cfg.regularization_scale * self.reconstruction_err
  1. 另外,定义a _summary(...)方法来报告损失和准确率可能会很方便:
#Summary
def _summary(self):train_summary = []train_summary.append(tf.summary.scalar('train/margin_loss', self.margin_loss))train_summary.append(tf.summary.scalar('train/reconstruction_loss', self.reconstruction_err))train_summary.append(tf.summary.scalar('train/total_loss', self.total_loss))recon_img = tf.reshape(self.decoded, shape=(cfg.batch_size, 28, 28, 1))train_summary.append(tf.summary.image('reconstruction_img', recon_img))correct_prediction = tf.equal(tf.to_int32(self.labels), self.argmax_idx)self.batch_accuracy = tf.reduce_sum(tf.cast(correct_prediction, tf.float32))self.test_acc = tf.placeholder_with_default(tf.constant(0.), shape=[])test_summary = []test_summary.append(tf.summary.scalar('test/accuracy', self.test_acc))self.train_summary = tf.summary.merge(train_summary)self.test_summary = tf.summary.merge(test_summary)

工作原理

CapsNet 与最先进的深度学习网络有很大的不同。 CapsNet 并没有添加更多的层并使网络更深,而是使用了浅层网络,其中,胶囊层嵌套在其他层内。 每个胶囊专门用于检测图像中的特定实体,并且使用动态路由机制将检测到的实体发送给父层。 使用 CNN,您必须从许多不同角度考虑成千上万张图像,以便从不同角度识别物体。 Hinton 认为,这些层中的冗余将使胶囊网络能够从多个角度和在不同情况下以 CNN 通常使用的较少数据识别对象。 让我们检查一下 tensorboad 所示的网络:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-24MhxpOb-1681565377472)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/23569842-8cea-4cde-a5ed-39ed16b08d7a.png)]

代码中定义并由 tensorboard 显示的 CapsNet 示例

如下图所示,其结果令人印象深刻。 CapsNet 在以前仅在更深层的网络中才能实现的三层网络上具有较低的测试误差(0.25%)。 基线是具有256, 256-128个通道的三个卷积层的标准 CNN。 每个都有5 x 5个内核,步幅为 1。最后一个卷积层后面是两个大小为328, 192 的完全连接的层。 最后一个完全连接的层通过压降连接到具有交叉熵损失的 10 类 softmax 层:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RVcIWBVW-1681565377472)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/19bafff9-7a12-40a4-91ef-68a4f2d51577.png)]

让我们检查保证金损失,重建损失和总损失的减少:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eWqEHHmB-1681565377472)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/2917c003-d3e1-46f7-891a-b4e15197ee89.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g0KttDgF-1681565377473)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/467c0b72-d272-43f9-a763-84f088317f09.png)]

我们还要检查准确率的提高; 经过 500 次迭代,它在 3500 次迭代中分别达到 92% 和 98.46% :

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pv2aup03-1681565377474)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/6007750c-8a79-4239-ad01-5ebaff4f3986.png)]

迭代 精度
500 0.922776442308
1000 0.959735576923
1500 0.971955128205
2000 0.978365384615
2500 0.981770833333
3000 0.983473557692
3500 0.984675480769

CapsNet 提高准确率的示例

更多

CapsNets 在 MNIST 上可以很好地工作,但是在理解是否可以在其他数据集(例如 CIFAR)或更通用的图像集合上获得相同的令人印象深刻的结果方面,还有很多研究工作要做。 如果您有兴趣了解更多信息,请查看以下内容:

Google 的 AI 向导在神经网络上带来了新的变化

Google 研究人员可以替代传统神经网络

Keras-CapsNet 是可在这个页面上使用的 Keras 实现。

杰弗里·欣顿(Geoffrey Hinton)讨论了卷积神经网络的问题

十二、分布式 TensorFlow 和云深度学习

在本章中,我们将讨论使用分布式 TensorFlow 和云深度学习。 我们将为您提供一些秘籍:

  • 使用 TensorFlow 和 GPU
  • 使用分布式 TensorFlow:多个 GPU 和一个 CPU
  • 使用分布式 TensorFlow:多台服务器
  • 训练分布式 TensorFlow MNIST 分类器
  • 使用 TensorFlow Serving 和 Docker
  • 使用 Compute Engine 在 Google Cloud(GCP)上运行分布式 TensorFlow
  • 在 Google CloudML 上运行分布式 TensorFlow
  • 在 Microsoft Azure 上运行分布式 TensorFlow
  • 在 Amazon AWS 上运行分布式 TensorFlow

介绍

每个 TensorFlow 计算均以图描述。 这允许在结构和操作的放置方面具有自然的灵活性,可以在计算的分布式节点之间拆分操作。 该图可以拆分为多个子图,这些子图分配给服务器集群中的不同节点。

我强烈建议读者看一看大型分布式深度网络(Jeffrey Dean,Greg S.Corrado,Rajat Monga,Kai Chen,Matthieu Devin,Quoc V.Le,Mark Z.Mao,Marc’Aurelio Ranzato,Andrew Senior ,Paul Tucker,Ke Yang 和 Andrew Y. Ng。 NIPS,2012 年)

本文的一项关键结果是证明可以运行分布式随机梯度下降SGD),其中多个节点在数据碎片上并行工作,并且通过将更新发送到参数服务器,来实现梯度的独立和异步更新。 引用论文摘要:

我们的实验揭示了关于大规模非凸优化的几个令人惊讶的结果。 首先,异步 SGD 很少用于非凸问题,对于训练深度网络非常有效,特别是与 Adagrad 自适应学习率结合使用时。

下图取自论文本身,很好地说明了这一点:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6FjXrRU4-1681565377474)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/b2700755-61ba-44f4-82aa-a60e2dd7f16c.png)]

来自参数服务器的分布式梯度下降示例

您应该阅读的另一份文档是白皮书《TensorFlow:异构分布式系统上的大规模机器学习》(MartínAbadi 等人,2015 年 11 月)

考虑其中包含的一些示例,我们可以在下面的图片的左侧看到 TensorFlow 代码的片段,然后将其表示为右侧的图形:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gf5TBxh4-1681565377474)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/b5cffc2b-9734-4179-abfb-71abe9fa4fa5.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ppNstFO1-1681565377475)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/4eaf774e-bf1e-423f-bd04-bbbe56dfe2d4.png)]

TensorFlow 图的示例

通过进行本地计算并在需要时透明地将远程通信节点添加到图,可以在多个节点之间划分图。 下图中对此作了很好的解释,该图仍取自前面提到的论文:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hOGw2dSf-1681565377475)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/bceaef6d-d560-4a58-9f7e-01797bfa3350.png)]

摘自以下内容的分布式 TensorFlow 图计算示例

可以通过集中方式(下图的左侧)或分布式方式(右侧)来计算梯度下降和所有主要的优化器算法。 后者涉及一个主进程,该主进程与调配 GPU 和 CPU 的多个工作器进行对话:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QxTVAfid-1681565377475)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/96de5e4c-3af3-4ba3-9afa-6d1ad513b03c.png)]

摘自以下内容的单机和分布式系统结构示例和分布式 TensorFlow 图计算示例

分布式计算既可以是同步的(所有工作程序都在同时更新分片数据上的梯度),也可以是异步的(更新没有同时发生)。 后者通常可以实现更高的可伸缩性,并且在收敛到最佳解决方案方面,较大的图计算仍然可以很好地工作。 同样,这些图片均来自 TensorFlow 白皮书,如果您想了解更多信息,我强烈建议有兴趣的读者阅读本文:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DZpccZd5-1681565377475)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/9f6bb40e-2159-4bf9-84ab-cddfebc6ae9d.png)]

同步和异步数据并行训练的示例

使用 TensorFlow 和 GPU

在本秘籍中,我们将学习如何在 GPU 上使用 TensorFlow:执行的操作是在 CPU 或 GPU 上的简单矩阵乘法。

准备

第一步是安装支持 GPU 的 TensorFlow 版本。 正式的 TensorFlow 安装说明是您的起点。 请记住,您需要一个通过 CUDA 或 CuDNN 支持 GPU 的环境。

操作步骤

我们按以下步骤进行:

  1. 首先导入一些模块
import sys
import numpy as np
import tensorflow as tf
from datetime import datetime
  1. 从命令行获取要使用的处理单元的类型("gpu""cpu"
device_name = sys.argv[1] # Choose device from cmd line. Options: gpu or cpu
shape = (int(sys.argv[2]), int(sys.argv[2]))
if device_name == "gpu":device_name = "/gpu:0"
else:device_name = "/cpu:0"
  1. 在 GPU 或 CPU 上执行矩阵乘法。 按键说明与tf.device(device_name)一起使用。 它创建一个新的上下文管理器,告诉 TensorFlow 在 GPU 或 CPU 上执行这些操作
with tf.device(device_name):random_matrix = tf.random_uniform(shape=shape, minval=0, maxval=1)dot_operation = tf.matmul(random_matrix, tf.transpose(random_matrix))sum_operation = tf.reduce_sum(dot_operation)startTime = datetime.now()
with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as session:result = session.run(sum_operation)print(result)

4.打印一些调试时间,只是为了验证 CPU 和 GPU 有什么区别

print("Shape:", shape, "Device:", device_name)
print("Time taken:", datetime.now() - startTime)

工作原理

本秘籍说明了如何将 TensorFlow 计算分配给 CPU 或 GPU。 该代码非常简单,它将用作下一个秘籍的基础。

使用分布式 TensorFlow:多个 GPU 和一个 CPU

我们将展示一个数据并行化的示例,其中数据被拆分到多个 GPU 中

准备

此秘籍的灵感来自尼尔·特内霍尔茨(Neil Tenenholtz)撰写的一篇不错的博客文章,该文章可在线获取

操作步骤

我们按以下步骤进行:

  1. 考虑这段在单个 GPU 上运行矩阵乘法的代码。
# single GPU (baseline)
import tensorflow as tf
# place the initial data on the cpu
with tf.device('/cpu:0'):input_data = tf.Variable([[1., 2., 3.],[4., 5., 6.],[7., 8., 9.],[10., 11., 12.]])
b = tf.Variable([[1.], [1.], [2.]])# compute the result on the 0th gpu
with tf.device('/gpu:0'):output = tf.matmul(input_data, b)# create a session and run
with tf.Session() as sess:sess.run(tf.global_variables_initializer())print sess.run(output)
  1. 如图 2 所示,在 2 个不同的 GPU 之间使用代码复制对代码进行分区。 请注意,CPU 充当主节点来分发图并收集最终结果。
# in-graph replication
import tensorflow as tf
num_gpus = 2
# place the initial data on the cpu
with tf.device('/cpu:0'):input_data = tf.Variable([[1., 2., 3.],[4., 5., 6.],[7., 8., 9.],[10., 11., 12.]])b = tf.Variable([[1.], [1.], [2.]])# split the data into chunks for each gpu
inputs = tf.split(input_data, num_gpus)
outputs = []# loop over available gpus and pass input data
for i in range(num_gpus):with tf.device('/gpu:'+str(i)):outputs.append(tf.matmul(inputs[i], b))# merge the results of the devices
with tf.device('/cpu:0'):output = tf.concat(outputs, axis=0)# create a session and run
with tf.Session() as sess:sess.run(tf.global_variables_initializer())print sess.run(output)

工作原理

这是一个非常简单的方法,其中通过将 CPU 用作主对象并将其分配到两个用作分布式工作程序的 GPU,将图分为两部分。 计算结果被收集回 CPU。

使用分布式 TensorFlow:多台服务器

在本秘籍中,我们将学习如何在多个服务器之间分配 TensorFlow 计算。 关键假设是工作程序和参数服务器的代码都相同。 因此,每个计算节点的角色都传递给命令行参数。

准备

同样,此秘籍的灵感来自尼尔·特纳霍尔茨(Neil Tenenholtz)撰写的一篇不错的博客文章,该文章可在线获取

操作步骤

我们按以下步骤进行:

  1. 考虑这段代码,在此我们指定集群架构,其中一个主服务器运行在192.168.1.1:1111上,两个工作服务器分别运行在192.168.1.2:1111192.168.1.3:1111上。
import sys
import tensorflow as tf# specify the cluster's architecture
cluster = tf.train.ClusterSpec({'ps': ['192.168.1.1:1111'],'worker': ['192.168.1.2:1111','192.168.1.3:1111']
})
  1. 请注意,代码是在多台机器上复制的,因此了解当前执行节点的作用很重要。 我们从命令行获得此信息。 机器可以是工作程序,也可以是参数服务器(ps)。
# parse command-line to specify machine
job_type = sys.argv[1] # job type: "worker" or "ps"
task_idx = sys.argv[2] # index job in the worker or ps list
# as defined in the ClusterSpec
  1. 在给定群集的情况下运行训练服务器,我们为每个计算赋予一个角色(工作者或ps)和一个 ID。
# create TensorFlow Server. This is how the machines communicate.
server = tf.train.Server(cluster, job_name=job_type, task_index=task_idx)
  1. 根据特定计算节点的角色,计算是不同的:

    • 如果角色是参数服务器,则条件是要加入服务器。 请注意,在这种情况下,没有代码要执行,因为工作进程将不断推送更新,并且参数服务器唯一要做的就是等待。
    • 否则,工作程序代码将在集群中的特定设备上执行。 这部分代码类似于在一台机器上执行的代码,在该机器上我们首先构建模型,然后在本地对其进行训练。 请注意,所有工作分配和更新结果的收集都是由 Tensoflow 透明完成的。 请注意,TensorFlow 提供了方便的tf.train.replica_device_setter,可自动将操作分配给设备。
# parameter server is updated by remote clients.
# will not proceed beyond this if statement.
if job_type == 'ps':server.join()
else:# workers onlywith tf.device(tf.train.replica_device_setter(worker_device='/job:worker/task:'+task_idx,cluster=cluster)):
# build your model here as if you only were using a single machinewith tf.Session(server.target):# train your model here

工作原理

在本秘籍中,我们已经看到了如何创建具有多个计算节点的集群。 节点既可以扮演参数服务器的角色,也可以扮演工作者的角色。

在这两种情况下,根据从命令行收集的参数,执行的代码相同,但是代码的执行不同。 参数服务器仅需要等待,直到工作器发送更新。 请注意,tf.train.replica_device_setter(..)的作用是将操作自动分配给可用设备,而tf.train.ClusterSpec(..)则用于集群设置。

更多

可以在这个页面在线获取针对 MNIST 的分布式训练的示例。

此外,请注意,出于效率考虑,您可以决定拥有多个参数服务器。 使用参数,服务器可以提供更好的网络利用率,并且可以将模型扩展到更多并行计算机。 可以分配多个参数服务器。 有兴趣的读者可以看看这里

训练分布式 TensorFlow MNIST 分类器

此秘籍用于以分布式方式训练完​​整的 MNIST 分类器。 该秘籍的灵感来自这个页面中的博客文章,此处提供了在 TensorFlow 1.2 上运行的代码

准备

此秘籍基于上一个秘籍。 因此,按顺序阅读它们可能会很方便。

操作步骤

我们按以下步骤进行:

  1. 导入一些标准模块并定义运行计算的 TensorFlow 集群。 然后为特定任务启动服务器
import tensorflow as tf
import sys
import time
# cluster specification
parameter_servers = ["pc-01:2222"]
workers = [ "pc-02:2222",
"pc-03:2222",
"pc-04:2222"]
cluster = tf.train.ClusterSpec({"ps":parameter_servers, "worker":workers})
# input flags
tf.app.flags.DEFINE_string("job_name", "", "Either 'ps' or 'worker'")
tf.app.flags.DEFINE_integer("task_index", 0, "Index of task within the job")FLAGS = tf.app.flags.FLAGS
# start a server for a specific task
server = tf.train.Server(cluster,job_name=FLAGS.job_name,task_index=FLAGS.task_index)
  1. 读取 MNIST 数据并定义用于训练的超参数
# config
batch_size = 100
learning_rate = 0.0005
training_epochs = 20
logs_path = "/tmp/mnist/1"
# load mnist data set
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
  1. 检查您的角色是参数服务器还是工作器。 如果工作器随后定义了一个简单的密集神经网络,则定义一个优化器以及用于评估分类器的度量(例如准确率)。
if FLAGS.job_name == "ps":server.join()
elif FLAGS.job_name == "worker":
# Between-graph replication
with tf.device(tf.train.replica_device_setter(worker_device="/job:worker/task:%d" % FLAGS.task_index,cluster=cluster)):
# count the number of updatesglobal_step = tf.get_variable( 'global_step', [], initializer =      tf.constant_initializer(0),
trainable = False)# input imageswith tf.name_scope('input'):# None -> batch size can be any size, 784 -> flattened mnist imagex = tf.placeholder(tf.float32, shape=[None, 784], name="x-input")# target 10 output classesy_ = tf.placeholder(tf.float32, shape=[None, 10], name="y-input")# model parameters will change during training so we use tf.Variabletf.set_random_seed(1)with tf.name_scope("weights"):W1 = tf.Variable(tf.random_normal([784, 100]))W2 = tf.Variable(tf.random_normal([100, 10]))# biaswith tf.name_scope("biases"):b1 = tf.Variable(tf.zeros([100]))b2 = tf.Variable(tf.zeros([10]))# implement modelwith tf.name_scope("softmax"):# y is our predictionz2 = tf.add(tf.matmul(x,W1),b1)a2 = tf.nn.sigmoid(z2)z3 = tf.add(tf.matmul(a2,W2),b2)y = tf.nn.softmax(z3)# specify cost functionwith tf.name_scope('cross_entropy'):# this is our costcross_entropy = tf.reduce_mean(
-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))# specify optimizerwith tf.name_scope('train'):# optimizer is an "operation" which we can execute in a sessiongrad_op = tf.train.GradientDescentOptimizer(learning_rate)train_op = grad_op.minimize(cross_entropy, global_step=global_step)with tf.name_scope('Accuracy'):# accuracycorrect_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))# create a summary for our cost and accuracytf.summary.scalar("cost", cross_entropy)tf.summary.scalar("accuracy", accuracy)# merge all summaries into a single "operation" which we can execute in a sessionsummary_op = tf.summary.merge_all()init_op = tf.global_variables_initializer()print("Variables initialized ...")
  1. 启动一个主管,该主管充当分布式设置的首席计算机。 首要的是负责管理集群其余所有部分的工作机。 会话由负责人维护,关键指令为sv = tf.train.Supervisor(is_chief=(FLAGS.task_index == 0))。 同样,使用prepare_or_wait_for_session(server.target),主管将等待模型准备就绪可以使用。 请注意,每个工作器将处理不同的批量模型,然后最终模型可用于主管。
sv = tf.train.Supervisor(is_chief=(FLAGS.task_index == 0),
begin_time = time.time()
frequency = 100
with sv.prepare_or_wait_for_session(server.target) as sess:# create log writer object (this will log on every machine)writer = tf.summary.FileWriter(logs_path, graph=tf.get_default_graph())# perform training cyclesstart_time = time.time()for epoch in range(training_epochs):# number of batches in one epochbatch_count = int(mnist.train.num_examples/batch_size)count = 0for i in range(batch_count):batch_x, batch_y = mnist.train.next_batch(batch_size)# perform the operations we defined earlier on batch_, cost, summary, step = sess.run([train_op, cross_entropy, summary_op, global_step],feed_dict={x: batch_x, y_: batch_y})writer.add_summary(summary, step)count += 1if count % frequency == 0 or i+1 == batch_count:elapsed_time = time.time() - start_timestart_time = time.time()print("Step: %d," % (step+1)," Epoch: %2d," % (epoch+1), " Batch: %3d of %3d," % (i+1, batch_count)," Cost: %.4f," % cost,"AvgTime:%3.2fms" % float(elapsed_time*1000/frequency))count = 0print("Test-Accuracy: %2.2f" % sess.run(accuracy, feed_dict={x:  mnist.test.images, y_: mnist.test.labels}))print("Total Time: %3.2fs" % float(time.time() - begin_time))print("Final Cost: %.4f" % cost)sv.stop()print("done")

工作原理

本秘籍描述了分布式 MNIST 分类器的示例。 在此示例中,TensorFlow 允许我们定义三台机器的集群。 一台充当参数服务器,另外两台机器用作工作器,负责处理不同批次的训练数据。

使用 TensorFlow Serving 和 Docker

在本秘籍中,我们将展示如何为 TensorFlow Serving 运行 Docker 容器,这是一组组件以导出经过训练的 TensorFlow 模型并使用标准tensorflow_model_server为其提供服务。 TensorFlow Serving 服务器发现新导出的模型并运行 gRPC 服务来为其服务。

准备

我们将使用 Docker,并假设您熟悉该系统。 如果没有,请确保查看并安装。 我们要做的是构建 TF 服务版本。

操作步骤

这是我们进行秘籍的方法:

  1. 从这里下载Dockerfile.devel
  2. 通过运行以下来构建容器
docker build --pull -t $USER/tensorflow-serving-devel -f Dockerfile.devel
  1. 运行容器
docker run -it $USER/tensorflow-serving-devel
  1. 克隆 TensorFlow 服务,配置和测试服务器
git clone --recurse-submodules https://github.com/tensorflow/serving
cd serving/tensorflow
./configure
cd ..
bazel test tensorflow_serving/...
  1. 现在,让我们看一个保存模型的示例,以便服务器可以保存它。 此步骤的灵感来自用于构建 MNIST 训练器和服务模型的示例。 第一步是将构建器导入为saved_model_builder。 然后,大部分工作由SavedModelBuilder()完成,该工作将已训练模型的快照保存到可靠的存储中。 请注意,此处export_path/tmp/mnist_model/
from tensorflow.python.saved_model import builder as saved_model_builder
...
export_path_base = sys.argv[-1]
export_path = os.path.join(compat.as_bytes(export_path_base),compat.as_bytes(str(FLAGS.model_version)))
print 'Exporting trained model to', export_path
builder = saved_model_builder.SavedModelBuilder(export_path)
builder.add_meta_graph_and_variables(sess, [tag_constants.SERVING],signature_def_map={'predict_images':prediction_signature,signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:classification_signature,},legacy_init_op=legacy_init_op)
builder.save()
  1. 然后可以通过简单的命令为模型提供服务
tensorflow_model_server --port=9000 --model_name=mnist --model_base_path=/tmp/mnist_model/

工作原理

Google 在 2016 年 2 月发布了 TensorFlow Serving,这是一种针对机器学习模型的高性能服务系统,专为生产环境而设计。 截至 2017 年 8 月,谷歌内部有 800 多个使用 TensorFlow Serving 的项目投入生产。

更多

TensoFlow Serving 是一款非常通用的软件,在本秘籍中,我们只是初步探究了潜在用途。 如果您有兴趣进一步了解高级功能。 例如大批量运行或动态加载模型,则应查看这个页面

使用 Compute Engine 在 Google Cloud(GCP)上运行分布式 TensorFlow

在本秘籍中,我们将学习如何在 Google Cloud(GCP)上使用 Google Tensorflow。 我们将要审查的示例是经典 MNIST。

准备

看看 GCP 在 GoogleCloud 中的工作方式会很好。 请注意,GCP 提供 300 美元的免费赠金,以开始使用任何 GCP 产品。 此外,在免费试用期间和之后,某些产品针对符合条件的客户可以免费使用。 (优惠如有更改,请参见这个页面。

操作步骤

这是我们进行秘籍的方法:

  1. 通过网络控制台创建一个新的 Google Cloud 项目。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-73FV5Zfv-1681565377476)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/d91fcd12-0e0f-49ac-8a2f-976810b3e96d.png)]

单击创建项目时,将显示以下屏幕:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Snww30Tf-1681565377476)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/95c462d7-af82-4b17-bef3-adeaecd81236.png)]

  1. 通过选择控制台左侧栏上的相关语音,为该项目启用计费。 然后为该项目启用 Compute Engine 和 Cloud Machine Learning API:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VIhDnJq4-1681565377476)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/41ea2e03-f1d7-4aac-a6e3-33db31053786.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tn1usKNP-1681565377476)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/ed57ff64-af8b-43fb-a692-892811cf9dfb.png)]

  1. 登录到网络 cloudshell。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IonITbzT-1681565377476)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/848d8c7b-e216-41ff-82f2-17c390720f1e.png)]

  1. 从控制台运行以下命令,以配置将在其中执行计算的区域,下载示例代码以及创建用于运行代码的 VM。 最后连接到机器:
gcloud config set compute/zone us-east1-c
gcloud config set project [YOUR_PROJECT_ID]
git clone https://github.com/GoogleCloudPlatform/cloudml-dist-mnist-example
cd cloudml-dist-mnist-example
gcloud compute instances create template-instance \--image-project ubuntu-os-cloud \--image-family ubuntu-1604-lts \--boot-disk-size 10GB \--machine-type n1-standard-1
gcloud compute ssh template-instance
  1. 现在,登录到机器后,我们需要通过使用这些命令安装 PIP 和 TensorFlow 来设置环境。
sudo apt-get update
sudo apt-get -y upgrade \&& sudo apt-get install -y python-pip python-dev
sudo pip install tensorflow
sudo pip install --upgrade tensorflow
  1. 我们将有多个工作器对 MNIST 数据进行操作,因此最好的方法是创建一个在所有工作器之间共享的存储桶,并在该存储桶中复制 MNIST 数据
BUCKET="mnist-$RANDOM-$RANDOM"
gsutil mb -c regional -l us-east1 gs://${BUCKET}
sudo ./scripts/create_records.py
gsutil cp /tmp/data/train.tfrecords gs://${BUCKET}/data/
gsutil cp /tmp/data/test.tfrecords gs://${BUCKET}/data/
  1. 现在,我们将创建多个工作程序(worker-0worker-1),它们是初始模板实例计算机的克隆。 我们不希望计算机在关闭时删除磁盘,因此这就是我们拥有第一个命令的原因。
gcloud compute instances set-disk-auto-delete template-instance \--disk template-instance --no-auto-delete
gcloud compute instances delete template-instance
gcloud compute images create template-image \--source-disk template-instance
gcloud compute instances create \master-0 worker-0 worker-1 ps-0 \--image template-image \--machine-type n1-standard-4 \--scopes=default,storage-rw
  1. 最后一步是运行用于分布式训练的计算。
./scripts/start-training.sh gs://${BUCKET}

工作原理

演示脚本将代码移动到每个 VM 并开始分布式计算。 这两个工作程序在公共存储桶上共享的相同 MNIST 数据上并行运行。 计算结束后,脚本将打印训练后的模型的位置。

更多

如果我们不想管理 TensorFlow,那么我们可以决定使用 Google 代表您运行的托管版本。 这是在下一个秘籍中描述的 CloudML 服务。 此外,如果您决定不将 GPU 与 CloudML 一起使用,那么此 URL 是一个不错的起点

在 Google CloudML 上运行分布式 TensorFlow

CloudML 是 Google 运行的 Tensorflow 的托管版本。 无需自己运行 TF,您只需使用 CloudML 即可,而无需考虑与基础架构和可伸缩性相关的所有问题。

准备

在这里,我们假设您已经创建了一个 Cloud Platform Project,为您的项目启用计费,并启用了 Google Compute Engine 和 Cloud Machine Learning API。 这些步骤类似于先前秘籍中描述的步骤。 此秘籍的灵感来自这个页面中提供的 MNIST 训练代码。

操作步骤

我们继续在 Google CloudML 上运行分布式 TensorFlow:

  1. 第一步只是下载示例代码
git clonehttps://github.com/GoogleCloudPlatform/cloudml-dist-mnist-example
cd cloudml-dist-mnist-example
  1. 然后,我们下载数据并将其保存在 GCP 存储桶中
PROJECT_ID=$(gcloud config list project --format "value(core.project)")
BUCKET="${PROJECT_ID}-ml"
gsutil mb -c regional -l us-central1 gs://${BUCKET}
./scripts/create_records.py
gsutil cp /tmp/data/train.tfrecords gs://${BUCKET}/data/
gsutil cp /tmp/data/test.tfrecords gs://${BUCKET}/data/
  1. 提交训练工作非常简单:我们可以使用 CloudML 引擎简单地调用训练步骤。 在此示例中,训练人员代码在us-central1区域中运行 1000 次迭代。 输入数据是从存储桶中提取的,而输出桶将被提交到其他存储桶中。
JOB_NAME="job_$(date +%Y%m%d_%H%M%S)"
gcloud ml-engine jobs submit training ${JOB_NAME} \--package-path trainer \--module-name trainer.task \--staging-bucket gs://${BUCKET} \--job-dir gs://${BUCKET}/${JOB_NAME} \--runtime-version 1.2 \--region us-central1 \--config config/config.yaml \-- \--data_dir gs://${BUCKET}/data \--output_dir gs://${BUCKET}/${JOB_NAME} \--train_steps 10000
  1. 如果需要,您可以通过访问这个页面中的 CloudML 控制台来控制训练过程。
  2. 训练结束后,就可以直接从 CloudML 服务模型了
MODEL_NAME=MNIST
gcloud ml-engine models create --regions us-central1 ${MODEL_NAME}
VERSION_NAME=v1
ORIGIN=$(gsutil ls gs://${BUCKET}/${JOB_NAME}/export/Servo | tail -1)
gcloud ml-engine versions create \--origin ${ORIGIN} \--model ${MODEL_NAME} \
${VERSION_NAME}
gcloud ml-engine versions set-default --model ${MODEL_NAME} ${VERSION_NAME}
  1. 在线提供模型后,便可以访问服务器并做出预测。 通过使用脚本make_request.py创建request.json,该脚本从 MNIST 读取数据,执行一次热编码,然后使用格式正确的 json 模式编写功能。
gcloud ml-engine predict --model ${MODEL_NAME} --json-instances request.json

工作原理

CloudML 是使用 Google 运行的托管版本的 TensorFlow 的便捷解决方案。 除了直接照顾基础设施和运营,还可以直接专注于开发机器学习模型。

更多

CloudML 的一项非常酷的功能是能够通过并行运行多个试验来自动调整模型中包含的超参数的能力。 这为您提供了超参数的优化值,从而最大化了模型的预测精度。 如果您有兴趣了解更多信息,那么看看这里

在 Microsoft Azure 上运行分布式 TensorFlow

Microsoft Azure 提供了一项名为 Batch AI 的服务,该服务使我们能够在 Azure 虚拟机的群集上运行机器学习模型。

准备

第一步,我们需要一个 Azure 帐户:如果您还没有 Azure 帐户,则可以在此处免费创建一个帐户 。 Azure 向新用户提供为期 30 天的 200 美元信用额度。 此秘籍将遵循 Microsoft Azure 提供的示例,以使用 TensorFlow 分布式在两个 GPU 上运行 MNIST,相关代码可在 Github 上获得

操作步骤

我们按以下步骤进行:

  1. 第一步是安装 Azure CLI。 可在此处获得在不同 OS 平台上安装 Azure CLI 的详细信息。
  2. 在创建群集之前,您需要使用命令az login登录 Azure。 它将生成一个代码,并为您提供一个网站地址,将要求您在其中验证您的凭据,一旦网站上的所有步骤都结束,将要求您关闭并验证您的 az 凭据。
  3. 配置默认位置,创建和配置资源组。
az group create --name myResourceGroup --location eastus
az configure --defaults group=myResourceGroup
az configure --defaults location=eastus
  1. 接下来,我们将需要使用az命令创建存储,并根据您的操作系统设置环境变量,有关环境变量及其值的详细信息,请参见这里

  2. 下载并提取预处理的 MNIST 数据库

wget "https://batchaisamples.blob.core.windows.net/samples/mnist_dataset_original.zip?st=2017-09-29T18%3A29%3A00Z&se=2099-12-31T08%3A00%3A00Z&sp=rl&sv=2016-05-31&sr=b&sig=Qc1RA3zsXIP4oeioXutkL1PXIrHJO0pHJlppS2rID3I%3D" -O mnist_dataset_original.zip
unzip mnist_dataset_original.zip
  1. 下载mnist_replica
wget "https://raw.githubusercontent.com/Azure/BatchAI/master/recipes/TensorFlow/TensorFlow-GPU-Distributed/mnist_replica.py?token=AcZzrcpJGDHCUzsCyjlWiKVNfBuDdkqwks5Z4dPrwA%3D%3D" -O mnist_replica.py
  1. 接下来,创建一个 Azure 文件共享,在其中上传下载的 MNIST 数据集和mnist_replica.py文件。
az storage share create --name batchaisample
az storage directory create --share-name batchaisample --name mnist_dataset
az storage file upload --share-name batchaisample --source t10k-images-idx3-ubyte.gz --path mnist_dataset
az storage file upload --share-name batchaisample --source t10k-labels-idx1-ubyte.gz --path mnist_dataset
az storage file upload --share-name batchaisample --source train-images-idx3-ubyte.gz --path mnist_dataset
az storage file upload --share-name batchaisample --source train-labels-idx1-ubyte.gz --path mnist_dataset
az storage directory create --share-name batchaisample --name tensorflow_samples
az storage file upload --share-name batchaisample --source mnist_replica.py --path tensorflow_samples
  1. 现在,我们为该秘籍创建一个集群,该集群由具有 standard_NC6 大小的两个 GPU 节点组成,具有标准的 Ubuntu LTS 或 Ubuntu DVSM。 可以使用 Azure CLI 命令创建群集:

对于 Linux:

az batchai cluster create -n nc6 -i UbuntuDSVM -s Standard_NC6 --min 2 --max 2 --afs-name batchaisample --afs-mount-path external -u $USER -k ~/.ssh/id_rsa.pub

对于 Windows:

az batchai cluster create -n nc6 -i UbuntuDSVM -s Standard_NC6 --min 2 --max 2 --afs-name batchaisample --afs-mount-path external -u <user_name> -p <password>
  1. 下一步是在job.json文件中创建作业创建参数:
{"properties": {"nodeCount": 2,"tensorFlowSettings": {"parameterServerCount": 1,"workerCount": 2,"pythonScriptFilePath": "$AZ_BATCHAI_INPUT_SCRIPT/mnist_replica.py","masterCommandLineArgs": "--job_name=worker --num_gpus=1 --ps_hosts=$AZ_BATCHAI_PS_HOSTS --worker_hosts=$AZ_BATCHAI_WORKER_HOSTS --task_index=$AZ_BATCHAI_TASK_INDEX --data_dir=$AZ_BATCHAI_INPUT_DATASET --output_dir=$AZ_BATCHAI_OUTPUT_MODEL","workerCommandLineArgs": "--job_name=worker --num_gpus=1 --ps_hosts=$AZ_BATCHAI_PS_HOSTS --worker_hosts=$AZ_BATCHAI_WORKER_HOSTS --task_index=$AZ_BATCHAI_TASK_INDEX --data_dir=$AZ_BATCHAI_INPUT_DATASET --output_dir=$AZ_BATCHAI_OUTPUT_MODEL","parameterServerCommandLineArgs": "--job_name=ps --num_gpus=0 --ps_hosts=$AZ_BATCHAI_PS_HOSTS --worker_hosts=$AZ_BATCHAI_WORKER_HOSTS --task_index=$AZ_BATCHAI_TASK_INDEX --data_dir=$AZ_BATCHAI_INPUT_DATASET --output_dir=$AZ_BATCHAI_OUTPUT_MODEL"
},"stdOutErrPathPrefix": "$AZ_BATCHAI_MOUNT_ROOT/external","inputDirectories": [{"id": "DATASET","path": "$AZ_BATCHAI_MOUNT_ROOT/external/mnist_dataset"}, {"id": "SCRIPT","path": "$AZ_BATCHAI_MOUNT_ROOT/external/tensorflow_samples"}],"outputDirectories": [{"id": "MODEL","pathPrefix": "$AZ_BATCHAI_MOUNT_ROOT/external","pathSuffix": "Models"}],"containerSettings": {"imageSourceRegistry": {"image": "tensorflow/tensorflow:1.1.0-gpu"}}}
}
  1. 最后,使用以下命令创建 Batch AI 作业:
az batchai job create -n distibuted_tensorflow --cluster-name nc6 -c job.json

工作原理

Batch AI 自行管理资源,您只需要指定作业,输入的位置以及存储输出的位置即可。 如果在执行作业期间想要查看结果,则可以使用以下命令:

az batchai job stream-file --job-name myjob --output-directory-id stdouterr --name stderr.txt

作业结束后,您可以使用az batchai job deleteaz batchai cluster delete命令删除作业和群集。

更多

上面我们学习了如何使用 Azure 命令行工具将 Microsoft Azure Batch AI 用于分布式 TensorFlow。 我们也可以使用 Jupyter 笔记本做同样的事情。 这将涉及设置 Azure Active Directory 并进行新的 App 注册。 可以在以下链接上获得详细信息。

Azure BatchAI 也可以与其他 AI 深度学习库一起使用,我们建议您仔细阅读 BatchAI Github 以获取更多详细信息。

在 Amazon AWS 上运行分布式 TensorFlow

Amazon AWS 提供了配备 NVIDIA K8 GPU 的 P2.x 机器。 为了能够使用,第一步再次涉及创建一个 Amazon AWS 账户。 如果还没有,可以使用以下链接创建它。 登录帐户后,仪表板将如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aNAdytxN-1681565377477)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/b32ea001-d1a5-464b-b2ec-a1a43c8d1001.png)]

您可以看到 Amazon AWS 提供了许多服务,但是在这里,我们担心使用 Amazon AWS 进行深度学习。

GPU 仅在 P2 实例创建中可用,并且默认情况下不可用,要获得此服务,您必须通过 AWS 支持筹集更多资源,一旦获得支持,该支持就会显示在右上角, 您将看到一个按钮,创建案例,选择按钮并进行以下选择:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6f9JhFLs-1681565377477)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/1b9d45a6-ea33-4b49-bf7e-028927a57452.png)]

您可以选择提供 p2.xlarge 实例的任何区域。 新的限制值决定了您可以使用的实例的最大数量,请谨慎选择数量,因为该服务不是免费的,并且每小时的费用约为 1 美元。 AWS 大约需要 24 小时才能响应请求。

准备

现在您已经可以使用 AWS 账户和 p2.xlarge 实例,现在就可以从 EC2 仪表板创建自己的实例了。 第一步是选择机器映像,到目前为止,Amazon 提供了预装有深度学习库的特殊机器映像,您可以选择 Ubuntu 或 Linux 版本。 接下来,选择 GPU 以计算实例类型。

您可以使用默认参数查看并启动实例,也可以配置设置,选择存储并配置安全组。 配置安全组很重要,默认情况下已设置 SSH 安全组,但是如果要使用 Jupyter 笔记本,则需要为端口 8888 添加自定义安全组,可以选择从中登录的源。 对于实例,有三种可能性:“自定义”,“随处可见”或“我的 IP”:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DCm6gx66-1681565377477)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/10716413-09c1-49c7-9c5c-207de1610b48.png)]

最后,在启动实例时,将要求您创建一个密钥对,以允许您登录到特定实例,您将需要创建一个密钥对并下载相应的.pem文件,您将使用文件以便后续记录。

操作步骤

  1. 第一步是连接到实例,您可以使用命令行通过 SSH 或浏览器来实现。 我们使用 CLI。

  2. 要进行连接,首先更改.pem文件的模式。

chmod 400 <security-keypair-filename>.pem
  1. 接下来,使用以下命令对实例进行 SSH。 选择连接时,确切的地址将在仪表板上可用:
ssh -i " <security-keypair-filename>.pem" ubuntu@ec2-XXXXXXXXXXXXX.compute-1.amazonaws.com
  1. 我们选择的机器实例已经包含了所有深度学习库,包括 TensorFlow,因此我们不需要安装任何东西:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4FNh2xpZ-1681565377477)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/97e2ab30-bc18-4894-bdbe-21be3c91b17d.png)]

  1. 每个文件夹都包含一个自述文件,该文件描述了如何使用相应的库:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-606vnSnO-1681565377478)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/ebb26449-ae6a-4899-a75c-995e10a1ef3a.png)]

工作原理

您可以运行在我们创建的实例上学到的代码。 工作结束后,不要忘记退出,并从仪表板停止实例。 有关价格和使用情况的更多详细信息,请参见这里

更多

AWS 市场上提供了带有预配置库和 API 的大量 Docker 映像和机器映像。 要启动 jupyter 笔记本,请在命令行中使用<jupyter notebook --ip=0.0.0.0 --no-browser>。 这将导致输出,如下所示:

首次连接以使用令牌登录时,将此 URL 复制/粘贴到浏览器中:

http://0.0.0.0:8888/?token=3156e...

您将 URL 复制并粘贴到浏览器中,就可以开始使用了。

此外,可以通过查看 AWS CloudFormation 简化整个过程。 它使用模板创建和配置 Amazon Web Services 资源。 这样可以简化设置分布式深度学习集群的过程。 有兴趣的读者可以看看这里

十三、AutoML 和学习如何学习(元学习)

深度学习的成功极大地促进了特征工程的工作。 确实,传统的机器学习很大程度上取决于对正确的特征集的选择,而且与选择特定的学习算法相比,这一步骤通常更为重要。 深度学习改变了这种情况。 创建正确的模型仍然非常重要,但是现今的网络对特定特征集的选择已不那么敏感,并且能够自动选择真正重要的特征。

取而代之的是,深度学习的引入使人们更加关注正确的神经网络架构的选择。 这意味着研究人员的兴趣正逐渐从特征工程转向网络工程。 AutoML元学习)是一个新兴的研究主题,旨在针对给定的学习任务自动选择最有效的神经网络。 换句话说,AutoML 代表学习如何有效学习的一组方法。 考虑例如机器翻译,图像识别或游戏的任务。 通常,模型是由工程师,数据科学家和领域专家组成的团队手动设计的。 如果您认为一个典型的 10 层网络可以具有约10^10个候选网络,那么您就会知道该过程可能很昂贵,容易出错并且最终不是最佳选择。

使用循环网络和强化学习的元学习

解决此问题的关键思想是拥有一个控制器网络,该控制器网络会在给定特定网络输入的情况下,以概率p提出模型架构。 对子项进行训练和评估,以解决要解决的特定任务(例如,子项获得的准确率R)。 该评估R被传递回控制器,该控制器进而使用R来改善下一个候选架构。 在此框架下,可以将候选子项到控制器的反馈建模为计算p的梯度的任务,然后通过R缩放此梯度。 控制器可以实现为循环神经网络(请参见下图)。 这样做,控制器将倾向于在迭代之后获得更好的R的架构候选区域,并倾向于给得分不那么高的候选区域分配较低的概率。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kdwAKivP-1681565377478)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/30ccd28f-f08f-4323-aae4-313b11ba8ddb.png)]

例如,控制器循环神经网络可以对卷积网络进行采样。 控制器可以预测许多超参数,例如过滤器高度,过滤器宽度,步幅高度,步幅宽度和一层过滤器的数量,然后可以重复。 每个预测可以由 softmax 分类器执行,然后输入到下一个 RNN 时间步中。 以下图片来自《使用增强学习的神经架构搜索》(Barret Zoph,Quoc V. Le):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hd5dL5F3-1681565377478)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/9986f40c-9051-4483-959c-00a067ed0e2a.png)]

预测超参数是不够的,因为最好定义一组动作以在网络中创建新层。 这特别困难,因为描述新层的奖励函数极有可能是不可区分的,因此无法通过标准技术(例如 SGD)对其进行优化。 解决方案来自强化学习,它包括采用类似于我们的第 9 章,“强化学习”中所述的策略梯度网络。

除此之外,并行性可用于优化控制器 RNN 的参数。 Quoc Le&Barret Zoph 建议采用参数服务器方案,其中我们有一个 S 碎片的参数服务器,用于存储 K 个控制器副本的共享参数。 每个控制器副本都采样了如下图所示的并行训练的不同子架构,如下图所示,取自《使用增强学习的神经架构搜索》(Barret Zoph,Quoc V. Le):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eQSEdLBz-1681565377478)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/23d54b43-728d-4230-b0ab-4d219de2c679.png)]

Quoc 和 Barret 将 AutoML 技术用于神经架构搜索应用于 Penn Treebank 数据集,这是语言建模的著名基准。 他们的结果改进了目前被认为是最先进的手动设计网络。 特别是,他们在 Penn Treebank 上实现了 62.4 的测试集困惑,这比以前的最新模型好 3.6 困惑。 同样,在 CIFAR-10 数据集上,该方法可以设计一种新颖的网络架构,与测试集准确率方面最好的人类发明架构旗鼓相当。 提出的 CIFAR-10 模型实现了 3.65 的测试错误率,比使用类似架构方案的最新技术模型好 0.09%,并且快 1.05 倍。

元学习块

在《用于可伸缩图像识别的学习可传输架构》(Barret Zoph,Vijay Vasudevan,Jonathon Shlens,Quoc V. Le,2017)中,建议在小型数据集上学习架构构造块,然后将其传输到大型数据集。 作者建议在 CIFAR-10 数据集上搜索最佳的卷积层(或单元),然后通过堆叠该单元的更多副本(每个都有其自己的参数),将此学习到的单元应用于 ImageNet 数据集。 准确地说,所有卷积网络都是由结构相同但权重不同的卷积层(或单元)组成的。 因此,将搜索最佳卷积架构简化为搜索最佳单元结构,这样可以更快地将其推广到其他问题。 尽管无法在 ImageNet 上直接学习该单元,但是在已发表的工作中,由学得最好的单元构成的架构可实现 ImageNet 的最新精度为 82.7% top-1 和 96.2% top-5。 该模型的 top-1 准确率比人类发明的最佳架构高 1.2%,而 FLOPS 则减少了 90 亿个,与之前的最新模型相比降低了 28%。 还需要注意的重要一点是,使用 RNN + RL(循环神经网络+强化学习)学习的模型正在击败随机搜索(RL)代表的基线,如本文中所取的图所示。 在 RL 与 RS 中确定的前 5 名和前 25 名模型的平均表现中,RL 始终是赢家:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E7CQbza6-1681565377478)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/c806db28-97c3-409d-8877-d86502c86e12.png)]

新任务的元学习

可以对元学习系统进行训练以完成大量任务,然后对其元学习新任务的能力进行测试。 这种元学习的一个著名例子是在高级 CNN 章节中讨论的所谓迁移学习,其中网络可以从相对较小的数据集中成功学习基于图像的新任务。 但是,对于诸如语音,语言和文本之类的非视觉领域,没有类似的预训练方案。

《用于快速适应深度网络的模型不可知元学习》(切尔西·芬恩(Chelsea Finn),彼得·阿比尔(Siety Levine),2017 年)提出了一个模型 -不可知论方法的名称为 MAML,它与经过梯度下降训练的任何模型兼容,并且适用于各种不同的学习问题,包括分类,回归和强化学习。 元学习的目标是针对各种学习任务训练模型,以便仅使用少量训练样本即可解决新的学习任务。 元学习器旨在找到一种可以快速(以很少的步骤)并有效地(仅使用几个示例)快速适应各种问题的初始化。 用参数为θ的参数化函数f[0]表示的模型。 当适应新任务T[i]时,模型参数θ变为θ[i']。 在 MAML 中,使用对任务T[i]的一个或多个梯度下降更新来计算更新的参数向量θ[i']

例如,当使用一个梯度更新时,θ[i'] = θ - α∇[0]L[Ti](f[θ]),其中L[Ti]是任务T的损失函数,而α是元学习参数。 该图报告了 MAML 算法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9inUds1x-1681565377479)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/30503d87-ad59-4ec7-8e66-2918624faaf7.png)]

MAML 能够在流行的少拍图像分类基准上大大胜过许多现有方法。 旨在从一个或几个概念中学习新概念的镜头很少有挑战性。 例如,《通过概率性程序归纳进行人级概念学习》(Brenden M. Lake,Ruslan Salakhutdinov,Joshua B. Tenenbaum,2015 年),建议人们可以学会从单个图片中识别新颖的两轮车,例如红色框中包含的图片,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VFOU0szK-1681565377479)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/d55d0f5e-ee42-4c09-a213-65fadee76b26.png)]

在 2017 年底,AutoML(或元学习)主题是一个活跃的研究主题,旨在针对给定的学习任务自动选择最高效的神经网络。 目标是学习如何高效,自动地设计网络,从而可以学习特定任务或适应新任务。 主要问题是不能简单地用可微分的损失函数描述网络的设计,因此传统的优化技术不能简单地用于元学习。 因此,已经提出了一些解决方案,包括具有控制器循环网络(RNN)和基于强化学习的奖励策略的思想,以及具有与模型无关的元学习的思想。 两种方法都非常有前途,但是肯定还有很多研究空间。

因此,如果您对一个热门话题感兴趣,那么学习深度学习当然是一个可以考虑作为下一份工作的空间。

  • Google 提出了采用 RNN 作为控制器的方法,该方法使用机器学习来探索神经网络架构。
  • 《带有增强学习的神经架构搜索》(Barret Zoph,Quoc V. Le)是一篇开创性的论文,它证明了有关 Google 方法的更多细节。 但是,RNN 不是唯一的选择。
  • 《图像分类器的大规模发展》(Esteban Real,Sherry Moore,Andrew Selle,Saurabh Saxena,Yutaka Leon Suematsu,Jie Tan,Quoc Le,Alex Kurakin,2017 年)提出在进化遗传算法中使用遗传计算来探索新的候选网络。
  • 《学习用于可伸缩图像识别的可迁移架构》(Barret Zoph,Vijay Vasudevan,Jonathon Shlens,Quoc V. Le)提出了在 CIFAR 上学习的单元,用于改善 ImageNet 分类。
  • 《构建可以建立人工智能的 AI》:谷歌和其他公司为争夺一小部分研究人员而奋斗,他们正在寻找自动方法来应对人工智能专家的短缺。
  • 《用于快速适应深度网络的模型不可知元学习》(切尔西·芬恩(Chelsea Finn),彼得·阿比耶尔(Pieter Abbeel),谢尔盖·莱文(Sergey Levine),2017 年)。
  • 《通过梯度下降学习》(Marcin Andrychowicz,Misha Denil,Sergio Gomez,Matthew W. Hoffman,David Pfau,Tom Schaul,Brendan Shillingford,Nando de Freitas)展示了如何将优化算法的设计转换为学习问题,从而使该算法能够自动学习感兴趣的问题中的结构。 LSMT 学习的算法在训练任务上胜过手工设计的竞争对手,并且可以很好地推广到结构相似的新任务。 该算法的代码可在 GitHub 上获得。

连体网络

连体网络是 Yann LeCun 及其同事在 NIPS 1994 中提出的一种特殊类型的神经网络。 它们背后的基本思想是,像“连体双胞胎”一样,该网络由两个不同的神经网络组成,它们共享相同的架构和权重。

在这里,您可以看到连体架构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BGrtYtnK-1681565377479)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/15b0d10f-3abe-4254-87dd-e3cb5ad93494.png)]

在训练阶段,该对网络会显示一个训练对(X[1], X[2]),其中两个输入不同但相似,例如, X[1] = 他很聪明,而X[2] = 他是一个聪明人。 这两个神经网络将产生两个不同的结果。 可以将组合网络视为测量训练对(X[1], X[2])之间相似度的标量能量函数 , 定义为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LmrUlxGs-1681565377479)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/7ae40c9e-adb2-4c8b-bb4d-1dab0e5c19b0.png)]

连体网络的目标是训练对(X[1], X[2])之间的能量应小于其他赝品对之间的能量(X[1], X'[2])

这可以通过使用对比损失函数进行训练来实现。

在训练阶段,网络被输入一个训练对和一个与之相关的标签,告诉它是一个真正的对或赝品对的网络:(X[1], X[2], Y[i])i个训练样本。 对比损失函数计算如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xQEZmj7V-1681565377480)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/32f13c94-c144-4116-bd64-e97805948eb6.png)]

其中,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uU4PBckp-1681565377480)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/633e200a-ea56-49bd-9669-15c9effa8a56.png)]

L[G]是真正对的部分损失, L[I]是赝品的部分损失对和P训练样本数。 当偶对是正品时,标签Y的值为 0;当偶对是赝品时,标签Y的值为 1。 设计局部损失L[G]L[I]的方式应使对比损耗L(W)将减少真正对的能量并增加赝品的能量。 这是通过选择部分损失L(G)单调增加而选择部分损失L(I)单调减少f来实现的。 一种可能的选择是使用余弦相似度来计算部分损耗。

使用反向传播算法调整权重。

连体网络的应用

近年来,连体网络已用于许多应用。 他们在 LeCun 论文中首次使用的是签名验证。 从那时起,出现了许多应用,我们将介绍一些最近的应用:

  • 与连体网络进行说话人和语音相似性的联合学习:他们训练了一个多输出连体网络,其中一个输出用于语音相似性,其他用于演讲者相似性。 他们将工作扩展到三体网络。
  • 用于对象跟踪的全卷积连体网络:他们使用在 ILSVRC15 数据集上训练的卷积连体网络进行视频中的目标检测。
  • 我们站在一起:连体网络进行类似问题的检索:本文使用连体网络来查找当前问题和已归档问题之间的语义相似性 。 他们还使用了卷积连体网络。

除此之外,还对连体网络进行了脸部验证/识别。 它们已用于问题解答。

一个有效的例子 – MNIST

工作示例基于 Github 页面。 此处的代码使用连体网络将手写的 MNIST 数字嵌入到 2D 空间中,属于同一类的数字被嵌入在一起。 该代码包含三个主要文件:

  • run.py:它包含执行训练的基本包装。 它使用“梯度下降”算法将对比度损失降至最低。

  • inference.py:包含定义 3 层全连接网络的连体类。 代码中两个网络的输出之间的相似性是欧几里得。 然后,使用部分生成损失和部分赝品损失来计算对比损失。

  • visualize.py:这只是用于可视化结果的包装。

经过前 100,000 个训练步骤,结果是:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FtY1CAhy-1681565377480)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/8b5c32c0-e504-4d4d-bdaf-24d3eb4ccef3.png)]

您可以看到相同(标记)的数字一起嵌入 2D 空间。

还有另一个有趣的示例](https://github.com/dhwajraj/deep-siamese-text-similarity) 。

在这里,使用 Tensorflow,训练了深层的连体 LSTM 网络以使用字符嵌入来捕获短语/句子相似性。

十四、TensorFlow 处理单元

Google 服务(例如 Google 搜索(RankBrain),街景,Google 照片和 Google 翻译)有一个共同点:它们都使用 Google 的 Tensor 处理单元或 TPU 进行计算。

您可能在想什么是 TPU,这些服务有什么好处? 所有这些服务都在后台使用最新的机器学习算法,并且这些算法涉及大量计算。 TPU 有助于加速所涉及的神经网络计算。 甚至 AlphaGo,一种在 Go 游戏中击败 Lee Sedol 的深度学习程序,都由 TPU 推动。 因此,让我们看看 TPU 到底是什么。

TPU 是 Google 专门为机器学习而定制的定制专用集成电路(ASIC),是针对 Tensorflow 量身定制的。 它基于 28 纳米工艺构建,运行频率为 700 MHz,运行时消耗 40 W 的能量。 它包装为外部加速卡,可以插入现有的 SATA 硬盘插槽中。 TPU 通过 PCIe Gen 3×16 总线连接到主机 CPU,该总线提供 12.5 GB/s 的有效带宽。

到目前为止,第一代 TPU 的目标是推理,即使用已经训练好的模型。 DNN 的训练通常需要更多时间,但仍在 CPU 和 GPU 上进行。 在 2017 年 5 月的博客文章中宣布的第二代 TPU 都可以训练和推断机器学习模型。

TPU 的组件

在本书涵盖的所有深度学习模型中,无论学习范例如何,都需要进行三个基本计算:乘法,加法和激活函数的应用。

前两个成分是矩阵乘法的一部分:权重矩阵W需要与输入矩阵X相乘W^T · X; 矩阵乘法在 CPU 上的计算量很大,尽管 GPU 使操作并行化,但仍有改进的余地。

TPU 具有 65,536 个 8 位整数矩阵乘法器单元(MXU),峰值吞吐量为 92 TOPS。 GPU 和 TPU 乘法之间的主要区别在于 GPU 包含浮点乘法器,而 TPU 包含 8 位整数乘法器。 TPU 还包含一个统一缓冲区(UB),用作寄存器的 24 MB SRAM 和一个包含硬接线激活函数的激活单元(AU)。

MXU 是使用脉动数组架构实现的。 它包含一个数组算术逻辑单元(ALU),该数组连接到网状拓扑中的少量最近邻居。 每个数据值仅读取一次,但在流过 ALU 数组时会多次用于不同的操作,而无需将其存储回寄存器。 TPU 中的 ALU 仅以固定模式执行乘法和加法。 MXU 已针对矩阵乘法进行了优化,不适用于通用计算。

每个 TPU 还具有一个片外 8GiB DRAM 池,称为加权存储器。 它具有四个阶段的流水线,并执行 CISC 指令。 到目前为止,TPU 由六个神经网络组成:两个 MLP,两个 CNN 和两个 LSTM。

在高级指令的帮助下对 TPU 进行编程; 下面是一些用于对 TPU 进行编程的指令:

  • Read_Weights:从内存读取权重
  • Read_Host_Memory:从内存中读取数据
  • MatrixMultiply/Convolve:与数据相乘或卷积并累加结果
  • Activate:应用激活函数
  • Write_Host_Memory:将结果写入存储器

Google 创建了一个 API 栈,以方便 TPU 编程; 它将来自 Tensorflow 图的 API 调用转换为 TPU 指令。

TPU 的优势

TPU 提供的优于 GPU 和 CPU 的首要优势是性能。 Google 将 TPU 的性能与运行基准代码(代表 95% 的推理工作量)的服务器级 Intel Haswell CPU 和 NVIDIA K80 GPU 进行了比较。 它发现 TPU 的速度比 NVIDIA GPU 和 Intel CPU 快 15-30 倍。

第二个重要参数是功耗。 降低功耗非常重要,因为它具有双重能源优势:它不仅减少了功耗,而且还通过降低散热成本来散热,从而节省了功耗,从而消除了加工过程中产生的热量。 TPU / CPU 每瓦性能比其他 CPU 和 GPU 配置提高了 30-80 倍。

TPU 的另一个优点是其最小化和确定性的设计,因为它们一次只能执行一个任务。

与 CPU 和 GPU 相比,单线程 TPU 没有任何复杂的微架构功能会消耗晶体管和能量来改善平均情况,但不会消耗 99% 的情况:没有缓存,分支预测,乱序执行, 多处理,推测性预取,地址合并,多线程,上下文切换等。 极简主义是特定领域处理器的优点。

访问 TPU

Google 已决定不直接将 TPU 出售给他人; 取而代之的是,将通过 Google 云平台提供 TPU:Cloud TPU Alpha。 Cloud TPU Alpha 将提供高达 180 teraflops 的计算性能和 64 GB 的超高带宽内存。 用户将能够从自定义虚拟机连接到这些 Cloud TPU。

Google 还决定向全球的机器学习研究人员免费提供 1000 个云 TPU 集群,以加快开放式机器学习研究的步伐。 在有限的计算时间内,将授予选定的个人访问权限; 个人可以使用以下链接进行注册。 根据 Google Blog:

“由于 TensorFlow 研究云的主要目标是使整个开放式机器学习研究社区受益,因此,成功的申请人有望做到以下几点:

通过同行评审的出版物,开源代码,博客文章或其他开放媒体与世界分享其 TFRC 支持的研究

与 Google 分享具体的建设性反馈,以帮助我们随着时间的推移改进 TFRC 计划和基础的 Cloud TPU 平台。

想象一下 ML 加速丰富的未来,并基于这种未来开发新的机器学习模型。”

TPU 上的资源

  • Norman P.Jouppi 等人,张量处理单元的数据中心内性能分析,arXiv:1704.04760(2017)。 在本文中,作者将 TPU 与服务器级的 Intel Haswell CPU 和 NVIDIA k80 GPU 进行了比较。 本文以 TPU 与 CPU 和 K80 GPU 的性能为基准。
  • 此 Google 博客通过以下简单术语说明了 TPU 及其工作原理

TensorFlow 1.x 深度学习秘籍:11~14相关推荐

  1. TensorFlow 1.x 深度学习秘籍·翻译完成

    原文:TensorFlow 1.x Deep Learning Cookbook 协议:CC BY-NC-SA 4.0 不要担心自己的形象,只关心如何实现目标.--<原则>,生活原则 2. ...

  2. TensorFlow 1.x 深度学习秘籍:1~5

    原文:TensorFlow 1.x Deep Learning Cookbook 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自[ApacheCN 深度学习 译文集],采用译后编辑(MTP ...

  3. TensorFlow 1.x 深度学习秘籍:6~10

    原文:TensorFlow 1.x Deep Learning Cookbook 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自[ApacheCN 深度学习 译文集],采用译后编辑(MTP ...

  4. 深度学习(11)TensorFlow基础操作七: 向前传播(张量)实战

    深度学习(11)TensorFlow基础操作七: 向前传播(张量)实战 1. 导包 2. 加载数据集 3. 转换数据类型 4. 查看x.shape, y.shape, x.dtype, y.dtype ...

  5. 资源|2019 年 11 月最新《TensorFlow 2.0 深度学习算法实战》中文版教材免费开源(附随书代码+pdf)...

    点击上方"AI遇见机器学习",选择"星标"公众号 重磅干货,第一时间送 2019 年 10 月,谷歌正式宣布,开源机器学习库 TensorFlow 2.0 现在 ...

  6. 视频教程-人人都会深度学习之Tensorflow基础入门-深度学习

    人人都会深度学习之Tensorflow基础入门 大数据工程师/算法工程师/大数据讲师,毕业于西华大学软件工程专业.在大数据领域有着丰富的实战经验. 擅长领域:Spark/Hadoop.算法设计及系统架 ...

  7. 400页《TensorFlow 2.0 深度学习算法实战》中文版教材免费下载(附随书代码+pdf)...

    Tensorflow自谷歌提出以来就成为最受欢迎的深度学习框架之一,到目前为止也已经被下载超过 4000 万次.其中TensorFlow2.0更是修复之前非常多的不人性的特性,备大家欢迎. 今天给大家 ...

  8. 深度学习笔记(14) 评估指标

    深度学习笔记(14) 评估指标 1. 正交化 2. 单一数字评估指标 3. 满足和优化指标 4. 改变开发/测试集和指标 1. 正交化 搭建建立机器学习系统的挑战之一是,可以尝试和改变的东西太多太多了 ...

  9. ElasticDL:首个基于 TensorFlow 实现弹性深度学习的开源系统

    9 月 11 日,蚂蚁金服开源了 ElasticDL 项目,据悉这是业界首个基于 TensorFlow 实现弹性深度学习的开源系统. Google Brain 成员 Martin Wicke 此前在公 ...

最新文章

  1. java 解析csv_java解析CSV文件(getCsvData 解析CSV文件 zipFiles 打成压缩包 exportObeEventDataExcel 前端页面响应)...
  2. mybatis基础,mybatis配置文件核心组件typeHandler元素
  3. python怎么变成竖行_python 处理文本 列变成行
  4. 『软件测试3』八大典型的黑盒测试方法已来袭,快快接住!
  5. c语言第一次作业,C语言培训班第一次作业 (1)
  6. Sublime Text快捷键去除空白行
  7. Android 系统(166)---GMO版本最近应用列表界面显示模糊的解决方案
  8. NUMA全称 Non-Uniform Memory Access,译为“非一致性内存访问”,积极NUMA内存策略
  9. ncurses面板库:new_panel(),doupdate(),show_panel(),hide_panel(),move_panel(),del_panel()...
  10. Java 的体系结构包含_第一章 java体系结构介绍
  11. java 对象快速赋值_JavaWeb学习笔记:简单JavaBean对象的快速赋值与获取
  12. 人工智能python实战代码_人工智能------基于Python实战注疏
  13. 二分搜索 POJ 1064 Cable master
  14. PS快速切换证件照背景颜色
  15. 华为外包测试2年,不甘被替换,168天的学习转岗成正式员工
  16. CAN总线隔离器简介
  17. 1072 开学寄语(20 分)
  18. 小米android隐藏游戏,MIUI8小米手机开启隐藏选项
  19. 小程序转发二维码携带参数不生效的问题
  20. 18本生物竞赛辅导书

热门文章

  1. SequoiaDB和mysql_Mysql的JSON与SequoiaDB的比较
  2. 百度繁殖软件【日推百万蜘蛛工具】
  3. 计算机硬件基础(一)
  4. 阿里正式发布《Java开发手册》终极版!
  5. 周期(KMP找最小循环节)
  6. 微软任命Kevin Scott为其新CTO
  7. 电吉他效果器评测:便捷、全能!
  8. pdcch加扰_pdcch的功能
  9. 电脑连上网线但是不能用linux,为什么无线网络连接上却不能上网,详细教您电脑连上无线网却不能上网怎么办...
  10. 【N1BOOK】[第一章 web入门] wp