PyTorch入门

1.读取数据类Dataset

Dataset将数据和label进行组织编号0 1 2 3......,使得可以根据编号读取数据;需获取每一个数据及其label以及数据总数 ,要实现 len() 方法和 getitem() 方法。

len() 方法返回数据集的样本数量;getitem() 方法根据给定的索引返回对应的数据样本;

通过继承Dataset类class MyData(Dataset),实现__len__和__getitem__方法,可以自定义自己的数据集类以适应不同的数据源和格式

python 复制代码
class MyData(Dataset):
    #root:根目录  label:标签(ants/bees)
    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)
        #os.listdir()获取指定目录下的所有条目
        self.img_path=os.listdir(self.path)

    def __getitem__(self,idx):
        img_name=self.img_path[idx]
        img_item_name=os.path.join(self.root_dir,self.label_dir,img_name)
        img=Image.open(img_item_name)
        label=self.label_dir
        return img,label

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

2.TensorBoard使用

(1)add_scalar方法:通常用于记录训练过程中的各种指标,如损失值、准确率等。它将这些数值与对应的步数关联起来,以便后续进行可视化分析

python 复制代码
 def add_scalar(
        self,
        tag,
        scalar_value,
        global_step=None,
        walltime=None,
        new_style=False,
        double_precision=False,
    ):
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">tag</font>: 字符串类型,用于标识数据的标签或名称,通常用于在可视化时区分不同的数据曲线
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">scalar_value</font>: 要记录的标量值,通常是数字
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">global_step</font>: 可选参数,表示训练的步数或迭代次数,用于x轴的刻度

(2)利用TensorBoard绘制y=x图像

python 复制代码
from torch.utils.tensorboard import SummaryWriter

#保存的目录路径
writer=SummaryWriter("logs")

#y=x
for i in range(100):
    writer.add_scalar("y=x",i,i)

writer.close()

(3)启动命令

在终端中输入如下命令

python 复制代码
tensorboard --logdir=logs  #logs是上面指定在writer = SummaryWriter("logs")中指定的文件夹名,日志文件存储在此文件中

(4)add_image方法:将图像数据添加到TensorBoard日志中

python 复制代码
def add_image(
        self, tag, img_tensor, global_step=None, walltime=None, dataformats="CHW"
    ):
  • tag:图像的标识符,用于在TensorBoard中区分不同的图像
  • img_tensor:图像数据,支持torch.Tensor、numpy.ndarray或字符串/blobname格式
  • global_step:记录的全局步数,用于时间轴上的定位
  • walltime:可选的时间戳,默认使用当前时间
  • dataformats:图像数据格式,如CHW(通道-高度-宽度)、HWC等

(5)add_image使用

python 复制代码
import numpy as np
from PIL import Image
from torch.utils.tensorboard import SummaryWriter

writer=SummaryWriter("logs")
image_path="dataset/train/ants/0013035.jpg"
img_PIL=Image.open(image_path)
#利用numpy将PIL格式转换为numpy数组
img_array=np.array(img_PIL)
print(type(img_array))
print(img_array.shape)
#HWC表示Height(高度)× Width(宽度)× Channels(通道数)
writer.add_image("test",img_array,2,dataformats='HWC')

writer.close()

3.Transforms学习

用于对图像进行预处理和数据增强操作,如调整图像大小、中心裁剪、随机裁剪、随机水平翻转、归一化、将 PIL 图像转换为 Tensor 等等

(1)ToTensor()使用:PyTorch的torchvision模块中的一个转换类,它的主要作用是将PIL图像或NumPy数组转换为PyTorch张量

python 复制代码
#1.创建具体的工具
tensor_trans=transforms.ToTensor()
#2.转换
tensor_img=tensor_trans(img)

writer.add_image("Tensor_img",tensor_img)

(2)Normalize: 对图像进行归一化,对每个通道进行归一化

