基于pytorch的DeepLearning学习笔记
最近开始学深度学习框架pytorch,从最简单的卷积神经网络开始了解pytorch的框架。以下涉及到的代码完整版请查看https://github.com/XieHanS/CPSC_ECGHbClassify_demo.git
基于pytorch的DL主要分为三个模块,数据块,模型块,和训练块。具体如下:
1、 数据集
pytorch提供有专门的数据下载,数据处理包,使用这些包可以极大地提高开发效率
torch.utils.data工具包
该包中有两个常用的类,分别为Dataset和DataLoader
Dataset 一个抽象类,抽象类只能作为基类派生新类使用,不能创建抽象类对象。其他数据集需要继承这个类,并覆写其中的两个方法:
__getitem__ 和 __len__
from torch.utils.data import Dataset, DataLoaderclass MyDataset(Dataset):def __init__(self, data, label):self.data = dataself.label = labeldef __getitem__(self, index):return (torch.tensor(self.data[index], dtype=torch.float), torch.tensor(self.label[index], dtype=torch.long))def __len__(self):return len(self.data)
调用__getitem__只返回一个样本,因此需要一个批量读取的工具,pytorch为我们提供了另外一个类DataLoader。DataLoader 定义一个新的迭代器,实现批量读取,打乱数据并提供并行加速等功能
loader = torch.utils.data.DataLoader(dataset = datasets, #加载的数据集batch_size = BATCH_SIZE, #批大小shuffle = True, #是否将数据打乱,默认为falsenum_workers=2,#使用多进程加载的进程数,0代表不使用多进程
使用的时候只需要调用这两个类即可
#继承Dataset类,自定义数据集以及对应的标签dataset = MyDataset(X_train, Y_train)dataset_test = MyDataset(X_test, Y_test)#装载数据,实现批量读取dataloader = DataLoader(dataset, batch_size=batch_size)dataloader_test = DataLoader(dataset_test, batch_size=batch_size, drop_last=False)
#训练模型时候的数据循环for epoch in range(n_epoch):model.train()for batch_idx, batch in enumerate(dataloader):input_x, input_y = tuple(batch)pred = model(input_x)[0]
2、 定义模型
pytorch中自定义的模型往往继承自nn.Model,包括两个函数,初始化函数__init__()和forward()。__init__()定义了卷积层和其他层的参数,forward()规定了网络执行的顺序。例如下面的网络:
__init__()定义了两个卷积层conv1和conv2,和一个全连接层out层,两个卷积层里面分别包含了一维卷积,DropOut,ReLU激活和最大池化层。
forward()定义了执行顺序。首先conv1,接着conv2,最后out层。由于上下层连接的问题,往往init里面会按照顺序撰写,而真正的执行顺序是forward里面的顺序。
class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() self.conv1 = nn.Sequential( # input shape (1, 1, 2000) nn.Conv1d( in_channels=1, # input height out_channels=16, # n_filters kernel_size=5, # filter size stride=1, # filter movement/step padding=2, ), # output shape (16, 1, 2000) nn.Dropout(0.2),#扔到0.2 nn.ReLU(), nn.MaxPool1d(kernel_size=5), # choose max value in 1x5 area, output shape (16, 1, 400)2000/5 ) self.conv2 = nn.Sequential( # input shape (16, 1, 400) nn.Conv1d(16, 32, 5, 1, 2),# output shape (32, 1, 400) nn.Dropout(0.2),#扔掉0.2 nn.ReLU(), nn.MaxPool1d(kernel_size=5),# output shape (32, 1, 400/5=80) ) self.out = nn.Linear(32 * 80, 3) # fully connected layer, output 3 classes def forward(self, x): x = self.conv1(x) x = self.conv2(x) x = x.view(x.size(0), -1) output = self.out(x) return output, x
我们打印出模型如下:
3、训练模型
1) 读数据,装载数据,随机批量分配
2) 初始化自定义的模型类
3) 定义优化器【SGD,自适应优化算法(RMSProp,Adam,Adadelta)】和损失函数【MSE(回归),crossEntropy(分类)】
4) 定义epoch数量,for循环训练模型
# 初始化自定义的模型类 model = CNN() model.verbose = False#运行的时候不显示详细信息 # 定义优化器和损失函数 LR = 0.001 optimizer = torch.optim.Adam(model.parameters(), lr=LR) loss_func = torch.nn.CrossEntropyLoss()
for epoch in range(n_epoch): model.train() for batch_idx, batch in enumerate(dataloader): input_x, input_y = tuple(batch) pred = model(input_x)[0] loss = loss_func(pred, input_y) optimizer.zero_grad()#梯度置零 loss.backward() #optimizer.step()是大多数optimizer所支持的简化版本。一旦梯度被如backward()之类的函数计算好后,就可以调用这个函数更新所有的参数。 optimizer.step() step += 1 # test model.eval()#为了固定BN和dropout层,使得偏置参数不随着发生变化
训练需要注意的几点:
1) 反向传播之前,优化器的梯度需要置零
2) optimizer.step()是大多数optimizer所支持的简化版本。一旦梯度被如backward()之类的函数计算好后,就可以调用这个函数更新所有的参数
3) model.eval()#训练完train_datasets之后,model要用来测试样本,model.eval()为了固定BN和dropout层,使得偏置参数不随着发生变化
完整的代码https://github.com/XieHanS/CPSC_ECGHbClassify_demo.git