训练神经网络主要围绕以下四个方面。
层,多个层组合成网络(或模型)。
输入数据和相应的目标。
损失函数,即用于学习的反馈信号。
优化器,决定学习过程如何进行。
将这四者的关系可视化,如下图所示:多个层链接在一起组成了网络,将输入数据映射为预测值。然后损失函数将这些预测值与目标进行比较,得到损失值,用于衡量网络预测值与预期结果的匹配程度。优化器使用这个损失值来更新网络的权重。
[successbox title="层:深度学习的基础组件"]
神经网络的基本数据结构是层。层是一个数据处理模块,将一个或多个输入张量转换为一个或多个输出张量。有些层是无状态的,但大多数的层是有状态的,即层的权重。权重是利用随机梯度下降学到的一个或多个张量,其中包含网络的知识。
不同的张量格式与不同的数据处理类型需要用到不同的层。例如,简单的向量数据保存在形状为 (samples, features) 的 2D 张量中,通常用密集连接层[densely connected layer,也叫全连接层(fully connected layer)或密集层(dense layer),对应于 Keras 的 Dense 类]来处理。序列数据保存在形状为 (samples, timesteps, features) 的 3D 张量中,通常用循环层(recurrent layer,比如 Keras 的 LSTM 层)来处理。图像数据保存在 4D 张量中,通常用二维
卷积层(Keras 的 Conv2D)来处理。
你可以将层看作深度学习的乐高积木,Keras 等框架则将这种比喻具体化。在 Keras 中,构建深度学习模型就是将相互兼容的多个层拼接在一起,以建立有用的数据变换流程。这里层兼容性(layer compatibility)具体指的是每一层只接受特定形状的输入张量,并返回特定形状的输出张量。
from keras import layers
# 有 32 个输出单元的密集层
layer = layers.Dense(32, input_shape=(784,))
我们创建了一个层,只接受第一个维度大小为 784 的 2D 张量(第 0 轴是批量维度,其大小没有指定,因此可以任意取值)作为输入。这个层将返回一个张量,第一个维度的大小变成了 32。
因此,这个层后面只能连接一个接受 32 维向量作为输入的层。使用 Keras 时,你无须担心兼容性,因为向模型中添加的层都会自动匹配输入层的形状,例如下面这段代码。
from keras import layers
from keras import models
model = models.Sequential()
# 有 32 个输出单元的密集层
model.add(layers.Dense(32, input_shape=(784,)))
model.add(layers.Dense(32))
其中第二层没有输入形状(input_shape)的参数,相反,它可以自动推导出输入形状等于上一层的输出形状。
[/successbox]
[successbox title="模型:层构成的网络"]
深度学习模型是层构成的有向无环图。最常见的例子就是层的线性堆叠,将单一输入映射为单一输出。
但随着深入学习,你会接触到更多类型的网络拓扑结构。一些常见的网络拓扑结构如下。
双分支(two-branch)网络
多头(multihead)网络
Inception 模块
网络的拓扑结构定义了一个假设空间(hypothesis space)。你可能还记得第 1 章里机器学习的定义:“在预先定义好的可能性空间中,利用反馈信号的指引来寻找输入数据的有用表示。”选定了网络拓扑结构,意味着将可能性空间(假设空间)限定为一系列特定的张量运算,将输入数据映射为输出数据。然后,你需要为这些张量运算的权重张量找到一组合适的值。
选择正确的网络架构更像是一门艺术而不是科学。虽然有一些最佳实践和原则,但只有动手实践才能让你成为合格的神经网络架构师。后面几章将教你构建神经网络的详细原则,也会帮你建立直觉,明白对于特定问题哪些架构有用、哪些架构无用。
[/successbox]
[successbox title="损失函数与优化器:配置学习过程的关键"]
一旦确定了网络架构,你还需要选择以下两个参数。
损失函数(目标函数)——在训练过程中需要将其最小化。它能够衡量当前任务是否已成功完成。
优化器——决定如何基于损失函数对网络进行更新。它执行的是随机梯度下降(SGD)的某个变体。
具有多个输出的神经网络可能具有多个损失函数(每个输出对应一个损失函数)。但是,梯度下降过程必须基于单个标量损失值。因此,对于具有多个损失函数的网络,需要将所有损失函数取平均,变为一个标量值。
选择正确的目标函数对解决问题是非常重要的。网络的目的是使损失尽可能最小化,因此,如果目标函数与成功完成当前任务不完全相关,那么网络最终得到的结果可能会不符合你的预期。想象一下,利用 SGD 训练一个愚蠢而又无所不能的人工智能,给它一个蹩脚的目标函数:“将所有活着的人的平均幸福感最大化”。为了简化自己的工作,这个人工智能可能会选择杀死绝大多数人类,只留几个人并专注于这几个人的幸福——因为平均幸福感并不受人数的影响。这可能并不是你想要的结果!请记住,你构建的所有神经网络在降低损失函数时和上述的人工智能一样无情。因此,一定要明智地选择目标函数,否则你将会遇到意想不到的副作用。
幸运的是,对于分类、回归、序列预测等常见问题,你可以遵循一些简单的指导原则来选择正确的损失函数。例如,对于二分类问题,你可以使用二元交叉熵(binary crossentropy)损失函数;对于多分类问题,可以用分类交叉熵(categorical crossentropy)损失函数;对于回归问题,可以用均方误差(mean-squared error)损失函数;对于序列学习问题,可以用联结主义时序分类(CTC,connectionist temporal classification)损失函数,等等。只有在面对真正全新的研究问题时,你才需要自主开发目标函数。在后面几章里,我们将详细说明对于各种常见任务应选择哪种损失函数。
[/successbox]
。Keras 是一个 Python 深度学习框架,可以方便地定义和训练几乎所有类型的深度学习模型。Keras 最开始是为研究人员开发的,其目的在于快速
实验。
Keras 具有以下重要特性。
相同的代码可以在 CPU 或 GPU 上无缝切换运行。
具有用户友好的 API,便于快速开发深度学习模型的原型。
内置支持卷积网络(用于计算机视觉)、循环网络(用于序列处理)以及二者的任意组合。
支持任意网络架构:多输入或多输出模型、层共享、模型共享等。这也就是说,Keras能够构建任意深度学习模型,无论是生成式对抗网络还是神经图灵机。
Keras 基于宽松的 MIT 许可证发布,这意味着可以在商业项目中免费使用它。它与所有版本的 Python 都兼容(截至 2017 年年中,从 Python 2.7 到 Python 3.6 都兼容)。
Keras 已有 200 000 多个用户,既包括创业公司和大公司的学术研究人员和工程师,也包括研究生和业余爱好者。Google、Netflix、Uber、CERN、Yelp、Square 以及上百家创业公司都在用 Keras 解决各种各样的问题。Keras 还是机器学习竞赛网站 Kaggle 上的热门框架,最新的深度学习竞赛中,几乎所有的优胜者用的都是 Keras 模型。
[successbox title="Keras、TensorFlow、Theano 和 CNTK"]
Keras 是一个模型级(model-level)的库,为开发深度学习模型提供了高层次的构建模块。它不处理张量操作、求微分等低层次的运算。相反,它依赖于一个专门的、高度优化的张量库来完成这些运算,这个张量库就是 Keras 的后端引擎(backend engine)。Keras 没有选择单个张量库并将 Keras 实现与这个库绑定,而是以模块化的方式处理这个问题。因此,几个不同的后端引擎都可以无缝嵌入到 Keras 中。目前,Keras 有三个后端实现:TensorFlow 后端、Theano 后端和微软认知工具包(CNTK,Microsoft cognitive toolkit)后端。未来 Keras 可能会扩展到支持更多的深度学习引擎。
TensorFlow、CNTK 和 Theano 是当今深度学习的几个主要平台。Theano 由蒙特利尔大学的MILA 实验室开发,TensorFlow 由 Google 开发,CNTK 由微软开发。你用 Keras 写的每一段代码都可以在这三个后端上运行,无须任何修改。也就是说,你在开发过程中可以在两个后端之间无缝切换,这通常是很有用的。例如,对于特定任务,某个后端的速度更快,那么我们就可以无缝切换过去。我们推荐使用 TensorFlow 后端作为大部分深度学习任务的默认后端,因为它的应用最广泛,可扩展,而且可用于生产环境。
通过 TensorFlow(或 Theano、CNTK),Keras 可以在 CPU 和 GPU 上无缝运行。在 CPU 上运行时,TensorFlow 本身封装了一个低层次的张量运算库,叫作 Eigen;在 GPU 上运行时,TensorFlow封装了一个高度优化的深度学习运算库,叫作 NVIDIA CUDA 深度神经网络库(cuDNN)。
[/successbox]
[successbox title="使用 Keras 开发:概述"]
你已经见过一个 Keras 模型的示例,就是 MNIST 的例子。典型的 Keras 工作流程就和那个例子类似。
(1) 定义训练数据:输入张量和目标张量。
(2) 定义层组成的网络(或模型),将输入映射到目标。
(3) 配置学习过程:选择损失函数、优化器和需要监控的指标。
(4) 调用模型的 fit 方法在训练数据上进行迭代。
定义模型有两种方法:一种是使用 Sequential 类(仅用于层的线性堆叠,这是目前最常见的网络架构),另一种是函数式 API(functional API,用于层组成的有向无环图,让你可以构建任意形式的架构)。
前面讲过,这是一个利用 Sequential 类定义的两层模型(注意,我们向第一层传入了输入数据的预期形状)
from keras import models
from keras import layers
from keras import optimizers
model = models.Sequential
# Sequential 模型
model.add(layers.Dense(32, activation="relu", input_shape=(784,)))
model.add(layers.Dense(10, activation="softmax"))
# 函数式 API 定义的相同模型
# 利用函数式 API,你可以操纵模型处理的数据张量,并将层应用于这个张量,就好像这些层是函数一样。
'''
input_tensor = layers.Input(shape=(784,))
x = layers.Dense(32, activation="relu")(input_tensor)
output_tensor = layers.Dense(10, activation="softmax")(x)
model = models.Model(inputs=input_tensor, outputs=output_tensor)
'''
'''
一旦定义好了模型架构,使用 Sequential 模型还是函数式 API 就不重要了。接下来的步骤都是相同的。
配置学习过程是在编译这一步,你需要指定模型使用的优化器和损失函数,以及训练过程中想要监控的指标。
下面是单一损失函数的例子,这也是目前最常见的。
'''
# 指定模型使用的优化器和损失函数,以及训练过程中想要监控的指标。
model.compile(optimizer=optimizers.RMSprop(lr=0.001), lose="mse", metrics=["accuracy"])
# 学习过程就是通过 fit() 方法将输入数据的 Numpy 数组(和对应的目标数据)传入模型,这一做法与 Scikit-Learn 及其他机器学习库类似。
model.fit(input_tensor, target_tensor, batch_size=128, epochs=10)
[/successbox]
。。。。。。
[collapse title="电影评论分类:二分类问题"]
二分类问题可能是应用最广泛的机器学习问题。在这个例子中,你将学习根据电影评论的文字内容将其划分为正面或负面。
import numpy as np
from keras import layers
from keras import losses
from keras import metrics
from keras import models
from keras import optimizers
from keras.datasets import imdb
import matplotlib.pyplot as plt
def vectorize_sequences(sequences, dimension=10000):
# 创建一个形状为(len(sequences), dimension) 的零矩阵
results = np.zeros((len(sequences), dimension))
for i, sequence in enumerate(sequences):
# 将 results[i] 的指定索引设为 1
results[i, sequence] = 1.
return results
'''
参数 num_words=10000 的意思是仅保留训练数据中前 10 000 个最常出现的单词。低频单
词将被舍弃。这样得到的向量数据不会太大,便于处理。
train_data 和 test_data 这两个变量都是评论组成的列表,每条评论又是单词索引组成
的列表(表示一系列单词)。train_labels 和 test_labels 都是 0 和 1 组成的列表,其中 0
代表负面(negative),1 代表正面(positive)。
'''
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
# word_index 是一个将单词映射为整数索引的字典
word_index = imdb.get_word_index()
# 键值颠倒,将整数 索引映射为单词
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
# 将评论解码。注意,索引减去了 3,因为 0、1、2 是为“padding”(填充)、“start of sequence”(序列开始)、
# “unknown”(未知词)分别保留的索引
decoded_review = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])
'''
不能将整数序列直接输入神经网络。你需要将列表转换为张量。转换方法有以下两种。
填充列表,使其具有相同的长度,再将列表转换成形状为 (samples, word_indices)
的整数张量,然后网络第一层使用能处理这种整数张量的层(即 Embedding 层,本书
后面会详细介绍)。
对列表进行 one-hot 编码,将其转换为 0 和 1 组成的向量。举个例子,序列 [3, 5] 将会
被转换为 10 000 维向量,只有索引为 3 和 5 的元素是 1,其余元素都是 0。然后网络第
一层可以用 Dense 层,它能够处理浮点数向量数据。
这里使用后一种
'''
# 训练数据向量化
x_train =vectorize_sequences(train_data)
# 测试数据向量化
x_test = vectorize_sequences(test_data)
# 标签向量化
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')
输入数据是向量,而标签是标量(1 和 0),这是你会遇到的最简单的情况。有一类网络在这种问题上表现很好,就是带有 relu 激活的全连接层(Dense)的简单堆叠,比如
Dense(16, activation='relu')。
传入 Dense 层的参数(16)是该层隐藏单元的个数。一个隐藏单元(hidden unit)是该层表示空间的一个维度。我们在第 2 章讲过,每个带有 relu 激活的 Dense 层都实现了下列张量
运算:
output = relu(dot(W, input) + b)
16 个隐藏单元对应的权重矩阵 W 的形状为 (input_dimension, 16),与 W 做点积相当于将输入数据投影到 16 维表示空间中(然后再加上偏置向量 b 并应用 relu 运算)。你可以将表示空间的维度直观地理解为“网络学习内部表示时所拥有的自由度”。隐藏单元越多(即更高维的表示空间),网络越能够学到更加复杂的表示,但网络的计算代价也变得更大,而且可能会导致学到不好的模式(这种模式会提高训练数据上的性能,但不会提高测试数据上的性能)。对于这种 Dense 层的堆叠,你需要确定以下两个关键架构:
网络有多少层;
每层有多少个隐藏单元。第 4 章中的原则将会指导你对上述问题做出选择。现在你只需要相信我选择的下列架构:
两个中间层,每层都有 16 个隐藏单元;
第三层输出一个标量,预测当前评论的情感。
中间层使用 relu 作为激活函数,最后一层使用 sigmoid 激活以输出一个 0~1 范围内的概率值(表示样本的目标值等于 1 的可能性,即评论为正面的可能性)。relu(rectified linear unit,整流线性单元)函数将所有负值归零(见图 3-4),而 sigmoid 函数则将任意值“压缩”到 [0, 1] 区间内,其输出值可以看作概率值
下图显示了网络的结构。下面代码是其 Keras 实现,与前面见过的 MNIST 例子类似。
# 模型定义
model = models.Sequential()
# dense 全连接层
model.add(layers.Dense(16,activation='relu',input_shape=(1000,)))
model.add(layers.Dense(16,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))
[warningbox title="什么是激活函数?为什么要使用激活函数?"]
如果没有 relu 等激活函数(也叫非线性),Dense 层将只包含两个线性运算——点积和加法:
output = dot(W, input) + b
这样 Dense 层就只能学习输入数据的线性变换(仿射变换):该层的假设空间是从输入数据到 16 位空间所有可能的线性变换集合。这种假设空间非常有限,无法利用多个表示层的优势,因为多个线性层堆叠实现的仍是线性运算,添加层数并不会扩展假设空间。为了得到更丰富的假设空间,从而充分利用多层表示的优势,你需要添加非线性或激活函数。relu 是深度学习中最常用的激活函数,但还有许多其他函数可选,它们都有类似的奇怪名称,比如 prelu、elu 等。
[/warningbox]
最后,你需要选择损失函数和优化器。由于你面对的是一个二分类问题,网络输出是一个概率值(网络最后一层使用 sigmoid 激活函数,仅包含一个单元),那么最好使用 binary_crossentropy(二元交叉熵)损失。这并不是唯一可行的选择,比如你还可以使用 mean_squared_error(均方误差)。但对于输出概率值的模型,交叉熵(crossentropy)往往是最好的选择。交叉熵是来自于信息论领域的概念,用于衡量概率分布之间的距离,在这个例子中就
是真实分布与预测值之间的距离。
下面的步骤是用 rmsprop 优化器和 binary_crossentropy 损失函数来配置模型。注意,我们还在训练过程中监控精度。
# 使用自定义的损失和指标
model.compile(optimizer=optimizers.RMSprop(lr=0.001),loss=losses.binary_crossentropy,metrics=[metrics.binary_accuracy])
# 方法验证
# 留出验证集
x_val = x_train[:10000]
partial_x_train = x_train[10000:]
y_val = y_train[:10000]
partial_y_train = y_train[10000:]
'''
现在使用 512 个样本组成的小批量,将模型训练 20 个轮次(即对 x_train 和 y_train 两个张量中的所有样本进行 20 次迭代)。
与此同时,还要监控在留出的 10 000 个样本上的损失和精度。你可以通过将验证数据传入 validation_data 参数来完成。
'''
# 训练模型
model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['acc'])
history = model.fit(partial_x_train,partial_y_train,epochs=20,batch_size=512,validation_data=(x_val, y_val))
'''
CPU 上运行,每轮的时间不到 2 秒,训练过程将在 20 秒内结束。每轮结束时会有短暂的停顿,因为模型要计算在验证集的 10 000 个样本上的损失和精度。
注意,调用 model.fit() 返回了一个 History 对象。这个对象有一个成员 history,它是一个字典,包含训练过程中的所有数据。
history_dict = history.history
history_dict.keys()
字典中包含 4 个条目,对应训练过程和验证过程中监控的指标。在下面代码中,我们将使用 Matplotlib 在同一张图上绘制训练损失和验证损失,
以及训练精度和验证精度。请注意,由于网络的随机初始化不同,得到的结果可能会略有不同。
'''
# 绘制训练损失和验证损失
history_dict = history.history
loss_values = history_dict['loss']
val_loss_values = history_dict['val_loss']
epochs = range(1, len(loss_values) + 1)
# 'bo' 表示蓝色圆点
plt.plot(epochs, loss_values, 'bo', label='Training loss')
# 'b' 表示蓝色实线
plt.plot(epochs, val_loss_values, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()
# 绘制训练精度和验证精度
# 清空图像
plt.clf()
acc = history_dict['acc']
val_acc = history_dict['val_acc']
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
如图所示,训练损失每轮都在降低,训练精度每轮都在提升。这就是梯度下降优化的预期结果——你想要最小化的量随着每次迭代越来越小。但验证损失和验证精度并非如此:它们似乎在第四轮达到最佳值。这就是我们之前警告过的一种情况:模型在训练数据上的表现越来越好,但在前所未见的数据上不一定表现得越来越好。准确地说,你看到的是过拟合(overfit):在第二轮之后,你对训练数据过度优化,最终学到的表示仅针对于训练数据,无法泛化到训练集之外的数据。在这种情况下,为了防止过拟合,你可以在 3 轮之后停止训练。通常来说,你可以使用许多方法来降低过拟合。我们从头开始训练一个新的网络,训练 4 轮,然后在测试数据上评估模型。
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['accuracy'])
model.fit(x_train, y_train, epochs=4, batch_size=512)
results = model.evaluate(x_test, y_test)
# 简单的方法得到了 88% 的精度。利用更好的方法,能够得到接近95%的精度。
训练好网络之后,可以用 predict 方法来得到评论为正面的可能性大小。
model.predict(x_test)
array([[3.4645200e-04],
[1.0000000e+00],
[7.1689188e-01],
...,
[8.3750486e-04],
[5.9402585e-03],
[9.9847871e-01]], dtype=float32)
网络对某些样本的结果非常确信(大于等于 0.99,或小于等于 0.01),但对其他结果却不那么确信(0.6 或 0.4)。
通过以下实验,可以确信前面选择的网络架构是非常合理的,虽然仍有改进的空间。
前面使用了两个隐藏层。你可以尝试使用一个或三个隐藏层,然后观察对验证精度和测试精度的影响。
尝试使用更多或更少的隐藏单元,比如 32 个、64 个等。
尝试使用 mse 损失函数代替 binary_crossentropy。 尝试使用 tanh 激活(这种激活在神经网络早期非常流行)代替 relu。
通常需要对原始数据进行大量预处理,以便将其转换为张量输入到神经网络中。单词序列可以编码为二进制向量,但也有其他编码方式。
带有 relu 激活的 Dense 层堆叠,可以解决很多种问题(包括情感分类),你可能会经常用到这种模型。
对于二分类问题(两个输出类别),网络的最后一层应该是只有一个单元并使用 sigmoid激活的 Dense 层,网络输出应该是 0~1 范围内的标量,表示概率值。
对于二分类问题的 sigmoid 标量输出,你应该使用 binary_crossentropy 损失函数。
无论你的问题是什么,rmsprop 优化器通常都是足够好的选择。这一点你无须担心。
随着神经网络在训练数据上的表现越来越好,模型最终会过拟合,并在前所未见的数据上得到越来越差的结果。一定要一直监控模型在训练集之外的数据上的性能。
import numpy as np
from keras import layers
from keras import losses
from keras import metrics
from keras import models
from keras import optimizers
from keras.datasets import imdb
import matplotlib.pyplot as plt
# 将整数序列编码为二进制矩阵
def vectorize_sequences(sequences, dimension=10000):
# 创建一个形状为(len(sequences), dimension) 的零矩阵
results = np.zeros((len(sequences), dimension))
for i, sequence in enumerate(sequences):
# 将 results[i] 的指定索引设为 1
results[i, sequence] = 1.
return results
'''
参数 num_words=10000 的意思是仅保留训练数据中前 10 000 个最常出现的单词。低频单
词将被舍弃。这样得到的向量数据不会太大,便于ain_lables).astype("float32"))
y_test = np.asarray((test_lab处理。
train_data 和 test_data 这两个变量都是评论组成的列表,每条评论又是单词索引组成
的列表(表示一系列单词)。train_labels 和 test_labels 都是 0 和 1 组成的列表,其中 0
代表负面(negative),1 代表正面(positive)。
'''
(train_data, train_lables), (test_data, test_lables) = imdb.load_data(num_words=10000)
# print(train_data.shape)
# print(train_data[0])
# print(train_lables[0])
# print(max([max(sequence) for sequence in train_data]))
# word_index 是一个将单词映射为整数索引的字典
word_index = imdb.get_word_index()
# 键值颠倒,将整数索引映射为单词
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
# 将评论解码。注意,索引减去了 3,因为 0、1、2 是为“padding”(填充)、
# “start of sequence”(序列开始)、“unknown”(未知词)分别保留的索引
decoded_review = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])
# 将整数序列编码为二进制矩阵
x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)
# 标签向量化
y_train = np.asarray(train_lables).astype('float32')
y_test = np.asarray(test_lables).astype('float32')
# 构建网络
# 输入数据是向量,而标签是标量(1 和 0),这是你会遇到的最简单的情况。有一类网络在这种问题上表现很好,
# 就是带有 relu 激活的全连接层(Dense)的简单堆叠,比如Dense(16, activation='relu')。
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
# 编译模型
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
# 配置优化器
model.compile(optimizer=optimizers.RMSprop(lr=0.001), loss='binary_crossentropy', metrics=['accuracy'])
# 使用自定义的损失和指标
model.compile(optimizer=optimizers.RMSprop(lr=0.001), loss=losses.binary_crossentropy,
metrics=[metrics.binary_accuracy])
# 留出验证集
x_val = x_train[:10000]
partial_x_train = x_train[10000:]
y_val = y_train[:10000]
partial_y_train = y_train[10000:]
# 训练模型
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
history = model.fit(partial_x_train, partial_y_train, epochs=20, batch_size=512, validation_data=(x_val, y_val))
# 训练过程中的所有数据
history_dict = history.history
print(history_dict.keys())
# 绘制训练损失和验证损失
history_dict = history.history
loss_values = history_dict['loss']
val_loss_values = history_dict['val_loss']
epochs = range(1, len(loss_values) + 1)
# 'bo' 表示蓝色圆点
plt.plot(epochs, loss_values, 'bo', label='Training loss')
# 'b' 表示蓝色实线
plt.plot(epochs, val_loss_values, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()
# 绘制训练精度和验证精度
# 清空图像
plt.clf()
acc = history_dict['acc']
val_acc = history_dict['val_acc']
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
# 从头开始重新训练一个模型
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
model.fit(x_train, y_train, epochs=4, batch_size=512)
results = model.evaluate(x_test, y_test)
# 生成预测结果
model.predict(x_test)
[/collapse]
[collapse title="新闻分类:多分类问题"][/collapse]
[collapse title="预测房价:回归问题"][/collapse]
Ps:本章内容来自对《Deep Learning with Python》学习过程的记录
文章评论
自毕业你就以此谋生.
https://bit.ly/2ZWlliV