如果一个简单的线性分类器不能对数据进行划分,我们就需要使用多个线性分类器来划分数据;使用多个分类器一起工作,这是神经网络的核心思想。
神经元不会立刻有输入就产生反应,而是会抑制输出,知道输入增强,强大到可以触发输出,一般我们会用sigmod函数来模拟阶跃函数。
输入到下一层结果矩阵中的信号,可以表示为X = W·I,W表示权值矩阵,I表示输入矩阵。这样一来,第二层的最终输出就称为O = sigmod(X)
神经网络通过调整链接权重进行学习,这种方法由误差引导。
内部节点相关联的误差:一种方法是按照链接权重的比例来分割输出层的误差,然后在每个内部节点处重组这些误差。(反向传播误差)
反向传播误差和前向馈送信号都可以使用矩阵实现。
梯度下降法是求解函数最小值的一种很好的办法,函数有很多参数的时候,这种方法仍然可以使用。
两个很常见的问题是饱和和零值权重:大信号(可能由大权重导致)导致了应用在信号上的激活函数的斜率变得非常平缓,这会降低神经网络学习到更好权重的能力;零权值的问题可能导致网络丧失学习更好权重的能力。
输入应该调整到较小值(参考sigmod函数的近0点),但不能为0;输出应该在激活函数能生成的值的范围内。
代码逻辑:
通过反向传播误差来实现对神经网络链接权值的更新
代码输入节点,隐藏层节点,输出层节点分别为784,200,10个,目前的代码是通过调整了训练次数,学习率,隐藏层节点数量之后形成的,拥有最好的学习效果的模型,预测的准确率可以达到96%以上
import numpy
import scipy.special
class neuralNetwork:
def __init__(self, inputNode, hiddenNode, outputNode, learningRate):
self.inodes = inputNode
self.hnodes = hiddenNode
self.onodes = outputNode
# 设置权重 input--hidden
self.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))
# 设置权重 input--hidden
self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))
# learning rate
self.lr = learningRate
# activation function
self.activation_fun = lambda x:scipy.special.expit(x)
pass
def train(self, inputs_list, targets_list):
# 将输入的矩阵转换为numpy二维矩阵
inputs = numpy.array(inputs_list, ndmin=2).T
targets = numpy.array(targets_list, ndmin=2).T
# 计算输入隐藏层的信号,隐藏层输出的信号
hiddenInputs = numpy.dot(self.wih, inputs)
hiddenOutputs = self.activation_fun(hiddenInputs)
# 计算输入输出层的信号,输出层输出的信号
final_inputs = numpy.dot(self.who, hiddenOutputs)
final_outputs = self.activation_fun(final_inputs)
# 误差
outputError = targets - final_outputs
hiddenError = numpy.dot(self.who.T, outputError)
# 更新链接权重
self.who += self.lr * numpy.dot((outputError * final_outputs * (1.0 - final_outputs)), numpy.transpose(hiddenOutputs))
self.wih += self.lr * numpy.dot((hiddenError * hiddenOutputs * (1.0 - hiddenOutputs)), numpy.transpose(inputs))
pass
def query(self, inputs_list):
# 输入等于inputs_list的转置,ndmin表示数组的最小维度
inputs = numpy.array(inputs_list, ndmin=2).T
# 计算输入隐藏层的信号,隐藏层输出的信号
hidden_inputs = numpy.dot(self.wih, inputs)
hidden_outputs = self.activation_fun(hidden_inputs)
# 计算输入输出层的信号,输出层输出的信号
final_inputs = numpy.dot(self.who, hidden_outputs)
final_outputs = self.activation_fun(final_inputs)
return final_outputs
if __name__ == '__main__':
# 定义参数
inputNodes = 784
hiddenNodes = 200
outputNodes = 10
learningRate = 0.2
n = neuralNetwork(inputNodes, hiddenNodes, outputNodes, learningRate)
# 导入训练数据集
trainning_data_file = open("/Users/lizhihan/PycharmProjects/NeuralNetwork/data/mnist_train.csv", "r")
trainning_data_list = trainning_data_file.readlines()
trainning_data_file.close()
# 导入测试数据集
test_data_file = open("/Users/lizhihan/PycharmProjects/NeuralNetwork/data/mnist_test.csv", "r")
test_data_list = test_data_file.readlines()
test_data_file.close()
# 训练神经网络
times = 10
for episode in range(times):
for record in trainning_data_list:
# 构建输入
all_values = record.split(',')
inputs = (numpy.asfarray(all_values[1:])/255.0*0.99+0.01)
# 构建目标输出
targets = numpy.zeros(outputNodes)+0.01
targets[int(all_values[0])] = 0.99
# 训练
n.train(inputs, targets)
pass
pass
# # 简单的测试
# test_value = test_data_list[0].split(",")
# print("目标值为:", test_value[0])
# print(n.query((numpy.asfarray(test_value[1:]))/255.0*0.99)+0.01)
# 一个真实的测试
# 先设置计分卡
scordCard = []
#遍历test中的所有数据
for record in test_data_list:
# 打印正确的数字
all_values = record.split(',')
correct_label = all_values[0]
# print(correct_label, "correct label!") # 在训练大量数据时设置为不显示
# 打印神经网络预测的数字
inputs = (numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
outputs = n.query(inputs) # 预测
label = numpy.argmax(outputs)
# print(label, "predicted label!") # 在训练大量数据时设置为不显示
# 实现记分卡
if(int(label) == int(correct_label)): # 注意本身的correct_label类型为str,label类型为numpy.int64,不能直接进行比较,需要进行格式转换
scordCard.append(1)
else:
scordCard.append(0)
pass
pass
# 输出得分卡记录的分数
scordCard_array = numpy.asarray(scordCard)
final_score = scordCard_array.sum()/scordCard_array.size
print("最终得分为", final_score)
最后补充训练数据和测试数据的下载地址:
测试数据
训练数据