python實現卷積神經網絡


最近學習了卷積神經網絡,推薦一些比較好的學習資源

1: https://www.zybuluo.com/hanbingtao/note/485480

2: http://blog.csdn.net/u010540396/article/details/52895074

對於網址,我大部分學習的資源和數學公式都是來源於此,強烈推薦學習。

對於網址2,我下面的代碼就是在其基礎上改寫的,作者是用matlab實現的,這對於不會matlab的同學而言,會比較費時,畢竟,

我們要做的是搞懂卷積神經網絡,而不是某一個編程語言。

而且最重要的是,我自己想弄明白CNN的前向網絡和誤差反向傳播算法,自己親自實現一遍,更有助於理解和記憶,哪怕是看着別人的代碼學會的。

 

A:下面代碼實現是LenNet-5的代碼,但是只有一個卷積層,一個mean-pooling層,和一個全連接層,出來經過softmax層。

B:使用的數據集是MNIST,你可以到http://yann.lecun.com/exdb/mnist/

C:MNIST的數據解析,可以從我下面的analysisMNIST.py中修改路徑,謝謝(http://blog.csdn.net/u014046170/article/details/47445919)然后取得到數據如下情況:

D:在C解析完之后,我把label文件的內容轉置了,開始的時候是一行,我改成了一列。

 

注:代碼里面的TODO是很多公式推導,我有空會敲出來,然后也作為超鏈接給弄出來,怕自己下次又給忘了。

 

我的總共有三個文件:

這是我定義的全局變量的文件 gParam.py

 1 #! /usr/bin/env python  
 2 # -*- coding: utf-8 -*-  
 3   
 4 TOP_PATH = '/media/autumn/Work/data/MNIST/mnist-png/'  
 5 LAB_PATH = '/media/autumn/Work/data/MNIST/mnist-png/label1.txt'  
 6 C_SIZE = 5  
 7 F_NUM = 12  
 8 P_SIZE = 2  
 9 FILE_TYPE = '.png'  
10 MAX_ITER_NUM = 50  

這是我測試的文件myCnnTest.py

 1 #! /usr/bin/env python  
 2 # -*- coding: utf-8 -*-  
 3   
 4 from numpy import *  
 5 import numpy as np  
 6 from myCnn import Ccnn  
 7 import math  
 8 import gParam  
 9   
10 # code  
11 cLyNum = 20  
12 pLyNum = 20  
13 fLyNum = 100  
14 oLyNum = 10  
15 train_num = 800  
16   
17 myCnn = Ccnn(cLyNum, pLyNum, fLyNum, oLyNum)  
18 ylabel = myCnn.read_label(gParam.LAB_PATH)  
19 for iter0 in range(gParam.MAX_ITER_NUM):  
20     for i in range(train_num):  
21         data = myCnn.read_pic_data(gParam.TOP_PATH, i)    
22         #print shape(data)  
23         ylab = int(ylabel[i])  
24         d_m, d_n = shape(data)  
25         m_c = d_m - gParam.C_SIZE + 1  
26         n_c = d_n - gParam.C_SIZE + 1  
27         m_p = m_c/myCnn.pSize  
28         n_p = n_c/myCnn.pSize  
29         state_c = zeros((m_c, n_c,myCnn.cLyNum))  
30         state_p = zeros((m_p, n_p, myCnn.pLyNum))  
31         for n in range(myCnn.cLyNum):  
32             state_c[:,:,n] = myCnn.convolution(data, myCnn.kernel_c[:,:,n])  
33             #print shape(myCnn.cLyNum)  
34             tmp_bias = ones((m_c,n_c)) * myCnn.cLyBias[:,n]  
35             state_c[:,:,n] = np.tanh(state_c[:,:,n] + tmp_bias)# 加上偏置項然后過激活函數  
36             state_p[:,:,n] = myCnn.pooling(state_c[:,:,n],myCnn.pooling_a)  
37         state_f, state_f_pre = myCnn.convolution_f1(state_p,myCnn.kernel_f, myCnn.weight_f)  
38         #print shape(state_f), shape(state_f_pre)  
39         #進入激活函數  
40         state_fo = zeros((1,myCnn.fLyNum))#全連接層經過激活函數的結果      
41         for n in range(myCnn.fLyNum):  
42                 state_fo[:,n] = np.tanh(state_f[:,:,n] + myCnn.fLyBias[:,n])  
43         #進入softmax層  
44         output = myCnn.softmax_layer(state_fo)  
45         err = -output[:,ylab]                 
46         #計算誤差  
47         y_pre = output.argmax(axis=1)  
48         #print output     
49         #計算誤差         
50         #print err   
51         myCnn.cnn_upweight(err,ylab,data,state_c,state_p,\  
52                             state_fo, state_f_pre, output)  
53         # print myCnn.kernel_c  
54         # print myCnn.cLyBias  
55         # print myCnn.weight_f  
56         # print myCnn.kernel_f  
57         # print myCnn.fLyBias  
58         # print myCnn.weight_output                       
59           
60 # predict  
61 test_num = []  
62 for i in range(100):  
63     test_num.append(train_num+i+1)  
64   
65 for i in test_num:  
66     data = myCnn.read_pic_data(gParam.TOP_PATH, i)    
67     #print shape(data)  
68     ylab = int(ylabel[i])  
69     d_m, d_n = shape(data)  
70     m_c = d_m - gParam.C_SIZE + 1  
71     n_c = d_n - gParam.C_SIZE + 1  
72     m_p = m_c/myCnn.pSize  
73     n_p = n_c/myCnn.pSize  
74     state_c = zeros((m_c, n_c,myCnn.cLyNum))  
75     state_p = zeros((m_p, n_p, myCnn.pLyNum))  
76     for n in range(myCnn.cLyNum):  
77         state_c[:,:,n] = myCnn.convolution(data, myCnn.kernel_c[:,:,n])  
78         #print shape(myCnn.cLyNum)  
79         tmp_bias = ones((m_c,n_c)) * myCnn.cLyBias[:,n]  
80         state_c[:,:,n] = np.tanh(state_c[:,:,n] + tmp_bias)# 加上偏置項然后過激活函數  
81         state_p[:,:,n] = myCnn.pooling(state_c[:,:,n],myCnn.pooling_a)  
82     state_f, state_f_pre = myCnn.convolution_f1(state_p,myCnn.kernel_f, myCnn.weight_f)  
83     #print shape(state_f), shape(state_f_pre)  
84     #進入激活函數  
85     state_fo = zeros((1,myCnn.fLyNum))#全連接層經過激活函數的結果      
86     for n in range(myCnn.fLyNum):  
87             state_fo[:,n] = np.tanh(state_f[:,:,n] + myCnn.fLyBias[:,n])  
88     #進入softmax層  
89     output = myCnn.softmax_layer(state_fo)    
90     #計算誤差  
91     y_pre = output.argmax(axis=1)  
92     print '真實數字為%d',ylab, '預測數字是%d', y_pre  

接下來是CNN的核心代碼,里面有中文注釋,文件名是myCnn.py

  1 #! /usr/bin/env python  
  2 # -*- coding: utf-8 -*-  
  3   
  4 from numpy import *  
  5 import numpy as np  
  6 import matplotlib.pyplot as plt  
  7 import matplotlib.image as mgimg  
  8 import math  
  9 import gParam  
 10 import copy  
 11 import scipy.signal as signal  
 12   
 13   
 14 # createst uniform random array w/ values in [a,b) and shape args  
 15 # return value type is ndarray  
 16 def rand_arr(a, b, *args):   
 17     np.random.seed(0)   
 18     return np.random.rand(*args) * (b - a) + a  
 19   
 20 # Class Cnn       
 21 class Ccnn:  
 22     def __init__(self, cLyNum, pLyNum,fLyNum,oLyNum):  
 23         self.cLyNum = cLyNum  
 24         self.pLyNum = pLyNum  
 25         self.fLyNum = fLyNum  
 26         self.oLyNum = oLyNum  
 27         self.pSize = gParam.P_SIZE  
 28         self.yita = 0.01  
 29         self.cLyBias = rand_arr(-0.1, 0.1, 1,cLyNum)  
 30         self.fLyBias = rand_arr(-0.1, 0.1, 1,fLyNum)  
 31         self.kernel_c = zeros((gParam.C_SIZE,gParam.C_SIZE,cLyNum))  
 32         self.kernel_f = zeros((gParam.F_NUM,gParam.F_NUM,fLyNum))  
 33         for i in range(cLyNum):  
 34             self.kernel_c[:,:,i] = rand_arr(-0.1,0.1,gParam.C_SIZE,gParam.C_SIZE)  
 35         for i in range(fLyNum):  
 36             self.kernel_f[:,:,i] = rand_arr(-0.1,0.1,gParam.F_NUM,gParam.F_NUM)  
 37         self.pooling_a = ones((self.pSize,self.pSize))/(self.pSize**2)    
 38         self.weight_f = rand_arr(-0.1,0.1, pLyNum, fLyNum)  
 39         self.weight_output = rand_arr(-0.1,0.1,fLyNum,oLyNum)  
 40     def read_pic_data(self, path, i):  
 41         #print 'read_pic_data'  
 42         data = np.array([])  
 43         full_path = path + '%d'%i + gParam.FILE_TYPE  
 44         try:  
 45             data = mgimg.imread(full_path) #data is np.array  
 46             data = (double)(data)  
 47         except IOError:  
 48             raise Exception('open file error in read_pic_data():', full_path)  
 49         return data       
 50     def read_label(self, path):  
 51         #print 'read_label'  
 52         ylab = []  
 53         try:  
 54             fobj = open(path, 'r')  
 55             for line in fobj:  
 56                 ylab.append(line.strip())  
 57             fobj.close()  
 58         except IOError:  
 59             raise Exception('open file error in read_label():', path)         
 60         return ylab       
 61     #卷積層  
 62     def convolution(self, data, kernel):  
 63         data_row, data_col = shape(data)  
 64         kernel_row, kernel_col = shape(kernel)  
 65         n = data_col - kernel_col  
 66         m = data_row - kernel_row  
 67         state = zeros((m+1, n+1))  
 68         for i in range(m+1):  
 69             for j in range(n+1):  
 70                 temp = multiply(data[i:i+kernel_row,j:j+kernel_col], kernel)  
 71                 state[i][j] = temp.sum()  
 72         return state          
 73     # 池化層             
 74     def pooling(self, data, pooling_a):       
 75         data_r, data_c = shape(data)  
 76         p_r, p_c = shape(pooling_a)  
 77         r0 = data_r/p_r  
 78         c0 = data_c/p_c  
 79         state = zeros((r0,c0))  
 80         for i in range(c0):  
 81             for j in range(r0):  
 82                 temp = multiply(data[p_r*i:p_r*i+1,p_c*j:p_c*j+1],pooling_a)  
 83                 state[i][j] = temp.sum()  
 84         return state  
 85     #全連接層  
 86     def convolution_f1(self, state_p1, kernel_f1, weight_f1):  
 87         #池化層出來的20個特征矩陣乘以池化層與全連接層的連接權重進行相加  
 88         #wx(這里的偏置項=0),這個結果然后再和全連接層中的神經元的核  
 89         #進行卷積,返回值:  
 90         #1:全連接層卷積前,只和weight_f1相加之后的矩陣  
 91         #2:和全連接層卷積完之后的矩陣          
 92         n_p0, n_f = shape(weight_f1)#n_p0=20(是Feature Map的個數);n_f是100(全連接層神經元個數)  
 93         m_p, n_p, pCnt = shape(state_p1)#這個矩陣是三維的  
 94         m_k_f1, n_k_f1,fCnt = shape(kernel_f1)#12*12*100  
 95         state_f1_temp = zeros((m_p,n_p,n_f))  
 96         state_f1 = zeros((m_p - m_k_f1 + 1,n_p - n_k_f1 + 1,n_f))     
 97         for n in range(n_f):  
 98             count = 0  
 99             for m in range(n_p0):  
100                 temp = state_p1[:,:,m] * weight_f1[m][n]   
101                 count = count + temp  
102             state_f1_temp[:,:,n] = count  
103             state_f1[:,:,n] = self.convolution(state_f1_temp[:,:,n], kernel_f1[:,:,n])    
104         return state_f1, state_f1_temp    
105     # softmax 層  
106     def softmax_layer(self,state_f1):  
107         # print 'softmax_layer'  
108         output = zeros((1,self.oLyNum))  
109         t1 = (exp(np.dot(state_f1,self.weight_output))).sum()  
110         for i in range(self.oLyNum):  
111             t0 = exp(np.dot(state_f1,self.weight_output[:,i]))  
112             output[:,i]=t0/t1  
113         return output     
114     #誤差反向傳播更新權值  
115     def cnn_upweight(self,err_cost, ylab, train_data,state_c1, \  
116                     state_s1, state_f1, state_f1_temp, output):  
117         #print 'cnn_upweight'  
118             m_data, n_data = shape(train_data)  
119             # softmax的資料請查看 (TODO)  
120             label = zeros((1,self.oLyNum))  
121             label[:,ylab]   = 1   
122             delta_layer_output = output - label  
123             weight_output_temp = copy.deepcopy(self.weight_output)  
124             delta_weight_output_temp = zeros((self.fLyNum, self.oLyNum))  
125             #print shape(state_f1)  
126             #更新weight_output              
127             for n in range(self.oLyNum):  
128                 delta_weight_output_temp[:,n] = delta_layer_output[:,n] * state_f1  
129             weight_output_temp = weight_output_temp - self.yita * delta_weight_output_temp  
130               
131             #更新bais_f和kernel_f (推導公式請查看 TODO)     
132             delta_layer_f1 = zeros((1, self.fLyNum))  
133             delta_bias_f1 = zeros((1,self.fLyNum))  
134             delta_kernel_f1_temp = zeros(shape(state_f1_temp))  
135             kernel_f_temp = copy.deepcopy(self.kernel_f)              
136             for n in range(self.fLyNum):  
137                 count = 0  
138                 for m in range(self.oLyNum):  
139                     count = count + delta_layer_output[:,m] * self.weight_output[n,m]  
140                 delta_layer_f1[:,n] = np.dot(count, (1 - np.tanh(state_f1[:,n])**2))      
141                 delta_bias_f1[:,n] = delta_layer_f1[:,n]  
142                 delta_kernel_f1_temp[:,:,n] = delta_layer_f1[:,n] * state_f1_temp[:,:,n]  
143             # 1  
144             self.fLyBias = self.fLyBias - self.yita * delta_bias_f1  
145             kernel_f_temp = kernel_f_temp - self.yita * delta_kernel_f1_temp  
146                
147             #更新weight_f1  
148             delta_layer_f1_temp = zeros((gParam.F_NUM,gParam.F_NUM,self.fLyNum))  
149             delta_weight_f1_temp = zeros(shape(self.weight_f))  
150             weight_f1_temp = copy.deepcopy(self.weight_f)  
151             for n in range(self.fLyNum):  
152                 delta_layer_f1_temp[:,:,n] = delta_layer_f1[:,n] * self.kernel_f[:,:,n]  
153             for n in range(self.pLyNum):  
154                 for m in range(self.fLyNum):  
155                     temp = delta_layer_f1_temp[:,:,m] * state_s1[:,:,n]  
156                     delta_weight_f1_temp[n,m] = temp.sum()  
157             weight_f1_temp = weight_f1_temp - self.yita * delta_weight_f1_temp  
158   
159             # 更新bias_c1  
160             n_delta_c = m_data - gParam.C_SIZE + 1  
161             delta_layer_p = zeros((gParam.F_NUM,gParam.F_NUM,self.pLyNum))  
162             delta_layer_c = zeros((n_delta_c,n_delta_c,self.pLyNum))  
163             delta_bias_c = zeros((1,self.cLyNum))  
164             for n in range(self.pLyNum):  
165                 count = 0  
166                 for m in range(self.fLyNum):  
167                     count = count + delta_layer_f1_temp[:,:,m] * self.weight_f[n,m]  
168                 delta_layer_p[:,:,n] = count  
169                 #print shape(np.kron(delta_layer_p[:,:,n], ones((2,2))/4))  
170                 delta_layer_c[:,:,n] = np.kron(delta_layer_p[:,:,n], ones((2,2))/4) \  
171                                       * (1 - np.tanh(state_c1[:,:,n])**2)  
172                 delta_bias_c[:,n] = delta_layer_c[:,:,n].sum()  
173             # 2  
174             self.cLyBias = self.cLyBias - self.yita * delta_bias_c  
175             #更新 kernel_c1  
176             delta_kernel_c1_temp = zeros(shape(self.kernel_c))  
177             for n in range(self.cLyNum):  
178                 temp = delta_layer_c[:,:,n]  
179                 r1 = map(list,zip(*temp[::1]))#逆時針旋轉90度           
180                 r2 = map(list,zip(*r1[::1]))#再逆時針旋轉90度  
181                 temp = signal.convolve2d(train_data, r2,'valid')  
182                 temp1 = map(list,zip(*temp[::1]))  
183                 delta_kernel_c1_temp[:,:,n] = map(list,zip(*temp1[::1]))  
184             self.kernel_c = self.kernel_c - self.yita * delta_kernel_c1_temp                                                  
185             self.weight_f = weight_f1_temp  
186             self.kernel_f = kernel_f_temp  
187             self.weight_output = weight_output_temp               
188               
189         # predict  
190     def cnn_predict(self,data):  
191         return 

這是單獨解析MNIST的腳本,analysisMNIST.py,修改相應的路徑后,運行能成功

 1 #!/usr/bin/env python  
 2 # -*- coding: utf-8 -*-  
 3   
 4   
 5 from PIL import Image  
 6 import struct  
 7   
 8   
 9 def read_image(filename):  
10   f = open(filename, 'rb')  
11   
12   
13   index = 0  
14   buf = f.read()  
15   
16   
17   f.close()  
18   
19   
20   magic, images, rows, columns = struct.unpack_from('>IIII' , buf , index)  
21   index += struct.calcsize('>IIII')  
22   
23   
24   for i in xrange(images):  
25   #for i in xrange(2000):  
26     image = Image.new('L', (columns, rows))  
27   
28   
29     for x in xrange(rows):  
30       for y in xrange(columns):  
31         image.putpixel((y, x), int(struct.unpack_from('>B', buf, index)[0]))  
32         index += struct.calcsize('>B')  
33   
34   
35     print 'save ' + str(i) + 'image'  
36     image.save('/media/autumn/Work/data/MNIST/mnist-png/' + str(i) + '.png')  
37   
38   
39 def read_label(filename, saveFilename):  
40   f = open(filename, 'rb')  
41   index = 0  
42   buf = f.read()  
43   
44   
45   f.close()  
46   
47   
48   magic, labels = struct.unpack_from('>II' , buf , index)  
49   index += struct.calcsize('>II')  
50     
51   labelArr = [0] * labels  
52   #labelArr = [0] * 2000  
53   
54   
55   for x in xrange(labels):  
56   #for x in xrange(2000):  
57     labelArr[x] = int(struct.unpack_from('>B', buf, index)[0])  
58     index += struct.calcsize('>B')  
59   
60   
61   save = open(saveFilename, 'w')  
62   
63   
64   save.write(','.join(map(lambda x: str(x), labelArr)))  
65   save.write('\n')  
66   
67   
68   save.close()  
69   print 'save labels success'  
70   
71   
72 if __name__ == '__main__':  
73   read_image('/media/autumn/Work/data/MNIST/mnist/t10k-images.idx3-ubyte')  
74   read_label('/media/autumn/Work/data/MNIST/mnist/t10k-labels.idx1-ubyte', '/media/autumn/Work/data/MNIST/mnist-png/label.txt')  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM