概述

本篇属于理论篇,你将了解什么是向量化、向量化对神经网络训练优化的重要性,以及如何向量化 Logistic 回归及其梯度输出。


转自猴开发博客:深度学习(二)向量化 Logistic 回归及其梯度输出

2.0 向量化概述

在前面,你已经认识了 Logistic 回归,并且对梯度下降以及梯度下降是如何工作的有了一个具体的认知。如果你有认真阅读第一篇的话,相信你还记得在第一篇中曾经提到过一个矩阵 XXX,它表示将所有的输入样本在水平方向上堆叠起来,也就是下面这个样子:

为了在后面方便说明,这里将每一个输入样本的下标也标示出来,这样你将看到公式(1)更加完整的形式:

为了确保你明白公式(2)中每一个角标的含义,在这里特别说明一下,使用小括号括起来的上标表示的是样本的编号,而没有用括号括起来的下标代表的是样本的某一个输入,例如对于符号 xnx(2)x^{(2)}_{n_x}xnx​(2)​,它所代表的是训练集中第2个训练样本的第 nxn_xnx​ 个输入,因为 nxn_xnx​ 是指输入的总个数,所以 xnx(2)x^{(2)}_{n_x}xnx​(2)​ 表示的就是第2个训练样本的最后一个输入。

将原本独立的一个个样本组合在一起,构成一个新的矩阵,其实这就是向量化。你可能要问,在上篇中已经实现了 Logistic 回归,使用 xxx 表示单个样本,在对所有样本逐个计算就足够了,为什么还要使用向量化引入一个样本矩阵 XXX?

2.1 非向量化与向量化实例

试想,如果给你一个给你 1000000 个数据 a1a_1a1​~a1000000a_{1000000}a1000000​,以及 1000000 个数据 b1b_1b1​~b1000000b_{1000000}b1000000​,要你求每一对 aia_iai​ 和 bib_ibi​ 相乘的结果的总和ccc,你会怎么做?

在接触向量化之前,你应该会想到使用 for 循环,将 aia_iai​ 与 bib_ibi​ 的乘积依次相加,就可以得到结果 ccc 了,我们来试一下。

使用 for 循环

import numpy as np
import time as t# 生成 1000000 随机数据
a = np.random.rand(1000000)
b = np.random.rand(1000000)# for 循环版本
c = 0# 开始计时
startTime = t.time()# 循环计算
for i in range(1000000):c += a[i]*b[i]# 停止计时
deltaTime = t.time() - startTime# 输出结果与耗时情况
print("计算结果:" + str(c) + ", for 循环计算耗时:" + str(1000 * deltaTime) + "ms")

以上是使用 for 循环完成要求计算的 python 代码,输出结果是:

计算结果:249879.05298545936, for 循环计算耗时:519.999980927ms

使用向量化

# 向量化版本
c = 0# 开始计时
startTime = t.time()#矩阵计算
c = np.dot(a,b)# 停止计时
deltaTime = t.time() - startTime# 输出结果与耗时情况
print("计算结果:" + str(c) + ", 矩阵计算耗时:" + str(1000 * deltaTime) + "ms")

以上是使用向量化完成要求计算的 python 代码,输出结果是:

计算结果:249879.05298545936, 矩阵计算耗时:0.999927520752ms

进行多次计算,可以绘制出 for 循环与向量化计算的耗时对比图:

图 1-1 for 循环与向量化计算耗时对比

实在是令人惊喜,正如你所看到的,向量化版本没有使用 for 循环就正确完成了所有计算,并且计算的代码量只有一行,而仅针对简单的乘法与加法运算而言,向量化计算的效率就要比 for 循环高出 500 倍上下,在其他更加复杂的运算下,这个差距还会拉得更大。可以看到,无论从简洁性还是从效率的角度讲,向量化计算几乎是完美的。

因此,不管是在什么算法当中,如果能够不使用 for 循环就尽量不要使用 for 循环,其效率实在是太糟糕了。在神经网络的训练过程中,效率显得尤为重要,面对数量巨大的训练样本,向量化你的模型是非常有必要的,它能够大量地节约你的时间去做更多的训练,或是做参数的调整。

