[十四]深度学习Pytorch-池化层、线性层、激活函数层

本文详细介绍了PyTorch中池化层(MaxPool2d、AvgPool2d、MaxUnpool2d)、线性层(Linear)以及几种常见的激活函数(Sigmoid、Tanh、ReLU、LeakyReLU、PReLU、RReLU)的工作原理、参数含义和使用示例。通过实例展示了它们在图像处理中的应用,帮助理解深度学习模型的构建和运作。
摘要由CSDN通过智能技术生成

0. 往期内容

[一]深度学习Pytorch-张量定义与张量创建

[二]深度学习Pytorch-张量的操作:拼接、切分、索引和变换

[三]深度学习Pytorch-张量数学运算

[四]深度学习Pytorch-线性回归

[五]深度学习Pytorch-计算图与动态图机制

[六]深度学习Pytorch-autograd与逻辑回归

[七]深度学习Pytorch-DataLoader与Dataset(含人民币二分类实战)

[八]深度学习Pytorch-图像预处理transforms

[九]深度学习Pytorch-transforms图像增强(剪裁、翻转、旋转)

[十]深度学习Pytorch-transforms图像操作及自定义方法

[十一]深度学习Pytorch-模型创建与nn.Module

[十二]深度学习Pytorch-模型容器与AlexNet构建

[十三]深度学习Pytorch-卷积层(1D/2D/3D卷积、卷积nn.Conv2d、转置卷积nn.ConvTranspose)

[十四]深度学习Pytorch-池化层、线性层、激活函数层


negative infinity 负无穷大;
implicit zero padding 隐式零填充;

1. 池化层 Pooling Layer

1.1 池化层定义

在这里插入图片描述

1.2 nn.MaxPool2d(kernel_size, padding=0, dilation=1)

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

同卷积类似,看池化的窗口在几个维度上滑动便是几维池化。
(1)功能:对二维信号进行最大值池化;
(2)参数
kernel_size: 池化核的尺寸;
stride: 步长,stride步长是滑动时滑动几个像素;
padding: 填充个数,保证输入和输出图像在尺寸上是匹配的;
dilation: 空洞卷积的大小;
ceil_mode:尺寸取整,ceil_mode设置为True则为尺寸向上取整,默认为False即尺寸向下取整;
return_indices:记录最大值像素所在的位置的索引,通常用于最大值反池化上采样时使用;
在这里插入图片描述在这里插入图片描述

(3)代码示例

set_seed(1)  # 设置随机种子

# ================================= load img ==================================
path_img = os.path.join(os.path.dirname(os.path.abspath(__file__)), "lena.png")
img = Image.open(path_img).convert('RGB')  # 0~255

# convert to tensor
#c:通道,h:高,w:宽
img_transform = transforms.Compose([transforms.ToTensor()])
img_tensor = img_transform(img)
img_tensor.unsqueeze_(dim=0)    # C*H*W to B*C*H*W

# ================================= create convolution layer ==================================

# ================ maxpool
flag = 1
if flag:
    #stride步长通常与池化窗口大小2*2一致,保证池化时不会发生重叠
    maxpool_layer = nn.MaxPool2d((2, 2), stride=(2, 2))  
    img_pool = maxpool_layer(img_tensor)

# ================================= visualization ==================================
print("池化前尺寸:{}\n池化后尺寸:{}".format(img_tensor.shape, img_pool.shape))
img_pool = transform_invert(img_pool[0, 0:3, ...], img_transform)
img_raw = transform_invert(img_tensor.squeeze(), img_transform)
plt.subplot(122).imshow(img_pool)
plt.subplot(121).imshow(img_raw)
plt.show()

在这里插入图片描述
池化后照片没有啥区别,池化常用于冗余信息的剔除并减少计算量。

在这里插入图片描述

1.3 nn.AvgPool2d(kernel_size, padding=0)

nn.AvgPool2d(kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True, divisor_override=None)

(1)功能:对二维信号(图像)进行平均值池化;
(2)参数
kernel_size: 池化核的尺寸;
stride: 步长,stride步长是滑动时滑动几个像素;
padding: 填充个数,保证输入和输出图像在尺寸上是匹配的;
ceil_mode:尺寸取整,ceil_mode设置为True则为尺寸向上取整,默认为False即尺寸向下取整;
count_include_pad:填充值是否用于计算;
divisor_override:除法因子,此时计算平均值时分母为divisor_override

在这里插入图片描述
(3)代码示例
avgpool

set_seed(1)  # 设置随机种子

# ================================= load img ==================================
path_img = os.path.join(os.path.dirname(os.path.abspath(__file__)), "lena.png")
img = Image.open(path_img).convert('RGB')  # 0~255

