天天看點

深度學習之BP神經網絡識别手寫數字(五)代碼運作結果參考

本節使用MNIST資料集作為輸入資料。

根據MNIST資料集的特性:

每張圖檔為28*28,其中大約有60000個手寫字型訓練樣本。因為是對數字的識别,是以輸出的範圍為0~9。這就類似于一個10分類的問題。

##建構神經網絡

輸入層需要28*28個節點,輸出成需要10個節點。對于隐藏層的層數以及節點數的判定是一個技術活。不過對于全連接配接網絡來說,一般隐藏層不要超過三層,當然如果層數越多,計算的難度肯定是越大。本次隻設定一個隐藏層。

而隐藏層的節點數目的确定,有幾個公式:

深度學習之BP神經網絡識别手寫數字(五)代碼運作結果參考

當然也沒有特定的确定方式,一般就是哪個效果好使用哪個。

本次隐藏層節點定為:300

是以網絡結構為:

Tables Cool
輸入層 784
隐藏層 300
輸出層 10

接着隻需要将MNIST的訓練資料按照節點一個個資料就可以了。

廢話不多說 看代碼。

代碼

getImage.py

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import struct
from bp import *
from datetime import datetime
import matplotlib.pyplot as plt

# 資料加載器基類
class Loader(object):
    def __init__(self, path, count):
        '''
        初始化加載器
        path: 資料檔案路徑
        count: 檔案中的樣本個數
        '''
        self.path = path
        self.count = count
    def get_file_content(self):
        '''
        讀取檔案内容
        '''
        f = open(self.path, 'rb')
        content = f.read()
        f.close()
        return content
    def to_int(self, byte):
        '''
        将unsigned byte字元轉換為整數
        '''
        return struct.unpack('B', byte)[0]
# 圖像資料加載器
class ImageLoader(Loader):
    def get_picture(self, content, index):
        '''
        内部函數,從檔案中擷取圖像
        '''
        ##從偏移量位置開始讀取有效資料
        start = index * 28 * 28 + 16

        picture = []
        for i in range(28):
            picture.append([])
            for j in range(28): 
                picture[i].append(
                    self.to_int(content[start + i * 28 + j]))
        #picture 結構 二位數組 28*28
        return picture
    def get_one_sample(self, picture):
        '''
        内部函數,将圖像轉化為樣本的輸入向量
        '''
        sample = []
        for i in range(28):
            for j in range(28):
                sample.append(picture[i][j])
        #将樣本
        return sample
    def load(self):
        '''
        加載資料檔案,獲得全部樣本的輸入向量
        '''
        #讀取所有的圖檔樣本
        content = self.get_file_content()
        data_set = []
        for index in range(self.count):
            data_set.append(
                self.get_one_sample(
                    self.get_picture(content, index)))
        return data_set
# 标簽資料加載器
class LabelLoader(Loader):
    def load(self):
        '''
        加載資料檔案,獲得全部樣本的标簽向量
        '''
        content = self.get_file_content()
        labels = []
        for index in range(self.count):
            labels.append(self.norm(content[index + 8]))
        return labels
    def norm(self, label):
        '''
        内部函數,将一個值轉換為10維标簽向量
        '''
        label_vec = []
        label_value = self.to_int(label)
        for i in range(10):
            if i == label_value:
                label_vec.append(0.9)
            else:
                label_vec.append(0.1)
        return label_vec

def get_training_data_set():
    '''
    獲得訓練資料集
    '''
    image_loader = ImageLoader('train-images.idx3-ubyte', 60000)
    label_loader = LabelLoader('train-labels.idx1-ubyte', 60000)
    return image_loader.load(), label_loader.load()

def get_test_data_set():
    '''
    獲得測試資料集
    '''
    image_loader = ImageLoader('t10k-images.idx3-ubyte', 10000)
    label_loader = LabelLoader('t10k-labels.idx1-ubyte', 10000)
    return image_loader.load(), label_loader.load()
           

netWork.py

