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
注:后面涉及的链接均不再附上 都可以在官方文档找到
大多数机器学习工作涉及:数据、模型建立、模型参数优化、保存模型
本教程将根据流程的pytorch实现来进行教学
学习者应有一定的Python和深度学习基础
张量是一种特殊的数据结构,类似于NumPy的ndarrays,与NumPy数组通常可以共享相同的底层内存,从而消除了复制数据的需要。
张量提供了 GPU或者其他硬件的加速、从而也对自动微分(automatic differentiation)进行了优化
import torch
import numpy as np
- *Initializing a Tensor
data = [[1,2],[3,4]]
x_data = torch.tensor(data)
print(x_data)
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
print('\n', x_np)
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]])
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}")
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}")
print(f"Datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}")
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之间转移大型张量是很浪费时间和资源的)
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(f'Using device {device}!')
tensor = tensor.to(device)
print(tensor.device)
Using device cuda!
cuda:0
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.]])
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.]])
print(tensor)
y1 = tensor @ tensor.T
y2 = tensor.matmul(tensor.T)
y3 = torch.rand_like(y1)
torch.matmul(tensor, tensor.T, out=y3)
print(y3)
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.]])
agg = tensor.sum()
agg_item = agg.item()
print(agg_item, type(agg_item))
12.0 <class 'float'>
</class>
- 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数组公用一个底层内存
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.]
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.]
为了将数据代码和模型代码分离,获得更好的可读性和模块化pytorch提供了 torch.utils.data.DataLoader
和 torch.utils.data.Dataset
以便于预处理好数据、便于使用时便捷的访问数据
pytorch本身提供了许多音频、图像、文本等等数据集可以直接下载成一个Dataset对象
下面以Fashion-Mnist数据集为例来演示
该数据包含60000个训练样本,10000个测试样本
每个样本由一个 28×28 的灰度图像和一个对应标签组成
下面通过以下参数来加载一个数据集
root
下载路径train
是否为训练集(测试\训练)download
是否下载 (未下载则下载 已下载则直接加载transform
andtarget_transform
对数据、标签进行transform
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()
)
- *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
标签文件格式如下
shirt1.jpg, 0
tshirt2.jpg, 0
…
ankleboot999.jpg, 9
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)
根据文件路径和参数 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所以每次遍历完所有的数据之后就会将顺序重新打乱
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}")
Feature batch shape: torch.Size([64, 1, 28, 28])
Labels batch shape: torch.Size([64])
img shape: torch.Size([28, 28])
Label: 8
你使用的或者下载来的数据样本和其标签不一定满足你训练模型所需要的格式
我们可以使用transforms来对他们进行一些变化
所有的Torchvision的dataset都提供了 transform
和 target_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(),
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))
未完待续
Original: https://blog.csdn.net/qq_53580131/article/details/126009967
Author: 说梦人丶
Title: Pytorch 官方文档教程整理 (一)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/627359/
转载文章受原作者版权保护。转载请注明原作者出处!