Pytorch官网:快速入门Pytorch地址:
https://pytorch.org/tutorials/beginner/basics/intro.html
步骤:
1.数据准备——2. 模型选择/开发——3. 模型训练调优——4. 模型评估测试
https://pytorch.org/tutorials/beginner/basics/data_tutorial.html
import torch
from torch import nn
from torch.utils.data import DataLoader # 处理数据API:torch.utils.data.DataLoader and torch.utils.data.Dataset
# Dataset存储示例及其对应的标签
# DataLoader将可迭代对象包装在Dataset周围。
from torchvision import datasets #PyTorch提供特定于域的库,如TorchText、TorchVision和TorchAudio,所有这些都包括数据集。
#每个TorchVision数据集包含两个参数:Transform和Target_Transform,分别用于修改样本和标签。
from torchvision.transforms import ToTensor, Lambda, Compose
import matplotlib.pyplot as plt
# Download training data from open datasets.
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor(),
)
# Download test data from open datasets.
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor(),
)
# 加载数据:https://pytorch.org/tutorials/beginner/basics/data_tutorial.html
# 我们将Dataset作为参数传递给DataLoader。
# 这将在我们的数据集上封装一个可迭代的包,并支持自动批处理、采样、洗牌和多进程数据加载。
# 在这里,我们定义了一个64的批处理大小batch size,即dataloader迭代中的每个元素都将返回一个由64个特性和标签组成的批处理。
batch_size = 64
# Create data loaders.
train_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)
for X, y in test_dataloader:
print("Shape of X [N, C, H, W]: ", X.shape)
print("Shape of y: ", y.shape, y.dtype)
break
# 创建模型
#构建神经网络:https://pytorch.org/tutorials/beginner/basics/buildmodel_tutorial.html
# PyTorch中定义一个神经网络:需要创建了一个继承自nn.Module的类。
# 我们在__init_函数中定义网络层,并指定数据在forward函数中通过网络。
# 为了加速神经网络中的操作,如果有可用的话,我们将其移动到GPU。
# Get cpu or gpu device for training.
device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))
# Define model
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),
nn.ReLU()
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
model = NeuralNetwork().to(device)
print(model)
# 优化模型参数:https://pytorch.org/tutorials/beginner/basics/optimization_tutorial.html
# 要训练模型,我们需要一个损失函数和一个优化器。
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
# 在单个训练循环中,模型对训练数据集进行预测(分批反馈),并反向传播预测误差以调整模型的参数。
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
for batch, (X, y) in enumerate(dataloader):
X, y = X.to(device), y.to(device)
# Compute prediction error
pred = model(X)
loss = loss_fn(pred, y)
# Backpropagation
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(dataloader, model):
size = len(dataloader.dataset)
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), 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 /= size
correct /= size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
# 训练过程经过几次迭代。在每次迭代,模型都会学习参数,以做出更好的预测。
# 在每个epoch打印模型的准确性和损失;我们希望看到准确性随着每个时代的增长而增加,损失减少。
epochs = 5
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model)
print("Done!")
# 保存模型
# 保存模型的常见方法是序列化内部状态字典(包含模型参数)。
torch.save(model.state_dict(), "model.pth")
print("Saved PyTorch Model State to model.pth")
# 加载模型
# 加载模型的过程包括重新创建模型结构并将状态字典加载到其中。
model = NeuralNetwork()
model.load_state_dict(torch.load("model.pth"))
classes = [
"T-shirt/top",
"Trouser",
"Pullover",
"Dress",
"Coat",
"Sandal",
"Shirt",
"Sneaker",
"Bag",
"Ankle boot",
]
model.eval()
x, y = test_data[0][0], test_data[0][1]
with torch.no_grad():
pred = model(x)
predicted, actual = classes[pred[0].argmax(0)], classes[y]
print(f'Predicted: "{predicted}", Actual: "{actual}"')
Tensors是一种与数组和矩阵非常相似的专门数据结构。在PyTorch中,我们使用张量对模型的输入和输出以及模型的参数进行编码。张量与NumPy的ndarray相似,只是张量可以在GPU或其他硬件加速器上运行。
import torch
import numpy as np
# 初始化张量Tensor
#法一: 使用数据,初始化Tensor
data = [[1, 2],[3, 4]]
x_data = torch.tensor(data)
print("数据初始化Tensor",x_data.shape)
#法二: NumPy数组,初始化Tensor
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
#法三:另一个张量,初始化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")
#法四:使用随机值或常量值,初始化Tensor
shape = (2,3,) #shape决定了输出张量的尺寸。
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}")
# 张量属性——描述它们的形状、数据类型和存储它们的设备。
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}")
# 张量操作:https://pytorch.org/docs/stable/torch.html。100多个张量运算,包括算术、线性代数、矩阵操作(转置、索引、切片)、采样等。
# 默认情况下,张量是在CPU上创建的。我们需要使用.to方法显式地将张量移动到GPU上(在检查GPU可用性后)。
if torch.cuda.is_available():
tensor = tensor.to('cuda')
# 标准数字索引和切片:
tensor = torch.ones(4, 4)
print('First row: ',tensor[0])
print('First column: ', tensor[:, 0])
print('Last column:', tensor[..., -1])
tensor[:,1] = 0
print(tensor)
# 连接多个tensor
t1 = torch.cat([tensor, tensor, tensor], dim=1)
print(t1)
# 算数运算
#通过将张量的所有值聚合为一个值,您可以使用item()将其转换为Python数值:
agg = tensor.sum()
agg_item = agg.item()
print(agg_item, type(agg_item))
# 代替操作——加,在之前基础上+5
print(tensor, "\n")
tensor.add_(5)
print(tensor)
# 和Numpy共享底层数据
# 张量到Numpy数组
t = torch.ones(5)
print(f"t: {t}") # t: tensor([1., 1., 1., 1., 1.])
n = t.numpy()
print(f"n: {n}") # n: [1. 1. 1. 1. 1.]
#张量的变化反映在NumPy数组中。
t.add_(1)
print(f"t: {t}")
print(f"n: {n}")
# NumPy数组到张量
n = np.ones(5)
t = torch.from_numpy(n)
# NumPy数组的变化反映在张量中。
np.add(n, 1, out=n)
print(f"t: {t}")
print(f"n: {n}")
我们希望数据集代码与模型训练代码分离,以获得更好的可读性和模块化。pytorch提供了torch.utils.data.DataLoader和torch.utils.data.Dataset,允许使用预加载的数据集以及您自己的数据。Dataset存储样本及其对应的标签,DataLoader将一个可迭代对象包装在数据集周围,以便方便地访问样本。
PyTorch域库提供了许多预加载的数据集(比如fashionmist),它们是torch.utils.data的子类。数据集和实现特定数据的函数。它们可以用来制作模型的原型和基准测试。例如: Image Datasets, Text Datasets, and Audio Datasets
从 TorchVision 加载 Fashion-MNIST 数据集的示例。Fashion-MNIST是Zalando文章图像的数据集,由60,000个培训示例和10,000个测试示例组成。每个示例包括28×28灰度图像和来自10个类别之一的相关标签。
import torch
from torch.utils.data import Dataset
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda
import matplotlib.pyplot as plt
# 加载数据集
# 加载带有以下参数的FashionMNIST数据集:
# root是存储训练/测试数据的路径,
# train指定训练或测试数据集,
# download=True downloads the data from the internet if it’s not available at root.
# transform和target_transform指定功能和标签转换
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()
# 创建自定义数据集
# 必须包含__init__, __len__, and __getitem__三个方法。
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)# 照片名,label:tshirt1.jpg, 0
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): #从给定索引idx的数据集加载并返回示例。
img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
image = read_image(img_path)#基于索引,标识图像在磁盘上的位置,并使用read_image将其转换为张量
label = self.img_labels.iloc[idx, 1]#从self.img_labels中的csv数据中检索相应的标签
if self.transform:
image = self.transform(image)
if self.target_transform:
label = self.target_transform(label)
sample = {"image": image, "label": label}
return sample
# DataLoaders为训练准备数据,并可以根据需要迭代该数据集。
# 在训练模型时,我们通常希望以“小批量”的方式传递样本,在每个epoch重新洗刷数据以减少模型过拟合,并使用Python的多处理来加速数据检索。
# DataLoader是一个迭代器。
from torch.utils.data import DataLoader
#该数据集加载到Dataloader。小批量
train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)
# 通过DataLoader迭代
#下面的每次迭代都返回一批train_features和train_labels ' '(分别包含' ' batch_size=64个特性和标签)。
# shuffle=True,在遍历所有批次之后,数据将被打乱(为了更细粒度地控制数据加载顺序)。
# Display image and label.
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()
label = train_labels[0]
plt.imshow(img, cmap="gray")
plt.show()
print(f"Label: {label}")
我们使用Transformers来对数据进行一些操作,并使其适合训练。所有TorchVision数据集都有两个参数——transform以修改功能和target_transform以修改标签——它们接受包含转换逻辑的可调用参数。torchvision.transforms模块提供了几种常用的开箱即用转换。
例如:FashionMNIST功能采用PIL图像格式,标签为整数。对于训练,我们需要normalized标准化张量功能,以及one-hot编码的张量标签。为了进行这些转换,我们使用ToTensor和Lambda。
其中ToTensor(),将PIL图像或NumPy ndarray转换为FloatTensor。并将图像的像素强度值缩放到[0.,1]范围内。
其中Lambda,定义一个函数来将整数转换为一个one-hot编码张量。它首先创建一个大小为10的零张量(数据集中标签的数量),并调用scatter_,该函数在标签y给定的索引上赋值为1。
import torch
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda
ds = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor(),#normalized标准化,将PIL图像或NumPy ndarray转换为FloatTensor。并将图像的像素强度值缩放到[0.,1]范围内。
target_transform=Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(0, torch.tensor(y), value=1))#定义一个函数来将整数转换为一个one-hot编码
#它首先创建一个大小为10的零张量(数据集中标签的数量),并调用scatter_,该函数在标签y给定的索引上赋值为1。
)
torch.nn命名空间提供了构建自己的神经网络所需的所有构建块。torch.nn.Module是所有神经网络模块的基类。神经网络是由其他模块(层)组成的模块本身。
例子:将建立一个神经网络,对FashionMNIST数据集中的图像进行分类。
import os
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
#希望能够在GPU等硬件加速器上训练我们的模型,让我们检查 torch.cuda 是否可用,否则我们将继续使用 CPU。
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('Using {} device'.format(device))
# Define the Class
#我们通过神经网络子类 nn.Module 来定义神经网络。
# 在__init__中初始化神经网络层。每一个nn.Module子类实现了forward方法中对输入数据的操作。
class NeuralNetwork(nn.Module):#定义神经网络,继承自 nn.Module
def __init__(self):#初始化
super(NeuralNetwork, self).__init__()
self.flatten = nn.Flatten()# 将每个2D 28x28图像转换为一个由784像素值组成的连续数组
self.linear_relu_stack = nn.Sequential(#Sequential是一个有序的模块容器。数据按照定义的相同顺序通过所有模块。您可以使用顺序容器来组合一个像seq_modules这样的快速网络。
nn.Linear(28*28, 512),#使用weights 和 biases.对输入应用线性变换的模块。
nn.ReLU(),#非线性激活在模型的输入和输出之间创建了复杂的映射。它们在线性变换后应用于引入非线性,
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
nn.ReLU()
)
def forward(self, x):#自动调用model.forward()
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
model = NeuralNetwork().to(device)#创建实例自定义的神经网络
print(model)
#调用model,将返回一个10维张量,其中包含每个类的原始预测值。我们通过nn.Softmax得到预测概率。
X = torch.rand(1, 28, 28, device=device)
logits = model(X)
pred_probab = nn.Softmax(dim=1)(logits)#logits被缩放到值[0,1]代表模型对每个类的预测概率。dim参数表示数值之和必须为1的维度。
y_pred = pred_probab.argmax(1)
print(f"Predicted class: {y_pred}")
#在训练过程中优化了相关的权重和偏差,nn.Module模块自动跟踪模型对象中定义的所有字段
# ,并使用模型的parameters()或named_parameters()方法访问所有参数。
print("Model structure: ", model, "\n\n")
for name, param in model.named_parameters():
print(f"Layer: {name} | Size: {param.size()} | Values : {param[:2]} \n")
在训练神经网络时,最常用的算法是反向传播算法。在该算法中,根据损失函数相对于给定参数的梯度来调整参数(模型权值)。为了计算这些梯度,PyTorch内置了一个名为torch.autograd的差异化引擎。它支持自动计算梯度为任何计算图形。
import torch
x = torch.ones(5) # input tensor
y = torch.zeros(3) # expected output
w = torch.randn(5, 3, requires_grad=True)# 默认情况下,所有require_grad =True的张量都在跟踪它们的计算历史,并支持梯度计算。
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)
print('Gradient function for z =',z.grad_fn)#grad_fn存储反向传播函数的引用;
print('Gradient function for loss =', loss.grad_fn)
loss.backward()#计算导数,loss.backward(),从w.grad和b.grad中检索值。
print(w.grad)
print(b.grad)
#先决条件代码
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor()
)
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor()
)
train_dataloader = DataLoader(training_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)
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),
nn.ReLU()
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
model = NeuralNetwork()
# Hyperparameters 超参数是可调参数,让您控制模型优化过程。不同的超参数值可以影响模型训练和收敛速度。
#为训练定义了以下超参数:
# epoch的数量——在数据集上迭代的次数
# Batch Size-模型在每个epoch 中看到的数据样本的数量
# Learning Rate-在每个batch/epoch更新模型参数的次数。较小的值产生缓慢的学习速度,而较大的值可能导致在训练过程中不可预测的行为
learning_rate = 1e-3
batch_size = 64
epochs = 5
# 一旦我们设置了超参数,我们就可以用一个优化循环来训练和优化我们的模型。优化循环的每次迭代称为epoch。
#每个epoch包括两个主要部分:
# 训练循环-迭代训练数据集,并尝试收敛到最优参数。
# 验证/测试循环——遍历测试数据集以检查模型性能是否得到改善。
# 损失函数Loss Function
#当使用一些训练数据时,未经训练的网络很可能给出不正确的答案。
# 损失函数用来度量得到的结果与目标值的不相似程度,它是我们在训练过程中希望最小化的损失函数。
# 为了计算损失,我们使用给定数据样本的输入进行预测,并将其与真实数据标签值进行比较。
# 常见的损失函数:nn.MSELoss (Mean Square Error)用于回归任务;nn.NLLLoss (Negative Log Likelihood)用于分类任务。
# nn.CrossEntropyLoss 结合了 nn.LogSoftmax、nn.NLLLoss.
# Initialize the loss function
loss_fn = nn.CrossEntropyLoss()# 模型的输出logit传递给nn.CrossEntropyLoss,它将标准化logit并计算预测误差。
# 优化器Optimizer
#优化是在每个训练步骤中调整模型参数以减少模型误差的过程。
# 优化算法定义了如何执行这个过程(在本例中,我们使用了随机梯度下降)。
# 所有优化逻辑都封装在优化器对象中。这里,我们使用SGD优化器;此外,PyTorch中还有许多不同的优化器,如ADAM和RMSProp,它们更适合于不同类型的模型和数据。
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)# 初始化需要训练的模型参数来初始化优化器,并通过学习速率超参数。
# 在训练循环中,优化分为三个步骤:
# 调用optimizer.zero_grad()重置模型参数的梯度。渐变默认为累加;为了防止重复计算,我们在每次迭代时显式地将它们置零。
# 通过调用loss.backward()来反向传播预测损失。
# 有了梯度之后,我们调用optimizer.step()通过向后传递收集的梯度来调整参数。
def train_loop(dataloader, model, loss_fn, optimizer):# 优化代码
size = len(dataloader.dataset)
for batch, (X, y) in enumerate(dataloader):
# Compute prediction and loss
pred = model(X)
loss = loss_fn(pred, y)
# Backpropagation
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):# 根据测试数据评估模型性能
size = len(dataloader.dataset)
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= size
correct /= size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(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)
test_loop(test_dataloader, model, loss_fn)
print("Done!")
import torch
import torch.onnx as onnx
import torchvision.models as models
# PyTorch模型将学习到的参数存储在名为state_dict的内部状态字典中。这些可以通过torch.save 保存方法:
model = models.vgg16(pretrained=True)
torch.save(model.state_dict(), 'model_weights.pth')
#要加载模型权重,您需要首先创建同一模型的实例,然后使用load_state_dict()方法加载参数。
model = models.vgg16() # we do not specify pretrained=True, i.e. do not load default weights
model.load_state_dict(torch.load('model_weights.pth'))
model.eval()
#将类的结构与模型一起保存,在这种情况下,我们可以将model(而不是model.state_dict())传递给保存函数:
torch.save(model, 'model.pth')
model = torch.load('model.pth')#加载模型: