引入:
前面学过的batch(全部样本,计算速度快,性能上可能有问题)和随机梯度下降(解决按点问题,随机性好,但没法利用gpu/cpu,训练时间长),由此mini-batch
如下图,在外层循环中,每一层是一个epoch(训练周期,即这一批要训练几次);在内层循环中,每一次是一个mini-batch(batch的迭代)
#training cycle
for epoch in range (trsining-batch):
#mini-batch
for i in range(total-batch)
相关概念:
Epotch:即所有样本都参与了训练,有前馈和反向传播。
batch-size:每次训练所用的样本数量/批量大小。。
iteration:内层执行了几次,就是分为几个mini-batch
eg.10000个Epotch,mini-batch为1000,每次拿1000个样本来训练,即batch-size为1000,则iteration=10。
DataLoader
这里batch-size为2,shuffle=True,[这里shuffle是把它打乱顺序,增加随机性]
功能:1.支持索引; 2.知道dataset的长度。从而对自动生成小批量数据集。
shuffle打乱顺序 ——> batch_size=2,两个为一组 ——>从而形成可迭代Loader
定义数据集:
1.如果数据本身不大且结构化,可以直接All Data [i]
2.如果 数据很大(eg图像、语音等非结构化),通过文件。
具体代码:
import torch
import numpy as np
from torch.utils.data import Dataset #抽象类,只能由子类来继承
from torch.utils.data import DataLoader #可实例化
filepath = 'C:\\Users\\jiwenting\\Desktop\\diabetes.csv'
class DiabetsDataset(Dataset): #自定义类
#魔法
def __init__(self,filepath):
xy = np.loadtxt(filepath,delimiter=',',dtype=np.float32)
self.len = xy.shape[0] #用shape[0]输出列的长度,即N
self.x_data = torch.from_numpy(xy[:,:-1]) #x_data为前八列
self.y_data = torch.from_numpy(xy[:,[-1]]) #y_data为最后一列
def __getitem__(self, index) : #通过索引调出数据
return self.x_data[index],self.y_data[index]
def __len__(self):
return self.len
dataset = DiabetsDataset(filepath) #通过自定义类实例化
#传入定义的数据集,然后输入 batch-size 和 shuffle 来进行loader; 而num-wokers表示几个并行的进程来读取数据
train_loader = DataLoader(dataset=dataset,batch_size=32,shuffle=True,num_workers=0)
#model
class Model(torch.nn.Module):
def __init__(self) -> None:
super(Model,self).__init__()
self.linear1 = torch.nn.Linear(8,6)#构造对象,八维到六维
self.linear2 = torch.nn.Linear(6,4)
self.linear3 = torch.nn.Linear(4,1)
self.activate = torch.nn.Sigmoid()
def forward(self,x):
x = self.activate(self.linear1(x))
x = self.activate(self.linear2(x))
x = self.activate(self.linear3(x))
return x
model = Model()
#loss & optimizer
criterion = torch.nn.BCELoss(reduction='mean')
optimzer = torch.optim.SGD(model.parameters(),lr=0.01)
#training circle
if __name__ == '__main__':
for epoch in range(100):
'''
用enumerate获得当前为第几次迭代,0为起始位置 :直接对train_loader做迭代
从train_loader拿出Dataset自己实现的__getitem__的返回值即(x,y)元组放入data中
在这里loader自动的把xy构成的矩阵转化为Tensor类型的计算图,所以直接传进去就好了
'''
for i,(input,labels) in enumerate(train_loader,0):
#forward
y_pred = model(input)
loss = criterion(y_pred,labels)
print(epoch,i,loss.item())
optimzer.zero_grad()
loss.backward()
optimzer.step()
遇到的问题:
1.Dataset 是一个抽象类,无法实例化。
定义抽象类时用到了魔法方法
在Python中,所有以双下划线
__
包起来的方法,统称为Magic Method(魔术方法),它是一种的特殊方法,普通方法需要调用,而魔术方法不需要调用就可以自动执行。
2.关于enumerate
4.关于shape 推荐博客https://blog.csdn.net/likeyou1314918273/article/details/89510234
直接用.shape可以快速读取矩阵的形状,使用shape[0]读取矩阵第一维度的长度
5.关于划分训练集和测试集:
推荐博客:https://zhuanlan.zhihu.com/p/248634166
import torch
import numpy as np
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
from sklearn.model_selection import train_test_split
# 读取原始数据,并划分训练集和测试集
raw_data = np.loadtxt('diabetes.csv', delimiter=',', dtype=np.float32)
X = raw_data[:, :-1]
y = raw_data[:, [-1]]
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3)
Xtest = torch.from_numpy(Xtest)
Ytest = torch.from_numpy(Ytest)
6.关于多线程num_workers=2
train_loader = DataLoader(dataset=dataset,batch_size=32,shuffle=True,num_workers=0)
表示mini-batch的数据读取是否并行。
但注意如下图,在windows中直接调用loader迭代会报错。所以在调用loader迭代时必须要把它封装(比如封装到if语句或者函数)
·