python 复制代码
trans_norm=transforms.Normalize([3,5,8],[3,2,1])
img_norm=trans_norm(img_tensor)
writer.add_image("Normalize",img_norm,2)

(3)Resize()使用:可以处理 PIL 图像对象,也可以处理张量类型的数据

python 复制代码
trans_resize=transforms.Resize((800,800))
img_resize=trans_resize(img)
img_resize=trans_totensor(img_resize)
writer.add_image("Resize",img_resize,2)

(4)Compose()使用: 组合多个图像转换(transform)操作,通过 Compose,可以创建一个转换流程,这个流程可以按顺序执行多个图像处理操作,这些操作可以包括缩放、裁剪、归一化等,其需要的参数是一个列表,其元素类型是transforms类型。

python 复制代码
trans_resize = transforms.Resize(512)
trans_totensor = transforms.ToTensor() 
trans_compose = transforms.Compose([trans_resize,trans_totensor])
img_resize_2 = trans_compose(img)

4.Torchvision数据集使用

(1)DataSet使用

python 复制代码
#将数据集中的每张图片转换为tensor类型
dataset_transform=torchvision.transforms.Compose([
    torchvision.transforms.ToTensor()
])

torch_set=torchvision.datasets.CIFAR10(root="./dataset",train=True,transform=dataset_transform,download=True)
test_set=torchvision.datasets.CIFAR10(root="./dataset",train=False,transform=dataset_transform,download=True)
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">root="./dataset"</font>: 指定数据集存储的根目录为当前路径下的"dataset"文件夹
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">train=True</font>: 表示加载的是训练集(CIFAR-10中有50000张训练图像)
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">transform=dataset_transform</font>: 对数据应用的预处理/变换操作
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">download=True</font>: 如果数据集不存在于指定目录,则自动下载

(2)Dataloader使用: PyTorch 提供的数据加载器,用于批量加载数据集。

python 复制代码
#transform参数指定了数据转换方式
test_data=torchvision.datasets.CIFAR10(root="./dataset",train="False",transform=torchvision.transforms.ToTensor())

test_loader=DataLoader(dataset=test_data,batch_size=4,shuffle=True,num_workers=0,drop_last=False)

img,target=test_data[0]
print(img.shape)
print(target)

for data in test_loader:
    imgs,targets=data
    print(imgs.shape)
    print(targets)
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">dataset=test_data</font>:指定要加载的数据集
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">batch_size=4</font>:每个批次包含4个样本
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">shuffle=True</font>:在每个epoch开始时打乱数据顺序
  • <font style="color:rgb(163, 21, 21);background-color:rgba(0, 0, 0, 0.1);">drop_last=False</font>:如果最后一批数据小于batch_size,仍然保留

5.神经网络基本骨架nn.Moduel使用

对于定义的模型都需要集成Moduel类,实现__init__和forward函数

python 复制代码
class Module(nn.Module):
    def __init__(self) :
        super().__init__()

    def forward(self,input):
        output=input+1
        return output

module=Module()
x=torch.tensor(1.0)
output=module(x)
print(output)

当调用一个 nn.Module 的实例时,例如 module(x),PyTorch 会自动触发该实例的 forward 方法。这是因为 nn.Module 类在 Python 中被视为一个可调用对象,这是通过在 nn.Module 类中实现特殊方法__call__()来实现的。

call 方法在 nn.Module 中被定义为调用 forward 方法的包装器,像函数一样调用一个 nn.Module 实例时,实际上是在执行 forward 方法,并将传入的参数(在这个例子中是 x)作为输入传递给 forward 方法

6.卷积层的使用

python 复制代码
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),
                                     download=True)

dataloader=DataLoader(dataset,batch_size=64)

class Module(nn.Module):
    def __init__(self):
        super(Module,self).__init__()
        #创建二维卷积层
        self.conv1=Conv2d(in_channels=3,out_channels=6,kernel_size=3,stride=1,padding=0)

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

