Ng-機器學習(Day 5)

神經網絡代碼實現:

  1. 讀取數據:

因爲要求y爲下圖的形式,所以要對y進行處理
在這裏插入圖片描述

import numpy as np
import pandas as pd
from scipy.io import loadmat
from sklearn.preprocessing import OneHotEncoder
path ='E:/Data/Ng/Coursera-ML-AndrewNg-Notes-master/code/ex4-NN back propagation/ex4data1.mat'
data = loadmat(path)
X = data['X']
y = data['y']
encoder = OneHotEncoder(sparse=False)
y_encoder = encoder.fit_transform(y) #可以直接利用OneHotEncoder進行轉換,比如說y當中一共有10個不同的元素,5000列,那麼轉化以後每一個數字都單獨爲1列,比如1就是[1,0,0,...,0],最後形狀爲(5000,10)
  1. 定義一個sigmoid函數和前向傳播函數
    根據下列公式可進行編寫
    在這裏插入圖片描述
def sigmoid(z):
    return 1/(1+np.exp(-z))

def forward(X,y_encoder,theta1,theta2):
	"""計算前向傳播的值
		Params:
			X:特徵值(5000*400)
			y_encoder:輸出變量(5000*10)
			theta1;theta2:初始化的值
		return"""
    m = X.shape[0] #獲取樣本總數,用於插入列的時候使用
    a1 = np.insert(X,0,values=np.ones(m),axis=1) #插入一個x0=1的列,
    z2 = a1 * theta1.T 
    #因爲 上圖中可以看到當輸入的樣本數爲1的時候z2= θ1*a1,即θ的每一行都要和樣本值相乘。但是這裏我們輸入的樣本值爲5000,θ1爲(25,401)的矩陣,也就是說我們的5000個樣本都要單獨和25行θ值對應相乘,所以這裏的θ要進行轉置。
    a2 = np.insert(sigmoid(z2),0,values=np.ones(m),axis=1)
    z3 = a2 *theta2.T
    h = sigmoid(z3)
    return a1,z2,a2,z3,h
  1. 根據公式編寫代價函數:
    在這裏插入圖片描述
