如何用Python实现常见机器学习算法-3

三、BP神经网络

1、神经网络模型

首先介绍三层神经网络,如下图

输入层(input layer)有三个units(为补上的bias,通常设为1)

表示第j层的第i个激励,也称为单元unit

为第j层到第j+1层映射的权重矩阵,就是每条边的权重

所以可以得到:

隐含层:

输出层:

其中,S型函数,也成为激励函数

可以看出为3??4的矩阵,为1??4的矩阵

==》j+1的单元数x(j层的单元数+1)

2、代价函数

假设最后输出的,即代表输出层有K个单元

其中,代表第i个单元输出与逻辑回归的代价函数

差不多,就是累加上每个输出(共有K个输出)

3、正则化

L-->所有层的个数

-->第l层unit的个数

正则化后的代价函数为

共有L-1层,然后是累加对应每一层的theta矩阵,注意不包含加上偏置项对应的theta(0)

正则化后的代价函数实现代码:

 1 # 代价函数
 2 def nnCostFunction(nn_params,input_layer_size,hidden_layer_size,num_labels,X,y,Lambda):
 3     length = nn_params.shape[0] # theta的中长度
 4     # 还原theta1和theta2
 5     Theta1 = nn_params[0:hidden_layer_size*(input_layer_size+1)].reshape(hidden_layer_size,input_layer_size+1)
 6     Theta2 = nn_params[hidden_layer_size*(input_layer_size+1):length].reshape(num_labels,hidden_layer_size+1)
 7
 8     # np.savetxt("Theta1.csv",Theta1,delimiter=‘,‘)
 9
10     m = X.shape[0]
11     class_y = np.zeros((m,num_labels))      # 数据的y对应0-9,需要映射为0/1的关系
12     # 映射y
13     for i in range(num_labels):
14         class_y[:,i] = np.int32(y==i).reshape(1,-1) # 注意reshape(1,-1)才可以赋值
15
16     ‘‘‘去掉theta1和theta2的第一列,因为正则化时从1开始‘‘‘
17     Theta1_colCount = Theta1.shape[1]
18     Theta1_x = Theta1[:,1:Theta1_colCount]
19     Theta2_colCount = Theta2.shape[1]
20     Theta2_x = Theta2[:,1:Theta2_colCount]
21     # 正则化向theta^2
22     term = np.dot(np.transpose(np.vstack((Theta1_x.reshape(-1,1),Theta2_x.reshape(-1,1)))),np.vstack((Theta1_x.reshape(-1,1),Theta2_x.reshape(-1,1))))
23
24     ‘‘‘正向传播,每次需要补上一列1的偏置bias‘‘‘
25     a1 = np.hstack((np.ones((m,1)),X))
26     z2 = np.dot(a1,np.transpose(Theta1))
27     a2 = sigmoid(z2)
28     a2 = np.hstack((np.ones((m,1)),a2))
29     z3 = np.dot(a2,np.transpose(Theta2))
30     h  = sigmoid(z3)
31     ‘‘‘代价‘‘‘
32     J = -(np.dot(np.transpose(class_y.reshape(-1,1)),np.log(h.reshape(-1,1)))+np.dot(np.transpose(1-class_y.reshape(-1,1)),np.log(1-h.reshape(-1,1)))-Lambda*term/2)/m
33
34     return np.ravel(J)

4、反向传播BP

上面正向传播可以计算得到J(θ),使用梯度下降算法还需要求它的梯度

BP反向传播的目的就是求代价函数的梯度

假设4层的神经网络,记为-->l层第j个单元的误差

没有,因为对于输入没有误差,因为S型函数的倒数为:

所以上面的可以在前向传播中计算出来

反向传播计算梯度的过程为:

for i=1-m:

正向传播计算(l=2,3,4...L)

最后,即得到代价函数的梯度

代码实现:

 1 # 梯度
 2 def nnGradient(nn_params,input_layer_size,hidden_layer_size,num_labels,X,y,Lambda):
 3     length = nn_params.shape[0]
 4     Theta1 = nn_params[0:hidden_layer_size*(input_layer_size+1)].reshape(hidden_layer_size,input_layer_size+1)
 5     Theta2 = nn_params[hidden_layer_size*(input_layer_size+1):length].reshape(num_labels,hidden_layer_size+1)
 6     m = X.shape[0]
 7     class_y = np.zeros((m,num_labels))      # 数据的y对应0-9,需要映射为0/1的关系
 8     # 映射y
 9     for i in range(num_labels):
