首页 > 其他分享 >pytorch学习

pytorch学习

时间:2024-04-20 19:56:18浏览次数:18  
标签:loss nn self torch 学习 pytorch model size

数据集

PyTorch中,torch.utils.data.DataLoader和torch.utils.data.Dataset 可以让我们方便使用预加载的数据集或者自己的数据集。Dataset存储数据样本及其对应的标签,而DataLoader将Dataset包裹起来,生成一个可迭代对象,以便轻松访问数据样本。

1. 加载数据集
import torch
from torch.utils.data import Dataset
from torchvision import datasets
from torchvision.transforms import ToTensor
import matplotlib.pyplot as plt
# 训练数据集
training_data = datasets.FashionMNIST(
    root="data", # 数据集下载路径
    train=True, # True为训练集,False为测试集
    download=True, # 是否要下载
    transform=ToTensor() # 对样本数据进行处理,转换为张量数据
)
# 测试数据集
test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor() 
2. 可视化数据集
# 标签字典,一个key键对应一个label
labels_map = {
    0: "数字1",
    1: "……",
    ……
}
# 设置画布大小
figure = plt.figure(figsize=(8, 8))
cols, rows = 3, 3
for i in range(1, cols * rows + 1):
    # 随机生成一个索引
    sample_idx = torch.randint(len(training_data), size=(1,)).item()
    # 获取样本及其对应的标签
    img, label = training_data[sample_idx]
    # 添加子图
    figure.add_subplot(rows, cols, i)
    plt.title(labels_map[label])
    # 不显示坐标轴
    plt.axis("off")
    # 显示灰度图
    plt.imshow(img.squeeze(), cmap="gray")#img.squeeze()被用来去除图像数组中的单通道维度,以便能够正确地显示灰度图像。
3.自定义数据集

在定义自己的数据集时,需继承Dataset类

init:实例化Dataset对象时运行,完成初始化工作。
len:返回数据集的大小。
getitem:根据索引返回一个样本(数据和标签)。

import os
import pandas as pd
from torchvision.io import read_image
class ImageDataset(Dataset):
    def __init__(self, annotations_file, img_dir, transform=None, target_transform=None):
        # 读取标签文件
        self.img_labels = pd.read_csv(annotations_file)
        # 读取图片存储路径
        self.img_dir = img_dir
        # 数据处理方法
        self.transform = transform
        # 标签处理方法
        self.target_transform = target_transform
    def __len__(self):
        return len(self.img_labels)
    def __getitem__(self, idx):
        # 单张图片路径
        img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
        # 读取图片
        image = read_image(img_path)
        # 获得对应的标签
        label = self.img_labels.iloc[idx, 1]
        if self.transform:
            image = self.transform(image)
        if self.target_transform:
            label = self.target_transform(label)
        # 返回一个元组
        return image, label

数据加载器

1.根据数据集生成一个可迭代的对象,用于模型训练

两个工具包,可配合DataLoader使用:

  • enumerate(iterable, start=0):输入是一个可迭代的对象和下标索引开始值;返回可迭代对象的下标索引和数据本身。

  • tqdm(iterable):进度条可视化工具包

    from torch.utils.data import DataLoader
    data_loader = DataLoader(
        dataset=MyDataset,#定义好的数据集
        batch_size=16,#每次放入网络训练的批次大小,默认为1.
        shuffle=True, #是否打乱数据的顺序,默认为False。一般训练集设置为True,测试集设置为False
        num_workers=0,#线程数,默认为0。在Windows下设置大于0的数可能会报错
        drop_last=False,#是否丢弃最后一个批次的数据,默认为False。
    )
    
    2.加载数据
    from torch.utils.data import DataLoader
    train_dataloader = DataLoader(
        dataset=training_data, 
        batch_size=64, 
        shuffle=True)
    test_dataloader = DataLoader(
        dataset=test_data, 
        batch_size=64,
        shuffle=True)
    
