1. 程式人生 > >不用框架,python實現卷積神經網路

不用框架,python實現卷積神經網路

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

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

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

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

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

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


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

注:程式碼裡面的TODO是很多公式推導,我有空會敲出來,然後也作為超連結給弄出來,怕自己下次又給忘了。

我的總共有三個檔案:

這是我定義的全域性變數的檔案 gParam.py

#! /usr/bin/env python
# -*- coding: utf-8 -*-

TOP_PATH = '/media/autumn/Work/data/MNIST/mnist-png/'
LAB_PATH = '/media/autumn/Work/data/MNIST/mnist-png/label1.txt'
C_SIZE = 5
F_NUM = 12
P_SIZE = 2
FILE_TYPE = '.png'
MAX_ITER_NUM = 50

這是我測試的檔案myCnnTest.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-

from numpy import *
import numpy as np
from myCnn import Ccnn
import math
import gParam

# code
cLyNum = 20
pLyNum = 20
fLyNum = 100
oLyNum = 10
train_num = 800

myCnn = Ccnn(cLyNum, pLyNum, fLyNum, oLyNum)
ylabel = myCnn.read_label(gParam.LAB_PATH)
for iter0 in range(gParam.MAX_ITER_NUM):
	for i in range(train_num):
		data = myCnn.read_pic_data(gParam.TOP_PATH, i)	
		#print shape(data)
		ylab = int(ylabel[i])
		d_m, d_n = shape(data)
		m_c = d_m - gParam.C_SIZE + 1
		n_c = d_n - gParam.C_SIZE + 1
		m_p = m_c/myCnn.pSize
		n_p = n_c/myCnn.pSize
		state_c = zeros((m_c, n_c,myCnn.cLyNum))
		state_p = zeros((m_p, n_p, myCnn.pLyNum))
		for n in range(myCnn.cLyNum):
			state_c[:,:,n] = myCnn.convolution(data, myCnn.kernel_c[:,:,n])
			#print shape(myCnn.cLyNum)
			tmp_bias = ones((m_c,n_c)) * myCnn.cLyBias[:,n]
			state_c[:,:,n] = np.tanh(state_c[:,:,n] + tmp_bias)# 加上偏置項然後過啟用函式
			state_p[:,:,n] = myCnn.pooling(state_c[:,:,n],myCnn.pooling_a)
		state_f, state_f_pre = myCnn.convolution_f1(state_p,myCnn.kernel_f, myCnn.weight_f)
		#print shape(state_f), shape(state_f_pre)
		#進入啟用函式
		state_fo = zeros((1,myCnn.fLyNum))#全連線層經過啟用函式的結果	
		for n in range(myCnn.fLyNum):
				state_fo[:,n] = np.tanh(state_f[:,:,n] + myCnn.fLyBias[:,n])
		#進入softmax層
		output = myCnn.softmax_layer(state_fo)
		err = -output[:,ylab]				
		#計算誤差
		y_pre = output.argmax(axis=1)
		#print output	
		#計算誤差		
		#print err 
		myCnn.cnn_upweight(err,ylab,data,state_c,state_p,\
							state_fo, state_f_pre, output)
		# print myCnn.kernel_c
		# print myCnn.cLyBias
		# print myCnn.weight_f
		# print myCnn.kernel_f
		# print myCnn.fLyBias
		# print myCnn.weight_output						
		
# predict
test_num = []
for i in range(100):
	test_num.append(train_num+i+1)

