pytorch学习(6)——神经网络基本骨架nn.module的使用

0 目录-神经网络框架

torch.nn(Neural network, 神经网络)内包含Pytorch神经网络框架

  • Containers: 容器
  • Convolution Layers: 卷积层
  • Pooling Layers: 池化层
  • Padding Layers: 填充层
  • Non-linear Activations (weighted sum, nonlinearity):非线性激活
  • Non-linear Activations (other):非线性激活
  • Normalization Layers:归一化层
  • Recurrent Layers:递归层
  • Transformer Layers:变换层
  • Linear Layers:全连接层
  • Dropout Layers:舍弃层
  • Distance Functions:距离函数
  • Loss Functions:损失函数

1 容器 Containers

1.1 Module类的使用

Module是所有神经网络模块的基类。
学习链接:

https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module

在这里插入图片描述

Class torch.nn.Module(*args, **kwargs)

使用案例:

import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 5)
        self.conv2 = nn.Conv2d(20, 20, 5)

    def forward(self, inputX):
        x = F.relu(self.conv1(inputX))
        return F.relu(self.conv2(x))
  • forward函数内relu()为激活函数,conv()为卷积函数。
  • 输入inputX-> 卷积-> 非线性处理(relu)-> 卷积 ->非线性处理(relu)。

完整构建的python代码:

from torch import nn
import torch

class MyNN(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, inputX):
        outputX = inputX + 1
        return outputX

mynn = MyNN()
x = torch.tensor(1.0)
output = mynn(x)
print(x)
print(output)

输出结果:

tensor(1.)
tensor(2.)

1.2 顺序容器 Sequential

能够按照容器内的函数顺序执行,相当于在forward函数中级联了多个函数。
按照我的理解,类似于图像处理transforms库内的Compose函数,对数据进行流水线处理。

例子:

# 使用Sequential的例子
model = nn.Sequential(
          nn.Conv2d(1,20,5),
          nn.ReLU(),
          nn.Conv2d(20,64,5),
          nn.ReLU()
        )

# 使用OrderedDict的Sequential的例子
model = nn.Sequential(OrderedDict([
          ('conv1', nn.Conv2d(1,20,5)),
          ('relu1', nn.ReLU()),
          ('conv2', nn.Conv2d(20,64,5)),
          ('relu2', nn.ReLU())
        ]))

1.2.1 构建顺序容器

数据集CIFAR10的模型结构:
在这里插入图片描述
数据操作步骤:

操作顺序输入数据长度输出数据长度
卷积(5*5)3x32x3232x32x32
最大池化(2*2)32x32x3232x16x16
卷积(5*5)32x16x1632x16x16
最大池化(2*2)32x16x1632x8x8
卷积(5*5)32x8x864x8x8
最大池化(2*2)64x8x864x4x4
数据展平64x4x41024
全连接层/线性层102464
全连接层/线性层6410

以下采用普通方法和Sequential方法对构建数据网络,能够发现第二种方法的代码量较小。python代码如下:

import torchvision
import torch
from torch import nn
from torch.nn import Linear, Conv2d, MaxPool2d, Flatten, Sequential
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10(root="G:\\Anaconda\\pycharm_pytorch\\learning_project\\dataset_CIFAR10",train=False,transform=torchvision.transforms.ToTensor(),download=False)
dataloader = DataLoader(dataset, batch_size=64)

