2. softmax回归
适用场景:分类问题,预测离散值,输出属于各类别的概率。如,预测图像类别等。
对比线性回归:相当于在线性回归的基础上,将加权和经softmax函数变换,转化为[0,1]的概率;且为输出多个类别的概率值,各类别概率总和为1。
2.1 模型定义
以图像分类问题为例:
假设输入图像的高和宽均为2像素,且色彩为灰度,图像中的4像素分别记为 。
假设训练数据集中,图像的真实标签为狗、猫、鸡,分别记为离散值 。
相当于共有4种特征和3种输出类别。权重包含12个标量(带下标的)、偏差包含3个标量(带下标的),针对输入可计算3个输出:
该过程可用神经网络图表示:
softmax回归
同线性回归一样,softmax回归也是一个单层神经网络,其输出层也是一个全连接层。
值得注意的是,实际的输出值,需要将
其中,
且 。
2.2 小批量样本的矢量计算表达式
为提升计算效率,通常对小批量数据做矢量计算。
给定一个小批量样本,其批量大小为,输入个数(特征数)为,输出个数(类别数)为。设批量特征为,权重和偏差分别为和,则softmax回归的矢量计算表达式为:
其中,,且这两个矩阵的第行分别为样本的输出和概率分布。
2.3 交叉熵损失函数
softmax回归预测输出各类别的概率分布,而真实标签也可以用类别分布表达:
对于样本,构造向量 ,使其第(样本类别的离散数值)个元素为1,其余为0。
由此,训练目标可以设为使预测概率分布尽可能接近真实的标签概率分布。
实现方法:利用交叉熵(cross entropy)衡量两个概率分布的差异。
其中,带下标的是向量中非0即1的元素。
假设训练数据集的样本数为,交叉熵损失函数定义为:
其中,代表模型参数。
若每个样本只有一个标签,那么,交叉熵损失函数可简写成。
2.4 模型预测及评价
对于训练好的softmax回归模型,给定任一样本特征,预测每个输出类别的概率。
通常将预测概率最大的类别作为输出类别,若与真实类别(标签)一致,则预测结果正确。
2.5 代码实现
2.5.1 读取数据
图像分类数据集:Fashion-MNIST
包含10个类别的图像数据:t-shirt(T恤)、trouser(裤子)、pullover(套衫)、dress(连衣裙)、coat(外套)、sandal(凉鞋)、shirt(衬衫)、sneaker(运动鞋)、bag(包)、ankle boot(短靴)。
图像的高和宽均为28像素,每个像素的数值为0到255之间8位无符号整数(uint8)。
均为灰度图像(仅两个维度),使用二维的numpy.ndarray存储。
import tensorflow as tf
from tensorflow import keras
fashion_mnist = keras.datasets.fashion_mnist
(x_train,y_train),(x_test,y_test) = fashion_mnist.load_data()
# 图像归一化
x_train = x_train / 255.0
x_test = x_test / 255.0
注:图像归一化,采用 Min-Max Normalization。
其中,max为样本数据的最大值,min为样本数据的最小值。
上述场景中,每个像素的数值为0到255之间。
2.5.2 定义模型及初始化参数
输入层:Flatten,将28 * 28的像素值,压缩为一行 (784, ) 。
输出层:输出个数为10的全连接层,激活函数使用softmax。
model = keras.Sequential([
keras.layers.Flatten(input_shape=(28,28)),
keras.layers.Dense(10,activation=tf.nn.softmax)])
2.5.3 定义损失函数
# Tensorflow2.0 的keras API的loss参数
loss = 'sparse_categorical_crossentropy'
问题:为何不按原始公式,先进行softmax运算再构造交叉熵损失函数。
回答:softmax函数会出现数值不稳定问题。
原因:上溢和下溢,使结果为NaN。
上溢:大量级的数被近似为无穷时发生上溢。
下溢:当接近零的数被四舍五入为零时发生下溢。
假设所有的都等于某个常数,理论上对所有上式结果为1/n。
若是很小的负数,下溢,softmax分母为0,最后的结果为NaN;
若量级很大,上溢,最后的结果为NaN。
2.5.4 定义优化算法
# 小批量随机梯度下降(学习率=0.1)
optimizer = tf.keras.optimizers.SGD(0.1)
2.5.5 训练模型
model.compile(optimizer=optimizer,
loss = loss,
metrics=['accuracy'])
model.fit(x_train,y_train,epochs=5,batch_size=256)
输出:
Train on 60000 samples
Epoch 1/5
60000/60000 [==============================] - 1s 23us/sample - loss: 0.7893 - accuracy: 0.7424
Epoch 2/5
60000/60000 [==============================] - 0s 7us/sample - loss: 0.5702 - accuracy: 0.8109
Epoch 3/5
60000/60000 [==============================] - 0s 6us/sample - loss: 0.5256 - accuracy: 0.8251
Epoch 4/5
60000/60000 [==============================] - 0s 7us/sample - loss: 0.5018 - accuracy: 0.8316
Epoch 5/5
60000/60000 [==============================] - 0s 7us/sample - loss: 0.4860 - accuracy: 0.8359
2.5.6 效果评估
test_loss, test_acc = model.evaluate(x_test, y_test)
print('Test Acc:',test_acc)
输出:
- 0s 21us/sample - loss: 0.4309 - accuracy: 0.8245
Test Acc: 0.8245
参考