for i in test_num:
	data = myCnn.read_pic_data(gParam.TOP_PATH, i)	
	#print shape(data)
	ylab = int(ylabel[i])
	d_m, d_n = shape(data)
	m_c = d_m - gParam.C_SIZE + 1
	n_c = d_n - gParam.C_SIZE + 1
	m_p = m_c/myCnn.pSize
	n_p = n_c/myCnn.pSize
	state_c = zeros((m_c, n_c,myCnn.cLyNum))
	state_p = zeros((m_p, n_p, myCnn.pLyNum))
	for n in range(myCnn.cLyNum):
		state_c[:,:,n] = myCnn.convolution(data, myCnn.kernel_c[:,:,n])
		#print shape(myCnn.cLyNum)
		tmp_bias = ones((m_c,n_c)) * myCnn.cLyBias[:,n]
		state_c[:,:,n] = np.tanh(state_c[:,:,n] + tmp_bias)# 加上偏置項然後過啟用函式
		state_p[:,:,n] = myCnn.pooling(state_c[:,:,n],myCnn.pooling_a)
	state_f, state_f_pre = myCnn.convolution_f1(state_p,myCnn.kernel_f, myCnn.weight_f)
	#print shape(state_f), shape(state_f_pre)
	#進入啟用函式
	state_fo = zeros((1,myCnn.fLyNum))#全連線層經過啟用函式的結果	
	for n in range(myCnn.fLyNum):
			state_fo[:,n] = np.tanh(state_f[:,:,n] + myCnn.fLyBias[:,n])
	#進入softmax層
	output = myCnn.softmax_layer(state_fo)	
	#計算誤差
	y_pre = output.argmax(axis=1)
	print '真實數字為%d',ylab, '預測數字是%d', y_pre
	






		
		

接下來是CNN的核心程式碼,裡面有中文註釋,檔名是myCnn.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-

from numpy import *
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mgimg
import math
import gParam
import copy
import scipy.signal as signal


# createst uniform random array w/ values in [a,b) and shape args
# return value type is ndarray
def rand_arr(a, b, *args): 
    np.random.seed(0) 
    return np.random.rand(*args) * (b - a) + a

