华龙建设部网站查不到网页设计兼职收费标准

当前位置: 首页 > news >正文

华龙建设部网站查不到,网页设计兼职收费标准,如何用表格做网站,建站网页建设原文#xff1a;TensorFlow 2.0 Quick Start Guide 协议#xff1a;CC BY-NC-SA 4.0 译者#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】#xff0c;采用译后编辑#xff08;MTPE#xff09;流程来尽可能提升效率。 不要担心自己的形象#xff0c;只关心如何实现… 原文TensorFlow 2.0 Quick Start Guide 协议CC BY-NC-SA 4.0 译者飞龙 本文来自【ApacheCN 深度学习 译文集】采用译后编辑MTPE流程来尽可能提升效率。 不要担心自己的形象只关心如何实现目标。——《原则》生活原则 2.3.c 第 3 部分TensorFlow 2.00 Alpha 的神经网络应用 在本节中我们将研究许多人工神经网络ANN应用。 这些包括图像识别神经风格迁移文本风格生成时尚识别以及电影评论的 IMDb 数据库的语义分析。 本节包含以下章节 第 6 章“使用 TensorFlow 2 识别图像”第 7 章“TensorFlow 2 和神经风格迁移”第 8 章“Tensorflow 2 和循环神经网络”第 9 章“TensorFlow 估计器和 TensorFlow HUB” 六、使用 TensorFlow 2 识别图像 本章分为两部分但我们将同时学习使用 TensorFlow 进行图像分类。 在本章中我们将涵盖以下主要主题 QuickDraw – 使用 TensorFlow 进行图像分类使用 TensorFlow 的 CIFAR 10 图像分类 在第一部分中我们将使用在前几章中学到的技术开发 TensorFlow 2 模型以进行图像识别尤其是第 2 章 “KerasTensorFlow 2 的高级 API”。 这将使我们能够看到如何使用 TensorFlow 2 将所有相关技术结合在一起来创建训练和评估完整的模型。我们将利用 Google 提供的 QuickDraw 图片数据集可帮助您解决此问题。 QuickDraw – 使用 TensorFlow 进行图像分类 我们将使用从 Google QuickDraw 拍摄的图像数据集。 这是一个公开的开放源代码它包含 345 个类别的 5000 万张图像的数据集所有这些图像都是由参与挑战的 1500 万名用户在 20 秒或更短的时间内绘制的。 我们将训练 10 个类别的 10,000 张图像其中一些被选择为相似图像以便我们可以测试模型的区分能力。 您可以在这个页面上查看这些图像的示例。 这些图片有多种格式请参见这个页面中的所有格式。 在这里我们将使用已存储为.npy文件的图像。 .npy文件的公共数据集托管在这个页面上。 从这里可以一次下载一组。 要使用不同的图像运行此示例请从数据目录中删除图像文件然后将所需的图像下载到存储库中的同一目录中。 该程序从文件名中读取标签。 在本节中我们将涵盖以下主题 采集数据预处理数据建立模型训练和测试模型保存加载和重新测试模型使用.h5格式保存和加载 NumPy 图像数据加载预训练的模型使用预训练的模型 我们将逐步开发和呈现代码片段。 这些代码段通过螺栓连接在一起成为存储库中的完整程序。 采集数据 我们将需要从 Google 下载数据。 您可以将数据下载到一个空目录data_files。 转到这里并将 10 个数据集下载到data_files文件夹中。 以下是将要下载的文件的示例 alarm_clock.npy, broom.npy, ant.npy, bee.npy, cell_phone.npy, baseball.npy, dolphin.npy, crocodile.npy, aircraft_carrier.npy, asparagus.npy您将下载的文件名称前会带有多余的位例如full_numpy_bitmap_alarm clock.npy。 为了使这些内容更简洁请删除开头的位然后重命名文件以使文件名在我们的示例中变为alarm_clock.npy。 对所有 10 个文件执行此操作。 建立环境 首先我们需要导入依赖项 import tensorflow as tf import keras import numpy as np from sklearn.model_selection import train_test_split from os import walk您可能需要运行pip install sklearn。 接下来我们将建立一些常量供以后使用 batch_size 128 img_rows, img_cols 28, 28 # image dimensions接下来我们将使用os.walk方法从data_files文件夹中收集数据集的文件名 请注意文件名收集在列表变量filenames中。 data_path data_files/ for (dirpath, dirnames, filenames) in walk(data_path):pass # filenames accumulate in list filenames print(filenames)对于我们的示例文件名对应于label类别如下 [alarm_clock.npy, broom.npy, ant.npy, bee.npy, cell_phone.npy, baseball.npy, dolphin.npy, crocodile.npy, aircraft_carrier.npy, asparagus.npy]要使用不同的图像运行该示例只需将 10 个不同的文件下载到data文件夹中。 接下来我们将定义模型所需的更多值。 图像总数num_images可在此处更改 num_images 1000000 ### was 100000, reduce this number if memory issues. num_files len(filenames) # we have 10 files images_per_category num_images//num_files seed np.random.randint(1, 10e7) i0 print(images_per_category)预处理数据 接下来是将图像加载到内存中的代码。 我们将遍历文件并在获取文件路径的值之后加载该文件或一组图像x。 然后将x转换为浮点数然后除以 255将其设置为 0 到 1 的范围。之后我们为该组图像x创建一个数字标签y。 对于第一组图像该值为 0对于下一组图像此值为 1一直到最后一组图像的 9由变量i控制。 然后我们将集合x和y切片以将图像和标签放回x和y中。 之后我们将x和y累积到x_all和y_all中如果这是它们第一次进入循环即i0则创建这两个新列表并将x和[ 如果这不是他们第一次通过循环即i0则将它们移到y上。 当此循环终止时x_all和y_all将分别包含带有标签的图像 i0 for file in filenames:file_path data_path filex np.load(file_path)x x.astype(float32) ##normalize imagesx / 255.0y [i] * len(x) # create numeric label for this imagex x[:images_per_category] # get the sample of images y y[:images_per_category] # get the sample of labels if i 0: x_all xy_all yelse: x_all np.concatenate((x,x_all), axis0)y_all np.concatenate((y,y_all), axis0)i 1之后我们将使用sklearn.model_selection模块中的train_test_split方法将x_all和y_all分为训练和测试集并以 8020 的训练/测试进行分割 #split data arrays into train and test segments x_train, x_test, y_train, y_test train_test_split(x_all, y_all, test_size0.2, random_state42)由于我们将使用卷积神经网络convNet对快速抽奖进行分类 图像接下来要做的是将x_train和x_test重塑为28 x 28 x 1图像它们开始出现时的样子其中前两个维度是图像的高度和宽度以像素为单位第三个维度是每个像素的灰度。 我们还将建立input_shape并将其用于convNet的第一层 x_train x_train.reshape(x_train.shape[0], img_rows, img_cols, 1) x_test x_test.reshape(x_test.shape[0], img_rows, img_cols, 1) input_shape (img_rows, img_cols, 1)此后我们将根据convNet的要求对y_train和y_test标签进行一次热编码 y_train tf.keras.utils.to_categorical(y_train, num_files) y_test tf.keras.utils.to_categorical(y_test, num_files)接下来我们将训练和测试x集进一步与验证集一起分成 9010 的更小的测试集 x_train, x_valid, y_train, y_valid train_test_split(x_train, y_train, test_size0.1, random_state42)建立模型 现在我们准备创建convNet模型。 有两个卷积层具有 ReLU 激活每个卷积层都插入最大池化和丢弃层然后是一个将卷积层的输出展平为一维的层。 在这些层之后是密集的完全连接的一维层同样具有 ReLU 激活最后的丢弃层最后是具有 10 个单元的 softmax 层。 softmax 层中每个输出单元的激活给出了该图像是 10 张图像之一的可能性。 这种 ANN 架构有足够的实验空间。 然后使用分类交叉熵的损失来编译模型 model tf.keras.Sequential()model.add(tf.keras.layers.Conv2D(32, kernel_size(3, 3), activationrelu, input_shapeinput_shape)) model.add(tf.keras.layers.MaxPooling2D(pool_size(2, 2))) model.add(tf.keras.layers.Dropout(0.25))model.add(tf.keras.layers.Conv2D(64, (3, 3), activationrelu)) model.add(tf.keras.layers.MaxPooling2D(pool_size(2, 2))) model.add(tf.keras.layers.Dropout(0.25))model.add(tf.keras.layers.Flatten()) model.add(tf.keras.layers.Dense(128, activationrelu)) model.add(tf.keras.layers.Dropout(0.5)) model.add(tf.keras.layers.Dense(num_files, activationsoftmax)) print(Compiling………..) model.compile(losstf.keras.losses.categorical_crossentropy,optimizertf.keras.optimizers.Adadelta(),metrics[accuracy])训练和测试模型 现在我们可以使用fit方法训练模型。 注意验证集的使用它不同于训练集。 callbacks列表还可以用于诸如保存最佳模型或在学习停止时终止训练如果在所有周期完成之前发生这种情况的操作。 有关详细信息请参见这里 epochs25 callbacks[tf.keras.callbacks.TensorBoard(logdir ./tb_log_dir)] model.fit( x_train, y_train,batch_sizebatch_size,epochsepochs,callbackscallbacks,verbose1,validation_data(x_valid, y_valid) )根据模型所处的硬件配置如果该模型在 GPU 上运行或者在 CPU 上运行缓慢则训练速度将非常快。 为了说明的目的可以减少周期的数量。 在 NVIDIA GTX 1080 GPU 上时间/周期约为 38 秒。 为了确定模型的准确率按以下方法使用evaluate方法。 请注意测试集用于此评估 score model.evaluate(x_test, y_test, verbose1) print(Test loss:, score[0]) print(Test accuracy:, score[1])我们还可以对测试图像进​​行随机采样并使用以下代码查看模型的效果。 从文件名中检索标签并打印以供参考然后再打印成对的预测标签与实际标签 import os labels [os.path.splitext(file)[0] for file in filenames] print(labels) print(\nFor each pair in the following, the first label is predicted, second is actual\n) for i in range(20):t np.random.randint(len(x_test) )x1 x_test[t]x1 x1.reshape(1,28,28,1) p model.predict(x1)print(————————-)print(labels[np.argmax(p)])print(labels[np.argmax(y_test[t])])print(————————-)TensorBoard 回调 TensorBoard 是用于训练模型的可视化工具。 TensorBoard 回调的完整签名如下 tf.keras.callbacks.TensorBoard(log_dir./logs, histogram_freq0, batch_size32, write_graphTrue, write_gradsFalse, write_imagesFalse, embeddings_freq0, embeddings_layer_namesNone, embeddings_metadataNone, embeddings_dataNone, update_freqepoch)在这个页面 上有所有这些参数的非常清晰而详细的描述。 TensorBoard 可以从命令行调用如下所示 tensorboard –logdir/full_path_to_your_logs例如我们可以使用tensorboard –logdir./logs作为默认目录。 将histogram_freq设置为非 0 的值会导致在写入数据时epochs之间有明显的停顿并且仅在需要模型所有层的激活和权重直方图时才应使用。 保存加载和重新测试模型 现在我们可以保存模型并将其删除 model.save(./QDrawModel.h5) del model然后我们需要重新加载它 from tensorflow.keras.models import load_model model load_model(./QDrawModel.h5)最后我们必须对其进行总结以表明我们已经成功地重新加载了保存的模型 model.summary()最后我们打印出 20 种时尚商品的测试样本以确保网络正常运行 print(For each pair, first is predicted, second is actual) for i in range(20):t np.random.randint(len(x_test))x1 x_test[t]x1 x1.reshape(1,28,28,1) p model.predict(x1)print(————————-)print(labels[np.argmax(p)])print(labels[np.argmax(y_test[t])])print(————————-)使用.h5格式保存和加载 NumPy 图像数据 如果需要保存先前程序中的训练和测试数据则可以使用以下代码 import h5py with h5py.File(x_train.h5, w) as hf:hf.create_dataset(QuickDraw, datax_train) with h5py.File(y_train.h5, w) as hf:hf.create_dataset(QuickDraw, datay_train) with h5py.File(x_test.h5, w) as hf:hf.create_dataset(QuickDraw, datax_test) with h5py.File(y_test.h5, w) as hf:hf.create_dataset(QuickDraw, datay_test)请注意加载数据集时传递给h5py.File()方法的数据集名称必须与使用h5py.File.create_dataset()方法保存数据集时使用的名称相同 import h5py hf h5py.File(x_train.h5, r) x_train np.array(hf[QuickDraw][:]) hf h5py.File(x_test.h5, r) x_test np.array(hf[QuickDraw][:]) hf h5py.File(y_train.h5, r) y_train np.array(hf[QuickDraw][:]) hf h5py.File(y_test.h5, r) y_test np.array(hf[QuickDraw][:])使用预训练的模型进行加载和推断 经过训练的模型QDrawModel.h5已运行 25 个周期并且达到了 90% 以上的测试准确率已保存在存储库中。 您已经看过此代码 为方便起见在此复制。 因此重申一下您可以使用以下代码加载此经过训练的模型 from keras.models import load_model model load_model(./QDrawModel.h5) model.summary()同样可以使用以下代码加载训练/测试数据 import h5py import numpy as np hf h5py.File(x_train.h5, r) x_train np.array(hf[QuickDraw][:]) hf h5py.File(x_test.h5, r) x_test np.array(hf[QuickDraw][:]) hf h5py.File(y_train.h5, r) y_train np.array(hf[QuickDraw][:]) hf h5py.File(y_test.h5, r) y_test np.array(hf[QuickDraw][:])再次重申我们可以使用以下代码获取标签我们看到的标签对应于图像文件名 from os import walk import os data_path data_files/ # folder for image files for (dirpath, dirnames, filenames) in walk(data_path):pass # filenames accumulate in list filenames labels [os.path.splitext(file)[0] for file in filenames] print(labels)然后可以通过以下代码使用我们加载的模型进行推理。 请注意如果有必要这还将演示如何强制在 CPU 上进行计算 import tensorflow as tf with tf.device(/cpu:0):for i in range(10):t np.random.randint(len(x_test) )x1 x_test[t]x1 x1.reshape(1,28,28,1) p model.predict(x1)y1 y_test[t]print(————————-)print(labels[np.argmax([p])])print(labels[y1]) print(————————-)使用 TensorFlow 的 CIFAR 10 图像分类 在第二部分中我们将研究训练模型以识别 CIFAR10 图像数据集中的图像。 这将使我们有机会举例说明顺序模型创建的稍有不同的风格。 介绍 具有 10 个类别的 CIFAR 10 图像数据集是 8000 万个微型图像数据集的标记子集。 这些图像由 Alex KrizhevskyVinod Nair 和 Geoffrey Hinton 收集。 有关此数据集的完整详细信息请访问这里。 在 10 个类别中总共有 60,000 个32 x 32彩色图像包括 50,000 个训练图像和 10,000 个测试图像。 类别如下 labels [airplane,automobile,bird,cat,deer,dog,frog,horse,ship,truck]以下是这些类别的图像的一些示例 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ig4X2Gp6-1681568242386)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/477a48fd-96b7-4311-a7ac-a7760a1626da.png)] 应用 首先以下是设置所需的导入 import tensorflow as tf import numpy as np from tensorflow.keras.datasets import cifar10 from tensorflow.keras.preprocessing.image import ImageDataGenerator from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten from tensorflow.keras.layers import Conv2D, MaxPooling2D,BatchNormalization from tensorflow.keras import regularizers from tensorflow.keras.models import load_model import os from matplotlib import pyplot as plt from PIL import Image您可能需要运行pip install PIL。 接下来我们将在其余的代码中使用一组值 batch_size 32 number_of_classes 10 epochs 100 # for testing; use epochs 100 for training ~30 secs/epoch on CPU weight_decay 1e-4 save_dir os.path.join(os.getcwd(), saved_models) model_name keras_cifar10_trained_model.h5 number_of_images 5然后我们可以加载并查看数据的形状 (x_train, y_train), (x_test, y_test) cifar10.load_data() print(x_train shape:, x_train.shape) print(x_train.shape[0], train samples) print(x_test.shape[0], test samples)这将产生预期的输出 x_train shape: (50000, 32, 32, 3) 50000 train samples 10000 test samples现在我们有了一个显示图像子集的函数。 这将在网格中显示它们 def show_images(images):plt.figure(1)image_index 0for i in range(0,number_of_images):for j in range(0,number_of_images):plt.subplot2grid((number_of_images, number_of_images),(i,j))plt.imshow(Image.fromarray(images[image_index]))image_index 1plt.gca().axes.get_yaxis().set_visible(False)plt.gca().axes.get_xaxis().set_visible(False) plt.show()让我们执行以下函数的调用 show_images(x_test[:number_of_images*number_of_images])这给我们以下输出 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1Ad1Gkp-1681568242387)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/b2b5bc7d-7dd7-4644-9c34-cf2222dcab0d.png)] 请注意图像在原始数据集中故意很小。 现在我们可以将图像投射到浮动对象上并将其范围更改为[0, 1] x_train x_train.astype(float32)/255 x_test x_test.astype(float32)/255如果将标签作为一站式向量提供则最好了解它们因此我们现在将这样做 y_train tf.keras.utils.to_categorical(y_train, number_of_classes) # or use tf.one_hot() y_test tf.keras.utils.to_categorical(y_test, number_of_classes)接下来我们可以指定模型的架构。 请注意与之前的操作相比我们使用的激活指定方法略有不同 model.add(Activation(elu))elu激活函数代表指数线性单元。 在这个页面中有很好的描述。 注意我们正在使用具有卷积层BatchNormalization和 MaxPooling 层的顺序模型。 倒数第二层使结构变平最后一层使用 softmax 激活因此我们预测的类将显示为具有最高激活的输出神经元 model Sequential() model.add(Conv2D(32, (3,3), paddingsame, kernel_regularizerregularizers.l2(weight_decay), input_shapex_train.shape[1:])) model.add(Activation(elu)) model.add(BatchNormalization()) model.add(Conv2D(32, (3,3), paddingsame, kernel_regularizerregularizers.l2(weight_decay))) model.add(Activation(elu)) model.add(BatchNormalization()) model.add(MaxPooling2D(pool_size(2,2))) model.add(Dropout(0.2))model.add(Conv2D(64, (3,3), paddingsame, kernel_regularizerregularizers.l2(weight_decay))) model.add(Activation(elu)) model.add(BatchNormalization()) model.add(Conv2D(64, (3,3), paddingsame, kernel_regularizerregularizers.l2(weight_decay))) model.add(Activation(elu)) model.add(BatchNormalization()) model.add(MaxPooling2D(pool_size(2,2))) model.add(Dropout(0.3))model.add(Conv2D(128, (3,3), paddingsame, kernel_regularizerregularizers.l2(weight_decay))) model.add(Activation(elu)) model.add(BatchNormalization()) model.add(Conv2D(128, (3,3), paddingsame, kernel_regularizerregularizers.l2(weight_decay))) model.add(Activation(elu)) model.add(BatchNormalization()) model.add(MaxPooling2D(pool_size(2,2))) model.add(Dropout(0.4))model.add(Flatten()) model.add(Dense(number_of_classes, activationsoftmax))接下来我们必须定义我们的优化器 RMSprop。 decay是每次更新后学习率降低的速度 opt tf.keras.optimizers.RMSprop(lr0.0001, decaydecay)现在我们将编译我们的模型 model.compile(losscategorical_crossentropy, optimizeropt,metrics[accuracy])为了帮助模型学习和推广我们将实现实时数据增强。 这是通过ImageDataGenerator()函数完成的。 其签名如下 keras.preprocessing.image.ImageDataGenerator(featurewise_centerFalse, samplewise_centerFalse, featurewise_std_normalizationFalse, samplewise_std_normalizationFalse, zca_whiteningFalse, zca_epsilon1e-06, rotation_range0, width_shift_range0.0, height_shift_range0.0, brightness_rangeNone, shear_range0.0, zoom_range0.0, channel_shift_range0.0, fill_modenearest, cval0.0, horizontal_flipFalse, vertical_flipFalse, rescaleNone, preprocessing_functionNone, data_formatNone, validation_split0.0, dtypeNone)但是我们将主要使用前面签名中所示的默认值。 数据将分批循环。 这是对图像应用各种转换例如水平翻转高度偏移宽度偏移旋转等。 我们将使用以下代码进行演示 # This will do preprocessing and real-time data augmentation: datagen ImageDataGenerator(rotation_range10, # randomly rotate images in the range 0 to 10 degreeswidth_shift_range0.1,# randomly shift images horizontally (fraction of total width)height_shift_range0.1,# randomly shift images vertically (fraction of total height)horizontal_flipTrue, # randomly flip imagesvalidation_split0.1)我们还将建立一个回调以便如果模型的准确率停止提高训练将停止并且将为模型恢复最佳权重。 EarlyStopping回调的签名如下 keras.callbacks.EarlyStopping(monitorval_loss, min_delta0, patience0, verbose0, modeauto, baselineNone, restore_best_weightsFalse)Monitor是要跟踪的数量min_delta是被算作改进的跟踪数量的最小变化patience是没有变化的周期数之后将停止训练而mode 是[‘min’‘max’‘auto’]之一它分别确定所跟踪的值是应该减少还是增加或者分别从其名称中确定。 baseline是要达到的跟踪值的值而restore_best_weights确定是否应恢复最佳周期的模型权重如果使用false则使用最新权重。 我们将有以下代码 callback tf.keras.callbacks.EarlyStopping(monitoraccuracy, min_delta0, patience1, verbose1,modemax, restore_best_weightsTrue) 现在我们可以训练模型了。 fit.generator()函数用于根据flow()生成器批量显示的数据训练模型。 可以在这个页面中找到更多详细信息 model.fit_generator(datagen.flow(x_train, y_train, batch_sizebatch_size), epochsepochs, callbacks[callback])让我们保存模型以便以后可以重新加载它 if not os.path.isdir(save_dir):os.makedirs(save_dir)model_path os.path.join(save_dir, model_name) model.save(model_path) print(Model saved at: %s % model_path)现在让我们重新加载它 model1 tf.keras.models.load_model(model_path) model1.summary()最后让我们看看我们的模型在测试集上的表现如何。 我们需要重新加载数据因为它已被损坏 (x_train, y_train), (x_test, y_test) cifar10.load_data() show_images(x_test[:num_images*num_images]) x_test x_test.astype(float32)/255这里又是标签 labels [airplane,automobile,bird,cat,deer,dog,frog,horse,ship,truck]最后我们可以检查预测的标签 indices tf.argmax(inputmodel1.predict(x_test[:number_of_images*number_of_images]),axis1) i 0 print(Learned \t True) print() for index in indices:print(labels[index], \t, labels[y_test[i][0]])i1在一次运行中提前停止开始了 43 个周期测试准确率为 81.4%并且前 25 张图像的测试结果如下 Learned Truecat cat ship ship ship ship ship airplane frog frog frog frog automobile automobile frog frog cat cat automobile automobile airplane airplane truck truck dog dog horse horse truck truck ship ship dog dog horse horse ship ship frog frog horse horse airplane airplane deer deer truck truck deer dog可以通过进一步调整模型架构和超参数例如学习率来提高此准确率。 到此结束了我们对 CIFAR 10 图像数据集的了解。 总结 本章分为两个部分。 在第一部分中我们研究了来自 Google 的数据集 QuickDraw。 我们介绍了它然后看到了如何将其加载到内存中。 这很简单因为 Google 善意地将数据集作为一组.npy文件提供这些文件可以直接加载到 NumPy 数组中。 接下来我们将数据分为训练验证和测试集。 创建ConvNet模型后我们对数据进行了训练并进行了测试。 在测试中经过 25 个周期该模型的准确率刚好超过 90%我们注意到通过进一步调整模型可能会改善这一精度。 最后我们看到了如何保存经过训练的模型然后如何重新加载它并将其用于进一步的推断。 在第二部分中我们训练了一个模型来识别 CIFAR 10 图像数据集中的图像。 该数据集包含 10 类图像是用于测试体系结构和进行超参数研究的流行数据集。 我们的准确率刚刚超过 81%。 在下一章中我们将研究神经风格迁移其中涉及获取一个图像的内容并将第二个图像的风格强加于其上以生成第三个混合图像。 七、TensorFlow 2 和神经风格迁移 神经风格迁移是一种使用神经网络将一幅图像的艺术风格施加到另一幅图像的内容上的技术因此最终得到的是两种图像的混合体。 您开始使用的图像称为内容图像。 您在内容图像上加上风格的图像称为风格参考图像。 Google 将转换后的图像称为输入图像这似乎令人困惑输入是从两个不同来源获取输入的意思 让我们将其称为混合图像。 因此混合图像是具有风格参考图像风格的内容图像。 神经风格迁移通过定义两个损失函数来工作-一个描述两个图像的内容之间的差异另一个描述两个图像之间的风格差异。 为了开始该过程用内容图像初始化混合图像。 然后使用反向传播将内容和内容以及混合图像的风格之间的差异也称为损失或距离最小化。 这将创建具有风格参考图像风格和内容图像内容的新图像即混合图像。 此过程中涉及一些技术-使用函数式 API使用预训练的模型及其特征图以及使用自定义训练循环以最小化loss函数。 我们将在下面的代码中满足所有这些要求。 要充分利用该技术有两个先决条件-Gatys 等人在 2015 年发表的原始论文虽非必要但确实可以解释该技术。 技术非常好因此非常有必要了解如何通过梯度下降来减少损失。 我们将使用 VGG19 架构中的特征层已在著名的 ImageNet 数据集上进行了训练其中包含 1400 万张图像和 1000 个类别。 我们将检查的代码源自 Google 提供的代码 它使用了急切的执行程序我们当然不需要编写代码因为它是 TensorFlow 2 中的默认代码。该代码在 GPU 上运行得更快但在耐心等待的情况下仍可以在 CPU 上合理的时间内进行训练。 在本章中我们将介绍以下主题 配置导入预处理图像查看原始图像使用 VGG19 架构建立模型计算损失执行风格迁移 配置导入 要对您自己的图像使用此实现您需要将这些图像保存在下载的存储库的./tmp/nst目录中然后编辑content_path和style_path路径如以下代码所示。 与往常一样我们要做的第一件事是导入并配置所需的模块 import numpy as np from PIL import Image import time import functoolsimport matplotlib.pyplot as plt import matplotlib as mpl