2.2 向量化 Logistic 回归

在前面你已经见识到了向量化威力,通过向量化你能够实现数据的并发计算,进而为你节约大量的时间。下面,我将用伪代码给出 Logistic 回归非向量化版本,即使用 for 循环编码实现上一篇当中的理论模型,你可以直接阅读代码,并思考如何向量化这个过程。

for 循环版本

1  | forforfor iii === 111 tototo mmm

2  | {\{{

3  |         z(i)z^{(i)}z(i) === wTx(i)w^Tx^{(i)}wTx(i) +++ bbb # 计算线性输出

4  |         a(i)a^{(i)}a(i) === σ(z(i))\sigma(z^{(i)})σ(z(i)) # 映射到 [0,1][0,1][0,1]

5  |         JJJ +=+=+= L(a(i),y(i))L(a^{(i)},y^{(i)})L(a(i),y(i)) # 记录 Loss Function 的累加

6  |         dz(i)dz^{(i)}dz(i) === a(i)−y(i)a^{(i)}-y^{(i)}a(i)−y(i) # 计算 ∂L(a,y)∂adσ(z)dz\frac{\partial L(a,y)}{\partial a} \frac{d\sigma(z)}{dz}∂a∂L(a,y)​dzdσ(z)​ (前两段"链条"的乘积)

7  |         forforfor jjj === 111 tototo nxn_xnx​

8  |                dwjdw_jdwj​ +=+=+= xj(i)dzx^{(i)}_jdzxj(i)​dz # 累加 dwdwdw

9  |         dbdbdb +=+=+= dzdzdz # 累加 dbdbdb

10 | }\}}

11 | forforfor jjj === 111 tototo nxn_xnx​

12 |         dwjdw_jdwj​ === dwj/mdw_j/mdwj​/m # 计算每个输入的 dwdwdw

13 | dbdbdb = db/mdb/mdb/m # 计算 dbdbdb

14 | JJJ = J/mJ/mJ/m # 计算 CostFunctionCost FunctionCostFunction


可以看到,在这段代码中出现了三个 for 循环,甚至出现了循环嵌套,这对算法效率的影响是很大的。如果你试着读上面的代码并结合注释,能够理解每一行代码在做些什么的话最好了。如果你觉得以你目前的思维将模型投射到代码还是有些困难也没有关系,我们来逐行解读代码,并一步步地将其向量化。

在这里,向量化的过程其实就是消除 for 循环的过程,我们从最里层的 for 循环开始。你看到了,最里层的 for 循环也就是 7 到 8 行,在 11 到 12 行也有一个小小的 for 循环,我们先从 7 到 8 行的 for 循环开始。

7  | forforfor jjj === 111 tototo nxn_xnx​

8  |         dwjdw_jdwj​ +=+=+= xj(i)dzx^{(i)}_jdzxj(i)​dz # 累加 dwdwdw

如果你还是觉得这个通式太抽象地话,我们可以将这个 for 循环一条条详细地列出来:

dw1+=x1(i)dzdw_1 += x^{(i)}_1dz dw1​+=x1(i)​dz

dw2+=x2(i)dzdw_2 += x^{(i)}_2dz dw2​+=x2(i)​dz

⋮\vdots ⋮

dwnx+=xnx(i)dzdw_{n_x} += x^{(i)}_{n_x}dz dwnx​​+=xnx​(i)​dz

仔细看一看,你有没有发现向量化的影子?

图 1-1 for 循环展开

这简直就是天然的矩阵形式!我们只需将等式左侧的所有 dw...dw_{...}dw...​ 封装进一个列矩阵 dwdwdw 即可,等式的右侧也是同理,所有的 x...(i)x^{(i)}_{...}x...(i)​ 可以封装进一个列矩阵 x(i)x^{(i)}x(i),即:

这时你会惊喜地发现,整个循环操作直接被简化成为了一行极其简短的矩阵运算!

dw+=x(i)dzdw += x^{(i)}dz dw+=x(i)dz

