Softmax回归多分类网络(PyTorch实现)

虽然说深度学习的教程已经烂大街了,基础理论也比较容易掌握,但是真正让自己去实现的时候还是有一些坑。一方面教程不会涉及太多具体的工程问题,另一方面啃PyTorch的英文文档还是有点麻烦。记录一下,就当是作业报告了。

获取数据集

首先导入所需要的包:

import torch
import torch.nn as nn
import torch.utils.data as Data
import numpy as np
import matplotlib.pyplot as plt

所用的数据集共有500条,输入特征feature_n = 8,输出类别lables_n = 4。取前两行数据看看数据的格式:

x1 x2 x3 x4 x5 x6 x7 x8 class label
0.4812 0.7790 0.8904 0.7361 0.9552 0.2119 0.7992 0.2409 4
0.4472 0.5985 0.7859 0.5035 0.6912 0.4038 0.0787 0.2301 1

我们将前400条数据作为训练集,后100条数据作为测试集。

定义一个函数用于从文件中获取此数据集:

def get_data(filename):
    dataset = np.loadtxt(filename)   
    x_train = dataset[0:400,0:8]
    raw_y_train = dataset[0:400,8:]
    x_test = dataset[400:,0:8]
    raw_y_test = dataset[400:,8:]
    
    y_train = np.zeros((400,4),dtype = np.int)
    y_test = np.zeros((100,4),dtype = np.int)

    y_train = raw_y_train - 1
    y_test = raw_y_test - 1

    #for i in range(400):
    #    y_train[i,int(raw_y_train[i])-1]=1
    
    #for j in range(100):
    #    y_test[j,int(raw_y_test[j])-1]=1
        
    return x_train,y_train,x_test,y_test

从原理上讲Softmax分类器的输出个数应与class label的数量相同,理想情况下正确的那一项为1,其他为0。那么class label4时,理想预测值应为[0, 0, 0, 1] ,而数据集中给出的值为[4] 。如果是用NumPy手动搭建网络和写Softmax函数,那么就需要把y_train处理成二维矩阵。

但是对于PyTorch中提供的损失函数torch.nn.CrossEntropyLoss()来说,数据格式稍有不同。torch.nn.CrossEntropyLoss()第一个参数y_predbatch_size * labels_n大小的矩阵,第二个参数y是一维的batch_size大小的向量,且数据范围为[0, labels_n -1],所以要在y_train的基础上减1,把标签1/2/3/4变成0/1/2/3 。

设置批训练

读取进来的数据集还是ndarray格式的,我们先将它们转化为tensor

x_train,y_train,x_test,y_test = get_data('dataset.txt')    
x_train = torch.from_numpy(x_train).type(torch.FloatTensor)
y_train = torch.from_numpy(y_train).type(torch.LongTensor)

注意对转换后的数据格式有要求。这也是损失函数torch.nn.CrossEntropyLoss()的要求,预测概率必须为float,正确标签必须为long

之后建立训练集并加载,测试集同理 :

train_set = Data.TensorDataset(x_train,y_train)

train_loader = Data.DataLoader(
            dataset=train_set,
            batch_size=BATCH_SIZE,
            shuffle=True
            )

在《动手学习深度学习》书中采用了自己手写的迭代器进行批训练的数据迭代。我个人觉得PyTorch提供的DataLoader工具更加简单好用。

定义模型

采用PyTorch提供的快速搭建法进行搭建神经网络,包含隐藏层和输出层共2层。需要注意一点,损失函数torch.nn.CrossEntropyLoss()中已经包含了Softmax函数,所以我们的神经网络直接线性输出即可。

net = nn.Sequential(
            nn.Linear(8,50),
            nn.ReLU(),
            nn.Linear(50,4)
            )

之后定义一些训练模型的函数和参数:

EPOCH = 5000
BATCH_SIZE = 100
LR = 0.01
LOSS_FUNC = nn.CrossEntropyLoss() 
OPTIMIZER = torch.optim.SGD(net.parameters(), lr=LR)  

神经网络建立后本身会对参数w、b进行初始化。因为我也不知道应该初始化为多少比较合适,所以在此不进行显式的初始化而采用其默认的。

训练模型

for epoch in range(1,EPOCH+1):
    loss_sum = 0.0
    for step,(x,y) in enumerate(train_loader):
        y_pred = net(x)
        y = y.squeeze() #修正标签格式
        loss = LOSS_FUNC(y_pred,y)
        loss_sum += loss
        OPTIMIZER.zero_grad()
        loss.backward()
        OPTIMIZER.step()
    print("epoch: %d, loss: %f" %(epoch,loss_sum/BATCH_SIZE))

之前说过损失函数对数据格式有要求。我们的标签y实际上还是二维矩阵,大小为batch_size * 1,所以在计算损失函数前需要进行降维。

测试模型

acc_sum = 0.0
acc_sum += (net(x_test).argmax(dim=1) == y_test.squeeze()).sum()     
print("test accuracy: %f" %(acc_sum/100)) 

用测试集进行测试可知准确率能达到93%。

猜你喜欢

转载自www.cnblogs.com/whitepony/p/11869417.html