set things up for images display

mpl.rcParamsfigure.figsize mpl.rcParams[axes.grid] False您可能需要pip install pillow这是 PIL 的分支。 接下来是 TensorFlow 模块 import tensorflow as tffrom tensorflow.keras.preprocessing import image as kp_image from tensorflow.keras import models from tensorflow.keras import losses from tensorflow.keras import layers from tensorflow.keras import backend as K from tensorflow.keras import optimizers这是我们最初将使用的两个图像 content_path ./tmp/nst/elephant.jpg#Andrew Shiva / Wikipedia / CC BY-SA 4.0 style_path ./tmp/nst/zebra.jpg # zebra:Yathin S Krishnappa, https://creativecommons.org/licenses/by-sa/4.0/deed.en预处理图像 下一个函数只需稍作预处理即可加载图像。 Image.open()是所谓的惰性操作。 该函数找到文件并将其打开以进行读取但是实际上直到从您尝试对其进行处理或加载数据以来才从文件中读取图像数据。 下一组三行会调整图像的大小以便任一方向的最大尺寸为 512max_dimension像素。 例如如果图像为1,024 x 768则scale将为 0.5512 / 1,024并且这将应用于图像的两个尺寸从而将图像大小调整为512 x 384。Image.ANTIALIAS参数保留最佳图像质量。 接下来使用img_to_array()调用tensorflow.keras.preprocessing的方法将 PIL 图像转换为 NumPy 数组。 最后为了与以后的使用兼容图像需要沿零轴的批次尺寸由于图像是彩色的因此共给出了四个尺寸。 这可以通过调用np.expand_dims()实现 def load_image(path_to_image):max_dimension 512image Image.open(path_to_image)longest_side max(image.size)scale max_dimension/longest_sideimage image.resize((round(image.size[0]*scale), round(image.size[1]*scale)), Image.ANTIALIAS)image kp_image.img_to_array(image) # keras preprocessing# Broadcast the image array so that it has a batch dimension on axis 0image np.expand_dims(image, axis0)return image下一个函数显示已由load_image()预处理过的图像。 由于我们不需要额外的尺寸来显示因此可以通过调用np.squeeze()将其删除。 之后根据对plt.imshow()的调用后面带有可选标题的要求将图像数据中的值转换为无符号的 8 位整数 def show_image(image, titleNone):# Remove the batch dimension from the imageimage1 np.squeeze(image, axis0)# Normalize the image for display image1 image1.astype(uint8)plt.imshow(image1)if title is not None:plt.title(title)plt.imshow(image1)查看原始图像 接下来我们使用对前面两个函数的调用来显示内容和风格图像请记住图像像素必须是无符号 8 位整数类型。 plt.subplot(1,2,1)函数意味着在位置 1 使用一排两列的网格 plt.subplot(1,2,2)表示在位置 2 使用一排两列的网格 channel_means [103.939, 116.779, 123.68] # means of the BGR channels, for VGG processingplt.figure(figsize(10,10))content_image load_image(content_path).astype(uint8) style_image load_image(style_path).astype(uint8)plt.subplot(1, 2, 1) show_image(content_image, Content Image)plt.subplot(1, 2, 2) show_image(style_image, Style Image)plt.show()输出显示在以下屏幕截图中 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nBLqDvBd-1681568242387)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/c2cdcfbd-80c8-4aca-bc8d-a0fbf9cab5ce.png)] 接下来是加载图像的函数。 正如我们将要提到的那样在经过训练的vgg19模型中我们需要相应地预处理图像数据。 tf.keras模块为我们提供了执行此操作的方法。 这里的预处理将我们的 RGB 彩色图像翻转为 BGR def load_and_process_image(path_to_image):image load_image(path_to_image)image tf.keras.applications.vgg19.preprocess_input(image)return image为了显示我们的图像我们需要一个函数来获取用load_and_process_image处理的数据并将图像数据返回到其原始状态。 这必须手动完成。 首先我们检查图像的尺寸是否正确如果不是 3 或 4则会引发错误。 预处理从每个通道中减去其平均值因此通道的平均值为零。 减去的值来自 ImageNet 分析其中 BGR 通道的均值分别为103.939116.779和123.68。 因此接下来我们将这些值添加回 BGR彩色通道以恢复原始值然后将 BGR 序列翻转回 RGB。 最后对于此函数我们需要确保我们的值是无符号的 8 位整数其值在 0 到 255 之间 这可以通过np.clip()函数实现 def deprocess_image(processed_image):im processed_image.copy()if len(im.shape) 4:im np.squeeze(im, 0)assert len(im.shape) 3, (Input to deprocess image must be an image of dimension [1, height, width, channel] or [height, width, channel])if len(im.shape) ! 3:raise ValueError(Invalid input to deprocessing image)# the inverse of the preprocessing stepim[:, :, 0] channel_means[0] # these are the means subtracted by the preprocessing stepim[:, :, 1] channel_means[1]im[:, :, 2] channel_means[2]im im[:, :, ::-1] # channel lastim np.clip(im, 0, 255).astype(uint8)return im使用 VGG19 架构 了解下一个代码片段的最好方法是查看 VGG19 架构。 这是一个好地方大约位于页面的一半。 在这里您将看到 VGG19 是一个相当简单的体系结构由卷积层的块组成每个块的末尾都有一个最大池化层。 对于内容层我们使用block5中的第二个卷积层。 之所以使用这个最高的块是因为较早的块具有更能代表单个像素的特征图。 网络中的高层会根据对象及其在输入图像中的排列来捕获高级内容但不会限制重建的实际精确像素值。 对于风格层我们将在每个层块中使用第一个卷积层即block1_conv1到block5_conv5。 然后保存内容和风格层的长度以供以后使用