至此,我们已经迈出了向量化的第一步,成功消除了代码中的一个 for 循环。下面我们继续看一看第二个即代码中 11 到 12 行的 for 循环。使用同样的方法,如果将其展开的话,你会发现这个 for 循环其实在做如下的重复性劳动:

dw1=dw1/mdw_1 = dw_1/m dw1​=dw1​/m

dw2=dw2/mdw_2 = dw_2/m dw2​=dw2​/m

⋮\vdots ⋮

dwnx=dwnx/mdw_{n_x} = dw_{n_x}/m dwnx​​=dwnx​​/m

我相信这一次你已经可以一眼看出如何将其向量化了,你会发现这个过程其实真的很简单,只需要将等式左侧的循环变量封装进一个列矩阵 dw=[dw1,dw2,⋯ ,dwnx]Tdw = [dw_1,dw_2,\cdots,dw_{n_x}]^Tdw=[dw1​,dw2​,⋯,dwnx​​]T,这个循环就被简化成为了下面一行代码:

dw=dw/mdw = dw/m dw=dw/m

不知道你发现没有,到现在为止,我们已经完成了所有输入的向量化,我们没有使用一个 for 循环就处理了所有输入系数 www 的 dwdwdw 计算,如果你觉得自己对 for 循环向量化的过程已经有所领会的话,建议你到此停下来,自己尝试将第一层也是最大的一层 for 循环也完成向量化,如果你能做到的话,你就实现了不使用一个 for 循环并一口气完成所有样本的训练。


下面我们来看最外一层的样本循环,首先第一条是线性组合的计算:

3  | z(i)z^{(i)}z(i) === wTx(i)w^Tx^{(i)}wTx(i) +++ bbb

先等一下,你可能会像之前一样将循环展开来看一看,之后得到封装的矩阵,最后用矩阵去替换原来的整列。但是其实你会发现你需要做的仅仅是将所有的循环变量替换掉,而不需要每一次都展开来看了。就比如上面这个第 3 行代码,它的循环变量是 z(i)z^{(i)}z(i) 与 x(i)x^{(i)}x(i),识别的方法就是它们带有这一层循环的变量 iii,将其直接替换为 ZZZ 与 XXX,你就得到了最终结果:

Z=wTX+bZ = w^TX + b Z=wTX+b

你只需要在心里记得与明白, ZZZ 和 XXX 是循环产生的列就好(公式(7)),也就是 图1-1 那样的形式,那是它的由来,但在实际向量化的过程中,你并不需每次都像那样展开一下再去替换,只要你对这个过程明了,那么直接写出结果就行了。

同理,第 4、5、6 行的向量形式应该分别是公式(8)(9)(10)所示:

其中:

至此,整个 for 循环版本都被我们向量化了,下面你看到的就是 Logistic 回归及其梯度输出的向量化版本:

向量化版本

1  | ZZZ = wTXw^TXwTX +++ bbb

2  | AAA = σ(Z)\sigma(Z)σ(Z)

3  | JJJ = −(1/m)(YlogA-(1/m)(YlogA−(1/m)(YlogA +++ (1−Y)log(1−A))(1-Y)log(1-A))(1−Y)log(1−A))

4  | dZdZdZ = AAA −-− YYY

5  | dwdwdw = (1/m)XdZT(1/m)XdZ^T(1/m)XdZT

6  | dbdbdb = (1/m)dZT(1/m)dZ^T(1/m)dZT

甚至,由于你在写代码的过程中并不需要将中间量写出来,因此你可以得到下面这个更简的版本:

1  | AAA = σ(wTX\sigma(w^TXσ(wTX +++ b)b)b)

2  | JJJ = −(1/m)(YlogA-(1/m)(YlogA−(1/m)(YlogA +++ (1−Y)log(1−A))(1-Y)log(1-A))(1−Y)log(1−A))

3  | dwdwdw = (1/m)X(A(1/m)X(A(1/m)X(A −-− Y)TY)^TY)T

4  | dbdbdb = (1/m)(A(1/m)(A(1/m)(A −-− Y)TY)^TY)T

