【PyTorch入门】之一文看懂如何用PyTorch训练softmax回归模型识别图像

先打个广告哈。我自己做的公众号【拇指笔记】,每天写写我自己学习中记下的笔记,欢迎各位大神关注一下~

本篇文章完整程序可以在我的公众号后台回复"pysoftmax"获取,欢迎各位关注!

1. 使用pytorch实现softmax回归模型

使用pytorch可以更加便利的实现softmax回归模型。

1.1 获取和读取数据

读取小批量数据的方法:

  1. 首先是获取数据,pytorch可以通过以下代码很方便的获取Fashion-MNIST数据集。

    mnist_train = torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST',train=True,download=True,transform=transforms.ToTensor())
    
    mnist_test = torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST',train=False,download=True,transform=transforms.ToTensor())
    
    #参数
    
    #root : processed/training.pt 和 processed/test.pt 的主目录 
    #train : True = 训练集, False = 测试集
    #download : True = 从互联网上下载数据集,并把数据集放在root目录下. 如果数据集之前下载过,将处理过的数据(minist.py中有相关函数)放在processed文件夹下
    #transform = transforms.ToTensor():使所有数据转换为Tensor
    
  2. 然后是生成一个迭代器,用来读取数据

    #生成迭代器
    train_iter = torch.utils.data.DataLoader(mnist_train,batch_size=batch_size,shuffle = True,num_workers = 0)
    
    test_iter = torch.utils.data.DataLoader(mnist_test,batch_size = batch_size,shuffle=False,num_workers=0)
    #参数
    
    #dataset:Dataset类型,从其中加载数据
    #batch_size:int类型,每个批量加载多少个数
    #shuffle:bool类型,每个学习周期都打乱顺序
    #num_workers:int类型,加载数据时使用多少子进程。默认值为0.
    #collate_fn:定义如何取样本,可通过定义自己的函数来实现。
    #pin_memory:锁页内存处理。
    #drop_last:bool类型,如果有剩余的样本,True表示丢弃;Flase表示不丢弃
    

1.2 定义和初始化模型

由softmax回归模型的定义可知,softmax回归模型只有权重参数和偏差参数。因此可以使用神经网络子模块中的线性模块。
o 1 = w 11 x 1 + w 21 x 2 + w 31 x 3 + w 41 x 4 + b 1 , o 2 = w 12 x 1 + w 22 x 2 + w 32 x 3 + w 42 x 4 + b 2 , o 3 = w 13 x 1 + w 23 x 2 + w 33 x 3 + w 43 x 4 + b 3 , o_1=w_{11}x_1+w_{21}x_2+w_{31}x_3+w_{41}x_4+b_1, \\o_2=w_{12}x_1+w_{22}x_2+w_{32}x_3+w_{42}x_4+b_2, \\o_3=w_{13}x_1+w_{23}x_2+w_{33}x_3+w_{43}x_4+b_3,

  1. 首先定义网络,softmax回归是一个两层的网络,所以只需要定义输入层和输出层即可。
num_inputs = 784
num_outputs = 10

class LinearNet(nn.Module):
    def __init__(self,num_inputs,num_outputs):
        super(LinearNet,self).__init__()
        self.linear = nn.Linear(num_inputs,num_outputs)
        #定义一个输入层
        
    #定义向前传播(在这个两层网络中,它也是输出层)
    def forward(self,x):
        y = self.linear(x.view(x.shape[0],-1))
        #将x换形为y后,再继续向前传播
        return y
    
net = LinearNet(num_inputs,num_outputs)
  1. 初始化参数

使用torch.nn中的init可以快速的初始化参数。我们令权重参数为均值为0,标准差为0.01的正态分布。偏差为0。

init.normal_(net.linear.weight, mean=0, std=0.01)
init.constant_(net.linear.bias, val=0) 

1.3 softmax运算和交叉熵损失函数

分开定义softmax运算和交叉熵损失函数会造成数值不稳定。因此PyTorch提供了一个具有良好数值稳定性且包括softmax运算和交叉熵计算的函数。

loss = nn.CrossEntropyLoss()

1.4 定义优化算法

依然使用小批量随机梯度下降作为优化算法。定义学习率为0.1。

optimizer = torch.optim.SGD(net.parameters(),lr=0.01)

1.5 计算分类准确率

计算准确率的原理:

我们把预测概率最大的类别作为输出类别,如果它与真实类别y一致,说明预测正确。分类准确率就是正确预测数量与总预测数量之比