The feature maps are obtained from this content layer

content_layers [block5_conv2]# Style layers we need style_layers [block1_conv1,block2_conv1,block3_conv1,block4_conv1,block5_conv1]number_of_content_layers len(content_layers) number_of_style_layers len(style_layers)建立模型 现在接下来是一系列函数这些函数最终导致执行风格迁移run_style_transfer()的主要函数。 此序列中的第一个函数get_model()创建我们将要使用的模型。 它首先加载训练后的vgg_model已在ImageNet上进行训练而没有其分类层include_topFalse。 接下来它冻结加载的模型vgg_model.trainable False。 然后使用列表推导获取风格和内容层的输出值该列表推导遍历我们在上一节中指定的层的名称。 然后将这些输出值与 VGG 输入一起使用以创建可以访问 VGG 层的新模型即get_model()返回 Keras 模型该模型输出已训练的 VGG19 模型的风格和内容中间层。 不必使用顶层因为这是 VGG19 中的最终分类层我们将不再使用。 我们将创建一个输出图像以使输出和相应特征层上的输入/风格之间的距离差异最小化 def get_model():vgg_model tf.keras.applications.vgg19.VGG19(include_topFalse, weightsimagenet)vgg_model.trainable False# Acquire the output layers corresponding to the style layers and the content layers style_outputs [vgg_model.get_layer(name).output for name in style_layers]content_outputs [vgg_model.get_layer(name).output for name in content_layers]model_outputs style_outputs content_outputs# Build model return models.Model(vgg_model.input, model_outputs)计算损失 现在我们需要两个图像的内容和风格之间的损失。 我们将使用均方损失如下。 请注意image1 - image2中的减法是两个图像数组之间逐元素的。 此减法有效因为图像已在load_image中调整为相同大小 def rms_loss(image1,image2):loss tf.reduce_mean(input_tensortf.square(image1 - image2))return loss接下来我们定义content_loss函数。 这只是函数签名中content和target之间的均方差 def content_loss(content, target):return rms_loss(content, target)风格损失是根据称为 Gram 矩阵的数量定义的。 Gram 矩阵也称为度量是风格矩阵及其自身的转置的点积。 因为这意味着图像矩阵的每一列都与每一行相乘所以我们可以认为原始表示中包含的空间信息已经分配。 结果是有关图像的非本地化信息例如纹理形状和权重即其风格。 产生gram_matrix的代码如下 def gram_matrix(input_tensor):channels int(input_tensor.shape[-1]) # channels is last dimensiontensor tf.reshape(input_tensor, [-1, channels]) # Make the image channels first number_of_channels tf.shape(inputtensor)[0] # number of channelsgram tf.matmul(tensor, tensor, transpose_aTrue) # produce tensorT*tensorreturn gram / tf.cast(number_of_channels, tf.float32) # scaled by the number of channels.因此风格损失其中gram_target将是混合图像上风格激活的 Gram 矩阵如下 def style_loss(style, gram_target):gram_style gram_matrix(style)return rms_loss(gram_style, gram_target) 接下来我们通过获取content_image和style_image并将它们馈入模型来找到content_features和style_features表示形式。 此代码分为两个块一个用于content_features另一个用于style_features。 对于内容块我们加载图像在其上调用我们的模型最后提取先前分配的特征层。 style_features的代码是相同的除了我们首先加载风格图像 def get_feature_representations(model, content_path, style_path):#Function to compute content and style feature representations.content_image load_and_process_image(content_path)content_outputs model(content_image)#content_features [content_layer[0] for content_layer in content_outputs[:number_of_content_layers]]content_features [content_layer[0] for content_layer in content_outputs[number_of_style_layers:]]style_image load_and_process_image(style_path)style_outputs model(style_image)style_features [style_layer[0] for style_layer in style_outputs[:number_of_style_layers]]return style_features, content_features接下来我们需要计算总损失。 查看该方法的签名我们可以看到首先我们传入模型可以访问 VGG19 的中间层。 接下来进入loss_weights它们是每个损失函数content_weightstyle_weight和总变化权重的每个贡献的权重。 然后我们有了初始图像即我们正在通过优化过程更新的图像。 接下来是gram_style_features和content_features分别对应于我们正在使用的风格层和内容层。 首先从方法签名中复制风格和content_weight。 然后在我们的初始图像上调用模型。 我们的模型可以直接调用因为我们使用的是急切执行如我们所见这是 TensorFlow 2 中的默认执行。此调用返回所有模型输出值。 然后我们有两个类似的块一个块用于内容一个块用于风格。 对于第一个内容块获取我们所需层中的内容和风格表示。 接下来我们累积来自所有内容损失层的内容损失其中每一层的贡献均被加权。 第二个块与第一个块相似不同之处在于这里我们累积来自所有风格损失层的风格损失其中每个损失层的每个贡献均被平均加权。 最后该函数返回总损失风格损失和内容损失如以下代码所示 def compute_total_loss(model, loss_weights, init_image, gram_style_features, content_features):style_weight, content_weight loss_weightsmodel_outputs model(init_image)content_score 0content_output_features model_outputs[number_of_style_layers:] weight_per_content_layer 1.0 / float(number_of_content_layers)for target_content, comb_content in zip(content_features, content_output_features):content_score weight_per_content_layer*content_loss(comb_content[0], target_content)content_score * content_weightstyle_score 0style_output_features model_outputs[:number_of_style_layers]weight_per_style_layer 1.0 / float(number_of_style_layers)for target_style, comb_style in zip(gram_style_features, style_output_features):style_score weight_per_style_layer style_loss(comb_style[0], target_style)style_score ** style_weighttotal_loss style_score content_scorereturn total_loss, style_score, content_score接下来我们有一个计算梯度的函数 def compute_grads(config):with tf.GradientTape() as tape: all_loss compute_total_loss(**config)# Compute gradients wrt input imagetotal_loss all_loss[0]return tape.gradient(total_loss, config[init_image]), all_lossimport IPython.display执行风格迁移 执行style_transfer的函数很长因此我们将分节介绍。 其签名如下 def run_style_transfer(content_path,style_path,number_of_iterations1000,content_weight1e3,style_weight1e-2):由于我们实际上不想训练模型中的任何层因此只需使用如前所述的层的输出值即可。 我们相应地设置其可训练属性 model get_model() for layer in model.layers:layer.trainable False接下来我们使用先前定义的函数从模型的各层获得style_features和content_features表示形式 style_features, content_features get_feature_representations(model, content_path, style_path)gram_style_features使用style_features上的循环如下所示 gram_style_features [gram_matrix(style_feature) for style_feature in style_features]接下来我们通过加载内容图像并将其转换为张量来初始化将成为算法输出的图像即混合图像也称为 Pastiche 图像 initial_image load_and_process_image(content_path) initial_image tf.Variable(initial_image, dtypetf.float32)下一行定义所需的AdamOptimizer函数 optimizer tf.compat.v1.train.AdamOptimizer(learning_rate5, beta10.99, epsilon1e-1)我们将继续保存best_image和best_loss因此请初始化变量以存储它们 best_loss, best_image float(inf), None接下来我们设置将被传递到compute_grads()函数的配置值字典 loss_weights (style_weight, content_weight)config {model: model,loss_weights: loss_weights,init_image: initial_image,gram_style_features: gram_style_features,content_features: content_features}这是显示常量 number_rows 2 number_cols 5 display_interval number_of_iterations/(number_rows*number_cols)接下来我们计算图像边界如下所示 norm_means np.array(channel_means) minimum_vals -norm_means maximum_vals 255 - norm_means 此列表将存储混合图像 images []接下来我们开始主图像处理循环如下所示 for i in range(number_of_iterations):因此接下来我们计算梯度计算损失调用优化器以应用梯度并将图像裁剪到我们先前计算的边界 grads, all_loss compute_grads(config)loss, style_score, content_score all_lossoptimizer.apply_gradients([(grads, initial_image)])clipped_image tf.clip_by_value(initial_image, minimum_vals, maximum_vals)initial_image.assign(clipped_image)我们将继续保存best_loss和best_image因此下一步 if loss best_loss:# Update best loss and best image from total loss. best_loss lossbest_image deprocess_image(initial_image.numpy()然后我们有条件地保存混合图像总共 10 张图像并将其与训练指标一起显示 if i % display_interval 0:# Use the .numpy() method to get the numpy image array, needs eager executionplot_image initial_image.numpy()plot_image deprocess_image(plot_image)images.append(plot_image)IPython.display.clear_output(waitTrue)IPython.display.display_png(Image.fromarray(plot_image))print(Iteration: {}.format(i)) print(Total loss: {:.4e}, style loss: {:.4e}, content loss: {:.4e} .format(loss, style_score, content_score))最后对于此函数我们显示所有best_image和best_loss IPython.display.clear_output(waitTrue)plt.figure(figsize(14,4))for i,image in enumerate(images):plt.subplot(number_rows,number_cols,i1)plt.imshow(image)plt.xticks([])plt.yticks([])return best_image, best_loss接下来我们调用前面的函数来获取best_image和best_loss还将显示 10 张图像 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HXgr5GW0-1681568242388)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/b5dbdb99-d9bd-49a3-94ff-1bf19b9e814b.png)] 的代码如下 best_image, best_loss run_style_transfer(content_path, style_path, number_of_iterations100) Image.fromarray(best_image)以下是best_image的显示 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FFvgqWEB-1681568242388)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/a98dd3a7-6f07-43a7-a4e1-71a4d002cc40.png)] 最终展示 最后我们有一个函数它与best_image一起显示内容和风格图像 def show_results(best_image, content_path, style_path, show_large_finalTrue):plt.figure(figsize(10, 5))content load_image(content_path)style load_image(style_path)plt.subplot(1, 2, 1)show_image(content, Content Image)plt.subplot(1, 2, 2)show_image(style, Style Image)if show_large_final:plt.figure(figsize(10, 10))plt.imshow(best_image)plt.title(Output Image)plt.show()接下来是对该函数的调用如下所示 show_results(best_image, content_path, style_path)总结 到此结束我们对神经风格迁移的研究。 我们看到了如何拍摄内容图像和风格图像并生成混合图像。 我们使用训练有素的 VGG19 模型中的层来完成此任务。 在下一章中我们将研究循环神经网络。 这些网络可以处理顺序的输入值并且输入值和输出值中的一个或两个具有可变长度。 八、TensorFlow 2 和循环神经网络 包括卷积网络CNN在内的许多神经网络体系结构的主要缺点之一是它们不允许处理顺序数据。 换句话说一个完整的特征例如图像必须一次全部呈现。 因此输入是固定长度张量而输出必须是固定长度张量。 先前特征的输出值也不会以任何方式影响当前特征。 同样所有输入值和输出值都应视为彼此独立。 例如在我们的fashion_mnist模型第 4 章“使用 TensorFlow 2的监督机器学习”中每个输入时尚图像都独立于并且完全不了解先前图像。 循环神经网络RNN克服了这个问题并使许多新的应用成为可能。 在本章中我们将研究以下主题 神经网络处理模式循环架构RNN 的应用我们的 RNN 示例的代码建立并实例化我们的模型训练和使用我们的模型 神经网络处理模式 下图说明了各种神经网络处理模式 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aK6d9UUU-1681568242389)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/8e01e880-e868-421b-a5a7-0a152e8795ed.png)] 矩形代表张量箭头代表函数红色是输入蓝色是输出绿色是张量状态。 从左到右我们有以下内容 普通前馈网络固定尺寸的输入和固定尺寸的输出例如图像分类序列输出例如拍摄一张图像并输出一组用于标识图像中项目的单词的图像字幕序列输入例如情感识别如我们的 IMDb 应用其中句子被分为正面情感或负面情感序列输入和输出例如机器翻译其中 RNN 接受英语句子并将其翻译为法语输出逐帧同步输入和输出的序列例如类似于视频分类的两者 循环架构 因此需要一种新的体系结构来处理顺序到达的数据并且其输入值和输出值中的一个或两个具有可变长度例如语言翻译应用中句子中的单词。 在这种情况下模型的输入和输出都具有不同的长度就像之前的第四种模式一样。 同样为了预测给定当前词的后续词还需要知道先前的词。 这种新的神经网络架构称为 RNN专门设计用于处理顺序数据。 出现术语循环是因为此类模型对序列的每个元素执行相同的计算其中每个输出都依赖于先前的输出。 从理论上讲每个输出都取决于所有先前的输出项但实际上RNN 仅限于回顾少量步骤。 这种布置等效于具有存储器的 RNN该存储器可以利用先前的计算结果。 RNN 用于顺序输入值例如时间序列音频视频语音文本财务和天气数据。 它们在消费产品中的使用示例包括 Apple 的 SiriGoogle 翻译和亚马逊的 Alexa。 将传统前馈网络与 RNN 进行比较的示意图如下 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F6LRavAT-1681568242389)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/98b325df-dafc-40e2-9825-80f9a1985632.png)] 每个 RNN 单元上的回送代表记忆。 前馈网络无法区分序列中的项目顺序而 RNN 从根本上取决于项目的顺序。 例如假设前馈网络接收到输入字符串aardvark到输入为d时网络已经忘记了先前的输入值为aa和r因此无法预测下一个va。 另一方面在给定相同输入的情况下循环网络“记住”先前的输入值为aa和r因此有可能根据其先前的训练来预测va是下一个。 RNN 的每个单独项目到网络的输入称为时间步长。 因此例如在字符级 RNN 中每个字符的输入都是一个时间步。 下图说明了 RNN 的展开。 时间步长从t 0开始输入为X[0]一直到时间步长t t输入为X[t]相应的输出值为h[0]至h[t]如下图所示 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jtG7eGKi-1681568242389)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/b33bb6fe-e10b-4a19-be19-ab717ecda115.png)] 展开式循环神经网络 RNN 在称为沿时间反向传播BPTT的过程中通过反向传播进行训练。 在此可以想象 RNN 的展开也称为展开会创建一系列神经网络并且会针对每个时间步长计算误差并将其合并以便可以使用反向传播更新网络中的权重。 例如为了计算梯度从而计算误差在时间步t 6时我们将向后传播五个步并对梯度求和。 但是在尝试学习长期依赖关系时即在相距很远的时间步之间这种方法存在问题因为梯度可能变得太小而使学习变得不可能或非常缓慢或者它们可能变得太大并淹没了网络。 这被称为消失/爆炸梯度问题并且已经发明了各种修改方法来解决它包括长短期记忆LSTM网络和门控循环单元GRU s我们将在以后使用。 下图显示了有关展开或展开的更多详细信息 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yiMjoKBM-1681568242389)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/e6d1b2a6-b40b-45bf-acbc-6c6c1433d13d.png)] 循环神经网络的示意图 在该图中我们可以看到以下内容 x[t]是时间步长t的输入。 例如x[t]可以是基于字符的 RNN 中的第十个字符表示为来自字符集的索引。s[t]是时间步t的隐藏状态因此是网络的内存。s[t]的计算公式为s[t] f(Ux[t] Ws[t-1])其中f是非线性函数例如 ReLU。 UV和W是权重。o[t]是时间步长t的输出。 例如如果我们要计算字符序列中的下一个字母它将是字符集o[t] Vs[t]的概率向量。 如前所述我们可以将s[t]视为网络的内存因为它包含有关网络中较早时间步长发生了什么的信息。 请注意权重UV和W在每个步骤中都是共享的因为我们在每个步骤都执行相同的计算只是使用不同的输入值 结果是学习权重的数量大大减少了。 还要注意我们可能不需要每个时间步长的输出值如图所示。 如果我们要进行情感分析每个步骤都是一个词比如说电影评论那么我们可能只关心最终的输出正面或负面。 现在让我们看一个使用 RNN 的有趣示例在该示例中我们尝试以给定的写作风格创建文本。 RNN 的应用 在此应用中我们将看到如何使用基于字符的循环神经网络创建文本。 更改要使用的文本的语料库很容易请参见下面的示例 在这里我们将使用查尔斯·狄更斯Charles Dickens的小说《伟大的期望》。 我们将在此文本上训练网络以便如果我们给它一个字符序列例如thousan它将产生序列中的下一个字符d。 此过程可以继续进行可以通过在不断演变的序列上反复调用模型来创建更长的文本序列。 这是训练模型之前创建的文本的示例 Input: o else is there to inform?”\n\n“Is there no chance person who might identify you in the street?” said\n Next Char Predictions: dUFdZ!mig())(ZIon“4gHZ”\nWGWtlinnqQY*dGJ7ioU6(vLKLcJ29LGlQW8n-,M!JSVy”cjN;1cH\ndEEeMXhtW$U8Mtsp这是一些文本其中包含Pip序列该序列是在模型经过 0.1 个温度请参阅下文进行 100 个周期约 10 秒每个的训练后创建的 Pip; it was not to be done. I had been a little while I was a look out and the strength of considerable particular by the windows of the rest of his prospering look at the windows of the room wing and the courtyard in the morning was the first time I had been a very much being strictly under the wall of my own person to me that he had done my sister, and I went on with the street common, I should have been a very little for an air of the river by the fire. For the man who was all the time of the money. My dear Herbert, who was a little way to the marshes he had ever seemed to have had once more than once and the more was a ragged hand before I had ever seemed to have him a dreadful loveriement in his head and with a falling to the table, and I went on with his arms, I saw him ever so many times, and we all the courtyard to the fire to be so often to be on some time when I saw his shoulder as if it were a long time in the morning I was a woman and a singer at the tide was remained by the 对于不了解语法或拼写的系统来说这并不是一个坏结果。 这显然是荒谬的但那时我们并不是在追求理性。 只有一个不存在的单词loveriement。 因此网络已经完成了学习拼写和学习单词是文本单元的工作。 还要注意在下面的代码中仅在短序列sequence_length 100上训练网络。 接下来我们将查看用于设置训练和测试循环神经网络的代码。 我们的 RNN 示例的代码 此应用基于 Google 根据 Apache 2 许可提供的应用。 像往常一样我们会将代码分解成片段然后将您引到存储库中获取许可证和完整的工作版本。 首先我们有模块导入如下所示 import tensorflow as tf import numpy as np import os import time接下来我们有文本文件的下载链接。 您可以通过在file中指定文件名和在url中指定文件的完整 URL轻松地将其更改为所需的任何文本 file1400-0.txt urlhttps://www.gutenberg.org/files/1400/1400-0.txt # Great Expectations by Charles Dickens然后我们为该文件设置了 Keras get_file()工具如下所示 path tf.keras.utils.get_file(file,url)然后我们打开并读取文件并以字符为单位查看文件的长度 text open(path).read() print (Length of text: {} characters.format(len(text)))在文件开头没有我们不需要的文本因此我们将其剥离掉然后再看一下前几个字符就很有帮助了接下来我们要做