# Class Cnn     
class Ccnn:
	def __init__(self, cLyNum, pLyNum,fLyNum,oLyNum):
		self.cLyNum = cLyNum
		self.pLyNum = pLyNum
		self.fLyNum = fLyNum
		self.oLyNum = oLyNum
		self.pSize = gParam.P_SIZE
		self.yita = 0.01
		self.cLyBias = rand_arr(-0.1, 0.1, 1,cLyNum)
		self.fLyBias = rand_arr(-0.1, 0.1, 1,fLyNum)
		self.kernel_c = zeros((gParam.C_SIZE,gParam.C_SIZE,cLyNum))
		self.kernel_f = zeros((gParam.F_NUM,gParam.F_NUM,fLyNum))
		for i in range(cLyNum):
			self.kernel_c[:,:,i] = rand_arr(-0.1,0.1,gParam.C_SIZE,gParam.C_SIZE)
		for i in range(fLyNum):
			self.kernel_f[:,:,i] = rand_arr(-0.1,0.1,gParam.F_NUM,gParam.F_NUM)
		self.pooling_a = ones((self.pSize,self.pSize))/(self.pSize**2)	
		self.weight_f = rand_arr(-0.1,0.1, pLyNum, fLyNum)
		self.weight_output = rand_arr(-0.1,0.1,fLyNum,oLyNum)
	def read_pic_data(self, path, i):
		#print 'read_pic_data'
		data = np.array([])
		full_path = path + '%d'%i + gParam.FILE_TYPE
		try:
			data = mgimg.imread(full_path) #data is np.array
			data = (double)(data)
		except IOError:
			raise Exception('open file error in read_pic_data():', full_path)
		return data		
	def read_label(self, path):
		#print 'read_label'
		ylab = []
		try:
			fobj = open(path, 'r')
			for line in fobj:
				ylab.append(line.strip())
			fobj.close()
		except IOError:
			raise Exception('open file error in read_label():', path)		
		return ylab		
	#卷積層
	def convolution(self, data, kernel):
		data_row, data_col = shape(data)
		kernel_row, kernel_col = shape(kernel)
		n = data_col - kernel_col
		m = data_row - kernel_row
		state = zeros((m+1, n+1))
		for i in range(m+1):
			for j in range(n+1):
				temp = multiply(data[i:i+kernel_row,j:j+kernel_col], kernel)
				state[i][j] = temp.sum()
		return state		
	# 池化層			
	def pooling(self, data, pooling_a):		
		data_r, data_c = shape(data)
		p_r, p_c = shape(pooling_a)
		r0 = data_r/p_r
		c0 = data_c/p_c
		state = zeros((r0,c0))
		for i in range(c0):
			for j in range(r0):
				temp = multiply(data[p_r*i:p_r*i+1,p_c*j:p_c*j+1],pooling_a)
				state[i][j] = temp.sum()
		return state
	#全連線層
	def convolution_f1(self, state_p1, kernel_f1, weight_f1):
		#池化層出來的20個特徵矩陣乘以池化層與全連線層的連線權重進行相加
		#wx(這裡的偏置項=0),這個結果然後再和全連線層中的神經元的核
		#進行卷積,返回值:
		#1:全連線層卷積前,只和weight_f1相加之後的矩陣
		#2:和全連線層卷積完之後的矩陣		
		n_p0, n_f = shape(weight_f1)#n_p0=20(是Feature Map的個數);n_f是100(全連線層神經元個數)
		m_p, n_p, pCnt = shape(state_p1)#這個矩陣是三維的
		m_k_f1, n_k_f1,fCnt = shape(kernel_f1)#12*12*100
		state_f1_temp = zeros((m_p,n_p,n_f))
		state_f1 = zeros((m_p - m_k_f1 + 1,n_p - n_k_f1 + 1,n_f))	
		for n in range(n_f):
			count = 0
			for m in range(n_p0):
				temp = state_p1[:,:,m] * weight_f1[m][n] 
				count = count + temp
			state_f1_temp[:,:,n] = count
			state_f1[:,:,n] = self.convolution(state_f1_temp[:,:,n], kernel_f1[:,:,n])	
		return state_f1, state_f1_temp	
	# softmax 層
	def softmax_layer(self,state_f1):
		# print 'softmax_layer'
		output = zeros((1,self.oLyNum))
		t1 = (exp(np.dot(state_f1,self.weight_output))).sum()
		for i in range(self.oLyNum):
			t0 = exp(np.dot(state_f1,self.weight_output[:,i]))
			output[:,i]=t0/t1
		return output	
	#誤差反向傳播更新權值
	def cnn_upweight(self,err_cost, ylab, train_data,state_c1, \
					state_s1, state_f1, state_f1_temp, output):
		#print 'cnn_upweight'
			m_data, n_data = shape(train_data)
			# softmax的資料請檢視 (TODO)
			label = zeros((1,self.oLyNum))
			label[:,ylab]	= 1 
			delta_layer_output = output - label
			weight_output_temp = copy.deepcopy(self.weight_output)
			delta_weight_output_temp = zeros((self.fLyNum, self.oLyNum))
			#print shape(state_f1)
			#更新weight_output			
			for n in range(self.oLyNum):
				delta_weight_output_temp[:,n] = delta_layer_output[:,n] * state_f1
			weight_output_temp = weight_output_temp - self.yita * delta_weight_output_temp
			
			#更新bais_f和kernel_f (推導公式請檢視 TODO)	
			delta_layer_f1 = zeros((1, self.fLyNum))
			delta_bias_f1 = zeros((1,self.fLyNum))
			delta_kernel_f1_temp = zeros(shape(state_f1_temp))
			kernel_f_temp = copy.deepcopy(self.kernel_f)			
			for n in range(self.fLyNum):
				count = 0
				for m in range(self.oLyNum):
					count = count + delta_layer_output[:,m] * self.weight_output[n,m]
				delta_layer_f1[:,n] = np.dot(count, (1 - np.tanh(state_f1[:,n])**2))	
				delta_bias_f1[:,n] = delta_layer_f1[:,n]
				delta_kernel_f1_temp[:,:,n] = delta_layer_f1[:,n] * state_f1_temp[:,:,n]
			# 1
			self.fLyBias = self.fLyBias - self.yita * delta_bias_f1
			kernel_f_temp = kernel_f_temp - self.yita * delta_kernel_f1_temp
			 
			#更新weight_f1
			delta_layer_f1_temp = zeros((gParam.F_NUM,gParam.F_NUM,self.fLyNum))
			delta_weight_f1_temp = zeros(shape(self.weight_f))
			weight_f1_temp = copy.deepcopy(self.weight_f)
			for n in range(self.fLyNum):
				delta_layer_f1_temp[:,:,n] = delta_layer_f1[:,n] * self.kernel_f[:,:,n]
			for n in range(self.pLyNum):
				for m in range(self.fLyNum):
					temp = delta_layer_f1_temp[:,:,m] * state_s1[:,:,n]
					delta_weight_f1_temp[n,m] = temp.sum()
			weight_f1_temp = weight_f1_temp - self.yita * delta_weight_f1_temp

			# 更新bias_c1
			n_delta_c = m_data - gParam.C_SIZE + 1
			delta_layer_p = zeros((gParam.F_NUM,gParam.F_NUM,self.pLyNum))
			delta_layer_c = zeros((n_delta_c,n_delta_c,self.pLyNum))
			delta_bias_c = zeros((1,self.cLyNum))
			for n in range(self.pLyNum):
				count = 0
				for m in range(self.fLyNum):
					count = count + delta_layer_f1_temp[:,:,m] * self.weight_f[n,m]
				delta_layer_p[:,:,n] = count
				#print shape(np.kron(delta_layer_p[:,:,n], ones((2,2))/4))
				delta_layer_c[:,:,n] = np.kron(delta_layer_p[:,:,n], ones((2,2))/4) \
									  * (1 - np.tanh(state_c1[:,:,n])**2)
				delta_bias_c[:,n] = delta_layer_c[:,:,n].sum()
			# 2
			self.cLyBias = self.cLyBias - self.yita * delta_bias_c
			#更新 kernel_c1
			delta_kernel_c1_temp = zeros(shape(self.kernel_c))
			for n in range(self.cLyNum):
				temp = delta_layer_c[:,:,n]
				r1 = map(list,zip(*temp[::1]))#逆時針旋轉90度			
				r2 = map(list,zip(*r1[::1]))#再逆時針旋轉90度
				temp = signal.convolve2d(train_data, r2,'valid')
				temp1 = map(list,zip(*temp[::1]))
				delta_kernel_c1_temp[:,:,n] = map(list,zip(*temp1[::1]))
			self.kernel_c = self.kernel_c - self.yita * delta_kernel_c1_temp							  					
			self.weight_f = weight_f1_temp
			self.kernel_f = kernel_f_temp
			self.weight_output = weight_output_temp				
			
		# predict
	def cnn_predict(self,data):
		return 
			
		

