一、代价函数
具体见:
https://blog.csdn.net/haha0825/article/details/102491643
二、优化器
具体见:
https://blog.csdn.net/haha0825/article/details/102503487
三、高级版MNIST手写数字识别
高级版主要做了以下改进:
(1)增加了隐藏层
(2)增加了每层的神经元
(3)改变了代价函数
(4)改变了优化器
(5)增加了dropout
# MNIST手写数字识别(高级版)
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data",one_hot=True) # 载入数据放在当前路径
sess = tf.InteractiveSession()
batch_size = 100 # 每个批次的大小
# n_batch = mnist.train.num_example # 一共有多少批次
n_batch = 5000
# 定义两个占位符
x = tf.placeholder(tf.float32,[None,784])
y = tf.placeholder(tf.float32,[None,10])
keep_prob = tf.placeholder(tf.float32)
# 创建一个神经网络
# 输入层
W1 = tf.Variable(tf.truncated_normal([784,1000],stddev=0.1))
b1 = tf.Variable(tf.zeros([1000])+0.1)
L1 = tf.nn.tanh(tf.matmul(x,W1)+b1)
L1_drop = tf.nn.dropout(L1,keep_prob) #keep_prob=0.4就是有40%的神经元失活
# 隐藏层1
W2 = tf.Variable(tf.truncated_normal([1000,1000],stddev=0.1))
b2 = tf.Variable(tf.zeros([1000])+0.1)
L2 = tf.nn.tanh(tf.matmul(L1_drop,W2)+b2)
L2_drop = tf.nn.dropout(L2,keep_prob)
# 隐藏层2
W3 = tf.Variable(tf.truncated_normal([1000,500],stddev=0.1))
b3 = tf.Variable(tf.zeros([500])+0.1)
L3 = tf.nn.tanh(tf.matmul(L2_drop,W3)+b3)
L3_drop = tf.nn.dropout(L3,keep_prob)
# 输出层
W4 = tf.Variable(tf.truncated_normal([500,10],stddev=0.1))
b4 = tf.Variable(tf.zeros([10])+0.1)
prediction = tf.nn.softmax(tf.matmul(L3_drop,W4)+b4)
# 二次代价函数
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=prediction))
# 优化器
# train_step = tf.train.GradientDescentOptimizer(1e-2).minimize(loss) #1e-2也就是0.01
train_step = tf.train.MomentumOptimizer(momentum=0.9,learning_rate=0.01).minimize(loss)
tf.global_variables_initializer().run()
correct_prediction = tf.equal(tf.arg_max(y,1),tf.arg_max(prediction,1))
# equal()两个值相等返回true,否则false
# arg_max返回一维张量中最大值的位置,对于y,里面是1个1和9个0,最大的那个位置就是该数字,比如第2个位置是1,则第二个位置最大,则该数字就是2
# 对于prediction来说,返回最大的概率的那个位置,其实同样也就是预测的数字。如果这两个值相等说明预测正确了.
# 总体的结果存放在一个布尔型列表中
# 准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
# cast :将布尔类型转换为float32类型,然后reduce_mean:求平均值.true转为1.0,false转为0.0
for epoch in range(21):
for batch in range(n_batch): # 循环总共的批次
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
# 取出100张图片,数据保存在batch_xs,标签保存在batch_yx,下一次再取出100张图片。
train_step.run({x:batch_xs,y:batch_ys,keep_prob:0.7})
test_acc = sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels,keep_prob:1.0}) # 训练一批输出一次准确率
train_acc = sess.run(accuracy,feed_dict={x: mnist.train.images, y: mnist.train.labels, keep_prob:1.0})
print("Iter" + str(epoch) + ",Testing Accuracy"+ str(test_acc)+",Training Accuracy"+str(train_acc))
输出结果
(1)在原来基础上仅仅改变代价函数或优化方法
改变代价函数(使用交叉熵代价函数):
改变优化方法(使用Adam):
(2)1000个神经元,梯度下降法
(3)2000个神经元,梯度下降法
(4)1000个神经元,Momentum优化器
(5)2000个神经元,Momentum优化器
(6)2000个神经元,Momentum优化器,dropout比例为0.8
(7)1000个神经元,Momentum优化器,不加dropout
可以看出:
(1)在相同的情况下,简单版的正确率只有不到93%,而这里改变了代价函数,正确率稍微有了提升
(2)使用Adam优化器,虽然最终结果没有提升,但是收敛速度极快;后面使用Momentum优化器,正确率和收敛速度都有较大提升。
(3)在这样情况下增加神经元数量已经没什么意义了,太多的神经元还会导致过拟合以及增加训练时间。
(4)增加了dropout的比例,效果稍微有了一些提升
(5)不加dropout时,1000个神经元已经有了明显的过拟合
四、继续改进
(1)继续填加隐藏层
(2)更改神经元数量
(3)更改dropout失活比例
(4)更改优化方法,学习率
(5)更改激活函数
(6)增加训练次数
(7)更改代价函数