strip off text we dont need

text text[835:]# Take a look at the first 300 characters in text print(text[:300])输出应如下所示 My fathers family name being Pirrip, and my Christian name Philip, my infant tongue could make of both names nothing longer or more explicit than Pip. So, I called myself Pip, and came to be called Pip.I give Pirrip as my fathers family name, on the authority of his tombstone and my sister,–Mrs现在让我们看一下文本中有多少个唯一字符使用一组字符来获取它们并按其 ASCII 码的顺序对其进行排序

The unique characters in the file

vocabulary sorted(set(text)) print ({} unique characters..format(len(vocabulary)))这应该提供 84 个唯一字符。 接下来我们创建一个字典其中字符是键而连续的整数是值。 这样我们就可以找到索引表示任何给定字符的数值

Create a dictionary of unique character keys to index values

char_to_index {char:index for index, char in enumerate(vocabulary)} print(char_to_index)输出如下 {\n: 0, : 1, !: 2, \(: 3, %: 4, : 5, : 6, (: 7, ): 8, *: 9, ,: 10, -: 11, .: 12, /: 13, 0: 14, 1: 15, 2: 16, 3: 17, 4: 18, 5: 19, 6: 20, 7: 21, 8: 22, 9: 23, :: 24, ;: 25, ?: 26, : 27, A: 28, B: 29, C: 30, D: 31, E: 32, F: 33, G: 34, H: 35, I: 36, J: 37, K: 38, L: 39, M: 40, N: 41, O: 42, P: 43, Q: 44, R: 45, S: 46, T: 47, U: 48, V: 49, W: 50, X: 51, Y: 52, Z: 53, a: 54, b: 55, c: 56, d: 57, e: 58, f: 59, g: 60, h: 61, i: 62, j: 63, k: 64, l: 65, m: 66, n: 67, o: 68, p: 69, q: 70, r: 71, s: 72, t: 73, u: 74, v: 75, w: 76, x: 77, y: 78, z: 79, ê: 80, ô: 81, “: 82, ”: 83}我们还需要将字符存储在数组中。 这样我们就可以找到与任何给定数值对应的字符即index index_to_char np.array(vocabulary) print(index_to_char)输出如下 [\n ! \) % ( ) * , - . / 0 1 2 3 4 5 6 7 8 9 : ; ? A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z ê ô “ ”]现在我们正在使用的整个文本已转换为我们作为字典创建的整数数组char_to_index text_as_int np.array([char_toindex[char] for char in text]这是字符及其索引的示例 print({) for char, in zip(char_to_index, range(20)):print( {:4s}: {:3d},.format(repr(char), char_to_index[char])) print( …\n})输出如下 {\n: 0, : 1,! : 2,$ : 3,% : 4, : 5, : 6,( : 7,) : 8,* : 9,, : 10,- : 11,. : 12,/ : 13,0 : 14,1 : 15,2 : 16,3 : 17,4 : 18,5 : 19,… }接下来查看文本如何映射为整数很有用 这是前几个

Show how the first 15 characters from the text are mapped to integers

print ({} —- characters mapped to int —- {}.format(repr(text[:15]), text_as_int[:15]))输出如下 My fathers fam —- characters mapped to int —- [40 78 1 59 54 73 61 58 71 6 72 1 59 54 66]然后我们设置每个输入的句子长度并因此设置训练周期中的示例数

The maximum length sentence we want for a single input in characters

sequence_length 100 examples_per_epoch len(text)//seq_length接下来我们创建data.Dataset以在以后的训练中使用

Create training examples / targets

char_dataset tf.data.Dataset.from_tensor_slices(text_as_int)

Display , sanity check

for char in char_dataset.take(5):print(index_to_char[char.numpy()])输出如下 M y f a我们需要批量此数据以将其馈送到我们的 RNN因此接下来我们要这样做 sequences char_dataset.batch(sequence_length1, drop_remainderTrue)请记住我们已经设置了sequence_length 100所以批量中的字符数是 101。 现在我们有了一个函数来创建我们的输入数据和目标数据必需的输出。 该函数返回我们一直在处理的文本以及相同的文本但是一起移动了一个字符即如果第一个单词是Python和sequence_length 5则该函数返回Pytho和ython 。 然后我们通过连接输入和输出字符序列来创建数据集 def split_input_target(chunk):input_text chunk[:-1]target_text chunk[1:]return input_text, target_textdataset sequences.map(split_input_target)接下来我们执行另一个健全性检查。 我们使用先前创建的数据集来显示输入和目标数据。 请注意dataset.take(n)方法从数据集中返回n批次。 在这里还请注意由于我们已经启用了急切执行当然默认情况下在 TensorFlow 2 中是这样因此我们可以使用numpy()方法来查找张量的值 for input_example, target_example in dataset.take(1):print (Input data: , repr(.join(index_to_char[input_example.numpy()]))) #101 charactersprint (Target data:, repr(.join(index_to_char[target_example.numpy()])))输出如下 Input data: My fathers family name being Pirrip, and my Christian name Philip, my\ninfant tongue could make of b Target data: y fathers family name being Pirrip, and my Christian name Philip, my\ninfant tongue could make of bo现在我们可以通过几个步骤显示输入和预期输出 for char, (input_index, target_index) in enumerate(zip(input_example[:5], target_example[:5])):print(Step {:4d}.format(char))print( input: {} ({:s}).format(input_index, repr(index_to_char[input_index])))print( expected output: {} ({:s}).format(target_index, repr(index_to_char[target_index])))以下是此输出 Step 0: input: 40 (M), expected output: 78 (y) Step 1: input: 78 (y), expected output: 1 ( ) Step 2: input: 1 ( ), expected output: 59 (f) Step 3: input: 59 (f), expected output: 54 (a) Step 4: input: 54 (a), expected output: 73 (t)接下来我们为训练进行设置如下所示

how many characters in a batch

batch 64# the number of training steps taken in each epoch steps_per_epoch examples_per_epoch//batch # note integer division# TF data maintains a buffer in memory in which to shuffle data

since it is designed to work with possibly endless data

buffer 10000dataset dataset.shuffle(buffer).batch(batch, drop_remainderTrue)# call repeat() on dataset so data can be re-fed into the model from the beginning dataset dataset.repeat()dataset这给出了以下数据集结构 RepeatBatchDataset shapes: ((64, 100), (64, 100)), types: (tf.int64, tf.int64)此处64是批次大小100是序列长度。 以下是我们训练所需的一些值

The vocabulary length in characters

vocabulary_length len(vocabulary)# The embedding dimension embedding_dimension 256# The number of recurrent neural network units recurrent_nn_units 1024我们正在使用 GRU在 CUDA 深度神经网络cuDNN库中如果代码在 GPU 上运行则可以使用这些例程进行快速计算。 GRU 是在 RNN 中实现内存的一种方式。 下一节将实现此想法如下所示 if tf.test.is_gpu_available():recurrent_nn tf.compat.v1.keras.layers.CuDNNGRUprint(GPU in use) else:import functoolsrecurrent_nn functools.partial(tf.keras.layers.GRU, recurrent_activationsigmoid)print(CPU in use)建立并实例化我们的模型 如我们先前所见一种用于构建模型的技术是将所需的层传递到tf.keras.Sequential()构造器中。 在这种情况下我们分为三层嵌入层RNN 层和密集层。 第一嵌入层是向量的查找表一个向量用于每个字符的数值。 它的尺寸为embedding_dimension。 中间循环层是 GRU 其大小为recurrent_nn_units。 最后一层是长度为vocabulary_length单元的密集输出层。 该模型所做的是查找嵌入使用嵌入作为输入来运行 GRU 一次然后将其传递给密集层该层生成下一个字符的对数对数赔率。 如下图所示 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FOZG37ap-1681568242390)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/3832c4d7-fb9f-40af-99bf-9f2c4acd2584.png)] 因此实现此模型的代码如下 def build_model(vocabulary_size, embedding_dimension, recurrent_nn_units, batch_size):model tf.keras.Sequential([tf.keras.layers.Embedding(vocabulary_size, embedding_dimension, batch_input_shape[batch_size, None]),recurrent_nn(recurrent_nn_units, return_sequencesTrue, recurrent_initializerglorot_uniform, statefulTrue),tf.keras.layers.Dense(vocabulary_length)])return model现在我们可以实例化我们的模型如下所示 model build_model(vocabulary_size len(vocabulary),embedding_dimensionembedding_dimension,recurrent_nn_unitsrecurrent_nn_units,batch_sizebatch)现在我们可以进行健全性检查以确保我们的模型输出正确的形状。 注意使用dataset.take()提取数据集的元素 for batch_input_example, batch_target_example in dataset.take(1):batch_predictions_example model(batch_input_example)print(batch_predictions_example.shape, # (batch, sequence_length, vocabulary_length))以下是此输出 (64, 100, 84) # (batch, sequence_length, vocabulary_length)这是预期的 回想一下我们的字符集中有84个唯一字符。 这是显示我们的模型外观的代码 model.summary()我们的模型架构摘要的输出如下 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P248FnJV-1681568242390)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/c16b150d-45b6-4f82-a596-8317ae714c1d.png)] 再次回想一下我们有84输入值我们可以看到对于嵌入层84 * 256 21,504对于密集层1024 * 84 84偏置单元 86,100。 使用我们的模型获得预测 为了从我们的模型中获得预测我们需要从输出分布中抽取一个样本。 此采样将为我们提供该输出分布所需的字符对输出分布进行采样很重要因为像通常那样对它进行argmax提取很容易使模型陷入循环。 在显示索引之前tf.random.categorical进行此采样axis-1与tf.squeeze删除张量的最后一个维度。 tf.random.categorical的签名如下 tf.random.categorical(logits, num_samples, seedNone, nameNone, output_dtypeNone)将其与调用进行比较我们看到我们正在从预测example_batch_predictions[0]中获取一个样本长度为sequence_length 100。 然后删除了多余的尺寸因此我们可以查找与示例相对应的字符 sampled_indices tf.random.categorical(logitsbatch_predictions_example[0], num_samples1)sampled_indices tf.squeeze(sampled_indices,axis-1).numpy()sampled_indices这将产生以下输出 array([79, 43, 3, 12, 20, 24, 54, 10, 61, 43, 46, 15, 0, 24, 39, 77, 2, 73, 4, 78, 5, 60, 13, 65, 1, 75, 47, 33, 61, 13, 64, 41, 32, 42, 40, 20, 37, 10, 60, 51, 21, 17, 69, 8, 3, 74, 64, 68, 2, 3, 35, 13, 67, 16, 46, 48, 47, 1, 38, 80, 47, 8, 32, 53, 50, 28, 63, 33, 35, 72, 80, 0, 7, 64, 2, 79, 1, 56, 61, 13, 55, 28, 62, 30, 40, 22, 32, 40, 27, 46, 21, 51, 10, 76, 64, 47, 72, 83, 45, 8])让我们看一下到训练之前的一些输入和输出** print(Input: \n, repr(.join(index_to_char[batch_input_example[0]])))print(Next Char Predictions: \n, repr(.join(index_to_char[sampled_indices ]))) #因此输出如下。 输入的文本之后是下一个字符预测在训练之前 Input: r, that I might refer to it again; but I could not find it, and\nwas uneasy to think that it must hav Next Char Predictions: hFTzJe;rAô:G*”x4d?ôce9QekL:*O7KuoZM“\(r0mg\n%/2-6QaE\))/Y8m.x)94b?fKp.rRô.3IMMTMjMMag.iL1LuM6 ?;接下来我们定义loss函数 def loss(labels, logits):return tf.keras.losses.sparse_categorical_crossentropy(labels, logits, from_logitsTrue)然后我们在训练之前查看模型的损失并进行另一次尺寸完整性检查 batch_loss_example tf.compat.v1.losses.sparse_softmax_cross_entropy(batch_target_example, batch_predictions_example) print(Prediction shape: , batch_predictions_example.shape, # (batch_size, sequence_length, vocab_size)) print(scalar_loss: , batch_loss_example.numpy())这将产生以下输出 Prediction shape: (64, 100, 84) # (batch, sequence_length, vocabulary_length) scalar_loss: 4.429237为了准备我们的训练模型我们现在使用AdamOptimizer和 softmax 交叉熵损失对其进行编译 #next produced by upgrade script…. #model.compile(optimizer tf.compat.v1.train.AdamOptimizer(), loss loss) #…. but following optimizer is available. model.compile(optimizer tf.optimizers.Adam(), loss loss) 我们将保存模型的权重因此接下来我们为此准备检查点

The checkpoints will be saved in this directory

directory ./checkpoints# checkpoint files fileprefix os.path.join(directory, ckpt{epoch}) callback[tf.keras.callbacks.ModelCheckpoint(filepathfile_prefix, save_weights_onlyTrue)]最后我们可以使用对model.fit()的调用来训练模型 epochs45 # much faster on GPU, ~10s / epoch, reduce this figure significantly if on CPU history model.fit(dataset, epochsepochs, steps_per_epochsteps_per_epoch, callbackscallback)这给出以下输出 Epoch 150 158158 [] - 10s 64ms/step - loss: 2.6995 ……………….. Epoch 5050 158158 [] - 10s 65ms/step - loss: 0.6143以下是最新的检查点 tf.train.latest_checkpoint(directory)可以解决以下结果 ./checkpoints/ckpt_45因此我们可以重建模型以展示其完成方式 model build_model(vocabulary_size, embedding_dimension, recurrent_nn_units, batch_size1)model.load_weights(tf.train.latest_checkpoint(directory))model.build(tf.TensorShape([1, None]))model.summary()下表显示了我们模型的摘要 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pZULE1kS-1681568242390)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/3066d8ab-9f14-4449-a8eb-f5416c4e6af9.png)] 接下来在给定训练有素的模型起始字符串和温度的情况下我们使用一个函数来生成新文本其值确定文本的随机性低值给出更多可预测的文本高值给出更多随机的文本。 首先我们确定要生成的字符数然后向量化起始字符串并为其添加空白尺寸。 我们将额外的维添加到input_string变量中因为 RNN 单元需要它两个必需的维是批量长度和序列长度。 然后我们初始化一个变量用于存储生成的文本。 temperature的值确定生成的文本的随机性较低的随机性较小意味着更可预测。 在一个循环中对于要生成的每个新字符我们使用包含 RNN 状态的模型来获取下一个字符的预测分布。 然后使用多项式分布来找到预测字符的索引然后将其用作模型的下一个输入。 由于存在循环模型返回的 RNN 状态将反馈到模型中因此它现在不仅具有一个字符而且具有更多信息。 一旦预测了下一个字符就将修改后的 RNN 状态反复反馈到模型中以便模型学习因为它从先前预测的字符获得的上下文会增加。 下图显示了它是如何工作的 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HQsXxfir-1681568242391)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/8cf34e04-9d73-46cc-b1aa-7bcd0a5342b3.png)] 在这里多项式用tf.random.categorical实现 现在我们准备生成我们的预测文本 def generate_text(model, start_string, temperature, characters_to_generate):# Vectorise the start string into numbers input_string [char_to_index[char] for char in start_string]

add extra dimension to input_stringinput_string tf.expand_dims(input_string, 0)# Empty list to store generated textgenerated []# (batch size is 1)model.reset_states()for i in range(characters_to_generate):predictions model(input_string) #heres where we need the extra dimension# remove the batch dimensionpredictions tf.squeeze(predictions, 0)# using a random categorical (multinomial) distribution to predict word returned by the modelpredictions predictions / temperaturepredicted_id tf.random.categorical(logitspredictions, num_samples1)[-1,0].numpy()# Pass predicted word as next input to the model along with previous hidden stateinput_string tf.expand_dims([predicted_id], 0)generated.append(index_to_char[predicted_id])

return (start_string .join(generated)) # generated is a list因此在定义函数之后我们可以调用它以返回生成的文本。 在给定的函数参数中低温给出更多可预测的文本而高温给出更多随机的文本。 同样您可以在此处更改起始字符串并更改函数生成的字符数 generated_text generate_text(modelmodel, start_stringPip, temperature0.1, characters_to_generate 1000) print(generated_text)经过 30 个训练周期后将产生以下输出 Pip; it was a much better to and the Aged and weaking his hands of the windows of the way who went them on which the more I had been a very little for me, and I went on with his back in the soldiers of the room with the whole hand the other gentleman with the hand on the service, when I was a look of half of the room was was the first time of the money. I forgetter, Mr. Pip?” “I dont know that I have no more than I know what I have no inquiry with the rest of its being straight up again. He came out of the room, and in the midst of the room was was all the words, “and he came into the Castle. One would repeat it to your expectations condition of the courtyard. In a moment was the first time in the house to the fork, and we all lighted and at his being so beautiful looking at the convicts. My depression of the morning, I looked at him in the morning, I should not have been made a strong for the first time of the wall before the table to the forefinger of the room, and had not quite diffiLoss 0.6761 该文本或多或少地被正确地拼写和标点尽管其含义我们并未试图实现的含义在很大程度上是愚蠢的。 它还没有学习如何正确使用语音标记。 只有两个无意义的单词forgetter和weaking经过检查在语义上仍然是合理的。 生成的是否为 Charles Dickens 风格是一个悬而未决的问题。 周期数的实验表明损失在约 45 周期时达到最小值此后它开始增加。 45 个周期后输出如下 Pip; or I should have felt painfully consciousness that he was the man with his back to the kitchen, and he seemed to have no strength, and as I had often seen her shutters with the poker on the parlor, through having been every disagreeable to be seen; I thought I would give him more letters of my own eyes and flared about the fire, and showed the greatest state of mind, I thought I would give up of his having fastened out of the room, and had made some advance in that respect to me to feel an indescribable awe as it was a to be even than ever of her steps, or for old asked, “Yes.”“What is it?” repeated Mr. Jaggers. “You know I was in my mind by his blue eyes most of all admirers, and that she had shaken hands contributing the poker out of his hands in his pockets and his dinner loosely tied in a busy preparation for the reference to my United and self-possession when Miss Havisham and Estella now that I had been too much to be the salvey dark night, which seemed so long ago. “Yes, deLoss 0.6166 该模型现在似乎已正确配对了语音标记并且没有无意义的单词。 总结 这样就结束了我们对 RNN 的研究。 在本章中我们首先讨论了 RNN 的一般原理然后介绍了如何获取和准备一些供模型使用的文本并指出在此处使用替代文本源很简单。 然后我们看到了如何创建和实例化我们的模型。 然后我们训练了模型并使用它从起始字符串中产生文本并注意到网络已了解到单词是文本的单元以及如何拼写各种各样的单词有点像文本作者的风格 几个非单词。 在下一章中我们将研究 TensorFlow Hub 的使用它是一个软件库。 九、TensorFlow 估计器和 TensorFlow HUB 本章分为两部分但是此处的技术是相关的。 首先我们将研究 TensorFlow 估计器如何为 TensorFlow 提供简单的高级 API其次我们将研究 TensorFlow Hub 如何包含可在自己的应用中使用的模块。 在本章中我们将涵盖以下主要主题 TensorFlow 估计器TensorFlow HUB TensorFlow 估计器 tf.estimator是 TensorFlow 的高级 API。 它通过提供用于服务模型的直接训练评估预测和导出的方法来简化机器学习编程。 估计器为 TensorFlow 开发人员带来了许多优势。 与低级 API 相比使用估计器开发模型更容易更直观。 特别是同一模型可以在本地计算机或分布式多服务器系统上运行。 该模型也不了解其所处的处理器即 CPUGPU 或 TPU。 估计器还通过简化模型开发人员共享实现的过程简化了开发过程并且由于构建在 Keras 层上因此使自定义更加简单。 估计器会处理与 TensorFlow 模型一起使用的所有背景管线。 它们支持安全分布式的训练循环用于图构建变量初始化数据加载异常处理创建检查点文件从故障中恢复以及为 TensorBoard 保存摘要。 正如我们将看到的由于它们创建检查点因此它们支持在给定数量的步骤之后停止和开始训练。 开发估计器模型的过程分为四个步骤 采集数据并创建数据函数创建特征列实例化估计器评估模型的表现 我们将在以下代码中举例说明这些步骤。 我们之前已经看过fashion_mnist数据集在第 5 章“将 TensorFlow 2 用于无监督学习”因此我们将再次使用该数据集来演示估计器的用例。 代码 首先这是必需的导入 import tensorflow as tf import numpy as np接下来我们获取并预处理数据。 注意tf.keras.datasets中方便地存在fashion_mnist。 数据集中的x值采用整数 NumPy 数组的形式每个元素的范围为 0 到 255代表28 x 28像素时尚图像中每个像素的灰度值。 为了进行训练必须将这些值转换为 0 到 1 范围内的浮点数。y值采用无符号 8 位整数(uint8)的形式并且必须转换为 32 位整数int32 供估计工具再次使用。 尽管可以用以下方法试验该超参数值但将学习率设置为一个很小的值 fashion tf.keras.datasets.fashion_mnist (x_train, y_train),(x_test, y_test) fashion.load_data() print(type(x_train)) x_train, x_test x_train / 255.0, x_test / 255.0y_train, y_test np.int32(y_train), np.int32(y_test)learning_rate 1e-4之后是我们的训练输入特征。 当您具有数组中的完整数据集并需要快速进行批量混排和/或重复的方法时将使用tf.compat.v1.estimator.inputs.numpy_input_fn。 其签名如下 tf.compat.v1.estimator.inputs.numpy_input_fn(x,yNone,batch_size128,num_epochs1,shuffleNone,queue_capacity1000,num_threads1 )将此与我们对函数的调用进行比较您可以看到x值如何作为 NumPy 数组的字典与张量兼容传递以及y照原样传递。 在此阶段我们尚未指定周期数即该函数将永远运行稍后将指定步骤我们的批量大小即一步中显示的图像数为50 并在每一步之前将数据在队列中混洗。 其他参数保留为其默认值 train_input_fn tf.compat.v1.estimator.inputs.numpy_input_fn(x{x: x_train},yy_train,num_epochsNone,batch_size50,shuffleTrue )值得一提的是尽管这样的便利函数虽然在 TensorFlow 2.0 alpha 中不可用但仍有望改用 TensorFlow2。 测试函数具有相同的签名但是在这种情况下我们仅指定一个周期并且正如 Google 所建议的那样我们不会对数据进行混洗。 同样其余参数保留为其默认值 test_input_fn tf.compat.v1.estimator.inputs.numpy_input_fn(x{x: x_test},yy_test,num_epochs1,shuffleFalse )接下来我们建立特征列。 特征列是一种将数据传递给估计器的方法。 特征列函数的签名如下。 key是唯一的字符串是与我们先前在输入函数中指定的字典名称相对应的列名称有关不同类型的特征列的更多详细信息请参见这里 tf.feature_column.numeric_column(key,shape(1,),default_valueNone,dtypetf.float32,normalizer_fnNone )在我们的特定特征列中我们可以看到关键是x并且形状就是fashion_mnist数据集图像的28 x 28像素形状 feature_columns [tf.feature_column.numeric_column(x, shape[28, 28])]接下来我们实例化我们的估计器它将进行分类。 它将为我们构建一个深度神经网络。 它的签名很长很详细因此我们将带您参考这里因为我们将主要使用其默认参数。 它的第一个参数是我们刚刚指定的特征而第二个参数是我们的网络规模。 输入层和输出层由估计器在后台添加。AdamOptimizer是安全的选择。 n_classes对应于我们fashion_mnist数据集的y标签数量我们在其中添加了0.1的适度dropout。 然后model_dir是我们保存模型参数及其图和检查点的目录。 此目录还用于将检查点重新加载到估计器中以继续训练

Build 2 layer DNN classifier

classifier tf.estimator.DNNClassifier(feature_columnsfeature_columns,hidden_units[256, 32],optimizertf.compat.v1.train.AdamOptimizer(learning_rate),n_classes10,dropout0.1,model_dir./tmp/mnist_modelx , loss_reductiontf.compat.v1.losses.Reduction.SUM)现在我们准备训练模型。 如果您第二次或之后运行.train循环则 Estimator 将从model_dir加载其模型参数并进行进一步的steps训练要完全从头开始只需通过model_dir删除指定的目录 classifier.train(input_fntrain_input_fn, steps10000)典型的输出线如下所示 INFO:tensorflow:loss 25.540459, step 1600 (0.179 sec) INFO:tensorflow:global_step/sec: 523.471最终输出如下所示 INFO:tensorflow:Saving checkpoints for 10000 into ./tmp/mnist_modelx/model.ckpt. INFO:tensorflow:Loss for final step: 13.06977.model_dir中指定的目录如下所示 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U64r8MOy-1681568242391)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/27a244c6-21a0-4834-a28a-4718d7197716.png)] 为了评估模型的表现使用了classifier.evaluate方法。 其签名如下 classifier.evaluate(input_fn, stepsNone, hooksNone, checkpoint_pathNone, nameNone)这将返回一个字典因此在我们的调用中我们正在提取准确率指标。 在此steps默认为None。 这将评估模型直到input_fn引发输入结束异常即它将评估整个测试集 accuracy_score classifier.evaluate(input_fntest_input_fn)[accuracy]print(\nTest Accuracy: {0:f}%\n.format(accuracy_score*100))我们还可以使用以下命令在 TensorBoard 中查看训练的进度 tensorboard –logdir./tmp/mnist_modelx此处损失图如下所示其中x轴以 1,000k单位表示 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cBbtQqFb-1681568242391)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/5b1262f0-e388-4537-ae0f-fe7ee09b7bb9.png)] 到此结束我们对时尚估计器分类器的了解。 现在我们来看看 TensorFlow Hub。 TensorFlow HUB TensorFlow Hub 是一个软件库。 其目的是提供可重用的组件称为模块这些组件可在开发组件的原始上下文之外的上下文中使用。 所谓模块是指 TensorFlow 图的一个独立部分及其权重可以在其他类似任务中重复使用。 IMDb电影评论数据库 在本节中我们将研究一种基于 Google 的应用该应用在情感分析中分析了电影评论的 IMDb 的子集。 该子集由斯坦福大学主持包含每部电影的评论以及情感积极性等级为 1 到 4差和 7 到 10好的情感。 问题在于确定关于每个电影的文本句子中表达的视图的极性即针对每个评论以确定它是正面评论还是负面评论。 我们将在 TensorFlow Hub 中使用一个模块该模块先前已经过训练以生成单词嵌入。 词嵌入是数字的向量因此具有相似含义的词也具有类似的向量。 这是监督学习的示例因为评论的训练集将使用 IMDB 数据库提供的阳性值来训练模型。 然后我们将在测试集上使用经过训练的模型并查看其预测与 IMDB 数据库中存储的预测相比如何从而为我们提供了一种准确率度量。 可以在这个页面中找到该数据库论文的引文。 数据集 以下是数据库随附的自述文件 “The core dataset contains 50,000 reviews split evenly into 25k train and 25k test sets. The overall distribution of labels is balanced (25k pos and 25k neg).” “In the entire collection, no more than 30 reviews are allowed for any given movie because reviews for the same movie tend to have correlated ratings. Further, the train and test sets contain a disjoint set of movies, so no significant performance is obtained by memorizing movie-unique terms and their associated with observed labels. In the labeled train/test sets, a negative review has a score 4 out of 10, and a positive review has a score 7 out of 10. Thus, reviews with more neutral ratings are not included in the train/test sets.” 这是从 IMDb 训练头的顶部起的五行示例 句子情感极性0I came here for a review last night before dec…301Look, Im reading and reading these comments and…402I was overtaken by the emotion. Unforgettable …1013This movie could have been a decent B-movie if…404I have a thing for old black and white movies …101 这是其尾部的五行 句子情感极性24995I have watched some pretty poor films in the p…1024996This film is a calculated attempt to cash in t…1024997This movie was so very badly written. The char…1024998I am a huge Stooges fan but the one and only r…2024999Well, let me start off by saying how utterly H…30 以下是测试集 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6rt0t3NU-1681568242392)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/2bfa077e-c4cd-43a1-9140-74b375ee7897.png)] 代码 现在让我们看一下在这些数据上训练的代码。 在程序的顶部我们有通常的导入以及可能需要与pip – tensorflow_hubpandas和seaborn一起安装的三个额外的导入。 如前所述我们将使用tensorflow_hub中的模块 我们还将使用pandas的一些DataFrame属性和seaborn的一些绘制方法 import tensorflow as tf import tensorflow_hub as hub import matplotlib.pyplot as plt import numpy as np import os import pandas as pd import re import seaborn as sns另外这是一些值和我们稍后需要的方法 n_classes 2 hidden_units [500,100] learning_rate 1e-4 steps 1000 optimizer tf.optimizers.Adagrad(learning_ratelearning_rate)

