主要是给自己用来复习的博客,同学们第一次学习的话可以去看官网的tutorials,那里有更详细的解释。
Pytorch官方Transforms的tutorials
Dataset或者Dataloader里的数据,往往不能直接作为训练用的数据,它们还要经过一些处理,这个处理的过程就是Transforms。
所有TrochVision的数据集都有两个参数,transform
和target_transform
FashionMNIST的特征图时PIL Image 标签时integers型的,但对于训练来说,我们需要的特征图是正则化向量,标签是“one-hot encoded tensors"应该是一维编码后的向量。
为了完成这种transform,我们要使用ToTensor和Lambda这两个方法。
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():
该方法可以讲PIL图像或者NumPy格式的数据转换成FloatTensor格式。
Lambda Transforms:
可以让任何人定义一个lambda方法,如代码中的
target_transform = Lambda(lambda y: torch.zeros(
10, dtype=torch.float).scatter_(dim=0, index=torch.tensor(y), value=1))
这里的scatter函数是根据y的值,确定torch.zero(10)这个1*10向量中第y个值设为1,其他为0。
lambda这个表达式平时也不咋用,去搜了一下使用方法,感觉上里面这层lambda定义规则,外面这个lambda相当于就是一个传递吧。
一个神经网络由很多的layers(层)/moduls组成。torch.nn
提供了所有用来搭建神经网络的所有“积木”。一个神经网络模块往往由其他模块(像layers)构成的,这样的好处是它能允许我们搭建很多很复杂的模型。
需要用到的一些库:
import os
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
首先需要确定你的设备能否支持GPU运算,就是安装cuda,安装的方法可以去csdn上搜一下,很容易就能搜到。如果不支持GPU的话也没事,就是放在cpu上运算。
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('Using {} device'.format(device))
定义一个nn.Module的子类作为我们的神经网络,在__init__
中初始化layer的信息。
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
现在,我们实例化一个NeuralNetwork
,再将它一如device
中,打印出它的结构。
注意,在使用过程中不要直接调用
model.forward()
调用模型,让其返回一个是分类的结果。我们通过将数据传送到一个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}")
结果为:
Predicted class: tensor([6], device='cuda:0')
下面逐个介绍一下各个的作用,首先我们创造一个3张28*28的图像。
input_image = torch.rand(3,28,28)
nn.Flatten
nn.Flatten()是将28*28的图像转化成一个784长的像素值。
flatten = nn.Flatten()
flat_image = flatten(input_image)
print(flat_image.size())
结果为:
torch.Size([3, 784])
nn.Linear
linear layer是一个将输入数据进行线性变换后输出的层。
layer1 = nn.Linear(in_features=28*28, out_features=20)
hidden1 = layer1(flat_image)
print(hidden1.size())
结果为:
torch.Size([3, 20])
nn.ReLU
中间层,输出用的,主要作用是让模型能够收敛。(好像)
print(f"Before ReLU: {hidden1}\n\n")
hidden1 = nn.ReLU()(hidden1)
print(f"After ReLU: {hidden1}")
结果为:
Before ReLU: tensor([[-0.5671, 0.4327, 0.1864, -0.3505, -0.1365, -0.2820, -0.0483, -0.4473,
-0.3046, 0.2645, -0.3248, -0.4859, -0.0381, -0.4285, 0.1732, 0.5823,
0.0651, -0.2859, -0.0588, 0.0078],
[-0.7329, 0.2745, 0.2050, -0.2773, -0.4696, -0.1483, -0.2550, -0.3837,
0.0274, 0.4271, -0.4471, -0.1616, 0.1872, -0.4931, 0.1550, 0.4568,
-0.1581, -0.2910, 0.1229, 0.3264],
[-0.3201, 0.4171, -0.0490, -0.0270, -0.4398, 0.1092, -0.0165, -0.3366,
0.1293, 0.6627, 0.1070, -0.2909, 0.2535, -0.2683, 0.0832, 0.2603,
-0.1257, -0.4058, 0.0765, 0.2798]], grad_fn=<AddmmBackward>)
After ReLU: tensor([[0.0000, 0.4327, 0.1864, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
0.2645, 0.0000, 0.0000, 0.0000, 0.0000, 0.1732, 0.5823, 0.0651, 0.0000,
0.0000, 0.0078],
[0.0000, 0.2745, 0.2050, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0274,
0.4271, 0.0000, 0.0000, 0.1872, 0.0000, 0.1550, 0.4568, 0.0000, 0.0000,
0.1229, 0.3264],
[0.0000, 0.4171, 0.0000, 0.0000, 0.0000, 0.1092, 0.0000, 0.0000, 0.1293,
0.6627, 0.1070, 0.0000, 0.2535, 0.0000, 0.0832, 0.2603, 0.0000, 0.0000,
0.0765, 0.2798]], grad_fn=<ReluBackward0>)
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)
nn.Softmax
最后一层线性层返回的值没有上下限,softmax模块能把数值压缩到[0,1]的范围,对应的是每个预测结果的可能性。其中,参数dim
代表着哪一个维度的总和必须是1。
softmax = nn.Softmax(dim=1)
pred_probab = softmax(logits)
另外,在模型中的每一层,都包含着很多参数,这些参数是可以被查看的。
print("Model structure: ", model, "\n\n")
for name, param in model.named_parameters():
print(f"Layer: {name} | Size: {param.size()} | Values : {param[:2]} \n")
Model structure: NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1)
(linear_relu_stack): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True)
(1): ReLU()
(2): Linear(in_features=512, out_features=512, bias=True)
(3): ReLU()
(4): Linear(in_features=512, out_features=10, bias=True)
(5): ReLU()
)
)
Layer: linear_relu_stack.0.weight | Size: torch.Size([512, 784]) | Values : tensor([[ 0.0033, 0.0199, -0.0016, ..., -0.0347, 0.0318, -0.0163],
[ 0.0250, 0.0342, -0.0142, ..., 0.0054, -0.0062, -0.0338]],
device='cuda:0', grad_fn=<SliceBackward>)
Layer: linear_relu_stack.0.bias | Size: torch.Size([512]) | Values : tensor([0.0205, 0.0168], device='cuda:0', grad_fn=<SliceBackward>)
Layer: linear_relu_stack.2.weight | Size: torch.Size([512, 512]) | Values : tensor([[ 0.0089, 0.0016, -0.0141, ..., -0.0031, 0.0040, -0.0112],
[-0.0306, -0.0074, -0.0249, ..., 0.0336, -0.0215, 0.0391]],
device='cuda:0', grad_fn=<SliceBackward>)
Layer: linear_relu_stack.2.bias | Size: torch.Size([512]) | Values : tensor([-0.0376, 0.0233], device='cuda:0', grad_fn=<SliceBackward>)
Layer: linear_relu_stack.4.weight | Size: torch.Size([10, 512]) | Values : tensor([[ 0.0155, -0.0111, 0.0200, ..., -0.0142, -0.0163, -0.0036],
[-0.0163, -0.0383, 0.0412, ..., -0.0419, 0.0184, -0.0137]],
device='cuda:0', grad_fn=<SliceBackward>)
Layer: linear_relu_stack.4.bias | Size: torch.Size([10]) | Values : tensor([0.0078, 0.0371], device='cuda:0', grad_fn=<SliceBackward>)
这里有更多关于torch.nn的API的信息