深度学习笔记_Week2

发布时间 2024-01-06 23:01:44作者: Exungsh?

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/? ∗ ??. ???(??)
?: = ? − ? ∗ ??
?: = ? − ? ∗ ??

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