深度学习pytorch--softmax回归(二)

softmax回归的从零开始实现

    • 实验前思考
    • 获取和读取数据
      • 获取数据集
      • 查看数据集
        • 查看下载后的.pt文件
        • 查看mnist_train和mnist_test
      • 读取数据集
        • 查看数据迭代器内容
    • 初始化模型参数
    • 定义softmax函数
    • 定义模型
    • 定义损失函数
    • 计算分类准确率
    • 模型评价--准确率
    • 开始训练
    • 可视化
    • 总结
    • 完整代码

实验前思考

  • 本文不使用框架解决多分类问题。
  • 一定要先明白实验原理。可看博客深度学习pytorch–softmax回归(一)
  • 一定要先弄清楚数据是怎么用Tensor表示的。

获取和读取数据

这里使用Fashion-MNIST为例,训练集60000张,测试集10000张,设置batch_size大小为256。

获取数据集

如果没有下载的话,将download设置为True。

mnist_train=torchvision.datasets.FashionMNIST('./Datasets/FashionMNIST',train=True,download=False,transform=transforms.ToTensor())
mnist_test=torchvision.datasets.FashionMNIST('./Datasets/FashionMNIST',train=False,download=False,transform=transforms.ToTensor())

查看数据集

查看下载后的.pt文件

要使用的是processed文件夹下的training.pttest.pt文件,包含了数据以及其标签,用元组的形式存储。
形如:

(tensor([],dtype=torch.unit8),tensor([]))
  • 第一个tensor表示数据的数量,形状为torch.Size([60000,28,28]),60000表示.pt文件包含1000张图片,28为宽和高都是28个像素,每个像素用一个数字表示(也可以说是图像的特征)。
  • 第二个tensor表示每张图片的真实标签(0-9)。形状为torch.Size([60000]),每个数字代表真实标签。

上次线性回归的数据集是自己手工构造的tensor,这次是图片的tensor表示。

查看mnist_train和mnist_test

查看经过torchvision.datasets.FashionMNIST处理后的mnist_train和mnist_test,

print(mnist_train) #查看mnist_train
print(type(mnist_train)) #查看它的类型
print(len(mnist_train), len(mnist_test))
feature, label = mnist_train[0] #访问数据集的任一个样本
print(feature.shape, label)  # Channel x Height x Width

输出:

Dataset FashionMNISTNumber of datapoints: 60000Root location: ./Datasets/FashionMNISTSplit: TrainStandardTransformTransform: ToTensor()
<class 'torchvision.datasets.mnist.FashionMNIST'>
60000 10000
torch.Size([1, 28, 28]) 9

由上面代码可见,torchvision.datasets.FashionMNIST将原来存储在一个张量的训练数据分成了60000份,可迭代访问或下标访问mnist.train。

  • feature为单张图片的tensor表示,形状为torch.Size([1, 28, 28]),其中1为通道数量.
  • label为int类型,表示真实标签。

读取数据集

DataLoader将之前的数据做成一个批量、随机打乱且可以通过多进程加速读取的迭代器。

batch_size=256
num_workers=0 #多进程加速数据读取,0则不需要额外的进程
train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)

查看数据迭代器内容

for X,y in train_iter:print(X.size())print(y.size())break

输出:

torch.Size([256, 1, 28, 28])
torch.Size([256])

一个X表示256个样本的特征(也就是softmax回归(一)中公式里的4个x,这里是28*28个x),一个y表示其每个样本的标签。

说明DataLoader只是将原来单个数据的张量通过增加一个维度合成了256个数据的张量。通俗地讲就是将256个1*28*28的张量放在一起,然后外面加一层[]。以后升维和降维要有这个思维。

关于该数据集的详细使用可看博客深度学习pytorch–MNIST数据集

初始化模型参数

由于像素(特征)有28*28=786个,所以输入层为一个786长度的向量。
由于为10分类任务,所以输出层的输出个数为10。

因此,根据softmax回归(一)的公式,可以推出 权重为参数为784X10的矩阵,偏置为1X10的矩阵。
上述分析的时候,脑子一定要有神经网络图和公式,就会觉得很明朗。根据公式还能够发现一点,不管是单样本还是批量样本,权重的形状是不发生改变的。

num_inputs=784 #28*28个像素(特征)
num_outputs=10 #分类的个数#权重初始化为均值为0,标准差为0.01的分布。
W=torch.tensor(np.random.normal(0,0.01,(num_inputs,num_outputs)),dtype=torch.float,requires_grad=True) 
b=torch.zeros(num_outputs,dtype=torch.float,requires_grad=True) #偏置初始化为0

