pytorch学习笔记-2022

学习笔记

文章目录

  • 学习笔记
      • 1. pytorch
        • 二、pytorch学习
          • 0. 先验概率后验概率:
          • 1. 函数
          • 2. python 对比 jupter
          • 3. pytorch读取数据
          • 4. tensorboard
          • 6. transform常用函数
          • 7. dataloader
          • 8. 神经网络
          • 9. 网络模型的训练-加载
          • 10. 使用GPU训练
          • 11. .eval()和torch.no_grad()区别

1. pytorch

一、安装路径:D:\SoftwareTool\anaconda3

二、pytorch学习

0. 先验概率后验概率:
  • 先验概率是 以全事件为背景下,A事件发生的概率,P(A|Ω)

  • 后验概率是 以新事件B为背景下,A事件发生的概率, P(A|B)

全事件一般是统计获得的,所以称为先验概率,没有实验前的概率

新事件一般是实验,如试验B,此时的事件背景从全事件变成了B,该事件B可能对A的概率有影响,那么需要对A现在的概率进行一个修正,从P(A|Ω)变成 P(A|B),

所以称 P(A|B)为后验概率,也就是试验(事件B发生)后的概率

1. 函数
  • dir()打开看见
  • help()说明书
2. python 对比 jupter

pytorch学习笔记-2022_第1张图片

3. pytorch读取数据
  1. Dataset (idx的数据集)
  2. Dataloader(数据加载入神经网络)
from torch.utils.data import Dataset
from PIL import Image
import os


class MyData(Dataset):
 def __init__(self, root_dir, label_dir):
     self.root_dir = root_dir
     self.label_dir = label_dir
     self.path = os.path.join(self.root_dir, self.label_dir)
     self.img_path = os.listdir(self.path)

 def __getitem__(self, idx):
     img_name = self.img_path[idx]
     img_item_path = os.path.join(self.path, img_name)
     img = Image.open(img_item_path) # img = Image.open(ImgPath)打开的图片是PIL类型,默认RGB
     label = self.label_dir
     return img, label

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

root_dir = "dataset/train"
ants_label_dir = "ants"
bees_label_dir = "bees"
ants_dataset = MyData(root_dir, ants_label_dir)
bees_dataset = MyData(root_dir, bees_label_dir)
train_dataset = ants_dataset + bees_dataset
4. tensorboard
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter("log") # 存储事件文件到log

# terminal 运行代码
tensorboard --logdir=logs --port=xxx

  1. add_scalar
for i in range(100):
 writer.add_scalar("y=3x", 3*i, i) #scalar 标量  标题,y轴,x轴 画数据曲线图
  2.  add_image
import numpy as np
from PIL import Image
writer = SummaryWriter("log") # 存储事件文件到log
image_path = "data/train/bees_image/16838648_415acd9e3f.jpg"
img_PIL = Image.open(image_path)
img_array = np.array(img_PIL)

writer.add_image("test", img_array, 2,dataformats='HWC')
  1. transform(torchvision)

    图片的变换

pytorch学习笔记-2022_第2张图片

6. transform常用函数
  • ToTensor()把灰度范围从(0,255)变换到(0,1),Normalize()把(0,1)变换到(-1,1)

pytorch学习笔记-2022_第3张图片

  • resize (PILImage对象size属性返回的是w, h,而resize的参数顺序是h, w)传入PIL传出PIL

  • compose组合函数

  • Normalize 归一化 image = (image - mean) / std

    # normalize 归一化 需要tensor类型图片
    print(img_tensor[0][0][0]) # 第0层0行0列
    trans_norm = transforms.Normalize([3, 0.5, 5],[2, 0.5, 1])
    img_norm = trans_norm(img_tensor)
    print(img_norm[0][0][0])
    writer.add_image("Normalize",img_norm,3)
    

    normalize的mean和std应该是基于训练集的统计得来的。

  • RandomCrop (H,W)(int*int) 处理PIL 随机裁剪

from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

writer = SummaryWriter("logs")
img = Image.open("data/train/ants_image/7759525_1363d24e88.jpg")
# print(img)

trans_totensor = transforms.ToTensor()
img_tensor = trans_totensor(img)
writer.add_image("ToTensor",img_tensor)

# normalize 归一化 需要tensor类型图片
print(img_tensor[0][0][0]) # 第0层0行0列
trans_norm = transforms.Normalize([3, 0.5, 5],[2, 0.5, 1])
img_norm = trans_norm(img_tensor)
print(img_norm[0][0][0])
writer.add_image("Normalize",img_norm,3)

# Resize 可以处理PIL类型
print(img.size)
trans_resize = transforms.Resize((512,512))
img_resize = trans_resize(img)
img_resize = trans_totensor(img_resize) # PIL->转换为tensor类型
writer.add_image("Resize",img_resize)

# Compose 组合函数 先转换大小 再转换类型
trans_resize_2 = transforms.Resize(512)
trans_compose = transforms.Compose([trans_resize_2, trans_totensor])
img_resize_2 = trans_compose(img)
writer.add_image("Resize",img_resize_2,1)

