手搓GPT系列之 - 线性回归与softmax分类器,从理论到实战

NLP还存不存在我不知道,但数学之美一直都在。线性回归是机器学习中非常重要的一个砖块,我们将介绍线性回归和softmax分类器的数学原理及其内在关联。既是对自己学习成果的一种记录,如果能够对别人有所帮助那真是让人开心。

1. 什么是分类器

1.1 感性认识一下分类器

在机器学习中,分类器的作用是在标记好类别的训练数据基础上判断一个新的观察样本所属的类别。常规任务是利用给定的类别、已知的训练数据来学习分类规则和分类器,然后对未知数据进行分类或预测。一个大小为n的分类器训练数据集可以表示为\{x_i,y_i\}^n,其中,x_i是d维特征值,x_i \in \mathbb{R}^dy_i是分类标签的值,令C为所有分类的集合,y_i\in C。下边展示了一个特征值维度为2的二元分类器(二元分类器就是会把样本分成2类的分类器,例如:男/女,强/弱,高/低等等):

from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
import numpy as np
import matplotlib.pyplot as plt

# Generate 2D classification data
X, y = make_classification(n_samples=100, n_features=2, n_redundant=0,
                           n_informative=2, random_state=1, n_clusters_per_class=2)

# Train logistic regression classifier
clf = LogisticRegression(random_state=0).fit(X, y)

# Plot decision boundary
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
                     np.arange(y_min, y_max, 0.02))
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, alpha=0.8)
plt.show()

1.2 生成式和判别式分类器

分类器模型可以分为两类:生成式(generative)和判别式(discriminative)。生成式模型与判别式模型的主要区别在于,对于特征数据x和分类结果y,生成式模型关注的是数据在空间中的分布情况,试图根据观察到的数据解释数据生成的逻辑,具体来说,就是通过先验数据学习联合概率分布p(x,y),然后再生成条件概率分布p(y|x);而判别式模型会跳过联合概率分布的计算,直接根据观察数据来推测新的样本的分类。换句话说,生成式模型会根据观察数据获得一个其自认为的世界真相,并根据这个真相来推测新样本的分类;判别式则不关心世界真相,只是看新数据和哪一撮观察数据最相似。

现有的生成式模型包括:贝叶斯模型、马尔可夫模型、分支定界法、混合高斯模型等。判别式模型包括:K近邻法(KNN)、决策树、SVM、Fisher线性判别、有限状态机、线性回归(感知机)、softmax算法、神经网络等。

我们本文将着重介绍判别式模型中的线性回归算法(感知机)、softmax算法及神经网络模型背后的数学原理及这三种算法之间的内在联系。

2. Logistic Regression

我们先从最基本的分类器说起,说的就是线性回归算法,或者更准确点应该叫感知机。上面的例子展示的就是一个线性回归,线性回归算法顾名思义就是通过一个可以用线性方程(线性方程指的是仅含有自变量一次幂的方程)来表示的高维平面来拟合样本特征值所表示的点,感知机则是通过该平面对样本数据进行分类,二者其实背后的原理是相同的,所以两个名称经常混用。现在让我们来认识一个最常用的线性回归算法:Logistic Regression (LR,中文名逻辑斯蒂回归或者逻辑回归,注意逻辑回归不是指Logit函数)。接下来让我们来推一推这个小骚的逻辑斯蒂回归函数。

2.1 Logistic Regression似然公式

给定模型参数向量为w\in \mathbb{R}^d和偏移参数b\in \mathbb{R}^d,给定数据训练样本数据集\{x_i,y_i\}^n,x_i为特征值向量,并且x_i\in \mathbb{R}^dd是特征数据的维数。模型的logit函数为:

g(x;w,b) = w^Tx +b

样本的分类标签集合为C = \{True,False\},样本x_i分类为y_i=True的似然值为p(x)。我们指定一个连接函数f(z)来表示目标函数与样本x分类y=True的似然值p(x)之间的关系,即:

p(x)=f(g(x;w,b))=f(w^Tx+b)

由于p(x)\in[0,1],因此f(z)\in [0,1]。我们选定f(z)=sigmoid(z)=\frac{1}{1+e^{-z}}

f(z)代入上式可得:

p(x)=\frac{1}{1+e^{-w^Tx+b}}

2.2 sigmoid函数的图像

import numpy as np
import math
import matplotlib.pyplot as plt

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

