神经网络与深度学习(7)

1. 向量化logistic回归中的梯度输出

还记得我们上一节所讲的么,我们基本上消灭了2个循环,一个内循环,一个外循环。但是那都是建立在向量化的基础上。但这都只是在正向传播的过程中。在反向传播的部分,我们仍然可以使用向量化,来使得程序更加迅速的执行。

在第五节的时候,我们讲过dz的计算: dz(i)=a(i)y(i) ,那么根据我们上一节的经验,我们应该可以很快的就能改造成我们的向量表示:
这里写图片描述
也就是 dZ=AY 。之前我们把dw的迭代解决了。那么现在只需要解决db的问题: db=1mnp.sum(dZ);dW=1mXdZT

至此,我们就已经完全向量化了,想想最原始的代码,再看看现在已经改造好的代码:
这里写图片描述
可以看到最终的代码里没有包含任何循环。就完成了一次迭代过程。但是事实上,我们需要很多次迭代才能够完成最终的循环。因此还是需要在最外面再加一层循环,不过这个循环并不对里面产生什么影响,只是让这段代码多执行几次罢了。

那么下面我们就讲解一下一直所说的广播。

2. 广播

(这一章没有按照吴大大的视频里介绍,因为他只是举了一个例子,我们这里还是想更深入的了解一下广播)。

我们首先看一下吴大大给出的例子:
这里写图片描述
在这个例子中,我们只是计算一下每一类食物中各种营养物质的百分比,也就是说,我们需要把表格里的所有数换成是百分比的形式。
而要做的,只是下面2行代码,第一行代码是按行求和,第二行代码是使用广播来对不同大小的矩阵(A的大小是3*4的,cal的大小是1*4的 )进行运算。

在python里的广播是numpy的特色,它可以使得不同大小的矩阵之间能够进行按位运算。但是也并不是所有的不同的矩阵之间都能够运算,正如它的定义所讲:

只有当数组的形状相同或者可兼容的(compatible),数组间逐个元素(element-wise)的操作才是有效地。

但是什么是可兼容的呢?Numpy从最后开始往前逐个比较它们的维度(dimensions)大小。比较过程中,如果两者的对应维度相同,或者其中之一(或者全是)等于1,比较继续进行直到最前面的维度。否则,你将看到ValueError错误出现(如,”operands could not be broadcast together with shapes …”)。

下面看几个例子

当任何一个维度是1,那么另一个不为1的维度将被用作最终结果的维度。也就是说,尺寸为1的维度将延展或“复制”到与另一个维度匹配。

下面的例子,A和B两个阵列中尺寸为1的维度在广播过程中都被拓展了。

A      (4d array):  8 x 1 x 6 x 1
B      (3d array):      7 x 1 x 5
Result (4d array):  8 x 7 x 6 x 5
Here are some more examples:

更多例子:

A      (1d array):  3
B      (1d array):  4 # trailing dimensions do not match  #维度尺寸不兼容
A      (2d array):      2 x 1
B      (3d array):  8 x 4 x 3 # second from last dimensions mismatched #倒数第二个维度不兼容

具体的可以参见《numpy.broadcasting官方文档》

A      (1d array):  3
B      (1d array):  4 # trailing dimensions do not match  #维度尺寸不兼容
A      (2d array):      2 x 1
B      (3d array):  8 x 4 x 3 # second from last dimensions mismatched #倒数第二个维度不兼容

具体的可以参见《numpy.broadcasting官方文档》、《Python库numpy中的Broadcasting机制解析》及《 numpy中的广播》。

3. 小心编码

由于广播的灵活性,所以有些时候可能会有一些隐秘的BUG出现,而你却浑然不知。下面我们就列举一些问题,引以为戒。

3.1 矩阵大小

由于Python的灵活性,可能有很多时候,我们并不需要显式的声明矩阵的大小。但是有些时候,可能它是一个四不像。
例如,如果我们想申请一个含有5个数的a的话,这样申请出的结果和你预想的不符:

a=np.random.randn(5)
print("a的样子:")
print(a)
print("a的大小:")
print(a.shape)
print("a的转置:")
print(a.T)
print("a与aT的乘积")
print(np.dot(a,a.T))
print("aT与a的乘积")
print(np.dot(a.T,a))

最终的运行结果如下:

a的样子:
[ 1.29280637  0.21452237  0.05347288 -0.44031021  0.18881367]
a的大小:
(5,)
a的转置:
[ 1.29280637  0.21452237  0.05347288 -0.44031021  0.18881367]
a与aT的乘积
1.94975119622
aT与a的乘积
1.94975119622

应该是这样申请才对:

a=np.random.randn(5,1)
print("a的样子:")
print(a)
print("a的大小:")
print(a.shape)
print("a的转置:")
print(a.T)
print("a与aT的乘积")
print(np.dot(a,a.T))
print("aT与a的乘积")
print(np.dot(a.T,a))

最终结果如下:

a的样子:
[[-0.43357311]
 [-0.01419874]
 [ 0.25242622]
 [ 1.98502872]
 [ 0.14664839]]
a的大小:
(5, 1)
a的转置:
[[-0.43357311 -0.01419874  0.25242622  1.98502872  0.14664839]]
a与aT的乘积
[[  1.87985639e-01   6.15619333e-03  -1.09445221e-01  -8.60655070e-01
   -6.35827965e-02]
 [  6.15619333e-03   2.01604316e-04  -3.58413517e-03  -2.81849135e-02
   -2.08222282e-03]
 [ -1.09445221e-01  -3.58413517e-03   6.37189976e-02   5.01073300e-01
    3.70178981e-02]
 [ -8.60655070e-01  -2.81849135e-02   5.01073300e-01   3.94033901e+00
    2.91101258e-01]
 [ -6.35827965e-02  -2.08222282e-03   3.70178981e-02   2.91101258e-01
    2.15057492e-02]]
aT与a的乘积
[[ 4.213751]]

这里的原因就是,如果没有指定大小的这个(5,),这是秩为1的数组,它既不是行向量也不是列向量。正如吴大大所说,放心使用reshape,因为它的时间复杂度只有O(1)但是可以保证你的代码质量。

3.2 *和numpy.dot

这里要介绍2个运算符,其中 如果连接两个矩阵的话,那么表示这两个矩阵要同大小,然后是对位点积。而如果是numpy.dot的话,则是按照矩阵乘法规则算的。具体的,可以看一下:《numpy中关于*和dot的区别

4. 一些小问题

在之前的一些介绍中,可能会有一些疑问的地方。首先,我们还是看一下这里的图:
这里写图片描述
一方面,我们困惑的是,J在这里没有向量化,那么实际上,它是需要向量化计算的,虽然它本身是一个标量,但是它可以使用向量化计算的。

另一方面,我们可能对于红方框下面的dz的样子感到困惑,为什么dz就变成了这样,这岂不是就变成了0-1损失了吗?事实上只是恰好长这个样子而已,它的推导过程如下图所示:
这里写图片描述

这样根据链式法则就可以知道dz其实指的是dLdz,而它的样子只不过恰好是这个样子罢了。

至此为止,我们就完成了第二周的学习,主要的内容是如何构建一个神经网络模型,并且使得Logistic回归向量化。但是如何实践我们还不得而知,这要在第三周的课程中,才会讲到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI让世界更懂你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值