Course2-Week2-神经网络的训练方法

Course2-Week2-神经网络的训练方法

文章目录

  • Course2-Week2-神经网络的训练方法
    • 1. 神经网络的编译和训练
      • 1.1 TensorFlow实现
      • 1.2 损失函数和代价函数的数学公式
    • 2. 其他的激活函数
      • 2.1 Sigmoid激活函数的替代方案
      • 2.2 如何选择激活函数
      • 2.3 为什么需要激活函数
    • 3. 多分类问题和Softmax函数
      • 3.1 多分类问题
      • 3.2 逻辑回归的推广:Softmax回归
      • 3.3 Softmax神经网络的代码实现
      • 3.4 多标签问题
    • 4. 更加高级的神经网络概念
      • 4.1 梯度下降法的改进:Adam算法
      • 4.2 其他类型的神经网络层
      • 4.3 神经网络代码实例——手写数字识别
    • 5. 反向传播(选修)
      • 5.1 计算图和导数
      • 5.2 神经网络中的反向传播

  • 笔记主要参考B站视频“(强推|双字)2022吴恩达机器学习Deeplearning.ai课程”。
  • 该课程在Course上的页面:Machine Learning 专项课程
  • 课程资料:“UP主提供资料(Github)”、或者“我的下载(百度网盘)”。
  • 本篇笔记对应课程 Course2-Week2(下图中深紫色)。

1. 神经网络的编译和训练

1.1 TensorFlow实现

  上周演示了如何定义一个神经网络并使用其进行“推理”,本周就来学习剩余的的“编译”和“训练”:

  1. 编译compile():输入参数有“损失函数loss”、“优化器optimizer”、“评估指标metrics”。主要考虑前两项。
  • “损失函数loss”:决定了神经网络的代价函数。在“训练”的某次迭代结束后,利用输出层的输出结果与真实目标值之间的差异计算神经网络的代价。进而可以通过反向传播更新参数。
  • “优化器optimizer”:则是“梯度下降法”的升级版,可以选择性能更强大、收敛速度更快的迭代算法。
  • “评估指标metrics”:和“训练”本身没有关系,和损失函数没有关系。只是在“训练”的单次迭代结束后,衡量一下所有训练集的推理结果与真实值之间的差异。loss也有此作用,但是不直观;metrics可以选择更加直观的指标,比如metrics='accuracy'可以计算“推理正确的训练样本”的百分比。
# compile()函数所有的可选选项及其示例
model.compile(loss=tf.keras.losses.BinaryCrossentropy(),
              optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
              metrics='accuracy'
)

参考Keras官网说明文档:The compile()method: specifying a loss, metrics, and an optimizer。

  1. 训练fit():有非常多的指标可以设置,但我们现在仅关心“数据集”、“迭代次数epchos”即可(下面代码示例的前三项)。注意每次迭代都会使用到所有的训练集样本,若样本太多,程序会自动将数据分批。并且,运行fit()函数后,会自动打印输出训练过程。
# fit()函数所有的可选选项及其示例(ChatGPT)
model.fit(
    x=None,                # 输入数据
    y=None,                # 标签
    epochs=1,              # 训练轮数
    batch_size=None,       # 指定进行梯度下降时每个批次包含的样本数
    verbose=1,             # 控制训练过程中的日志输出,0:不输出日志,1:输出进度条记录,2:每个epoch输出一行记录
    callbacks=None,        # 在训练过程中调用的回调函数列表
    validation_split=0.0,  # 用于验证的训练数据的比例
    validation_data=None,  # 用于验证的数据,可以是输入数据和标签的元组
    shuffle=True,          # 是否在每个epoch之前随机打乱输入数据
    class_weight=None,     # 类别权重
    sample_weight=None,    # 样本权重
    initial_epoch=0,       # 开始训练的epoch值
    steps_per_epoch=None,  # 每个epoch包含的步数,当为None时,将自动计算
    validation_steps=None, # 在每个epoch结束时执行验证的步数,当为None时,将自动计算
    validation_batch_size=None,  # 用于验证的批次大小
    validation_freq=1,     # 仅在`validation_data` 的某些训练轮上进行验证
    max_queue_size=10,     # 生成器队列的最大尺寸
    workers=1,             # 使用的生成器工作进程数
    use_multiprocessing=False,  # 是否使用多进程生成器
    **kwargs
)
# 运行fit()函数后,会自动打印输出训练过程,下面为单次迭代的输出示例
Epoch 1/40
157/157 [==============================] - 1s 1ms/step - loss: 1.5179 - accuracy: 0.5406

参考Keras官网说明文档:Training & evaluation using tf.dataDatasets。若没跳转到相应位置就按照标题翻翻。

熟悉了上面的选项之后,回到简化的“手写数字识别”问题,其训练代码如下,主要看“编译model.compile()”和“训练model.fit()”:

