机器学习第十九周周报

摘要

本周学习了向量化,向量化能使代码更短,也能使其运行更有效。还允许使用现代数值线性代数库,甚至可能使用GPU加速执行代码。

Abstract

This week I learned about vectorization, which makes the code shorter and makes it run more efficiently. It also allows the use of modern numeric linear algebraic libraries, and may even use GPU to accelerate code execution.

一、向量化

向量化是非常基础的去除代码中for循环的艺术,在深度学习安全领域、深度学习实践中,会经常发现自己训练大数据集,因为深度学习算法处理大数据集效果很棒,所以代码运行速度非常重要,否则如果在大数据集上,代码可能花费很长时间去运行,将要等待非常长的时间去得到结果。所以在深度学习领域,运行向量化是一个关键的技巧,让我们举个例子说明什么是向量化。
使用非向量化方法去计算wTx:

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

这是一个非向量化的实现,你会发现这真的很慢,作为一个对比,向量化实现将会非常直接计算wTx:

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个小时去运行。
一句话总结,以上都是再说和for循环相比,向量化可以快速得到结果。

二、向量化的更多例子

当我们在写神经网络程序时,或者在写逻辑回归,或者其他神经网络模型时,应该避免写循环语句。虽然有时写循环是不可避免的,但是我们可以使用比如numpy的内置函数或者其他办法去计算。当你这样使用后,程序效率总是快于循环。
如果你想计算向量u=Av,这时矩阵乘法定义为,矩阵乘法的定义就是:ui=Aijvi,这取决于你怎么定义ui值。同样使用非向量化实现,u=np.zeros(n,1), 并且通过两层循环for(i),for(j),得到u[i]=u[i]+A[i][j]*v[j]。现在就有了i和j 的两层循环,这就是非向量化。向量化方式就可以用u=np.dot(A,v),右边这种向量化实现方式,消除了两层循环使得代码运行速度更快。
在这里插入图片描述
下面通过另一个例子继续了解向量化。如果你已经有一个向量,并且想要对向量的每个元素做指数操作,得到向量e等于e的v1,e的v2,一直到e的vn次方。这里是非向量化的实现方式,首先你初始化了向量u=np.zeros(n,1),并且通过循环依次计算每个元素。但事实证明可以通过python的numpy内置函数,帮助你计算这样的单个函数。所以我会引入import numpy as np,执行u=np.exp(v)命令。注意到,在之前有循环的代码中,这里仅用了一行代码,向量v作为输入,u作为输出。你已经知道为什么需要循环,并且通过右边代码实现,效率会明显的快于循环方式。
事实上,numpy库有很多向量函数。比如 u=np.log是计算对数函数(log)、 np.abs() 是计算数据的绝对值、np.maximum() 计算元素中的最大值,你也可以 np.maximum(v,0) 、 v**2代表获得元素 y每个值得平方、 1/v获取元素y的倒数等等。所以当你想写循环时候,检查numpy是否存在类似的内置函数,从而避免使用循环(loop)方式。
在这里插入图片描述
那么,将刚才所学到的内容,运用在逻辑回归的梯度下降上,看看我们是否能简化两个计算过程中的某一步。这是我们逻辑回归的求导代码,有两层循环。在这例子我们有n个特征值。如果你有超过两个特征时,需要循环dw1、dw2 、dw3 等等。所以 j的实际值是1、2 和nx ,就是你想要更新的值。所以我们想要消除第二循环,在这一行,这样我们就不用初始化 dw1 ,dw2 都等于0。去掉这些,而是定义dw 为一个向量u=np.zeros(n(x),1),设置 。定义了一个x行的一维向量,从而替代循环。我们仅仅使用了一个向量操作dw=dw+x(i)dz(i) 。最后,我们得到dw=dw/m 。现在我们通过将两层循环转成一层循环,我们仍然还有这个循环训练样本。
在这里插入图片描述
在这里插入图片描述

三、向量化 logistic 回归的梯度输出

在这里插入图片描述
如果你参照上面的定义,第一个元素恰好是z1的定义,第二个元素恰好是z2的定义,等等。所以,因为X是一次获得的,当你得到你的训练样本,一个一个横向堆积起来,结果发现,为了计算WTX+[bb…b] ,numpy命令是Z=np.dot(w.T,X)+b。这里在Python中有一个巧妙的地方,这里b是一个实数,或者你可以说是一个11 矩阵,只是一个普通的实数。但是当你将这个向量加上这个实数时,Python自动把这个实数 b 扩展成一个 1m 的行向量。所以这种情况下的操作似乎有点不可思议,它在Python中被称作广播。
在这里插入图片描述
在这里插入图片描述
现在我们利用前五个公式完成了前向和后向传播,也实现了对所有训练样本进行预测和求导,再利用后两个公式,梯度下降更新参数。我们的目的是不使用for循环,所以我们就通过一次迭代实现一次梯度下降,但如果你希望多次迭代进行梯度下降,那么仍然需要for循环,放在最外层。不过我们还是觉得一次迭代就进行一次梯度下降,避免使用任何循环比较舒服一些。

四、Python 中的广播

在这里插入图片描述
这是一个不同食物(每100g)中不同营养成分的卡路里含量表格,表格为3行4列,列表示不同的食物种类,从左至右依次为苹果,牛肉,鸡蛋,土豆。行表示不同的营养成分,从上到下依次为碳水化合物,蛋白质,脂肪。
那么,我们现在想要计算不同食物中不同营养成分中的卡路里百分比。
现在计算苹果中的碳水化合物卡路里百分比含量,首先计算苹果(100g)中三种营养成分卡路里总和56+1.2+1.8 = 59,然后用56/59 = 94.9%算出结果。
可以看出苹果中的卡路里大部分来自于碳水化合物,而牛肉则不同。
对于其他食物,计算方法类似。首先,按列求和,计算每种食物中(100g)三种营养成分总和,然后分别用不用营养成分的卡路里数量除以总和,计算百分比。
那么,能否不使用for循环完成这样的一个计算过程呢?
假设上图的表格是一个4行3列的矩阵A,记为A34 ,接下来我们要使用Python的numpy库完成这样的计算。我们打算使用两行代码完成,第一行代码对每一列进行求和,第二行代码分别计算每种食物每种营养成分的百分比。
在这里插入图片描述
下面使用如下代码计算每列的和,可以看到输出是每种食物(100g)的卡路里总和。
在这里插入图片描述
接下来计算百分比,这条指令将 3
4的矩阵A除以一个14的矩阵,得到了一个34的结果矩阵,这个结果矩阵就是我们要求的百分比含量。
在这里插入图片描述
下面再来解释一下A.sum(axis = 0)中的参数axis。axis用来指明将要进行的运算是沿着哪个轴执行,在numpy中,0轴是垂直的,也就是列,而1轴是水平的,也就是行。

五、总结

本周学习了向量化以及python中的广播相关知识,下周将继续学习python中的广播以及后续内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值