各个深度模型解读(3) softmax 回归 (多分类)

原理

softmax 回归一般用于多分类.

如果我们下图遇到这种分类任务,没得说,反手就是一个逻辑回归.

逻辑回归

按照上图的数据,我们建立一个模型:
y = X W + b y = XW+b y=XW+b

l a b e l = s i g m o i d ( y ) label = sigmoid(y) label=sigmoid(y)

然后,我们的任务就是训练这个W和b,由于这玩意明显只有两个维度的特征, 输出就是一个一维的0或者1,所以我们的W的形状就是(2×1). 然后:

  • 数据正则化
  • 参数初始化为0或随机初始化
  • 计算梯度和errors,更新参数
  • 最后得到模型的参数W和b.
  • 根据W和b画一条直线将其分割: w 1 f 1 + w 2 f 2 + b = 0 w_1f_1+w_2f_2+b=0 w1f1+w2f2+b=0
  • 打完收工

Softmax 回归

而当我们进化到softmax之后, 适应的任务就是多回归了.MNIST数据集就是10回归任务,这也是我们本文的实验.

思路如下:

  • 数据准备

  • 构建模型:

    • linear

    关于torch.nn.linear, 其真正的模型就是:
    y = X W T + b y = XW^T+b y=XWT+b
    其中的W是Pytorch自动生成的.

    在此模型中,原始MNIST数据集的特征数量是784, 需要将模型分成10类. 训练集一共6000条数据.于是:
    X 60000 × 784 , W 10 × 784 X_{60000\times 784} , W_{10\times 784} X60000×784,W10×784
    当然,这只是想象.真正的场景中,我们需要做两步操作,将数据特征搞成自己想要的列,经过一系列经验积累,搞成256列比较合适. 并且每个批次的输入值也是256. 那么每次迭代的时候 X 256 × 256 X_{256\times 256} X256×256, W 256 × 10 W_{256\times 10} W256×10

    所以,现在我们可以明白linear中的num_features和num_classes到底是什么含义了.

    • softmax

    数据经过了linear之后,只是得到了一个数据,如何将数据搞到(0,1)之间呢,用softmax.

    经过了linear产生的 1 × 10 1\times 10 1×10数据经过softmax之后依然是这个形状,但是其中所有的数据都是(0,1)之间,我们可以视其为概率, 其中最大值对应的类就是我们的分类label.

实战

导入必要的工具包

import torch
import torchvision
import sys

print("cuda:{}".format(torch.cuda.is_available()))
print("torch version:{}".format(torch.__version__))
print("torchvision version:{}".format(torchvision.__version__))
print("python version:{}".format(sys.version))
# print(torch.cuda.__version__)

from torchvision import datasets
from torchvision import transforms
from torch.utils.data import DataLoader
import torch.nn.functional as F

设置必要的参数

device = torch.device('cuda:0' if torch.cuda.is_available() else "cpu")

random_seed = 123
learning_rate = 0.1
num_epochs = 10
batch_size = 256

num_features = 784
num_classes = 10
  • random seed 用于确定模型可以复现

其他的参数都是司空见惯的.

数据集准备

train_dataset = datasets.MNIST(root='./data', train=True, transform=transforms.ToTensor(), download=True)
test_dataset = datasets.MNIST(root='./data', train=False, transform=transforms.ToTensor())
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)
for images, labels, in train_loader:
    print('Image batch dimensions:{}'.format(images.shape))
    print('Image label dimensions:{}'.format(labels.shape))
    break
  • train=Truetrain=Flase 用于确定是训练集还是测试集

  • transforms.ToTensor()其实transform是可以做很多数据增强处理的,但是这里没有做

  • 有了Dataset之后,需要有dataloader,dataloader加载的时候可以设置每次epoch中的每次训练导入的数据量,如果显存不足的化,这里可以设置的小一些.

定义模型

class SoftmaxRegression(torch.nn.Module):
    def __init__(self, num_features, num_classes):
        super(SoftmaxRegression, self).__init__()
        self.linear = torch.nn.Linear(num_features, num_classes)
        self.linear.weight.detach().zero_()
        self.linear.bias.detach().zero_()

    def forward(self, x):
        logits = self.linear(x)
        probas = F.softmax(logits, dim=1)
        return logits, probas


model = SoftmaxRegression(num_features=num_features, num_classes=num_classes)
model.to(device)

optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

线性模型

关于torch.nn.linear, 其真正的模型就是:
y = X W T + b y = XW^T+b y=XWT+b
其中的W是Pytorch自动生成的.