得到权重形状为torch.Size([786,10])的W和一个形状为torch.Size(1,10])的偏置b。

定义softmax函数

首先,想一下,根据公式,softmax函数的输入和输出是什么?
输入是网络输出层的结果,也就是每个样本10个输出。此处为批量处理,所以根据softmax回归(一)的公式,可以知道模型输出为一个256*10的矩阵。256为样本数量,10为10个分类的输出。
输出是根据softmax公式将其转化成概率的形式。

def softmax(X): #X为一个形状为256*10的二维张量X_exp=X.exp() #矩阵中每个元素取指数partition=X_exp.sum(dim=1,keepdim=True) #每行进行求和,并且保持维度不变,不懂的话可以看博客return X_exp/partition #实现softmax公式,用了广播机制

先随意定义一个X测试一下函数,下面的sum(dim=1)表示每一行相加,并且降低一个维度。如果dim=0则表示每一列相加。

X = torch.rand((2, 5))
X_prob = softmax(X)
print(X_prob, X_prob.sum(dim=1))

输出:

tensor([[0.2206, 0.1520, 0.1446, 0.2690, 0.2138],[0.1540, 0.2290, 0.1387, 0.2019, 0.2765]]) tensor([1., 1.])

从输出可以看到softmax函数定义的代码没有问题。

定义模型

定义模型之前想一想模型是什么,模型的输入是什么,输出是什么?
模型是一层神经网络+一层softmax函数,
模型的输入是迭代器的X,表示256个图片的像素(数据特征),形状为torch.Size([256, 1, 28, 28]),其中1表示通道数量
模型的输出是softmax函数的输出,形状为torch.Size([256, 10]),256表示batch_size(256)个样本,10表示每个样本对每个分类的概率分布情况。

def net(X):O=torch.mm(X.view(-1, num_inputs),W)+b #如果最后一个维度变了则,按以前的元素顺序来组合。return softmax(O)

由于迭代器中X的形状不对应神经网络输入层该有的形状,所以通过view把X从torch.Size([256, 1, 28, 28])变成torch.Size([256, 784])。
以前不理解为什么经常要像这样用view,现在思路很清晰。主要有2点原因:

  • 1.脑子一定要有神经网络结构(此处只有一层786输入,10输出),可以在纸上画一画。
  • 2.张量降维和升维的思维一定要正确,升维就是加括号,降维就是减少中括号,没有改变内容,不要被形状的数字给迷惑了。

定义损失函数

本实验采用交叉熵损失函数。
输入为预测结果y_hat和真实标签y
其中y_hat为torch.Size([256, 10])的张量,y为torch.Size([256])的张量。
输出为运算结果。

def cross_entropy(y_hat,y): #y_hat为模型输出(所有样本对所有样本的softmax概率值),y为标签(真实值)return - torch.log(y_hat.gather(1, y.view(-1, 1)))

真正计算的时候还需要用.sum()将张量中的元素相加才是损失函数值。
对比之后用框架实现该实验后的loss值才发现在计算完log之后少乘了 预测标签概率值 。算啦,不重要,以后有机会再回来改叭。
这里用到了gather函数,这个函数的作用就是找出y_hat中对应真实标签的概率,举例如下:

y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
y = torch.LongTensor([0, 2])
y_hat.gather(1, y.view(-1, 1))

输出:

tensor([[0.1000],[0.5000]])

0.1就是将真实标签中的0作为索引,在y_hat中得到的,相当于y_hat[0][0]。
0.5就是将真实标签中的2作为索引,在y_hat中得到的,相当于y_hat[1][2]。

计算分类准确率

先计算预测正确的个数,也就是判断每个样本预测最大概率的标签是否和真实标签y相等就可以了。
再除以预测总数,就得到准确率。
下面的代码用的是y_hat处理后的张量和y张量中的每个元素比较,通过float()将true和false分别转换为1,0,再通过mean()求和平均

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

其中dim=1表示每行,dim=0表示每列。

模型评价–准确率

根据上面的思想,可以评价模型net在测试集上的准确率。

def evaluate_accuracy(data_iter,net): #在所有样本上的准确率acc_sum,n=0.0,0for X,y in data_iter:acc_sum+=(net(X).argmax(dim=1) == y).float().sum().item()n+=y.shape[0] #获取总数量(此处每批256)return acc_sum / n

