- 迭代是什么:持续的,一点一点的改进答案的方法。
模型的概念:当我们不能精确知道一些事情如何运作时,我们可以尝试使用模型来估计其运作方法,模型往往是一个算法,里面包括了可以调整的参数
改进模型的方法:基于模型和已知真实示例之间的比较,得到模型偏移的误差值,调整参数。
- 预测器:接受输入,并做出应有的预测,输出结果
分类器:数据挖掘中对样本进行分类方式的统称
分类不同于预测,预测我们是希望得到的值尽可能接近我们期望的值
而分类一般是期望找到一个值能很好的区分不同类型的样本,而这个值
往往不同于样本值。
- 如何训练一个简单分类器?
首先:从分类器的线性函数开始
y=Ax
我们直到A的初始猜测值给出了错误的y值,而实际上y应该等于训练数据给出的值,我们将正确的期望值t称为目标值。而为了得到t值,我们需要对A进行稍微的调整
t=(A+▲A)x
误差值E=(期望目标值t-实际输出值y)
E=t-y
而我们希望找个一个式子能调整我们▲A,使得我们的实际输出值能接近目标期望值(误差值小),所以我们对E的表达式进行化简和变形
E=t-y=(A+▲A)x-Ax
E=(▲A)x
▲A=E/x
这就是我们寻找的式子。找到了基于当前误差值调整参数的方法。
问题:无论我们给什么训练数据,经过修改▲A,就可以很好的得到一个期望的值,但是,我们修改的值只会对最后一次训练的样本很匹配,而抛弃之前所有的学习结果。
解决:我们对参数A,不应该过于激烈的进行改进,而应该循循渐进,这样单一样本就不能主导错误样本的影响,这种自我节制的调整,还带来了一个好处,就是来自真实世界中的训练样本可能充满噪声和错误适度更新有助于限制这些错误样本的影响。
方法:在公式中加入一个调节系数,被称为学习率
▲A=L(E/x)
我们挑选一个合适的L,比如0.5,这样在第一训练时,我们改进A,而第二次训练时,我们基于前面一次改进的A上继续进行改进,这样我们就可以实现自动化的学习。
- 有时候一个分类器不足以解决问题:
如果数据本身不是由单一的线性过程支配,那么一个简单的线性分类器不能对数据进行划分。
下面一个将绿色区域划分问题
上面的问题可以一条直线可以划分
而这个问题则不能用一条直线解决,但解决方法很简单,也就是用多个线性分类器划分,在这里也就是用两条直线
神经网络就是用多个分类器组合构成的。
- 神经元不能表示成线性函数的原因:
生物神经元不能简单的对输入做出响应,生成输出。观察表明,神经元不会立即反应,而是会抑制输入,直到输入增强到足够大才触发输出。
有许多激活函数可以达到这种效果,例如一个简单的阶跃函数。
改进阶跃函数:相比于冷冰冰的阶跃函数,我们更多使用平滑的S※函数来制作神经网络,有时S函数也称为逻辑函数。
- 为什么把前后层的每一个神经元与其他所有其他层的神经元相互连接?
虽然可以提出创造性的方式把神经元之间连接,但我们不采用,有两个原因:
(1)这种完全连接形式事实上可以相对容易的编码成计算器指令
(2)神经网络的学习过程会弱化这些不需要的连接(就是这些连接权重趋于0)
- 矩阵乘法在神经网路中的作用:
(1) 通过神经网络向前馈送信号所需的大量运算可以表示为矩阵乘法。
(2) 不论神经网络的规模如何,将输入输出表达为矩阵乘法,使得我们可以更简洁地进行书写
(3) 更重要的是,一些计算机编程语言理解矩阵计算,并认识到潜在的计算方法的相似性,这允许计算机高速地进行这些计算。
两层神经网络:
X= W·I
W是权重矩阵,I是输入矩阵,X是组合调节后的信号
O=sigmoid(X).其中O矩阵是最终输出的结果,sigmoid是S函数
三层神经网络则是把第二层的输出结果O矩阵当作第三层的输入I,用第二层和第三层的链接权重矩阵W来进行矩阵运算,再将新得到的X用S函数得到最终新的矩阵O。
- 通过误差值更新链接权重的思想:
一种思想是在所以造成误差的节点中平分误差
另一种思想是不等分误差,我们为较大的链接权重的链接分配更多的误差,因为这些链接对造成误差的贡献较大
使用权重,将误差从输出向后传播到网络中,称这种方法为反向传播误差。
- 反向传播误差到更多层,并利用矩阵乘法表示
这个式子带分母很复杂,我们发现下面的分母只是归一化因子,如果我们忽略这个因子,失去的仅仅只是后馈误差的大小
这个权重和先前构建的矩阵很像,但是这个矩阵延对角线进行了翻转
10.
*梯度下降法
梯度下降法使求解函数最小值的一种很好的方法,当函数非常复杂困难,并且不能轻易使用数学代数求解函数时,这种方法却发挥了很好的作用。更重要的是,当函数有很多参数,一些其他方法不切实际,或者会得出错误答案,这种方法依然可以适用。这种方法也具有弹性,可以容忍不完善的数据,如果我们不能完美地描述函数,或我们偶尔意外地走错了一步,也不会错得离谱。
梯度下降法需要选择一个合适的误差函数:
神经网络输出函数不是一个误差函数,但由于误差是目标训练值与实际输出值之间的差值,我们很容易把输出函数变成误差函数。
误差函数的几个候选项
第一个:(目标值-实际值) 问题:正负误差会出现抵消,导致出现误差总和为0而显得没有误差的假象
第二个:|目标值-实际值|
问题:当误差函数接近最小值时,斜率也不会变的很小,因此我们的步长也不会很小,这意味着我们可能会有超调的风险。
第三个:(目标值-实际值)^2
原因:
(1) 使用误差的平方,我们很容易使用袋鼠计算梯度下降的斜率
(2) 误差函数平滑连续,这使得梯度下降法很好地发挥作用—–没有间断,也没有突然的跳跃
(3) 越接近最小值,梯度越小,这意味着,如果我们使用这个函数调节步长,超调的风险就会变得较小。
接下来我们需要推导误差函数斜率:
我们试图用矩阵乘法的形式进行运算
因此,权重更新有如下矩阵表达式
- 神经网络数据准备需要注意的问题:
(1) 如果输入、输出和初始权重数据的准备与网络设计和实际求解的问题不匹配,那么神经网络并不能很好的工作
(2) 一个常见的问题是饱和。在这个时候,大信号(这有时候是由大权重带来的)导致了应用在信号上的激活函数的斜率变得非常平缓。这降低了神经网络学习到更好权重的能力
(3) 另一个问题是零值信号或零值权重。这也可以使网络丧失学习更好权重的能力
(4) 内部链接的权重应该使随机的,值较小,但要避免零值。如果节点的传入链接较多,有一些人会使用相对复杂的规则,如减小这些权重的大小。
(5) 输入应该调整到较小值,但不能为零。一个常见的范围为0.01-0.99,或-1.0-1.0,使用哪个范围,取决于是否匹配了问题。
(6) 输出应该在激活函数能够生成的值范围内。逻辑S函数使不可能生成小于等于0或大于等于1的值。将训练目标值设置在有效的范围之外,将会驱使产生越来越大的权重,导致网络饱和。一个合适的范围为0.01-0.99.
源代码:
#神经网络数字识别
import numpy
import scipy.special
import matplotlib.pyplot
class neuralNetwork:
def __init__(self,inputnodes,hiddennodes,outputnodes,learningrate):
self.inodes=inputnodes
self.hnodes=hiddennodes
self.onodes=outputnodes
self.lr=learningrate
#创建输入层和隐藏层之间的权重矩阵
self.wih=numpy.random.normal(0.0,pow(self.hnodes,-0.5),(self.hnodes,self.inodes))
#创建隐藏层和输出层之间的权重矩阵
self.who=numpy.random.normal(0.0,pow(self.onodes,-0.5),(self.onodes,self.hnodes))
#定义激活函数
self.activation_function=lambda x: scipy.special.expit(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_inputs = numpy.dot(self.wih, inputs) # 隐藏层输入
hidden_outputs = self.activation_function(hidden_inputs) # 隐藏层输出
final_inputs = numpy.dot(self.who, hidden_outputs) # 输出层输入
final_outputs = self.activation_function(final_inputs) # 输出层输出
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.0-final_outputs)),numpy.transpose(hidden_outputs))
self.wih+=self.lr*numpy.dot((hidden_errors*hidden_outputs*(1.0-hidden_outputs)),numpy.transpose(inputs))
pass
def query(self,inputs_list): #查询
inputs=numpy.array(inputs_list,ndmin=2).T
hidden_inputs=numpy.dot(self.wih,inputs) #隐藏层输入
hidden_outputs=self.activation_function(hidden_inputs) #隐藏层输出
final_inputs=numpy.dot(self.who,hidden_outputs) #输出层输入
final_outputs=self.activation_function(final_inputs) #输出层输出
return final_outputs
#设置神经网络数据
input_nodes=784
hidden_nodes=200
output_nodes=10
learning_rate=0.1
n=neuralNetwork(input_nodes,hidden_nodes,output_nodes,learning_rate) #创建一个神经网络对象
#载入训练文件
training_data_file=open("mnist_train.csv",'r')
training_data_list=training_data_file.readlines()
training_data_file.close()
#训练神经网络
epochs=5 #训练次数
for e in range(epochs):
for record in training_data_list:
all_values=record.split(',')
inputs=(numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
targets=numpy.zeros((output_nodes))+0.01
targets[int(all_values[0])]=0.99
n.train(inputs,targets)
pass
pass
#加载测试集数据
test_data_file=open("mnist_test.csv",'r')
test_data_list=test_data_file.readlines()
test_data_file.close()
#测试神经网络
scorecard=[]
for record in test_data_list:
all_values=record.split(',')
correct_label=int(all_values[0])
print("正确的答案:",correct_label)
inputs=(numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
outputs=n.query(inputs)
label=numpy.argmax(outputs)
print("识别的答案:",label)
if(label==correct_label):
scorecard.append(1)
else:
scorecard.append(0)
pass
pass
#算出神经网络准确率
scorecard_array=numpy.asanyarray(scorecard)
print("准确率为",scorecard_array.sum()/scorecard_array.size)
参考文献 :《Python神经网络编程》 --塔里克.拉希德