输入28*28像素大小的数字图片,输出对应数字
思路:
1、构建三层(输出层、隐藏层、输出层)神经网络,创建网络权重和偏置
2、输入测试数据、训练数据,确定小批量训练数量、学习速率、迭代期
3、从训练数据中随机分批次选择小批量数据进行训练
4、每次迭代期结束时,将测试数据应用到当前网络并输出测试结果
import random
import numpy as np
import sys
class Network(object):
def __init__(self, sizes):#初始化Network
self.num_layers = len(sizes) #网络的层数
self.sizes = sizes #每层神经元个数
self.biases = [np.random.randn(y, 1) for y in sizes[1:]]
#随机2、3层偏置
self.weights = [np.random.randn(y, x)
for x, y in zip(sizes[:-1], sizes[1:])]
'''随机(1,2)、(2,3)层权值,weights中的每一个元素为y行x列矩阵,表示
表示对应的神经连接的权重'''
def feedforward(self, a):
for b, w in zip(self.biases, self.weights): #遍历网络权重和偏置
a = sigmoid(np.dot(w, a)+b)
#δ(z)计算输出a,a列表共10个数据,对应数字0~9的计算结果
return a
def SGD(self, training_data, epochs, mini_batch_size, eta,
test_data=None):
T=list(test_data) #测试数据
if test_data: n_test = len(T) #测试数据不为零时,n_test为测试数据的数量
ls=list(training_data) #用于训练的总数据
n = len(ls) #训练数据的数量
for j in range(epochs): #训练迭代期
random.shuffle(ls) #打乱训练数据
mini_batches = [
ls[k:k+mini_batch_size]
for k in range(0, n, mini_batch_size)]
#获取mini_batch_size数量的小批量测试数据
for mini_batch in mini_batches: #遍历小批量数据
self.update_mini_batch(mini_batch, eta)
#对每个数据开始训练,更新weight和biase,eta为学习速率
if T: #测试数据不为空时,第j次迭代期后的成功率
print ("Epoch {0}: {1} / {2}".format(
j, self.evaluate(T), n_test))
else:
print ("Epoch {0} complete".format(j))
def update_mini_batch(self, mini_batch, eta):
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
#创建与weights、biases格式一致的零矩阵列表,用于累加梯度
for x, y in mini_batch:
#获取单个测试数据中的(x,y),x为输入,y为期望输出
delta_nabla_b, delta_nabla_w = self.backprop(x, y)
#反向传播算法求出梯度
nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
#累加b,w梯度分量
self.weights = [w-(eta/len(mini_batch))*nw
for w, nw in zip(self.weights, nabla_w)]
self.biases = [b-(eta/len(mini_batch))*nb
for b, nb in zip(self.biases, nabla_b)]
#更新网络的weights和biases
def backprop(self, x, y):
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
activation = x
activations = [x] #存放每层激活值a=sigmoid(z)
zs = [] #存放每一层的z=w·x+b
for b, w in zip(self.biases, self.weights): #遍历网络权重和偏置
z = np.dot(w, activation)+b #计算每层带权输入z
zs.append(z)
activation = sigmoid(z) #每层激活值a
activations.append(activation)
delta = self.cost_derivative(activations[-1], y) * \
sigmoid_prime(zs[-1]) #计算最后一层L的差值是δ=▽Ca⊙σ'(z)(反向传播公式1)
nabla_b[-1] = delta #储存最后一层的梯度分量b=δ
nabla_w[-1] = np.dot(delta, activations[-2].transpose()) #储存最后一层的梯度分量w
for i in range(2, self.num_layers): #反向传播
z = zs[-i] #取出l层的带权输入z
sp = sigmoid_prime(z)
delta = np.dot(self.weights[-i+1].transpose(), delta) * sp #计算l层的差值(反向传播公式2)
nabla_b[-i] = delta #储存l层的梯度分量b(反向传播公式3)
nabla_w[-i] = np.dot(delta, activations[-i-1].transpose()) #储存l层的梯度分量w(反向传播公式4)
return (nabla_b, nabla_w)
#numpy.transpose()将矩阵转置
def evaluate(self, test_data):
test_results = [(np.argmax(self.feedforward(x)), y)
for (x, y) in test_data]
'''self.feedforward(x):计算测试数据中输入x在当前网络中的实际输出
np.argmax():找出实际输出中最大值的索引=0~9中最有可能的数字
test_results中记录实际输出和期望输出'''
return sum(int(x == y) for (x, y) in test_results)
#逐个比较test_results中的实际输出x和期望输出y相等则int(x==y)值为1
#sum()将测试数据中符合期望输出的个数累加完成后返回
def cost_derivative(self, output_activations, y):
return (output_activations-y)
def sigmoid(z):
return (1.0/(1.0+np.exp(-z)))
def sigmoid_prime(z): #sigmoid(z)的导数
return sigmoid(z)*(1-sigmoid(z))
def main():
import mnist_loader
training_data,validation_data,test_data=mnist_loader.load_data_wrapper()
#读入数据
net=Network([784,30,10])
#net网络输入:784个输入神经元(28*28像素),隐藏层30个神经元,10个输出神经元
net.SGD(training_data,30,10,3.0,test_data=test_data)
#调用函数训练样本
main()
函数记录:
np.random.randn(x,y):随机生成正态分布元素的x行y列矩阵
zip(x,y):拼接举证x,y,用于一次循环遍历两组数据
np.dot(x,y):x和y的点积
np.random.shuffle(x):打乱矩阵x元素
np.zeros(x.shape):生成x的同型零矩阵
np.argmax(x):输出列表中最大元素的索引
np.transpose()矩阵转置