10         class_y[:,i] = np.int32(y==i).reshape(1,-1) # 注意reshape(1,-1)才可以赋值
11
12     ‘‘‘去掉theta1和theta2的第一列,因为正则化时从1开始‘‘‘
13     Theta1_colCount = Theta1.shape[1]
14     Theta1_x = Theta1[:,1:Theta1_colCount]
15     Theta2_colCount = Theta2.shape[1]
16     Theta2_x = Theta2[:,1:Theta2_colCount]
17
18     Theta1_grad = np.zeros((Theta1.shape))  #第一层到第二层的权重
19     Theta2_grad = np.zeros((Theta2.shape))  #第二层到第三层的权重
20
21     Theta1[:,0] = 0;
22     Theta2[:,0] = 0;
23     ‘‘‘正向传播,每次需要补上一列1的偏置bias‘‘‘
24     a1 = np.hstack((np.ones((m,1)),X))
25     z2 = np.dot(a1,np.transpose(Theta1))
26     a2 = sigmoid(z2)
27     a2 = np.hstack((np.ones((m,1)),a2))
28     z3 = np.dot(a2,np.transpose(Theta2))
29     h  = sigmoid(z3)
30
31     ‘‘‘反向传播,delta为误差,‘‘‘
32     delta3 = np.zeros((m,num_labels))
33     delta2 = np.zeros((m,hidden_layer_size))
34     for i in range(m):
35         delta3[i,:] = h[i,:]-class_y[i,:]
36         Theta2_grad = Theta2_grad+np.dot(np.transpose(delta3[i,:].reshape(1,-1)),a2[i,:].reshape(1,-1))
37         delta2[i,:] = np.dot(delta3[i,:].reshape(1,-1),Theta2_x)*sigmoidGradient(z2[i,:])
38         Theta1_grad = Theta1_grad+np.dot(np.transpose(delta2[i,:].reshape(1,-1)),a1[i,:].reshape(1,-1))
39
40     ‘‘‘梯度‘‘‘
41     grad = (np.vstack((Theta1_grad.reshape(-1,1),Theta2_grad.reshape(-1,1)))+Lambda*np.vstack((Theta1.reshape(-1,1),Theta2.reshape(-1,1))))/m
42     return np.ravel(grad)

5、BP可以求梯度的原因

实际是利用了链式求导法则

因为下一层的单元利用上一层的单元作为输入进行计算

大体的推导过程如下,最终我们是想预测函数与已知的y非常接近,求均方差的梯度沿着此梯度方向可使代价函数最小化。可对照上面求梯度的过程。

求误差更详细的推导过程:

6、梯度检查

检查利用BP求的梯度是否正确

利用导数的定义验证:

求出来的数值梯度应该与BP求出的梯度非常接近

验证BP正确后就不需要再执行验证梯度的算法了

代码实现

 1 # 检验梯度是否计算正确
 2 # 检验梯度是否计算正确
 3 def checkGradient(Lambda = 0):
 4     ‘‘‘构造一个小型的神经网络验证,因为数值法计算梯度很浪费时间,而且验证正确后之后就不再需要验证了‘‘‘
 5     input_layer_size = 3
 6     hidden_layer_size = 5
 7     num_labels = 3
 8     m = 5
 9     initial_Theta1 = debugInitializeWeights(input_layer_size,hidden_layer_size);
10     initial_Theta2 = debugInitializeWeights(hidden_layer_size,num_labels)
11     X = debugInitializeWeights(input_layer_size-1,m)
12     y = 1+np.transpose(np.mod(np.arange(1,m+1), num_labels))# 初始化y
13
14     y = y.reshape(-1,1)
15     nn_params = np.vstack((initial_Theta1.reshape(-1,1),initial_Theta2.reshape(-1,1)))  #展开theta
16     ‘‘‘BP求出梯度‘‘‘
17     grad = nnGradient(nn_params, input_layer_size, hidden_layer_size,
18                      num_labels, X, y, Lambda)
19     ‘‘‘使用数值法计算梯度‘‘‘
20     num_grad = np.zeros((nn_params.shape[0]))
21     step = np.zeros((nn_params.shape[0]))
22     e = 1e-4
23     for i in range(nn_params.shape[0]):
24         step[i] = e
25         loss1 = nnCostFunction(nn_params-step.reshape(-1,1), input_layer_size, hidden_layer_size,
26                               num_labels, X, y,
27                               Lambda)
28         loss2 = nnCostFunction(nn_params+step.reshape(-1,1), input_layer_size, hidden_layer_size,
29                               num_labels, X, y,
30                               Lambda)
31         num_grad[i] = (loss2-loss1)/(2*e)
32         step[i]=0
33     # 显示两列比较
34     res = np.hstack((num_grad.reshape(-1,1),grad.reshape(-1,1)))
35     print res