module=Module()

writer=SummaryWriter("./logs")

step=0
for data in dataloader:
    imgs,targets=data
    output=module(imgs)
    print(imgs.shape)
    print(output.shape)
    #torch。Size([64,3,32,32])
    writer.add_images("input",imgs,step)
    #torch.Size([64,6,30,30])
    #卷积之后图像的形状 torch.Size([64, 6, 30, 30])是6个通道的 而add_images只能接收3通道的输入
    output=torch.reshape(output,(-1,3,30,30))
    writer.add_images("output",output,step)
    step+=1

7.最大池化层

保留输入的特征,同时减少数据量 加快训练速度

python 复制代码
input=torch.tensor([
    [1,2,0,3,1],
    [0,1,2,3,1],
    [1,2,1,0,0],
    [5,2,3,1,1],
    [2,1,0,1,1]
])

input=torch.reshape(input,(-1,1,5,5))
print(input.shape)

class Module(nn.Module):
    def __init__(self):
        super(Module,self).__init__()
        #ceil_mode=True:当输入尺寸不能被池化窗口整除时,使用向上取整的方式计算输出尺寸
        self.maxpool1=MaxPool2d(kernel_size=3,ceil_mode=True)

    def forward(self,input):
        output=self.maxpool1(input)
        return output

8.非线性激活层

引入非线性的特性,使得神经网络具有更强的表达能力和适应能力

(1)ReLU:当输入大于0时,输出等于输入,当输入小于等于0时,输出为0

python 复制代码
input=torch.tensor([
    [1,-0.5],
    [-1,3]
])

input=torch.reshape(input,(-1,1,2,2))
print(input.shape)

class Module(nn.Module):
    def __init__(self):
        super(Module,self).__init__()
        self.relu=ReLU()

    def forward(self,input):
        output=self.relu(input)
        return output

(2)Sigmod:用于隐层神经单元输出,取值范围为(0,1),它可以将一个实数映射到(0,1)的区间,可以用来做二分类。在特征相差比较复杂或者相差不是特别大的时候效果比较好。

9.线性层及其他层

Linear:

output=input×weightT+bias

  • <font style="color:#DF2A3F;">input</font>:输入数据(形状 <font style="color:#000000;">[batch_size, input_dim]</font>
  • <font style="color:#DF2A3F;">weight</font>:权重矩阵(形状 <font style="color:#000000;">[output_dim, input_dim]</font>
  • <font style="color:#DF2A3F;">bias</font>:偏置向量(形状 <font style="color:#000000;">[output_dim]</font>
python 复制代码
import torch
import torch.nn as nn

# 定义一个线性层:输入100维,输出64维
linear_layer = nn.Linear(100, 64)

# 随机生成输入数据(batch_size=5, 输入维度=100)
input_data = torch.randn(5, 100)

# 前向传播
output = linear_layer(input_data)
print("输出形状:", output.shape)  # 输出: torch.Size([5, 64])

10.flatten层

将输入张量扁平化(flatten)的函数,它将输入张量沿着指定的维度范围进行扁平化处理,并返回一个一维张量作为结果

python 复制代码
t = torch.tensor([[[1, 2],
                   [3, 4]],
                  [[5, 6],
                   [7, 8]]])
torch.flatten(t)

11.Sequential的使用

以按照添加的顺序依次执行包含的各个模块,torch.nn.Sequential提供了一种简单的方式来构建神经网络模型,代码十分简洁。

python 复制代码
class Module(nn.Module):
    def __init__(self):
        super(Module,self).__init__()
        #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)
        )

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

module=Module()
print(module)

#网络结构检测
input=torch.ones((64,3,32,32))
output=module(input)
print(output.shape)

12.损失函数

损失函数(Loss Function)用于衡量模型的预测输出与实际标签之间的差异或者误差,损失越小越好,根据loss调整参数(反向传播),更新输出,减小损失

python 复制代码
inputs=torch.tensor([1,2,3],dtype=torch.float32)
targets=torch.tensor([1,2,5],dtype=torch.float32)

inputs=torch.reshape(inputs,(1,1,1,3))
targets=torch.reshape(targets,(1,1,1,3))

#平均绝对误差
loss=L1Loss(reduction="sum")
result=loss(inputs,targets)

#均方误差
loss_mse=MSELoss()
result_mse=loss_mse(inputs,targets)

print(result,result_mse)

分类问题常用损失:CrossEntropyLoss交叉熵损失函数

python 复制代码
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),
                                     download=True)
