C1 - week2 - part6 向量化 Vectorization

week2-part6 向量化(Vectorization)

在深度学历领域,你会经常发现自己要训练相当大的数据集,因为深度学习算法处理大数据集效果很好,所以你的代码运行速度非常重要,否则你的代码在大数据集上可能需要花费相当长的时间去运行。在深度学习领域,向量化是一个关键技巧。

一、向量化

在逻辑回归中你需要去计算 z = w t x + b z = w^tx + b z=wtx+b w 、 x w、x wx都是列向量,如果你的数据有很多特征,那么就会有一个非常大的向量。其中,$w \in \mathbb{R}^{n_x}, x \in \mathbb{R}^{n_x} , 如 果 你 想 用 非 向 量 化 方 法 去 计 算 ,如果你想用非向量化方法去计算 w^tx$,你需要代码如下

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

这是一个非向量化的实现,你会发现这真的很慢,作为一个对比,向量化实现会非常直接快速地计算 w t x w^tx wtx,代码如下

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

让我们用一个小例子展示一下效率的对比:

import time
# 随机得到两个一百万维度的数组
a = np.random.rand(1000000)
b = np.random.rand(1000000) 

tic = time.time()
c   = np.dot(a, b)
toc = time.time()

print(c)
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')

运行结果如下:

250286.989866
Vectorized version:1.5027523040771483ms
250286.989866
For loop:474.29513931274414ms

在两个方法中,计算得到了相同的值,但时间却相差约300倍。

让我们来看另外一个例子,如果你想计算向量 u = A v u = Av u=Av,根据矩阵乘法定义:$u_{i} = \sum_{j} A_{i j} v_i $。我们用非向量化方法实现,需要通过两层循环for(i):for(j),得到u[i] = u[i] + A[i][j] * v[j]。而向量化方法就可以用u = np.dot(A, v),向量化实现方法消除了两层循环使得代码运行速度更快。

如果你已经有了一个向量 v v v,并想要对其每个元素做指数操作,得到向量 u u u等于 e e e v 1 v_1 v1,e的 v 2 v_2 v2,一直到 e e e v n v_n vn次方。我们可以通过循环一次计算每个元素,但若使用向量化技巧,我们仅需要一个内置函数u = np.exp(v)。事实上,numpy库有很多向量函数,当你想要写循环的时候,可以去查找一下numpy是否存在类似的内置函数,从而避免使用循环方式。

二、向量化逻辑回归

首先我们回顾一下逻辑回归的前向传播步骤,假设有 m m m个训练样本。我们对第一个样本进行预测,先计算 z ( 1 ) = w t x ( 1 ) + b z^{(1)} = w^{t}x^{(1)} + b z(1)=wtx(1)+b,然后计算激活函数 a ( 1 ) = σ ( z ( 1 ) ) a^{(1)} = \sigma(z^{(1)}) a(1)=σ(z(1)),计算第一个样本的预测值 y y y

对第二个样本进行预测, z ( 2 ) = w t x ( 2 ) + b z^{(2)} = w^{t}x^{(2)} + b z(2)=wtx(2)+b a ( 2 ) = σ ( z ( 2 ) ) a^{(2)} = \sigma(z^{(2)}) a(2)=σ(z(2))

对第三个样本进行预测, z ( 3 ) = w t x ( 3 ) + b z^{(3)} = w^{t}x^{(3)} + b z(3)=wtx(3)+b a ( 3 ) = σ ( z ( 3 ) ) a^{(3)} = \sigma(z^{(3)}) a(3)=σ(z(3))。以此类推

现在我们有 m m m个训练样本,我们可能需要一个for循环来对 m m m个样本完成前向传播。但如果我们合理使用向量化,我们可以不需要一个明确的for循环。

​ 回忆一下,我们曾经定义了一个矩阵 X X X作为我们的训练输入,将所有的训练集作为不同的列堆积在一起,我们将其写成Python numpy的形式 ( n x , m ) (n_{x}, m) (nx,m),这表示 X X X是一个 n x n_{x} nx乘以 m m m的矩阵。

X = [ ⋮ ⋮ ⋯ ⋮ x ( 1 ) x ( 2 ) ⋯ x ( m ) ⋮ ⋮ ⋯ ⋮ ] X=\left[\begin{array}{cccc} \vdots & \vdots & \cdots & \vdots \\ x^{(1)} & x^{(2)} & \cdots & x^{(m)} \\ \vdots & \vdots & \cdots & \vdots \end{array}\right] X=x(1)x(2)x(m)