x=np.arange(-25.0,25.0,0.01)
y1=[sigmoid(a) for a in x]


plot1=plt.plot(x,y1,'*',label='sigmoid(x)')


plt.xlabel('X axis')
plt.ylabel('Y axis')
plt.title('Logit Function')
plt.legend(loc=4)
plt.grid(True)
plt.show()

2.3 Logistic Regression目标公式

我们对模型参数w,b的优化目标为:使得训练样本中,所有y_i根据样本的取值的似然值最大化。我们使用q(x)表示实际在训练样本中观察到y=True的概率,当然,当y=True时,q(x)=1,否则q(x)=0。有:​​​​​​ 

\arg \max_{w,b} L(x;w,b)=\prod_{i=1}^n p(x_i)^{q(x_i)}(1-p(x_i))^{1-q(x_i)}

对上式右侧取对数得:

\arg \max_{w,b} L(x;w,b)=\sum_{i=1}^n (q(x_i) \log p(x_i)+(1-q(x_i)) \log (1-p(x_i)))

目标函数又称为损失函数,我们应该最小化目标函数,使得似然值最大化,因此有:

J(x;w,b) = -\frac1n\sum_{i=1}^n (q(x_i) \log p(x_i)+(1-q(x_i)) \log (1-p(x_i)))

3. softmax分类

3.1 似然公式

上文提到的Logistic Regression是二分类算法,即对于任何已标记样本\{x,y\}y的可能取值只有两个。那么遇到多个分类的场景,应该怎么处理呢?有一个非常直观的办法就是:可以为每一个分类建立一个感知机用于判断样本xy =\in C的概率。我们可以单个感知机的logit函数输出的结果作为样本x到分类y的相似度(similarity),标记为h(y|x)。则有:

h(y|x)=w_y^Tx + b_y

为了使上式的结果永远大于0。我们引入自然指数。则:

h(y|x)=\exp(w_y^Tx + b_y)

似然值要求我们把样本x被归类为y的相似度归一化处理,即样本x对与所有分类y\in C的似然值之和为1。我们把似然值标记为p(y|x)。则有:

p(y|x)=\frac{\exp(w_y^Tx +b_y)}{\sum_{c\in C} \exp(w_c^Tx + b_c)}

3.2 目标公式

目标公式可以描述为:

J(x;w,b) = -\prod_{i=1}^n \frac{\exp(w_y^Tx_i)}{\sum_c \exp(w_c^Tx_i)}

给上式增加对数操作,可以把累乘转为累加:

J(x;w,b) = -\sum_{i=1}^n \log \frac{\exp(w_y^Tx_i)}{\sum_c \exp(w_c^Tx_i)}

上式的结果会受训练样本的大小影响,因此增加一个因子用于平衡训练样本大小:

J(x;w,b) = -\frac1n \sum_{i=1}^n \log \frac{\exp(w_y^Tx_i)}{\sum_c \exp(w_c^Tx_i)}

3.3 与LR模型的关系

LR模型是一个二元分布模型。我们把softmax的目标公式,在类别标签数量为2(记为\{True,False\})的情况下,可以改写为:

J(x;w,b) = -\frac1n \sum_{i=1}^n \log \frac{\exp(w_{y_i}^Tx_i)}{ \exp(w_{True}^Tx_i) + \exp(w_{False}^Tx_i)}

设:

p(x) = p(True|x) = \frac{\exp(w_{True}^Tx)}{ \exp(w_{True}^Tx) + \exp(w_{False}^Tx)}

q(x)=\begin{cases} 1 & y=True \\ 0 & y=False\end{cases}

给定已标记的样本\{x,y\}

p(y|x) = \frac {\exp(w_y^Tx)}{\exp(w_{True}^Tx) + \exp(w_{False}^Tx)}

p(y|x)= q(x) \frac {\exp(w_{True}^Tx) }{\exp(w_{True}^Tx) + \exp(w_{False}^Tx)} + (1-q(x)) \frac{\exp(w_{False}^Tx)}{\exp(w_{True}^Tx) + \exp(w_{False}^Tx)}

p(y|x)= q(x) p(x) + (1-q(x)) (1 - p(x))

因此softmax目标函数可以改写为:

J(x;w,b) = -\frac1n \sum_{i=1}^n \log[{q(x_i)}p(x_i) + (1-q(x_i))(1-p(x_i)) ]

在多分类的情形下,上边的式子依然有效:

给定分类标签的集合C,令c\in C

