1、Dataset
1.1 定义好这个项目的x和y是什么
官方文档:
class Dataset(object):
"""An abstract class representing a Dataset.
All other datasets should subclass it. All subclasses should override
``__len__``, that provides the size of the dataset, and ``__getitem__``,
supporting integer indexing in range from 0 to len(self) exclusive.
"""
def __getitem__(self, index):
raise NotImplementedError
def __len__(self):
raise NotImplementedError
def __add__(self, other):
return ConcatDataset([self, other])
__getitem__就是获取样本对,模型直接通过这一函数获得一对样本对{x:y}。
__len__是指数据集长度。
(46条消息) Pytorch中的dataset类——创建适应任意模型的数据集接口_木盏的博客-CSDN博客
(46条消息) PyTorch 入门实战(三)——Dataset和DataLoader_一株草的世界的博客-CSDN博客
import torch
import torch.utils.data.dataset as Dataset
import numpy as np
#创建子类
class subDataset(Dataset.Dataset):#因为Dataset是module模块,不是class类,所以需要调用module里的class才行,因此是Dataset.Dataset!
#初始化,定义数据内容和标签
def __init__(self, Data, Label):
self.Data = Data
self.Label = Label
#返回数据集大小
def __len__(self):
return len(self.Data)
#得到数据内容和标签,作用是接收一个索引, 返回一个样本
def __getitem__(self, index):
data = torch.Tensor(self.Data[index])
label = torch.Tensor(self.Label[index])
return data, label
抽象类不能实例化,因此我们需要构造这个抽象类的子类来创建数据集
补充:python中的类与模块
类:一种抽象的概念,将数据和操作进行封装,以便将来的复用;
模块:一个python文件就可以认为是一个模块,模块名就是去掉.py后缀
1.2 if __name__ == '__main__':的作用
__name__:当该模块被直接执行的时候,__name__ 等于文件名(包含后缀 .py );如果该模块 import 到其他模块中,则该模块的 __name__ 等于模块名称(不包含后缀.py)。
“__main__” 始终指当前执行模块的名称(包含后缀.py)。进而当模块被直接执行时,__name__ == 'main' 结果为真,继续执行后面的代码。
(46条消息) Python中if __name__ == ‘__main__‘:的作用和原理_if name =main python_农村詹姆斯的博客-CSDN博客
2、Dataloader
数据集(dataset) + 采样器(sampler),并在数据集上提供单线程或多线程(num_workers )的可迭代对象
参数意义:
1. epoch:所有的训练样本输入到模型中称为一个epoch;
2. iteration:一批样本输入到模型中,成为一个Iteration;
3. batchszie:批大小,决定一个epoch有多少个Iteration;
4. 迭代次数(iteration)=样本总数(epoch)/批尺寸(batchszie)
5. dataset (Dataset) – 决定数据从哪读取或者从何读取;
6. batch_size (python:int, optional) – 批尺寸(每次训练样本个数,默认为1)
7. shuffle (bool, optional) –每一个 epoch是否为乱序 (default: False);
8. num_workers (python:int, optional) – 是否多进程读取数据(默认为0);
9. drop_last (bool, optional) – 当样本数不能被batchsize整除时,最后一批数据是否舍弃(default: False)
10. pin_memory(bool, optional) - 如果为True会将数据放置到GPU上去(默认为false)
- Epoch: 所有训练样本都已输入到模型中,称为一个Epoch
- Iteration: 一批样本输入到模型中,称为一个Iteration
- Batchsize: 一批样本的大小, 决定一个Epoch有多少个Iteration
循环嵌套
for epoch in range(100):#100次训练
for i in range(total_batch):#每一次iteration,就是从DataLoader中获取一个batch_size大小的数据的。
(46条消息) PyTorch学习笔记(4)--DataLoader的使用_我这一次的博客-CSDN博客
- 读哪些数据? 我们每一次迭代要去读取一个batch_size大小的样本,那么读哪些样本呢?
- 从哪读数据? 也就是在硬盘当中该怎么去找数据,在哪设置这个参数。
- 怎么读数据?
3、代码
import torch
import numpy as np
from sklearn.model_selection import train_test_split#分割数据集
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
# prepare dataset
class DiabetesDataset(Dataset):#定义子类,为后续实例化做准备
def __init__(self, filepath):#从哪读
xy = np.loadtxt(filepath, delimiter=',', dtype=np.float32)
self.len = xy.shape[0] # shape(多少行,多少列);shape[0]可以得到有多少个样本
self.x_data = torch.from_numpy(xy[:, :-1])#除了最后一列
self.y_data = torch.from_numpy(xy[:, [-1]])#只要最后一列
def __getitem__(self, index):#给一个索引,返回一个样本(x,y)
return self.x_data[index], self.y_data[index]
def __len__(self):
return self.len
# 读取数据集,读什么
dataset = DiabetesDataset('diabetes.csv')#子类实例化,传入的参数
# 构建读取器,如何读
train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True, num_workers=0) # train_loader迭代器,num_workers 多线程 怎么读
# print(len(dataset))#759
# design model using class
class Model(torch.nn.Module):#继承torch.nn.Module
def __init__(self):#这个方法会在创建类的实例的时候自动执行
super(Model, self).__init__()#子类把父类的__init__()放到自己的__init__()当中,这样子类就有了父类的__init__()的那些东西
self.linear1 = torch.nn.Linear(8, 6)
self.linear2 = torch.nn.Linear(6, 4)
self.linear3 = torch.nn.Linear(4, 1)
self.sigmoid = torch.nn.Sigmoid()
def forward(self, x):
x = self.sigmoid(self.linear1(x))
x = self.sigmoid(self.linear2(x))
x = self.sigmoid(self.linear3(x))
return x
epoch_list = []
loss_avg_list = []
loss_list = []
model = Model()
# construct loss and optimizer
criterion_each = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
# training cycle forward, backward, update
if __name__ == '__main__':
for epoch in range(100):
for i, data in enumerate(train_loader, 0): # train_loader 是迭代器,从0开始,先shuffle后mini_batch i=759/32=23 enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标
inputs, labels = data
y_pred = model(inputs)
loss_each = torch.mean(criterion_each(y_pred, labels))
#print(epoch, i, data, loss_each.item())
optimizer.zero_grad()
loss_each.backward()
optimizer.step()
loss = torch.mean(loss_each) # 每个样本的损失
loss_list.append(loss.item()) # 整个batch的平均损失
epoch_list.append(epoch)
# print(len(loss_list))
# print(len(epoch_list))
plt.figure(1)
plt.plot(epoch_list, loss_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()
3.1 lr=0.01, batch=32
排查问题:
lossfunction 一直震荡,先降低学习率
lr=0.001