系列文章
pytorch学习笔记(1)–QUICKSTART
pytorch学习笔记(2)–Tensor
pytorch学习笔记(3)–数据集与数据导入
pytorch学习笔记(4)–创建模型(Build Model)
pytorch学习笔记(5)–Autograd
文章目录
一、 什么是神经网络
神经网络是按层连接的神经元的集合。 每个神经元都是一个小的计算单元,执行简单的计算来共同解决问题。 神经元分为 3 种类型的层:输入层、隐藏层和输出层。 隐藏层和输出层包含许多神经元。 神经网络模仿人脑处理信息的方式。
1. 神经网络的组成
(1)激活函数
激活函数决定神经元是否应该被激活。 神经网络中发生的计算包括应用激活函数。 如果神经元激活,则意味着输入很重要。 有不同种类的激活函数。 选择使用哪个激活函数取决于您想要的输出。 激活函数的另一个重要作用是为模型添加非线性。
-
Binary
f ( x ) = { 0 , if x < 0 1 , if x ≥ 0 f(x) = \begin{cases} 0, & \text{if $x$ $ <$ 0} \\ 1, & \text{if $x$ $\geq$ 0} \\ \end{cases} f(x)={0,1,if x < 0if x ≥ 0 -
Sigmoid:用于预测输出节点介于 0 和 1 之间的概率
f ( x ) = 1 1 + e − x f(x) = {1 \over {1+e^{-x}}} f(x)=1+e−x1 -
Tanh:用于预测输出节点是否在 1 到 -1 之间,用于分类用例子。
f ( x ) = e x − e − x e x + e − x f(x) =\frac {e^x-e^{-x}} {e^x+e^{-x}} f(x)=ex+e−xex−e−x -
ReLU
f ( x ) = { 0 , if x < 0 x , if x ≥ 0 f(x) = \begin{cases} 0, & \text{if $x$ $ <$ 0} \\ x, & \text{if $x$ $\geq$ 0} \\ \end{cases} f(x)={0,x,if x < 0if x ≥ 0
(2)权重
影响我们网络的输出与预期输出值的接近程度。 当输入进入神经元时,它会乘以权重值,所得输出要么被观察,要么被传递到神经网络中的下一层。 一层中所有神经元的权重被组织成一个张量。
(3) 偏置
弥补了激活函数的输出与其预期输出之间的差异。 低偏差值表明网络对输出形式做出更多假设,而高偏差值对输出形式做出更少假设。
二、创建一个神经网络
%matplotlib inline
import os
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets,transformers
1.选择一个用于训练的硬件设备
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('Using {} device'.format(device))
2.定义类
我们通过子类化 nn.Module 来定义神经网络,并在 __init__ 中初始化神经网络层。 每个nn.Module子类都实现了forward方法中对输入数据的操作。
我们的神经网络由以下部分组成:
- 输入层具有 28x28 或 784 个特征/像素。
- 第一个线性模块采用输入 784 个特征,并将其转换为具有 512 个特征的隐藏层。
- ReLU 激活函数将应用于转换中。
- 第二个线性模块将第一个隐藏层的 512 个特征作为输入,并将其转换到具有 512 个特征的下一个隐藏层。
- ReLU 激活函数将应用于转换中。
- 第三个线性模块将 512 个特征作为来自第二个隐藏层的输入,并将这些特征转换到输出层,其中 10 是类的数量。
- ReLU 激活函数将应用于转换中。
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)
输出:
NeuralNetwork(
(flatten): Flatten()
(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()
)
)
我们把输入数据X作为model的输入,模型开始执行forward,和一些后台操作,不要直接调用 model.forward() !!!
在输入上调用模型会返回一个二维张量,其中 dim=0 对应于每个类的 10 个原始预测值的每个输出,dim=1 对应于每个输出的各个值。我们通过将结果传递给 nn.Softmax 模块的实例来获得预测概率。
X = torch.rand(1, 28, 28, device=device)
logits = model(X)
print(logits.shape)
print(logits)
print(logits[0])
print(logits[0][1])
pred_probab = nn.Softmax(dim=1)(logits)
pred_probab0 = nn.Softmax(dim=0)(logits)
# print(pred_probab)
# print(pred_probab0)
y_pred = pred_probab.argmax(1)
print(f"Predicted class: {y_pred}")
输出:
三、模型Layers
我们将分解 FashionMNIST 模型中的各个层次。为了说明这一点,我们将采用小批量样本minibatch=3 张,大小为 28x28 的图像,看看当我们将其传递到网络时会发生什么。
input_image = torch.rand(3,28,28)
print(input_image.size())
输出:
torch.Size([3, 28, 28])
1.nn.Flatten
我们初始化 nn.Flatten 层,将每个 2D 28x28 图像转换为 784 个像素值的连续数组(维持小批量维度(在 dim=0 时))。
flatten = nn.Flatten()
flat_image = flatten(input_image)
print(flat_image.size())
输出:
torch.Size([3, 784])
2.nn.Linear
线性层是一个使用其存储的权重和偏差对输入应用线性变换的模块。
layer1 = nn.Linear(in_features=28*28, out_features=20)
hidden1 = layer1(flat_image)
print(hidden1.size())
输出:
torch.Size([3, 20])
3.nn.ReLU
非线性激活在模型的输入和输出之间创建复杂的映射。它们在线性变换后应用以引入非线性,帮助神经网络学习各种现象。
在此模型中,我们在线性层之间使用 nn.ReLU,但还有其他激活可以在模型中引入非线性。
print(f"Before ReLU: {hidden1}\n\n")
hidden1 = nn.ReLU()(hidden1)
print(f"After ReLU: {hidden1}")
输出:
Before ReLU: tensor([[ 0.4158, -0.0130, -0.1144, 0.3960, 0.1476, -0.0690, -0.0269, 0.2690,
0.1353, 0.1975, 0.4484, 0.0753, 0.4455, 0.5321, -0.1692, 0.4504,
0.2476, -0.1787, -0.2754, 0.2462],
[ 0.2326, 0.0623, -0.2984, 0.2878, 0.2767, -0.5434, -0.5051, 0.4339,
0.0302, 0.1634, 0.5649, -0.0055, 0.2025, 0.4473, -0.2333, 0.6611,
0.1883, -0.1250, 0.0820, 0.2778],
[ 0.3325, 0.2654, 0.1091, 0.0651, 0.3425, -0.3880, -0.0152, 0.2298,
0.3872, 0.0342, 0.8503, 0.0937, 0.1796, 0.5007, -0.1897, 0.4030,
0.1189, -0.3237, 0.2048, 0.4343]], grad_fn=<AddmmBackward0>)
After ReLU: tensor([[0.4158, 0.0000, 0.0000, 0.3960, 0.1476, 0.0000, 0.0000, 0.2690, 0.1353,
0.1975, 0.4484, 0.0753, 0.4455, 0.5321, 0.0000, 0.4504, 0.2476, 0.0000,
0.0000, 0.2462],
[0.2326, 0.0623, 0.0000, 0.2878, 0.2767, 0.0000, 0.0000, 0.4339, 0.0302,
0.1634, 0.5649, 0.0000, 0.2025, 0.4473, 0.0000, 0.6611, 0.1883, 0.0000,
0.0820, 0.2778],
[0.3325, 0.2654, 0.1091, 0.0651, 0.3425, 0.0000, 0.0000, 0.2298, 0.3872,
0.0342, 0.8503, 0.0937, 0.1796, 0.5007, 0.0000, 0.4030, 0.1189, 0.0000,
0.2048, 0.4343]], grad_fn=<ReluBackward0>)
4.nn.Sequential
nn.Sequential 是模块的有序容器。数据按照定义的相同顺序传递通过所有模块。您可以使用顺序容器来组合一个快速网络,例如 seq_modules。
seq_modules = nn.Sequential(
flatten,
layer1,
nn.ReLU(),
nn.Linear(20, 10)
)
input_image = torch.rand(3,28,28)
logits = seq_modules(input_image)
5.nn.Softmax
神经网络的最后一个线性层返回 logits - [-infty, infty] 中的原始值 - 被传递到 nn.Softmax 模块。Logits 缩放为值 [0, 1],表示模型对每个类别的预测概率。 dim 参数指示值总和必须为 1 的维度。
softmax = nn.Softmax(dim=1)
pred_probab = softmax(logits)
四、模型参数
神经网络内的许多层都是参数化的,如在训练期间优化的相关权重和偏置, nn.Module 的子类会自动跟踪模型对象中定义的所有字段,并使用模型的parameters()或named_parameters()方法访问所有参数。
在此示例中,我们迭代每个参数,并打印其大小及其值的预览。
print(f"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)
)
)
Layer: linear_relu_stack.0.weight | Size: torch.Size([512, 784]) | Values : tensor([[ 0.0273, 0.0296, -0.0084, ..., -0.0142, 0.0093, 0.0135],
[-0.0188, -0.0354, 0.0187, ..., -0.0106, -0.0001, 0.0115]],
device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.0.bias | Size: torch.Size([512]) | Values : tensor([-0.0155, -0.0327], device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.2.weight | Size: torch.Size([512, 512]) | Values : tensor([[ 0.0116, 0.0293, -0.0280, ..., 0.0334, -0.0078, 0.0298],
[ 0.0095, 0.0038, 0.0009, ..., -0.0365, -0.0011, -0.0221]],
device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.2.bias | Size: torch.Size([512]) | Values : tensor([ 0.0148, -0.0256], device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.4.weight | Size: torch.Size([10, 512]) | Values : tensor([[-0.0147, -0.0229, 0.0180, ..., -0.0013, 0.0177, 0.0070],
[-0.0202, -0.0417, -0.0279, ..., -0.0441, 0.0185, -0.0268]],
device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.4.bias | Size: torch.Size([10]) | Values : tensor([ 0.0070, -0.0411], device='cuda:0', grad_fn=<SliceBackward0>)