# convert to tensor
#c:通道,h:高,w:宽
img_transform = transforms.Compose([transforms.ToTensor()])
img_tensor = img_transform(img)
img_tensor.unsqueeze_(dim=0)    # C*H*W to B*C*H*W

# ================================= create convolution layer ==================================

# ================ avgpool
flag = 1
if flag:
    avgpoollayer = nn.AvgPool2d((2, 2), stride=(2, 2))   
    img_pool = avgpoollayer(img_tensor)

# ================================= visualization ==================================
print("池化前尺寸:{}\n池化后尺寸:{}".format(img_tensor.shape, img_pool.shape))
img_pool = transform_invert(img_pool[0, 0:3, ...], img_transform)
img_raw = transform_invert(img_tensor.squeeze(), img_transform)
plt.subplot(122).imshow(img_pool)
plt.subplot(121).imshow(img_raw)
plt.show()

在这里插入图片描述
平均值池化的图像相较于最大值池化的图像较暗淡,因为像素值较小,最大值池化图像取得是最大值,平均值池化图像取得是平均值。

在这里插入图片描述

avgpool_divisor_override

set_seed(1)  # 设置随机种子

# ================================= load img ==================================
path_img = os.path.join(os.path.dirname(os.path.abspath(__file__)), "lena.png")
img = Image.open(path_img).convert('RGB')  # 0~255

# convert to tensor
#c:通道,h:高,w:宽
img_transform = transforms.Compose([transforms.ToTensor()])
img_tensor = img_transform(img)
img_tensor.unsqueeze_(dim=0)    # C*H*W to B*C*H*W

# ================================= create convolution layer ==================================
# ================ avgpool divisor_override
flag = 1
if flag:
    img_tensor = torch.ones((1, 1, 4, 4))#创建1*1*4*4,代表B*C*H*W, B是batchsize
    avgpool_layer = nn.AvgPool2d((2, 2), stride=(2, 2))
    img_pool = avgpool_layer(img_tensor) #输出1*1*2*2,因为(1+1+1+1)/4=1

    avgpool_layer = nn.AvgPool2d((2, 2), stride=(2, 2), divisor_override=3)
    img_pool = avgpool_layer(img_tensor) #输出1*1*1.3333*1.3333,因为(1+1+1+1)/3=1.3333

    print("raw_img:\n{}\npooling_img:\n{}".format(img_tensor, img_pool))

在这里插入图片描述
在这里插入图片描述

1.4 nn.MaxUnpool2d(kernel_size, padding=0)

nn.MaxUnpool2d(kernel_size, stride=None, padding=0)

(1)功能:对二维信号(图像)进行最大值池化上采样;
(2)参数
kernel_size: 池化核的尺寸;
stride: 步长,stride步长是滑动时滑动几个像素;
padding: 填充个数,保证输入和输出图像在尺寸上是匹配的;
在这里插入图片描述
(3)代码示例
test.py

set_seed(1)  # 设置随机种子

# ================================= load img ==================================
path_img = os.path.join(os.path.dirname(os.path.abspath(__file__)), "lena.png")
img = Image.open(path_img).convert('RGB')  # 0~255

# convert to tensor
#c:通道,h:高,w:宽
img_transform = transforms.Compose([transforms.ToTensor()])
img_tensor = img_transform(img)
img_tensor.unsqueeze_(dim=0)    # C*H*W to B*C*H*W

# ================================= create convolution layer ==================================

# ================ max unpool
flag = 1
if flag:
    # pooling
    img_tensor = torch.randint(high=5, size=(1, 1, 4, 4), dtype=torch.float) #生成尺寸为1*1*4*4的整数[0, 5)均匀分布
    maxpool_layer = nn.MaxPool2d((2, 2), stride=(2, 2), return_indices=True)
    img_pool, indices = maxpool_layer(img_tensor) #记录最大像素值的索引

    # unpooling
    #创建反池化层的输入,输入的尺寸与图片池化后的尺寸一致。
    img_reconstruct = torch.randn_like(img_pool, dtype=torch.float) #标准正态分布
    #构建反池化层(窗口、步长参数与池化层参数一一对应相等)
    maxunpool_layer = nn.MaxUnpool2d((2, 2), stride=(2, 2))
    #生成反池化后的图像
    img_unpool = maxunpool_layer(img_reconstruct, indices)

    print("raw_img:\n{}\nimg_pool:\n{}".format(img_tensor, img_pool))
    print("img_reconstruct:\n{}\nimg_unpool:\n{}".format(img_reconstruct, img_unpool))

