inferno Pytorch: inferno.extensions.layers.convolutional 介绍及使用

inferno简介

Inferno是一个库,提供了围绕PyTorch的实用程序和方便的函数/类,为深度学习和实现神经网络提供便利。关于inferno的其他模块介绍:
inferno Pytorch: inferno.extensions.layers.convolutional 介绍及使用
inferno Pytorch: inferno.io.box.cifar下载cifar10 cifar100数据集 介绍及使用
inferno Pytorch: inferno.io.transform 介绍及使用

inferno安装

pip install inferno-pytorch

调用

from inferno.extensions.layers.convolutional import (
    Conv2D,
    ConvSigmoid2D,
)

没有报错就安装成功了。

卷积相关介绍

这部分是卷积的基本知识,可以跳过。

卷积尺寸变换

先定义几个参数
输入图片大小 W×W
Filter大小 K×K
步长 S t r i d e Stride Stride
padding的像素数 P
于是我们可以得出:

W o u t = ( W i n − K + 2 P ) / S t r i d e + 1 W_{out} = (W_{in} − K + 2P) / Stride + 1 Wout=(WinK+2P)/Stride+1

输出图片大小为 N×N。
以上是最基本的卷积。对于dilation不为1的情况:
使用带dilation的卷积输出尺寸计算公式

