向量化
-
向量化是去除代码中显示for循环的艺术。
-
假设现在x和W都是一个向量:
x = ( x 1 . . . x n ) , W = ( W 1 . . . W n ) x =\left(\begin{matrix} x_1 \\ ... \\ x_n \end{matrix} \right), W = \left(\begin{matrix} W_1 \\ ... \\ W_n \end{matrix} \right) x= x1...xn ,W= W1...Wn
并有函数:
Z = W × x + b Z = W\times x + b Z=W×x+b
非向量化计算函数Z:int Z = 0; int W[n] = {....}; int x[n] = {....}; int b = arg; for(int i = 1; i <= n; i++){ Z += W[i]*x[i]; } Z += b;
向量化计算函数Z:
int vectorFunc(int* W, int* x); // 专门用于计算矩阵乘法的函数 int Z = 0; int W[n] = {....}; int x[n] = {....}; int b = arg; Z = vectorFunc(W, x) + b;
向量化消除了代码中显示的for循环。
-
这里有一条编写神经网络的建议:“Whenever possible, avoid explicit for-loops.”
“尽可能的避免显示的for循环。”
Logisitic的向量化
-
我们用以下算式对M个样本进行Logistic:
z ( 1 ) = W T x ( 1 ) + b z^{(1)}=W^Tx^{(1)}+b z(1)=WTx(1)+bz ( 2 ) = W T x ( 2 ) + b z^{(2)}=W^Tx^{(2)}+b z(2)=WTx(2)+b
. . . . . . ... ... ......
z ( m ) = W T x ( m ) + b z^{(m)}=W^Tx^{(m)}+b z(m)=WTx(m)+b
其中,z和b都是实数,而W和x都是一维向量:
z ∈ R , b ∈ R , W T = ( w 1 . . . w n ) , X = ( x 1 . . . x n ) z \in R, b\in R, W^T= \left(\begin{matrix} w_1 & ... & w_n \end{matrix} \right), X = \left(\begin{matrix} x_1 \\ ... \\ x_n \end{matrix} \right) z∈R,b∈R,WT=(w1...wn),X= x1...xn -
我们使用向量化简化上述的m个算式,只需要把z和b也都定义为向量:
Z = ( z 1 . . . z n ) , b = ( b 1 . . . b n ) Z = \left(\begin{matrix} z_1 & ... & z_n \end{matrix} \right), b = \left(\begin{matrix} b_1 & ... & b_n \end{matrix} \right) Z=(z1...zn),b=(b1...bn)
此时,m个算式可简化为一个:
Z = ( z 1 . . . z n ) = W T X + b = ( w 1 . . . w n ) × ( x 1 . . . x n ) + ( b 1 . . . b n ) Z = \left(\begin{matrix} z_1 & ... & z_n \end{matrix} \right)=W^TX+b = \left(\begin{matrix} w_1 & ... & w_n \end{matrix} \right)\times \left(\begin{matrix} x_1 \\... \\x_n\end{matrix} \right)+\left(\begin{matrix}b_1&... &b_n\end{matrix} \right) Z=(z1...zn)=WTX+b=(w1...wn)× x1...xn +(b1...bn)Z = [ ( W T x ( 1 ) + b 1 ) ( W T x ( 2 ) + b 2 ) . . . ( W T x ( n ) + b n ) ] Z = \left[\begin{matrix} (W^Tx^{(1)} + b_1) & (W^Tx^{(2)}+b_2) &... & (W^Tx^{(n)}+b_n) \end{matrix} \right] Z=[(WTx(1)+b1)(WTx(2)+b2)...(WTx(n)+bn)]
-
以上的计算过程为正向传播(forward),同样可以使用向量化反向传播(backward)。
Logistic向量化的梯度下降
-
我们多样本Logistic的代码是这样写的:
#define MAX_TIMES N // 假设我们希望更新W的次数为N,即梯度下降N次 int W , b; // 进行梯度下降的W和b for(int j = 0; j<MAX_TIMES; j++){ int dw = 0, db = 0, dz=0, z[m], x[m], a[m]; // dw是每一轮的求导值,db是参数,dz存放每一轮的损失函数值 // z[m]存放每一轮的计算结果(forward),x[m]是每一轮输入的数据 // a[m]存放是每一轮的真实值,a[i]-z[i]即为损失值 for(int i = 1; i<m; i++){ // ===将这个for循环去除==== z[i] = W*x[i] + b; dz = a[i] - z[i]; // 这样求出dz有些草率,这里只做演示 int dwi = x[i]*dz; int dbi = dz; // 这个计算dwi和dbi的方式写在前面的简化里 dw += dwi; db += dbi; // 求和 } dw /= m; db /= b; // 求平均值 w = w - a*dw; b = b - a*db; // 更新w和b的值 }
最外层的循环我们不需要去掉,因为这是在遍历参数的更新次数。但是内循环可以去掉,可以将m个样本一次计算完。
逐句向量化for循环内的代码
-
其中的z[i] = W*x[i] + b可以简化为向量操作(共有m个样本,每个样本n个值):
z = ( w 1 . . . w n ) × [ x 1 1 . . . x 1 m . . . . . . . . . x n 1 . . . . x n m ] + [ b 1 . . . b m ] z = \left(\begin{matrix} w_1 & ... & w_n \end{matrix} \right)\times \left[\begin{matrix} x_1^1&...&x_1^m \\ ...& ... &...\\ x_n^1 & .... & x_n^m \end{matrix} \right] + \left[\begin{matrix} b_1 &...& b_m\end{matrix} \right] z=(w1...wn)× x11...xn1..........x1m...xnm +[b1...bm] -
最终的z是一个一维m列的向量:
z = [ z 1 . . . z m ] z = \left[\begin{matrix} z_1 &...& z_m\end{matrix} \right] z=[z1...zm] -
对应的真实值a,同样是一个一维m列的向量:
a = [ a 1 . . . a m ] a = \left[\begin{matrix} a_1 &...& a_m\end{matrix} \right] a=[a1...am] -
其中的dz = a[i] - z[i]就可以写为向量操作:
d z = [ ( a i − z i ) . . . ( a m − z m ) ] , dz = \left[\begin{matrix} (a_i-z_i) & ... & (a_m-z_m) \end{matrix} \right], dz=[(ai−zi)...(am−zm)], -
其中的int dwi = dz*x[i]同样转换为向量操作,dwi同样会变成m列的一维矩阵:
d w i = [ ( a i − z i ) . . . ( a m − z m ) ] × [ x 1 1 . . . x 1 m . . . . . . . . . x n 1 . . . . x n m ] dw_i = \left[\begin{matrix} (a_i-z_i) & ... & (a_m-z_m) \end{matrix} \right] \times \left[\begin{matrix} x_1^1&...&x_1^m \\ ...& ... &...\\ x_n^1 & .... & x_n^m \end{matrix} \right] dwi=[(ai−zi)...(am−zm)]× x11...xn1..........x1m...xnm
d w i = [ d w 1 . . . d w m ] dw_i = \left[\begin{matrix} dw_1 & ... & dw_m \end{matrix} \right] dwi=[dw1...dwm] -
其中int dbi = dz;转换为向量化操作:
d b i = [ ( a i − z i ) . . . ( a m − z m ) ] dbi = \left[\begin{matrix} (a_i-z_i) & ... & (a_m-z_m) \end{matrix} \right] dbi=[(ai−zi)...(am−zm)] -
其中,dw += dwi;db += dbi;是两个求和操作,把矩阵的每一列相加即可,这一步通常都有现成的方法。
d w = d w 1 + d w 2 + . . . + d w m dw = dw_1 + dw_2 + ...+ dw_m dw=dw1+dw2+...+dwm
d b = d b 1 + d b 2 + . . . + d b m db = db_1 + db_2 + ...+ db_m db=db1+db2+...+dbm