你没看错,只有短短的四行!并且这四行精简的代码是一次性并行完成整个数据集上所有样本的训练!现在你可以想象,假如没有经过向量化操作,直接用嵌套的 for 循环去训练基数庞大的海量数据,不仅代码繁杂,效率上更将是多么可怕的一件事。向量化技术极大的提升了神经网络的训练的效率,也正因如此,向量化才在神经网络与深度学习当中具有重要的意义。

2.3 本篇小结

向量化的意义:实现循环操作的并行化。

向量化后的 Logistic 回归模型及其梯度输出:

A=σ(wTX+b)A = \sigma(w^TX + b)A=σ(wTX+b)
J=−1m(YlogA+(1−Y)log(1−A))J = -\frac{1}{m}(YlogA + (1-Y)log(1-A))J=−m1​(YlogA+(1−Y)log(1−A))
dw=1mX(A−Y)Tdw = \frac{1}{m}X(A - Y)^Tdw=m1​X(A−Y)T
db=1m(A−Y)Tdb = \frac{1}{m}(A - Y)^Tdb=m1​(A−Y)T


经过向量化后的 Logistic 回归,并没有使用一个 for 循环,我们只用四行极简的代码,抽象了上一篇中上万字的复杂过程,我想你也不得不为向量化与矩阵运算的强大而感慨了。

至此,你已经完成了向量化的理论部分学习,在下一篇里,你将在实战中看到向量化 Logistic 回归及其梯度输出的落地实现,即猫图的识别。你将看到单层神经网络的模块化开发与如何一步步编写代码,动手搭建一个自己的神经网络,并使它完整的工作起来。

在进入下一篇之前,你可以试着先思考以下几个问题,这些是本篇当中的核心内容:

  1. 在第一篇中已经建立了 Logistic 回归模型,还有必要做向量化工作吗?(有必要)
  2. 向量化后的 Logistic 回归能够一次性完成所有样本的一次训练,并完成参数的一次迭代,正确或错误?(正确)
  3. 下面是向量化版本的 Logistic 回归与梯度输出,其中哪几行实现的是向前传播?哪几行实现的是向后传播?(向前1、2行;向后3、4行)
     1  | AAA = σ(wTX\sigma(w^TXσ(wTX +++ b)b)b)
     2  | JJJ = −(1/m)(YlogA-(1/m)(YlogA−(1/m)(YlogA +++ (1−Y)log(1−A))(1-Y)log(1-A))(1−Y)log(1−A))
     3  | dwdwdw = (1/m)X(A(1/m)X(A(1/m)X(A −-− Y)TY)^TY)T
     4  | dbdbdb = (1/m)(A(1/m)(A(1/m)(A −-− Y)TY)^TY)T
  4. 试用向量化技术将下面代码简化成一行,其中 Fun(a,b)=a+bFun(a,b) = a + bFun(a,b)=a+b,kik_iki​ 与 μi\mu_iμi​ 是维度相同的矩阵(var=(1/n)(k+μ)var=(1/n)(k+\mu)var=(1/n)(k+μ))
     1  |forforfor iii === 111 tototo nnn
     2  |        varivar_ivari​ +=+=+= Fun(ki,μi)Fun(k_i,\mu_i)Fun(ki​,μi​)
     3  |forforfor iii === 111 tototo nnn
     4  |        varivar_ivari​ === vari/nvar_i/nvari​/n

使用鼠标选中括号内容以查看答案。

