文章目录
- 一、神经网络概述
- 二、神经网络的表示
- 三、神经网络的输出
- 四、多个例子的向量化
- 五、向量化实现的解释
- 六、深度学习激活函数
- 七、激活函数导数
- 八、神经网络的梯度下降法
- 九、深度学习随机初始化
- 十、上述学习总结
- 1、第一题
- 2、第二题
- 3、第三题
- 4、第四题
- 5、第五题
- 6、第六题
- 7、第7题
- 十一、深层神经网络常识
- 十二、深度学习前向和反向传播
- 十三、编程大作业实现
- 1、环境准备与数据集
- 2、Logistic回归的分类效果
- 2、定义神经网络结构
- 3、初始化模型的参数
- 4、sigmoid与tanh前向传播
- 5、计算成本函数J
- 6、反向传播(难点)
- 7、更新参数和模型整合
- 8、预测与运行
一、神经网络概述
推荐视频神经网络的本质与结构 3Blue1Brown
- 前情提要:神经网络公式
- 可以把许多
sigmoid
单元堆叠起来形成一个神经网络
在逻辑回归中,通过直接计算 z 得到结果 a 。而这个神经网络中,我们反复的计算 z 和 a ,计算 a 和 z ,最后得到了最终的输出`loss function`。在逻辑回归中,有一些从后向前的计算用来计算导数 `da、dz` 。同样,在神经网络中我们也有从后向前的计算,看起来就像这样,最后会计算 da^[2]^、 dz^[2]^、 计算出来之后,然后计算dw^[2]^、 db^[2]^等,按公式3.4、3.5箭头表示的那样,从右到左反向计算。
基于逻辑回归重复使用了两次该模型得到上述例子的神经网络。
逻辑回归中的导数 ( da ) 和 ( dz ) 是损失函数关于预测概率 (a) 和线性组合输入 (z) 的偏导数,它们在反向传播算法中用于更新模型参数 (w) 和 (b)。具体来说:
- 导数 ( da ) 是损失函数 ( L(a,y) ) 相对于预测概率 ( a ) 的偏导数。根据二元交叉熵损失函数,我们有:
- ( da = dL/da = -y/a + (1-y)/(1-a) )
- 导数 ( dz ) 是损失函数 ( L(a,y) ) 相对于 ( z ) 的偏导数,并且是通过链式法则从 ( da ) 推导得到的:
- ( dz = dL/dz = da * a(1-a) )
- 在具体的梯度下降步骤中,我们会使用以下公式来更新参数 ( w ) 和 ( b ):
- ( dw = X^Tdz ) (其中 ( X ) 是输入特征矩阵,( dz ) 是一个向量或矩阵,根据上下文而定)
- ( db = dz ) (因为 ( b ) 是一个标量)
这些导数对于理解如何通过梯度下降来优化逻辑回归模型至关重要。在每次迭代中,我们计算这些导数值并用它们来调整 ( w ) 和 ( b ),以期减小损失函数的值,从而提高模型的预测性能。
二、神经网络的表示
下面的x1 x2 x3
表示一个样本的三个特征值
- 有输入特征
x 1 、 x 2 、 x 3
,它们被竖直地堆叠起来,这叫做神经网络的输入层(Input Layer
)。 - 它包含了神经网络的输入;然后这里有另外一层我们称之为隐藏层
(Hidden Layer
)。 - 在本例中最后一层只由一个结点构成,而这个只有一个结点的层被称为输出层
(Output Layer)
,它负责产生预测值。 - 隐藏层的含义:在一个神经网络中,使用监督学习训练它的时候,训练集包含了输入 x 也包含了目标输出 y ,所以术语隐藏层的含义是在训练集中,这些中间结点的准确值我们是不知道到的,也就是说你看不见它们在训练集中应具有的值。你能看见输入的值,你也能看见输出的值,但是隐藏层中的东西,在训练集中你是无法看到的。所以这也解释了词语隐藏层,只是表示你无法在训练集中看到他们。
现在我们再引入几个符号,就像我们之前用向量 x
表示输入特征。这里有个可代替的记号 a[0] 可以用来表示输入特征。 a
表示激活的意思,它意味着网络中不同层的值会传递到它们后面的层中,输入层将 x
传递给隐藏层,所以我们将输入层的激活值称为 a[0]
下一层即隐藏层也同样会产生一些激活值,那么我将其记作 a[1],所以具体地,这里的第一个单元或结点我们将其表示为 a1[1],第二个结点的值我们记为 a2[2]以此类推。所以这里的是一个四维的向量如果写成Python代码,那么它是一个规模为4x1
的矩阵或一个大小为4的列向量,如下公式,它是四维的,因为在本例中,我们有四个结点或者单元,或者称为四个隐藏层单元;
- 最后输出层将产生某个数值 a ,它只是一个单独的实数,所以 y 帽
的值将取为 a[2] 这与逻辑回归很相似,在逻辑回归中,我们有 y 帽
直接等于 a ,在逻辑回归中我们只有一个输出层,所以我们没有用带方括号的上标。 - 但是在神经网络中,我们将使用这种带上标的形式来明确地指出这些值来自于哪一层,有趣的是在约定俗成的符号传统中,在这里你所看到的这个例子,只能叫做一个两层的神经网络。原因是当我们计算网络的层数时,输入层是不算入总层数内,所以隐藏层是第一层,输出层是第二层。第二个惯例是我们将输入层称为第零层,所以在技术上,这仍然是一个三层的神经网络,因为这里有输入层、隐藏层,还有输出层。但是在传统的符号使用中,如果你阅读研究论文或者在这门课中,你会看到人们将这个神经网络称为一个两层的神经网络,因为我们不将输入层看作一个标准的层。
最后,我们要看到的隐藏层以及最后的输出层是带有参数的,这里的隐藏层将拥有两个参数 W和 b ,我将给它们加上上标 [1] ( W [1], b [1])
表示这些参数是和第一层这个隐藏层有关系的。之后在这个例子中我们会看到 W 是一个4x3的矩阵,而 b 是一个4x1
的向量,第一个数字4源自于我们有四个结点或隐藏层单元,然后数字3源自于这里有三个输入特征,我们之后会更加详细地讨论这些矩阵的维数,到那时你可能就更加清楚了。相似的输出层也有一些与之关联的参数W [2], b [2] 从维数上来看,它们的规模分别是1x4以及1x1。1x4是因为隐藏层有四个隐藏层单元而输出层只有一个单元,之后我们会对这些矩阵和向量的维度做出更加深入的解释,所以现在你已经知道一个两层的神经网络什么样的了,即它是一个只有一个隐藏层的神经网络。
三、神经网络的输出
神经网络计算
,从逻辑回归开始,如下图所示。用圆圈表示神经网络的计算单元,逻辑回归的计算有两个步骤,首先你按步骤计算出 z ,然后在第二步中以sigmoid
函数为激活函数计算 z (得出 a ),一个神经网络只是这样子做了好多次重复计算。
如果执行神经网络的程序,用for循环来做这些看起来真的很低效。所以接下来我们要做的就是把这四个等式向量化。向量化的过程是将神经网络中的一层神经元参数纵向堆积起来,例如隐藏层中的 w 纵向堆积起来变成一个 (4,3) 的矩阵,用符号 W[1]表示。另一个看待这个的方法是我们有四个逻辑回归单元,且每一个逻辑回归单元都有相对应的参数——向量 w,把这四个向量堆积在一起,你会得出这4×3的矩阵。 因此, 公式3.8:
四、多个例子的向量化
[n]
表示第n层,(i)
表示第i个样本,下标表示样本的第几个特征
a[i](m)
→其中i是神经网络的第几层(层数),m是第几个样本。行列式,行数代表层数,列数代表样本序号。
隐藏单元就是指每一层神经网络中的那些圆圈圈。
for循环是来遍历所有个训练样本。 定义矩阵 X 等于训练样本,将它们组合成矩阵的各列,形成一个 n 维或 n 乘以 m维矩阵。接下来计算见公式3.15:
以此类推,从小写的向量 x 到这个大写的矩阵 X ,只是通过组合 x 向量在矩阵的各列中。同理z[1](1), z[1](2) 等等都是 z [1](m) 的列向量,将所有 m 都组合在各列中,就的到矩阵 Z[1]
- 同理a[1](1), a[1](2) ……a[1](m), 将其组合在矩阵各列中,如同从向量 x 到矩阵 X ,以及从向量 z 到矩阵 Z 一样,就能得到矩阵 A [1]
同样的,对于 Z[2]和A[2] ,也是这样得到。
这种符号其中一个作用就是,可以通过训练样本来进行索引。这就是水平索引对应于不同的训练样本的原因,这些训练样本是从左到右扫描训练集而得到的。
神经网络上通过在多样本情况下的向量化来使用这些等式。
横向是样本,竖向是隐藏层的节点
五、向量化实现的解释
吴恩达老师很细心的用不同的颜色表示不同的样本向量,及其对应的输出。所以从图中可以看出,当加入更多样本时,只需向矩阵 X中加入更多列。
所以从这里我们也可以了解到,之前我们对单个样本的计算要写成z[1](i)=W[1] x(i)+b[1] 这种形式,因为当有不同的训练样本时,将它们堆到矩阵 X 的各列中,那么它们的输出也就会相应的堆叠到矩阵 Z[1] 的各列中。现在我们就可以直接计算矩阵 Z[1] 加上 b[1] ,因为列向量 b[1] 和矩阵 Z[1] 的列向量有着相同的尺寸,而Python的广播机制对于这种矩阵与向量直接相加的处理方式是,将向量与矩阵的每一列相加。 所以这一节只是说明了为什么公式 Z [1]= W [1]X + b[1]是前向传播的第一步计算的正确向量化实现,但事实证明,类似的分析可以发现,前向传播的其它步也可以使用非常相似的逻辑,即如果将输入按列向量横向堆叠进矩阵,那么通过公式计算之后,也能得到成列堆叠的输出。
六、深度学习激活函数
结果表明,如果在隐藏层上使用函数 公式3.20: g (z[1]) = tanh ( z[1]) 效果总是优于sigmoid函数。因为函数值域在-1和+1的激活函数,其均值是更接近零均值的。在训练一个算法模型时,如果使用tanh函数代替sigmoid函数中心化数据,使得数据的平均值更接近0而不是0.5.
两者的优点是:
第一,在 z 的区间变动很大的情况下,激活函数的导数或者激活函数的斜率都会远大于0,在程序实现就是一个if-else
语句,而sigmoid
函数需要进行浮点四则运算,在实践中,使用ReLu激活函数神经网络通常会比使用sigmoid或者tanh激活函数学习的更快。
第二,sigmoid
和tanh
函数的导数在正负饱和区的梯度都会接近于0,这会造成梯度弥散,而Relu和Leaky ReLu函数大于0部分都为常数,不会产生梯度弥散现象。(同时应该注意到的是,Relu进入负半区的时候,梯度为0,神经元此时不会训练,产生所谓的稀疏性,而Leaky ReLu不会有这问题)
z 在ReLu
的梯度一半都是0,但是,有足够的隐藏层使得z值大于0,所以对大多数的训练数据来说学习过程仍然可以很快。
快速概括一下不同激活函数的过程和结论。
-
sigmoid
激活函数:除了输出层是一个二分类问题基本不会用它。 -
tanh
激活函数:tanh是非常优秀的,几乎适合所有场合。 -
ReLu
激活函数:最常用的默认函数,,如果不确定用哪个激活函数,就使用ReLu或者Leaky ReLu。
为什么需要非线性激活函数
- 如果不设置激活函数,那么不论设置多少个隐藏层其实和设置一个隐藏层是一样的,也就是说没有激活函数,本质上都是单层的神经网络,只有有了激活函数才相当于真正扩展到了多层神经网络
七、激活函数导数
八、神经网络的梯度下降法
n是对于每层的节点数,比如w[1]行位置上的n[1]就是第一层那n[1]个节点,而列位置上的n[0]就是输入特征向量x有n[0]个特征,也就是输入层第0层有n[0]个节点]
n0是输入层元素个数,n1是第一层隐藏单元个数
上述是反向传播的步骤,注:这些都是针对所有样本进行过向量化, Y 是 1 ∗ m
的矩阵;这里np.sum
是python的numpy命令,axis=1
表示水平相加求和,keepdims
是防止python输出那些古怪的秩数 ( n , )
加上这个确保矩阵db[2]这个向量输出的维度为 ( n , 1 )这样标准的形式。
目前为止,我们计算的都和Logistic
回归十分相似,但当你开始计算反向传播时,你需要计算,是隐藏层函数的导数,输出在使用sigmoid
函数进行二元分类。这里是进行逐个元素乘积,因为 W[2]T dz[2]W 和 (Z[1] )这两个都为(n[1],m)矩阵;
还有一种防止python输出奇怪的秩数,需要显式地调用reshape把np.sum输出结果写成矩阵形式。
九、深度学习随机初始化
- 当训练神经网络时,权重随机初始化是很重要的。对于逻辑回归,把权重初始化为0当然也是可以的。但是对于一个神经网络,如果你把权重或者参数都初始化为0,那么梯度下降将不会起作用。
十、上述学习总结
1、第一题
正解:BDEF
错因:
A:第2层的第12个神经元的激活值
C: 就是D描述
G: 就是B描述
2、第二题
正解:D
3、第三题
A = np.random.randn(4,3)
B = np.sum(A, axis = 1, keepdims = True)
B.shape是多少?
A.(4,) B.(1, 3) C.(, 3) D.(4, 1)
正解:D
首先,A = np.random.randn(4,3)
创建了一个形状为(4, 3)的数组,即有4行3列的矩阵。
然后,B = np.sum(A, axis = 1, keepdims = True)
对矩阵A进行操作,其中np.sum
函数用于计算数组元素的和。参数axis = 1
指定了沿着水平轴(即每一行内部)进行求和,而keepdims = True
的作用是在求和后保持原有的维度不变,即不降维。
因此,经过这样的操作后,B的形状将变为(4, 1),也就是说,它仍然是一个4行的矩阵,但列数减少为1,因为原本每一行的3个元素被求和成了一个元素。
4、第四题
逻辑回归的权重w应该随机初始化,而不是全部初始化为全部零,否则,逻辑回归将无法学习有用的决策边界,因为它将无法“打破对称
这种说法并不准确。逻辑回归模型的权重w可以初始化为全零,这并不影响模型的学习能力和最终性能。
5、第五题
已经为所有隐藏的单位建立了一个使用tanh激活的网络。使用np.random.randn(…, …)*1000
将权重初始化为相对较大的值。会发生什么?
A.没关系。只要随机初始化权重,梯度下降不受权重大小的影响。
B.这将导致tanh的输入也非常大,从而导致梯度也变大。因此,你必须将设置得非常小,以防止发散;这将减慢学习速度。
C.这将导致tanh的输入也非常大,导致单元被“高度激活”。与权重从小值开始相比,加快了学习速度。
D.这将导致tanh的输入也非常大,从而导致梯度接近于零。因此,优化算法将变得缓慢。
正解:D
6、第六题
考虑以下1个隐层的神经网络:
正解:BCEH
W[i]后面对应的是(i层的神经元数目,i-1层的神经元数目)⭐️⭐️⭐️⭐️⭐️
7、第7题
同一层的z的维度和A的相同,m是样本数目。
正解:C
十一、深层神经网络常识
以下面的图为例,深度学习常见记号
- 权重矩阵的行数对应于当前层的神经元数量,列数对应于上一层的神经元数量。
核对矩阵维数
关于为什么要缓存z[l],因为dz[l] =da[l] dot(g[l] ′ (z [l]))
而dw[l]=a[l-1]dz[l],db[l]=dz[l],da[l-1]=w[l]Tdz[l]都间接(因为用到了dz[l])用到了z[l]
十二、深度学习前向和反向传播
搭建深层神经网络块
da又叫做a‘,导数的意思,这里是偏导数(梯度)
参数 vs 超参数
十三、编程大作业实现
序幕:我们要建立一个神经网络,它有一个隐藏层。这个模型和上一个逻辑回归实现
的模型有很大的区别。
- 构建具有单隐藏层的2类分类神经网络。
- 使用具有非线性激活功能激活函数
tanh
。 - 计算交叉熵损失(损失函数)。
- 实现向前和向后传播。
1、环境准备与数据集
软件包环境:
numpy
:是用Python进行科学计算的基本软件包。
sklearn
:为数据挖掘和数据分析提供的简单高效的工具。
matplotlib
:是一个用于在Python中绘制图表的库。
import numpy as np
import matplotlib.pyplot as plt
from testCases import *
import sklearn
import sklearn.datasets
import sklearn.linear_model
from planar_utils import plot_decision_boundary, sigmoid, load_planar_dataset, load_extra_datasetsnp.random.seed(1) #设置一个固定的随机种子,以保证接下来的步骤中我们的结果是一致的。
load_planar_dataset()
是一个用于加载平面数据集的函数。
- 这个函数通常在机器学习和深度学习的教程或示例代码中出现,用于创建一个简单的二分类问题数据集。它返回两个矩阵,一个是特征矩阵X,另一个是对应的标签矩阵Y。
- 在深度学习的背景下,
load_planar_dataset()
可能会被用来演示如何使用神经网络来解决分类问题,特别是当数据不是线性可分的时候。例如,通过使用这个函数,可以生成一个类似于“鲜花形状”
的数据集,其中包含两类不同的点,需要通过建立适当的模型来进行分类。
数据看起来像一朵红色(y = 0)和一些蓝色(y = 1)的数据点的花朵的图案。 我们的目标是建立一个模型来适应这些数据。现在,我们已经有了以下的东西:
-
- X:一个numpy的矩阵,包含了这些数据点的数值
-
- Y:一个numpy的向量,对应着的是X的标签【0 | 1】(红色:0 , 蓝色 :1)
2、Logistic回归的分类效果
对照组
sklearn.linear_model.LogisticRegressionCV
() 是一个用于逻辑回归分类的类,它结合了交叉验证和正则化。
该类使用L2正则化(岭回归)或L1正则化(套索回归),并使用交叉验证来选择最佳的正则化参数。它通过在训练集上进行多次拟合,每次使用不同的正则化参数,然后选择具有最高交叉验证得分的模型作为最终模型。
from sklearn.linear_model import LogisticRegressionCV# 创建 LogisticRegressionCV 对象
lrcv = LogisticRegressionCV(Cs=[1, 10, 100], cv=5, penalty='l2', solver='lbfgs', max_iter=100)# 拟合数据
lrcv.fit(X_train, y_train)# 预测新数据
y_pred = lrcv.predict(X_test)
这段代码是用于绘制逻辑回归模型的决策边界,并计算模型的准确性。
-
首先,
plot_decision_boundary(lambda x: clf.predict(x), X, Y)
这行代码调用了一个名为plot_decision_boundary
的函数,该函数接受一个预测函数、特征矩阵 X 和标签向量 Y 作为参数。这里的预测函数是一个匿名函数lambda x: clf.predict(x)
,它使用逻辑回归分类器clf
对输入数据进行预测。(进行画红蓝分解图像) -
然后,
LR_predictions = clf.predict(X.T)
这行代码使用逻辑回归分类器clf
对特征矩阵 X 的转置进行预测,得到预测结果LR_predictions
。 -
最后,
print("逻辑回归的准确性: %d " % float((np.dot(Y, LR_predictions) + np.dot(1 - Y, 1 - LR_predictions)) / float(Y.size) * 100) + "% " + "(正确标记的数据点所占的百分比)")
这行代码计算了逻辑回归模型的准确性。准确性是通过计算正确标记的数据点所占的百分比来得到的。这里使用了np.dot()
函数来计算两个向量的点积,然后将结果除以标签向量 Y 的大小(即样本数量),再乘以 100 得到百分比。最后,将准确性以字符串的形式打印出来。
准确性只有47%的原因是数据集不是线性可分的,所以逻辑回归表现不佳(对照组),现在正式开始构建神经网络。
2、定义神经网络结构
理论公式可以看我之前写的博客
https://blog.csdn.net/QuantumYou/article/details/137249807?spm=1001.2014.3001.5502
def layer_sizes(X , Y):"""参数:X - 输入数据集,维度为(输入的数量,训练/测试的数量)Y - 标签,维度为(输出的数量,训练/测试数量)返回:n_x - 输入层的数量n_h - 隐藏层的数量n_y - 输出层的数量"""n_x = X.shape[0] #输入层n_h = 4 #,隐藏层,硬编码为4n_y = Y.shape[0] #输出层return (n_x,n_h,n_y)
3、初始化模型的参数
实现函数initialize_parameters()
。确保我们的参数大小合适,如果需要的话,请参考上面的神经网络图。
我们将会用随机值初始化权重矩阵。
-
np.random.randn(a,b)* 0.01
来随机初始化一个维度为(a,b)的矩阵。
将偏向量初始化为零。 -
np.zeros((a,b))
用零初始化矩阵(a,b)。
def initialize_parameters( n_x , n_h ,n_y):"""参数:n_x - 输入层节点的数量n_h - 隐藏层节点的数量n_y - 输出层节点的数量返回:parameters - 包含参数的字典:W1 - 权重矩阵,维度为(n_h,n_x)b1 - 偏向量,维度为(n_h,1)W2 - 权重矩阵,维度为(n_y,n_h)b2 - 偏向量,维度为(n_y,1)"""np.random.seed(2) #指定一个随机种子,以便你的输出与我们的一样。W1 = np.random.randn(n_h,n_x) * 0.01b1 = np.zeros(shape=(n_h, 1))W2 = np.random.randn(n_y,n_h) * 0.01b2 = np.zeros(shape=(n_y, 1))#使用断言确保我的数据格式是正确的assert(W1.shape == ( n_h , n_x ))assert(b1.shape == ( n_h , 1 ))assert(W2.shape == ( n_y , n_h ))assert(b2.shape == ( n_y , 1 ))parameters = {"W1" : W1,"b1" : b1,"W2" : W2,"b2" : b2 }return parameters
4、sigmoid与tanh前向传播
def forward_propagation( X , parameters ):"""参数:X - 维度为(n_x,m)的输入数据。parameters - 初始化函数(initialize_parameters)的输出返回:A2 - 使用sigmoid()函数计算的第二次激活后的数值cache - 包含“Z1”,“A1”,“Z2”和“A2”的字典类型变量"""W1 = parameters["W1"]b1 = parameters["b1"]W2 = parameters["W2"]b2 = parameters["b2"]#前向传播计算A2Z1 = np.dot(W1 , X) + b1A1 = np.tanh(Z1)Z2 = np.dot(W2 , A1) + b2A2 = sigmoid(Z2)#使用断言确保我的数据格式是正确的assert(A2.shape == (1,X.shape[1]))cache = {"Z1": Z1,"A1": A1,"Z2": Z2,"A2": A2}return (A2, cache)
5、计算成本函数J
def compute_cost(A2,Y,parameters):"""计算方程(6)中给出的交叉熵成本,参数:A2 - 使用sigmoid()函数计算的第二次激活后的数值Y - "True"标签向量,维度为(1,数量)parameters - 一个包含W1,B1,W2和B2的字典类型的变量返回:成本 - 交叉熵成本给出方程(13)"""m = Y.shape[1]W1 = parameters["W1"]W2 = parameters["W2"]#计算成本logprobs = logprobs = np.multiply(np.log(A2), Y) + np.multiply((1 - Y), np.log(1 - A2))cost = - np.sum(logprobs) / mcost = float(np.squeeze(cost))assert(isinstance(cost,float))return cost
6、反向传播(难点)
def backward_propagation(parameters,cache,X,Y):"""使用上述说明搭建反向传播函数。参数:parameters - 包含我们的参数的一个字典类型的变量。cache - 包含“Z1”,“A1”,“Z2”和“A2”的字典类型的变量。X - 输入数据,维度为(2,数量)Y - “True”标签,维度为(1,数量)返回:grads - 包含W和b的导数一个字典类型的变量。"""m = X.shape[1]W1 = parameters["W1"]W2 = parameters["W2"]A1 = cache["A1"]A2 = cache["A2"]dZ2= A2 - YdW2 = (1 / m) * np.dot(dZ2, A1.T)db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2))dW1 = (1 / m) * np.dot(dZ1, X.T)db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)grads = {"dW1": dW1,"db1": db1,"dW2": dW2,"db2": db2 }return grads
7、更新参数和模型整合
图片来源Adam Harley⭐️
def update_parameters(parameters,grads,learning_rate=1.2):"""使用上面给出的梯度下降更新规则更新参数参数:parameters - 包含参数的字典类型的变量。grads - 包含导数值的字典类型的变量。learning_rate - 学习速率返回:parameters - 包含更新参数的字典类型的变量。"""W1,W2 = parameters["W1"],parameters["W2"]b1,b2 = parameters["b1"],parameters["b2"]dW1,dW2 = grads["dW1"],grads["dW2"]db1,db2 = grads["db1"],grads["db2"]W1 = W1 - learning_rate * dW1b1 = b1 - learning_rate * db1W2 = W2 - learning_rate * dW2b2 = b2 - learning_rate * db2parameters = {"W1": W1,"b1": b1,"W2": W2,"b2": b2}return parametersdef nn_model(X,Y,n_h,num_iterations,print_cost=False):"""参数:X - 数据集,维度为(2,示例数)Y - 标签,维度为(1,示例数)n_h - 隐藏层的数量num_iterations - 梯度下降循环中的迭代次数print_cost - 如果为True,则每1000次迭代打印一次成本数值返回:parameters - 模型学习的参数,它们可以用来进行预测。"""np.random.seed(3) #指定随机种子n_x = layer_sizes(X, Y)[0]n_y = layer_sizes(X, Y)[2]parameters = initialize_parameters(n_x,n_h,n_y)W1 = parameters["W1"]b1 = parameters["b1"]W2 = parameters["W2"]b2 = parameters["b2"]for i in range(num_iterations):A2 , cache = forward_propagation(X,parameters)cost = compute_cost(A2,Y,parameters)grads = backward_propagation(parameters,cache,X,Y)parameters = update_parameters(parameters,grads,learning_rate = 0.5)if print_cost:if i%1000 == 0:print("第 ",i," 次循环,成本为:"+str(cost))return parameters
8、预测与运行
def predict(parameters,X):"""使用学习的参数,为X中的每个示例预测一个类参数:parameters - 包含参数的字典类型的变量。X - 输入数据(n_x,m)返回predictions - 我们模型预测的向量(红色:0 /蓝色:1)"""A2 , cache = forward_propagation(X,parameters)predictions = np.round(A2)return predictions# 运行
parameters = nn_model(X, Y, n_h = 4, num_iterations=10000, print_cost=True)#绘制边界
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y)
plt.title("Decision Boundary for hidden layer size " + str(4))predictions = predict(parameters, X)
print ('准确率: %d' % float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100) + '%')
predict
函数,它接收两个参数:parameters
和X
。parameters
是一个包含模型参数的字典,X
是输入数据。
函数的主要目的是使用学习的参数为输入数据X
中的每个示例预测一个类。首先,它调用forward_propagation
函数,将X
和parameters
作为输入参数,返回A2
和cache
。然后,通过对A2
进行四舍五入操作(np.round(A2)
),得到预测结果predictions
。最后,函数返回预测结果predictions
。
注解:训练一个神经网络模型并绘制决策边界的。首先,通过调用nn_model
函数来训练模型,传入输入数据X
、标签Y
、隐藏层大小n_h
、迭代次数num_iterations
和是否打印损失值print_cost
等参数。然后,使用plot_decision_boundary
函数绘制决策边界,传入预测函数(通过lambda x: predict(parameters, x.T)
定义)、输入数据X
和标签Y
。接着,设置图表标题为"Decision Boundary for hidden layer size "加上隐藏层大小。最后,使用predict
函数对输入数据X
进行预测,并计算准确率,将结果打印出来。
- 边界在机器学习中通常用于区分不同类别的数据。在这个例子中,决策边界是一条线或曲线,它将输入空间划分为两个区域:一个区域包含属于类别1的样本,另一个区域包含属于类别2的样本。通过绘制决策边界,我们可以直观地看到模型如何根据输入特征将数据点分类到不同的类别中。这对于理解模型的性能和进行模型评估非常有用。
用于绘制不同隐藏层节点数量下的决策边界,并输出对应的准确率。首先设置画布大小为16x32
,然后定义一个包含不同隐藏层节点数量的列表。接着使用循环遍历这个列表,每次循环中绘制一个子图,标题为当前隐藏层节点数量,调用nn_model
函数训练模型,传入输入数据X、标签Y、当前隐藏层节点数量和迭代次数5000。然后调用plot_decision_boundary
函数绘制决策边界,传入预测函数、输入数据X和标签Y。接着调用predict函数对输入数据X进行预测,计算准确率并输出。
- 隐藏层节点数量是指神经网络中隐藏层的神经元数量。在这段代码中,隐藏层节点数量分别为1、2、3、4、5、20和50。
⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️