本文分为 理论介绍 和 Python 代码实现 两部分
👉 点此直接跳转到代码实现
Softmax 回归模型
与逻辑回归一样,我们先对数据进行向量化:
$$
X = (x_0, x_1, \dots, x_n)
$$其中,$x_0$ 等于 1,且 $X$ 的形状为 $m$ 行 $n+1$ 列,$m$ 为样本个数,$n$ 为特征个数。
$$
W = (w_1, \dots, w_c)
$$$W$ 的形状为 $n+1$ 行 $c$ 列,$c$ 为总类别个数。
$$
Z = XW
$$$Z$ 的形状为 $m$ 行 $c$ 列。
$$
\hat{Y} = \text{softmax}(Z)
$$同样的,$\hat{Y}$ 的形状为 $m$ 行 $c$ 列。第 $i$ 行代表第 $i$ 个样本为每个类别的概率。
对于每个样本,我们将其判定为输出中最大值对应的类别。
Softmax 回归训练流程
Softmax 回归训练流程同逻辑回归一样,首先需要构造一个损失函数,再利用梯度下降方法最小化损失函数,从而达到更新参数的目的。具体流程如下:
Python 代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
import numpy as np
from sklearn.preprocessing import OneHotEncoder
def softmax(x):
'''
input:x(ndarray):输入数据
output:y(ndarray):经过 softmax 函数后的输出
'''
exp_x = np.exp(x - np.max(x)) # 防止溢出
y = exp_x / np.sum(exp_x, axis=1, keepdims=True)
return y
def softmax_reg(train_data, train_label, test_data, lr, max_iter):
'''
input:train_data(ndarray):训练数据
train_label(ndarray):训练标签
test_data(ndarray):测试数据
lr(float):梯度下降中的学习率参数
max_iter(int):训练轮数
output:predict(ndarray):预测结果
'''
# 将 x0 加入训练数据
train_data = np.c_[np.ones((train_data.shape[0], 1)), train_data]
# 转换为 onehot 标签
encoder = OneHotEncoder(sparse=False)
train_label_onehot = encoder.fit_transform(train_label.reshape(-1, 1))
# 对 w 初始化
num_features = train_data.shape[1]
num_classes = train_label_onehot.shape[1]
w = np.zeros((num_features, num_classes))
# 利用梯度下降对模型进行训练
for _ in range(max_iter):
z = np.dot(train_data, w)
y_pred = softmax(z)
gradient = np.dot(train_data.T, (y_pred - train_label_onehot)) / train_data.shape[0]
w -= lr * gradient
# 将 x0 加入测试数据
test_data = np.c_[np.ones((test_data.shape[0], 1)), test_data]
# 进行预测
z_test = np.dot(test_data, w)
y_test_pred = softmax(z_test)
predict = np.argmax(y_test_pred, axis=1)
return predict
|