我们构建一个 1 × m 1 \times m 1×m的矩阵,实际上也是一个行向量,同时我们准备计算 z ( 1 ) , z ( 2 ) , ⋯ z ( m ) z^{(1)}, z^{(2)}, \cdots z^{(m)} z(1),z(2),z(m)。根据矩阵运算的知识,我们知道它可以表示为 w w w的转置乘以 X X X然后加上向量 [ b , b , b ] [b, b, b] [b,b,b],即 [ z ( 1 ) z ( 2 ) ⋯ z ( m ) ] = w T X + [ b b . . . b ] [z^{(1)} z^{(2)} \cdots z^{(m)}] = w^{T}X + [bb...b] [z(1)z(2)z(m)]=wTX+[bb...b]。我们将 [ z ( 1 ) z ( 2 ) ⋯ z ( m ) ] [z^{(1)} z^{(2)} \cdots z^{(m)}] [z(1)z(2)z(m)]定义为大写的 Z Z Z,不需要for循环,我们只需要一行代码就可以一次性计算出 z z z

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

同理,和前面的np.exp(v)相似,我们通过恰当运用 σ \sigma σ也可以一次性计算所有的 a a a。这里,你可能会对代码中的+ b有所疑惑,为什么可以将实数与数组直接相加,这就涉及到了python中的广播机制,我们会在后续详细介绍。

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

在之前介绍梯度计算的时候,列举过几个例子 d z ( 1 ) = a ( 1 ) − y ( 1 ) ,   d z ( 2 ) = a ( 2 ) − y ( 2 ) ⋯ d z^{(1)} = a^{(1)} - y^{(1)},\ d z^{(2)} = a^{(2)} - y^{(2)} \cdots dz(1)=a(1)y(1), dz(2)=a(2)y(2)等一系列类似公式。现在,对 m m m个训练数据做同样的计算,我们可以类似地定义一个 d Z = [ d z ( 1 ) , d z ( 2 ) , ⋯   , d z ( m ) ] d Z = [d z^{(1)}, d z^{(2)}, \cdots, d z^{(m)}] dZ=[dz(1),dz(2),,dz(m)],所有 d z dz dz变量横向排列, d Z d Z dZ是一个 1 × m 1 \times m 1×m 的矩阵。

在之前的实现中,我们已经去掉了一个for循环,但我们仍有一个遍历训练集的循环,如下所示

dw = 0 
dw += x1 * dz1 
dw += x2 * dz2 
...
dw += xm * dzm 
dw = dw / m 
db = 0 
db += dz1 
db += dz2 
... 
db += dzm 
db = db / m

上述伪代码就是我们在之前实现做的,我们已经去掉了一个for循环,但用上述方法计算 d w dw dw d b db db仍需要一个循环遍历训练集,现在我们要做的就是将其向量化!

首先我们来看 d b db db,不难发现 d b = 1 m ∑ i = 1 m d z ( i ) db = \frac{1}{m}\sum_{i = 1}^{m}d z^{(i)} db=m1i=1mdz(i),我们在之前将所有的 d z ( i ) dz^{(i)} dz(i)已经组成了一个行向量 d Z dZ dZ,所以在Python中,我们可以简单地使用db = 1 / m * mp.sum(dZ);同理,dw = 1 / m * X * dz.T。这样,我们就避免了在训练集上使用for循环。

现在,让我们可以用向量化代码来替代之前的循环式代码

Z = np.dot(w.T, X) + b
A = sigmoid(Z)
dZ = A - Y
dw = 1 / m * X * dz.T
db = 1 / m * np.sum(dZ)
w := w - a * dw
b := b - a * db

现在,我们没有任何一个for循环完成了前向和后向传播,也实现了对所有训练样本进行预测和求导,并使用梯度下降更新参数。但如果你希望多次迭代进行梯度下降,你仍然需要for循环放在最外层。


最后,我们得到了一个高度向量化、非常高效的逻辑回归的梯度下降算法,我们将在下一节介绍Python中的Broadcasting技术。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Doris和ClickHouse是两个流行的开源分布式列式存储数据库,它们都支持向量化Vectorization)技术。向量化是一种优化技术,通过处理数据的向量(数组)而不是单个元素,以提高查询和计算的效率。 在传统的处理方式中,数据库系统通常会逐个处理数据,即逐行或逐列进行操作。而向量化技术则将一组数据(向量)作为单个单元进行处理,以实现更高的并行度和更好的硬件资源利用率。以下是向量化的一些关键概念和特点: 1. 批处理:向量化技术通常以批处理的方式工作,即一次处理多个数据项。这样可以减少函数调用和循环的开销,并利用SIMD(单指令多数据)指令集进行并行计算。 2. 矢量化操作:向量化技术可以将一组数据应用于相同的操作,例如加法、乘法或逻辑运算等。通过将操作应用于整个向量,可以减少指令的开销,并提高计算效率。 3. 数据压缩:向量化技术通常与数据压缩相结合,以减少内存和存储开销。通过对向量进行压缩,可以减少数据传输和存储的需求,并提高整体性能。 向量化技术在Doris和ClickHouse中的应用主要体现在查询和计算操作上。通过使用向量化技术,这些数据库可以更高效地执行复杂的分析查询、聚合操作和向量运算。这对于处理大规模数据集和高并发负载非常有益,可以显著提高查询性能和系统吞吐量。 需要注意的是,向量化技术的效果取决于具体的使用场景和数据特征。因此,在选择数据库时,建议根据自己的需求和实际情况评估向量化技术对性能的影响。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值