1.每次采用一个样本进行随机梯度下降,会得到随机性较好的训练结果,但是速度较慢,训练时间长
2.加入batch,用全部的样本进行训练时速度十分快,但是会训练效果会下降。
所以在这里引入mini-batch,综合二者的优点,得到折衷的结果。
batch_size(批量大小):进行一次前馈、反馈、更新所用到的样本数量
iteration(迭代次数):样本数量/批量大小
一般来说PyTorch中深度学习训练的流程:
Dataset负责建立索引到样本的映射,DataLoader负责以特定的方式从数据集中迭代的产生 一个个batch的样本集合。在enumerate过程中实际上是dataloader按照其参数sampler规定的策略调用了其dataset的getitem方法。
简介:
1.torch.utils.data.Dataset是代表自定义数据集方法的抽象类,你可以自己定义你的数据类继承这个抽象类,非常简单,只需要定义__len__和__getitem__这两个方法就可以。
2.通过继承torch.utils.data.Dataset的这个抽象类,我们可以定义好我们需要的数据类。当我们通过迭代的方式来取得每一个数据,但是这样很难实现取batch,shuffle或者多线程读取数据,所以pytorch还提供了一个简单的方法来做这件事情,通过torch.utils.data.DataLoader类来定义一个新的迭代器,用来将自定义的数据读取接口的输出或者PyTorch已有的数据读取接口的输入按照batch size封装成Tensor。
Dataset成员函数:
下面通过介绍python定制容器的方式来介绍__len__(self),getitem(self)两种方法。
在python中,像序列类型(如列表,元组和字符串)或映射类型(如字典)都属于容器类型。讲定制容器,那就必须要知道,定制容器有关的一些协议:
如果你希望定制的容器是不可变的话,你只需要定义__len__()和__getitem__这两个魔法方法。
如果你希望定制的容器是可变的话,除了__len__()和__getitem__这两个方法,还需要定义__setitem__()和__delitem__()两个方法。
举例说明(处理图像数据集):
这里我们的图片文件储存在“./data/faces/”文件夹下,图片的名字并不是从1开始,而是从final_train_tag_dict.txt这个文件保存的字典中读取,label信息也是用这个文件中读取。
from torch.utils import data
import numpy as np
from PIL import Image
class face_dataset(data.Dataset):
def __init__(self):
self.file_path = './data/faces/'
f=open("final_train_tag_dict.txt","r") #读取图片名字典
self.label_dict=eval(f.read()) #将读取到的字符串转化为相应的字典值
f.close()
def __getitem__(self,index):
label = list(self.label_dict.values())[index-1] #获取标签
img_id = list(self.label_dict.keys())[index-1] #id
img_path = self.file_path+str(img_id)+".jpg" #图片路径
img = np.array(Image.open(img_path)) #获取图片
return img,label #返回图片和标签
def __len__(self):
return len(self.label_dict)
DataLoader负责以特定的方式从数据集中迭代的产生 一个个batch的样本集合,不需要我们过多的编写内部实现,只要会用即可(正常情况下只需要关注加粗的参数即可)。
DataLoader(dataset, batch_size=1, shuffle=False, sampler=None,
batch_sampler=None, num_workers=0, collate_fn=None,
pin_memory=False, drop_last=False, timeout=0,
worker_init_fn=None)
参数介绍:
collate_fn:如何取样本的,我们可以定义自己的函数来准确地实现想要的功能
MINIST数据集的dataset是由一张图片和一个label组成的元组
collate_fn为lamda x:x时表示对传入进来的数据不做处理,当我们需要进行处理时,就需要自定义一个函数
自定义一个collate_fn函数:
def collate(data): #对如何取样本进行自定义
img = []
label = []
for each in data:
img.append(each[0])
label.append(each[1])
return img,label
dataloader = torch.utils.data.DataLoader(dataset=mnist, batch_size=2, shuffle=True,collate_fn=lambda x:collate(x))
for each in dataloader:
pass
1.把所有的数据加载进来,在使用getitem时将第i个样本传出去(适合样本总量较小的数据集)
2.定义一个列表,将文件名放入列表中,在使用getitem时,读取第i个文件中的内容(如几十个G的图像集)
import numpy as np
import torch
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
class DiabetesDataset(Dataset): #由Dataset(抽象类)继承
def __init__(self, filepath):
xy = np.loadtxt(filepath, delimiter=',', dtype=np.float32)
self.len = xy.shape[0]
self.x_data = torch.from_numpy(xy[:, :-1])
self.y_data = torch.from_numpy(xy[:, [-1]])
def __getitem__(self, index): #通过索引得到数据
return self.x_data[index], self.y_data[index]
def __len__(self):
return self.len
dataset = DiabetesDataset('diabetes.csv') #实例化为一个对象
#dataset每次可以拿到一个数据样本
#加载器 DataLoader根据batch_size的数量将多个dataset的x和y组合成矩阵,并自动生成Tensor
train_loader = DataLoader(dataset=dataset,
batch_size=32,
shuffle=True,
num_workers=2 #多线程
)
相应的训练过程为:
for epoch in range(100):
for i, data in enumerate(train_loader, 0):
#得到数据
inputs, labels = data
#前馈
y_pred = model(inputs)
loss = criterion(y_pred, labels)
print(epoch, i, loss.item())
#反向传播
optimizer.zero_grad()
loss.backward()
#更新
optimizer.step()