神经网络如何工作
预测器与分类器
预测器:接受输入,做出应有的预测,输出结果。根据结果与已知真实示例比较,得到误差,调整内部参数。
分类器:可以对输入进行分类。
简单线性分类器的限制:如果不能用一条直线把根本性的问题划分开来,就没用
神经元
观察表明,神经元不会立即反应,而是会抑制输入,直到输入增强,强到可以触发输出(阈值)。
一般使用S函数(Signoid Function):y = 1 / (1 + e^-x)
神经网络
第一层是输入层,只是输入而已,不做其它事,无需任何计算。
第二层是隐藏层
第三层是输出层
计算下一层的公式:X = W * I(W是权重矩阵),然后应用S函数
调整权重
反向传播:将误差通过神经网络,从输出反向传播到网络中。
梯度下降:通过偏层数,找到梯度为负的方向并前进。
权重变化式:△Wj,k = α · Ek · Ok(1 - Ok) · Oj^T
准备数据
由于S函数的值在0-1间且不可能等于0或1,所以输入值和目标值都必须在0-1间。
随机初始权重
数学家所得到的经验规则是,我们可以在一个节点传入链接数量平方根倒数的大致范围内随机采样,初始化权重。
禁止将初始权重设定为0,也禁止将其设定为相同的值。
使用Python进行DIY
神经网络类
NeuralNetwork.py文件,神经网络类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import numpy import scipy.special
class NeuralNetwork: def __init__(self, input_num, hidden_num, output_num, learning_rate): self.i_num = input_num self.h_num = hidden_num self.o_num = output_num self.lr = learning_rate self.wih = numpy.random.normal(0.0, pow(self.h_num, -0.5), (self.h_num, self.i_num)) self.who = numpy.random.normal(0.0, pow(self.o_num, -0.5), (self.o_num, self.h_num))
self.activation_func = lambda x: scipy.special.expit(x) self.inverse_activation_func = lambda x: scipy.special.logit(x)
pass
def train(self, inputs_list, targets_list): inputs = numpy.array(inputs_list, ndmin=2).T targets = numpy.array(targets_list, ndmin=2).T
hidden_outputs = self.activation_func(numpy.dot(self.wih, inputs))
final_outputs = self.activation_func(numpy.dot(self.who, hidden_outputs))
output_errors = targets - final_outputs hidden_errors = numpy.dot(self.who.T, output_errors)
self.who += self.lr * numpy.dot((output_errors * final_outputs * (1 - final_outputs)), numpy.transpose(hidden_outputs)) self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1 - hidden_outputs)), numpy.transpose(inputs)) pass
def query(self, inputs): hidden_inputs = numpy.dot(self.wih, inputs) hidden_outputs = self.activation_func(hidden_inputs) final_inputs = numpy.dot(self.who, hidden_outputs) final_outputs = self.activation_func(final_inputs) return final_outputs pass
|
包括初始化、训练、和查询
训练
使用Mnist手写数字数据集:http://yann.lecun.com/exdb/mnist/
CSV文件:https://pjreddie.com/projects/mnist-in-csv/
训练、测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import numpy import NeuralNetwork
training_file_loc = r'./MnistDataSets/mnist_train.csv' testing_file_loc = r'./MnistDataSets/mnist_test.csv' input_node_num = 784 hidden_node_num = 150 output_node_num = 10 learning_rate = 0.1 epochs = 2
n = NeuralNetwork.NeuralNetwork(input_node_num, hidden_node_num, output_node_num, learning_rate)
training_data_file = open(training_file_loc, 'r') training_data_list = training_data_file.readlines() training_data_file.close()
for e in range(epochs): for training_data in training_data_list: all_values = training_data.split(',') inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 targets = numpy.zeros(output_node_num) + 0.01 targets[int(all_values[0])] = 0.99 n.train(inputs, targets) pass pass
test_data_file = open(testing_file_loc, 'r') test_data_list = test_data_file.readlines() test_data_file.close()
score = 0 for test_data in test_data_list: all_values = test_data.split(',') correct_num = int(all_values[0]) outputs = n.query((numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01) output_num = numpy.argmax(outputs) if output_num == correct_num: score += 1 else: print("输出错误:将", correct_num, "识别为", output_num) pass pass print("分数:", score)
|
其它
向后查询
输入数字,生成图像:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def back_query(self, targets): final_outputs = numpy.array(targets, ndmin=2).T final_inputs = self.inverse_activation_func(final_outputs)
hidden_outputs = numpy.dot(self.who.T, final_inputs) hidden_outputs -= numpy.min(hidden_outputs) hidden_outputs /= numpy.max(hidden_outputs) hidden_outputs = hidden_outputs * 0.98 + 0.01 hidden_inputs = self.inverse_activation_func(hidden_outputs)
inputs = numpy.dot(self.wih.T, hidden_inputs) inputs -= numpy.min(inputs) inputs /= numpy.max(inputs) inputs = inputs * 0.98 + 0.01
return inputs
|
旋转图像
可以用Rotate函数将每个图像旋转正负10度,增强训练效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| for e in range(epochs): for training_data in training_data_list: all_values = training_data.split(',') inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 targets = numpy.zeros(output_node_num) + 0.01 targets[int(all_values[0])] = 0.99 n.train(inputs, targets) input_rotate_image_1 = scipy.ndimage.rotate(inputs.reshape(28, 28), 10, cval=0.01, reshape=False) input_rotate_image_2 = scipy.ndimage.rotate(inputs.reshape(28, 28), -10, cval=0.01, reshape=False) n.train(input_rotate_image_1.reshape(784), targets) n.train(input_rotate_image_2.reshape(784), targets) pass pass
|