文章目录
- 数据加载
- 1、为何在模型中使用数据加载器
- 2、数据集类
- 2.1 Dataset基类介绍
- 2.2 案例
- 2.3 迭代数据集
- 3、自带数据集
- 3.1 torchversion.datasets
- 4、实现手写数字识别
- 4.1 思路和流程分析
- 4.2 准备训练集和测试集
- 4.3 构建模型
- 4.4 损失函数
- 4.5 训练模型
- 4.6 模型保存和加载
- 4.7 模型评估
数据加载
1、为何在模型中使用数据加载器
- 在前面的线性回归模型中,我们使用的数据很少,所以直接把全部数据放到模型中去使用。
- 但是在深度学习中,数据量通常是都非常多,非常大的,如此大量的数据,不可能一次性的在模型中进行向前的计算和反向传播,经常我们会对整个数据进行随机的打乱顺序,把数据处理成一个个的batch,同时还会对数据进行预处理。
2、数据集类
2.1 Dataset基类介绍
通常继承
torch.until.data.Dataset
实现对数据集的加载。
class Dataset(object):
r"""An abstract class representing a :class:`Dataset`.
All datasets that represent a map from keys to data samples should subclass
it. All subclasses should overwrite :meth:`__getitem__`, supporting fetching a
data sample for a given key. Subclasses could also optionally overwrite
:meth:`__len__`, which is expected to return the size of the dataset by many
:class:`~torch.utils.data.Sampler` implementations and the default options
of :class:`~torch.utils.data.DataLoader`.
.. note::
:class:`~torch.utils.data.DataLoader` by default constructs a index
sampler that yields integral indices. To make it work with a map-style
dataset with non-integral indices/keys, a custom sampler must be provided.
"""
def __getitem__(self, index):
raise NotImplementedError
def __add__(self, other):
return ConcatDataset([self, other])
# No `def __len__(self)` default?
# See NOTE [ Lack of Default `__len__` in Python Abstract Base Classes ]
# in pytorch/torch/utils/data/sampler.py
2.2 案例
# -*- coding: utf-8 -*-
""" @Time : 2021/5/17 9:28
@Author : XXX
@Site :
@File : DemoGetData.py
@Software: PyCharm
"""
from torch.utils.data import Dataset
class MyDLoadData(Dataset):
def __init__(self):
self.file = open('../databases/test.txt').readlines()
def __getitem__(self, item):
return self.file[item]
def __len__(self):
return len(self.file)
if __name__ == '__main__':
data =MyDLoadData()
print("第一行的数据为:",data[1])
print("该数据集的长度为:",len(data))
运行结果
2.3 迭代数据集
- 批处理数据(Batching the data)
- 打乱数据(Shuffling the data)
- 使用多线程mu1tiprocessing 并行加载数据。
在pytorch中torch.until. data.DataLpader
提供了上述的所用方法
# -*- coding: utf-8 -*-
""" @Time : 2021/5/17 9:28
@Author : XXX
@Site :
@File : DemoGetData.py
@Software: PyCharm
"""
from torch.utils.data import DataLoader, Dataset
class MyDLoadData(Dataset):
def __init__(self):
self.file = open('../databases/test.txt').readlines()
# 对数据进行处理返回
def __getitem__(self, item):
return self.file[item]
# 返回数据的长度
def __len__(self):
return len(self.file)
if __name__ == '__main__':
my_data = MyDLoadData()
data_load = DataLoader(dataset=my_data, batch_size=2, shuffle=True, num_workers=2)
"""
参数:
· dataset:提前定义的dataset的实例;
· batch_size:传入数据的batch的大小,常用128/256;
· shuffle:【bool】获取数据的时候是否打乱;
· num_workers:加载数据的线程数。
*** 注意:数据总长度的:batch_size*len(data_load)
"""
for i in data_load:
print(i)
break
3、自带数据集
torchvision
:提供对图片数据处理相关的API和数据。
- 数据位置:
torchvision.datasets
torchtext
:提供了对文本数据处理相关的API和数据。
- 数据位置:
torchtext.datasets
3.1 torchversion.datasets
torchvision.datasets.MNIST(root='files', train, download, transform)
"""
参数:
· root:参数表示数据存放的位置;
· train:【bool】使用训练集的数据还是测试集的数据;
· download:【bool】是否需要下载数据到root目录;
· transform:实现的对图片的处理函数。
"""
下载
MNIST是由Yann Lecun等人提供的免费的图像识别的数据集,其中包括60000个训练样本和10000个测试样本,其中图拍了的尺寸已经进行的标准化的处理,都是黑白的图像,大小为28×28
import torchvision
dataset = torchvision.datasets.MNIST(root='../databases', download=True)
4、实现手写数字识别
4.1 思路和流程分析
- 准备数据
- 构建模型
- 模型训练
- 模型评估
- 保存模型
4.2 准备训练集和测试集
下载数据:
torchvision.datasets.MNIST(root='files', train, download, transform)
使用这个下载即可
数据处理:
ToTensor:
torchvision.transforms.ToTensor
:把一个取值范围是[0, 255]的PIL.Image
或者shape
为(H,W,C)的numpy.ndarray
,转换形状为[C,H,W],取值范围是[0,1,0]的torch.FloatTensor
。- 其中(H,W,C)为(高,宽,通道数),黑白图片的通道数只有1,其中每个像素点的取值为[0,255],彩色图片的通道数为(R,G,B)每个通道的每个像素点的取值为[0,255],三个通道的颜色相互叠加,形成了各种颜色。
result = transform.ToTensor()(dataset[0][0])
Normalize:
torchvision.transforms.Normalize(mean, std)
- 给定均值:mean,shape和图片的通道数相同(指的是
每个通道的均值
),方差:std,和图片的通道数(指的是每个通道的方差
),将会把Tensor规范化处理。=>Normalized_image = (image-mean)/std
。Compose(transforms)
- 使用列表的存储方式,将多个transform组合起来。
4.3 构建模型
- 激活函数:
torch.nn.functional
- 原始输入数据的形状:
[batch_size, 1,28, 28]
;- 进行形状的修改:
[batch_size, 28*28]
(全连接层是在进行矩阵的乘法操作);- 第一个全连接层的输出形状:
[batch_size, 28]
;- 激活函数不会修改数据的形状;
- 第二个全连接层的输出形状:
[batch_size, 10]
10个类别。
4.4 损失函数
对于
二分类
,我们使用sigmoid
计算对数似然损失,来定义二分类的损失。
- 在二分类中我们有正类和负类,正类的概率为:,而父类的概率:1-P(x);
- 将这个结果进行计算对数似然损失就可以到的最终的损失。
而对于多分类
,我们使用softmax
函数,与sigmoid
的区别在于我们需要去计算样本属于每个类别的概率,需要计算多次,而sigmoid只需计算一次。
例如:输入2.3,2.4,5.6后的结果为:
在经过前面的计算后,还需要进行对数似然损失的计算得到交叉熵损失。
实现损失的俩种方法
# 第一种
criterion = nn.CrossEntropyLoss()
loss = criterion(input, targtet)
# 第二种
# 对输出值计算softmax和取对数
output = F.log_softmax(x, dim=-1)
# 使用带权损失
loss = F.nll_loss(output, target)
带权损失定义:
ln = -Σwi*xi
,log§作为xi,真实值Y作为权重。
4.5 训练模型
- 实例化模型
- 实例化优化器,实例化损失函数
- 获取,遍历dataloder
- 梯度置为0
- 进行向前计算
- 计算损失
- 反向传播
- 更新参数
4.6 模型保存和加载
模型保存:
torch.save(mnist_net.state_dict(), 保存路径)
torch.save(optimizer.state_dict(),保存路径)
模型加载
mnist_net.load_state_dict(torch.load(保存路径))
optimizer.load_state_dict(torch.load(保存路径))
4.7 模型评估
- 不需要计算
梯度
;- 需要收集
损失
和准确率
,用来计算平均损失
和平均准确率
;- 损失的计算和训练时候损失的计算方法相同;
- 准确率的计算:
- 模型的输出为
[batch_size,10]
的形状;- 其中最大值的位置就是其预测的目标值(预测值进行过sotfmax后为概率,sotfmax中分母都是相同的,
分子越大,概率越大
);- 最大值的位置获取的方法可以使用
torch.max
,返回最大值和最大值的位置;- 返回最大值的位置后,和
真实值
( [batch_size])进行对比,相同表示预测成功。