首先我们需要得到预测的结果。

从一组预测概率(变量y_hat)中找出最大的概率对应的索引(索引即代表了类别)

#argmax(f(x))函数,对f(x)求最大值所对应的点x。我们令f(x)= dim=1,即可实现求所有行上的最大值对应的索引。
A = y_hat.argmax(dim=1)	
#最终输出结果为一个行数与y_hat相同的列向量

然后我们需要将得到的最大概率对应的类别与真实类别(y)比较,判断预测是否是正确的

B = (y_hat.argmax(dim=1)==y).float()
#由于y_hat.argmax(dim=1)==y得到的是ByteTensor型数据,所以我们通过.float()将其转换为浮点型Tensor()

最后我们需要计算分类准确率

我们知道y_hat的行数就对应着样本总数,所以,对B求平均值得到的就是分类准确率

(y_hat.argmax(dim=1)==y).float().mean()

上一步最终得到的数据为tensor(x)的形式,为了得到最终的pytorch number,需要对其进行下一步操作

(y_hat.argmax(dim=1)==y).float().mean().item()
#pytorch number的获取统一通过.item()实现

整理一下,得到计算分类准确率函数

def accuracy(y_hat,y):
    return (y_hat.argmax(dim=1).float().mean().item())

作为推广,该函数还可以评价模型net在数据集data_iter上的准确率。

def net_accurary(data_iter,net):
    right_sum,n = 0.0,0
    for X,y in data_iter:
    #从迭代器data_iter中获取X和y
        right_sum += (net(X).argmax(dim=1)==y).float().sum().item()
        #计算准确判断的数量
        n +=y.shape[0]
        #通过shape[0]获取y的零维度(列)的元素数量
    return right_sum/n

1.6 训练模型

num_epochs = 5
#一共进行五个学习周期

def train_softmax(net,train_iter,test_iter,loss,num_epochs,batch_size,optimizer,net_accurary):
    for epoch in range(num_epochs):
        #损失值、正确数量、总数 初始化。
        train_l_sum,train_right_sum,n= 0.0,0.0,0
        
        for X,y in train_iter:
            y_hat = net(X)
            l = loss(y_hat,y).sum()
            #数据集损失函数的值=每个样本的损失函数值的和。            
            optimizer.zero_grad()			#对优化函数梯度清零
            l.backward()	#对损失函数求梯度
            optimizer(params,lr,batch_size)
            
            train_l_sum += l.item()
            train_right_sum += (y_hat.argmax(dim=1) == y).sum().item()
            n += y.shape[0]
            
        test_acc = net_accurary(test_iter, net)	#测试集的准确率
        print('epoch %d, loss %.4f, train right %.3f, test acc %.3f' % (epoch + 1, train_l_sum / n, train_right_sum / n, test_acc))
        
train_softmax(net,train_iter,test_iter,cross_entropy,num_epochs,batch_size,optimizernet_accurary,net_accurary)

1.7 预测

使用训练好的模型对测试集进行预测

做一个模型的最终目的当然不是训练了,所以来预测一下试试。

#将样本的类别数字转换成文本
def get_Fashion_MNIST_labels(labels):
    text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
                   'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
    return [text_labels[int(i)] for i in labels]
    #labels是一个列表,所以有了for循环获取这个列表对应的文本列表

#显示图像
def show_fashion_mnist(images,labels):
    display.set_matplotlib_formats('svg')
    #绘制矢量图
    _,figs = plt.subplots(1,len(images),figsize=(12,12))
    #设置添加子图的数量、大小
    for f,img,lbl in zip(figs,images,labels):
        f.imshow(img.view(28,28).numpy())
        f.set_title(lbl)
        f.axes.get_xaxis().set_visible(False)
        f.axes.get_yaxis().set_visible(False)
    plt.show()

#从测试集中获得样本和标签
X, y = iter(test_iter).next()

true_labels = get_Fashion_MNIST_labels(y.numpy())
pred_labels = get_Fashion_MNIST_labels(net(X).argmax(dim=1).numpy())

#将真实标签和预测得到的标签加入到图像上
titles = [true + '\n' + pred for true, pred in zip(true_labels, pred_labels)]

show_fashion_mnist(X[0:9], titles[0:9])

欢迎各位关注【拇指笔记】,每天更新我的学习笔记~
在这里插入图片描述

发布了31 篇原创文章 · 获赞 72 · 访问量 4953

猜你喜欢

转载自blog.csdn.net/weixin_44610644/article/details/104671738