這是單獨解析MNIST的指令碼,analysisMNIST.py,修改相應的路徑後,執行能成功

#!/usr/bin/env python
# -*- coding: utf-8 -*-


from PIL import Image
import struct


def read_image(filename):
  f = open(filename, 'rb')


  index = 0
  buf = f.read()


  f.close()


  magic, images, rows, columns = struct.unpack_from('>IIII' , buf , index)
  index += struct.calcsize('>IIII')


  for i in xrange(images):
  #for i in xrange(2000):
    image = Image.new('L', (columns, rows))


    for x in xrange(rows):
      for y in xrange(columns):
        image.putpixel((y, x), int(struct.unpack_from('>B', buf, index)[0]))
        index += struct.calcsize('>B')


    print 'save ' + str(i) + 'image'
    image.save('/media/autumn/Work/data/MNIST/mnist-png/' + str(i) + '.png')


def read_label(filename, saveFilename):
  f = open(filename, 'rb')
  index = 0
  buf = f.read()


  f.close()


  magic, labels = struct.unpack_from('>II' , buf , index)
  index += struct.calcsize('>II')
  
  labelArr = [0] * labels
  #labelArr = [0] * 2000


  for x in xrange(labels):
  #for x in xrange(2000):
    labelArr[x] = int(struct.unpack_from('>B', buf, index)[0])
    index += struct.calcsize('>B')


  save = open(saveFilename, 'w')


  save.write(','.join(map(lambda x: str(x), labelArr)))
  save.write('\n')


  save.close()
  print 'save labels success'


