首页 > 其他分享 >【基础教程】Tutorial on Pytorch 结合官方基础文档和个人经验

【基础教程】Tutorial on Pytorch 结合官方基础文档和个人经验

时间:2024-07-26 22:50:21浏览次数:17  
标签:tensor self torch transform Pytorch 基础教程 print data Tutorial

参考与前言

此教程首次书写于2021年12月份 至 2022年4月份间不断补充;阅读本文时可以对着代码运行查看

  1. 官方网址:https://pytorch.org/tutorials/ 【基本从这里翻译而来 更简洁版+碎碎念】
  2. https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py
  3. 简单版分类器:https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html

好像还是很tensorflow有点区别的 毕竟 tensorflow emmm 我看一下 好像懂了,我记得久远之前我看过pytorch的 但是因为没做笔记+好久没用了 所以 忘得也挺快

相关训练细节上加速的tutorial:Tutorial: GPU利用率问题 [V]

1. 数据结构

tensor

tensor 是一种特殊的数据结构,与数组和矩阵非常相似。在 PyTorch 中,我们使用 tensor 对模型的输入和输出以及模型的参数进行编码。

  • 好吧 torch.from_numpy 也很快 emm

初始化方法

# Directly from data
data = [[1, 2], [3, 4]]
x_data = torch.tensor(data)

# From a NumPy array
np_array = np.array(data)
x_np = torch.from_numpy(np_array)

# From another tensor:
x_ones = torch.ones_like(x_data) # retains the properties of x_data
print(f"Ones Tensor: \n {x_ones} \n")
x_rand = torch.rand_like(x_data, dtype=torch.float) # overrides the datatype of x_data
print(f"Random Tensor: \n {x_rand} \n")

# With random or constant values:
shape = (2, 3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)

print(f"Random Tensor: \n {rand_tensor} \n")
print(f"Ones Tensor: \n {ones_tensor} \n")
print(f"Zeros Tensor: \n {zeros_tensor}")

可以 from numpy 当然也可以to numpy啦,Changes in the NumPy array reflects in the tensor.

t = torch.ones(5)
print(f"t: {t}")
n = t.numpy()
print(f"n: {n}")

t.add_(1)
print(f"t: {t}")
print(f"n: {n}")

t: tensor([2., 2., 2., 2., 2.])
n: [2. 2. 2. 2. 2.]

Attribute

就是类似numpy里面的.shape, type(), 以及其特有的存储地点:描述它们的形状、数据类型和存储它们的设备。

tensor = torch.rand(3, 4)

print(f"Shape of tensor: {tensor.shape}")
print(f"Datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}")

操作

换个地方放放:

# We move our tensor to the GPU if available
if torch.cuda.is_available():
  tensor = tensor.to('cuda')
  print(f"Device tensor is stored on: {tensor.device}")

# 和numpy基本一模一样的操作形式
tensor = torch.ones(4, 4)
tensor[:,1] = 0
print(tensor)

tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])

# -------------------------------------------------
# 把几个tensor合在一起
t1 = torch.cat([tensor, tensor, tensor], dim=1)
print(t1)

tensor([[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.]])

# -------------------------------------------------

# 对应位置的元素相乘
# This computes the element-wise product
print(f"tensor.mul(tensor) \n {tensor.mul(tensor)} \n")
# Alternative syntax:
print(f"tensor * tensor \n {tensor * tensor}")

# 矩阵的形式
# This computes the matrix multiplication between two tensors
print(f"tensor.matmul(tensor.T) \n {tensor.matmul(tensor.T)} \n")
# Alternative syntax:
print(f"tensor @ tensor.T \n {tensor @ tensor.T}")

# -------------------------------------------------
print(tensor, "\n")
tensor.add_(5)
print(tensor)

tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])

tensor([[6., 5., 6., 6.],
        [6., 5., 6., 6.],
        [6., 5., 6., 6.],
        [6., 5., 6., 6.]])

In-place operations Operations that have a _ suffix are in-place. For example: x.copy_(y), x.t_(), will change x.

2. 数据与加载

处理数据样本的代码可能会变得混乱且难以维护; 我们希望数据集代码与模型训练代码分离,以获得更好的可读性和模块化。pytorch提供了两个数据的使用库: torch.utils.data.DataLoader and torch.utils.data.Dataset that allow you to use pre-loaded datasets as well as your own data.

  • Dataset stores the samples and their corresponding labels
  • DataLoader wraps an iterable around the Dataset to enable easy access to the samples.

当然pytorch里的Dataset 也有一些开源的数据集成,更多查询: Image Datasets, Text Datasets, and Audio Datasets

FashionMNIST

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,
    download=True,
    transform=ToTensor()
)