dataloader=DataLoader(dataset=dataset,batch_size=64)

class Module(nn.Module):
    def __init__(self):
        super(Module,self).__init__()
        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)
        )

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

#使用交叉熵损失函数
loss=nn.CrossEntropyLoss()
module=Module()
for data in dataloader:
    imgs,targets=data
    outputs=module(imgs)
    result_loss=loss(outputs,targets)
    #执行反向传播,计算损失相对于模型参数的梯度,这些梯度将用于后续的参数更新
    result_loss.backward()
    print(result_loss)

反向传播:在张量上进行操作时,PyTorch 会自动跟踪操作并构建计算图,可以使用 .backward() 方法(反向传播)计算梯度,然后通过 .grad 属性获取梯度值

13.优化器使用

在深度学习中,optimizer.zero_grad()是一个非常重要的操作,它的含义是将模型参数的梯度清零。

在训练神经网络时,通常采用反向传播算法来计算损失函数关于模型参数的梯度,并利用优化器来更新模型参数以最小化损失函数。在每次反向传播计算梯度后,梯度信息会被累积在对应的参数张量(tensor)中。如果不清零梯度,在下一次计算梯度时,这些梯度将会被新计算的梯度累加,导致梯度信息错误。

python 复制代码
#创建一个计算交叉损失熵函数
loss=nn.CrossEntropyLoss()
module=Module()
#创建一个随机梯度下降(SGD)优化器
optim=torch.optim.SGD(module.parameters(),lr=0.01)

for epoch in range(20):
    running_loss=0.0
    for data in dataloader:
        imgs,targets=data
        outputs=module(imgs)
        result_loss=loss(outputs,targets)
        #将模型中所有参数(parameters)的梯度清零。
        optim.zero_grad()
        #反向传播
        result_loss.backward()
        #optim.step()是优化器对象的一个方法,用于根据计算得到的梯度更新模型的参数
        optim.step()
        running_loss=running_loss+result_loss
    print(running_loss)

14.网络模型使用

(1)模型下载、添加、修改

python 复制代码
#vgg16网络模型下载
vgg16_false=torchvision.models.vgg16(pretrained=False)
vgg16_true=torchvision.models.vgg16(pretrained=True)

#现有网络模型添加
vgg16_true.classifier.add_module("add_linear",nn.Linear(1000,10))

#现有网络模型修改
vgg16_false.classifier[6]=nn.Linear(4096,10)
print(vgg16_false)

(2)模型保存

python 复制代码
vgg16=torchvision.models.vgg16(weights=None)
#保存方式1,模型结构+模型参数
torch.save(vgg16,"vgg16_method1.pth")

#保存方式2(推荐),模型参数
torch.save(vgg16.state_dict(),"vgg16_method2.pth")

(3)模型加载

python 复制代码
#加载模型方式1
model=torch.load("vgg16_method1.pth")
print(model)

#加载模型方式2
#创建一个未预训练的VGG16模型,weights=None表示不加载预训练权重
vgg16=torchvision.models.vgg16(weights=None)
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
print(vgg16)

15.完整网络模型训练与测试套路

python 复制代码
import torch.optim
import torchvision.datasets
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

from model import *
from nn_optim import epoch

#使用GPU进行训练
device=torch.device("cuda")

