深度学习笔记10/27——向量化

向量化——When ever possible, avoid explicit for-loops.

        向量化计算意味着你可以在数组上执行操作,而不需要明确地循环遍历其元素,这样可以极大提高效率

        将矩阵或者向量的运算用np这个库去运算要比自己写循环运算快一百倍左右,比如:

import numpy as np
import time

a = np.array([1, 2, 3, 4])

print(a)

b = np.random.rand(1000000)
c = np.random.rand(1000000)

tic = time.time()
d = np.dot(b, c)
toc = time.time()
print(d)
print("vectorized version:" + str(1000 * (toc - tic)) + "ms")

d = 0
tic = time.time()
for i in range(1000000):
    d += c[i] * b[i]
toc = time.time()
print(d)
print("unvectorized version:" + str(1000 * (toc - tic)) + "ms")

这里的输出结果为:
 

可以看到对两个向量点乘得到相同的结果,但是运行时间大有不同。大概的原理是因为numpy能够充分利用CPU和GPU的并行化去完成程序。

相同的用法还有:
        np.exp(v)     np.log(v)      np.abs(v)-绝对值      np.Maxium(v,0)-与0相比求最大值 

        np.transpose() - 转置数组     np.dot() - 计算点积(也用于矩阵乘法)

        所以在上一节中,由于特征数量很多,因此在for循环中需要再嵌套一个for循环来遍历每个特征值的操作就可以简化为:
        用np.zero(n_x,1)将W声明成为一个列向量,然后直接计算

        W_{[i]}=x^{(i)}*dz^{(i)}

逻辑回归的向量化实现

        在逻辑回归中,不同的x[i]会根据sigmoid公式得到不同的a[i]值,从而得到不同的预测结果y[i].  这些不同的x[i]可以表示为多个列向量,因此可以用一个m行i列的矩阵X_{i*m}来表示. 

        所以基于此,在最开始计算sigmoid函数的指数项Z^{(i)}时可以将结果表示为一个行向量Z_{1*m},用来保存每次计算的Z^{(n)}值(实际上每次计算的Z^{(n)}值都是一个列向量). 因此,原先计算Z^{(i)}的公式可以表示为
                                                Z_{1*m}=W^T*X+[b,b,b,...b]

在python里,可以用

Z=np.dot(W^T*X)+b

来表示,这里的b可以是一个实数,在运算中python会自动的将其变为向量,也就是broadcasting.

在反向传播中也如此,定义一个1*m的矩阵

Z_{1*m}=A-Y

用来保存dZ^{(1)},dZ^{(2)},dZ^{(3)}....然后有

dW = \frac{1}{m}XdZ^T

db = \frac{1}{m}\sum_{i=1}^{m}dz^{(i)}

db=(1/m)np.sum(dZ)
dW=(1/m)Xdz^T

总的向量化的反向传播的步骤为:

Python中的广播(Broadcasting)

前提:

  1. 两个数组在该维度的大小相同。
  2. 其中一个数组在该维度的大小为1.

作用:将做形式上不可运算的矩阵自动填充为可以运算的形式并计算,比如一个2*3的矩阵加上一个2*1的矩阵,在广播之后python会自动地将后者填充为2*3的矩阵(复制第一列到后两列).

以下是例子:

import numpy as np
import time

A = np.array([[56.0, 0.0, 4.4, 68.0],
              [1.2, 104.0, 52.0, 8.0],
              [1.8, 135.0, 99.0, 0.9]])

A_T = np.transpose(A)

cal = A.sum(axis=0)
percentage = A / cal.reshape(1, 4)
# print(percentage)
"""由于 NumPy 的广播特性,无论你是否显式地使用 .reshape(1,4),cal 都会被广播到与 A 
相同的形状,所以在这种情况下,加不加 .reshape(1,4) 都不会影响结果。"""

A = np.array([[0, 1, 0, 1], [1, 0, 1, 0]])
B = np.zeros((4, 4))
print(B)
arr = A
A = np.vstack((arr, arr))  # 垂直堆叠,参数表示怎样堆叠
C = A + B
print(C)

向量的注释

        在使用np表示向量的过程过程中,如果我们使用一个数组来表示向量的话就会出现以下问题:

import numpy as np

a = np.random.rand(5)
print(a)
print(a.shape)
a_T = np.transpose(a)
print(a_T)

        会发现数组经过转置之后仍然没有变化,而且没有报错.  这是因为在python中,一个一维数组被视为一个向量(在这里(5, )表示这个数组有5个元素,但是什么向量都不是),但是没有确定到底是一个行向量还是一个列向量,所以自然就不存在转置,但是没有报错提示就可能会导致一些隐藏的bug出现,因此我们在创建随机向量时一般使用

np.random.rand(5,1)

来创建一个指定维数的确定的向量,如果不确定向量的形式,可以用

assert a.shape == (m,n)

来检查向量的形式

扩展:

数组的秩 (Tensor Rank):在 NumPy 中,数组的“秩”指的是数组的维度数。例如,对于一个形状为 (5,) 的一维数组,其秩为1。对于一个形状为 (5, 3) 的二维数组,其秩为2。对于一个形状为 (4, 3, 2) 的三维数组,其秩为3。以此类推。

使用 numpy.ndim 可以获得数组的秩

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Zack Wesson

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

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

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

打赏作者

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

抵扣说明:

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

余额充值