p(c|x) = \frac {\exp(w_c^Tx)}{\exp(w_{c}^Tx) + \sum_{y \ne c} \exp(w_{y}^Tx)}

令:

q(c|x)=\begin{cases} 1 & y = c \\ 0 & y \ne c \end{cases}

进一步转换:

p(c|x) = q(c|x)\frac {\exp(w_c^Tx)}{\exp(w_{c}^Tx) + \sum_{y \ne c} \exp(w_{y}^Tx)} + (1-q(c|x)) \frac {\sum_{z\ne c} \exp(w_z^Tx)}{ \exp(w_{c}^Tx) + \sum_{y \ne c} \exp(w_{y}^Tx)}

p(c|x)= q(c|x) p(c|x) + (1-q(c|x)) (1 - p(c|x))

针对分类标签c的目标公式为:

J(c|x;w,b) = -\frac1n\sum_{i=1}^n (q(c|x_i) \log p(c|x_i)+(1-q(c|x_i)) \log (1-p(c|x_i)))

可以看到上述公式就是LR模型的目标公式。因此Softmax模型是LR模型的扩展。我们可以把softmax模型看成是将与分类标签一样多的LR模型并联的结果,每个LR模型用于计算输入的样本属于某个分类标签的似然值。

4. 实现一个softmax分类器

4.1 加载mnist手写体数据

from keras.datasets import mnist
import matplotlib.pyplot as plt

(train_X, train_y), (test_X, test_y) = mnist.load_data()
sample_X = []

for i in range(9):
    plt.subplot(330 + 1 + i)
    plt.imshow(train_X[i], cmap=plt.get_cmap('gray'))
plt.show()

for _train_x in train_X:
    sample_X.append(_train_x.flatten())

 4.2 实现一个softmax损失函数

import torch.nn.functional as F

class CustomSoftmaxLoss(nn.Module):
    def __init__(self):
        super(CustomSoftmaxLoss, self).__init__()

    def forward(self, input, target):
        # calculate softmax values
        softmax_output = F.softmax(input, dim=1)
        # calculate log-softmax values
        log_softmax_output = F.log_softmax(input, dim=1)
        # create mask for one-hot encoding
        mask = torch.zeros_like(log_softmax_output)
        mask.scatter_(1, target.view(-1, 1), 1)
        # apply mask to log-softmax output
        masked_log_softmax_output = log_softmax_output * mask
        # sum over classes
        loss = -masked_log_softmax_output.sum(dim=1)
        return loss.mean()

4.3 训练

import torch.nn as nn
import torch.optim as optim
import torch

def softmax_loss(x,y):
    loss = -np.sum(np.log(probs[range(X.shape[0]), y]))


# create a tensor
x = torch.tensor(sample_X, dtype=torch.float32)

# create a tensor with labels
y = torch.tensor(train_y, dtype=torch.int64)

losses=[]

# define the model
model = nn.Sequential(
    nn.Linear(784, 10),
    nn.Softmax(dim=1)
)

# define the loss function
# criterion = nn.CrossEntropyLoss()
criterion = CustomSoftmaxLoss()
# define the optimizer
optimizer = optim.SGD(model.parameters(), lr=0.01)

# train the model
for epoch in range(200):
    # zero the gradients
    optimizer.zero_grad()
    # forward + backward + optimize
    outputs = model(x)
    loss = criterion(outputs, y)
    losses.append(loss.item())
    loss.backward()
    optimizer.step()

 4.4 预测

for i in range(5):
    predict = model(torch.tensor([test_X[i].flatten()],dtype=torch.float32))
    predict_n = predict.argmax().item()
    plt.subplot(330 + 1 + i)
    plt.imshow(test_X[i], cmap=plt.get_cmap('gray'))
    print('image:')
    plt.show()
    print('predicted:',predict_n,'\n')
        

 

 总体准确率:62.79%

5. 后记

这篇文章存在一个bug。这是笔者后来整理LR模型和softmax模型的目标函数于CrossEntropy函数之间的关系后发现的。各位朋友发现这个bug了吗?快到评论区告诉我。如果你还没发现任何问题,可以移步下边的链接看看你是不是也有一个跟笔者一样的知识漏洞呢?评论区等你哦。深入理解Linear Regression,Softmax模型的损失函数https://blog.csdn.net/marlinlm/article/details/130167585?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22130167585%22%2C%22source%22%3A%22marlinlm%22%7D 


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值