先打个广告哈。我自己做的公众号【拇指笔记】,每天写写我自己学习中记下的笔记,欢迎各位大神关注一下~
本篇文章完整程序可以在我的公众号后台回复"pysoftmax"获取,欢迎各位关注!
1. 使用pytorch实现softmax回归模型
使用pytorch可以更加便利的实现softmax回归模型。
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
-
然后是生成一个迭代器,用来读取数据
#生成迭代器 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,
o1=w11x1+w21x2+w31x3+w41x4+b1,o2=w12x1+w22x2+w32x3+w42x4+b2,o3=w13x1+w23x2+w33x3+w43x4+b3,
- 首先定义网络,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)
- 初始化参数
使用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])
欢迎各位关注【拇指笔记】,每天更新我的学习笔记~