upgrade script gave this:

#optimizer tf.compat.v1.train.AdagradOptimizer(learning_rate learning_rate)重要的是要认识到这里使用的 IMDb 数据是目录的分层结构形式。 顶级 IMDb 目录包含两个子目录train和test。 train和test子目录分别包含另外两个子目录pos和neg pos包含文本文件的集合。 每个文本文件都是正面评价极性为 1。neg包含文本文件的集合。 每个文本文件都是负面评论极性为 0。 情感分别为 7 到 10 或 1 到 4记录在文件名中 例如文件名为18_7.txt的文本文件评论的情感为 7pos而文件名为38_2.txt的文本文件评论的情感为 2neg [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PM7BuP4E-1681568242392)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/5b2f5728-0221-484e-b748-dd9191aa5d53.png)] IMDb 目录/文件层次结构 我们从调用层次结构中的三个函数开始这些函数获取并预处理审阅数据。 在第一个函数load_data(directory)中directory_data是一个字典其中加载了directory中的数据该数据作为参数传入并作为 pandas DataFrame返回。 用description和sentiment键初始化directorydata字典然后将它们分配为空列表作为值。 然后该函数循环遍历directory中的每个文件并且对于每个文本文件读取其内容作为电影评论并将其附加到情感列表中。 然后它使用正则表达式分析文件名并提取数字情感如前所示该数字情感紧随文件名中的下划线。 该函数将此数字情感附加到sentiment列表中。 当所有.txt文件都循环通过后该函数将返回已转换为 pandas DataFrame的字典