#randomCrop   随即裁剪
trans_random = transforms.RandomCrop((300,400))
trans_compose_2 = transforms.Compose([trans_random,trans_totensor])
for i in range(10):
 img_crop = trans_compose_2(img)
 writer.add_image("RandomCropHW",img_crop,i)

writer.close()
7. dataloader

Pytorch的Dataloader中一个很方便的功能是允许使用多进程来加速数据读取,我们可以通过num_workers来设置使用几个进程读取数据。

我们可以将一个torch.utils.data.Dataset的子类传入DataLoader来创建一个读取小批量数据样本的DataLoader实例。

  • 分成多组进行试验。

    test_data = torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor())
    
    # dataloader
    # batch_size 打包
    # num_worker个worker 工作进程
    # drop_last True代表不舍弃数据 False代表舍弃(默认false)
    # collate_fn: 在Dataset的__getitem__把一条一条的数据发出来以后,Dataloader会根据你定义的batch_size参数把这些东西组织起来(其实是一个batch_list)。然后再送给collate_fn组织成batch最后的样子,lambda x: x就是指不对这个batch_list进行任何组织,直接输出。从这里就能看到,如果不设置collate_fn,我们得到的数据是很不好用的,且不说这数据是list的形式;就近了说,所有的数据格式是[(data1, label1), (data2, label2)m, (data3, label3), ......]。但是我们希望得形式是:(data1, data2, data3); (label1, label2, label3)。注意这里是一个示意,就是说我们希望从dataloader出来的东西,所有的数据部分组织到一起,所有的label又组织到一起。它们的大小是batch_size。
    test_loader = DataLoader(dataset=test_data,batch_size=64,shuffle=True,num_workers=0,drop_last=False)
    
8. 神经网络
  1. 卷积层

pytorch学习笔记-2022_第4张图片
pytorch学习笔记-2022_第5张图片

nn.Conv2d(图像二维)
class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)stride 步长;padding 边缘填充 kernel_size 卷积核大小

参数可以通过函数计算:
pytorch学习笔记-2022_第6张图片

  1. 池化层

    nn.maxpool2d()

    class torch.nn.MaxPool1d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)

    • 池化层夹在连续的卷积层中间, 用于压缩数据和参数的量,减小过拟合。
      简而言之,如果输入是图像的话,那么池化层的最主要作用就是压缩图像。

    • 下采样层也叫池化层,其具体操作与卷积层的操作基本相同,只不过下采样的卷积核为只取对应位置的最大值、平均值等(最大池化、平均池化),即矩阵之间的运算规律不一样,并且不经过反向传播的修改。

池化层的作用:
个人觉得主要是两个作用:
1. invariance(不变性),这种不变性包括translation(平移),rotation(旋转),scale(尺度)
2. 保留主要的特征同时减少参数(降维,效果类似PCA)和计算量,防止过拟合,提高模型泛化能力
pytorch学习笔记-2022_第7张图片

  1. 线性层

    torch.flatten(imgs) # 摊平成一维
    self.linear1 = Linear(196608, 10) # 降维 
    
  2. Sequential

    self.model1 = Sequential(
                Conv2d(3, 32, 5, padding=2),
                MaxPool2d(2),
                Conv2d(32, 32, 5, padding=2),
                MaxPool2d(2),
                Conv2d(32, 64, 5, padding=2),
                MaxPool2d(2),
                Flatten(),
                Linear(1024, 64),
                Linear(64, 10),
            )
    
  3. 损失函数

    Loss Function (loss = nn.CrossEntropyLoss() result=loss(output,targets))

    反向传播->梯度下降
    优化器

    • optim = torch.optim.SGD(test.parameters(), lr=0.01 ) # lr: 学习速率及梯度下降前的参数,小了下降太慢,大了容易梯度振荡
      

      优化器:

      • vgg16_true.classifier[6].add_module('add_linear',nn.Linear(1000,10)) # 直接插入覆盖	
        vgg16_true.add_module('add_linear',nn.Linear(1000,10)) # 在外层增加线性器
        
9. 网络模型的训练-加载
#保存-1-2
# 保存方式1
torch.save(vgg16,"vgg16_method1.pth")
# 保存方式2 官方推荐
torch.save(vgg16.state_dict(),"vgg16_method2.pth") # 只保存参数为字典形式,不保模型存


#加载-1-2
# 方式1-保存方式1,加载model
model=torch.load("vgg16_method1.pth")
print(model)
# 方式2,加载模型
vgg16 = torchvision.models.vgg16(pretrained=False)
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
print(vgg16) # 把储存的字节再正常输出

正确率估计:pytorch学习笔记-2022_第8张图片

10. 使用GPU训练

pytorch学习笔记-2022_第9张图片

项目完整代码:

import torch.optim
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
import time
from model import *