test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor()
)

labels_map = {
    0: "T-Shirt",
    1: "Trouser",
    2: "Pullover",
    3: "Dress",
    4: "Coat",
    5: "Sandal",
    6: "Shirt",
    7: "Sneaker",
    8: "Bag",
    9: "Ankle Boot",
}
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")
plt.show()

Custom Dataset

自定义的Dataset必须有这三个函数: init, len, and getitem.

对应 FashionMNIST 的数据集,其照片是存在 img_dir文件夹中 and their labels are stored separately in a CSV file annotations_file.

官方示例:

import os
import pandas as pd
from torchvision.io import read_image

class CustomImageDataset(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

init

init 函数仅在你实例化这个Dataset object的时候运行一次. 我们在这里给出包含图片,label和是否需要转换

如果一个labels.csv文件长这样的话:

tshirt1.jpg, 0
tshirt2.jpg, 0
......
ankleboot999.jpg, 9

那么__init__函数为:

def __init__(self, annotations_file, img_dir, transform=None, target_transform=None):
    self.img_labels = pd.read_csv(annotations_file, names=['file_name', 'label'])
    self.img_dir = img_dir
    self.transform = transform
    self.target_transform = target_transform

len

这个函数主要返回我们数据集的大小,比如:

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

getitem

这个函数主要用来加载输入的 idx 对应的数据,基于给的idx,可以定位到哪张图片,然后使用 read_image 转成tensor,从 self.img_labels找到对应的label,然后返回tensor格式的图片和一个tuple格式的label

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

transforms

数据并不总是以训练机器学习算法所需的最终处理形式出现。 我们使用转换来对数据进行一些操作并使其适合训练。

从上一条我们知道需要返回tensor格式的数据,如image可能直接可以从库里调用ToTensor()

TorchVision 库里的数据集,通常有两个参数

  • transform to modify the features
  • target_transform to modify the labels - that accept callables containing the transformation logic.

torchvision.transforms 这个模块,已经提供了很多通用的transform的功能

例如以下,同样FashionMNIST 这个数据集下 feature图片是PIL图片格式,label是整数;为了训练,我们需要把feature归一化成tensors,把label用one-hot encoded的tensor表示,为了实现这些呢:我们就需要使用 ToTensor and Lambda. 比如这里:比前面的多了一行对label的转换

import torch
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda

ds = datasets.FashionMNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor(),
    target_transform=Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(0, torch.tensor(y), value=1))
)

比如最近参加kaggle竞赛练手的,写了关于image的transforms

preprocess = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

ToTensor()

ToTensor 是把PIL图片或者是numpy的ndarray转成 FloatTensor. 然后图片的像素intensity值都归一化到[0., 1.]

Lambda Transforms

Lambda 转换适用于任何用户定义的 lambda 函数。 在这里,我们定义了一个函数来将整数转换为单one-hot tensor。 它首先创建一个大小为 10(我们数据集中的标签数量)的zero tensor,并调用 scatter_,它在标签 y 给定的索引上分配一个值=1

target_transform = Lambda(lambda y: torch.zeros(
    10, dtype=torch.float).scatter_(dim=0, index=torch.tensor(y), value=1))

3. 网络NetWork

构建网络

神经网络由对数据执行操作的层/模块组成。 torch.nn 命名空间提供了构建自己的神经网络所需的所有构建块。 PyTorch 中的每个模块都是 nn.Module 的子类。 神经网络是一个模块,由其他模块(层)组成。 这种嵌套结构允许轻松构建和管理复杂的架构。

在下面是构建一个神经网络来对 FashionMNIST 数据集中的图像进行分类的一个例子

import os
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(f'Using {device} device')

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

    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

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

通过继承 nn.Module 来定义我们的神经网络,并在 __init__ 中初始化神经网络层。 每个 nn.Module 子类都在 forward 方法中实现对输入数据的操作。

  • 这里就是和tensorflow不太一样的地方,比如这里tensorflow定义完后 直接是 .fit 然后就是trainde 过程了

    # Creat a neural network now
    model_cnn = Sequential(name = "CNN")
    
    # First Convolution Layer
    model_cnn.add(Conv2D(8, input_shape = x_trainr.shape[1:], kernel_size = 3,padding='same',strides=1,activation='relu'))
    model_cnn.add(MaxPooling2D(pool_size=2))
    
    # 2nd Convolution Layer
    model_cnn.add(Conv2D(16,kernel_size = 3,padding='same',strides=1,activation='relu'))
    model_cnn.add(MaxPooling2D(pool_size=2))
    
    # Fully connected layer
    model_cnn.add(Flatten())
    model_cnn.add(Dense(64))
    model_cnn.add(Activation("relu"))
    
    # Last Fully connected layer
    model_cnn.add(Dense(11))
    
    model_cnn.add(Activation("softmax"))
    model_cnn.compile(loss = "sparse_categorical_crossentropy",optimizer="adam",metrics=['accuracy'])
    model_cnn.summary()
    model_cnn.fit(x_trainr,y_train,epochs=10)
    print("Test Dataset:")
    test_loss, test_acc = model_cnn.evaluate(x_testr,y_test)
    