其中net(X)就是y_hat,因为都表示模型的输出,形状为torch.Size([256, 10])。

开始训练

训练步骤:

  • 迭代数据
  • 将数据导入模型得到输出
  • 计算损失函数
  • 反向传播计算梯度
  • 使用优化算法更新参数
  • 梯度清零

每个epoch过后将训练好的参数在测试集上计算一下准确率。

num_epochs=5
lr=0.1
for epoch in range(num_epochs):train_loss_sum=0.0train_acc_sum=0.0n=0 #用来计算数据总数for X,y in train_iter:y_hat=net(X) loss=cross_entropy(y_hat,y).sum() #计算损失函数loss.backward() #反向传播#参数更新sgd([W,b],lr,batch_size)#梯度清零W.grad.data.zero_()b.grad.data.zero_()train_loss_sum+=loss.item()train_acc_sum+=(y_hat.argmax(dim=1) == y).sum().item()n+=y.shape[0]test_acc=evaluate_accuracy(test_iter,net)print('epoch {}, loss {:.4f}, train acc {:.3f}, test acc {:.3f}'.format(epoch + 1, train_loss_sum / n, train_acc_sum / n, test_acc))   

可视化

对训练结果进行可视化。
下图第一行文本为真实标签。
第二行文本为模型预测结果。
第三行为图像输出(预先给定的图像)。

def use_svg_display():"""Use svg format to display plot in jupyter"""display.set_matplotlib_formats('svg')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]def show_fashion_mnist(images, labels):use_svg_display()# 这里的_表示我们忽略(不使用)的变量_, 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])

总结

  • 所谓特征就是每个像素的的tensor表示。
  • 提取特征就是通过一个权重w与特征x相乘,权重越大则说明该像素的特征提取得越多。
  • 张量降维和升维的思维要正确,升维就是加括号,降维就是减少中括号,没有改变内容,不要被形状的数字给迷惑了。
  • 写函数或者模型的时候,先想一想要实现什么功能,再想一想输入和输出是什么。

完整代码

#softmax回归的从零开始实现(MINST数据集)
import torch
import torchvision
import numpy as np
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
from IPython import display#获取数据集
mnist_train=torchvision.datasets.FashionMNIST('./Datasets/FashionMNIST',train=True,download=False,transform=transforms.ToTensor())
mnist_test=torchvision.datasets.FashionMNIST('./Datasets/FashionMNIST',train=False,download=False,transform=transforms.ToTensor())#读取数据集
batch_size=256
num_workers=0 #多进程加速数据读取,0则不使用多进程
train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)#初始化模型参数
num_inputs=784 #28*28个像素(特征)
num_outputs=10 #分类的个数W=torch.tensor(np.random.normal(0,0.01,(num_inputs,num_outputs)),dtype=torch.float,requires_grad=True)
b=torch.zeros(num_outputs,dtype=torch.float,requires_grad=True)#定义模型
def softmax(X):X_exp=X.exp() #矩阵中每个元素取指数partition=X_exp.sum(dim=1,keepdim=True) #每行进行求和,并且保持维度不变,不懂的话可以看博客return X_exp/partition #实现softmax公式,用了广播机制def net(X):O=torch.mm(X.view(-1, num_inputs),W)+breturn softmax(O)#定义损失函数
def cross_entropy(y_hat,y): #y_hat为模型输出(所有样本对所有样本的softmax概率值),y为标签(真实值)return - torch.log(y_hat.gather(1, y.view(-1, 1)))#模型评价
def evaluate_accuracy(data_iter,net): #在所有样本上的准确率acc_sum,n=0.0,0for X,y in data_iter:acc_sum+=(net(X).argmax(dim=1) == y).float().sum().item()n+=y.shape[0] #获取总数量(此处每批256)return acc_sum / n#定义优化算法
def sgd(params,lr,batch_size):for param in params:param.data-=lr*param.grad/batch_size #除以batch_size之后计算批量loss的时候就不用求平均了,只需要sum()
#开始训练
num_epochs=5
lr=0.1
for epoch in range(num_epochs):train_loss_sum=0.0train_acc_sum=0.0n=0 #用来计算数据总数for X,y in train_iter:y_hat=net(X) loss=cross_entropy(y_hat,y).sum() #计算损失函数loss.backward() #反向传播#参数更新sgd([W,b],lr,batch_size)#梯度清零W.grad.data.zero_()b.grad.data.zero_()train_loss_sum+=loss.item()train_acc_sum+=(y_hat.argmax(dim=1) == y).sum().item()n+=y.shape[0]test_acc=evaluate_accuracy(test_iter,net)print('epoch {}, loss {:.4f}, train acc {:.3f}, test acc {:.3f}'.format(epoch + 1, train_loss_sum / n, train_acc_sum / n, test_acc))   #可视化
def use_svg_display():"""Use svg format to display plot in jupyter"""display.set_matplotlib_formats('svg')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]def show_fashion_mnist(images, labels):use_svg_display()# 这里的_表示我们忽略(不使用)的变量_, 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])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/333767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML块级元素/块标签/块元素

