一、通过维度变化
梯度下降:采用全部样本
随机梯度下降:
二、Mini-Batch
1)DataSet 是抽象类,不能实例化对象,主要是用于构造我们的数据集
2)DataLoader 需要获取DataSet提供的索引[i]和len;用来帮助我们加载数
3)对应参数:
epoch:对全部训练样本实现一次前馈和反馈
Batch-Size:一次前馈和反馈包含的训练样本数量
Iterations: Batch分成了多少份,内部循环的次数
三、DataLoader : Batch-Size = 2 ,shuffle = True(随机打乱)
3.1 步骤
1)需要提供样本数量和样本长度
2)随机打乱顺序
3)样本分组形成迭代Loader
四、数据集划分
x_train,x_test,y_train,y_test=sklearn.model_selection.train_test_split(x_data,y_target,test_size=0.4, random_state=0, stratify=y_train)
1)x_data :所要划分的样本特征数据集()数据集
2)y_data :所要划分的样本标签
3)test_size :测试集样本占比
4)random_state:随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。控制随机状态,固定random_state后,每次构建的模型是相同的、生成的数据集是相同的、每次的拆分结果也是相同的。
5)stratify是为了保持split前类的分布:
比如有100个数据,80个属于A类,20个属于B类。如果train_test_split(… test_size=0.25, stratify = y_all), 那么split之后数据如下:
training: 75个数据,其中60个属于A类,15个属于B类。
testing: 25个数据,其中20个属于A类,5个属于B类。
用了stratify参数,training集和testing集的类的比例是 A:B= 4:1,等同于split前的比例(80:20)。通常在这种类分布不平衡的情况下会用到stratify。
将stratify=X就是按照X中的比例分配
将stratify=y就是按照y中的比例分配
五、代码实现
代码说明:
1)需要mini_batch 就需要import DataSet和DataLoader
2)继承DataSet的类需要重写init,getitem,len魔法函数。分别是为了加载数据集,获取数据索引,获取数据总量。
3)DataLoader对数据集先打乱(shuffle),然后划分成mini_batch。
4)len函数的返回值 除以 batch_size 的结果就是每一轮epoch中需要迭代的次数。
5)inputs, labels = data中的inputs的shape是[32,8],labels 的shape是[32,1]。也就是说mini_batch在这个地方体现的
#dataset and dataloader
import numpy as np
import torch
from torch.utils.data import Dataset #数据工具,为抽象类不可实例化只可用子类继承
from torch.utils.data import DataLoader #可用来加载数据,可实例化
import matplotlib.pyplot as plt
import os
os.environ['KMP_DUPLICATE_LIB_OK']='True'
#___________________________________Prepare dataset___________________________________#
'''
Dataset是一个抽象函数,不能直接实例化,所以我们要创建一个自己类,继承Dataset
继承Dataset后我们必须实现三个函数:
__init__()是初始化函数,之后我们可以提供数据集路径进行数据的加载
__getitem__()帮助我们通过索引找到某个样本
__len__()帮助我们返回数据集大小
'''
class DiabetesDataset(Dataset): #继承Dataset
def __init__(self,filepath): #输入文件地址
xy = np.loadtxt(filepath,delimiter = ',',dtype = np.float32) #下载文件,分割,读取32浮点数
self.len = xy.shape[0] #取xyshape[0] 数据集为N*9 取第0元素得到数据集的个数N
#shape本身是一个二元组(x,y)对应数据集的行数和列数,这里[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
loss_list = []
dataset = DiabetesDataset('D:\\anaconda3\\Lib\\site-packages\\sklearn\\datasets\\data\\diabetes.csv.gz')
train_loader = DataLoader(dataset = dataset, #传递数据集
batch_size =32,
shuffle = True,
num_workers = 0) #读取mini-batch进行的线程提高读取效率
#___________________________________Design model using class___________________________________#
class Model(torch.nn.Module):
def __init__(self):
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) #输入维度为8 输出维度为1
# self.linear4 = torch.nn.Linear(2,1)
self.sigmoid = torch.nn.Sigmoid() #添加激活函数模块作为计算模块,添加非线性变换
#添加激活函数模块作为网络的一层,计算模块,添加非线性变换,无参数无需训练
#可采用多种激活函数,最常用ReLU,但是采用ReLU的过程中需要考虑,当x<0,ln(ReLU(x))错误
#可以改为:
self.activate = torch.nn.ReLU()
#def forward (self,x):
#x = self.activate(self.linear1(x))
#x = self.activate(self.linear2(x))
#x = self.activate(self.linear3(x))
#x = self.activate(self.linear4(x))
def forward (self,x):
x = self.activate(self.linear1(x)) #调用非线性函数做变换
x = self.activate(self.linear2(x))
x = self.sigmoid(self.linear3(x))
return x
model = Model()
#___________________________________construct loss and optimizer___________________________________#
criterion = torch.nn.BCELoss(reduction='sum')
optimizer = torch.optim.Adam(model.parameters(),lr = 0.05)
#___________________________________Training cycle___________________________________#
#if __name__ == '__main__':
for epoch in range(100):
for i, (inputs,labels) in enumerate (train_loader ,0): #遍历索引并得到索引值
y_pred = model(inputs)
loss = criterion(y_pred, labels)
print(epoch , i,loss.item())
#backward
optimizer.zero_grad()
loss.backward()
optimizer.step()
loss_list.append(loss.item())
plt.plot(range(100*(dataset.__len__()//32+1)), loss_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()
六、拓展
with torch.no_gard()和requires_gard
requires_gard:tensor有该参数,可设置为True,在进行反向传播的过程中,该tensor会自动求导。设置为False节省时间
with torch.no_gard():在该模块下计算的tensor.requires_gard =False
将数据集分为训练集和测试集,采用Mini-Batch,并对测试集的准确率进行评估
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
import matplotlib.pyplot as plt
import os
os.environ['KMP_DUPLICATE_LIB_OK']='True'
xy_data = np.loadtxt('D:\\anaconda3\\Lib\\site-packages\\sklearn\\datasets\\data\\diabetes.csv.gz',delimiter = ',',dtype = np.float32)
x = xy_data[:, :-1]
y = xy_data[:,[-1]]
x_train ,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.3)
x_test = torch.from_numpy(x_test)
y_test = torch.from_numpy(y_test)
#nimi_batch
class DiabetesDataset(Dataset):
def __init__(self, data,label):
self.x_data = torch.from_numpy(data)
self.y_data = torch.from_numpy(label)
self.len = data.shape[0]
def __getitem__(self,index):
return self.x_data[index] ,self.y_data[index]
def __len__(self):
return self.len
#实例化对象
train_dataset = DiabetesDataset(x_train,y_train)
train_loader = DataLoader(dataset=train_dataset, batch_size=32, shuffle=True, num_workers=0)
#数据batch
class Model(torch.nn.Module):
def __init__(self):
super(Model,self).__init__()
self.linear1 = torch.nn.Linear(8,6)
self.linear2 = torch.nn.Linear(6,4)
self.linear3 = torch.nn.Linear(4,2)
self.linear4 = torch.nn.Linear(2,1)
self.activate = torch.nn.ReLU()
self.sigmoid = 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))
x = self.sigmoid(self.linear4(x))
return x
model =Model()
#优化器和损失函数
criterion = torch.nn.BCELoss(reduction = 'sum')
optimizer = torch.optim.SGD(model.parameters(),lr =0.01)
loss_list = []
acc_list = []
count =0
for epoch in range(5000):
for i,data in enumerate(train_loader,0):
inputs ,labels =data
y_preds =model(inputs)
loss = criterion(y_preds, labels)
print('Epoch = ',epoch,'i = ',i)
print('\t',loss.item())
#backward
optimizer.zero_grad()
loss.backward()
optimizer.step()
loss_list.append(loss.item())
if epoch%200 == 0:
with torch.no_grad():
count +=1
y_pred = model(x_test)
y_pred_label = torch.where(y_pred>=0.5,torch.tensor([1.0]),torch.tensor([0.0]))
acc = torch.eq(y_pred_label, y_test).sum().item() / Ytest.size(0)
acc_list.append(acc)
print("\t test acc : ", acc)
plt.plot(range(5000*(train_dataset.__len__()//32+1)), loss_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()
plt.plot(range(count), acc_list)
plt.ylabel('Acc')
plt.xlabel('epoch')
plt.show()