在此模型中,MNIST数据集的特征数量是784, 需要将模型分成10类. 训练集一共6000条数据.于是:
X 60000 × 784 , W 10 × 784 X_{60000\times 784} , W_{10\times 784} X60000×784,W10×784
所以,现在我们可以明白linear中的num_features和num_classes到底是什么含义了.

前向传播

前项传播的就是在经过基本模型之后得出结果之后,将这个结果经过一个激活函数.

  • 经过模型得出结果
  • 加激活函数(sigmoid softmax relu)
  • 将得出的结果返回出去

后向传播

后向传播就是两个步骤

  • 计算梯度确定更新方向
  • 更新参数

不过本文的后向传播是用的pytorch自带的更简单的方法,将在之后介绍

训练与评估

torch.manual_seed(random_seed)


def compute_accuracy(model, data_loader):
  	# 设置两个参数,最后的结果就是前者除以后者
  	correct_pred, num_examples = 0, 0
	  
    # data_loader 返回的结果是什么?
    for features, targets in data_loader:
      	# 最初的的features 其实就是图像的矩阵,现在利用view函数将其变成256列(这种训练方式其实在现在已经不太推荐,因为它无法将像素之间的相关性考虑在内.
        features = features.view(-1, 28 * 28).to(device)
       	# targets 就是分类值,一共有10类,我们分别设置为0-9
        targets = targets.to(device)
        # 其实这一步就是调用了模型的forward函数,返回的logits就是线性模型的生成值.将logits值经过softmax得到一个256*10的值.  至于为什么是256行,是因为batch_size设置的为256,所以代码每次训练的数据是256项
        logits, probas = model(features)
        # torch.max(a,0)返回每一列中最大值的那个元素,且返回索引(返回最大元素在这一列的行索引)
        # torch.max(a,1)返回每一行中最大值的那个元素,且返回其索引(返回最大元素在这一行的列索引)
        _, predicted_labels = torch.max(probas, 1)
        
        # 计量数据总数
        num_examples += targets.size(0)
        # 计算分类正确的总数
        correct_pred += (predicted_labels == targets).sum()

    return correct_pred.float() / num_examples * 100

# 训练次数
# epoch 是指所有的训练数据进入了模型并返回了一次
for epoch in range(num_epochs):
    # 大胆猜测一下 batch_idx 可以用于计数器,用于代表当前是第几批次 ,(features,targets)分别代表一个 批次(256条)中的图像(或处理过的特征)以及给定的分类结果.
    for batch_idx, (features, targets) in enumerate(train_loader):
        features = features.view(-1, 28 * 28).to(device) # 将图像矩阵调整到256列,形成图像特征
        targets = targets.to(device)

        logits, probas = model(features) # 现在得到的有一个经过模型后生成的(256✖️10)的矩阵,以及将它经过softmax激活函数之后得到的矩阵. 矩阵每一行中最大的元素对应的列索引就是预测值.

        cost = F.cross_entropy(logits, targets) # 计算cost是为了向后确定向后传播的参数,以便更好的优化模型
        optimizer.zero_grad() # cost 上次计算完成之后,在本次迭代中,optimizer需要将先梯度清零,为了本次的迭代(训练一个batch_size)做好准备.
        cost.backward() # 后向传播,这里pytorch自带的backward()函数,根据上下文猜测,这玩意可以根据计算出梯度方向,以及偏置的更新值
        optimizer.step()# 将根据cost计算出的值乘以学习率按照某种梯度下降策略更新值

        if not batch_idx % 50:
            print('Epoch: %03d/%03d | Batch %03d/%03d | Cost:%.4f' % (
                epoch + 1, num_epochs, batch_idx, len(train_dataset) // batch_size, cost))
		# 这意思是本次epoch将要结束了,模型评估一下让攻城狮看看模型的劳动成果,就是为了邀功
    with torch.set_grad_enabled(False):
        print('Epoch: %03d/%03d training accuracy: %.2f%%' % (
            epoch + 1, num_epochs, compute_accuracy(model, train_loader)))

模型评估

对于分类问题来讲,模型评估无非就是计算正确率.


关于epoch \ batch_size\迭代 三者之间的关系,可以查看文章: epoch batchsize 迭代 傻傻分不清楚


模型测试

print("Test  accuracy:%.2f%%" % (compute_accuracy(model, test_loader)))

模型测试这部分,虽然少,但还是要有的. 就是将数据集换为test_loader重新过一遍模型,计算一下正确率.

image-20200921193834238

image-20200921193856741

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古承风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值