文章目录块元素的特点块元素清单block level element. 块级元素想在同一行显示需浮动或者 display:inline。 块元素的特点 每个块级元素都是独自占一行&#xff0c;其后的元素也只能另起一行&#xff0c;并不能两个元素共用一行&#xff1b; 元素的高度、宽度、行高、顶边距、…

物联卡查询流量_电信物联卡官网是多少?如何快速查询流量信息?

高速率设备的使用场景需要用到5G&#xff0c;中速率LET-Cat1应用范围更广&#xff0c;而低速率则要靠窄带物联网NB-IOT去维护了。这三种网络制式全都与物联网息息相关&#xff0c;这就能知道为什么国家层面对物联网基础设施建设这么重视了。电信物联卡在智能化硬件中有优秀表现…

java8日期转时间戳_Java 8日期和时间

java8日期转时间戳如今&#xff0c;一些应用程序仍在使用java.util.Date和java.util.Calendar API&#xff0c;包括使我们的生活更轻松地使用这些类型的库&#xff0c;例如JodaTime。 但是&#xff0c;Java 8引入了新的API来处理日期和时间&#xff0c;这使我们可以对日期和时间…

HTML行内元素/行级元素/内联元素/行标签/内联标签/行内标签/行元素

文章目录行内元素的特点行内元素清单可变元素列表inline element. 也叫行级元素、内联元素。行内元素默认设置宽度是不起作用&#xff0c;需设置 display:inline-block 或者 block 才行。 行内元素的特点 可以和其他元素处于一行&#xff0c;不用必须另起一行&#xff1b; 元…

深度学习pytorch--softmax回归(三)

softmax回归的简洁实现获取和读取数据定义和初始化模型softmax和交叉熵损失函数定义优化算法模型评价训练模型小结完整代码前两篇链接: 深度学习pytorch–softmax回归(一) 深度学习pytorch–softmax回归(二) 本文使用框架来实现模型。 获取和读取数据 我们仍然使用Fashion-M…

正则表达式的分类

文章目录一、正则表达式引擎二、正则表达式分类三、正则表达式比较四、Linux/OS X 下常用命令与正则表达式的关系一、正则表达式引擎 正则引擎大体上可分为不同的两类&#xff1a;DFA 和 NFA&#xff0c;而 NFA 又基本上可以分为传统型 NFA 和 POSIX NFA。 DFA(Deterministic …

spock测试_使用Spock测试您的代码

spock测试Spock是针对Java和Groovy应用程序的测试和规范框架。 Spock是&#xff1a; 极富表现力 简化测试的“给定/何时/然后” 语法 与大多数IDE和CI服务器兼容。 听起来不错&#xff1f; 通过快速访问Spock Web控制台&#xff0c;您可以非常快速地开始使用Spock。 当您有…

深度学习pytorch--多层感知机(一)

多层感知机隐藏层激活函数ReLU函数sigmoid函数tanh函数多层感知机小结我们已经介绍了包括线性回归和softmax回归在内的单层神经网络。然而深度学习主要关注多层模型。在本节中&#xff0c;我们将以多层感知机&#xff08;multilayer perceptron&#xff0c;MLP&#xff09;为例…

太阳能板如何串联_光伏板清洁专用的清洁毛刷

光伏发电是利用半导体界面的光生伏特效应将光能直接转变为电能的一种技术。主要由太阳电池板&#xff08;组件&#xff09;、控制器和逆变器三大部分组成。主要部件由电子元器件构成。太阳能电池经过串联后进行封装保护可形成大面积的太阳电池组件&#xff0c;再配合上功率控制…

java 异步等待_Java中的异步等待

