Pytorch 官方文档教程整理 (一)

Pytorch 官方文档教程整理 (一)

对应官方的 Instuction to Pytorch 前半部分

运行的Python版本:3.9.12

所使用的库:

numpy                     1.23.0  
pandas                    1.4.3  
pip                       21.2.4  
tensorboard               2.9.1  
torch                     1.12.0+cu116     
torchaudio                0.12.0+cu116   
torchvision               0.13.0+cu116  

原文地址链接

注:后面涉及的链接均不再附上 都可以在官方文档找到

Chapter 1: Tensor

大多数机器学习工作涉及:数据、模型建立、模型参数优化、保存模型

本教程将根据流程的pytorch实现来进行教学

学习者应有一定的Python和深度学习基础

  1. 数据集:FashionMNIST
  2. 分类:T-shirt, Trouser, Pullover, Dress, Coat, Sandal, Shirt, Sneaker, Bag, Ankle boot
tensor

张量是一种特殊的数据结构,类似于NumPy的ndarrays,与NumPy数组通常可以共享相同的底层内存,从而消除了复制数据的需要。

张量提供了GPU或者其他硬件的加速、从而也对自动微分(automatic differentiation)进行了优化

import torch
import numpy as np
  • Initializing a Tensor
# 1.from list
data = [[1,2],[3,4]]
x_data = torch.tensor(data)
print(x_data)

# 2.from numpy array
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
print('\n', x_np)

# 3.from other tensor  即由其他的tensor提供shape
x_ones = torch.ones_like(x_data)
x_rand = torch.rand_like(x_data, dtype=torch.float)  # 指定数据类型
print(f"\nOnes Tensor: \n {x_ones} \n")
print(f"Random Tensor: \n {x_rand} \n")
tensor([[1, 2],
        [3, 4]])

 tensor([[1, 2],
        [3, 4]])

Ones Tensor: 
 tensor([[1, 1],
        [1, 1]]) 

Random Tensor: 
 tensor([[0.7730, 0.6609],
        [0.8345, 0.5773]]) 
# 4.with random or constant values 和第三种类似
shape = (2,3,)  # shape表示张量的维度 此处2为第零维的长度 3为第一维的长度 即高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}")
Random Tensor: 
 tensor([[0.9749, 0.8934, 0.1137],
        [0.1913, 0.0333, 0.6570]]) 

Ones Tensor: 
 tensor([[1., 1., 1.],
        [1., 1., 1.]]) 

Zeros Tensor: 
 tensor([[0., 0., 0.],
        [0., 0., 0.]])
  • Attributes of a Tensor

张量的性质包括:shape(形状), datatype(数据类型), device(运行设备cpu,gpu)

tensor = torch.rand(3,4)  # 初始化方式与第四种类似

print(f"Shape of tensor: {tensor.shape}")              # (3, 4)
print(f"Datatype of tensor: {tensor.dtype}")           # torch.float32
print(f"Device tensor is stored on: {tensor.device}")  # cpu
Shape of tensor: torch.Size([3, 4])
Datatype of tensor: torch.float32
Device tensor is stored on: cpu
  • Operations on Tensors

对于张量的操作有一百多种,比如:算术、线性代数、矩阵操作(转置、索引、切片)、采样等等(更多介绍见官网)

每一种操作都可以在GPU完成

默认张量的操作在CPU完成,我们需要用.to方法将张量转移到GPU(但是需要注意的是在不同的device之间转移大型张量是很浪费时间和资源的)

# We move our tensor to the GPU if available
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(f'Using device {device}!')

tensor = tensor.to(device)  # tensor 为先前创建的张量
print(tensor.device)
Using device cuda!
cuda:0
  1. 首先做一些与列表类似操作
# shape = (2,3,)  # shape表示张量的维度 此处2为第零维的长度 3为第一维的长度 即高2宽3
# rand_tensor = torch.rand(shape)
tensor = torch.ones(4, 4)  # 初始化方式与上面的方式相同
print(tensor)

# 切片
print(f"First row: {tensor[0]}")  # 第一行
print(f"First column: {tensor[:, 0]}")  # 第一列
print(f"Last column: {tensor[..., -1]}")  # 最后一列
tensor[:,1] = 0  # 第二列清零
print(tensor)
tensor([[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]])
First row: tensor([1., 1., 1., 1.])
First column: tensor([1., 1., 1., 1.])
Last column: tensor([1., 1., 1., 1.])
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])
  1. 张量链接操作 (torch.cat方法将指定的张量沿着指定的维度连接起来)
t1 = torch.cat([tensor, tensor, tensor], dim=1)  # 沿着row的方向链接
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.]])
  1. 算术操作 (@ and matmul 矩阵乘法,* and mul 对应元素相乘)
print(tensor)
# 矩阵的乘法  y1 y2 y3结果一样
y1 = tensor @ tensor.T
y2 = tensor.matmul(tensor.T)

# 另一种输出形式
y3 = torch.rand_like(y1)
torch.matmul(tensor, tensor.T, out=y3)
print(y3)

# 对应元素相乘  z1 z2 z3结果一样
z1 = tensor * tensor
z2 = tensor.mul(tensor)

z3 = torch.rand_like(tensor)
torch.mul(tensor, tensor, out=z3)
print(z1)
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])
tensor([[3., 3., 3., 3.],
        [3., 3., 3., 3.],
        [3., 3., 3., 3.],
        [3., 3., 3., 3.]])
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])
  1. 有单个元素的张量 (.item()方法可以将它转换成一个scalar)
    计算正确率的时候会用到