在这里插入图片描述
official_test

>>> pool = nn.MaxPool2d(2, stride=2, return_indices=True)
>>> unpool = nn.MaxUnpool2d(2, stride=2)
>>> input = torch.tensor([[[[ 1.,  2.,  3.,  4.],
                            [ 5.,  6.,  7.,  8.],
                            [ 9., 10., 11., 12.],
                            [13., 14., 15., 16.]]]])
>>> output, indices = pool(input)
>>> unpool(output, indices)
tensor([[[[  0.,   0.,   0.,   0.],
          [  0.,   6.,   0.,   8.],
          [  0.,   0.,   0.,   0.],
          [  0.,  14.,   0.,  16.]]]])
>>> # Now using output_size to resolve an ambiguous size for the inverse
>>> input = torch.torch.tensor([[[[ 1.,  2.,  3., 4., 5.],
                                  [ 6.,  7.,  8., 9., 10.],
                                  [11., 12., 13., 14., 15.],
                                  [16., 17., 18., 19., 20.]]]])
>>> output, indices = pool(input)
>>> # This call will not work without specifying output_size
>>> unpool(output, indices, output_size=input.size())
tensor([[[[ 0.,  0.,  0.,  0.,  0.],
          [ 0.,  7.,  0.,  9.,  0.],
          [ 0.,  0.,  0.,  0.,  0.],
          [ 0., 17.,  0., 19.,  0.]]]])

2. 线性层(全连接层)

2.1 线性层定义

在这里插入图片描述
每个 上一层所有

2.2 nn.Linear(in_features, out_features, bias=True)

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

(1)功能:对一维信号(向量)进行线性组合;
(2)参数
in_features: 输入节点数;
in_features: 输出节点数;
bias: 是否需要偏置,默认为True

在这里插入图片描述
(3)代码示例
在这里插入图片描述

test.py

# ================ linear
flag = 1
if flag:
    inputs = torch.tensor([[1., 2, 3]]) #1*3
    linear_layer = nn.Linear(3, 4) #输入节点3个,输出节点4个
    #w权值矩阵为4*3,每一行代表一个神经元与上一层神经元连接的权值。
    linear_layer.weight.data = torch.tensor([[1., 1., 1.],
                                             [2., 2., 2.],
                                             [3., 3., 3.],
                                             [4., 4., 4.]])

    linear_layer.bias.data.fill_(0.5)
    output = linear_layer(inputs)
    print(inputs, inputs.shape)
    print(linear_layer.weight.data, linear_layer.weight.data.shape)
    #output=inputs*w^T+bias
    print(output, output.shape) #输出的尺寸为1*4

official_test

>>> m = nn.Linear(20, 30)
>>> input = torch.randn(128, 20)
>>> output = m(input)
>>> print(output.size())
torch.Size([128, 30])

3. 激活函数

3.1 激活函数定义

在这里插入图片描述

3.2 nn.Sigmoid()

在这里插入图片描述
(1)多个网络层叠加后,导数范围会变得更小,甚至消失。
(2)输出不是0均值分布,破坏了数据分布。

代码示例

>>> m = nn.Sigmoid()
>>> input = torch.randn(2)
>>> output = m(input)

3.3 nn.Tanh()

在这里插入图片描述
多个网络层叠加后,导数范围会变得更小,甚至消失。

代码示例

>>> m = nn.Tanh()
>>> input = torch.randn(2)
>>> output = m(input)

3.4 nn.ReLU()

在这里插入图片描述
(1)ReLU=修正线性单元;
(2)死神经元:导数为0,没有输出。
(3)多个网络层叠加后,导数一直是1,不会使梯度下降,有可能梯度越来越大,引发梯度爆炸。

代码示例

  >>> m = nn.ReLU()
  >>> input = torch.randn(2)
  >>> output = m(input)

3.5 nn.LeakyReLU(negative_slope=0.01, inplace=False)

在这里插入图片描述

LeakyReLU:负半轴0.01的斜率.

代码示例

>>> m = nn.LeakyReLU(0.1)
>>> input = torch.randn(2)
>>> output = m(input)

3.5 nn.PReLU(num_parameters=1, init=0.25, device=None, dtype=None)

在这里插入图片描述
在这里插入图片描述

PReLU:斜率是可学习的.

代码示例

>>> m = nn.PReLU()
>>> input = torch.randn(2)
>>> output = m(input)

3.6 nn.RReLU(lower=0.125, upper=0.3333333333333333, inplace=False)

在这里插入图片描述
RReLU:斜率是随机的,均匀分布.

在这里插入图片描述
代码示例

