def _bwd(self,dLdy,X):
dX = []
for dy,x in zip(dLdy, X):
dxi = []
for dyi, xi in zip(*np.atleast_2d(dy, x)): # 用xi 计算yi.
# 梯度:当i=j : yj - yj yj, 当i \= j : -yj yj
# dyi,xi 都是矩阵,1 n_out, 1 n_in.
yi = self._fwd(xi.reshape(1, -1)).reshape(-1, 1) # 列向量的样子,二维的。 shape : n_out , 1
dyidxi = np.diagflat(yi) - yi @ yi.T # 只有对角线是相等的。 nout,1, 1 out -> n_out,n_out
# np.diagflat, 将矩阵展平,填充对角 -> n_out,n_out 对角阵。
# dyidxi -> n_out,n_out.
dxi.append(dyi @ dyidxi) # dyi -> 1 n_out. -> 1 , n_out. y1/xi,y2/xi,y3/xi....
dX.append(dxi) # dX, 最后是n_sample , n_out.
return np.array(dX).reshape(*X.shape) # 但是X.shape : n_sample, n_in , 因为是softmax,所以n_in == n_out.
# 这样就得到jacobin矩阵。
其中的
dL/dy = (dL/dy1,dL/dy2,....)^T
shape: samples, n_out.
X shape : samples, n_in.
其中的:
np.atleast_2d(dy, x)
得到的结果是一个list,list中是将dy,x
扩展成二维的矩阵。
Out[86]: [array([['a', 'b', 'c', 'd', 'e']], dtype='), array([[1, 2, 3, 4, 5]])]
然后经过:
for dyi, xi in zip(*np.atleast_2d(dy, x)):
得到的dyi,xi
分别就是(1,n_out), (1, n_in)
的两个二维矩阵,这个遍历的次数就只有一次,作用只是用来进行维度扩展。