示例:摄氏度转化为华氏度

这是优达学城深度学习课程的第一个案例, 我们的目的是训练计算机学习摄氏度转换成华氏度有数学公式:

  1. f = c * 1.8 + 32

首先引入相关的库:

  1. import tensorflow as tf
  2. import numpy as np
  3. import matplotlib.pyplot as plt
  4. import logging
  5. %matplotlib inline
  6. logger = tf.get_logger() #返回tf的日志实例
  7. logger.setLevel(logging.ERROR)

准备训练数据

  1. celsius_q = np.array([-40, -10, 0, 8, 15, 22, 38], dtype=float)
  2. fahrenheit_a = np.array([-40, 14, 32, 46, 59, 72, 100], dtype=float)

相关概念:训练集与测试集

数据集通常会划分为不同的子集,用于训练和评估神经网络。在此部分,我们提到了以下术语:

  • 训练集: 用于训练神经网络的数据。
  • 测试集: 用于测试神经网络最终效果的数据。

通过测试数据集,我们可以使用网络从未见过的数据测试网络。这样我们便能检测模型的泛化程度,即泛化到训练期间未见过的数据的效果,而不是仅仅记住训练样本。

同样,我们通常会使用验证数据集。此类数据集不用于训练,而是在训练期间用于测试模型。我们在一定的训练步数之后使用验证集,判断训练进展如何。例如,如果在训练过程中损失降低了,但是验证集的准确率下降了,则表明模型在记住测试集。

训练完毕时,也会使用验证集衡量模型的最终准确率。

创建及编译模型

定义输入的形状,创建一个层,编译模型,使用的损失函数为均方差 mean_squared_error ,优化器使用Adam,设置优化率为0.1。

  1. l0 = tf.keras.layers.Dense(units=1, input_shape=[1])
  2. model = tf.keras.Sequential([l0])
  3. model.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.1))

由于问题比较简单,因此我们只需要建立的密集网络将只需要一个单层神经网络(只有一个神经元)。下面单独解释每一行代码的意义。

建立一个层

我们会把这一层叫做 l0,并且使用 tf.keras.layers.Dense (全连接层) 来建立

  1. l0 = tf.keras.layers.Dense(units=1, input_shape=[1])
  • units=1 指定本层神经元数量。神经元的数量定义了本层需要有多少内部变量来学习解决这个问题。由于这是本模型的最后一层,因此它也代表模型输出的大小。(在多层神经网络中,该层的大小与形状需要与下一层的input_shape相匹配
  • input_shape=[1] 指定本层输入值为单值。表明这是一个包含单个成员的一维数组。由于这是本模型的第一层(也是唯一一层),因此该输入形状也是整个模型的输入形状。单值是浮点数,即摄氏度

将Layer组装到模型中

定义了层之后,使用 Sequential 将它们组装成模型

  1. model = tf.keras.Sequential([l0])

编译模型

搭好模型架构之后,在训练模型之前,还要执行编译操作。

  1. model.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.1))

在编译时,经常需要指定三个参数:

  • Loss function (损失函数) 一种衡量结果与预期相差多少的方法(测得的差异称为loss(损失))
  • Optimizer function (优化函数) 一种调整内部值以减少损耗的方法
  • Metrics function

在训练过程中使用model.fit()来首先计算每个点的损耗,之后对其改善。优化器功能用于计算对模型内部变量的调整,目的是调整内部变量直到模型(实际是一个数学函数)接近将摄氏度转换为华氏度的公式为止

这里使用的优化函数mean_squared_error(均方误差)和优化器Adam是这种简单模型的标准配置,实际还有其他可用配置。

在建立自己的模型时,我们需要考虑的Optimizer优化器的部分是学习率(即上式中的0.1),这是在模型中调整值时采取的步长,它决定着目标函数能否收敛到局部最小值以及何时收敛到最小值。合适的学习率能够使目标函数在合适的时间内收敛到局部最小值。范围通常在0.001(默认)和0.1之间

训练模型

在训练过程中,模型输入摄氏温度,使用当前的内部变量(权重)执行计算,并输出相应华氏温度的值。 由于权重最初是随机设置的,因此输出并不会接近正确的值。实际输出与期望输出之间的差值通过损失函数计算,而优化器函数将指导如何调整权重。