if __name__ == '__main__':
  read_image('/media/autumn/Work/data/MNIST/mnist/t10k-images.idx3-ubyte')
  read_label('/media/autumn/Work/data/MNIST/mnist/t10k-labels.idx1-ubyte', '/media/autumn/Work/data/MNIST/mnist-png/label.txt')


最後:如果您想直接跑程式,您可以通過以下方式獲取我的資料和源程式。由於考慮到個人的人工成本,我形式上只收取2塊錢的人工費,既是對我的支援,也是對我的鼓勵。謝謝大家的理解。把訂單後面6位號碼傳送給我,我把原始碼和資料給您呈上。謝謝。

1:掃如下支付寶或微信二維碼,支付2元

2:把支付單號的後6位,以郵件傳送到我的郵箱[email protected]

3:您也可以在下方留言,把訂單號寫上來,我會核實。

謝謝大家。


相關推薦

不用框架python實現神經網路

最近學習了卷積神經網路,推薦一些比較好的學習資源 對於網址,我大部分學習的資源和數學公式都是來源於此,強烈推薦學習。 對於網址2,我下面的程式碼就是在其基礎上改寫的,作者是用matlab實現的,這對於不會matlab的同學而言,會比較費時,畢竟, 我們要做的是搞懂卷積神

利用Python實現神經網路的視覺化(附Python程式碼)

對於深度學習這種端到端模型來說,如何說明和理解其中的訓練過程是大多數研究者關注熱點之一,這個問題對於那種高風險行業顯得尤為重視,比如醫療、軍事等。在深度學習中,這個問題被稱作“黑匣子(Black Box)”。如果不能解釋模型的工作過程,我們怎麼能夠就輕易相信模型的輸出結果呢? 以深度學習模型檢測

[深度學習] Python實現神經網路- Convolution

[深度學習] Python實現卷積神經網路- Convolution 作者 sunsided github 地址: https://github.com/sunsided/python-conv2d import cv2 import numpy as np # load the

python實現神經網路層Conv2D實現(帶stride、padding)

關於卷積操作是如何進行的就不必多說了,結合程式碼一步一步來看卷積層是怎麼實現的。 程式碼來源:https://github.com/eriklindernoren/ML-From-Scratch   先看一下其基本的元件函式,首先是determine_padding(filter_shape, ou

Python CNN神經網路程式碼實現

1 # -*- coding: utf-8 -*- 2 """ 3 Created on Wed Nov 21 17:32:28 2018 4 5 @author: zhen 6 """ 7 8 import tensorflow as tf 9 from tensorflow.e

字元型圖片驗證碼使用tensorflow實現神經網路進行驗證碼識別CNN

本專案使用卷積神經網路識別字符型圖片驗證碼,其基於 TensorFlow 框架。它封裝了非常通用的校驗、訓練、驗證、識別和呼叫 API,極大地減低了識別字符型驗證碼花費的時間和精力。  專案地址: https://github.com/nickliqian/cnn_captcha

不用框架Python實現手寫數字識別

​ 有一句話說得好,要有造輪子的技術和用輪子的覺悟,今年來人工智慧火的不行,大家都爭相學習機器學習,作為學習大軍中的一員,我覺得最好的學習方法就是用python把機器學習演算法實現一遍,下面我介紹一下用邏輯迴歸實現手寫字型的識別。 邏輯迴歸知識點回顧

Tensorflow實現神經網路用於人臉關鍵點識別

今年來人工智慧的概念越來越火,AlphaGo以4:1擊敗李世石更是起到推波助瀾的作用。作為一個開挖掘機的菜鳥,深深感到不學習一下deep learning早晚要被淘汰。 既然要開始學,當然是搭一個深度神經網路跑幾個資料集感受一下作為入門最直觀了。自己寫程式碼實

深度學習、影象識別入門從VGG16神經網路開始

剛開始接觸深度學習、卷積神經網路的時候非常懵逼,不知道從何入手,我覺得應該有一個進階的過程,也就是說,理應有一些基本概念作為奠基石,讓你有底氣去完全理解一個龐大的卷積神經網路: 本文思路: 一、我認為學習卷積神經網路必須知道的幾個概念: 1、卷積過程: 我們經常說卷積神經網路卷積神經網路,到

