12池化、线性、激活函数层

一、池化层——Pooling Layer

1.1 池化层概念

池化运算: 对信号进行“收集”并“总结” ,类似水池收集水资源,因而 ,得名池化层

  • “收集" : 多变少
  • “总结" : 最大值/平均值
    在这里插入图片描述

1.2 nn.MaxPool2d

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

功能: 对二维信号(图像)进行最大值池化
主要参数:

  • kernel_size: 池化核尺寸
  • stride: 步长
  • padding : 填充个数
  • dilation: 池化核间隔大小
  • ceil_mode: 尺寸向上取整
  • return_indices: 记录池化像素索引,在最大值反池化上采样时使用

最大值反池化上采样:
在这里插入图片描述
早期的自编码器和图像分割任务中都会涉及图像上采样的操作,当时常使用最大值反池化上采样

如上图所示,图片先进行池化下采样,然后再进行上采样,此时就出现问题:2*2的图像中的像素值上采样后应该放到哪个位置?

而return_indices记录了最大池化下采样时,每个像素值来自的位置,在上采样时就可以根据记录的位置进行上采样

代码:

# -*- coding: utf-8 -*-
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
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:
    maxpool_layer = nn.MaxPool2d((2, 2), stride=(2, 2))   # input:(i, o, size) weights:(o, i , h, w)
    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

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

功能:对二维信号(图像)进行平均值池化
主要参数:

  • kernel_size: 池化核尺寸
  • stride: 步长
  • padding: 填充个数
  • ceil mode: 尺寸向上取整
  • count_include_pad: 填充值用于计算
  • divisor_override: 除法因子
# -*- coding: utf-8 -*-

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
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
# flag = 0
if flag:
    avgpoollayer = nn.AvgPool2d((2, 2), stride=(2, 2))   # input:(i, o, size) weights:(o, i , h, w)
    img_pool = avgpoollayer(img_tensor)

# ================ avgpool divisor_override
# flag = 1
flag = 0
if flag:
    img_tensor = torch.ones((1, 1, 4, 4))
    avgpool_layer = nn.AvgPool2d((2, 2), stride=(2, 2), divisor_override=3)
    img_pool = avgpool_layer(img_tensor)

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


# ================================= 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.4 nn.MaxUnpool2d

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

forward(self, input, indices, output_size=None) 

功能: 对二维信号(图像)进行最大值池化上采样
注意: forward中要传入indices
主要参数:

  • kernel size: 池化核尺寸
  • stride: 步长
  • padding: 填充个数
# -*- coding: utf-8 -*-

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
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
# flag = 0
if flag:
    # pooling
    img_tensor = torch.randint(high=5, size=(1, 1, 4, 4), dtype=torch.float)
    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 Layer

2.1 线性层概念

线性层又称全连接层,其每个神经元与上一层所有神经元相连实现对前一层的线性组合, 线性变换
在这里插入图片描述
在这里插入图片描述

2.2 nn.Linear

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

功能: 对一维信号(向量)进行线性组合
主要参数:

  • in_features: 输入结点数
  • out_features: 输出结点数
  • bias : 是否需要偏置

计算公式: y = x W T + b i a s y=xW^T + bias

代码:

# -*- coding: utf-8 -*-

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
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 ==================================
# ================ linear
flag = 1
# flag = 0
if flag:
    inputs = torch.tensor([[1., 2, 3]])
    linear_layer = nn.Linear(3, 4)
    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)
    print(output, output.shape)

运行结果:
在这里插入图片描述
注意:由上面计算公式可知,线性层计算时,对权值矩阵是进行转置后再运算的,所以设置权值矩阵时需要按转置形式设置

三、激活函数层——Activation Layer

3.1 激活函数层

激活函数对特征进行非线性变换, 赋予多层神经网络具有深度的意义
在这里插入图片描述
当使用线性激活函数时,如上图所示,输出就变成了输入的线性组合,中间的隐藏层就失去了意义,所以,通过引入非线性激活函数,增加了网络的深度,同时给予了网络的非线性

3.2 nn.Sigmoid

计算公式: y = 1 1 + e x y=\frac{1}{1+e^{-x}}
梯度公式: y = y ( 1 y ) y'=y* (1-y)
在这里插入图片描述
特性:

  • 输出值在(0,1),符合概率
  • 导数范围是[0, 0.25],易导致梯度消失
  • 输出为非0均值,破坏数据分布

3.3 nn.tanh

计算公式: y = s i n x c o s x = e x e x e x + e x = 2 1 + e 2 x + 1 y=\frac{sinx}{cosx}=\frac{e^x-e^{-x}}{e^x+e^{-x}}=\frac{2}{1+e^{-2x}}+1

梯度公式: y = 1 y 2 y'=1-y^2

在这里插入图片描述

特性:

  • 输出值在(-1,1),数据符合0均值
  • 导数范围是(0, 1),易导致梯度消失

3.4 nn.ReLU

3.4.1 nn.ReLU

计算公式: y = m a x ( 0 , x ) y= max(0,x)

梯度公式: y = { 1 , x > 0 u n d e f i n e d , x = 0 0 , x < 0 y'= \begin{cases} 1, \qquad \qquad \quad x>0 \\undefined, \quad x=0 \\0,\qquad \qquad \quad x<0\end{cases}

在这里插入图片描述
特性:

  • 输出值均为正数,负半轴导致死神经元
  • 导数是1,缓解梯度消失,但易引发梯度爆炸

3.4.2 nn.LeakyReLU

功能:负半轴增加一个很小的斜率,防止死神经元

  • negative_slope: 设置负半轴斜率

3.4.3 nn.PReLU

功能:使负半轴的斜率是可学习的,随着网络更新斜率参数会变化

  • init: 设置可学习斜率的初始值

3.4.4 nn.RReLU

功能:随机地从均匀分布中采样斜率

  • lower: 均匀分布下限
  • upper:均匀分布上限

在这里插入图片描述

发布了105 篇原创文章 · 获赞 9 · 访问量 7812

猜你喜欢

转载自blog.csdn.net/qq_36825778/article/details/104107787