Pytorch速通笔记

总之这是第二次速通,只写了基本的一些东西,可能够用了
官网地址:https://pytorch.org/

Dateset类(包括构建Transform)

# 所有自己的 Dataset 需要继承自这个类
# 需要覆写3个method

from torch.utils.data import Dataset


class MyDataset(Dataset):
    
    # 初始化自己的数据集,传入自己预处理好的数据集,可以先处理数据路径更方便
    def __init__(self, data, transform, myloader):
        self.data = data
        self.transform = transform
        self.loader = loader

    def __len__(self):
        return len(self.data)

    # 获取每一个数据的具体值的方法
    def __getitem__(self, idx):
        # data的数据格式为 [imgpath,lable]对应
        imgpath, label = self.data[idx] 
        
        # 如果 label 比较复杂的时候,可以写一个 label_loder 的方法
        image = self.transform(self.myloader(imgpath))
        return image, label
    
# Dataset 类具有如下聚合方式
TrainDataset = MyDataset_1 + MyDataset_2

Transform的使用

from torchvision import transforms

# 自定义 transform
    transform = transforms.Compose([
         transforms.ToPILImage(),
    	transforms.Resize(256),
    	# transforms.RandomResizedCrop(224,scale=(0.5,1.0)),
    	transforms.RandomHorizontalFlip(),
    	transforms.ToTensor(),
    	transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])
裁剪
中心裁剪 transforms.CenterCrop
随机裁剪 transforms.RandomCrop
随机长宽比裁剪 transforms.RandomResizedCrop
上下左右中心裁剪 transforms.FiveCrop
上下左右中心裁剪后翻转 transforms.TenCrop
翻转和旋转——Flip and Rotation
依概率p水平翻转 transforms.RandomHorizontalFlip(p=0.5)
依概率p垂直翻转 transforms.RandomVerticalFlip(p=0.5)
随机旋转 transforms.RandomRotation
图像变换
重置大小 transforms.Resize
标准化 transforms.Normalize
转为tensor,并归一化至[0-1] transforms.ToTensor
填充 transforms.Pad
修改亮度、对比度和饱和度 transforms.ColorJitter
转灰度图 transforms.Grayscale
线性变换 transforms.LinearTransformation()
仿射变换 transforms.RandomAffine
依概率p转为灰度图 transforms.RandomGrayscale
将数据转换为PILImage ransforms.ToPILImage
Apply a user-defined lambda as a transform transforms.Lambda
对transforms操作,使数据增强更灵活
transforms.RandomChoice(transforms) 从给定的一系列transforms中选一个进行操作
transforms.RandomApply(transforms, p=0.5) 给一个transform加上概率,依概率进行操作
transforms.RandomOrder 将transforms中的操作随机打乱

TensorBoard的使用

from torch.utils.tensorboard import SummaryWeiter
# 写入tensorboard日志
# 很方便的数据图表

writer = SummaryWriter(logdir)
writer.add_image(tag , img_tensor_or_numpy , step, dataformats="HWC") #添加图片 
writer.add_scalar(tag , scalar_value , global_step) # 添加图表


writer.close()
# cmd 指令:tensorboard --logdir=logdir --port=6006

torchvision使用

在pytorch的官方文档中看,可以直接下载一些比较简单的数据集

DataLoader初始化数据集

from torch.utils.data import Dataset, DataLoader

Dtr = DataLoader(
    dataset=train_data, 
    batch_size=50,
    shuffle=True, 	# 是否打乱顺序
    num_workers=0,	# 读取进程数量,0为默认主进程
    drop_last=True	# 最后一个batch除不尽的时候是否丢弃
)

# DataLoader 本质是一个迭代器

nn.Module 神经网络搭建

官方文档 https://pytorch.org/docs/stable/nn.html#

基本所有的神经网络结构都在里面了,要什么自己找,torch的结构搭建非常简单

import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        
        # 自定义网络 - 卷积层
        # in_channels (int), out_channels (int), kernel_size (int or tuple) 
        # With square kernels and equal stride
        self.conv1 = nn.Conv2d(3, 20, 3, stride=2)
        # non-square kernels and unequal stride and with padding
        self.conv2= nn.Conv2d(20, 15, (3, 5), stride=(2, 1), padding=(4, 2))
        # non-square kernels and unequal stride and with padding and dilation
        self.cov3 = nn.Conv2d(15, 1, (5, 5), stride=(1, 1), padding=(2, 2), dilation=(3, 1))
        
        # 自定义网路 - 池化层
        # pool of square window of size=3, stride=2
        self.pool1 = nn.MaxPool2d(3, stride=2,)
        # pool of non-square window
        self.pool2 = nn.MaxPool2d((3, 2), stride=(2, 1))
	
    
    # 前馈路径示例
	def forward(self, x):
        x = F.relu(self.conv1(x))
        x = self.pool1(x)
        x = F.sigmod(self.conv2(x))
        x = self.pool2(X)
        x = F.relu(self.conv3(x))
        return x
        
# 小孩子不懂,网络瞎搭的,很抽象但看到的人先别急

nn.Sequential 更方便的小型网络生成器

# Using Sequential to create a small model. When `model` is run,
# input will first be passed to `Conv2d(1,20,5)`. The output of
# `Conv2d(1,20,5)` will be used as the input to the first
# `ReLU`; the output of the first `ReLU` will become the input
# for `Conv2d(20,64,5)`. Finally, the output of
# `Conv2d(20,64,5)` will be used as input to the second `ReLU`
model = nn.Sequential(
    nn.Conv2d(1,20,5),
    nn.ReLU(),
    nn.Conv2d(20,64,5),
    nn.ReLU()
)

# Using Sequential with OrderedDict. This is functionally the
# same as the above code
model = nn.Sequential(
    OrderedDict([
    ('conv1', nn.Conv2d(1,20,5)),
    ('relu1', nn.ReLU()),
    ('conv2', nn.Conv2d(20,64,5)),
    ('relu2', nn.ReLU())
]))

torch.optim 优化器构造

官方文档https://pytorch.org/docs/stable/optim.html

# 构造优化器
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr=0.0001)

# 使用优化器(简单示例)
for input, target in dataset:
    optimizer.zero_grad()
    output = model(input)
    loss = loss_fn(output, target)
    loss.backward()
    optimizer.step()
    
# 一些优化算法,如共轭梯度和LBFGS,需要多次重新评估函数,因此您必须传递一个closure,允许它们重新计算您的模型。closure 应该清除梯度,计算损失并返回。

for input, target in dataset:
    def closure():
        optimizer.zero_grad()
        output = model(input)
        loss = loss_fn(output, target)
        loss.backward()
        return loss
    optimizer.step(closure)

网路运行示例

for epoch in range(epoch_num): # epoch 表示训练代数
    train_loss = []
    for batch_idx, minibatch in enumerate(Dtr, 0): 
        # Dtr = Dataloader(XXXX)
        # enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标
        # 表示模型迭代,次数太少模型没效果,次数太对容易没有免费的午餐定理

        data, target = Mygetdata(minibatch)

        optimizer.zero_grad()	# 每个 batch 计算前梯度清空,因为前面的 batch 的 grid 对本次无用
        output = my_module(data)	# 前馈传播
        loss = my_loss(output, target)	# 计算损失函数
        loss.backward()		# 反向传播
        optimizer.step()	# 更新参数
        train_loss.append(loss.cpu().item())


        torch.save(model.state_dict(), 'model_weights.pth')
    
# 可以用 tqdm 插件显示进度条,但是在进度需要写入log文件时就算了
# 过程中的数据可以利用 tensorboard 进行可视化