《TensorFlow:實戰Google深度學習框架》——6.3 神經網路常用結構

1、卷積層 圖6-8顯示了卷積層神經網路結構中重要的部分:濾波器(filter)或者核心(kernel)。 過濾器可以將當前層神經網路上的一個子節點矩陣轉化為下一層神經網路上的一個單位節點矩陣 。 單位節點矩陣指的是一個長和寬都為1,但深度不限的節點矩陣 。 在一個卷積層巾,過濾器

《TensorFlow:實戰Google深度學習框架》——6.2 神經網路簡介(神經網路的基本網路結構及其與全連線神經網路的差異)

下圖為全連線神經網路與卷積神經網路的結構對比圖: 由上圖來分析兩者的差異:                  全連線神經網路與卷積網路相同點   &nb

《TensorFlow:實戰Google深度學習框架》——6.3 神經網路常用結構(池化層)

池化層在兩個卷積層之間,可以有效的縮小矩陣的尺寸(也可以減小矩陣深度,但實踐中一般不會這樣使用),co。池從而減少最後全連線層中的引數。 池化層既可以加快計算速度也可以防止過度擬合問題的作用。 池化層也是通過一個類似過濾器結構完成的,計算方式有兩種: 最大池化層:採用最

基於Python神經網路和特徵提取

基於Python的卷積神經網路和特徵提取 發表於2015-08-27 21:39| 4577次閱讀| 來源blog.christianperone.com/| 13 條評論| 作者Christian S.Peron 深度學習特徵提取神經網路Pythonnolea

基於cifar10實現神經網路影象識別

1 import tensorflow as tf 2 import numpy as np 3 import math 4 import time 5 import cifar10 6 import cifar10_input 7 """ 8 Create

Tensorflow實現神經網路

如果不明白什麼是卷積神經網路,請參考:計算機視覺與卷積神經網路 下面基於開源的實現簡單梳理如何用tensorflow實現卷積神經網路. 實現卷積神經網路 載入資料集 # 載入資料集 impor

TensorFlow學習筆記(5)--實現神經網路(MNIST資料集)

這裡使用TensorFlow實現一個簡單的卷積神經網路,使用的是MNIST資料集。網路結構為:資料輸入層–卷積層1–池化層1–卷積層2–池化層2–全連線層1–全連線層2(輸出層),這是一個簡單但非常有代表性的卷積神經網路。 import tensorflow

機器學習筆記:tensorflow實現神經網路經典案例--識別手寫數字

從識別手寫數字的案例開始認識神經網路,並瞭解如何在tensorflow中一步步建立卷積神經網路。 安裝tensorflow 資料來源 kaggle新手入門的數字識別案例,包含手寫0-9的灰度值影象的csv檔案,下載地址:https://www.

深度學習筆記5-tensorflow實現神經網路

深度學習筆記5-tensorflow實現卷積神經網路 在股票等預測模型中,可以從原始資料提取金融因子等特徵。而影象則無有效特徵,只能藉助SIFT、HOG等提取有效特徵,再集合SVM等機器學習演算法進行影象識別。卷積神經網路(CNN)提取的特徵則可以達到更好的效果,同時它不需要將特徵提取和

手動實現神經網路中的操作(conv2d)

寫這個的原因:一來好像沒怎麼搜到別人手動實現,作為補充;二來鞏固一下基礎。 卷積操作示意 先從一張示意圖說起,卷積基礎概念和操作步驟就不囉嗦了,只講這張圖,大意就是,有in-channel,有out-channel,你需要把in-channel都做卷積操作,然

Pytorch實現神經網路CNN

Pytorch是torch的Python版本,對TensorFlow造成很大的衝擊,TensorFlow無疑是最流行的,但是Pytorch號稱在諸多效能上要優於TensorFlow,比如在RNN的訓練上,所以Pytorch也吸引了很多人的關注。之前有一篇關於TensorF