Load all files from a directory into a Pandas DataFrame.

def load_data(directory):directory_data {}directory_data[description] []directory_data[sentiment] []for file in os.listdir(directory):with tf.io.gfile.GFile(os.path.join(directory, file), r) as f:directory_data[description].append(f.read())directorydata[sentiment].append(re.match(\d(\d).txt, file).group(1))return pd.DataFrame.from_dict(directory_data)如我们前面所述下一个函数load(directory)调用load_data(directory)从pos和neg子目录创建一个DataFrame。 它将适当的极性作为额外字段添加到每个DataFrame。 然后它返回一个新的DataFrame该数据帧由pos和neg的DataFrame的连接组成经过混洗sample(frac1)并插入了新的数字索引因为我们已经对行进行了混排

Merge positive and negative examples, add a polarity column and shuffle.

def load(directory):positive_df load_data(os.path.join(directory, pos))positive_df[polarity] 1negative_df load_data(os.path.join(directory, neg))negative_df[polarity] 0return pd.concat([positive_df, negative_df]).sample(frac1).reset_index(dropTrue)第三个也是最后一个函数是acquire_data()。 如果缓存中不存在该函数则使用 Keras 工具从 Stanford URL 中获取我们所需的文件。 默认情况下高速缓存是位于~/.keras/datasets的目录如有必要文件将提取到该位置。 该工具将返回到我们的 IMDb 的路径。 然后将其传递给load_dataset()的两个调用以获取训练和测试DataFrame