def cost(params,in_size,h_size,label_nums,X,y_encoder,l):
	"""代價函數的前面部分
		Params:
			params:存放所有初始化theta1,theta2值的ndarray
			in_size:特徵值的數量
			h_szie:隱藏層的項數
			label_nums:總分類數
			X:特徵值數據
			y_encoder:轉換後的y
			l:lambda
		return
			J:代價函數"""
	
	m = X.shape[0] #獲取樣本總數
	X = np.mat(X)
	y_encoder = np.mat(y_encoder)
	theta1 = np.mat(np.reshape(params[:h_size*(in_size+1)],(h_size,in_size+1))) #(25,401)
	theta2 = np.mat(np.reshape(params[h_size*(in_size+1):],(label_nums,h_size+1))) #(10,26)
	a1,z2,a2,z3,h = forward(X,y_encoder,theta1,theta2) #獲取h
	
	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,:]))
		#注意神經網絡的代價函數要求兩次和,一次是m一次是k。這個循環是用來求m的,那麼在循環裏面要將k求好
		J += np.sum(first_term-second_term) #累加求m,sum是在求k
	
	J=J/m
	
	J = J + (l/(2*m)*(np.sum(np.power(theta1[:,1:],2))+np.sum(np.power(theta2[:,1:],2))) 
	#加上正則優化項
	return J	
  1. 後向傳播的偏導數項
    後向傳播比較難以理解,代碼中使用的是一個一個樣本計算的方法。
    求代價函數的偏導數。

    先假設對一個樣本一個權重求偏導:
    假設神經網絡有四層,中間兩層爲隱藏層
    在這裏插入圖片描述
    一般化可以這樣表示:
    在這裏插入圖片描述

矢量化,因爲a此時不再只是一個數,而是所有樣本的數,所以要將其轉置。
在這裏插入圖片描述

再求前一層的偏導
在這裏插入圖片描述

在這裏插入圖片描述

代碼實現:

def sigmoid_gradient(z): #g的偏導數項
    return np.multiply(sigmoid(z),(1-sigmoid(z)))

def bp(params,in_size,h_size,label_nums,X,y_encoder,l):
	"""計算所有的代價函數對於θ的偏導數項
		Params:
			params:存放所有初始化theta1,theta2值的ndarray
			in_size:特徵值的數量
			h_szie:隱藏層的項數
			label_nums:總分類數
			X:特徵值數據
			y_encoder:轉換後的y
			l:lambda
		return
			J:代價函數
			grad:梯度值""""""
    m = X.shape[0]
    X = np.mat(X)
    y_encoder = np.mat(y_encoder)
    theta1 = np.mat(np.reshape(params[:(in_size+1)*h_size],(h_size,in_size+1))) #(25,401)
    theta2 = np.mat(np.reshape(params[(in_size+1)*h_size:],(label_nums,h_size+1)))#(10,26)
    
    a1,z2,a2,z3,h=forward(X,y_encoder,theta1,theta2)
    
    J=0
    for i in range(m):
        first = np.multiply(-y_encoder[i,:],np.log(h[i,:]))
        second = np.multiply((1-y_encoder)[i,:],np.log(1-h[i,:]))
        J += np.sum(first-second)
    J = J/m
    
    reg_term = (np.sum(np.power(theta1[:,1:],2)) + np.sum(np.power(theta2[:,1:],2)))*(float(l)/(2*m))
    
    J += reg_term
    
    delta2 = np.zeros(theta2.shape) #(25,401) #初始化梯度2
    delta1 = np.zeros(theta1.shape) #(10,26) #初始化梯度1
    
    for t in range(m): #一個樣本一個樣本的進行計算
        a1t = a1[t,:] #(1,401) #拿出第一個樣本的值
        z2t = z2[t,:] #(1,25)
        a2t = a2[t,:] #(1,26)
        z3t = z3[t,:] #(1,10)
        ht = h[t,:] #(1,10)
        yt = y_encoder[t,:] #(1,10)
        
        d3 = ht - yt #(1,10) #計算δ(3)
        z2t = np.insert(z2t,0,values=np.ones(1)) 
        d2 = np.multiply((theta2.T * d3.T).T,sigmoid_gradient(z2t) )
		#注意這裏是用的點乘,所以用multiply        
        delta1 = delta1 + d2[:,1:].T*a1t #偏導向1,因爲第一列不用計算
        delta2 = delta2 + d3.T*a2t #偏導項2
    delta1 = delta1/m
    delta2 = delta2/m
    
    delta1[:,1:] = delta1[:,1:] + (theta1[:,1:]*l)/m #正則優化
    delta2[:,1:] = delta2[:,1:] + (theta2[:,1:]*l)/m
    
    grad = np.concatenate((np.ravel(delta1),np.ravel(delta2)))
    return J,grad

if __name__ == '__main__':
	in_size = 400
	h_size=25
	label_nums=10
	l=1
	params = (np.random.random(size = h_size*(in_size+1)+label_nums*(h_size+1))-0.5)*0.25
	J,grad = bp(params,in_size,h_size,label_nums,X,y_encoder,l)
	print(grad.shape)
	

結果如下:
在這裏插入圖片描述

  1. 利用庫去擬合最優參數
from scipy.optimize import minimize

fmin = minimize(fun=bp,x0=params,args=(in_size,h_size,label_nums,X,y_encoder,l),method='TNC',jac=True,options={'maxiter':250})
fmin

在這裏插入圖片描述

  1. 通過h值來檢測準確度
X = np.mat(X)
theta1 = np.mat(np.reshape(fmin.x[:(in_size+1)*h_size],(h_size,in_size+1))) #(25,401)
theta2 = np.mat(np.reshape(fmin.x[(in_size+1)*h_size:],(label_nums,h_size+1)))#(10,26)
a1,z2,a2,z3,h=forward(X,y_encoder,theta1,theta2)
y_pred = np.array(np.argmax(h,axis=1)+1) #利用h來獲得結果,輸出可能性最大的值的索引,
#因爲我們的數字是從1開始到10
y_pred

在這裏插入圖片描述

  1. 測試精準度
correct = [1 if a == b else 0 for (a, b) in zip(y_pred, y)]
accuracy = (sum(map(int, correct)) / float(len(correct)))
print ('accuracy = {0}%'.format(accuracy * 100))

在這裏插入圖片描述

每一個代價函數對於權重的偏導數由兩個部分組成。
第一部分:z對於權重的偏導數
第二部分:代價函數對於z的偏導數
在這裏插入圖片描述

第一部分很好計算:
如果求z(i+1)對於權重 θ(i)的偏導,那就是a(i)
在這裏插入圖片描述

第二部分就比較難:
首先計算代價函數對於z的偏導可以利用鏈式求導法則,進行如下圖的分解。
因此,又分爲了兩個部分。
第一部分:a對於z求偏導
第二部分:代價函數對於a求偏導

第一部分:a(i)對於z(i)求偏導,由sigmoid函數的特點可知=a(i) *(1-a(i))
在這裏插入圖片描述

第二部分:若知道了最後一層的h值,則可以算出δ=h-y
然後從後往前推
比如現在又一個三層的神經網絡,我們通過前向傳播求出了a(3)
因此δ(3)的值就等於a(3)-y
又通過下圖可以知道,想要求出前面的一個代價函數關於z的偏導,就可以通過用δ(3) * θ(2)

在這裏插入圖片描述

然後將δ(3) * θ(2)和a(i) *(1-a(i))相乘就可以得出第二部分。然後再與第一部分相乘就可以得出第一個梯度。

然後令δ(3) * θ(2)*a(i) *(1-a(i))爲δ(2) 按照同樣的道理去計算出第二個梯度。

目前就只能理解到這裏。。。

參考資料:

  1. Ng機器學習
  2. 黃博筆記
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章