机器学习——神经网络,反向传播注解
我们是要用数据网络实现一个多分类问题
多变量相对于单变量我们至少还要考虑两个问题:
-
编码问题
对于这些类别无序关系的离散变量可以用one-hot编码。
采用sklearn.preprocessing进行
from sklearn.preprocessing import OneHotEncoder encoder = OneHotEncoder(sparse=False) y_onehot = encoder.fit_transform(y) y_onehot.shape
-
向量化
-
给出代价函数
J ( θ ) = 1 m ∑ i = 1 m ∑ k = 1 K [ − y k ( i ) log ( ( h θ ( x ( i ) ) ) k ) − ( 1 − y k ( i ) ) log ( 1 − ( h θ ( x ( i ) ) ) k ) ] + λ 2 m [ ∑ j = 1 25 ∑ k = 1 400 ( Θ j , k ( 1 ) ) 2 + ∑ j = 1 10 ∑ k = 1 25 ( Θ j , k ( 2 ) ) 2 ] \begin{aligned}J(\theta)=& \frac{1}{m} \sum_{i=1}^{m} \sum_{k=1}^{K}\left[-y_{k}^{(i)} \log \left(\left(h_{\theta}\left(x^{(i)}\right)\right)_{k}\right)-\left(1-y_{k}^{(i)}\right) \log \left(1-\left(h_{\theta}\left(x^{(i)}\right)\right)_{k}\right)\right]+\\& \frac{\lambda}{2 m}\left[\sum_{j=1}^{25} \sum_{k=1}^{400}\left(\Theta_{j, k}^{(1)}\right)^{2}+\sum_{j=1}^{10} \sum_{k=1}^{25}\left(\Theta_{j, k}^{(2)}\right)^{2}\right]\end{aligned} J(θ)=m1i=1∑mk=1∑K[−yk(i)log((hθ(x(i)))k)−(1−yk(i))log(1−(hθ(x(i)))k)]+2mλ[j=1∑25k=1∑400(Θj,k(1))2+j=1∑10k=1∑25(Θj,k(2))2]
相对于二分类,输出只有一个,在这里,我们发现,这里是对K个输出都要求代价然后求和。正则化项是根据神经元个数及参数进行设定。400个输入,中间层是25个神经单元,输出层是10个单元,对应最终的0—9这10个数字的分类。参数矩阵400*25,25*10.
那么参数是如何设定和更新的呢?
设定
不同层之间连接的参数,我们一般是随机置数,一般是一些比较小的数。在输入数据之后,通过前向传播和反向传播算法对参数进行更新
。
每个神经元中的激活函数我们选择 s i g m o d sigmod sigmod函数。
代价函数选择交叉熵函数:
def cost(params,input_size,hidden_size,num_label,X,y,learning_rate):
#m是样本数
m = X.shape[0]
X = np.matrix(X)
y = np.matrix(y)
#只是截取参数而已,而且只是针对这样一个只有一层隐藏层的神经网络
theta1 = np.matrix(np.reshape(params[:hidden_size(input_size+1)],(hidden_size,(input_size+1))))
theta2 = np.matrix(np.reshape(params[hidden_size*(input_size+1):],(num_label,(hidden_size+1))))
a1, z2, a2, z3, h = forward_propagate(X, theta1, theta2)
#
J = 0
for i in range (m):
#采用交叉熵代价函数
first_term = np.multiply(-y[i,:],np.log(h[i,:]))
second_term = np.multiply(1-y[i,:],np.log(1-h[i,:]))
J += np.sum(first_term-second_term)
J = J / m
return J
梯度检验
首先梯度检验是对于任意函数都是可行的。
Gradient checking works for any function where you are computing the cost and the gradient.
因为神经网络中的参数比较多,然后步骤又比较多,所以梯度检验只是类似于一个检查的过程,是针对我们的参数更新是否合理,看反向传播中梯度值是否有较大差别。size函数的一个作用就可以让我了解之间的数据,防止我们的维数不匹配。
用数值梯度(numerical gradient对梯度的估计)检验解析梯度(analytic gradient,可谓函数的实际梯度值)。
反向传播
关键在于求偏导的链式法则:
链式法则。为了更加具体,避免太抽象,我直接适用 s i g m o d sigmod sigmod函数
代价函数对 J ( s i g m o d ( θ . T ∗ a i ) ) J(sigmod(\theta.T*a_{i})) J(sigmod(θ.T∗ai))对 s i g m o d ( θ . T ∗ a i ) sigmod(\theta.T*a_{i}) sigmod(θ.T∗ai)求偏导, s i g m o d ( θ . T ∗ a i ) sigmod(\theta.T*a_{i}) sigmod(θ.T∗ai)再对 θ . T ∗ a i \theta.T*a_{i} θ.T∗ai求偏导, θ . T ∗ a i \theta.T*a_{i} θ.T∗ai在对 θ \theta θ求偏。
结果显而易见,最终结果是 a i ∗ s i g m o d ′ ∗ J ′ a_{i}*{sigmod'}*J' ai∗sigmod′∗J′
J ′ J' J′不论是交叉熵函数,还是平方误差最后的结果其实会发现惊人的想似,就是 1 m ∑ i = 1 m ( h x − y ) x i \frac{1}{m}\sum_{i=1}^{m}(h_{x}-y)x_{i} m1i=1∑m(hx−y)xi
那么我们这里将之后的一系列求导代替 x i x_{i} xi,那么我们就可以得到 J J J对 θ \theta θ求导结果为 1 m ∑ i = 1 m ( h x − y ) ∗ a i ∗ s i g m o d ′ \frac{1}{m}\sum_{i=1}^{m}(h_{x}-y)*a_{i}*{sigmod'} m1i=1∑m(hx−y)∗ai∗sigmod′求和用 θ . T \theta.T θ.T替代 ( h x − y ) ∗ θ T ∗ a i ∗ s i g m o d ′ (h_{x}-y)*{\theta^T}*a_{i}*{sigmod'} (hx−y)∗θT∗ai∗sigmod′
在吴恩达的课程中为了避免引入求偏导,链式法则这些微积分的内容,而进行了略过,并代之以一些隐藏细节的概念,直接给出的第几层的误差等等。因而给大家带来来一些困扰。
而这些完全可以直接从损失函数直接推导得出。只是吴恩达课程中隐藏,代之以一些概念。