# 定义训练设备
device = torch.device("cuda")
train_data = torchvision.datasets.CIFAR10("../data",train=True,transform=torchvision.transforms.ToTensor(),
                                          download=True)
test_data = torchvision.datasets.CIFAR10("../data",train=False,transform=torchvision.transforms.ToTensor(),
                                          download=True)

train_data_size = len(train_data)
test_data_size = len(test_data)

print("训练长度 {} 测试长度{}".format(train_data_size,test_data_size))

train_dataloader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# 创建网络模型
class Test(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.model1 = nn.Sequential(
            nn.Conv2d(3, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10),
        )

    def forward(self,x):
        x = self.model1(x)
        return x

test = Test()
# gpu-
# test = test.cuda()
test = test.to(device)
# 损失函数
loss_fn = nn.CrossEntropyLoss() # 交叉熵损失函数
# loss_fn = loss_fn.cuda()
loss_fn = loss_fn.to(device)

# 优化器
learning_rate = 1e-2
optimizer = torch.optim.SGD(params=test.parameters(),lr = learning_rate)

# 设置训练网络参数
total_train_step = 0 # 训练步数
total_test_step = 0# 测试步数
epoch = 10 # 训练轮数

# 添加tensorboard
writer = SummaryWriter("logs_train")
# 设置时间
start_time=time.time()
for i in range(epoch):
    print("_____第{}轮开始".format(i+1))
    # 训练步骤开始
    test.train() #
    for data in train_dataloader:
        imgs, targets = data
        # imgs = imgs.cuda()
        # targets = targets.cuda()
        imgs = imgs.to(device)
        targets = targets.to(device)
        outputs = test(imgs)
        loss = loss_fn(outputs, targets)
        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_train_step += 1
        if total_train_step % 100 == 0:
            end_time=time.time()
            print(end_time-start_time)
            print("训练次数:{} loss:{}".format(total_train_step,loss.item()))
            writer.add_scalar("train_loss",loss.item(),total_train_step)
    # 测试步骤开始
    test.eval() # 测试阶段,避免BN Dropout产生的影响
    total_test_loss = 0
    total_accuracy = 0
    with torch.no_grad(): # 提升性能 包裹的记录再反向传播时不会被记录
        for data in test_dataloader:
            imgs, targets = data
            # imgs = imgs.cuda()
            # targets = targets.cuda()
            imgs = imgs.to(device)
            targets = targets.to(device)
            outputs = test(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss += loss.item()
            # 整体正确率
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy += accuracy
    print("整体测试集合上的loss:{}".format(total_test_loss))
    print("整体测试集合上的正确率:{}".format(total_accuracy/test_data_size))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step)
    total_test_step += 1

    # 保存每一轮训练的模型
    torch.save(test, "test_{}.pth".format(i+1))
    print("模型已保存")
writer.close()

11. .eval()和torch.no_grad()区别
  • 在PyTorch中进行validation时,会使用model.eval()切换到测试模式,在该模式下,

  • 主要用于通知dropout层和batchnorm层在train和val模式间切换

    • 在train模式下,dropout网络层会按照设定的参数p设置保留激活单元的概率(保留概率=p); batchnorm层会继续计算数据的mean和var等参数并更新。
    • 在val模式下,dropout层会让所有的激活单元都通过,而batchnorm层会停止计算和更新mean和var,直接使用在训练阶段已经学出的mean和var值。
  • 该模式不会影响各层的gradient计算行为,即gradient计算和存储与training模式一样,只是不进行反传(backprobagation)

  • with torch.no_grad()则主要是用于停止autograd模块的工作,以起到加速和节省显存的作用,具体行为就是停止gradient计算,从而节省了GPU算力和显存,但是并不会影响dropout和batchnorm层的行为。

池化层总结(Summary)

接收单元大小为:W1∗H1∗D1W1∗H1∗D1
需要两个参数(hyperparameters):
their spatial extent FF,
the stride SS,
输出大小:W2∗H2∗D2W2∗H2∗D2,其中:
W2=W1−FSW2=W1−FS
H2=H1−FS+1H2=H1−FS+1
D2=D1D2=D1
不需要引入新权重
————————————————

卷积层总结(Summary)

接收三维输入 W1∗H1∗D1W1∗H1∗D1
需要给出4个参数(hyperparameters):
Number of filters KK,
their spatial extent FF,
the stride SS,
the amount of zero padding PP.
输出一个三维单元 W2∗H2∗D2W2∗H2∗D2,其中:
W2=W1−F+2PS+1W2=W1−F+2PS+1
H2=H1−F+2PS+1H2=H1−F+2PS+1
D2=KD2=K
应用权值共享,每个filter会产生F∗F∗D1F∗F∗D1 个权重,总共 (F∗F∗D1)∗K(F∗F∗D1)∗K 个权重和 KK 个偏置。
在输出单元,第d个深度切片的结果是由第d个filter 和输入单元做卷积运算,然后再加上偏置而来。
————————————————

你可能感兴趣的:(学习记录,python,人工智能,pytorch,计算机视觉)