TensorFlow学习笔记3-从MNIST开始学习softmax
本笔记内容为“从MNIST学习softmax regression算法的实现”。
注意:由于我学习机器学习及之前的书写习惯,约定如下:
- \(X\)表示训练集的设计矩阵,其大小为m行n列,m表示训练集的大小(size),n表示特征的个数;
- \(W\)表示权重矩阵,其大小是n行k列,n为输入特征的个数,k为输出(特征)的个数;
- \(\boldsymbol{y}\)表示训练集对应标签,其大小为m行,m表示训练集的大小(size);
-
\(\boldsymbol{y’}\)表示将测试向量\(x\)输入后得到的测试结果;
总之:
注意区分这里的:\(\boldsymbol{y'}=XW+\boldsymbol{b}\) 表示矩阵形式的预测结果(\(\boldsymbol{y’}\)和\(\boldsymbol{b}\)是向量);
之前机器学习中的是(如《机器学习实战》中SVM一章):$y’=\omega^T x+b $ 表示向量形式的预测结果(\(y'\)和\(b\)是标量);
算法部分:包括预测模型和优化目标
以手写输入MNIST为例:
预测模型
\[
\boldsymbol{y'}=softmax(\boldsymbol{z})=softmax(X \times W + \boldsymbol{b})
\]
其中softmax函数是归一化函数:
\[ softmax(x_i)=\frac{exp(x_i)}{\sum_j exp(x_j)} \]
其中\(i , j\)的范围为1~10。softmax函数将\(\boldsymbol{z}\)归一化之后变为\(\boldsymbol{y’}\)(预测值)。如下图。
- 训练集:共55000条数据,每条数据中有784个特征(将28*28个像素点进行展开,忽略了像素间的结构关系),矩阵中m=55000,n=784;
- 参数\(W\)中的元素\(W_{i,j}\)的含义是:第i个像素点在数字j中占的权重,意思是如果很多数字j的实例中都有i,说明像素点i很大可能代表数字j,那么其权重会很大。
- 参数\(b\)中的元素\(b_{i,j}\)的含义是:第i个像素点在数字j的偏置量,意思是如果大部分数字都是0,则0的特征对应的bias值会很大。
优化目标:交叉熵的最小化
交叉熵:
\[
H_{y}(y')=-\sum{y_i log(y'_i)}
\]
其中,
每个batch中的所有预测项的交叉熵的平均值为评价指标。
实现部分:
用随机梯度下降优化器对评价指标进行优化。
每次随机选取训练集中的100个子集作为batch(桶)进行训练,共训练1000次。
预测模型的评价
统计准确率。
附代码:
# -*- coding: utf-8 -*-
"""
- [x] Created on Wed Oct 31 21:35:42 2018
@author: ccl
"""
# 下载数据集
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) # 使用one-hot编码
print(mnist.train.assets.shape, mnist.train.labels.shape)
print(mnist.test.assets.shape, mnist.test.labels.shape)
print(mnist.validation.assets.shape, mnist.validation.labels.shape)
import tensorflow as tf
sess = tf.InteractiveSession()
# 第一步,定义算法公式
x = tf.placeholder(tf.float32, [None, 784]) # 构建占位符,None表示样本的数量可以是任意的
W = tf.Variable(tf.zeros([784, 10])) # 构建一个变量,代表权重矩阵,初始化为0
b = tf.Variable(tf.zeros([10])) # 构建一个变量,代表偏置,初始化为0
y_ = tf.nn.softmax(tf.matmul(x, W) + b) # 构建了一个softmax的模型:y = softmax(Wx + b),y指样本标签的预测值
# 第二步,定义损失函数,选定优化器,并指定优化器优化损失函数
y = tf.placeholder(tf.float32, [None, 10])
# 交叉熵损失函数
cross_entropy = -tf.reduce_mean(tf.reduce_sum(y * tf.log(y_),reduction_indices=[1]))
# 使用梯度下降法最小化cross_entropy损失函数
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
# 第三步,迭代地对数据进行训练
tf.global_variables_initializer().run()
for i in range(1000): # 迭代次数1000
batch_xs, batch_ys = mnist.train.next_batch(100) # 使用minibatch,一个batch大小为100
train_step.run({x: batch_xs, y: batch_ys})
if i%100 ==0:
print("进度:%d%%" % (i//10))
# 第四步,在测试集或验证集上对准确率进行评测
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) # tf.argmax()返回的是某一维度上其数据最大所在的索引值,在这里即代表预测值和真值
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) # 用平均值来统计测试准确率
# 你会得到大约92%的准确率
print(accuracy.eval({x:mnist.test.assets,y:mnist.test.labels}))
#关闭会话
sess.close()
#### 更进一步
- 使用
InteractiveSession
将这个session注册为默认的session,之后的运算都默认跑在这个session里,不同session之间的运算与数据相互独立。 - 比较
batch_xs, batch_ys = mnist.train.next_batch(100) # 使用minibatch,一个batch大小为100
train_step.run({x: batch_xs, y: batch_ys})
与
batch = mnist.train.next_batch(50)
train_step.run(feed_dict={x: batch[0], y_: batch[1]})
的异同。
本质没有区别:也就是说只要是字典dict形式的写法,就是输入;否则就是输出。