3 遍历DataLoader
# 展示图片和标签
train_features, train_labels = next(iter(train_dataloader))
# (B,N,H,W)
print(f"Feature batch shape: {train_features.size()}")# Feature batch shape:torch.Size([64, 1, 28, 28])
print(f"Labels batch shape: {train_labels.size()}")# Labels batch shape: torch.Size([64])
# 获取第一张图片,去除第一个批量维度
img = train_features[0].squeeze()
label = train_labels[0]
plt.imshow(img, cmap="gray")
plt.show()
print(f"Label: {label}")# Label: 8

torchvision.transforms图片处理

import torch
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda
ds = datasets.FashionMNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor(),
    # Lambda变换,定义了一个函数来将整数转换为one-hot编码张量
    # 它首先创建一个大小为10的零张量(数据集中的标签数量)并调用scatter_,根据索引y将值更改为1
    target_transform = Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(dim=0, index=torch.tensor(y), value=1))
)
transfroms.ToTensor()

将PIL Image或者numpy.ndarray格式的数据转换为tensor格式,像素值大小缩放至区间[0., 1.]。

transforms.Normalize()

对输入进行标准化,传入均值(mean[1],…,mean[n])和标准差(std[1],…,std[n]),n与输入的维度相同。

output[channel] = (input[channel] - mean[channel]) / std[channel]

transforms.ToPILImage()

将tensor或者numpy.ndarray格式的数据转换为PIL Image图片格式。

transforms.Resize()

修改图片尺寸。参数size可是序列或整数,传序列,修改后图片尺寸和序列一致;传入整数,则等比例缩放图片。

transforms.CenterCrop()

中心裁剪图片。参数size可序列或整数,传序列,则裁剪后的图片尺寸和序列一致;传整数,则裁剪尺寸长宽都为size的正方形

transforms.RandomCrop()

随机裁剪。参数size可以是序列也可以是整数

transforms.RandomResizedCrop()

将给定图像随机裁剪为不同的大小和宽高比,然后缩放所裁剪得到的图像为制定的大小。

transforms.RandomHorizontalFlip()

有一定概率将图片水平翻转,默认概率为0.5。

transforms.RandomVerticalFlip()

有一定概率将图片垂直翻转,默认概率为0.5。

transforms.RandomRotation()

将图片旋转。参数degrees可以为序列或者数值,如果为序列,则旋转角度为(min_degree, max_degree);如果为数值,则旋转角度为(-degrees, +degrees)。

模型定义

torch.nn提供了构建神经网络所需的全部模块。

1.训练设备

device = "cuda" if torch.cuda.is_available() else "cpu"

2 定义模型

class NeuralNetwork(nn.Module):
    def __init__(self):
        super(NeuralNetwork, self).__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(in_features=28 * 28, out_features=512),
            nn.ReLU(),
            nn.Linear(in_features=512, out_features=512),
            nn.ReLU(),
            nn.Linear(in_features=512, out_features=10),
        )
    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

实例化NeuralNetwork类,并将其移动到device上。

model = NeuralNetwork().to(device)
print(model)

3 网络模型中的各种层

我们随机生成3张大小为 28x28 的图像的小批量样本,观察每一层对输入数据处理的结果

input_image = torch.rand(3,28,28)
# torch.Size([3, 28, 28])
1 nn.Flatten
flatten = nn.Flatten()
flat_image = flatten(input_image)
 # torch.Size([3, 784])
2 nn.Linear
layer1 = nn.Linear(in_features=28*28, out_features=20)
hidden1 = layer1(flat_image)
print(hidden1.size())
# torch.Size([3, 20])
3 nn.ReLU
hidden1 = nn.ReLU()(hidden1)
4 nn.Sequential

nn.Sequential可以理解为网络层的容器,在其中我们定义各种网络层,数据会按照我们设置的顺序经过所有网络层。