深度学习(二)向量化 Logistic 回归及其梯度输出相关推荐

  1. 2.14 向量化 Logistic 回归的梯度输出-深度学习-Stanford吴恩达教授

    ←上一篇 ↓↑ 下一篇→ 2.13 向量化 Logistic 回归 回到目录 2.15 Python 中的广播 向量化 Logistic 回归的梯度输出 (Vectorizing Logistic R ...

  2. 2.14 向量化 logistic 回归的梯度输出

  3. 吴恩达深度学习第二周--logistic回归作业1

    吴恩达深度学习第二周–logistic回归作业1 本系列为吴恩达老师深度学习作业的总结,其中参考了很多优秀的文章,本文为了方便日后的复习与巩固,更为详细的作业讲解参考 目录 吴恩达深度学习第二周--l ...

  4. 吴恩达深度学习 —— 2.14 向量化逻辑回归的梯度输出

    这一节将学习如果向量化计算m个训练数据的梯度,强调一下,是同时计算. 前面已经说过,在逻辑回归中,有dz(1)=a(1)−y(1)dz^{(1)}=a^{(1)}-y^{(1)}dz(1)=a(1)− ...

  5. 吴恩达深度学习——2.3 logistic回归损失函数

    为了训练logistic回归模型的参数w和b,需要定义一个成本函数,让我们来看一下,用logistic回归来训练的成本函数,回忆一下,这是上一张幻灯片的函数,所以你的输出y^=sigmoid(wTx+ ...

  6. 吴恩达深度学习——2.2 Logistic回归

    logistic回归是一个学习算法,用在监督学习问题中,输出y标签是0或1时,这是一个二元分类问题. 已知输入的特征向量x可能是一张图,你希望能识别出这是不是猫图,你需要一个算法,可以给出一个预测值, ...

  7. 2.13 向量化 Logistic 回归-深度学习-Stanford吴恩达教授

    ←上一篇 ↓↑ 下一篇→ 2.12 向量化的更多例子 回到目录 2.14 向量化 Logistic 回归的梯度输出 向量化 Logistic 回归 (Vectorizing Logistic Regr ...

  8. 2.9 Logistic 回归的梯度下降法-深度学习-Stanford吴恩达教授

    ←上一篇 ↓↑ 下一篇→ 2.8 计算图的导数计算 回到目录 2.10 m 个样本的梯度下降 Logistic 回归的梯度下降法 (Logistic Regression Gradient Desce ...

  9. 深度学习 实验三 logistic回归预测二分类

    文章目录 深度学习 实验三 logistic回归预测二分类 一.问题描述 二.设计简要描述 三.程序清单 深度学习 实验三 logistic回归预测二分类 一.问题描述   学会使用学习到的逻辑回归的 ...

最新文章

  1. 轻松创建Silverlight 4开发环境
  2. IIS 7.5 配置伪静态方法
  3. 第二十篇:定义一个整形变量
  4. 【每周CV论文推荐】换脸算法都有哪些经典的思路?
  5. pytorch 之 分开安装 torch 和 torchvision
  6. 【LeetCode】深搜DFS(共85题)
  7. TFT_LCD液晶屏驱动设计与验证
  8. python实现二分法查找_python二分法查找
  9. centos7进入单用户模式
  10. linux-tomcat连接数查询
  11. Java Web文件下载
  12. 7.1.Zeng_Cache(2) --- 缓存原理
  13. 【车辆分类】基于matlab的视频中车辆跟踪监测分类算法仿真,包括背景差分与帧间差分以及形态学处理
  14. office韩文版本
  15. 2018.12.26 Jquery 使用 slideBox 实现滚动 效果
  16. Noi 十连测 Zbox loves meizi
  17. Roboastere 地盘功率限制(大方向)(RM论坛同步更新,同ID,头像)
  18. 主流深度学习CTR模型
  19. 京东云引擎:免费好用的web应用托管平台
  20. 华为员工自曝百万级年终奖,论坛征女友!

热门文章

  1. 《计算机网络自顶向下方法》笔记
  2. 子网怎么算?IP地址(A,B,C,D,E类地址),子网,子网掩码,容纳主机20台,网络号,主机号
  3. 分拆计划陷入困境,英特尔还能重回巅峰吗?
  4. 可燃气体传感器在智慧消防中的应用
  5. 视频发微信文件过大怎么办大于200m视频发送微信?
  6. Eclipse平台技术概述
  7. 一文搞懂,PO设计模式详解
  8. 英特尔® 快速存储技术
  9. Golang数组练习题:已知有一个排序好的升序数组,要求插入一个元素,最后打印该数组,顺序依然是升序
  10. 获取联想锁屏壁纸(超简单两个方法)