7、权重的随机初始化

神经网络不能像逻辑回归那样初始化theta为0,因为若是每条边的权重都为0,每个神经元都是相同的输出,在反向传播中也会得到同样的梯度,最终只会预测一种结果。

所以应该初始化为接近0的数

代码实现

1 # 随机初始化权重theta
2 def randInitializeWeights(L_in,L_out):
3     W = np.zeros((L_out,1+L_in))    # 对应theta的权重
4     epsilon_init = (6.0/(L_out+L_in))**0.5
5     W = np.random.rand(L_out,1+L_in)*2*epsilon_init-epsilon_init # np.random.rand(L_out,1+L_in)产生L_out*(1+L_in)大小的随机矩阵
6     return W

8、预测

正向传播预测结果

代码实现

 1 # 预测
 2 def predict(Theta1,Theta2,X):
 3     m = X.shape[0]
 4     num_labels = Theta2.shape[0]
 5     #p = np.zeros((m,1))
 6     ‘‘‘正向传播,预测结果‘‘‘
 7     X = np.hstack((np.ones((m,1)),X))
 8     h1 = sigmoid(np.dot(X,np.transpose(Theta1)))
 9     h1 = np.hstack((np.ones((m,1)),h1))
10     h2 = sigmoid(np.dot(h1,np.transpose(Theta2)))
11
12     ‘‘‘
13     返回h中每一行最大值所在的列号
14     - np.max(h, axis=1)返回h中每一行的最大值(是某个数字的最大概率)
15     - 最后where找到的最大概率所在的列号(列号即是对应的数字)
16     ‘‘‘
17     #np.savetxt("h2.csv",h2,delimiter=‘,‘)
18     p = np.array(np.where(h2[0,:] == np.max(h2, axis=1)[0]))
19     for i in np.arange(1, m):
20         t = np.array(np.where(h2[i,:] == np.max(h2, axis=1)[i]))
21         p = np.vstack((p,t))
22     return p 

9、输出结果

梯度检查

随机显示100个手写数字

显示theta1权重

训练集预测准确度

归一化后训练集预测准确度