seq_modules = nn.Sequential(
    flatten,
    layer1,
    nn.ReLU(),
    nn.Linear(20, 10)
)
input_image = torch.rand(3,28,28)
logits = seq_modules(input_image)

优化模型参数

训练模型是一个迭代过程;在每次迭代(epoch)中,模型对输出进行预测,首先计算猜测值与真实值的误差(损失),然后计算误差关于其参数的导数,最后使用梯度下降法优化这些参数

1 超参数
  • 训练次数epochs:迭代数据集的次数。
  • 批处理大小batch_size:每次传入网络中的样本数量。
  • 学习率learning_rate:在每个批次更新模型参数的程度。较小的值会产生较慢的学习速度,而较大的值可能会导致训练期间出现不可预测的行为。
2 优化循环
  • 训练循环:迭代训练数据集并尝试收敛到最佳参数。
  • 验证/测试循环:迭代测试数据集以检查模型性能是否正在改善。
损失函数
# 初始化损失函数
loss_fn = nn.CrossEntropyLoss()
优化器
  • 调用optimizer.zero_grad()将模型参数的梯度归零。默认情况下梯度会累加。
  • 调用loss.backward()来反向传播预测损失。PyTorch存储每个参数的损失梯度。
  • 计算梯度完成后,调用optimizer.step()来调整参数。
# 优化模型参数
def train_loop(dataloader, model, loss_fn, optimizer, device):
    size = len(dataloader.dataset)
    for batch, (X, y) in enumerate(dataloader):
        X = X.to(device)
        y = y.to(device)
        pred = model(X)
        # 计算损失
        loss = loss_fn(pred, y)
        # 反向传播,优化参数
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
 
        if batch % 100 == 0:
            loss, current = loss.item(), batch * len(X)
            print(f"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")
 
# 测试模型性能
def test_loop(dataloader, model, loss_fn, device):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    test_loss, correct = 0, 0
    with torch.no_grad():
        for X, y in dataloader:
            X = X.to(device)
            y = y.to(device)
            # 前向传播,计算预测值
            pred = model(X)
            # 计算损失
            test_loss += loss_fn(pred, y).item()
            # 计算准确率
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
 
    test_loss /= num_batches
    correct /= size
    print(f"Test Error: \n Accuracy: {(100 * correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")

我们初始化损失函数和优化器,并将其传递给train_looptest_loop

loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(params=model.parameters(), lr=learning_rate)
 
epochs = 10
for t in range(epochs):
    print(f"Epoch {t+1}\n-------------------------------")
    train_loop(train_dataloader, model, loss_fn, optimizer, device)
    test_loop(test_dataloader, model, loss_fn, device)
print("Done!")
 
# ...
# Epoch 5
# -------------------------------
# loss: 1.214354  [    0/60000]
# loss: 1.228768  [ 6400/60000]
# loss: 1.314466  [12800/60000]
# loss: 1.234377  [19200/60000]
# loss: 1.242174  [25600/60000]
# loss: 1.027974  [32000/60000]
# loss: 1.062843  [38400/60000]
# loss: 1.157571  [44800/60000]
# loss: 1.091189  [51200/60000]
# loss: 1.143303  [57600/60000]
# Test Error: 
#  Accuracy: 64.6%, Avg loss: 1.092479 
# 
# Done!

保存和加载模型

保存和加载模型权重
# 样例代码如下
model = models.vgg16(pretrained=True) # pretrained=True加载预训练好的参数
torch.save(model.state_dict(), 'model_weights.pth')
 
# 要加载模型权重,首先需要创建一个相同模型的实例,然后使用load_state_dict()方法加载参数。
model = models.vgg16() # 不加载预训练好的参数
model.load_state_dict(torch.load('model_weights.pth'))
model.eval() # 将模型设置为测试模式,避免dropout和batch normalization对预测结果造成的影响
保存和加载整个模型

保存模型的结构和参数:

torch.save(model, 'model.pth')

加载模型:

model = torch.load('model.pth')

标签:loss,nn,self,torch,学习,pytorch,model,size
From: https://www.cnblogs.com/1019-Yan/p/18148058

相关文章

  • 值得学习的技巧/码风——mainly from jiangly
    1、主体框架:#include<bits/stdc++.h>usingi64=longlong;intmain(){ std::ios::sync_with_stdio(false);std::cin.tie(nullptr);}2、基本都在主函数中定义数组而非全局,且多用\(\rmstd::vector\)而非数组。3、常用函数std::rotate、std::swap、std::max、s......
  • CAN总线原理_学习
    随着通信技术的发展,现今通信方式和协议五花八门,但CAN通信仍然是车载网络最安全可靠且应用最广的技术之一。过去,汽车通常采用常规的点对点通信方式将电子控制单元及电子装置连接起来,但随着电子设备的不断增加,导线数量也随之增多,采用CAN总线网络结构,可以达到信息共享、......
  • (数据结构代码,总结,自我思考)=> { return 个人学习笔记; } 【To be continued~】
    俗话说“学而不思则罔”,是时候复习和整理一下自己先前的学习历程了!Chapter-One《BinarySearch》publicstaticintbinarySearch(int[]a,inttarget){inti=0,j=a.length-1;while(i<=j){intm=(i+j)>>>1;//求......
  • 四元数 学习笔记
    License:CCBY-NC-SA4.0目录复数极坐标表示三维旋转四元数Grassmann积纯四元数共轭逆三维旋转,但是四元数矩阵形式旋转的复合四元数的插值杂参考资料复数在了解四元数之前,要先了解复数对空间干了什么。设有复数\(z_1=a+b\mathrm{i},z_2=c+d\mathrm{i}\),则\[z_1z_2......
  • 结构体学习
    /**********************************************************************************************************提高可移植性Copyright(c)[email protected]*******************************************************************......
  • 拉格朗日插值学习笔记
    拉格朗日插值学习笔记应用众所周知,在平面直角坐标系中,对于任意的\(n\)个点,都一定有一个不超过\(n-1\)次的函数与之相对应。拉格朗日插值适用于求解这\(n\)个点对应的函数。思路考虑给定的\(n\)个点的坐标表示为\((x_i,y_i)\),不难构造出如下函数:\[f(x)=\sum_{i=1}^{n......
  • .NET开源免费的跨平台框架 - MAUI(附学习资料)
    前言前几天分享了一个.NETMAUI开源免费的UI工具包-Uranium,然后技术群有不少同学问.NETMAUI是不是免费的?能做什么?今天特意写这篇文章来介绍一下.NET开源、免费(基于MITLicense)的跨平台框架:MAUI。.NETMAUI官方介绍.NET多平台应用UI(.NETMAUI)是一个跨平台框架,用于使用......
  • 算法中的变形金刚——单纯形算法学习笔记
    目录阅读本文你将会知道线性规划简介线性规划的标准形一般型转标准型<与≤线性规划的松弛形标准型转松弛形单纯形算法基本可行解如何判断最优旋转操作如何通过旋转更新解?退化与布兰德规则基本不可行解单纯形算法的几何意义单纯形算法的时间复杂度分析线性规划问题有更优的做法吗......
  • MVCC学习圣经:一文穿透MySQL MVCC,吊打面试官
    文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+涨薪必备免费赠送:《尼恩技术圣经+高并发系列PDF》,帮你实现技术自由,完成职业升级,薪......
  • opencascade官网文档学习之OCCT-Shape healing (3)分析 TopoDS_Shape
    Analysis分析Analysisofshapevalidity形状有效性分析ShapeAnalysis软件包提供了用于分析拓扑形状的工具。在执行修复工具之前,没有必要通过这些工具检查形状,因为这些工具用于在修复工具内部执行修复之前的分析。但是,如果您愿意,这些工具可以独立于修复工具用于检测某些形状问......