java 异步等待编写异步代码很困难。 试图了解异步代码应该做什么的难度更大。 承诺是尝试描述延迟执行流程的一种常见方式&#xff1a;首先做一件事&#xff0c;然后再做另一件事&#xff0c;以防万一出错时再做其他事情。 在许多语言中&#xff0c;承诺已成为协调异步行为的实…

cass生成曲线要素_干货在线 | CASS入门指南——道路断面计算土方

CASS操作指南——道路断面计算土方法小伙伴们赶紧学起来&#xff01;道路类的土方工程&#xff0c;主要用CASS的断面法土方计算之道路断面来计算。整个计算过程主要分为以下四步&#xff1a;菜单截图第一步&#xff1a;绘制道路中心线道路的中心线&#xff0c;一般由直线段和缓…

正则表达式的捕获性分组/反向引用

文章目录分组捕获性分组和反向引用分组 正则的分组主要通过小括号来实现&#xff0c;括号包裹的子表达式作为一个分组&#xff0c;括号后可以紧跟限定词表示重复次数。如下&#xff0c;小括号内包裹的 abc 便是一个分组: // (abc) 表示匹配一个或多个"abc"&#xf…

深度学习pytorch--多层感知机(二)

多层感知机的从零开始实现获取和读取数据定义模型参数定义激活函数定义模型定义损失函数训练模型小结我们已经从上一节里了解了多层感知机的原理。下面&#xff0c;我们一起来动手实现一个多层感知机。首先导入实现所需的包或模块。 import torch import numpy as np获取和读取…

jwt同一会话_在会话中使用JWT

jwt同一会话这个话题已经在黑客新闻&#xff0c;reddit和博客上讨论了很多次。 共识是–请勿使用JWT&#xff08;用于用户会话&#xff09;。 而且我在很大程度上同意对JWT的典型论点 &#xff0c; 典型的“但我可以使其工作……”的解释以及JWT标准的缺陷的批评 。 。 我不会…

表必须要有主键吗_玄关隔断什么材质好?玄关隔断必须要做吗?

为了避免一到门口就能够看到全部室内的东西&#xff0c;为了更好的保护家居的隐私&#xff0c;目前有很多人都会在玄关的位置加一个隔断&#xff0c;而玄关隔断什么材质好?在做玄关隔断的时候&#xff0c;有些人觉得做了隔断会太浪费空间了&#xff0c;而玄关隔断必须要做吗?…

深度学习pytorch--多层感知机(三)

使用pytorch框架实现多层感知机和实现softmax回归唯一的不同在于我们多加了一个全连接层作为隐藏层。它的隐藏单元个数为256&#xff0c;并使用ReLU函数作为激活函数。#模型的核心代码为:nn.Linear(num_inputs, num_hiddens),nn.ReLU(),nn.Linear(num_hiddens, num_outputs),

mysql 日期索引的使用_日期使用

mysql 日期索引的使用时区糟透了。 特别是夏令时。 我不介意像与此行为相关的编程错误那样&#xff0c;不停移动时钟或失去一个小时的睡眠。 更糟糕的是Java的旧日期/时间API。 Java社区通过JSR 310公开承认了这一点&#xff0c;该JSR 310代替了Java Date&#xff06;Time API…

axure元件库 文件上传_手把手教你打造一套属于产品经理自己的元件库

之前有篇文章聊完了如何打造一套属于自己的原型图设计规范&#xff0c;今天咱们来聊聊如何打造一套属于自己的元件库。毕竟&#xff0c;每个追求效率的PM&#xff0c;总会拥有一个专属自己的Axure元件库&#xff0c;并不断打磨优化。今天就教大家一步一步创建属于自己的Axure元…

KMP算法笔记

1.KMP算法本质上就是对朴素匹配算法(BF)的一个优化&#xff0c;减少朴素匹配算法中不必要匹配的次数&#xff0c;核心代码和朴素匹配算法差不多&#xff0c;BF是移动字串逐个字符匹配&#xff0c;每次模式串(子串)匹配只移动一个字符单位&#xff0c;而KMP算法是每次模式串匹配…

正则表达式的非捕获性分组

非捕获性分组&#xff0c;通常由一对括号加上 ?: 加上子表达式组成&#xff0c;非捕获性分组不会创建反向引用&#xff0c;就好像没有括号一样。如下: var color "#808080"; var output color.replace(/#(?:\d)/,"$1""~~"); console.log(Re…