图2-2-1 训练神经网络的代码-手写数字识别
  1. 定义神经网络。定义神经网络的层数、每层神经元数量、激活函数。和之前相同。
  2. 编译神经网络。关键在于确定损失函数,由于是二元分类问题所以选取了“二元交叉熵损失函数”。
  3. 训练神经网络。X,Y为训练集、epochs为迭代次数,也就是“梯度下降法”的迭代次数,每次迭代都会使用全部训练集的数据。

1.2 损失函数和代价函数的数学公式

图2-2-2 训练神经网络的步骤

  上一节介绍了“编译”和“训练”的实现代码,那“编译”中所配置的“二元交叉熵损失函数”到底是什么呢?其实,其定义和“逻辑回归”中的损失函数相同。在统计学中,损失函数形式是“交叉熵”(如下式),而“二元”只是强调输出为二元分类,所以称之为“二元交叉熵损失函数”。下面是“手写数字识别”神经网络的损失函数和代价函数:
Loss Function:    L ( f ( x ⃗ ) , y ) = − y l o g ( f ( x ⃗ ) ) − ( 1 − y ) l o g ( 1 − f ( x ⃗ ) ) Cost Function:    { J ( W , B ) = 1 m ∑ i = 1 m L ( f ( x ⃗ ) , y ) , W = [ W [ 1 ] , W [ 2 ] , W [ 3 ] ] , B = [ b ⃗ [ 1 ] , b ⃗ [ 2 ] , b ⃗ [ 3 ] ] . \begin{aligned} \text{Loss Function:} & \; L(f(\vec{x}),y) = -ylog(f(\vec{x})) - (1-y)log(1-f(\vec{x})) \\ \text{Cost Function:} & \; \left\{\begin{aligned} & J(\bold{W},\bold{B}) = \frac{1}{m}\sum_{i=1}^{m}L(f(\vec{x}),y), \\ & \bold{W}=[\bold{W}^{[1]}, \bold{W}^{[2]}, \bold{W}^{[3]}], \\ & \bold{B}=[\vec{\bold{b}}^{[1]}, \vec{\bold{b}}^{[2]}, \vec{\bold{b}}^{[3]}]. \end{aligned}\right. \end{aligned} Loss Function:Cost Function:L(f(x ),y)=ylog(f(x ))(1y)log(1f(x )) J(W,B)=m1i=1mL(f(x ),y),W=[W[1],W[2],W[3]],B=[b [1],b [2],b [3]].

假设神经网络输入为20x20图片,于是输入特征 x ⃗ \vec{x} x 长度为400。

  • L ( f ( x ⃗ ) , y ) L(f(\vec{x}),y) L(f(x ),y):单个样本的损失函数,其中的 ( x ⃗ , y ) (\vec{x},y) (x ,y) 是训练集中的单个样本。注意只有输出层才计算损失函数。
  • W [ 1 ] \bold{W}^{[1]} W[1] 400 × 25 400×25 400×25 的二维矩阵。同理, W [ 2 ] \bold{W}^{[2]} W[2] 维度为 25 × 15 25×15 25×15 W [ 3 ] \bold{W}^{[3]} W[3] 维度为 15 × 1 15×1 15×1
  • b ⃗ [ 1 ] \vec{\bold{b}}^{[1]} b [1]:长度 25 25 25 的向量。同理, b ⃗ [ 2 ] \vec{\bold{b}}^{[2]} b [2] 长度为 15 15 15 b ⃗ [ 3 ] \vec{\bold{b}}^{[3]} b [3]长度为 1 1 1
  • W \bold{W} W:三个二维矩阵的列表,也就是表示神经网络的全部 w w w 参数。
  • B \bold{B} B:三个向量的列表,也就是表示神经网络的全部 b b b 参数。
  • J ( W , B ) J(\bold{W},\bold{B}) J(W,B):所有样本的损失平均值,也就是代价函数。

  在代码中,Keras库最初是独立的数学函数库,后来被TensorFlow收录,所以TensorFlow使用Keras库来定义损失函数。这也是最初的代码中,从keras导入损失函数的原因。当然记住所有的损失函数名称并不现实,需要的时候问问ChatGPT就行。当然上述是对“分类问题”的代码,如果想编译“回归问题”,可以采用下面的代码(注意修改损失函数):

# 回归问题中,使用“平方差损失函数”编译模型
from tensorflow.keras.losses import MeanSquareError
model.compile(loss = MeanSquareError())

  当前,最后还有一点就是怎么求解代价函数的偏导。显然“训练”的过程就是最小化代价函数,若使用“梯度下降”,那么每一次迭代,就要求计算代价函数对每一层每个神经元的每个参数的偏导。这工作量想想就惊人!更别说神经网络很难求出显式的偏导表达式。所以实际上,神经网络的“训练”使用“反向传播(back propogation)”来进行迭代,可以大大节省计算量。TensorFlow将上述“反向传播”寻找最低点的过程全部封装在model.fit()函数中,并迭代设定好的次数epochs,“5.反向传播”一节将进行介绍其数学原理。

  现在知道如何训练一个基本的神经网络,也被称为“多层感知器”。下面几节将继续介绍一些改进,使神经网络的性能更好。

本节 Quiz

  1. Here is some code that you saw in the lecture: model.compile(loss=BinaryCrossentropy()). For which type of task would you use the binary cross entropy loss function?
    × BinaryCrossentropy()should not be used for any task.
    × A classification task that has 3 or more classes (categories).
    √ Binary classification (classification with exactly 2 classes).
    × Regression tasks (tasks that predict a number).

  2. Which line of code updates the network parameters in order to reduce the cost?

model= Sequential([Dense(units=25, activation='sigmoid),
                   Dense(units=15, activation=' sigmoid"),
                   Dense(units=1 , activation='sigmoid')])
model.compile(loss=BinaryCrossentropy())
model.fit(X, y, epochs=100)

2. 其他的激活函数

再继续介绍“编译”和“训练”之前,我们来继续看看其他的“激活函数”。这可以首先帮助我们优化整个神经网络。

2.1 Sigmoid激活函数的替代方案

  由于前面介绍了“逻辑回归”,于是我们将每个神经元都看成一个小的逻辑回归单元,所以目前一直使用Sigmiod函数作为隐藏层和输出层所有神经元的激活函数。但Sigmoid函数显然也有其局限性。比如下面的“需求预测”问题,我们最开始假设隐藏层输出的有“心理预期价格”、“认可度”、“产品质量”,但实际上这些指标并不一定都为0~1之间的小数字,比如“认可度”可以有“不认可”、“一般认可”、“极度认可”、“完全传播开来”等。于是我们不妨将“认可度”的范围扩展为到所有“非负数”,也就是从0到非常大的数字。也就是ReLU函数(Rectified Linear Unit, 修正线性单元):

图2-2-3 ReLU函数-需求预测

于是,这启示我们,激活函数的形状应该和输出范围有关,下面就是三种常见的激活函数:

图2-2-4 常见的三种激活函数
  1. 线性激活函数: g ( z ) = z g(z)=z g(z)=z,人们也会称之为“没有使用任何激活函数”。
  2. Sigmoid函数: g ( z ) = 1 1 + e − z g(z)=\frac{1}{1+e^{-z}} g(z)=1+ez1,常见于“二元分类问题”。
  3. ReLU函数: g ( z ) = max ⁡ ( 0 , z ) g(z)=\max(0,z) g(z)=max(0,z),经常作为默认激活函数。
  4. Softmax函数:“第三节”讨论多分类问题时进行介绍。

合理使用上述激活函数可以进一步提升神经网络性能,进而构建各种各样的强大的神经网络。

2.2 如何选择激活函数

  那该如何选择激活函数呢?首先我们从输出层开始。输出层的激活函数通常取决于“目标值”,比如二元分类问题就使用Sigmoid函数、如果预测股票涨跌的回归问题就使用线性激活函数(因为有正有负)、如果是“预测房价”这样的回归问题就使用ReLU函数(因为房价非负)。而对于隐藏层来说,若无特殊原因,所有隐藏层的神经元都应选择ReLU函数。最早人们都默认使用Sigmoid函数,但是现在逐渐演变成默认使用ReLU函数,主要有以下几个原因:

  1. ReLU函数形式更简单、计算更快。
  2. ReLU仅在负数域平坦,而Sigmoid函数在正负两侧都平坦。而平坦的区域越大,会导致代价函数平坦的区域越大,“梯度下降”等算法训练模型的速度就越慢。

总结:“输出层”按照“目标值”取值范围选取,“隐藏层”默认全部采用ReLU函数(如下图)。

图2-2-5 改进输出层、隐藏层的激活函数——手写数字识别

  对于大多数情况、大多数应用来说,上述介绍的几个激活函数已经够用了。当然还有其他激活函数,比如Tanh函数、Leaky ReLU函数、Swish函数等。每隔几年,研究人员都会提出新的激活函数,这些激活函数在某些方面的性能确实会更好。想了解的话可以自行查阅。

2.3 为什么需要激活函数

  既然ReLU函数比Sigmoid函数计算更快,那能不能默认使用更简洁的“线性激活函数”呢?换句话说,能不能不使用激活函数呢?显然是不行的。由于“线性函数的线性组合还是线性函数”,若只使用线性激活函数,整个神经网络就会退化成“线性回归”,所以 尽量不在隐藏层使用线性激活函数。使用其他的非线性函数,比如ReLU函数,只要有足够多的神经元,通过调整参数就可以拟合出任意的曲线,进而实现神经网络想要的拟合效果。

下面是ChatGPT给出的激活函数的几个作用:

  1. 引入非线性:激活函数引入了非线性变换,使神经网络能够学习和表示复杂的非线性关系。如果没有激活函数,神经网络将仅能够表示线性映射,限制了其表达能力。
  2. 特征映射:激活函数能够将输入映射到另一种表示形式,使得网络能够学习到数据中的更高阶的特征。不同的激活函数对输入数据的映射方式不同,因此选择合适的激活函数有助于提取关键特征。
  3. 输出范围控制:激活函数可以控制神经元的输出范围。例如,Sigmoid 函数将输入映射到 (0, 1) 范围,适用于二分类问题,而 Tanh 函数将输入映射到 (-1, 1) 范围。这有助于输出符合任务要求的范围。
  4. 处理梯度消失问题:激活函数的选择也与梯度消失问题有关。某些激活函数(如 Sigmoid 和 Tanh)在输入较大或较小时,梯度可能趋于零,导致梯度消失问题。ReLU 和其变种等激活函数对于缓解这个问题有一定帮助。
  5. 稀疏激活:一些激活函数能够产生稀疏激活,即只有部分神经元被激活。这有助于网络学习到数据的稀疏表示,提高模型的泛化能力。

本节 Quiz

  1. Which of the following activation functions is the most common choice for the hidden layers of a neural network?
    × Most hidden layers do not use any activation function.
    √ ReLU (rectified linear unit)
    × Sigmoid
    × Linear

  2. For the task of predicting housing prices, which activation functions could you choose for the output layer? Choose the 2 options that apply.
    √ Linear
    √ ReLU
    × Sigmoid

  3. A neural network with many layers but no activation function (in the hidden layers) is not effective; that’s why we should instead use the linear activation function in every hidden layer.
    √ False
    × True

3. 多分类问题和Softmax函数

  本节来进一步优化“编译compile()”的“损失函数loss”设置。在第一节中,由于“手写数字识别”已经被我们简化成只识别数字1和数字0,所以使用了“二元交叉熵损失函数loss=BinaryCrossentropy()”,那如果要识别全部的数字0~数字9,又该如何设置损失函数呢?下面就来介绍。

3.1 多分类问题

  显然,要识别全部的数字0~数字9,就需要将二元分类问题进行推广。于是,分类输出的目标值有多个可能的问题,便称为“多分类问题(multiclass classfication problem)”。比如“手写数字识别”要分类10个数字、“肿瘤检测”要分类多种恶化类型、流水线产品检测不同类型的缺陷等。

注:聚类是无监督学习,神经网络自行分类;多分类问题是有监督学习,只不过是类别多了。

图2-2-6 二元分类推广到多分类

对于多分类问题,显然希望决策边界如上右图所示。于是下节介绍由二元分类的“逻辑回归算法”推广得到的“Softmax回归算法”,可以解决上述“多分类问题”,并将其应用到神经网络中。

3.2 逻辑回归的推广:Softmax回归

下面是Softmax函数的定义,也就是 g ( z ) g(z) g(z) 的定义:

图2-2-7 Softmax回归算法的模型
  • j j j 为单层神经网络内的神经元索引; k k k 也为神经元索引,但其主要目的是将本层内所有神经元求和。
  • a j a_j aj:当前层第 j j j 个神经元的输出。

注1:尽管参数不完全一致,但 N = 2 N=2 N=2 时,“Softmax回归”会退化成“逻辑回归”。
注2:Softmax回归使用指数,不仅可以保证概率非负,同时也可以扩大不同值之间的差异。
注3:多分类问题所有可能输出的概率之和为1。

于是类似于“逻辑回归”的“二元交叉熵(Binary Crossen tropy)损失函数”,“Softmax回归”的损失函数为“稀疏分类交叉熵(Sparse Categorical Crossen tropy)”。同样也是,推理结果越接近真实结果,损失越小:

图2-2-8 Softmax回归算法的损失函数

3.3 Softmax神经网络的代码实现

  显然,要创建解决多分类问题的神经网络,只需要更改输出层激活函数为“Softmax函数”、损失函数为“稀疏分类交叉熵”即可,代码如下:

图2-2-9 Softmax回归神经网络(实际不使用此代码)-10分类的手写数字识别

注意到,Softmax层,也被称为“Softmax激活函数”,和之前的激活函数都不同。因为Softmax函数的输出 a j a_j aj 不只取决于当前的输入 z j z_j zj,而是取决于所有的输入 z 1 , . . . , z N z_1,...,z_N z1,...,zN。所以Softmax层并不能逐个计算神经元的输出,而是需要“同时计算”该层所有神经元的输出。

  虽然上述代码规定好了损失函数,但实际上并不采用上述代码。因为采用上面的代码,会要求TensorFlow保留损失函数计算的中间结果 a j , j = 1 , . . , N . a_j,j=1,..,N. aj,j=1,..,N.。但实际上,多计算一个变量就会引入更多的舍入误差,尤其是“Sigmoid函数 1 1 + e − z \frac{1}{1+e^{-z}} 1+ez1”、“Softmax函数 e z j ∑ k = 1 N e z k \frac{e^{z_j}}{\sum_{k=1}^N e^{z_k}} k=1Nezkezj”的计算结果中,其总会有些值非常小,进而使得计算精度不足导致 舍入误差。为了消除这部分的舍入误差,我们可以令TensorFlow不要再计算中间结果 z z z,而是直接将 z z z 的表达式代入到损失函数中。这样TensorFlow会先化简损失函数表达式(重排列),再进行计算,从而减少一步的舍入误差:

图2-2-10 更精确的的代码实现——二元分类问题
图2-2-11 更精确的的代码实现——多分类问题
  • logits就是表示 z z zfrom_logits=True表示直接使用 z z z 计算代价函数。
  • 尽管上述代码可能会使得代码含义没那么清楚,但是可以使TensorFlow的数值舍入误差减小。

3.4 多标签问题

  最后,“多分类问题(multi-classfication problem)”和“多标签问题(multi-label problem)”非常容易混淆,本小节就是来区分一下这两个定义。“多标签分类”是一个输入,多个不同类型的分类。所以,“多标签问题”可以看成是多个“二元分类”的组合。比如下面的“多标签问题”就是由3个不同的“二元分类”组成的:

图2-2-12 多标签问题示意图

直观上,我们可能会想到针对不同的标签分类,创建各自独立的的神经网络,比如上图就创建三个独立的神经网络,但显然这看起来不聪明,所以实际上会创建一个神经网络同时解决这三个二元分类。创建网络时只要注意将最后的输出层调整为三个Sigmoid神经元即可。

下面来介绍更加高级的神经网络概念,包括比“梯度下降”更好的迭代算法。

本节 Quiz

  1. For a multiclass classification task that has 4 possible outputs, the sum of all the activations adds up to 1. For a multiclass classification task that has 3 possible outputs, the sum of all the activations should add up to …
    × It willvary, depending on the input x.
    × Less than 1.
    × More than 1.
    √ 1.

  2. For multiclass classification, the cross entropy loss is used for training the model. If there are 4 possible classes for the output, and for a particular training example, the true class of the example is class 3 (y=3), then what does the cross entropy loss simplify to? [Hint: This loss should get smaller when a 3 a_3 a3 gets larger.]
    × − l o g ( a 1 ) − l o g ( a 2 ) − l o g ( a 3 ) − l o g ( a 4 ) 4 \frac{-log(a_1)-log(a_2)-log(a_3)-log(a_4)}{4} 4log(a1)log(a2)log(a3)log(a4)
    − l o g ( a 3 ) -log(a_3) log(a3)
    × z 3 z 1 + z 2 + z 3 + z 4 \frac{z_3}{z_1 + z_2 + z_3 + z_4} z1+z2+z3+z4z3
    × z 3 z_3 z3

  3. For multiclass classification, the recommended way to implement softmax regression is to set from_logits=Truein the loss function, and also to define the model’s output layer with…
    √ a “linear” activation
    × a “softmax” activation

4. 更加高级的神经网络概念

4.1 梯度下降法的改进:Adam算法

  “梯度下降”广泛应用于机器学习算法中,如线性回归、逻辑回归、神经网络早期实现等,但是还有其他性能更好的最下滑代价函数的算法。比如“Adam算法(Adaptive Moment estimation, 自适应矩估计)”就可以自动调整“梯度下降”学习率 α \alpha α 的大小,从而加快“梯度下降”的收敛速度。下面是其算法逻辑和代码示例:

  1. “Adam算法”并不只使用同一个学习率 α \alpha α,而是 针对每个参数都定义一个 α j \alpha_j αj
  2. 如果参数一直向同一个方向前进,就逐步增大该参数的学习率;若每次方向都不一样(振荡),就逐步减小学习率。
  3. “Adam算法”还需要一个参数来控制每个参数的学习率的增大或减小的速度——全局学习率(下面设置为 1 0 − 3 10^{-3} 103)。
图2-2-13 Adam算法逻辑及实现代码

有兴趣可以试着调大全局学习率learning_rate,看看Adam算法能否学的更快。

4.2 其他类型的神经网络层

“心电图监测”问题:根据心电图(electrocardiogram, EKG/ECG)判断是否有心脏病。

  • 输入特征:长度为100的心电图信号。
  • 输出:有心脏病的概率。

  目前为止学习到的所有神经网络都是“密集层类型(dense layer type)”,也就是层内的每一个神经元都会得到上一层的所有输入特征。虽然“密集层类型”的神经网络功能很强大,但是其计算量很大。于是,Yann LeCun 最早提出“卷积层(convolution layer)”,并将其应用到计算机视觉领域。“卷积层”中,每个神经元只关心输入图像的某个区域。如下左图中,对于输入图像,每个神经元只关心某个小区域(按照颜色对应)。“卷积层”的优点如下:

  1. 加快计算。
  2. 需要的训练集可以更小,并且也不容易“过拟合”。(Week3会更加详细的介绍“过拟合”)
图2-2-14 卷积层、卷积神经网络示意图

如果神经网络有很多“卷积层”,就会称之为“卷积神经网络”(如上右图)。上右图便给出了“心电图监测”问题(本小节开始的说明)的卷积神经网络示意图。显然,改变每个神经元查看的窗口大小,每一个有多少神经元,有效的选择这些参数,可以构建比“密集层类型”更加有效的神经网络。

  除了“卷积层”之外,当然还有其他的神经网络层类型,将不同类型的“层”结合在一起,组成更加强大的神经网络:

  1. 全连接层(Fully Connected Layer):全连接层是最简单的神经网络层,其中每个神经元与上一层的所有神经元相连接。
  2. 卷积层(Convolutional Layer):卷积层用于处理图像和其他二维数据,通过卷积操作提取图像的局部特征。
  3. 池化层(Pooling Layer):池化层通常与卷积层结合使用,用于减小特征图的空间尺寸,提高计算效率,并减少参数量。
  4. 循环神经网络层(Recurrent Neural Network Layer):RNN层用于处理序列数据,具有记忆性,能够捕捉时间上的依赖关系。
  5. 长短时记忆网络层(Long Short-Term Memory Layer,LSTM):LSTM是一种特殊的循环神经网络层,具有更强大的记忆性,适用于处理长序列依赖关系。
  6. ……

4.3 神经网络代码实例——手写数字识别

图2-2-15 训练集和神经网络模型-手写数字识别
  • 本节来自于“C2_W2_Assignment.ipynb”中的“Exercise 2”。
  • 训练集来自:MNIST handwritten digit dataset (http://yann.lecun.com/exdb/mnist/),可以直接打开课程资料(本文开头说明),也可以使用百度网盘单独下载“2-2data.rar(6.18MB)”。

  到本节为止,本周与代码有关的部分就介绍完了。现在根据本周实验,给出完整的“手写数字识别”代码,并在后面给出了神经网络参数及预测结果。代码的整体逻辑是,使用训练集进行训练;训练完毕后,再从训练集中挑出一些图片,看看训练后的神经网络能否正确预测。所以最后的“训练错误汇总”是因为迭代次数过少导致:

# 导入头文件
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.activations import linear, relu, sigmoid
import matplotlib.pyplot as plt
plt.style.use('./deeplearning.mplstyle')
import logging
logging.getLogger("tensorflow").setLevel(logging.ERROR)
tf.autograph.set_verbosity(0)

# 加载训练集:5000张手写体图片,每张图片大小20x20
X = np.load("data/X.npy") # 5000x400
y = np.load("data/y.npy") # 5000x1

# 定义神经网络
model = Sequential(
    [
        tf.keras.Input(shape=(400,)),       # 输入特征的长度
        Dense(units=25, activation='relu',   name='layer1'),
        Dense(units=15, activation='relu',   name='layer2'),
        Dense(units=10, activation='linear', name='layer3'),
    ], name = "my_model"
)

# 编译模型
model.compile(
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    optimizer=tf.keras.optimizers.Adam(learning_rate=0.001)
)

# 训练模型
history = model.fit(X, y, epochs=40)

# 预测结果
image_new = X[1015]
prediction = model.predict(image_new.reshape(1,400))  # prediction
yhat = np.argmax(prediction)
prediction_p = tf.nn.softmax(prediction)
print(f" Largest Prediction index: {yhat}")
print(f"The Probability of Largest index: {prediction_p[0,yhat]:0.2f}")
图2-2-16 “定义神经网络”后的神经网络参数
图2-2-17 “预测”单个图片
图2-2-18 预测错误汇总

本节 Quiz

  1. The Adam optimizer is the recommended optimizer for finding the optimal parameters of the model. How do you use the Adam optimizer in TensorFlow?
    × The Adam optimizer works only with Softmax outputs. So if a neural network has a Softmax output layer, TensorFlow will automatically pick the Adam optimizer.
    × The call to model.compile()uses the Adam optimizer by default.
    × The call to model.compile()will automatically pick the best optimizer, whether it is gradient descent, Adam or something else. So there’s no need to pick an optimizer manually.
    √ When calling model.compile(), set optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3).

  2. The lecture covered a different layer type where each single neuron of the layer does not look at all the values of the input vector that is fed into that layer. What is this name of the layer type discussed in lecture?
    × Image layer.
    √ Convolutional layer.
    × 1D layer or 2D layer (depending on the input dimension).
    × A fully connected layer.

5. 反向传播(选修)

本节介绍TensorFlow如何使用“反向传播”,计算神经网络的代价函数对所有参数的偏导。
“反向传播”是“自动微分(auto-diff)算法”的一种。

5.1 计算图和导数

  显然,由于神经网络可以创建的相当庞大,所以很难显式的写出偏导表达式。此时,我们求解代价函数偏导的思路就转成,求解代价函数在该点切线的斜率,也就是使用很小的步长来近似当前点的切线斜率。但是神经网络通常又有很多层,于是对于每个神经元的每个参数都通过这种方式,直接迭代一次神经网络求解对一个参数的偏导,显然也不现实。于是,我们先通过“计算图(Computation Graph)”来研究一下神经网络的计算流程,找找灵感,比如下面对于单神经元网络的代价函数计算:

图2-2-19 计算代价函数的偏导-单神经元

J ( w , b ) = 1 2 ( ( w x + b ) − y ) 2 ∂ J ∂ w = ∂ d ∂ w ∂ J ∂ d = ∂ a ∂ w ∂ d ∂ a ∂ J ∂ d = ∂ c ∂ w ∂ a ∂ c ∂ d ∂ a ∂ J ∂ d \begin{aligned} J(w,b) &= \frac{1}{2}((wx+b)-y)^2\\ \frac{\partial J}{\partial w} &= \frac{\partial d}{\partial w} \frac{\partial J}{\partial d} = \frac{\partial a}{\partial w} \frac{\partial d}{\partial a} \frac{\partial J}{\partial d} = \frac{\partial c}{\partial w} \frac{\partial a}{\partial c} \frac{\partial d}{\partial a} \frac{\partial J}{\partial d} \end{aligned} J(w,b)wJ=21((wx+b)y)2=wddJ=waaddJ=wccaaddJ

也就是,将整体的计算过程拆成一步一步的,就组成了“计算图”。从左到右,求解当前点的代价函数大小很简单。但注意到,如果我们想要求解代价函数的表达式时,还可以根据上述“计算图”写出求导的“链式法则(chain rule)”!!而且“链式法则”的顺序正好是从右向左的!!由于越靠右的节点也会被更多的参数共用,于是反向传播一次,便可以把依次把路径上的每一个参数的偏导都求解出来。而不是针对每个参数,都额外增加一点,通过从左到右计算代价函数的变化率来求得相应参数的偏导。于是,若“计算图”总共有 N N N 个节点、 P P P 个输入参数,要计算所有函数偏导:

  • 反向传播:只需大约 N + P N+P N+P 个步骤。
  • 针对每个参数求切线斜率:大约 N × P N×P N×P 个步骤。

总结:在“计算图”中使用“链式法则”可以大大加快神经网络的训练速度!!
总结:反向传播就是从左到右计算代价函数,然后从右向左计算所有参数的偏导

5.2 神经网络中的反向传播

  本节就来将上一节的想法应用到大型神经网络中。显然可以如下图所示,先“前向传播”计算神经网络中所有神经元的取值,然后一次“反向传播”遍历走完所有节点,即可计算出神经网络的代价函数对每个神经元的每个参数的偏导。显然,此时“计算图”实际上就相当于神经网络:

图2-2-20 计算代价函数的偏导-两层神经网络

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/217467.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis 分布式锁测试

一、前提依赖&#xff08;除去SpringBoot项目基本依赖外&#xff09;&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId> </dependency><!-- 配置使用redis启动…

移动端APP自动化测试框架-UiAutomator2基础

很早以前&#xff0c;我用uiautomatorjava实践过Android APP自动化测试&#xff0c;不过今天要提的不是uiautomator&#xff0c;而是uiautomator2。听起来uiautomator2像是uiautomator的升级版&#xff0c;但是这两款框架仅仅是名字上比较相似&#xff0c;实际上没有任何关联。…

BiseNet实现遥感影像地物分类

遥感地物分类通过对遥感图像中的地物进行准确识别和分类&#xff0c;为资源管理、环境保护、城市规划、灾害监测等领域提供重要信息&#xff0c;有助于实现精细化管理和科学决策&#xff0c;提升社会治理和经济发展水平。深度学习遥感地物分类在提高分类精度、自动化程度、处理…

最长连续序列代码中的细节解读

最长连续序列 一、题目概述 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 原题地址&#xff1a;https://leetcode.cn/problems/l…

前端开发学习 (四) 自定义按键修饰符

一、 v-on的按键修饰符 按键修饰符&#xff0c;通俗的来说就是监听键盘输入的事件&#xff0c; 在Vue 中允许为 v-on 在监听键盘事件时添加按键修饰符 修饰符用途.enter当在输入框按下回车时触发.tab当按下tab时触发.delete当按下删除键&#xff08;通常是键盘上的Delete键&am…

软件工程 课后题 选择 查缺补漏

在一张状态图中只能有一个初态&#xff0c;而终态则可以没有&#xff0c;也可以有多个 所有的对象可以成为各种对象类&#xff0c;每个对象类都定义了一组 方法 通过执行对象的操作可以改变对象的属性&#xff0c;但它必须经过 消息 的传递 UML应用于 基于对象的面向对象的方…

主动张罗,持续改善!震坤行客服团队再获「全国青年文明号」殊荣

主动张罗&#xff0c;持续改善&#xff01;震坤行客服团队再获「全国青年文明号」殊荣 近日&#xff0c;第21届全国青年文明号集体评选结果揭晓。由共青团中央、最高人民法院、国家发展改革委、工业和信息化部等23家全国创建青年文明号活动组委会成员单位联合印发《关于命名第2…

升辉清洁IPO:广东清洁服务“一哥”还需要讲好全国化的故事

近日&#xff0c;广东物业清洁服务“一哥”升辉清洁第四次冲击IPO成功&#xff0c;拟于12月5日在香港主板挂牌上市。自2021年4月第一次递交招股书&#xff0c;时隔两年半&#xff0c;升辉清洁终于拿到了上市的门票。 天眼查显示&#xff0c;升辉清洁成立于2000年&#xff0c;主…

读SAM代码

def add_decomposed_rel_pos(attn: torch.Tensor,q: torch.Tensor,rel_pos_h: torch.Tensor, 27,80的全零训练参数rel_pos_w: torch.Tensor,q_size: Tuple[int, int], (14,14)k_size: Tuple[int, int], ) -> torch.Tensor:计算相对位置嵌入"""Calculate deco…

Taro 学习教程 - - - - - 开发环境的安装 helloworld

一、Taro脚手架安装 npm install tarojs/cli -g // or yarn add tarojs/cli -g // or cnpm install tarojs/cli -g1.1 如何判断taro安装成功 taro -v正常安装成功之后显示如图&#xff1a; 1.2 环境变量配置(自行判断是否需要手动配置) 如果遇到如下问题&#xff0c;则是需要…

基于stm32的LCD1602与无线蓝牙温湿度显示

这一篇博客是为了实现温湿度的显示&#xff0c;温湿度传感器将数据穿给单片机&#xff0c;单片机又把数据送给LCD1602和蓝牙&#xff0c;让温度和湿度可以再LCD1602显示屏和手机上显示&#xff0c;它的执行逻辑和C51那里基本一样&#xff0c;就是要修改程序&#xff0c;在程序上…

【Linux20.04-qt5.12.4软件安装与初步使用-qt在Linux使用-记录-笔记】

【Linux-qt软件安装与初步使用-qt在Linux使用-记录-笔记】 1、概述2、环境说明3、步骤总结1、了解并选择自己想要安装的版本2、访问 Qt 官方网站3、在 Qt 网站上找到下载部分&#xff08;自己想下载&#xff09;4、下载完成后&#xff0c;给安装程序文件赋予执行权限。5、自动配…

单显卡插槽安装英伟达Tesla P4 AI加速卡

Tesla P4是专业AI显卡&#xff0c;只有70瓦功耗&#xff0c;可以作为AI入门使用。 安装时碰到的几个问题&#xff1a; 首先因为单显卡插槽&#xff0c;就需要先安装好机器&#xff0c;然后ssh登录进行相关配置。安装的时候来回插拔了好多次&#xff01; 其次就是安装驱动时&a…

微信聊天记录年度报告

记忆恢复 若运行代码&#xff0c;执行下列命令安装 git clone https://github.com/LC044/WeChatMsg cd WeChatMsg pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple一、登录微信 切记需要先登录要提取的微信号的微信。 手机端使用聊天记录迁移功…

【电路笔记】-电阻器额定功率

电阻器额定功率 文章目录 电阻器额定功率1、概述2、电阻功率&#xff08;P&#xff09;3、功率电阻器4、电阻器额定功率示例15、电阻器额定功率示例2 电能被电阻吸收&#xff0c;因为它是电压和电流的乘积&#xff0c;一些电阻将这种电能转化为热量。 1、概述 当电流由于电阻器…

基础堆溢出原理与DWORD SHOOT实现

堆介绍 堆的数据结构与管理策略 程序员在使用堆时只需要做三件事情&#xff1a;申请一定大小的内存&#xff0c;使用内存&#xff0c;释放内存。 对于堆管理系统来说&#xff0c;响应程序的内存使用申请就意味着要在"杂乱"的堆区中"辨别"出哪些内存是正在…

实用篇 | 利用Flask+Postman为深度学习模型进行快速测试(超详细)

利用FlaskPostman为深度学习模型进行快速测试&#xff0c;以及算法中的一些实例&#xff0c;以后会更新一些新的模板~~ #本文环境&#xff1a;服务器Ubuntu20.04(docker) 目录 1.下载postrman 2.编写flas的app文件 3.在postrman发送请求 4.实例 在服务器创建app.py文件 …

12月2号作业

#include <iostream>using namespace std; class Sofa{ private:string setting;string *lying new string;public:Sofa(){cout << "Sofa::无参构造函数" << endl;}Sofa(string setting,string lying):setting(setting),lying(new string (lying)…

【shell】

shell 一、shell简介二、shell脚本的执行方式三、shell变量3.1 shell变量介绍3.2 shell变量的定义3.1.1 基本语法3.2.2 定义变量的规则3.2.3 将命令的返回值赋予变量 四、环境变量的设置4.1 基本语法&#xff1a; 五、位置参数变量5.1 基本介绍5.2 基本语法 六、预定义变量6.1 …

金蝶云星空表单插件单据体批量删除,序号自增

文章目录 金蝶云星空表单插件单据体批量删除&#xff0c;序号自增字段标识说明表单插件获取单据体数据包移除物料为空的行其他移除物料为空的行的方式&#xff0c;但是测试不通过&#xff0c;不建议使用序号重新生成测试 金蝶云星空表单插件单据体批量删除&#xff0c;序号自增…