计算,比较,调整的整个流程由fit方法进行控制:

  1. history = model.fit(celsius_q, fahrenheit_a, epochs=2000, verbose=0)
  2. print('Those are the layer variables: {}'.format(l0.get_weights()))

fit的各个参数含义:

  • 第一个参数是输入
  • 第二个参数是期望的输出结果
  • epochs参数指定模型应运行此循环多少次
  • verbose参数控制该方法的日志显示
    • verbose = 0 为不在标准输出流输出日志信息
    • verbose = 1 为输出进度条记录, 默认值
    • verbose = 2 为每个epoch输出一行记录

训练结束后,通过 l0.get_weights() 可以获取通过训练得到的参数。

打印出参数分别为1.7979496和31.95248,跟实际值 权重 weights=1.8偏差 biases=32已经非常接近了:

  1. Those are the layer variables: [array([[1.7979496]], dtype=float32), array([31.95248], dtype=float32)]

可视化训练数据

绘制训练损失值随训练次数增加而减小的曲线:

  1. plt.xlabel('Epoch Number') #x坐标轴
  2. plt.ylabel("Loss Magnitude") #y坐标轴
  3. plt.plot(history.history['loss']) #标点
  4. plt.show()

📃 线性回归模型 - 图1
通过图可以看出,开始的时候,损失值很大,大概训练到 500 次的时候,损失值开始稳定不再有明显的变化。

使用模型

通过 model.predict 输入已知的摄氏度, 这将输出预测的华氏度

利用前面训练好的模型预测100℃时对应的℉

  1. print(model.predict([100.0])) #向模型输入100.0
  2. # 100*1.8 + 32 = 212

可以看到,输出值与真实值已经非常接近了:

  1. [[211.74744]]

由于机器性能的差异,不同计算机训练出来的结果将不一样。

总结

通过此节,我们学习了使用 TensorFlow 训练了首个模型。

训练流程(发生在 model.fit(...) 当中)是指将网络的内部变量调整为最佳可能值,使它们能够将输入映射到输出。为了实现这个目标,我们将采用梯度下降法这一优化流程,它会使用数值分析找到模型内部变量的最佳可能值。

梯度下降法会以迭代方式调整参数,每次朝着正确的方向小幅更改参数,直到达到最佳值。“最佳值”是指再调整的话,会降低模型的效果。在每次迭代过程中衡量模型好坏的函数称为“损失函数”,每次调整的目标是“最小化损失函数”。

预测出一个值后,模型将计算预测值与正确值之间的差值。这个差值称为损失,用于衡量模型执行映射任务的效果。我们使用损失函数计算损失,并且在调用 model.compile() 时通过损失参数指定损失函数

计算损失后,模型将调整所有层级的内部变量(权重和偏差),从而最小化该损失,使输出值更接近正确值。

这个优化流程称为梯度下降法。我们会通过一个具体算法计算每个内部变量的新值,并且在调用 model.compile(...) 时用优化器参数指定该算法。在此示例中,我们使用的是 Adam优化器

术语

  • 特征: 模型的输入
  • 样本: 用于训练流程的输入/输出对
  • 标签: 模型的输出
  • 层级: 神经网络中相互连接的节点集合。
  • 模型: 神经网络的表示法
  • 密集全连接层 (FC): 一个层级中的每个节点都与上个层级中的每个节点相连。
  • 权重和偏差: 模型的内部变量
  • 损失: 期望输出和真实输出之间的差值
  • MSE: 均方误差,一种损失函数,它会将一小部分很大的差值视作比大量很小的差值更糟糕。
  • 梯度下降法: 每次小幅调整内部变量,从而逐渐降低损失函数的算法。
  • 优化器: 梯度下降法的一种具体实现方法。(有很多算法。在这门课程中,我们将仅使用“Adam”优化器,它是 ADAptive with Momentum 的简称,并且被视为最佳优化器。)
  • 学习速率: 梯度下降过程中的损失改进“步长”。
  • 批次: 在训练神经网络的过程中使用的一组样本。
  • 周期: 完全经过整个训练数据集一轮
  • 前向传播: 根据输入计算输出值
  • 反向传播: 根据优化器算法计算内部变量的调整幅度,从输出层级开始,并往回计算每个层级,直到抵达输入层。
  • 扁平化: 将二维图像转换为一维向量的过程

参考资料