一个更复杂高效的架构是多层感知器MLP。典型的学习算法是后向传播算法。
后向传播算法比较系统的输出值和期望输出值,根据他们之间的差值(或者称为error),修改神经网络的突触的权值。需要强调的是,虽然你不知道隐藏层神经元的期望输出,依然可以通过梯度下降技术来进行监督学习。
输入层的数量需要根据输入的数量来决定。例如mnist的每个输入有28*28个,因此输入层必须有784个。最终的输出有10中可能性,因此输出层可以是10个。隐藏层的层数和每层的神经元数量没有严格的准则,仅有以写经验供参考
当增加隐藏层的数量时,我们也需要增加训练集的大小和连接的数量,这回导致训练时间增加。
如果隐藏层的神经元太多,一方面更多权重需要更新,另一方面需要的训练集数量跟多。这会导致较差的一般化能力,毕竟训练集仅仅时真实情况的一个样本,拟合得太接近了,当输入一个不在训练集中的数据时,容易出错。但如果隐藏的神经元太少,可能没有能力完成训练集的学习。
#import MNIST data
import input_data
mnist=input_data.read_data_sets("MNIST_data/",one_hot=True)
import tensorflow as tf
import matplotlib.pyplot as plt
#Parameters
learning_rate=0.01
training_epochs=20
batch_size=100
display_step=1
n_hidden_1 = 256 #the number of neurons for the first layer
n_hidden_2 = 256 # the second hidden layer.
n_input=784 #mnist data input in input layer
n_classes = 10 # all kindes of output in output layer
#tf Graph Input
x=tf.placeholder("float",[None,n_input]) #input is 28*28 image,
y=tf.placeholder("float",[None,n_classed]) #output is 0~9
#Create model
bias_layer_1 = tf.Variable(tf.random_normal([n_hidden_1]))
h=tf.Variable(tf.random_normal([n_input,n_hidden_1]))
layer_1=tf.nn.sigmoid(tf.add(tf.matmul(x,h),bias_layer_1)) #output of layer 1
bias_layer_2 = tf.Variable(tf.random_normal([n_hidden_2]))
w=tf.Variable(tf.random_normal([n_hidden_1,n_hidden_2]))
layer_2=tf.nn.sigmoid(tf.add(tf.matmul(layer_1,w),bias_layer_2))
bias_output = tf.Variable(tf.random_normal([n_classes]))
output=tf.Variable(tf.random_normal([n_hidden_2,n_classes]))
output_layer=tf.nn.sigmoid(tf.add(tf.matmul(layer_2,output),bias_output)) #这里调用了sigmoid函数
#Construct model
#Minimize error using cross entropy
cost=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(output_layer,y)) #这里还用了一次softmax函数然后再计算交叉熵。
optimizer=tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
#Plot settings
avg_set = []
epoch_set=[]
#initializing the variables
init=tf.global_variables_initializer()
#Launch the graph
with tf.Session() as sess:
sess.run(init)
#training cycle
for epoch in range(training_epochs):
avg_cost=0
total_batch=int(mnist.train.num_examples/batch_size)
#print "total_batch = %d" % total_batch
#loop overall batches
for i in range(total_batch):
batch_xs,batch_ys=mnist.train.next_batch(batch_size)
sess.run(optimizer,feed_dict={x:batch_xs,y:batch_ys})
avg_cost+= sess.run(cost,feed_dict={x:batch_xs,y:batch_ys})/total_batch
if epoch %display_step ==0:
print "Epoch:",'%04d'%(epoch+1),"cost=","{:.9f}".format(avg_cost)
avg_set.append(avg_cost)
epoch_set.append(epoch+1)
correct_prediction=tf.equal(tf.argmax(output_layer,1),tf.argmax(y,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,"float"))
print "Model accuracy:",accuracy.eval({x:mnist.test.images,y:mnist.test.labels})
print "Training phase finished"
sigmoid函数(也叫逻辑斯谛函数):
引用wiki百科的定义:
A logistic function or logistic curve is a common “S” shape (sigmoid curve).
其实逻辑斯谛函数也就是经常说的sigmoid函数,它的几何形状也就是一条sigmoid曲线。
logistic曲线如下:
同样,我们贴一下wiki百科对softmax函数的定义:
softmax is a generalization of logistic function that “squashes”(maps) a K-dimensional vector z of arbitrary real values to a K-dimensional vector σ(z) of real values in the range (0, 1) that add up to 1.
这句话既表明了softmax函数与logistic函数的关系,也同时阐述了softmax函数的本质就是将一个K
维的任意实数向量压缩(映射)成另一个K维的实数向量,其中向量中的每个元素取值都介于(0,1)之间。
softmax函数形式如下:
总结:sigmoid将一个real value映射到(0,1)的区间(当然也可以是(-1,1)),这样可以用来做二分类。
而softmax把一个k维的real value向量(a1,a2,a3,a4….)映射成一个(b1,b2,b3,b4….)其中bi是一个0-1的常数,然后可以根据bi的大小来进行多分类的任务,如取权重最大的一维。
本例中sigmoid计算后的结果再进行一次softmax压缩,使得每种结果可以表示成一个概率。
【adam优化器的特点】
Adam梯度经过偏置校正后,每一次迭代学习率都有一个固定范围,使得参数比较平稳。
结合了Adagrad善于处理稀疏梯度和RMSprop善于处理非平稳目标的优点
为不同的参数计算不同的自适应学习率
也适用于大多非凸优化问题——适用于大数据集和高维空间。
由此相较于单层感知器,多层感知器在实现上有以下一个改进:
构建模型时多加几条代码即可完成模型构建
sigmoid之后再调用softmax进行一次映射,使得每次运算结果都是一个概率分布。
模型复杂度增加,原有的优化算法性能上存在问题,这里采用adam优化算法