p.p1 { margin: 0.0px 0.0px 8.0px 8.0px; text-align: justify; text-indent: -8.0px; font: 15.0px "Helvetica Neue"; color: #3f3f3f; background-color: #ffffff }
span.s1 { }

时间: 2024-08-30 16:20:05

如何用Python实现常见机器学习算法-3的相关文章

如何用Python实现常见机器学习算法-1

最近在GitHub上学习了有关python实现常见机器学习算法 目录 一.线性回归 1.代价函数 2.梯度下降算法 3.均值归一化 4.最终运行结果 5.使用scikit-learn库中的线性模型实现 二.逻辑回归 1.代价函数 2.梯度 3.正则化 4.S型函数 5.映射为多项式 6.使用的优化方法 7.运行结果 8.使用scikit-learn库中的逻辑回归模型实现 逻辑回归_手写数字识别_OneVsAll 1.随机显示100个数字 2.OneVsAll 3.手写数字识别 4.预测 5.运行

如何用Python实现常见机器学习算法-2

二.逻辑回归 1.代价函数 可以将上式综合起来为: 其中: 为什么不用线性回归的代价函数表示呢?因为线性回归的代价函数可能是非凸的,对于分类问题,使用梯度下降很难得到最小值,上面的代价函数是凸函数的图像如下,即y=1时: 可以看出,当趋于1,y=1,与预测值一致,此时付出的代价cost趋于0,若趋于0,y=1,此时的代价cost值非常大,我们最终的目的是最小化代价值,同理的图像如下(y=0): 2.梯度 同样对代价函数求偏导: 可以看出与线性回归的偏导数一致. 推导过程: 3.正则化 正则化的目

8种常见机器学习算法比较

机器学习算法太多了,分类.回归.聚类.推荐.图像识别领域等等,要想找到一个合适算法真的不容易,所以在实际应用中,我们一般都是采用启发式学习方式来实验.通常最开始我们都会选择大家普遍认同的算法,诸如SVM,GBDT,Adaboost,现在深度学习很火热,神经网络也是一个不错的选择.假如你在乎精度(accuracy)的话,最好的方法就是通过交叉验证(cross-validation)对各个算法一个个地进行测试,进行比较,然后调整参数确保每个算法达到最优解,最后选择最好的一个.但是如果你只是在寻找一个

(转)8种常见机器学习算法比较

机器学习算法太多了,分类.回归.聚类.推荐.图像识别领域等等,要想找到一个合适算法真的不容易,所以在实际应用中,我们一般都是采用启发式学习方式来实验.通常最开始我们都会选择大家普遍认同的算法,诸如SVM,GBDT,Adaboost,现在深度学习很火热,神经网络也是一个不错的选择.假如你在乎精度(accuracy)的话,最好的方法就是通过交叉验证(cross-validation)对各个算法一个个地进行测试,进行比较,然后调整参数确保每个算法达到最优解,最后选择最好的一个.但是如果你只是在寻找一个

常见机器学习算法原理+实践系列5(KNN分类+Keans聚类)

一,KNN分类 K-Nearest Neighbor K临近算法是一种有监督的分类算法,工作原理很简单,存在一个样本集合,也成为训练样本,样本中包含标签,将新数据的每个特征与样本集合的数据对应特征进行比较,然后提取样本最相似的分类标签,k就是选择的最相似的数据点,选择k个点中出现频率最高的分类,就是新数据的分类.一般来说k不会超过20个.Knn有两个细节需要注意,一个是相似度算法,常用包含欧式距离,余弦距离等等,另外一个在计算相似度之前需要归一化特征,比如使用离差标准化(Min-Max),把所有

常见机器学习算法原理+实践系列2(SVD)

SVD奇异值分解 利用Singular Value Decomposition 奇异值分解,我们能够用小得多的数据集来表示原始数据集,可以理解为了去除噪音以及冗余信息.假设A是一个m*n的矩阵,通过SVD分解可以把A分解为以下三个矩阵: 其中U为m*m矩阵,里面的向量是正交的,U里面的向量称为左奇异向量,Σ是一个m*n对角矩阵,对角线以外的因素都是0,对角线都是奇异值,按照大到小排序,而VT(V的转置)是一个N * N的矩阵,里面的向量也是正交的,V里面的向量称为右奇异向量).那么奇异值和特征值

常见机器学习算法原理+实践系列6(朴素贝叶斯分类)

朴素贝叶斯NB Native Bayes是一种简单有效的分类算法, 贝叶斯定律用这个条件概率公式来表示: P(A|B) = P(B|A)* P(A) / P(B),其中P(A|B)的意思是,在B发生的前提下,发生A的概率,P(A),P(B)代表现实中发生A以及B的概率,实际上取决于我们输入样本的情况.贝叶斯分类算法在邮件分类,文本分类等等很多场景有非常广泛的应用.比如在邮件分类中,可以这样简单的理解,假如一个邮件用这个词组合(w1,w2,….wn)来表示,那么这个邮件是垃圾邮件的概率是多少.实际

常见机器学习算法原理+实践系列1(逻辑回归)

一,逻辑回归Logistic Regression 逻辑回归是线性模型Y=f(x)=b0+b1*x的延伸,一般用来做2分类问题,输出标记C={0,1},C就是classification的意思,通俗的讲,就要建立Y和C之间的关系,Y是多少的时候,C是0,Y是多少的时候,C是1,传统的线性回归输出的y是实数,在负无穷到正无穷之间,而C是0,1两种,使用Sigmoid函数就可以把y从负无穷到正无穷之间转换到0,1之间,该函数为:y=1/(1+e-z),其中z=wTX,x为自变量,w为权重.P记为发生

mahout 常见机器学习算法及分类

最近一直在学习hadoop 一直没有梳理接触到的东西,常见算法分类: 推荐系统(推荐引擎): 基于用户的协同过滤算法UserCF      近邻算法,容易实现 基于物品的协同过滤算法ItemCF       速度快,容易实现分布式计算 SlopeOne算法       @Deprecated at mahout 0.8 KNN Linear interpolation item–based推荐算法    最近邻算法   @Deprecated at mahout 0.8 SVD推荐算法   奇异