Download and process the dataset files.

def acquire_data():data tf.keras.utils.get_file(fnameaclImdb.tar.gz,originhttp://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz, extractTrue)train_df load(os.path.join(os.path.dirname(data), aclImdb, train))test_df load(os.path.join(os.path.dirname(data), aclImdb, test))return train_df, test_df tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)主程序要做的第一件事是通过调用我们刚刚描述的函数来获取训练并测试 pandas DataFrame train_df, test_df acquire_data()此时train_df和test_df包含我们要使用的数据。 在查看下一个片段之前让我们看一下它的签名。 这是一个估计器它返回用于将 Pandas DataFrame馈入模型的输入函数 tf.compat.v1.estimator.inputs.pandas_input_fn(x, yNone, batch_size128, num_epochs1, shuffleNone, queue_capacity1000, num_threads1, target_columntarget)调用本身如下

Training input on the whole training set with no limit on training epochs

train_input_fn tf.compat.v1.estimator.inputs.pandas_input_fn(train_df, train_df[polarity], num_epochsNone, shuffleTrue)通过将此调用与函数签名进行比较我们可以看到训练数据帧train_df与每个评论的极性一起传入。 num_epochs None表示对训练周期的数量没有限制因为我们将在后面进行指定 shuffleTrue表示以随机顺序读取记录即文件的每一行。 接下来是预测训练结果的函数

Prediction on the whole training set.

predict_train_input_fn tf.compat.v1.estimator.inputs.pandas_input_fn(train_df, train_df[polarity], shuffleFalse)我们还具有预测测试结果的函数

Prediction on the test set.

predict_test_input_fn tf.compat.v1.estimator.inputs.pandas_input_fn(test_df, test_df[polarity], shuffleFalse)然后我们有特征列。 特征列是原始数据和估计器之间的中介。 共有九种特征列类型。 它们根据其类型采用数值或分类数据然后将数据转换为适用于估计器的格式。 在这个页面上有一个出色的描述以及许多示例。 请注意嵌入来自tf.hub embedded_text_feature_column hub.text_embedding_column(keydescription,module_spechttps://tfhub.dev/google/nnlm-en-dim128/1)接下来我们有我们的深度神经网络估计器。 估计器是用于处理模型的高级工具。 估计器的示例包括DNNClassifier即用于 TensorFlow 深层神经网络的分类器在以下代码中使用以及LinearRegressor即用于线性回归问题的分类器。 其签名如下 tf.estimator.DNNClassifier(hidden_units, feature_columns, model_dirNone, n_classes2, weight_columnNone, label_vocabularyNone, optimizerAdagrad, activation_fnfunction relu at 0x7fbb75512488, dropoutNone, input_layer_partitionerNone, configNone, warm_start_fromNone, loss_reductionweighted_sum, batch_normFalse, loss_reductionNone)让我们将此与通话进行比较 estimator tf.estimator.DNNClassifier(hidden_units hidden_units,feature_columns[embedded_text_feature_column],n_classesn_classes,optimizer optimiser,model_dir ./tmp/IMDbModel , loss_reductiontf.compat.v1.losses.Reduction.SUM)我们可以看到我们将使用具有 500 和 100 个单元的隐藏层的神经网络我们先前定义的特征列两个输出类标签和ProximalAdagrad优化器。 请注意与前面的示例一样由于我们指定了model_dir因此估计器将保存一个检查点和各种模型参数以便在重新训练时将从该目录加载模型并对其进行进一步的训练steps。 现在我们可以使用以下代码来训练我们的网络 estimator.train(input_fntrain_input_fn, stepssteps);此代码块为我们的结果造成混淆矩阵。 在我们的上下文中混淆矩阵是一个图表显示了经过训练的模型的以下内容 真阳性真实的正面情感被正确地预测为正面的评论右下真阴性真实的负面情感被正确地预测为负面的评论左上假阳性真实的负面情感被错误地预测为正面的评论右上假阴性真实的正面情感被错误地预测为负面的评论左下 以下是我们的训练集的混淆矩阵 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XJyW4h3v-1681568242392)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/788706bf-771d-4d36-be04-a6c134703cfb.png)] 训练集的混淆矩阵 原始数据如下 | 9,898 | 2602 | | 2,314 | 10,186 | 注意总数是 25,000这是我们使用的训练示例的数量。 这是我们测试集的混淆矩阵 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OhYxNAfB-1681568242392)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-20-quick-start-guide/img/0c50c8c8-6cec-4269-8fc3-7dfdf34ea031.png)] 测试集的混淆矩阵 原始数据如下 | 9859 | 2641 | | 2500 | 10000 | 对于混淆矩阵重要的是对角线的值左上到右下要比该对角线的值高得多。 我们可以从混淆矩阵中立即看到我们的模型在训练和测试集上都表现良好如果在测试集上差一些。 在代码中我们首先有一个获取预测的函数 def get_predictions(estimator, input_fn):return [prediction[class_ids][0] for prediction in estimator.predict(input_fninput_fn)]TensorFlow 有一种创建混淆矩阵的方法如前所述它们可以显示在原始图中。 其签名如下 tf.math.confusion_matrix(labels, predictions, num_classesNone, dtypetf.int32, nameNone, weightsNone)在这里labels是真实的标签。 我们的代码调用如下方法 confusion_train tf.math.confusion_matrix(labelstrain_df[polarity], predictionsget_predictions(estimator, predict_train_input_fn)) print(Raw figures:) print(confusion_train.numpy())接下来我们对混淆矩阵进行归一化以便其行总计为 1

Normalize the confusion matrix so that each row sums to 1.top confusion_train.numpy()

bottom np.sum(top) confusion_train 2*top/bottom最后我们使用seaborn方法heatmap绘制混淆矩阵。 此方法的签名很长且很详细因此查看它的最简单方法是在 Jupyter 笔记本中将光标放在Shift TAB上。 我们在这里只需要四个参数 sns.heatmap(confusion_train, annotTrue, xticklabelsLABELS, yticklabelsLABELS) plt.xlabel(Predicted) plt.ylabel(True)在这里我们得到以下内容 LABELS [negative, positive]除了使用测试集代替训练集之外用于显示测试集的混淆矩阵的代码是相同的

Create a confusion matrix on test data.

confusion_test tf.math.confusion_matrix(labelstest_df[polarity], predictionsget_predictions(estimator, predict_test_input_fn)) print(confusion_test.numpy())

Normalize the confusion matrix so that each row sums to 1.

top confusion_test.numpy() bottom np.sum(top) confusion_test 2*top/bottom sns.heatmap(confusion_test, annotTrue, xticklabelsLABELS, yticklabelsLABELS); plt.xlabel(Predicted); plt.ylabel(True);到此结束我们对 IMDb 情感分析的研究。 总结 在本章中我们介绍了用于训练时装数据集的估计器。 我们了解了估计器如何为 TensorFlow 提供简单直观的 API。 然后我们查看了另一个应用这一次是对 IMDb 中电影评论的情感分类。 我们看到了 TensorFlow Hub 如何为我们提供文本嵌入即单词的向量这是具有相似含义的单词具有相似向量的地方。 在本书中我们看到了 TensorFlow 2.0 alpha 的概述。 十、从 tf1.12 转换为 tf2 Google 提供了一个名为 tf_upgrade_v2的命令行脚本该脚本会将 1.12 版文件.py和.ipynb文件转换为 TensorFlow 2 兼容文件。 此转换的语法如下 tf_upgrade_v2 –infile file_to_convert –outfile converted_file这里是更新脚本的实战演示以及有关它的更多详细信息请参见这里 。 重要的是要注意在运行脚本之前不应该手动更新代码部分。 该脚本不会解决所有问题但是它生成的报告将标识那些必须手动解决的问题。 特别是tf.contrib已从 TF2 中删除因此必须跟踪并手动修复以前驻留在其中的函数。 这是脚本生成的报告的示例 Processing file Chapter1_TF2_Snippets.ipynboutputting to Chapter1_TF2_alpha——————————————————————————–37:4: INFO: Added keywords to args of function tf.size48:13: INFO: Added keywords to args of function tf.transpose74:0: INFO: Added keywords to args of function tf.reduce_mean75:0: INFO: Added keywords to args of function tf.reduce_mean76:0: INFO: Added keywords to args of function tf.reduce_mean77:0: INFO: Added keywords to args of function tf.reduce_mean78:0: INFO: Added keywords to args of function tf.reduce_mean110:4: INFO: Added keywords to args of function tf.argmax114:4: INFO: Added keywords to args of function tf.argmin121:4: INFO: Added keywords to args of function tf.argmax123:4: INFO: Added keywords to args of function tf.argmin127:4: INFO: Added keywords to args of function tf.argmax129:4: INFO: Added keywords to args of function tf.argmin136:0: ERROR: Using member tf.contrib.integrate.odeint in deprecated module tf.contrib. tf.contrib.integrate.odeint cannot be converted automatically. tf.contrib will not be distributed with TensorFlow 2.0, please consider an alternative in non-contrib TensorFlow, a community-maintained repository, or fork the required code.162:10: INFO: Added keywords to args of function tf.transpose173:11: INFO: Added keywords to args of function tf.reduce_mean