使用将data传到模型里就行,它会自动运行 model’s forward, 同时还有 background operations. 不需要自己调用 model.forward() directly!

在输入上调用模型会返回一个 10D tensor,其中包含每个类的原始预测值。 我们通过将其传递给 nn.Softmax 模块的实例来获得预测概率。

X = torch.rand(1, 28, 28, device=device)
logits = model(X)
pred_probab = nn.Softmax(dim=1)(logits)
y_pred = pred_probab.argmax(1)
print(f"Predicted class: {y_pred}")
  • 原来是自己写ephoc来训练

block 形式的

参考于:5. 深度学习计算 - 动手学深度学习 2.0.0-beta0 documentation

训练方法

直接快进到这里了,这个是示例里的:

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

# 1. 导入数据
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
batch_size = 4
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,
                                          shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,
                                         shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

# 2. 定义网络层
class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = torch.flatten(x, 1) # flatten all dimensions except batch
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

net = Net()

# 3. 评判器
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

# 4. 训练过程
for epoch in range(2):  # loop over the dataset multiple times
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs; data is a list of [inputs, labels]
        inputs, labels = data
        # zero the parameter gradients
        optimizer.zero_grad()
        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        # print statistics
        running_loss += loss.item()
        if i % 2000 == 1999:    # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0
print('Finished Training')

# 5. save model
PATH = './cifar_net.pth'
torch.save(net.state_dict(), PATH)

# 6. 从测试集中弄一些出来
dataiter = iter(testloader)
images, labels = dataiter.next()

# print images
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

# 7. 打开原来的model
net = Net()
net.load_state_dict(torch.load(PATH))

# 8. 输出output
outputs = net(images)
_, predicted = torch.max(outputs, 1)
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
                              for j in range(4)))

动态调整 learning rate

参考,此处需要注意文档的版本选择,因为1.10后的torch实现了更多动态调整的方式:torch.optim - PyTorch 1.10.1 documentation

使用方式参考:

import torch.optim as optim
net = MODEL(out_label = len(classes)).to(device)

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=lr)

# 动态改变Learning rate
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.5)

# 4. 训练过程
for epoch in tqdm(range(num_epochs)):  # loop over the dataset multiple times
    for i, data in enumerate(train_dataloader,0):
        # get the inputs; data is a list of [inputs, labels]
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)
        # zero the parameter gradients
        optimizer.zero_grad()
        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
    scheduler.step()

4. 数据操作

由杰哥代码发现的一个更好用的:rearrange

rearrange - Einops

Pytorch view() permute() contiguous() transpose()

view

CSDN介绍官网介绍

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda, Compose
import matplotlib.pyplot as plt

x = torch.rand(24,3,256,256)
x.size()

a = x.view(x.size(0), -1)
print('after view',a.size())

m = nn.Sequential(nn.Flatten())
y = m(x)
print('after flatten',y.size())

有意思的是,CSDN 下有人问了 和flatten有什么区别 这个操作,从数据输出上来看,都是一样的输出 [24,196608] ,而且展开的数据也都是一样的,关于这个我提了一个问 有人回答了 真不错呀,省流版:一般大家在model中都会习惯性nn.Flatten()

YP大哥:好像是某个开的空间是连续的

  • 但是我实践了一下 并没有什么区别?首先是关于contiguous说的是返回和原数据一样的形式的连续空间tensor,但是我一改b/y 还是会对其他造成影响,也就是说明 =和=.contiguous 都是直接指向了原tensor的地址?→ 但这点我实际vscode debug的时候发现地址并不一样

    view

December 14, 2021 10:22 PM (GMT+8) 刚刚又仔细看了一下,是这样的view的操作需要这个tensor在连续的空间呢,所以呢一般都会在view操作前先contiguous,使其放在一个连续的内存空间上

contiguous

将数据放在连续空间内存下,一般在view操作前会用一下,因为tensor经过permute,

permute

torch官方

torch.permute(input, dims) → Tensor
  • input (Tensor) – 输出的tensor数据
  • dims (tuple of python:ints) – 想要的维度的顺序

举个例子,在这里 2,0,1 表示 我希望第二个维度(也就是size 5那里)在第0个,第零个维度在第1个,第一个维度在第2个【以0为开始哈】

x = torch.randn(2, 3, 5)
x.size()
torch.permute(x, (2, 0, 1)).size()

所以permute后,size就变成了(5,2,3)

sqeeze 和 unsqeeze

  • torch.squeeze():这个函数主要对数据的维度进行压缩,去掉维数为1的的维度,默认是将a中所有为1的维度删掉。也可以通过dim指定位置,删掉指定位置的维数为1的维度。
  • torch.unsqueeze():这个函数主要是对数据维度进行扩充。需要通过dim指定位置给指定位置加上维数为1的维度

这里是关于squeeze和unsqueeze的图示 (图片摘自stackexchange):


赠人点赞 手有余香

标签:tensor,self,torch,transform,Pytorch,基础教程,print,data,Tutorial
From: https://www.cnblogs.com/kin-zhang/p/18326411

相关文章

  • 如何使用pytorch 远程服务器调试代码|同步编辑
    写在前面:写这篇博客的原因是本新手小白开始用服务器跑代码,有时候发现效果不理想,就要重新更改代码再上传到服务器重新跑,一来二去觉得很费工夫,就想:能不能在自己电脑上更新代码同时在服务器同步跟新,研究了一下发现pytorch可以远程服务器,实现了在我的电脑上改代码,在服务器上跑代......
  • PyTorch学习(1)
    PyTorch学习(1)CIFAR-10数据集-图像分类数据集来源是官方提供的:torchvision.datasets.CIFAR10()共有十类物品,需要用CNN实现图像分类问题。代码如下:(CIFAR_10_Classifier_Self_1.py)importtorchimporttorchvisionfromtorchimportoptimfromtorch.utils.dataimp......
  • 学习资源系列之《Python深度学习基于PyTorch》
     前言近期应部分读者朋友的强烈邀请,希望推荐一本python深度学习实操的书籍。呐,今天为大家推荐小编偶然发现的这一本珍藏好书:《Python深度学习基于PyTorch》,文末附电子版获取方式《Python深度学习基于PyTorch》BriefIntroduction前言面对众多的深......
  • TLM求解器使用方法【CST软件零基础教程】
    TLM是三维全波电磁算法的一种,在CST中和T-solver一样都属于时域算法,互相补充。CST于2008年将TLM求解器收购。由于TLM求解器支持一些特殊的材料和结构,比如压缩模型,二维材料,而在EMC仿真中常用这些特殊材料和结构将系统简化,TLM便派上用场。当然,在天线,PCB,生物模型SAR仿真方面,TLM也......
  • conda 中的“torch”和“pytorch”版本不匹配
    我在环境中安装了以下内容:cudatoolkit=11.3pytorch=1.11.0torchvision=0.12.0但是当询问torch/cuda版本时,我得到了这个:$python3-c"importtorch;print(torch.__version__)"1.12.1+cu102这不是我想要的(1.12.1就可以了,但是cu102太旧了)。进一步看,我看到这......
  • 无法在 Jupyter Notebook 中导入 Pytorch 模块
    我在激活虚拟环境时使用conda命令安装了pytorch。但是,当我在JupyterNotebook中导入torch模块时出现一些问题。我在提示符和JupyterNotebook中检查了sys.path。|||嗯..在提示符中,的结果是sys.path,并且导入torch模块时没有错误。['','/home/u......
  • 从 pyTorch 中的检查点文件夹加载模型
    我正在尝试从某个检查点加载模型并将其用于推理。检查点文件夹如下所示。如何从该文件夹将模型加载到torch中。资源我可以找到用于从检查点文件加载,而不是文件夹。importwhisper_timestampedaswhisperfromtransformersimportAutoProcessor,Whisper......
  • 【PyTorch】基于YOLO的多目标检测项目(二)
    【PyTorch】基于YOLO的多目标检测项目(一)【PyTorch】基于YOLO的多目标检测项目(二)YOLO-v3网络由跨距为2的卷积层、跳跃连接层和上采样层组成,没有池化层。网络接收一幅416*416的图像作为输入,并提供三个YOLO输出。目录准备配置文件搭建YOLO模型 搭建PyTorch模块搭......
  • pytorch深度学习笔记
    copy()是浅拷贝,它创建一个新的对象,但是只复制了对象本身及其顶层元素的引用,而不是元素的内容。deepcopy() 是深拷贝,它创建一个全新的对象,递归地复制原始对象及其所有嵌套的对象。这意味着它会复制对象本身以及对象中的所有元素,包括嵌套的列表、字典等。模型通过学习率获得稳定......
  • 六、【Python】基础教程-【Python全掌握】六大基础数据类型:浮点、布尔、列表、元组、
    ......