agg = tensor.sum()  # 全部维度求和
agg_item = agg.item()  # 转化成一个常量
print(agg_item, type(agg_item))
12.0 <class 'float'>
  1. In-place operations(忘记怎么翻译了)

    在方法后面加上一个_后缀就可以改变张量自身的值

  • In-place operations 节约了内存但是会导致导数丢失没办法进行方向传播之类的操作 要注意使用
print(f"{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.]])
  • Bridge with NumPy

在CPU上的张量可以和numpy数组公用一个底层内存

# Tensor to numpy array
# 使用.numpy() 方法
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([1., 1., 1., 1., 1.])
n: [1. 1. 1. 1. 1.]
t: tensor([2., 2., 2., 2., 2.])
n: [2. 2. 2. 2. 2.]
# numpy array to tensor
# 使用.from_array方法  同上面的初始化第二种方法
n = np.ones(5)
t = torch.from_numpy(n)

# 两者都改变
np.add(n, 1, out=n)
print(f"t: {t}")
print(f"n: {n}")
t: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
n: [2. 2. 2. 2. 2.]

Chapter 2: DATASETS & DATALOADERS

为了将数据代码和模型代码分离,获得更好的可读性和模块化pytorch提供了torch.utils.data.DataLoadertorch.utils.data.Dataset以便于预处理好数据、便于使用时便捷的访问数据

  • Dataset 将所有的数据和其对应的标签都整合在一起
  • Dataloader进一步将Dataset中的数据整理打包为一个一个batch的形式 可以迭代的使用、访问

pytorch本身提供了许多音频、图像、文本等等数据集可以直接下载成一个Dataset对象

下面以Fashion-Mnist数据集为例来演示
该数据包含60000个训练样本,10000个测试样本
每个样本由一个 28x28 的灰度图像和一个对应标签组成

下面通过以下参数来加载一个数据集

  • root 下载路径
  • train 是否为训练集(测试\训练)
  • download 是否下载 (未下载则下载 已下载则直接加载
  • transform and target_transform 对数据、标签进行transform
import torch
from torch.utils.data import Dataset
from torchvision import datasets  # 用于下载官方的数据集
from torchvision.transforms import ToTensor  # transform
import matplotlib.pyplot as plt  #  画图


training_data = datasets.FashionMNIST(
    root="data",  # 在当前文件夹新建一个data文件夹存储
    train=True,
    download=True,
    transform=ToTensor()
)  # 加载训练集

test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor()
)  # 加载测试集
  • Iterating and Visualizing the Dataset

我们可以对dataset进行索引
然后通过matplolib进行样本可视化

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()
  • Creating a Custom Dataset for your files

创建自己的数据集

建立自己的数据集需要实现 __init__ __len__ __getitem__方法
(假设)FashionMNIST的图像样例存储在img_dir 他们对应的标签存储在annotations_file

下面来看看这些方法内部的实现过程

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

__ init __

标签文件格式如下

shirt1.jpg, 0
tshirt2.jpg, 0

ankleboot999.jpg, 9

# 通常包含图像文件、标签文件、transforms等等
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

__ len __

# 返回有多少数据样本
def __len__(self):
    return len(self.img_labels)

__ getitem __

根据文件路径和参数idx返回图片样本和标签

如果有transform那么进行transform后返回

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

完整实现如下

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
  • Preparing your data for training with DataLoaders

Dataset一次只返回一个样本

我们在训练时一次update往往需要一个minibatch个样本 将全部数据都update一遍就称为一个epoch

为了避免过拟合每个epoch都通过dataloader进行reshuffle

同时也采用Python的多线程来加速数据检索

from torch.utils.data import DataLoader

train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)
  • Iterate through the DataLoader

dataloader每次迭代都会返回minibatch个样本特征和其对应的label
因为shuffle=true所以每次遍历完所有的数据之后就会将顺序重新打乱

# 因为可迭代所以使用iter和next方法进行一次迭代 并且移动到下一个迭代的目标
train_features, train_labels = next(iter(train_dataloader))  
print(f"Feature batch shape: {train_features.size()}")
print(f"Labels batch shape: {train_labels.size()}")

img = train_features[0].squeeze()
print(f"img shape: {img.size()}")
label = train_labels[0]

plt.imshow(img, cmap="gray")
plt.show()
print(f"Label: {label}")  # 数字label对应的物品种类见上面的label_map
Feature batch shape: torch.Size([64, 1, 28, 28])
Labels batch shape: torch.Size([64])
img shape: torch.Size([28, 28])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BGiNSVuX-1658890106796)(output_51_1.png)]

Label: 8

Chapter 3:Transforms

你使用的或者下载来的数据样本和其标签不一定满足你训练模型所需要的格式
我们可以使用transforms来对他们进行一些变化

所有的Torchvision的dataset都提供了transformtarget_transforms分别对特征和标签进行变化
torchvision.transforms提供了一些变化方法

FashionMNIST 的特征是PIL image 标签是整数格式
为了适应训练模型,使用ToTensor方法和Lamda方法进行转化

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

ds = datasets.FashionMNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor(),
    # 沿着维度0将索引为y的位置置1  (沿着维度0是因为初始化时默认为列向量)
    target_transform=Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(0, torch.tensor(y), value=1))
)
  • ToTensor()

ToTensor 将PIL image图像或者numpy数组转化成FloatTensor型数据
并且将图片每个像素限制在[0,1]范围内

  • Lamda Transforms

用户自定义一个转换方式
上文中将整数转换成了独热码张量

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

未完待续

  • 7
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值