__author__ = 'sjs'
import numpy as np
from datetime import datetime
import os
from PIL import Image
def new_str():
return datetime.now().strftime('%b-%d-%y %H:%M:%S')
def logistic(x):
return 1 / (1 + np.exp(-x))
def logistic_derivative(x):
return x*(1-x)
def tanh(x):
return np.tanh(x)
def tanh_derivative(x):
return 1-x**2
class NetLayer:
'''
网络层封装
管理当前网络层的神经元列表
'''
#神经网络层初始化
def __init__(self, len_node, in_count, default='sigmoid',mu=0,sigma=0.5,bias=True):
'''
:param len_node: 当前层的神经元数
:param in_count: 当前层的输入数
:bias为偏置项
'''
#如果是sigmoid
if default=='sigmoid':
self.nonlinear = (logistic, logistic_derivative)
#如果是tanh
elif default=='tanh':
self.nonlinear = (tanh, tanh_derivative)
self.bias = bias
#如果bias为真,则输入层数加1
if bias:
in_count += 1# bias
#权重矩阵初始化
self.weights = np.reshape(np.random.normal(mu, sigma, len_node*in_count), (len_node, in_count))
#残差初始化
self.deltas_item = np.zeros(len_node)
# 记录下一层的引用,方便递归操作
self.next_layer = None
#输入输出初始化
self.input = np.array([])
self.output = np.array([])
#递归计算输出值
def calc_output(self, x):
if self.bias:
self.input = np.hstack((x, np.ones((len(x),1))))
else:
self.input = x
self.output = self.nonlinear[0](np.dot(self.input, self.weights.T))
if self.next_layer is not None:
return self.next_layer.calc_output(self.output)
return self.output
#递归更新权重
def update_weight(self, learning_rate, target):
'''
更新当前网络层及之后层次的权重
使用了递归来操作,所以要求外面调用时必须从网络层的第一层(输入层的下一层)来调用
:param learning_rate: 学习率
:param target: 输出值
'''
self.deltas_item = self.nonlinear[1](self.output)
if self.next_layer is None:
self.deltas_item *= (target - self.output )
else:
self.deltas_item *= self.next_layer.update_weight(learning_rate, target)
#计算出weight应当变化的量,w_add的大小为当前层weight的大小,即i*j,这个值是len(target)个变量作用的结果
w_add = np.dot(self.deltas_item.T, self.input)
w_add *= learning_rate
self.weights +=w_add
weights = self.weights if not self.bias else self.weights[:, :-1]
return np.dot(self.deltas_item, weights)
class NeuralNetWork:
#初始化,构造输入规模的神经网络
def __init__(self, layers):
self.initLayers=[]
self.layers = []
self.construct_network(layers)
self.kind=layers[-1]
pass
def construct_network(self, layers):
last_layer = None
for i, layer in enumerate(layers):
if i == 0:
continue
cur_layer = NetLayer(layer, layers[i-1])
self.layers.append(cur_layer)
if last_layer is not None:
last_layer.next_layer = cur_layer
last_layer = cur_layer
def fit(self, x_train, y_train,learning_rate=0.01, epochs=500,mode='shuffle'):
'''
训练网络, 默认按顺序来训练
方法 1:按训练数据顺序来训练
方法 2: 随机选择测试
:param x_train: 输入数据
:param y_train: 输出数据
:param learning_rate: 学习率
:param epochs:权重更新次数
'''
y_trainformat=format_y(y_train,self.kind)
if mode=='shuffle':
indices = np.arange(len(y_train))
np.random.shuffle(indices)
length = 100
accper=0.0
cishu=0
while accper < 0.95:
for index in range(len(indices)//length):
indexes = indices[index*length: (index+1)*length]
self.layers[0].calc_output(x_train[indexes])
self.layers[0].update_weight(learning_rate, y_trainformat[indexes])
accper=self.show_test(x_train,y_train)
print(new_str(),"epochs", cishu)
print('准确率',self.show_test(x_train,y_train))
cishu +=1
if cishu > epochs:
break
def show_test(self, x_test, y_test):
predict = self.predict(x_test)
predicts = []
for p in predict:
predicts.append(unformat_y(p))
predicts = np.array(predicts)
ok_cnt = sum([1 for i in range(len(predicts)) if predicts[i] == y_test[i]])
return float(ok_cnt)/len(predicts)
def predict(self, x):
return self.layers[0].calc_output(x)
def format_y(data,kind):
y_tmp = np.zeros((len(data), kind))
for i in range(len(data)):
y_tmp[i, data[i]] = 1
return y_tmp
def unformat_y(data):
#找到最大的那一项
m = max(data)
for j, val in enumerate(data):
if val == m:
return j
#出现意外返回-1
return -1
def getimdata(imfile):
#读取图片
im=Image.open(imfile)
return list(map((lambda x:x/255),im.getdata()))
def getDigitData(patharg):
X=list()
Y=list()
filelist=os.listdir(patharg)
for i in filelist:
#flag为这张图片代表几
flag=i.split('_')[0]
Y.append(int(flag))
resx=getimdata(patharg+i)
X.append(resx)
return np.array(X),np.array(Y)
#start
X,Y=getDigitData(r'smallhandscriptdata/')
Xtest,Ytest=getDigitData(r'test/')
bp=NeuralNetWork([28*28,400,300,10])
bp.fit(X,Y)
print('###########################################')
res=bp.predict(Xtest)
for i in range(len(res)):
print('实际结果:',Ytest[i],' 预测结果:',unformat_y(res[i]))