昨天做的MLP,网络中每一层都没用任何激活函数,所以输出层的结果_logits中的部分数值比较大(绝对值在3000左右)。最后使用softmax函数对输出层进行处理得到各个结果的概率,发现训练的结果很不理想,准确率在50%以下。最后发现softmax的结果大部分是[0,0,0,0,0,1,0,0,0,0]这种单位向量。最后又看了看softmax,softmax函数的定义如下:
盗一张描述softmax的图:
softmax函数容易出现的问题就是溢出:
解决以上问题的方法也很简单,令,即
为所有
中最大的值,令
,那么我们只需要把计算
的值,改为计算
的值,就可以解决上溢出、下溢出的问题了,并且,计算结果理论上仍然和
保持一致。公式的推导也非常简单:
此外,在实际使用中(比如计算交叉熵时)经常要对softmax的结果取log,而如果softmax的结果中包含0,计算时就会出现inf(nan)的结果。这种问题的解决方法也很简单,直接看推导:
经过上式的变化后就不会在出现log(0)的情况了。
昨天使用tensorflow实现MLP时,因为每一层都没用激活函数,所以出现了softmax结果溢出的问题,可以在每一层增加sigmoid函数将结果控制在一定范围内就可以了,也可以使用tensorflow.nn.log_softmax(_logits)代替tensorflow.log(tensorflow.nn.softmax(_logits))来解决该问题,tensorflow中log_softmax的实现应该已经考虑到了以上问题,但是tensorflow.nn.softmax函数并没有对以上问题进行优化。下面时我修改后的MLP的代码,增加了sigmoid激活函数,求交叉熵的方法除了第三种应该是精度有问题外,使用
__loss_cross_entropy = -tf.reduce_mean(__Y_true*tf.nn.log_softmax(_logits))
和使用
__loss_cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=_logits, labels=__Y_true))
的训练结果的正确率都在95%左右。再贴一次代码吧,省的想看的再翻上一篇博客。
# coding:utf-8
'''
Multilayer Perceptron 多层感知机。
[MNIST Dataset](http://yann.lecun.com/exdb/mnist/)
参考 "https://github.com/aymericdamien/TensorFlow-Examples/blob/master/examples/3_NeuralNetworks/multilayer_perceptron.py"
项目地址:https://github.com/IMLHF/tensorflow_practice
'''
from __future__ import print_function
import tensorflow as tf
import numpy as np
# 加载MNIST数据集
from tensorflow.examples.tutorials.mnist import input_data
__mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
# 模型训练相关参数
__learning_rate = 0.001
__training_epochs = 15
__batch_size = 100 # 每批训练数据的大小
__display_step = 1 # 每隔__display_step批次显示一次进度
# 神经网络参数
__n_hidden_1 = 256 # 隐层第一层神经元个数
__n_hidden_2 = 256 # 隐层第二层神经元个数
__n_input = 784 # 输入层维度,与MNIST数据集的输入维度对应(图片大小28*28,展开成784维向量)
__n_output = 10 # 输出层维度,与MNIST数据集的输出维度(分类个数)对应,数字(0-9)
# tensorflow Graph输入口
__X_input = tf.placeholder("float", [None, __n_input])
__Y_true = tf.placeholder("float", [None, __n_output])
# 定义网络中的权重和阈值(偏置)
__weights = {
'w_hidden_layer1': tf.Variable(tf.random_normal([__n_input, __n_hidden_1])),
'w_hidden_layer2': tf.Variable(tf.random_normal([__n_hidden_1, __n_hidden_2])),
'w_out': tf.Variable(tf.random_normal([__n_hidden_2, __n_output])),
}
__biases = {
'b_hidden_layer1': tf.Variable(tf.random_normal([__n_hidden_1])),
'b_hidden_layer2': tf.Variable(tf.random_normal([__n_hidden_2])),
'b_out': tf.Variable(tf.random_normal([__n_output])),
}
# 创建多层感知机模型(双隐层)
def multilayer_perceptron(__x_input_t):
__hidden_layer1 = tf.nn.sigmoid(tf.add(tf.matmul(__x_input_t, __weights['w_hidden_layer1']),
__biases['b_hidden_layer1']))
__hidden_layer2 = tf.nn.sigmoid(tf.add(tf.matmul(__hidden_layer1, __weights['w_hidden_layer2']),
__biases['b_hidden_layer2']))
___out_layer = tf.nn.sigmoid(tf.add(tf.matmul(__hidden_layer2, __weights['w_out']),
__biases['b_out']))
return ___out_layer
# 训练和测试
if __name__ == '__main__':
_logits = multilayer_perceptron(__X_input)
# 使用softmax建立回归模型
# # 使用交叉熵作为损失函数
'''三种不同的方法求交叉熵'''
__loss_cross_entropy = -tf.reduce_mean(__Y_true*tf.nn.log_softmax(_logits)) # 准确率在95%左右
# __loss_cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
# logits=_logits, labels=__Y_true)) # 准确率在95%左右
# __loss_cross_entropy = -tf.reduce_mean(__Y_true*tf.log(tf.nn.softmax(_logits))) # 准确率在75%左右
# 使用Adam算法优化模型
__train_op = tf.train.AdamOptimizer(
learning_rate=__learning_rate).minimize(__loss_cross_entropy)
# 初始化变量
__init = tf.global_variables_initializer()
# 开始训练并测试
with tf.Session() as __session_t:
__session_t.run(__init)
for epoch in range(__training_epochs):
__avg_lost = 0
__total_batch = int(__mnist.train.num_examples/__batch_size)
for i in range(__total_batch):
__x_batch, __y_batch = __mnist.train.next_batch(__batch_size)
__nouse, __loss_t = __session_t.run([__train_op, __loss_cross_entropy],
feed_dict={__X_input: __x_batch,
__Y_true: __y_batch})
__avg_lost += float(__loss_t)/__total_batch
# region debug
# print(__loss_t)
# tmp = __session_t.run(
# _logits, feed_dict={__X_input: __x_batch, __Y_true: __y_batch})
# print(np.shape(_logits))
# for tt in tmp:
# for pp in tt:
# print("%.2f, " % pp, end="")
# print()
# print(__y_batch)
# endregion edbug
if epoch % __display_step == 0:
print("Epoch:", '%04d' % (epoch+1), "Avg_Loss=", __avg_lost)
print("Optimizer Finished!")
# 测试模型
__predict = tf.nn.softmax(multilayer_perceptron(__X_input))
__correct = tf.equal(tf.argmax(__predict, 1), tf.argmax(__Y_true, 1))
__accuracy_rate = tf.reduce_mean(tf.cast(__correct, tf.float32))
print("Accuracy:", __session_t.run(__accuracy_rate,
feed_dict={__X_input: __mnist.test.images,
__Y_true: __mnist.test.labels}))