train_data=torchvision.datasets.CIFAR10(root="./dataset",train=True,transform=torchvision.transforms.ToTensor(),
                                        download=True)
test_data=torchvision.datasets.CIFAR10(root="./dataset",train=False,transform=torchvision.transforms.ToTensor(),
                                        download=True)
#length长度
train_data_size=len(train_data)
test_data_size=len(test_data)
print("训练数据长度为{}".format(train_data_size))
print("测试数据长度为{}".format(test_data_size))

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

#创建网络模型
module=Module()
module=module.to(device)

#损失函数
loss_fn=nn.CrossEntropyLoss()
loss_fn=loss_fn.to(device)

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

#设置训练网络的一些参数
#记录训练次数
total_train_step=0
#记录测试次数
total_test_step=0
#训练轮数
epoch=10

#添加tensorboard
writer=SummaryWriter("./logs_train")

for i in range(epoch):
    print("--------第{}轮训练开始----------".format(i+1))

    #训练步骤
    for data in train_dataloader:
        imgs,targets=data
        imgs=imgs.to(device)
        targets=targets.to(device)
        outputs=module(imgs)
        loss=loss_fn(outputs,targets)

        #优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_train_step=total_train_step+1
        if total_train_step%100==0:
            print("训练次数:{},loss:{}".format(total_train_step,loss))
            writer.add_scalar("train_loss",loss,total_train_step)

    #测试步骤
    total_test_loss=0
    total_accuracy=0

    with torch.no_grad():
        for data in test_dataloader:
            imgs,targets=data
            imgs = imgs.to(device)
            targets = targets.to(device)
            outputs=module(imgs)
            loss=loss_fn(outputs,targets)
            total_test_loss=total_test_loss+loss
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy=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=total_test_step+1

    #保存网络模型
    torch.save(module,"moduel_{}.pth".format(i))
    print("模型已保存")
writer.close()

在推理或评估模型时使用torch.no_grad(),表明当前计算不需要反向传播使用之后,强制后边的内容不进行计算图的构建,

with 语句是 Python 中的一个语法结构,用于包裹代码块的执行,并确保在代码块执行完毕后,能够自动执行一些清理工作。


model.train()开启训练模式,模型会跟踪所有层的梯度,以便在优化器进行梯度下降时更新模型的权重。

model.eval():开启评估模式,在评估模式下,模型不会跟踪梯度,这有助于减少内存消耗并提高计算效率。

16.使用GPU进行训练

(1)对于网络模型,数据,以及损失函数,都要调用cuda()

(2)(推荐)xx=xx.to(device)

python 复制代码
device=torch.device("cuda")

#模型
module=module.to(device)
#损失函数
loss_fn=loss_fn.to(device)
#数据
imgs=imgs.to(device)
targets=targets.to(device)
相关推荐
机器之心5 小时前
谷歌重大突破!量子计算首次可验证,登《Nature》封面
人工智能·openai
ZhengEnCi5 小时前
Python_哈希表完全指南-从字典到高效查找的 Python 编程利器
python
gustt5 小时前
每天一杯科技资讯咖啡,用 n8n 喂给 AI
人工智能·node.js
技术闲聊DD5 小时前
深度学习(8)- PyTorch 数据处理与加载
人工智能·pytorch·深度学习
Juchecar5 小时前
从LLM训练和推理角度,区分 “知识”与“智慧”
人工智能
今天没ID5 小时前
Python 集合类型全解析:从网球赛事案例看透字符串、列表、元组、集合与字典(1)
python
小宁爱Python5 小时前
从零搭建 RAG 智能问答系统 4:从多模态架构到 Milvus 向量存储实践
python·milvus
林炳然5 小时前
Python-Basic Day-2 python容器(列表、元组)
python
掘金一周5 小时前
一个前端工程师的年度作品:从零开发媲美商业级应用的后台管理系统 | 掘金一周 10.23
前端·人工智能·后端