机器学习 2014斯坦福大学课程: 4-1 神经网络
刚开始学习机器学习,学习的视频教程是coursera网站上吴恩达(Andrew Ng)教授的机器学习课程。
在此梳理并记录总结笔记,供学习交流,欢迎批评指正!
文章目录
机器学习 分类回顾
- 监督学习(supervised learning )
1.1 回归问题(regression):线性回归问题(linear regression)
1.2 分类问题(classification):逻辑回归问题(logistic regression)
- 无监督学习(unsupervised learning)
2.1 聚集问题(clustering)
2.2. 非聚集问题(non-clustering)
神经网络(Neural Networks)
神经网络可用于解决非线性回归问题,当输入特征太多数据量大的时候。
回归问题:m为样本数,n为特征数
展示一个最简单的神经网络结构:
一个输入层,一个隐藏层,一个输出层;
隐藏层的层数和每层的个数是自己决定的,一般每层隐藏层的个数相同
标记:
- 输入层input layer :Layer1
输入单元数:3个 x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3 对应于3个特征
又可表示为: a 1 1 , a 2 1 , a 3 1 a_1^1,a_2^1,a_3^1 a11,a21,a31
偏差单元bias unit:1个 x 0 x_0 x0- 隐藏层hidden layer:Layer2
激活单元数:3个 a 1 2 , a 2 2 , a 3 2 a_1^2,a_2^2,a_3^2 a12,a22,a32
a i j a_i^j aij代表第j层的第i个激活单元
偏差单元:1个 a 0 a_0 a0- 输出层output laye :Layer3
- 权重weight(参数 Θ \Theta Θ)
Θ ( 1 ) \Theta^{(1)} Θ(1)表示从Layer1到Layer2的映射,即输入层到隐藏层 a ( 2 ) = Θ 1 ∗ X a^{(2)}=\Theta^{1}*X a(2)=Θ1∗X
Θ ( 2 ) \Theta^{(2)} Θ(2)表示从Layer2到Layer3的映射,即隐藏层到输出层 a ( 3 ) = Θ 2 ∗ a ( 2 ) a^{(3)}=\Theta^{2}*a^{(2)} a(3)=Θ2∗a(2)
h = a ( 3 ) h=a^{(3)} h=a(3)
前向传播算法(Forward Propagation)
逻辑回归问题
,二分类,y=0或1代表属于两个分类,n个特征
只考虑一个样本,神经网络只有一层隐藏层,一共神经网络层数L为3层,
s
l
s_l
sl表示该层的神经元数,
隐藏层的神经元单元数为
s
2
=
s
i
z
e
s_2=size
s2=size,输入层的单元数则为
s
L
=
1
s_L=1
sL=1
输入层Layer1: x ( n + 1 ) ∗ 1 = [ x 0 x 1 x 2 ⋮ x n ] = a ( 1 ) x_{(n+1)*1}=\begin{bmatrix}x_0\\x_1 \\x_2 \\\vdots\\x_n\\\end{bmatrix}=a^{(1)} x(n+1)∗1=⎣⎢⎢⎢⎢⎢⎡x0x1x2⋮xn⎦⎥⎥⎥⎥⎥⎤=a(1)
隐藏层Layer2: a ( s i z e + 1 ) ∗ 1 ( 2 ) = [ a 0 ( 2 ) a 1 ( 2 ) a 2 ( 2 ) ⋮ a n ( 2 ) ] a^{(2)}_{(size+1)*1}=\begin{bmatrix}a_0^{(2)}\\a_1^{(2)} \\a_2^{(2)} \\\vdots\\a_n^{(2)}\\\end{bmatrix} a(size+1)∗1(2)=⎣⎢⎢⎢⎢⎢⎢⎡a0(2)a1(2)a2(2)⋮an(2)⎦⎥⎥⎥⎥⎥⎥⎤
输出层: a ( 3 ) = a 1 ( 3 ) a^{(3)}=a_1^{(3)} a(3)=a1(3)
权重: Θ ( 1 ) \Theta^{(1)} Θ(1), Θ ( 2 ) \Theta^{(2)} Θ(2),
过程
:
z ( 2 ) = Θ ( 1 ) x z^{(2)}=\Theta^{(1)}x z(2)=Θ(1)x
其中 z s i z e ∗ 1 ( 2 ) , Θ s i z e ∗ ( n + 1 ) ( 1 ) , x ( n + 1 ) ∗ 1 z^{(2)}_{size*1},\Theta^{(1)}_{size*(n+1)},x_{(n+1)*1} zsize∗1(2),Θsize∗(n+1)(1),x(n+1)∗1
a ( 2 ) = g ( z ( 2 ) ) a^{(2)}=g(z^{(2)}) a(2)=g(z(2)),
a ( 2 ) = [ a 0 ( 2 ) a 1 ( 2 ) ⋮ a n ( 2 ) ] = g ( [ θ 10 ( 1 ) θ 11 ( 1 ) ⋯ θ 1 n ( 1 ) θ 20 ( 1 ) θ 21 ( 1 ) ⋯ θ 2 n ( 1 ) ⋮ ⋮ ⋱ ⋮ θ s i z e 0 ( 1 ) θ s i z e 1 ( 1 ) ⋯ θ s i z e n ( 1 ) ] ∗ [ x 0 x 1 ⋮ x n ] ) a^{(2)}=\begin{bmatrix}a_0^{(2)}\\a_1^{(2)}\\\vdots\\a_n^{(2)}\\\end{bmatrix}= g( \begin{bmatrix}\theta_{10}^{(1)} & \theta_{11}^{(1)} & \cdots & \theta_{1n}^{(1)} \\ \theta_{20}^{(1)} & \theta_{21}^{(1)} & \cdots & \theta_{2n}^{(1)}\\ \vdots & \vdots & \ddots & \vdots \\ \theta_{size0}^{(1)} & \theta_{size1}^{(1)} & \cdots & \theta_{sizen}^{(1)} \\\end{bmatrix} *\begin{bmatrix}x_0\\x_1\\\vdots\\x_n\\\end{bmatrix}) a(2)=⎣⎢⎢⎢⎢⎡a0(2)a1(2)⋮an(2)⎦⎥⎥⎥⎥⎤=g(⎣⎢⎢⎢⎢⎡θ10(1)θ20(1)⋮θsize0(1)θ11(1)θ21(1)⋮θsize1(1)⋯⋯⋱⋯θ1n(1)θ2n(1)⋮θsizen(1)⎦⎥⎥⎥⎥⎤∗⎣⎢⎢⎢⎡x0x1⋮xn⎦⎥⎥⎥⎤)
其中 a s i z e ∗ 1 ( 2 ) , z s i z e ∗ 1 ( 2 ) a^{(2)}_{size*1},z^{(2)}_{size*1} asize∗1(2),zsize∗1(2),g(z)为sigmoid函数,添加偏差单元 a 0 ( 2 ) = 1 a_0^{(2)}=1 a0(2)=1,变为 a ( s i z e + 1 ) ∗ 1 ( 2 ) a^{(2)}_{(size+1)*1} a(size+1)∗1(2)
z ( 3 ) = Θ ( 2 ) a 2 z^{(3)}=\Theta^{(2)}a^2 z(3)=Θ(2)a2
其中, z 1 ∗ 1 ( 3 ) , Θ ( 1 ∗ ( s i z e + 1 ) ) ( 2 ) , a ( s i z e + 1 ) ∗ 1 2 z^{(3)}_{1*1},\Theta^{(2)}_{(1*(size+1))},a^2_{(size+1)*1} z1∗1(3),Θ(1∗(size+1))(2),a(size+1)∗12
h = a ( 3 ) = g ( z ( 3 ) ) h=a^{(3)}=g(z^{(3)}) h=a(3)=g(z(3))
对于所有样本,只需要将X转置,保证一个样本的特征在同一列,即可。
对于多分类问题,k>2, 将 y m ∗ 1 y_{m*1} ym∗1扩展到 Y m ∗ k Y_{m*k} Ym∗k
1分类, y=[1 0 0 0 0 … 0 0 0]
2分类, y=[0 1 0 0 0 … 0 0 0]
k分类, y=[0 0 0 0 0 … 0 0 1]
通过以上过程,即前向传播算法,我们能得到h,即拟合的公式
代价函数
逻辑回归问题中代价函数为:
J
(
θ
0
,
θ
1
,
.
.
.
θ
n
)
=
1
m
∑
i
=
1
m
(
−
y
(
i
)
∗
l
o
g
(
h
θ
(
x
(
i
)
)
)
+
(
1
−
y
(
i
)
)
)
l
o
g
(
1
−
h
θ
(
x
(
i
)
)
)
)
+
λ
2
m
∑
j
=
1
n
θ
j
2
J(\theta_0,\theta_1,...\theta_n)=\frac{1}{m}\sum_{i=1}^m (-y^{(i)}*log(h_\theta(x^{(i)}))+(1-y^{(i))})log(1-h_\theta(x^{(i)}))) +\frac{\lambda}{2m}\sum_{j=1}^n\theta_j^2
J(θ0,θ1,...θn)=m1i=1∑m(−y(i)∗log(hθ(x(i)))+(1−y(i)))log(1−hθ(x(i))))+2mλj=1∑nθj2
神经网络中代价函数为:
J
(
Θ
)
=
1
m
∑
i
=
1
m
∑
k
=
1
K
(
−
y
k
(
i
)
∗
l
o
g
(
h
Θ
(
x
(
i
)
)
)
k
+
(
1
−
y
k
(
i
)
)
)
l
o
g
(
1
−
h
Θ
(
x
(
i
)
)
)
k
)
+
λ
2
m
∑
l
=
1
L
−
1
∑
i
=
1
s
l
∑
j
=
1
s
l
+
1
(
Θ
j
i
l
)
2
J(\Theta)=\frac{1}{m}\sum_{i=1}^m\sum_{k=1}^K (-y_k^{(i)}*log(h_\Theta(x^{(i)}))_k+(1-y_k^{(i))})log(1-h_\Theta(x^{(i)}))_k) +\frac{\lambda}{2m}\sum_{l=1}^{L-1}\sum_{i=1}^{s_l}\sum_{j=1}^{s_l+1}(\Theta_{ji}^l)^2
J(Θ)=m1i=1∑mk=1∑K(−yk(i)∗log(hΘ(x(i)))k+(1−yk(i)))log(1−hΘ(x(i)))k)+2mλl=1∑L−1i=1∑slj=1∑sl+1(Θjil)2
第一项中,可以理解为有k个分类,每一个样本输出的k个分类求和,再所有样本求和
正则化一项,可以理解为每两层之间的权重,去掉
θ
0
\theta_0
θ0后平方所有元素求和,再所有层得权重相加。
以下是不严格的写法,帮助理解:
J
(
Θ
)
=
1
m
∑
i
=
1
m
(
−
Y
.
∗
l
o
g
(
h
(
Θ
)
)
+
(
1
−
Y
)
.
∗
l
o
g
(
1
−
h
(
Θ
)
)
)
+
λ
2
m
(
s
u
m
(
(
Θ
(
1
)
)
2
)
+
s
u
m
(
(
Θ
(
2
)
)
2
)
)
+
.
.
.
)
J(\Theta)=\frac{1}{m}\sum_{i=1}^m(-Y.*log(h(\Theta))+(1-Y).*log(1-h(\Theta)))+\frac{\lambda}{2m}(sum((\Theta^{(1)})^2)+sum((\Theta^{(2)})^2))+...)
J(Θ)=m1i=1∑m(−Y.∗log(h(Θ))+(1−Y).∗log(1−h(Θ)))+2mλ(sum((Θ(1))2)+sum((Θ(2))2))+...)
反向传播算法(back propagation)
反向传播算法用于计算代价函数偏导上,在数学上得到证明,在此略。
在例子中有两个参数矩阵
Θ
(
1
)
,
Θ
(
2
)
\Theta^{(1)},\Theta^{(2)}
Θ(1),Θ(2)
那么对应的偏导数有
∂
∂
Θ
(
1
)
J
Θ
,
∂
∂
Θ
(
2
)
J
Θ
\frac{\partial}{\partial\Theta^{(1)}}J_{\Theta},\frac{\partial}{\partial\Theta^{(2)}}J_{\Theta}
∂Θ(1)∂JΘ,∂Θ(2)∂JΘ
对于每一个样本m:
输出层的误差: δ ( 3 ) = y − h = y − a ( 3 ) \delta^{(3)}=y-h=y-a^{(3)} δ(3)=y−h=y−a(3)
隐藏层的误差: δ ( 2 ) = ( θ ( 2 ) ) T δ ( 3 ) ∗ g ′ ( z 2 ) \delta^{(2)}=(\theta^{(2)})^T\delta^{(3)}*g^{'}(z^2) δ(2)=(θ(2))Tδ(3)∗g′(z2)
其中, g ′ ( z ) g^{'}(z) g′(z)为sigmoid函数的导函数,在数学上证明为 g ′ ( z ) = g ( z ) ∗ ( 1 − g ( z ) ) g^{'}(z)=g(z)*(1-g(z)) g′(z)=g(z)∗(1−g(z))
输入层不存在误差
对于所有样本 : Δ j i ( l ) = Δ j i ( l ) + a j ( l ) δ i l + 1 \Delta_{ji}^{(l)}=\Delta_{ji}^{(l)}+a_j^{(l)}\delta_i^{l+1} Δji(l)=Δji(l)+aj(l)δil+1
在此例子中:
Δ j i ( 1 ) = Δ j i ( 1 ) + a j ( 1 ) δ i 2 \Delta_{ji}^{(1)}=\Delta_{ji}^{(1)}+a_j^{(1)}\delta_i^{2} Δji(1)=Δji(1)+aj(1)δi2
Δ j i ( 2 ) = Δ j i ( 2 ) + a j ( 2 ) δ i 3 \Delta_{ji}^{(2)}=\Delta_{ji}^{(2)}+a_j^{(2)}\delta_i^{3} Δji(2)=Δji(2)+aj(2)δi3
代价函数的偏导数为:
D j i ( l ) = 1 m Δ j i ( l ) + λ m Θ i j l , j ≠ 0 D_{ji}^{(l)}=\frac{1}{m}\Delta_{ji}^{(l)}+\frac{\lambda}{m}\Theta_{ij}^{l},j\ne0 Dji(l)=m1Δji(l)+mλΘijl,j̸=0
在此例子中:
∂ ∂ Θ ( 1 ) J Θ = D j i ( 1 ) = 1 m Δ j i ( 1 ) + λ m Θ i j ( 1 ) , j ≠ 0 \frac{\partial}{\partial\Theta^{(1)}}J_{\Theta}=D_{ji}^{(1)}=\frac{1}{m}\Delta_{ji}^{(1)}+\frac{\lambda}{m}\Theta_{ij}^{(1)},j\ne0 ∂Θ(1)∂JΘ=Dji(1)=m1Δji(1)+mλΘij(1),j̸=0
∂ ∂ Θ ( 2 ) J Θ = D j i ( 2 ) = 1 m Δ j i ( 2 ) + λ m Θ i j ( 2 ) , j ≠ 0 \frac{\partial}{\partial\Theta^{(2)}}J_{\Theta}=D_{ji}^{(2)}=\frac{1}{m}\Delta_{ji}^{(2)}+\frac{\lambda}{m}\Theta_{ij}^{(2)},j\ne0 ∂Θ(2)∂JΘ=Dji(2)=m1Δji(2)+mλΘij(2),j̸=0
不难看出,反向传播算法需要与前向传播算法结合使用
解决思路
神经网络可以解决回归问题、分类问题
在本例子中,将分类问题的解决方法之一逻辑回归做了改进,用神经网络姐姐
- 构架神经网络(多少层,每层多少单元等)
- 通过前向传播算法可以计算出 h Θ ( x ) h_\Theta(x) hΘ(x),即拟合的式子
- 通过前向传播算法可以计算代价函数
- 通过前向后向传播算法可以计算代价函数偏导数
- 选择优化算法来优化代价函数,得到权重 Θ \Theta Θ,再代入到 h Θ ( x ) h_\Theta(x) hΘ(x)可以得到预测的y值
Octave/matlab代码
在课程练习4问题中,识别手写数字0-9,一共k=10个分类;
有5000个样本,每个样本图400个像素点,对应400个特征。
sigmoid和其偏导数函数
function [g] = sigmoid_test (z)
g=1.0./(1.0+exp(-z));
endfunction
function [g] = sigmoidGrad (z)
g=zeros(size(z));
g=sigmoid_test(z).*(1-sigmoid_test(z));
endfunction
costfunc(计算代价函数,代价函数偏导数)
function [J,grad] = costfunc(X,y,input_layer_size,hidden_layer_size,output_layer_size,nn_para,lambda)
%%costfunction and costfunction gradient
%% add x0=1 to X
m=size(X,1);
X=[ones(m,1) X];%for every traning example, add x0=1;
%%set y(5000,1)->y(5000,10)
Y=[];
E=eye(output_layer_size);
for k=1:output_layer_size
y0=find(y==k);
Y(y0,:)=repmat(E(k,:),size(y0,1),1);%%将对应k=1的那些样本,都替换成[10000000...]
end
%%J(cost function)
J=0;
%%从两个theta参数矩阵存成了一个长的列向量,现在提取出来
theta1=reshape(nn_para(1:hidden_layer_size*(input_layer_size+1)),hidden_layer_size,input_layer_size+1);
theta2=reshape(nn_para(hidden_layer_size*(input_layer_size+1)+1:end),output_layer_size,hidden_layer_size+1);
%forward propagation
a1=X;
z2=a1*theta1';
a2=sigmoid(z2);
a2=[ones(m,1) a2];
z3=a2*theta2';
a3=sigmoid(z3);
h=a3;
temp1=[zeros(size(theta1,1),1) theta1(:,2:end)];%%%%%%%theta(1,:)=0, for lambda regulation
temp2=[zeros(size(theta2,1),1) theta2(:,2:end)];
temp1=sum(temp1.^2);
temp2=sum(temp2.^2);
cost=Y.*log(h)+(1-Y).*log(1-h);
J=-1/m*(sum(cost(:)))+lambda/(2*m)*(sum(temp1(:))+sum(temp2(:)));
%%grad
theta1_grad=zeros(size(theta1));
theta2_grad=zeros(size(theta2));
delta_1=zeros(size(theta1));
delta_2=zeros(size(theta2));
for i=1:m
%forward prop
a_1=X(i,:)';
z_2=theta1*a_1;
a_2=sigmoid(theta1*a_1);
a_2=[1;a_2];
z_3=theta2*a_2;
a_3=sigmoid(z_3);
%backward prop
err_3=zeros(output_layer_size,1);
for k=1:output_layer_size
err_3(k)=a_3(k)-(y(i)==k);
end
err_2=theta2'*err_3;
err_2=err_2(2:end).*sigmoidGrad(z_2); %%%%%%%去掉第一项
delta_1=delta_1+err_2*a_1';
delta_2=delta_2+err_3*a_2';
end
theta1_temp=[zeros(size(theta1,1),1) theta1(:,2:end)]; %%%%%%%%%%%%将theta0都变为0
theta2_temp=[zeros(size(theta2,1),1) theta2(:,2:end)];
theta1_grad=1/m*delta_1+lambda/m*theta1_temp;
theta2_grad=1/m*delta_2+lambda/m*theta2_temp;
grad=[theta1_grad(:);theta2_grad(:)];
endfunction
Python代码
def sigmoid(z):
return 1.0/(1.0+np.exp(-z))
def sigmoidGrad(z):
return sigmoid(z)*(1-sigmoid(z))
def expand_y(y):
res=[]
for i in y:
y_array=np.zeros(10)
y_array[i-1]=1
res.append(y_array)
#encoder=OneHotEncoder(sparse=False)
#y_onehot=encoder.fit_transform(y)
#return y_onehot
return np.array(res)
def serialize(a,b):
return np.concatenate((np.ravel(a),np.ravel(b)))
def deserialize(seq,a1,a2,b1,b2):
return seq[:a1*a2].reshape(a1,a2),seq[a1*a2:].reshape(b1,b2)
def feed_forward(nn_para,X,y,input_layer_size,hidden_layer_size,output_layer_size):
theta1,theta2=deserialize(nn_para,hidden_layer_size,input_layer_size+1,output_layer_size,hidden_layer_size+1)
a1=X
z2=a1@theta1.T
a2=sigmoid(z2)
a2=np.insert(a2,0,values=np.ones(a2.shape[0]),axis=1)
z3=a2@theta2.T
a3=sigmoid(z3)
h=a3
theta1_temp=theta1[:,1:]
theta2_temp=theta2[:,1:]
reg=np.power(theta1_temp,2).sum()+np.power(theta2_temp,2).sum()
return theta1,theta2,a1,a2,a3,z2,z3,h,reg
def cost(nn_para,X,y,input_layer_size,hidden_layer_size,output_layer_size,l):
m=X.shape[0];
theta1,theta2,a1,a2,a3,z2,z3,h,reg=feed_forward(nn_para,X,y,input_layer_size,hidden_layer_size,output_layer_size)
c=y*np.log(h)+(1-y)*np.log(1-h)
J=-1/m*c.sum()+l/(2*m)*reg
return J
def back_forward(nn_para,X,y,input_layer_size,hidden_layer_size,output_layer_size,l):
m=X.shape[0];
theta1,theta2,a1,a2,a3,z2,z3,h,reg=feed_forward(nn_para,X,y,input_layer_size,hidden_layer_size,output_layer_size)
delta1=np.zeros(theta1.shape)
theta1_grad=np.zeros(theta1.shape)
delta2=np.zeros(theta2.shape)
theta2_grad=np.zeros(theta2.shape)
for i in range(m):
a1i=np.array([a1[i,:]]).T
z2i=np.array([z2[i,:]]).T
a2i=np.array([a2[i,:]]).T
hi=np.array([h[i,:]]).T
yi=np.array([y[i,:]]).T
err3=hi-yi
err2=(theta2.T)@err3
err2=err2[1:]
err2=err2*sigmoidGrad(z2i)
delta1=delta1+err2*a1i.T
delta2=delta2+err3*a2i.T
theta1_temp=np.insert(theta1[:,1:],0,values=np.zeros(theta1.shape[0]),axis=1)
theta2_temp=np.insert(theta2[:,1:],0,values=np.zeros(theta2.shape[0]),axis=1)
theta1_grad=1/m*delta1+l/m*theta1_temp
theta2_grad=1/m*delta2+l/m*theta2_temp
return serialize(theta1_grad,theta2_grad)
注意:1. python中,矩阵元素与元素相乘为*或者np.multiply,矩阵相乘为@或者np.dot
2.a一维数组a.shape 返回为(x,)与(x,1) 意义完全不同,
要通过np.array(a).reshape(5,1)转换为而为矩阵,再进行矩阵运算,否则运算会出现维度不一致
未完待续