# coding=utf-8
import numpy as np
import getImage as gim
#全連接配接神經網絡層類
class BPLayer(object):
	def __init__(self, input_size, output_size, activator):
		'''
		input_siez:本層輸入向量次元
		output_size:本層輸出向量次元
		activator:本層激活函數
		'''
		self.input_size = input_size;
		self.output_size = output_size;
		self.activator = activator;
		#權值數組(範圍-0.1~0.1)
		self.W = (np.random.rand(output_size, input_size)-0.5)*2;
		#偏執項
		self.B = np.zeros((output_size, 1));
		#輸出向量
		self.output = np.zeros((output_size, 1));
		return;

	def forward(self, input_array):
		'''
		向前運算
		'''
		self.input = input_array;
		self.output = self.activator.forward(np.dot(self.W, self.input)+self.B);
		return;

	def backward(self, detal_array):
		'''
		向後運算
		'''
		self.detal = self.activator.backward(self.input)*np.dot(self.W.T, detal_array);
		self.W_grad = np.dot(detal_array, self.input.T);
		self.B_grad = detal_array;
		return;

	def update(self, learning_rate):
		'''
		更新權重
		'''
		self.W +=learning_rate*self.W_grad;
		self.B +=learning_rate*self.B_grad;
		return;

#激活函數類
class SigmoidActivator(object):
	def forward(self, x):
		return 1/(1+np.exp(-x));

	def backward(self, x):
		return x*(1-x);

#BP神經網絡類
class BPNetWork(object):
	def __init__(self, layers):
		self.layers = [];
		for i in range(len(layers)-1):
			self.layers.append(BPLayer(layers[i], layers[i+1], SigmoidActivator()));

	def predict(self, sample):
		'''
		預測實作
		'''
		output = sample;
		for layer in self.layers:
			layer.forward(output);
			output = layer.output;
		return output;

	def train(self, labels, data_set, rate, epoch):
		'''
		訓練網絡
		'''
		for i in range(epoch):
			for d in range(len(data_set)):
				#按照矩陣乘的結構具狀資料 W [300行*784列]  input[1行*784列]
				self.train_one_sample(np.array([labels[d]]).T, np.array([data_set[d]]).T, rate);
##				self.train_one_sample(labels[d], data_set[d], rate);
		return;

	def train_one_sample(self, label, date, rate):
		self.predict(date);
		self.calc_gradient(label);
		self.update_w(rate);
		return;

	def calc_gradient(self, label):
		detal = self.layers[-1].activator.backward(self.layers[-1].output)*(label - self.layers[-1].output);
		for layer in self.layers[::-1]:
			layer.backward(detal);
			detal = layer.detal;
		return;

	def update_w(self, rate):
		for layer in self.layers:
			layer.update(rate);
		return;

def get_result(vec):
	max_value_index = 0;
	max_value = 0;
	for i in range(len(vec)):
		if vec[i] > max_value:
			max_value = vec[i];
			max_value_index = i;

	return max_value_index;

def evaluate(network, test_data_set, test_labels):
	error = 0;
	total = len(test_data_set);
	for index in range(total):
		label = get_result(test_labels[index]);
		predict = get_result(network.predict(np.array([test_data_set[index]]).T));
		if label != predict:
			error += 1;
	return float(error)/float(total);

def  train_and_evaluate():
	last_error_ratio = 1.0;
	epoch = 0;
	x_train,y_train = gim.get_training_data_set();
	x_test,y_test = gim.get_test_data_set();
	
	layers=[784,300,10];
	bpNet = BPNetWork(layers);

	while True:
		epoch += 1;

		bpNet.train(y_train, x_train, 0.3, 1);
		print 'epoch %d finished' % (epoch);

		if epoch % 3 == 0:
			error_ratio = evaluate(bpNet, x_test, y_test);
			print 'after epoch %d , error ratio is %f' % (epoch, error_ratio);

			if error_ratio > last_error_ratio:
				break;
			else:
				last_error_ratio = error_ratio;
	


if __name__ == '__main__':
	train_and_evaluate();
           

運作結果

深度學習之BP神經網絡識别手寫數字(五)代碼運作結果參考

訓練的效果很慢,目前也就達到這個水準。偷下懶O(∩_∩)O哈哈~

參考

零基礎入門深度學習(3) - 神經網絡和反向傳播算法

https://www.zybuluo.com/hanbingtao/note/476663

繼續閱讀