class MYNN(nn.Module):
    def __init__(self):
        super(MYNN, self).__init__()
        self.conv1 = Conv2d(3, 32, 5, padding=2, stride=1)
        self.maxpool1 = MaxPool2d(2)
        self.conv2 = Conv2d(32, 32, 5, padding=2, stride=1)
        self.maxpool2 = MaxPool2d(2)
        self.conv3 = Conv2d(32, 64, 5, padding=2, stride=1)
        self.maxpool3 = MaxPool2d(2)
        self.flatten1 = Flatten()
        self.linear1 = Linear(1024, 64)
        self.linear2 = Linear(64, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = self.maxpool1(x)
        x = self.conv2(x)
        x = self.maxpool2(x)
        x = self.conv3(x)
        x = self.maxpool3(x)
        x = self.flatten1(x)
        x = self.linear1(x)
        x = self.linear2(x)
        return x

# 使用Sequential函数
class MYNN2(nn.Module):
    def __init__(self):
        super(MYNN2, self).__init__()
        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2, stride=1),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2, stride=1),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2, stride=1),
            MaxPool2d(2),
            Flatten(),
            Linear(1024,64),
            Linear(64,10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x


mynn = MYNN()
print(mynn)     # 查看网络结构
# 测试
input = torch.ones([64, 3, 32, 32])
print(input.shape)
output = mynn(input)
print(output.shape)
print("\r\n")

# 使用Sequential函数
mynn2 = MYNN2()
print(mynn2)     # 查看网络结构
# 测试
input2 = torch.ones([64, 3, 32, 32])
print(input2.shape)
output2 = mynn2(input2)
print(output2.shape)

运行输出结果:

MYNN(
  (conv1): Conv2d(3, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
  (maxpool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (conv2): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
  (maxpool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (conv3): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
  (maxpool3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (flatten1): Flatten(start_dim=1, end_dim=-1)
  (linear1): Linear(in_features=1024, out_features=64, bias=True)
  (linear2): Linear(in_features=64, out_features=10, bias=True)
)
torch.Size([64, 3, 32, 32])
torch.Size([64, 10])

MYNN2(
  (model1): Sequential(
    (0): Conv2d(3, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    (1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (2): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    (3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (4): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    (5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (6): Flatten(start_dim=1, end_dim=-1)
    (7): Linear(in_features=1024, out_features=64, bias=True)
    (8): Linear(in_features=64, out_features=10, bias=True)
  )
)
torch.Size([64, 3, 32, 32])
torch.Size([64, 10])

1.2.2 Tensorboard显示顺序容器

python代码如下:

writer = SummaryWriter("G:/Anaconda/pycharm_pytorch/learning_project/logs_container")
writer.add_graph(mynn2, input2)
writer.close()

代码运行完成后,进入terminal终端,输入:

tensorboard --logdir=logs_container

点击网页链接,能够看到以下内容:
在这里插入图片描述
能够清晰看到各个层之间的关系和数据维度。

2 卷积层 Convolution Layers

2.1 二维卷积计算conv2d()

CLASS torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode=‘zeros’, device=None, dtype=None)

  • in_channels (int) – 输入图像中的通道数。
  • out_channels (int) – 输出图像中的通道数。
  • kernel_size (int or tuple) – 卷积核的大小。
  • stride (int or tuple, optional) – 卷积步长(默认为1)。
  • padding (int, tuple or str, optional) – 为输入框的四面添加内边距(默认为0)。
  • padding_mode (str, optional) – ‘zeros’、‘reflect’、‘replicate’或’circular’(默认为’zeros’)。
  • dilation (int or tuple, optional) – 内核元素之间的间距(默认为1)。
  • groups (int, optional) – 从输入通道到输出通道的阻塞连接数(默认为1)。
  • bias (bool, optional) – 如果为True,则在输出中添加一个可学习的偏差(默认为True)。

输出图像大小计算方法:
在这里插入图片描述
二维卷积 conv2d()
输入和输出的矩阵类型都需要(N, C_{in}, H_{in}, W_{in})

在这里插入图片描述

输入图像1024x800,卷积核3x3,每次9个元素相乘后相加,不断向右移动并计算,移动到最右侧之后;然后向下移动并计算,移动到最下侧之后,完成卷积计算。

import torch
import torch.nn.functional as F

input = torch.tensor([[1, 2, 0, 3, 1],
                      [0, 1, 2, 3, 1],
                      [1, 2, 1, 0, 0],
                      [5, 2, 3, 1, 1],
                      [2, 1, 0, 1, 1]])
kernel = torch.tensor([[1, 2, 1],
                       [0, 1, 0],
                       [2, 1, 0]])
input = torch.reshape(input, (1, 1, 5, 5))
kernel = torch.reshape(kernel, (1, 1, 3, 3))

print("input:")
print(input)
print("kernel:")
print(kernel)

output = F.conv2d(input, kernel, stride=1)
print("output:")
print(output)

输出结果:

input:
tensor([[[[1, 2, 0, 3, 1],
          [0, 1, 2, 3, 1],
          [1, 2, 1, 0, 0],
          [5, 2, 3, 1, 1],
          [2, 1, 0, 1, 1]]]])
kernel:
tensor([[[[1, 2, 1],
          [0, 1, 0],
          [2, 1, 0]]]])
output:
tensor([[[[10, 12, 12],
          [18, 16, 16],
          [13,  9,  3]]]])

如果将步进stride修改为2。

output2 = F.conv2d(input, kernel, stride=2)
print("output2:")
print(output2)

输出结果为:

output2:
tensor([[[[10, 12],
          [13,  3]]]])

padding填充,将原图像的四周填充一圈0,这样的话,卷积计算的结果维度就会更大。
在这里插入图片描述

output3 = F.conv2d(input, kernel, stride=1, padding=1)
print("output3:")
print(output3)

输出的结果:

tensor([[[[ 1,  3,  4, 10,  8],
          [ 5, 10, 12, 12,  6],
          [ 7, 18, 16, 16,  8],
          [11, 13,  9,  3,  4],
          [14, 13,  9,  7,  4]]]])

2.2 图像卷积操作

学习链接:

https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html#torch.nn.Conv2d

CLASS torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode=‘zeros’, device=None, dtype=None)

  • in_channels (int) – 输入图像通道数
  • out_channels (int) – 输出图像通道数
  • kernel_size (int or tuple) – 卷积核大小
  • stride (int or tuple, optional) – 卷积步长(默认为1)。
  • padding (int, tuple or str, optional) – 添加到输入图像四周的边长(默认为1)
  • padding_mode (str, optional) – 边长类型:‘zeros’, ‘reflect’, ‘replicate’ or ‘circular’。默认为: ‘zeros’
  • dilation (int or tuple, optional) – 卷积核之间的间距(默认为1),空洞卷积。
    *groups (int, optional) – 从输入通道到输出通道的阻塞连接数(默认为1)。
  • bias (bool, optional) – 如果为 True, 在输出中添加一个可学习的偏差(默认为True)。

如果in_channel=1,out_channel=2,则会使用两个卷积核对输入图像进行计算,输出两个通道的数据:
在这里插入图片描述

卷积公式:
在这里插入图片描述
二维卷积动图:

https://github.com/vdumoulin/conv_arithmetic/blob/master/README.md

在这里插入图片描述

当dilation=2时,卷积的方法:
在这里插入图片描述

图像二维卷积python代码:

import torch
import torchvision
from torch import nn
from torch.nn import Conv2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10(root="G:\\Anaconda\\pycharm_pytorch\\learning_project\\dataset_CIFAR10",
                                       train=False,
                                       transform=torchvision.transforms.ToTensor(),
                                       download=False)
dataloader = DataLoader(dataset, batch_size=64)

class MyNN(nn.Module):
    def __init__(self):
        super(MyNN, self).__init__()
        self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)

    def forward(self, x):
        x = self.conv1(x)
        return x

myNN = MyNN()
print(myNN)

writer = SummaryWriter("G:/Anaconda/pycharm_pytorch/learning_project/logs")
step = 0
for data in dataloader:
    imgs, targets = data
    output = myNN(imgs)
    print(imgs.shape)       # torch.Size([64, 3, 32, 32])
    print(output.shape)     # torch.Size([64, 6, 30, 30])
    writer.add_images("input", imgs, step)
    # torch.Size([64, 6, 30, 30]) -> # torch.Size([xxx, 3, 30, 30])
    output = torch.reshape(output, (-1, 3, 30, 30))
    writer.add_images("output", output, step)

    step = step + 1

writer.close()

代码运行后,终端输入tensorboard --logdir=logs,打开tensorboard。
能够看到output图片为卷积后的部分通道。
在这里插入图片描述

3 池化层 Pooling Layers

学习链接:

https://pytorch.org/docs/stable/nn.html#pooling-layers

池化层的作用:(1)下采样(downsampling),降低数据维度,减少网络前向运算消耗的内存大小;(2)保持输入特征,扩大网络模型的感知野;(3)防止过拟合或欠拟合。

3.1 最大池化MaxPool2d()

在由几个输入平面组成的输入信号上应用2D最大池化。

CLASS torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)

  • kernel_size (Union[int, Tuple[int, int]]) – 池化窗口的最大尺寸。
  • stride (Union[int, Tuple[int, int]]) – 池化窗口的步长(默认值为kernel_size)。
  • padding (Union[int, Tuple[int, int]]) – 两边隐式地添加负无穷内边距。
  • dilation (Union[int, Tuple[int, int]]) – 一个参数,控制窗口中元素的步长。
  • return_indices (bool) – 如果为True,将返回最大索引以及输出。在torch.nn.MaxUnpool2d之后有用。
  • ceil_mode (bool) – 当为True时,将使用ceil而不是floor来计算输出形状。

ceil表示ceiling模式(天花板),floor表示floor模式(地板)。如果为Ceil表示取整数时,向上取整;floor表示取整数时,向下取整。

在这里插入图片描述

在二维卷积中表示,当出现以下的情况,ceil_mode为True时,需要保留剩下的6个数的卷积;如果ceil_mode为False时,不需要保留此次卷积。
在这里插入图片描述
池化操作与卷积操作不同,池化的补偿就是池化核的大小,池化操作得到的输出结果如下图右侧所示,ceil_mode的True和False得到的结果大小不同。
在这里插入图片描述

最大池化python代码:

import torch
from torch import nn
from torch.nn import MaxPool2d

input = torch.tensor([[1, 2, 0, 3, 1],
                     [0, 1, 2, 3, 1],
                     [1, 2, 1, 0, 0],
                     [5, 2, 3, 1, 1],
                     [2, 1, 0, 1, 1]], dtype=torch.float32)

input = torch.reshape(input, (-1, 1, 5, 5))
print(input)

class MYNN(nn.Module):
    def __init__(self):
        super(MYNN,self).__init__()
        self.maxpool1 = MaxPool2d(kernel_size=3,ceil_mode=True)
        self.maxpool2 = MaxPool2d(kernel_size=3, ceil_mode=False)

    def forward(self, input):
        output1 = self.maxpool1(input)
        output2 = self.maxpool2(input)
        return output1, output2

mynn = MYNN()
output1, output2 = mynn(input)
print(output1)
print(output2)

运行脚本得到输出结果:

tensor([[[[1., 2., 0., 3., 1.],
          [0., 1., 2., 3., 1.],
          [1., 2., 1., 0., 0.],
          [5., 2., 3., 1., 1.],
          [2., 1., 0., 1., 1.]]]])
tensor([[[[2., 3.],
          [5., 1.]]]])
tensor([[[[2.]]]])

3.2 图像池化操作

python代码:

import torch
import torchvision
from torch import nn
from torch.nn import MaxPool2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10(root="G:\\Anaconda\\pycharm_pytorch\\learning_project\\dataset_CIFAR10",
                                       train=False,
                                       transform=torchvision.transforms.ToTensor(),
                                       download=False)
dataloader = DataLoader(dataset, batch_size=64)


class MYNN(nn.Module):
    def __init__(self):
        super(MYNN,self).__init__()
        self.maxpool = MaxPool2d(kernel_size=3, ceil_mode=False)

    def forward(self, input):
        output = self.maxpool(input)
        return output


mynn = MYNN()
writer = SummaryWriter("G:/Anaconda/pycharm_pytorch/learning_project/logs_maxpool")
step = 0
for data in dataloader:
    imgs, targets = data
    writer.add_images("input", imgs, step)
    # torch.Size([64, 6, 30, 30]) -> # torch.Size([xxx, 3, 30, 30])
    output = mynn(imgs)
    writer.add_images("output", output, step)
    step = step + 1

writer.close()

代码运行后,终端输入tensorboard --logdir=logs_maxpool,打开tensorboard。能够看到output图片为池化操作后的图像清晰度降低。
在这里插入图片描述

4 填充层 Padding Layers

学习链接:

https://pytorch.org/docs/stable/nn.html#padding-layers

主要使用的函数:

函数名说明
nn.ZeroPad2d用零填充输入张量(Tensor)边界。
nn.ConstantPad2d用常数填充输入张量(Tensor)边界。

在其他的层内也能实现,因此可以不用这一层。

5 非线性激活 Non-linear Activations (weighted sum, nonlinearity)

给神经网络引入非线性特征。

函数名说明
nn.ReLU按元素应用修正线性单位函数。
nn.Sigmoid应用针对元素的函数。

5.1 激活函数

5.1.1 ReLU

按元素应用修正线性单位函数:
在这里插入图片描述

CLASS torch.nn.ReLU(inplace=False)

参数:

  • inplace (bool) – 是否可以选择现场进行操作(默认值False)。
    Shape:
  • Input: (∗), ∗指的是任意数量的维度。
  • Output: (∗), 与输入相同的shape。
    在这里插入图片描述

5.1.2 Sigmod

应用元素函数:
在这里插入图片描述

CLASS torch.nn.Sigmoid(*args, **kwargs)

Shape:

  • Input: (∗),∗ 是指任意数量的维度。
  • Output: (∗),与输入相同的shape。

在这里插入图片描述

5.2 数字代入激活函数测试

python代码:

import torch
from torch import nn
from torch.nn import ReLU
from torch.nn import Sigmoid

input = torch.tensor([[1, -0.5],
                      [-1, 3]])

output = torch.reshape(input, (-1, 1, 2, 2))
print(output)

class MYNN(nn.Module):
    def __init__(self):
        super(MYNN, self).__init__()
        self.relu1 = ReLU()
        self.sigmod1 = Sigmoid()

    def forward(self, input):
        output = self.relu1(input)
        output2 = self.sigmod1(input)
        return output, output2

mynn = MYNN()
output, output2 = mynn(input)
print(output)
print(output2)

运行结果:

tensor([[[[ 1.0000, -0.5000],
          [-1.0000,  3.0000]]]])
tensor([[1., 0.],
        [0., 3.]])
tensor([[0.7311, 0.3775],
        [0.2689, 0.9526]])

5.3 图像非线性激活操作

图像非线性激活操作的python代码:

# 使用数字显示relu和sigmod非线性激活函数的作用
import torch
import torchvision
from torch import nn
from torch.nn import ReLU
from torch.nn import Sigmoid
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10(root="G:\\Anaconda\\pycharm_pytorch\\learning_project\\dataset_CIFAR10",
                                       train=False,
                                       transform=torchvision.transforms.ToTensor(),
                                       download=False)
dataloader = DataLoader(dataset, batch_size=64)

class MYNN(nn.Module):
    def __init__(self):
        super(MYNN, self).__init__()
        self.relu1 = ReLU()
        self.sigmod1 = Sigmoid()

    def forward(self, input):
        output_relu = self.relu1(input)
        output_sigmod = self.sigmod1(input)
        return output_relu, output_sigmod

mynn = MYNN()
writer = SummaryWriter("G:/Anaconda/pycharm_pytorch/learning_project/logs_relu")
step = 0
for data in dataloader:
    imgs, targets = data
    writer.add_images("input", imgs, step)
    output_relu, output_sigmod = mynn(imgs)
    writer.add_images("output_relu", output_relu, step)
    writer.add_images("output_sigmod", output_sigmod, step)
    step += 1
    print(step)

writer.close()
print("Done")

代码运行后,终端输入tensorboard --logdir=logs_relu,打开tensorboard。能够看到output图片为池化操作后的图像清晰度降低。

因为relu操作为将赋值修正为0,但图像都是0-255的值,所以input和output_relu没有区别;但是sigmod操作是将图像0-255的值按一定的指数比例修正,因此会产生灰度变化。
在这里插入图片描述

6 归一化层 Normalization Layers

学习链接:

https://pytorch.org/docs/stable/nn.html#normalization-layers

归一化,也称正则化,这一步能够加快神经网络学习速度。

7 全连接层 Linear Layers

全连接层,又称线性层。
一个点的计算公式为:
g 1 ( x ) = ( k 1 ∗ x 1 + b 1 ) + ( k 2 ∗ x 2 + b 2 ) + . . . + ( k n ∗ x n + b n ) g_1(x)=(k_1*x_1+b_1)+(k_2*x_2+b_2)+...+(k_n*x_n+b_n) g1(x)=(k1x1+b1)+(k2x2+b2)+...+(knxn+bn)

在这里插入图片描述

7.1 Linear()函数

CLASS torch.nn.Linear(in_features, out_features, bias=True, device=None, dtype=None)

  • in_features (int) – 每个输入样本的大小
  • out_features (int) – 每个输出样本的大小
  • bias (bool) – 如果设置为False,该层将不会学习加性偏差(默认值:True)。

在这里插入图片描述

import torchvision
import torch
from torch import nn
from torch.nn import Linear
from torch.utils.data import DataLoader

dataset = torchvision.datasets.CIFAR10(root="G:\\Anaconda\\pycharm_pytorch\\learning_project\\dataset_CIFAR10",
                                       train=False,
                                       transform=torchvision.transforms.ToTensor(),
                                       download=False)

dataloader = DataLoader(dataset, batch_size=64)

class MYNN(nn.Module):
    def __init__(self):
        super(MYNN, self).__init__()
        self.linear1 = Linear(196608, 10)

    def forward(self, input):
        output = self.linear1(input)
        return output

mynn = MYNN()

for data in dataloader:
    imgs, targets = data
    print("imgs.shape:")
    print(imgs.shape)
    output1 = torch.reshape(imgs, (1, 1, 1, -1))     # 数据变形
    print("output1.shape:")
    print(output1.shape)

    output2 = mynn(output1)              # 线性化
    print("output2.shape:")
    print(output2.shape)

    output3 = torch.flatten(imgs)       # 数据展平
    print("output3.shape:")
    print(output3.shape)

    output4 = mynn(output3)             # 线性化
    print("output4.shape:")
    print(output4.shape)

代码运行结果(部分):

imgs.shape:
torch.Size([64, 3, 32, 32])
output1.shape:
torch.Size([1, 1, 1, 196608])
output2.shape:
torch.Size([1, 1, 1, 10])
output3.shape:
torch.Size([196608])
output4.shape:
torch.Size([10])

8 损失函数 Loss Functions

损失函数(Loss Function)是在机器学习和深度学习中使用的一种衡量模型预测结果与实际标签之间差异的函数。它用于衡量模型的预测值与真实值之间的误差,并作为模型训练的优化目标。

损失值为输出值和目标值之差,越小越好。
损失函数的作用:
(1)计算实际输出和目标之间的差距。
(2)为我们反向传播的更新输出提供一定的依据。

8.1 L1Loss() L1损失函数

计算输入x和目标y对应元素之间的差值。

CLASS torch.nn.L1Loss(reduction=‘mean’)

  • reduction (str, 可选) – 指定要应用于输出的缩减:nonemeansum。默认值为mean
  • none:不进行缩减。
  • mean:输出的总和将除以输出中的元素数量。
  • sum:输出将被求和。

python代码:

import torch
from torch.nn import L1Loss

inputs = torch.tensor([1, 2, 3], dtype=torch.float32)
targets = torch.tensor([1, 2, 5], dtype=torch.float32)

inputs = torch.reshape(inputs, (1, 1, 1, 3))
targets = torch.reshape(targets, (1, 1, 1, 3))

loss1 = L1Loss(reduction="mean")
result1 = loss1(inputs, targets)
loss2 = L1Loss(reduction="sum")
result2 = loss2(inputs, targets)

print(inputs)
print(targets)
print(result1)
print(result2)

输出结果:

tensor([[[[1., 2., 3.]]]])
tensor([[[[1., 2., 5.]]]])
tensor(0.6667)
tensor(2.)

8.2 MSELoss() 平方差函数

计算输入x和目标y之间每个元素的误差的平方(L2范数的平方)。

CLASS torch.nn.MSELoss(reduction=‘mean’)

  • reduction (str, 可选) – 指定要应用于输出的缩减:nonemeansum。默认值为mean
  • none:不进行缩减。
  • mean:输出的总和将除以输出中的元素数量。
  • sum:输出将被求和。注意:size_average和reduce正在被弃用的过程中,同时,指定这两个参数中的任何一个都会覆盖reduction。

python代码如下:

import torch
from torch.nn import MSELoss

inputs = torch.tensor([1, 2, 3], dtype=torch.float32)
targets = torch.tensor([1, 2, 5], dtype=torch.float32)

inputs = torch.reshape(inputs, (1, 1, 1, 3))
targets = torch.reshape(targets, (1, 1, 1, 3))

loss3 = MSELoss()           # 误差的平方
result3 = loss3(inputs, targets)
print(result3)

输出结果:

tensor([[[[1., 2., 3.]]]])
tensor([[[[1., 2., 5.]]]])
tensor(1.3333)

8.3 CrossEntropyLoss() 交叉熵函数

CLASS torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction=‘mean’, label_smoothing=0.0)

  • weight (Tensor, 可选) – 给每个类(CLASS)手动调整权重。如果给定,它的张量的大小必须是C

  • size_average (bool, 可选) – 已弃用(见reduction)。默认情况下,损失是批处理中每个损失元素的平均损失。注意,对于某些损失,每个样本有多个元素。如果字段size_average设置为False,则对每个小批量的损失值求和。reduce为False时忽略。默认值为True。

  • ignore_index (int, 可选) – 指定一个被忽略且不影响输入梯度的目标值。当size_average为True时,损失函数是未被忽略的目标的平均值。注意,ignore_index仅适用于目标包含类索引时。

  • reduce (bool, 可选) – 已弃用(见reduction)。默认情况下,根据size_average对每个minibatch的观测值进行平均或求和。当reduce为False时,为每个批处理元素返回一个损失值并忽略size_average。默认值为True。

  • reduction (str, 可选) – 指定要应用于输出的缩减:nonemeansumnone:不进行缩减。mean:获取输出的加权平均值。sum:对输出进行求和。注意:size_average和reduce正在被弃用的过程中,同时,指定这两个参数中的任何一个都会覆盖reduction。默认值为mean

  • label_smoothing (float, 可选) – 取值范围在[0.0, 1.0]的浮点数。指定计算损失时的平滑量,0.0表示不平滑。如重新思考计算机视觉的Inception架构中所述,目标变成了原始真实值和均匀分布的混合。默认值为0.0。

python代码:

import torch
from torch.nn import CrossEntropyLoss

x = torch.tensor([0.1, 0.2, 0.3])
y = torch.tensor([1])
x = torch.reshape(x, (1, 3))
loss_cross = CrossEntropyLoss()
result_cross = loss_cross(x, y)
print(result_cross)

输出结果:

tensor(1.1019)

8.3.1 神经网络中的使用

将一张图片imgs输入到神经网络中,通过一系列的卷积、池化、展平、归一化后得到outputs,包含10个参数,表示网络识别对应图像内容的概率。将outputs和图片的target代入CrossEntropyLoss()损失函数,计算得到损失值。

python代码如下:

import torchvision
import torch
from torch import nn
from torch.nn import Linear, Conv2d, MaxPool2d, Flatten, Sequential,CrossEntropyLoss
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10(root="G:\\Anaconda\\pycharm_pytorch\\learning_project\\dataset_CIFAR10",
                                       train=False,
                                       transform=torchvision.transforms.ToTensor(),
                                       download=False)

dataloader = DataLoader(dataset, batch_size=1)

class MYNN(nn.Module):
    def __init__(self):
        super(MYNN, self).__init__()
        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2, stride=1),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2, stride=1),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2, stride=1),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x

loss = CrossEntropyLoss()

mynn = MYNN()
for data in dataloader:
    imgs, targets = data
    outputs = mynn(imgs)
    result_loss = loss(outputs, targets)
    print(outputs)          # 神经网络输出
    print(targets)          # 目标
    print(result_loss)      # 损失函数-交叉熵计算结果

运行结果(部分):

tensor([[-0.1174,  0.0607, -0.0290,  0.0328, -0.0593,  0.1143,  0.0187, -0.0872,
          0.1212,  0.0344]], grad_fn=<AddmmBackward0>)
tensor([0])
tensor(2.4319, grad_fn=<NllLossBackward0>)

tensor([[-1.1158e-01,  2.9356e-02, -4.1232e-02,  2.3896e-02, -1.0031e-01,
          9.5460e-02, -4.1537e-07, -6.9785e-02,  1.1017e-01,  9.5974e-03]],
       grad_fn=<AddmmBackward0>)
tensor([3])
tensor(2.2758, grad_fn=<NllLossBackward0>)

8.4 补充:反向传播

result_loss.backward() :反向传播函数,计算损失值的梯度grad。
以便优化器(optimizer)以梯度下降法对网络中的weight和bias进行优化。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值