K ′ = k e r n e l + ( k e r n e l − 1 ) ⋅ ( d i l a t i o n − 1 ) K'=kernel+(kernel-1)\cdot(dilation-1) K=kernel+(kernel1)(dilation1)
W o u t = w i n − K ′ + 2 p a d d i n g s t r i d e + 1 W_{out}=\frac{w_{in}-K'+2padding}{stride}+1 Wout=stridewinK+2padding+1

卷积方式

首先我们知道卷积有 valid,same,full三种模式 (卷积的三种模式:full, same, valid),三种卷积的具体方式见下图。简单来说,full模式使得feature map变大,same模式保持原来的尺寸,valid模式使得feature map减小。

  1. full mode
    在这里插入图片描述

  2. same mode在这里插入图片描述

  3. valid mode在这里插入图片描述
    inferno.extensions.layers.convolutional 主要提供了valid 和same 两种填充方式的卷积。

inferno.extensions.layers.convolutional

   inferno库提供了以下实现卷积的方式:'ConvActivation',
       'ConvELU2D', 'ConvELU3D',
       'ConvSigmoid2D', 'ConvSigmoid3D',
       'DeconvELU2D', 'DeconvELU3D',
       'StridedConvELU2D', 'StridedConvELU3D',
       'DilatedConvELU2D', 'DilatedConvELU3D',
       'Conv2D', 'Conv3D',
       'BNReLUConv2D', 'BNReLUConv3D',
       'BNReLUDepthwiseConv2D',
       'ConvSELU2D', 'ConvSELU3D',
       'ConvReLU2D', 'ConvReLU3D',
       'BNReLUDilatedConv2D', 'DilatedConv2D',
       'GlobalConv2D'

ConvActivation基类源码

same的卷积方式+一个激活函数。
ConvActivation是以下其他类的基类,源码如下:

class ConvActivation(nn.Module):
    """Convolutional layer with 'SAME' padding followed by an activation."""
    def __init__(self, in_channels, out_channels, kernel_size, dim, activation,
                 stride=1, dilation=1, groups=None, depthwise=False, bias=True,
                 deconv=False, initialization=None):
        super(ConvActivation, self).__init__()
        # Validate dim
        assert_(dim in [2, 3], "`dim` must be one of [2, 3], got {}.".format(dim), ShapeError)
        self.dim = dim
        # Check if depthwise
        if depthwise:
            assert_(in_channels == out_channels,
                    "For depthwise convolutions, number of input channels (given: {}) "
                    "must equal the number of output channels (given {})."
                    .format(in_channels, out_channels),
                    ValueError)
            assert_(groups is None or groups == in_channels,
                    "For depthwise convolutions, groups (given: {}) must "
                    "equal the number of channels (given: {}).".format(groups, in_channels))
            groups = in_channels
        else:
            groups = 1 if groups is None else groups
        self.depthwise = depthwise
        if not deconv:
            # Get padding
            padding = self.get_padding(kernel_size, dilation)
            self.conv = getattr(nn, 'Conv{}d'.format(self.dim))(in_channels=in_channels,
                                                                out_channels=out_channels,
                                                                kernel_size=kernel_size,
                                                                padding=padding,
                                                                stride=stride,
                                                                dilation=dilation,
                                                                groups=groups,
                                                                bias=bias)
        else:
            self.conv = getattr(nn, 'ConvTranspose{}d'.format(self.dim))(in_channels=in_channels,
                                                                         out_channels=out_channels,
                                                                         kernel_size=kernel_size,
                                                                         stride=stride,
                                                                         dilation=dilation,
                                                                         groups=groups,
                                                                         bias=bias)
        if initialization is None:
            pass
        elif isinstance(initialization, Initializer):
            self.conv.apply(initialization)
        else:
            raise NotImplementedError

        if isinstance(activation, str):
            self.activation = getattr(nn, activation)()
        elif isinstance(activation, nn.Module):
            self.activation = activation
        elif activation is None:
            self.activation = None
        else:
            raise NotImplementedError

    def forward(self, input):
        conved = self.conv(input)
        if self.activation is not None:
            activated = self.activation(conved)
        else:
            # No activation
            activated = conved
        return activated

    def _pair_or_triplet(self, object_):
        if isinstance(object_, (list, tuple)):
            assert len(object_) == self.dim
            return object_
        else:
            object_ = [object_] * self.dim
            return object_

    def _get_padding(self, _kernel_size, _dilation):
        assert isinstance(_kernel_size, int)
        assert isinstance(_dilation, int)
        assert _kernel_size % 2 == 1
        return ((_kernel_size - 1) // 2) * _dilation

    def get_padding(self, kernel_size, dilation):
        kernel_size = self._pair_or_triplet(kernel_size)
        dilation = self._pair_or_triplet(dilation)
        padding = [self._get_padding(_kernel_size, _dilation)
                   for _kernel_size, _dilation in zip(kernel_size, dilation)]
        return tuple(padding)

其他一些子类的介绍

ValidConvActivation
valid的卷积方式+一个激活函数

class ValidConvActivation(ConvActivation):
    """Convolutional layer with 'VALID' padding followed by an activation."""
    def _get_padding(self, _kernel_size, _dilation):
        return 0

Conv2D/Conv3D
具有相同填充和正交权值初始化的二维/三维卷积层。
默认情况下,此层不应用激活函数。

class Conv2D(ConvActivation):
    """
    2D convolutional layer with same padding and orthogonal weight initialization.
    By default, this layer does not apply an activation function.
    """
    def __init__(self, in_channels, out_channels, kernel_size, dilation=1, stride=1,
                 activation=None):
        super(Conv2D, self).__init__(in_channels=in_channels,
                                     out_channels=out_channels,
                                     kernel_size=kernel_size,
                                     dilation=dilation,
                                     stride=stride,
                                     dim=2,
                                     activation=activation,
                                     initialization=OrthogonalWeightsZeroBias())


class Conv3D(ConvActivation):
    """
    3D convolutional layer with same padding and orthogonal weight initialization.
    By default, this layer does not apply an activation function.
    """
    def __init__(self, in_channels, out_channels, kernel_size, dilation=1, stride=1,
                 activation=None):
        super(Conv3D, self).__init__(in_channels=in_channels,
                                     out_channels=out_channels,
                                     kernel_size=kernel_size,
                                     dilation=dilation,
                                     stride=stride,
                                     dim=3,
                                     activation=activation,
                                     initialization=OrthogonalWeightsZeroBias())

ConvELU2D/ConvELU3D
具有“same”卷积、ELU和正交权值初始化的2D/3D卷积层

class ConvELU2D(ConvActivation):
    """2D Convolutional layer with 'SAME' padding, ELU and orthogonal weight initialization."""
    def __init__(self, in_channels, out_channels, kernel_size):
        super(ConvELU2D, self).__init__(in_channels=in_channels,
                                        out_channels=out_channels,
                                        kernel_size=kernel_size,
                                        dim=2,
                                        activation='ELU',
                                        initialization=OrthogonalWeightsZeroBias())

class ConvELU3D(ConvActivation):
    """3D Convolutional layer with 'SAME' padding, ELU and orthogonal weight initialization."""
    def __init__(self, in_channels, out_channels, kernel_size):
        super(ConvELU3D, self).__init__(in_channels=in_channels,
                                        out_channels=out_channels,
                                        kernel_size=kernel_size,
                                        dim=3,
                                        activation='ELU',
                                        initialization=OrthogonalWeightsZeroBias())

ConvSigmoid2D/ConvSigmoid3D
具有“same”填充、sigmoid和正交权值初始化的2D/3D卷积层

class ConvSigmoid2D(ConvActivation):
    """2D Convolutional layer with 'SAME' padding, Sigmoid and orthogonal weight initialization."""
    def __init__(self, in_channels, out_channels, kernel_size):
        super(ConvSigmoid2D, self).__init__(in_channels=in_channels,
                                            out_channels=out_channels,
                                            kernel_size=kernel_size,
                                            dim=2,
                                            activation='Sigmoid',
                                            initialization=OrthogonalWeightsZeroBias())


class ConvSigmoid3D(ConvActivation):
    """3D Convolutional layer with 'SAME' padding, Sigmoid and orthogonal weight initialization."""
    def __init__(self, in_channels, out_channels, kernel_size):
        super(ConvSigmoid3D, self).__init__(in_channels=in_channels,
                                            out_channels=out_channels,
                                            kernel_size=kernel_size,
                                            dim=3,
                                            activation='Sigmoid',
                                            initialization=OrthogonalWeightsZeroBias())

上面提到的其他子类就不一一介绍了,注意输入参数,初始化方式和激活函数就可以了。

使用示例(可以直接运行)

需要注意inferno封装的类基本都带有初始化方式,例如orthogonal weight initialization,Kaiming normal weight initialization等等,而nn.Conv2d的权值初始化需要你手动设置。因此,在编写神经网络的时候使用inferno比直接使用Pytorch可能更为方便一点点。
但是我个人觉得其实也没方便多少,例如,当你要写一个bias=False的卷积核的时候,它的Conv2D并没有接受这个参数,而基类ConvActivation默认是True(泪目)。

  1. 使用same卷积编写一个简单的三层网络如下:
import torch
import torch.nn as nn
from inferno.extensions.initializers import KaimingNormalWeightsZeroBias
from inferno.extensions.layers.convolutional import (
    Conv2D,
    ConvSigmoid2D,
    ValidConvReLU2D,
)
class Net_by_inferno(nn.Module):
    def __init__(self):
        super(Net_by_inferno,self).__init__()
        ReLU = nn.ReLU(inplace=True)
        self.conv1 = Conv2D(in_channels=1, out_channels=32, kernel_size=3, dilation=1, stride=1, activation=ReLU) # 可以自己设置激活函数
        self.conv2 = Conv2D(in_channels=32, out_channels=32, kernel_size=3, dilation=1, stride=1, activation=None) # 默认无激活函数
        self.conv3 = ConvSigmoid2D(in_channels=32, out_channels=1, kernel_size=3)  # 默认激活函数sigmoid
    def forward(self,x):       
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        print(x.shape) # (batchsize,1,100,100)
        
# from torchsummary import summary
net = Net_by_inferno()
print(net)
# summary(net.cuda(),(1,100,100))
x = torch.rand(4,1,100,100)
x = torch.autograd.Variable(x)
y = net(x)

三层网络如下图所示:
在这里插入图片描述

  1. 使用valid卷积,减小feature map的尺寸
class Net_by_inferno_valid(nn.Module):
    def __init__(self):
        super(Net_by_inferno_valid,self).__init__()
        self.conv = ValidConvReLU2D(in_channels=1, out_channels=1, kernel_size=3)  # 激活函数relu
    def forward(self,x):       
        x = self.conv(x)
        print(x.shape) # (4,1,100,100)
        
        
net = Net_by_inferno_valid()
print(net)
x = torch.rand(4,1,100,100)
x = torch.autograd.Variable(x)
y = net(x)

在这里插入图片描述

参考:
https://pypi.org/project/inferno-pytorch/

猜你喜欢

转载自blog.csdn.net/qq_36937684/article/details/110072215
今日推荐