>>> m = nn.RReLU(0.1, 0.3)
>>> input = torch.randn(2)
>>> output = m(input)

4. 完整代码

# -*- coding: utf-8 -*-
"""
# @file name  : nn_layers_others.py
# @brief      : 其它网络层
"""
import os
import torch
import random
import numpy as np
import torchvision
import torch.nn as nn
from torchvision import transforms
from matplotlib import pyplot as plt
from PIL import Image
from tools.common_tools import transform_invert, set_seed

set_seed(1)  # 设置随机种子

# ================================= load img ==================================
path_img = os.path.join(os.path.dirname(os.path.abspath(__file__)), "lena.png")
img = Image.open(path_img).convert('RGB')  # 0~255

# convert to tensor
#c:通道,h:高,w:宽
img_transform = transforms.Compose([transforms.ToTensor()])
img_tensor = img_transform(img)
img_tensor.unsqueeze_(dim=0)    # C*H*W to B*C*H*W

# ================================= create convolution layer ==================================

# ================ maxpool
# flag = 1
flag = 0
if flag:
    #stride步长通常与池化窗口大小2*2一致,保证池化时不会发生重叠
    maxpool_layer = nn.MaxPool2d((2, 2), stride=(2, 2))  
    img_pool = maxpool_layer(img_tensor)

# ================ avgpool
# flag = 1
flag = 0
if flag:
    avgpoollayer = nn.AvgPool2d((2, 2), stride=(2, 2))   
    img_pool = avgpoollayer(img_tensor)

# ================ avgpool divisor_override
# flag = 1
flag = 0
if flag:
    img_tensor = torch.ones((1, 1, 4, 4))#创建1*1*4*4,代表B*C*H*W, B是batchsize
    avgpool_layer = nn.AvgPool2d((2, 2), stride=(2, 2))
    img_pool = avgpool_layer(img_tensor) #输出1*1*2*2,因为(1+1+1+1)/4=1

    avgpool_layer = nn.AvgPool2d((2, 2), stride=(2, 2), divisor_override=3)
    img_pool = avgpool_layer(img_tensor) #输出1*1*1.3333*1.3333,因为(1+1+1+1)/3=1.3333

    print("raw_img:\n{}\npooling_img:\n{}".format(img_tensor, img_pool))


# ================ max unpool
# flag = 1
flag = 0
if flag:
    # pooling
    img_tensor = torch.randint(high=5, size=(1, 1, 4, 4), dtype=torch.float) #生成尺寸为1*1*4*4的整数[0, 5)均匀分布
    maxpool_layer = nn.MaxPool2d((2, 2), stride=(2, 2), return_indices=True)
    img_pool, indices = maxpool_layer(img_tensor) #记录最大像素值的索引

    # unpooling
    #创建反池化层的输入,输入的尺寸与图片池化后的尺寸一致。
    img_reconstruct = torch.randn_like(img_pool, dtype=torch.float) #标准正态分布
    #构建反池化层(窗口、步长参数与池化层参数一一对应相等)
    maxunpool_layer = nn.MaxUnpool2d((2, 2), stride=(2, 2))
    #生成反池化后的图像
    img_unpool = maxunpool_layer(img_reconstruct, indices)

    print("raw_img:\n{}\nimg_pool:\n{}".format(img_tensor, img_pool))
    print("img_reconstruct:\n{}\nimg_unpool:\n{}".format(img_reconstruct, img_unpool))


# ================ linear
flag = 1
# flag = 0
if flag:
    inputs = torch.tensor([[1., 2, 3]]) #1*3
    linear_layer = nn.Linear(3, 4) #输入节点3个,输出节点4个
    #w权值矩阵为4*3,每一行代表一个神经元与上一层神经元连接的权值。
    linear_layer.weight.data = torch.tensor([[1., 1., 1.],
                                             [2., 2., 2.],
                                             [3., 3., 3.],
                                             [4., 4., 4.]])

    linear_layer.bias.data.fill_(0.5)
    output = linear_layer(inputs)
    print(inputs, inputs.shape)
    print(linear_layer.weight.data, linear_layer.weight.data.shape)
    #output=inputs*w^T+bias
    print(output, output.shape) #输出的尺寸为1*4


# ================================= visualization ==================================
print("池化前尺寸:{}\n池化后尺寸:{}".format(img_tensor.shape, img_pool.shape))
img_pool = transform_invert(img_pool[0, 0:3, ...], img_transform)
img_raw = transform_invert(img_tensor.squeeze(), img_transform)
plt.subplot(122).imshow(img_pool)
plt.subplot(121).imshow(img_raw)
plt.show()
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值