深度学习笔记_Week2

2.10 m 个样本的梯度下降(Gradient Descent on m Examples)

​ 将2.9对一个样本的操作应用到m个训练样本上,我们要做的是计算这些微分,如我们在之前的训练样本上做的,并且求平均, 得到全局梯度值,把它直接应用到梯度下降算法中。

初始化𝐽 = 0, 𝑑𝑤1 = 0, 𝑑𝑤2 = 0, 𝑑𝑏 = 0

J=0;dw1=0;dw2=0;db=0;
for i = 1 to m
    z(i) = wx(i)+b;
    a(i) = sigmoid(z(i));
    J += -[y(i)log(a(i))+(1-y(i))log(1-a(i));
    dz(i) = a(i)-y(i);
    dw1 += x1(i)dz(i);
    dw2 += x2(i)dz(i);
    db += dz(i);
J/= m;
dw1/= m;
dw2/= m;
db/= m;
w=w-alpha*dw
b=b-alpha*db

​ 在这种计算中有两个缺点,需要编写两个 for 循环。第一个 for 循环是一个小循环遍历𝑚个训练样本,第二个 for 循环是一个遍历所有特征的 for 循环。这个例子中只有 2 个特征,所以𝑛等于 2 并且𝑛𝑥 等于 2。 但如果有更多特征,需要一 个 for 循环遍历所有𝑛个特征。

​ 在代码中显式地使用 for 循环使算法很低效,同时在深度学习领域会有越来越大的数据集。所以使算法没有显式的 for 循环是十分重要的,可以适用于更大的数据集。使用向量化技术可以使得代码摆脱 for 循环。

2.11 向量化(Vectorization)

对于计算𝑧 = 𝑤𝑇𝑥 + 𝑏,𝑤、𝑥都是列向量。

如果采用非向量化方法:

z=0
for i in range(n_x)
 z+=w[i]*x[i]
z+=b

采用向量化方法:

z=np.dot(w,x)+b

老师在课上举的例子:

import numpy as np #导入 numpy 库
a = np.array([1,2,3,4]) #创建一个数据 a
print(a)# [1 2 3 4]
import time #导入时间库
a = np.random.rand(1000000)
b = np.random.rand(1000000) #通过 round 随机得到两个一百万维度的数组
tic = time.time() #现在测量一下当前时间
#向量化的版本
c = np.dot(a,b)
toc = time.time()
print(“Vectorized version:” + str(1000*(toc-tic)) +”ms”) #打印一下向量
化的版本的时间
#继续增加非向量化的版本
c = 0
tic = time.time()
for i in range(1000000):
 c += a[i]*b[i]
toc = time.time()
print(c)
print(“For loop:” + str(1000*(toc-tic)) + “ms”)#打印 for 循环的版本的时
间

​ 在两个方法中,向量化和非向量化计算了相同的值,向量化版本花费了 1.5 毫秒,非向量化版本的 for 循环花费了大约几乎 500 毫秒,非向量化版本多花费了 300 倍时间。所以在这个例子中,仅仅是向量化你的代码,就会运行 300 倍快。这意味着如果向量化方法需要花费一分钟去运行的数据,for 循环将会花费 5 个小时去运行。

2.12 向量化的更多例子(More Examples of Vectorization)

​ 如果你想计算向量𝑢 = 𝐴𝑣,这时矩阵乘法定义为,矩阵乘法的定义就是:𝑢𝑖 = ∑𝑗 𝐴ij𝑣𝑖

​ 同样使用非向量化实现,𝑢 = 𝑛𝑝. 𝑧𝑒𝑟𝑜𝑠(𝑛, 1), 并且通过两层循环𝑓𝑜𝑟(𝑖): 𝑓𝑜𝑟(𝑗):,得到𝑢[𝑖] = 𝑢[𝑖] + 𝐴[𝑖] [𝑗] ∗ 𝑣[𝑗] 。现在就有了𝑖 和 𝑗 的两层循环

​ 向量化方式就可以用𝑢 = 𝑛𝑝. 𝑑𝑜𝑡(𝐴, 𝑣),向量化实现方式,消除了两层循环,使得代码运行速度更快。

image

​ 如果你已经有一个向量𝑣,并且想要对向量𝑣的每个元素做指数操作,得到向量𝑢等于𝑒的𝑣1,𝑒的𝑣2,一直到𝑒的𝑣𝑛次方。这里是非向量化的实现方式,首先你初始化了向量𝑢 = 𝑛𝑝. 𝑧𝑒𝑟𝑜𝑠(𝑛, 1),并且通过循环依次计算每个元素。但也可以通过 python 的 numpy 内置函数,import numpy as np,执行 𝑢 = 𝑛𝑝. 𝑒𝑥𝑝(𝑣) 命令。

​ 将以上知识应用到梯度下降法中,如果有超过两个特征时,需要循环 𝑑𝑤1 、𝑑𝑤2 、𝑑𝑤3 等等。所以 𝑗 的实际值是 1、2 和 𝑛𝑥。要想消除第二循环,不用初始化 𝑑𝑤1 , 𝑑𝑤2 都等于 0,而是定义 𝑑𝑤 为一个向量,设置 𝑢 = 𝑛𝑝. 𝑧𝑒𝑟𝑜𝑠(𝑛(𝑥),1)。定义了一个𝑥行的一维向量,从而替代循环,仅仅使用了一个向量操作 𝑑𝑤 = 𝑑𝑤 + 𝑥 (𝑖)𝑑𝑧 (𝑖) 。最后得到 𝑑𝑤 = 𝑑𝑤/𝑚 ,将两层循环转成一层循环。

image

2.13 向量化逻辑回归(Vectorizing Logistic Regression)

​ 如果有 𝑚 个训练样本,然后对第一个样本进行预测,需要这样计算:计算 𝑧,𝑧 (1) = 𝑤𝑇𝑥 (1) + 𝑏 。
然后计算激活函数 𝑎 (1) = 𝜎(𝑧 (1) ) ,计算第一个样本的预测值 𝑦 。
​ 对第二个样本进行预测,需要计算 𝑧 (2) = 𝑤𝑇𝑥 (2) + 𝑏 , 𝑎 (2) = 𝜎(𝑧 (2) ) 。
​ 对第三个样本进行预测,需要计算 𝑧 (3) = 𝑤𝑇𝑥 (3) + 𝑏 ,𝑎 (3) = 𝜎(𝑧 (3) ) ,依次类推。
​ 如果有 𝑚 个训练样本,需要这样做 𝑚 次。

​ 为了在一个步骤中计算 𝑧1、 𝑧2 、𝑧3 …… zm。先构建一个 1 × 𝑚 的矩阵,实际上它是一个行向量,同时准备计算 𝑧 (1), 𝑧 (2) …… 𝑧 (𝑚) 。它可以表达为 𝑤 的转置乘以大写矩阵 𝑥 然后加上向量 [𝑏𝑏. . . 𝑏] ,

\[([𝑧 (1) 𝑧 (2) . . . 𝑧 (𝑚) ] = 𝑤𝑇 + [𝑏𝑏. . . 𝑏]) 。 \]

[𝑏𝑏. . . 𝑏] 是一个 1 × 𝑚 的向量或者 1 × 𝑚 的矩阵或者是一个 𝑚 维的行向量。
𝑤𝑇𝑥 (1) + 𝑏 这是第一个元素,𝑤𝑇𝑥 (2) + 𝑏 这是第二个元素,𝑤𝑇𝑥 (𝑚) + 𝑏 这是第 𝑚 个 元素。

​ 第一个元素恰好是 𝑧 (1) 的定义,第二个元素恰好是 𝑧 (2) 的定义,以此类推。所以当将不同训练样本对应的小写 𝑥 横向堆积在一起时得到大写变量 𝑋 并且将其他小写变量也用相同方法处理,将它们横向堆积起来,最终能得到大写变量 𝑍 。

numpy 命令是:

Z = np.dot(w.T,X) + b

得到 Z 后,使用

𝐴 = [𝑎(1)𝑎(2). . . 𝑎(𝑚)] = 𝜎(𝑍)

一次性计算所有 𝑎 ,完成所有 m 个训练样本的前向传播向量化计算。

2.14 向量化 logistic 回归的梯度输出(Vectorizing Logistic Regression's Gradient)

​ 对 𝑚个 训练数据做同样的运算,可以定义一个新的变量 𝑑𝑍 = [𝑑𝑧 (1) , 𝑑𝑧 (2) . . . 𝑑𝑧 (𝑚) ] ,所有的 𝑑𝑧 变量横向排列,因此,𝑑𝑍 是一个 1 × 𝑚 的矩阵,或者说是一个 𝑚 维行向量。

​ 在上一小节中,已经计算出 A ,即

\[[𝑎 (1) , 𝑎 (2) . . . 𝑎 (𝑚) ] \]

需要找到这样的一个行向量

\[𝑌 = [𝑦 (1),𝑦 (2), . . . 𝑦 (𝑚) ] \]

\[𝑑𝑍 = 𝐴 − 𝑌 = [𝑎 (1) − 𝑦 (1)𝑎 (2) − 𝑦 (2) . . . 𝑎 (𝑚) − 𝑦 (𝑚) ] \]

不难发现第一个元素就是 𝑑𝑧 (1),第二个元素就是 𝑑𝑧 (2) ,以此类推。

得到dZ后,尝试求出其他需要的量。首先求db:

\[db = \frac{1}{m} \sum_{i=1}^{m} z^{(i)} \]

而此时dz已经组成一个行向量dZ了,可以使用

db = 1/m * np.sum(dZ);

同理,

dw = 1/m * X * dZT

就可以避免在训练集上使用for循环。

总结所有向量化表示,可以使用以下代码:

𝑍 = 𝑤𝑇𝑋 + 𝑏 = 𝑛𝑝. 𝑑𝑜𝑡(𝑤.𝑇, 𝑋) + 𝑏
𝐴 = 𝜎(𝑍)
𝑑𝑍 = 𝐴 − 𝑌
𝑑𝑤 = 1/𝑚 ∗ 𝑋 ∗ 𝑑𝑧𝑇
𝑑𝑏 = 1/𝑚 ∗ 𝑛𝑝. 𝑠𝑢𝑚(𝑑𝑍)
𝑤: = 𝑤 − 𝑎 ∗ 𝑑𝑤
𝑏: = 𝑏 − 𝑎 ∗ 𝑑𝑏

​ 利用前五个公式完成了前向和后向传播,也实现了对所有训练样本进行预测和求导,再利用后两个公式,梯度下降更新参数,至此,我们得到了一个高度向量化的、非常高效的逻辑回归的梯度下降算法。

posted @ 2024-01-06 22:57  Exungsh💫  阅读(4)  评论(0编辑  收藏  举报