针对线性不可分的问题(多分类),SVM算法是通过建立曲线(升维)来划分,神经网络通过建立多条直线(多个神经元,以及激活函数)来进行划分。 神经网络演示
神经网络输入层的输入个数与特征个数保持一致,输出层输出个数与目标类别数保持一致,输出通过softmax函数转换成每个目标类别的概率。
SoftMax公式如下:
损失函数--交叉熵损失函数:
交叉熵损失函数与信息熵公式类似,表示一种不确定性。交叉熵越小说明结果越确定,说明神经网络输出的预测概率越接近真实结果的概率(真实结果的概率由one-hot编码表示)。
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2' # 设置警告级别
# 配置,进行训练还是测试
IS_TRAIN = 1 # 1:进行训练并保存模型。 0:加载模型并进行测试
# 获取数据
# TensorFlow自带的数据集(手写数字图片,55000个训练样本,10000个测试样本,图片尺寸28*28=784)
mnist = input_data.read_data_sets("./data/mnist/", one_hot=True)
# mnist.train.images 图片数据
# mnist.train.labels 目标标签(0-9,10个目标类别)
# mnist.train.next_batch(100) 可以批量获取数据
# 1、准备输入数据的占位符(与输入的真实数据的形状对应) x [None, 784] y_true [None, 10](one-hot编码) 图片大小28*28=784
with tf.variable_scope("data"):
x = tf.placeholder(tf.float32, [None, 784]) # 图片大小28*28=784
y_true = tf.placeholder(tf.int32, [None, 10]) # 目标类别:0-9,10个类别。 one-hot编码形式表示
# 2、建立一个全连接层的神经网络 权重形状[784, 10] 偏置形状[10]
with tf.variable_scope("fc_model"):
# 随机初始化权重,初始化偏置。 权重、偏置的参数需要优化(变化),必须用变量定义
weight = tf.Variable(tf.random_normal([784, 10], mean=0.0, stddev=1.0), name="w") # TensorBoard中会显示name
bias = tf.Variable(tf.constant(0.0, shape=[10]))
# 预测None个样本的输出结果(矩阵乘法) [None, 784]* [784, 10] + [10] = [None, 10]
y_predict = tf.matmul(x, weight) + bias # matmul()表示矩阵乘法
# 3、求出所有样本的交叉熵损失,然后求平均值
with tf.variable_scope("soft_cross"):
# 求平均交叉熵损失
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_true, logits=y_predict))
# 4、梯度下降优化损失(反向传播)
with tf.variable_scope("optimizer"):
train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss) # 0.1表示学习速率(步长)。 学习率并不是一个超参数,它并不会影响优化的结果,只影响优化的快慢(学习率过大容易出现梯度爆炸)
# 5、计算准确率
with tf.variable_scope("acc"):
equal_list = tf.equal(tf.argmax(y_true, 1), tf.argmax(y_predict, 1)) # y_true和y_predict形状:[None, 10] (one-hot编码)
# tf.argmax()返回最大值的下标,第二个参数1表示坐标轴(每一行的最大值)
# tf.equal()判断是否相等,返回0、1组成的张量(1表示相等,0表示不相等)
# tf.reduce_mean()计算平均值。 equal_list:None个样本[1, 0, 1, 0, 1, 1,..........]
accuracy = tf.reduce_mean(tf.cast(equal_list, tf.float32))
# TensorBoard 收集变量进行显示 (标量)
tf.summary.scalar("losses", loss)
tf.summary.scalar("acc", accuracy)
# 收集高纬度变量
tf.summary.histogram("weightes", weight)
tf.summary.histogram("biases", bias)
# 合并收集的变量的op (合并变量,一次性写入事件文件,通过TensorBoard进行可视化)
merged = tf.summary.merge_all()
# 初始化变量的op
init_op = tf.global_variables_initializer()
# 创建一个saver (保存模型)
saver = tf.train.Saver()
# 开启会话进行训练或测试
with tf.Session() as sess:
# 初始化变量
sess.run(init_op)
# 建立events文件,然后写入。 (TensorBoard根据events文件进行可视化)
filewriter = tf.summary.FileWriter("./tmp/summary/test/", graph=sess.graph)
# 如果是训练
if IS_TRAIN == 1:
# 迭代训练,更新参数预测 (迭代2000次)
for i in range(2000):
# 取出训练集的特征值和目标值 (每次迭代取出50个样本)
mnist_x, mnist_y = mnist.train.next_batch(50)
# 运行train_op训练优化 (feed_dict:用实时的训练数据填充占位符)
sess.run(train_op, feed_dict={x: mnist_x, y_true: mnist_y})
# 合并收集的所有变量 (一次性写入事件文件)
summary = sess.run(merged, feed_dict={x: mnist_x, y_true: mnist_y})
filewriter.add_summary(summary, i) # 将收集的数据写入事件文件。i表示第i次的值。
print("训练第%d步,准确率为:%f" % (i, sess.run(accuracy, feed_dict={x: mnist_x, y_true: mnist_y})))
# 保存模型
saver.save(sess, "./tmp/ckpt/fc_model")
else: # 否则进行测试
# 加载模型
saver.restore(sess, "./tmp/ckpt/fc_model")
# 预测100张图片的结果
for i in range(100):
# 每次测试一张图片 y_test的形状[1,10] (one-hot编码):[0,0,0,0,0,1,0,0,0,0]
x_test, y_test = mnist.test.next_batch(1)
print("第%d张图片,手写数字图片真实目标是:%d, 预测结果是:%d" % (
i,
tf.argmax(y_test, 1).eval(),
tf.argmax(sess.run(y_predict, feed_dict={x: x_test, y_true: y_test}), 1).eval()
))