PyTorch框架

1. 张量

1.1 Variable

Variabletorch.autograd中的数据类型,主要用于封装Tensor,进行 自动求导

在这里插入图片描述

  • data:被包装的 Tensor
  • grad:data 的梯度
  • grad_fn :创建 Tensor 的 Function,是自动求导的关键
  • requires_grad:指示是否需要梯度
  • is_leaf:指示是否是叶子节点

1.2 Tensor

在这里插入图片描述
  Pytorch 0.4.0 开始,Variable 并入Tensor。

  • dtype:张量的数据类型,如 torch.FloatTensor, torch.cuda.FloatTensor
  • shape:张量的形状,如 ( 64 , 3 , 224 , 224 ) (64,3,224,224) (64,3,224,224)
  • device :张量所在的设备,GPU/CPU,是加速的关键

1.3 张量的创建

张量创建-参考链接-pytorch中文手册
① 直接创建

  • torch.tensor(),从data 创建 tensor
  • torch.from_numpy(ndarry),从numpy 创建 tensor,共享内存,当修改一个值时,另一个也将被改动。

② 依据数值创建

  • torch.zeros(),依 size 创建全 0 张量
  • torch.zeros_like(),依 input 形状创建全 0 张量
  • torch.ones()、torch.ones_likes(),依 input 形状创建全 1 张量
  • torch.full()、torch.full_likes(),依 input 形状创建 指定数据 的张量
  • torch.arange(),创建等差的 1 维张量
  • torch.linspace(),创建均分的 1 维张量
  • torch.logspace(),创建对数均分的 1 维张量
  • torch.eye(),创建单位对角矩阵(2维张量)

③ 依概率分布创建张量

  • torch.normal(),生成正太分布
  • torch.randn(),生成标准正太分布
  • torch.rand(),在区间 [0,1) 上,生成均匀分布
  • torch.randint(),生成均匀分布
  • torch.randperm(),生成从0~1的随机排列
  • torch.bernoulli(),以 input 为概率,生成伯努利分布( 0-1 分布,两点分布)

1.4 张量的操作

张量-索引,切片,连接,换位Indexing, Slicing, Joining, Mutating Ops-参考链接

pytorch实现线性回归小案例-code

1.5 计算图与动态图

1.5.1 计算图

  计算图是用来 描述运算 的有向无环图,计算图有两个主要元素: 节点(Node)和 (Edge)。节点 表示 数据,如向量,矩阵,张量;边 表示 运算,如加减乘除卷积等。
  用计算图表示 y = ( x + w ) ⋅ ( w + 1 ) y = (x+w)\cdot(w+1) y=(x+w)(w+1),则可表示为 a = x + w , b = w + 1 , y = a ⋅ b a=x+w, b=w+1, y=a\cdot b a=x+w,b=w+1,y=ab

在这里插入图片描述
计算图与梯度求导
∂ y ∂ w = ∂ y ∂ a ∂ a ∂ w + ∂ y ∂ b ∂ b ∂ w = b ∗ 1 + a ∗ 1 = b + a = ( w + 1 ) + ( x + w ) = 2 ∗ w + x + 1 = 2 × 1 + 2 + 1 = 5 \begin{aligned} \frac{\partial y}{\partial w} &=\frac{\partial y}{\partial a} \frac{\partial a}{\partial w}+\frac{\partial y}{\partial b} \frac{\partial b}{\partial w} \\ &=b * 1+a * 1 \\ &=b+a \\ &=(w+1)+(x+w) \\ &=2 * w+x+1 \\ &=2\times1+2+1=5 \end{aligned} wy=aywa+bywb=b1+a1=b+a=(w+1)+(x+w)=2w+x+1=2×1+2+1=5

叶子节点:用户创建的结点成为叶子节点,如 x x x w w w
  设置 叶子节点 主要是为了节省内存,在梯度反向传播结束之后,非叶子结点的梯度会被释放掉。

  • grad_fn :记录创建该张量时所用的方法(函数)
w = torch.tensor([1.], requires_grad=True)  # 梯度为1
x = torch.tensor([2.], requires_grad=True)  # 梯度为2
a = torch.add(w, x)  # retain_grad()保留梯度
# a.retain_grad()
b = torch.add(w, 1)
y = torch.mul(a, b)
y.backward()
print(w.grad)   # tensor([5.])

# 查看叶子结点
print("is_leaf:\n", w.is_leaf, x.is_leaf, a.is_leaf, b.is_leaf, y.is_leaf)
# True True False False False

# 查看梯度
print('gradient:\n', w.grad, x.grad, a.grad, b.grad, y.grad)
# tensor([5.]) tensor([2.]) None None None

# 查看grad_fn
print("grad_fn:\n", w.grad_fn, x.grad_fn, a.grad_fn, b.grad_fn, y.grad_fn)
# None None <AddBackward0 object at 0x000001ED078C3148>
# <AddBackward0 object at 0x000001ED1E91F108>
# <MulBackward0 object at 0x000001ED1E91F208>

1.6 autograd

1.6.1 torch.autograd.backward()

  自动求取梯度

torch.autograd.backward(tensors,  # 用于求导的张量,如 loss
						grad_tensors=None,   # 多梯度权重  
						retain_grad=None,    # 保存计算图
						create_graph=False)  # 创建导数计算图,用于高阶求导

例子:

w = torch.tensor([1.], requires_grad=True)  # 梯度为1
x = torch.tensor([2.], requires_grad=True)
a = torch.add(w, x)  
# a.retain_grad()   # retain_grad()保留梯度
b = torch.add(w, 1)
y0 = torch.mul(a, b)  # y0 = (x+w) * (w+1) = 6    dy0/dw = 5   y0对 w求梯度,也可看上面
y1 = torch.add(a, b)  # y1 = (x+w) + (w+1) = 5    dy1/dw = 2

loss = torch.cat([y0, y1], dim=0)   # tensor([6., 5.])
grad_tenors = torch.tensor([1., 2.])    # 多个梯度中权重的设置,y0对应 1,y1对应 2
# gradient 传入 torch.autograd.backward()中的grad_tensors
loss.backward(gradient=grad_tenors)

print(w.grad)  # 9 = 1*5 + 2*2

1.6.2 torch.autograd.gard()

  求取梯度

torch.autograd.grad(outputs,  # 用于求导的张量,如loss
                    inputs,   # 需要梯度的张量
                    grad_outputs=None,   # 多梯度权重
                    retain_graph=None,   # 保存计算图
                    create_graph=False)  # 创建计算图

例子:

x = torch.tensor([3.], requires_grad=True)
y = torch.pow(x, 2)  # y = x**2

grad_1 = torch.autograd.grad(y, x, create_graph=True)
# grad_1 = dy/dx = 2x = 2 * 3 = 6
print(grad_1)  # (tensor([6.], grad_fn=<MulBackward0>),)

print(grad_1[0])  # tensor([6.], grad_fn=<MulBackward0>)
grad_2 = torch.autograd.grad(grad_1[0], x)  # 求二阶导
# grad_2 = d(dy/dx)/dx = d(2x)/dx = 2
print(grad_2)   # (tensor([2.]),)

1.6.3 autograd 三个要点

  1. 梯度不自动清零
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
for i in range(4):
    a = torch.add(w, x)
    b = torch.add(w, 1)
    y = torch.mul(a, b)
    y.backward()
    print(w.grad)

    w.grad.zero_()  # 手动对梯度进行清零,'_':原位操作。
# tensor([5.])
# tensor([5.])
# tensor([5.])
  1. 依赖于叶子结点的结点,requires_grad 默认为True
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
a = torch.add(w, x)
b = torch.add(w, 1)
y = torch.mul(a, b)

print(a.requires_grad, b.requires_grad, y.requires_grad)
# True True True
  1. 叶子结点不可执行in-place
    in-place 原位操作:在原始内存当中去改变这一数据
    为什么叶子节点不能进行in-place操作?
      在反向传播过程中需要用到叶子结点。而在前向传播时,要记录叶子结点的地址。到反向传播时根据叶子结点的地址去寻找这个数据,进行使用计算。
a = torch.ones((1, ))
print(id(a), a)
# 1970317858920 tensor([1.])

a = a + torch.ones((1, ))
print(id(a), a)
# 1970369990728 tensor([2.])
# 开辟了新的地址,就不是原位操作,

a += torch.ones((1, ))  # 原位操作.在原始地址上改变
print(id(a), a)
# 1970369990728 tensor([3.])

另一个例子

w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)

a = torch.add(w, x)
b = torch.add(w, 1)
y = torch.mul(a, b)

w.add_(1)
"""
autograd小贴士:
    梯度不自动清零 
    依赖于叶子结点的结点,requires_grad默认为True     
    叶子结点不可执行in-place 
"""
y.backward()  # 报错,叶子结点不可执行in-place

这一节的代码,可查看链接
逻辑回归pytorch实现小案例

2. 数据处理

  机器学习训练五大步骤,数据模型损失函数优化器迭代训练

在这里插入图片描述

2.1 数据读取 Dataloader

torch.utils.data.DataLoader(),数据加载器。组合数据集和采样器,并在数据集上提供单进程或多进程迭代器。参数解释链接

  • Epoch :所有训练样本都已输入到模型中,成为一个Epoch
  • Iteration:一批样本输入到模型中,称之为一个Iteration
  • BatchSize:批大小,决定一个Epoch有多少个Iteration
  • 假如有80个样本,设置 BatchSize 为 8,则 1 Epoch = 10 Iteration。

torch.utils.data.Dataset(),Dataset 抽象类,所有自定义的 Dataset 需要继承它,并且复写 __getitem__()getitem:接收一个索引,返回一个样本。对__getitem__()具体解释可参考链接

class Dataset(object):
    def __getitem__(self, index):
        raise NotImplementedError
    def __add__(self, other):
        return ConcatDataset([self, other])

在这里插入图片描述

数据读取流程图

dataloader 划分人民币小案例

2.2 数据预处理 transforms

torchvision.transforms 常用的图像预处理方法,数据中心化数据标准化缩放裁剪旋转翻转填充噪声添加灰度变换线性变换仿射变换亮度、饱和度及对比度变换

transforms.Normalize(),逐channel 的对图像进行标准化, o u t p u t = ( i n p u t − m e a n ) / s t d output = (input-mean)/std output=(inputmean)/std

from torchvision import transforms
transforms.Normalize(mean,     # 各通道的均值
                     std,      # 各通道的标准差
                     inplace=False)   # 是否原地操作

2.2.1 数据增强 Data Augmentation

  数据增强又称为数据增广,数据扩增,它是对训练集进行变换,使训练集更丰富,从而让模型更具泛化能力
张贤同学 - 二十二种 transforms 图片数据预处理方法 - 参考链接

方法 功能
transforms.CenterCrop() 裁剪从图像中心裁剪图片
transforms.RandomCrop() 裁剪从图片中随机裁剪出尺寸为size的图片
transforms.RandomResizedCrop() 裁剪随机大小,长宽比裁剪图片
transforms.FiveCrop() 裁剪在图像上下左右以及中心裁剪出尺寸为size5张图片
transforms.TenCrop() 裁剪对这5张图片进行水平或者垂直镜像获得10张图片
transforms.RandomHorizontalFlip() 翻转和旋转依概率水平或左右翻转图片
transforms.RandomVerticalFlip() 翻转和旋转依概率垂直或上下翻转图片
transforms.RandomRotation() 翻转和旋转随机旋转图片
transforms.Pad() 图像变换对图片边缘进行填充
transforms.ColorJitter() 图像变换调整亮度,对比度,饱和度和色相
transforms.Grayscale() 图像变换依概率将图片转为灰度图
transforms.RandomGrayscale() 图像变换依概率将图片转为灰度图
transforms.RandomAffine() 图像变换对图片进行仿射变换,仿射变换是二维的线性变换,由五种基本原子变换构成,分别是旋转平移缩放错切翻转
transforms.LinearTransformation() 图像变换
transforms.RandomErasing() 图像变换对图像进行随机遮挡
transforms.Lambda() 图像变换用户自定义Lambda方法
transforms.Resize() 图像变换给定大小缩放
transforms.Totensor() 图像变换转为张量
transforms.Normalize() 图像变换标准化,归一化
transforms.RandomChoice() transforms的操作从一系列transforms方法中随机挑一个
transforms.RandomApply() transforms的操作依据概率执行一组transforms操作
transforms.RandomOrder() transforms的操作对一组transforms操作打乱顺序

2.2.2 自定义 transforms

自定义 transforms 要素:

  • 仅接收一个参数,返回一个参数
  • 注意上下游的输出与输入,上一个transform 的输出是下一个 tranform 的输入

可以通过类实现多参数的传入,这里代码相关解释可参考链接

class YourTransforms(object):
	def __init__(self, ...):
		...
	def __call__(self, img):
		...
		return img
	def Compose(object):
		def __call__(self, img):
			for t in self.transforms:
				img = t(img)
			return img

椒盐噪声:

  椒盐噪声又称为脉冲噪声,是一种随机出现的白点或者黑点,白点称为盐噪声,黑色为椒噪声。
信噪比(Signal-Noise Rate,SNR)是衡量噪声的比例,图像中图像像素的占比。值越大(越接近 1),噪声越小。

  定义一个AddPepperNoise类,作为添加椒盐噪声的 transform。在构造函数中传入 信噪比 概率,在__call__()函数中执行具体的逻辑,返回的是 image。

# 自定义添加椒盐噪声的 transform
class AddPepperNoise(object):
    """增加椒盐噪声
    Args:
        snr (float): Signal Noise Rate
        p (float): 概率值,依概率执行该操作
    """

    def __init__(self, snr, p=0.9):
        assert isinstance(snr, float) or (isinstance(p, float))
        self.snr = snr
        self.p = p

    # transform 会调用该方法
    def __call__(self, img):
        """
        Args:
            img (PIL Image): PIL Image
        Returns:
            PIL Image: PIL image.
        """
        # 如果随机概率小于 seld.p,则执行 transform
        if random.uniform(0, 1) < self.p:
            # 把 image 转为 array
            img_ = np.array(img).copy()
            # 获得 shape
            h, w, c = img_.shape
            # 信噪比
            signal_pct = self.snr
            # 椒盐噪声的比例 = 1 -信噪比
            noise_pct = (1 - self.snr)
            # 选择的值为 (0, 1, 2),每个取值的概率分别为 [signal_pct, noise_pct/2., noise_pct/2.]
            # 椒噪声和盐噪声分别占 noise_pct 的一半
            # 1 为盐噪声,2 为 椒噪声
            mask = np.random.choice((0, 1, 2), size=(h, w, 1), p=[signal_pct, noise_pct/2., noise_pct/2.])
            mask = np.repeat(mask, c, axis=2)
            img_[mask == 1] = 255   # 盐噪声
            img_[mask == 2] = 0     # 椒噪声
            # 再转换为 image
            return Image.fromarray(img_.astype('uint8')).convert('RGB')
        # 如果随机概率大于 seld.p,则直接返回原图
        else:
            return img

3. 模型构建

在这里插入图片描述
  模型创建包括两个要素, 构建子模块 __init__() 拼接子模块 forward()。 在 LeNet 中继承nn.Module,必须实现__init__() 方法和forward()方法。其中在__init__() 方法里创建子模块,在 forward() 方法里拼接子模块。
  在 LeNet 的__init__()中创建了 5 个子模块,nn.Conv2d()nn.Linear()都是 继承于nn.module,也就是说一个 module 都是包含多个子 module 的。

class LeNet(nn.Module):
	# 子模块创建
    def __init__(self, classes):  #  父类函数调用
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, classes)
	# 子模块拼接
    def forward(self, x):
        out = F.relu(self.conv1(x))
        out = F.avg_pool2d(out, 2)
        out = F.relu(self.conv2(out))
        out = F.avg_pool2d(out, 2)
        out = out.view(out.size(0), -1)
        out = F.relu(self.fc1(out))
        out = F.relu(self.fc2(out))
        out = self.fc3(out)
        return out

3.1 nn.Module

  pytorch神经网络模块 torch.nn 里包含很多子模块,主要以下面四个展开,其具体方法可参考链接
在这里插入图片描述

nn.Module主要包含有8 个属性, 都是OrderDict(有序字典)。在 LeNet 的__init__()方法中会调用父类nn.Module__init__()方法,创建这 8 个属性。
nn.Module 代码debug 解释部分 - 参考链接

def __init__(self):
    """
    Initializes internal Module state, shared by both nn.Module and ScriptModule.
    """
    torch._C._log_api_usage_once("python.nn_module")

    self.training = True
    self._parameters = OrderedDict()   # 存储管理nn.Parameter类型的参数
    self._buffers = OrderedDict()      # 存储管理缓存属性,如BN层中的running_mean
    self._non_persistent_buffers_set = set()   
    self._backward_hooks = OrderedDict()  # ***_hooks: 存储管理钩子函数
    self._forward_hooks = OrderedDict()
    self._forward_pre_hooks = OrderedDict()
    self._state_dict_hooks = OrderedDict()
    self._load_state_dict_pre_hooks = OrderedDict()
    self._modules = OrderedDict()    # 存储管理 nn.Module类型的参数

nn.Module 使用方法总结:

  • 一个 Module 里可以包含多个子 module。比如 LeNet 是一个Module,里面包括多个卷积层、池化层、全连接层等子Module
  • 一个 Module 相当于一个运算,必须实现 forward() 运算
  • 每个 Module 都有 8 个字典管理自己的属性

3.2 模型容器 Containers

常见的模型容器Containers包含如下:

  • nn.Sequetial 按顺序包装多个网络层。 顺序性各网络层之间严格按顺序执行,常用于block构建。
  • nn.ModuleList:像python的 list 一样包装多个网络层。 迭代性常用于大量重复网构建,通过 for 循环实现重复构建。
  • nn.ModuleDict:像python的 dict 一样包装多个网络层。 索引性常用于可选择的网络层。

3.2.1 nn.Sequetial

  在深度学习中,特征工程的概念被弱化了, 特征提取 分类器 这两步被融合到了一个神经网络中。在卷积神经网络中,前面的卷积层以及池化层可以认为是特征提取部分,而后面的全连接层可以认为是分类器部分。比如 LeNet 就可以分为特征提取和分类器两部分,这 2 部分都可以分别使用 nn.Sequetial 来包装。
nn.Sequentialnn.module 的容器,用于按顺序包装一组网络层,有以下两个特征:

  1. 顺序性:各网络层之间严格按照顺序构建
  2. 自带 forward():自带的 forward 里,通过 for 循环依次执行前向传播运算。

LeNet网络结构- 图片引用链接

class LeNetSequential(nn.Module):
    def __init__(self, classes):
        super(LeNetSequential, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 6, 5),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(6, 16, 5),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
        )

        self.classifier = nn.Sequential(
            nn.Linear(16*5*5, 120),
            nn.ReLU(),
            nn.Linear(120, 84),
            nn.ReLU(),
            nn.Linear(84, classes),
        )

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size()[0], -1)
        x = self.classifier(x)
        return x

  初始化时,nn.Sequetial会调用__init__()方法,将每一个子 module 添加到 自身的_modules属性中。这里可以看到,传入的参数可以是一个 list,或者一个 OrderDict。如果是一个 OrderDict,那么则使用 OrderDict 里的 key,否则使用数字作为 key 。(下图所示)

# container.py
def __init__(self, *args: Any):
    super(Sequential, self).__init__()
    if len(args) == 1 and isinstance(args[0], OrderedDict):
        for key, module in args[0].items():
            self.add_module(key, module)
    else:
        for idx, module in enumerate(args):
            self.add_module(str(idx), module)

  网络初始化后,得到两个子Modulefeaturesclassifier

在这里插入图片描述

上面图以序号为 key,下面图以自定义的字符串为key

    在进行前向传播时,会进入 LeNet 的forward()函数,首先调用第一个Sequetial容器:self.features,由于self.features也是一个 module,因此会调用_call_impl(self, *input, **kwargs):函数,里面调用result = self.forward(*input, **kwargs),进入nn.Seuqetialforward()函数,在这里依次调用所有的 module。具体过程可参考视频链接-模型容器章节

    在nn.Sequetial中,里面的每个子网络层 module 是使用序号来索引的,即使用数字来作为 key。一旦网络层增多,难以查找特定的网络层,这种情况可以使用 OrderDict (有序字典)。(结果如上图所示)

class LenetSequentialOrderDict(nn.Module):
    def __init__(self, classes):
        super(LenetSequentialOrderDict, self).__init__()

        self.features = nn.Sequential(OrderedDict({
   
            'conv1': nn.Conv2d(3, 6, 5),
            'relu1': nn.ReLU(inplace=True),
            'pool1': nn.MaxPool2d(kernel_size=2, stride=2),
            'conv2': nn.Conv2d(6, 16, 5),
            'relu2': nn.ReLU(inplace=True),
            'pool2': nn.MaxPool2d(kernel_size=2, stride=2),
        }))

        self.classifier = nn.Sequential(OrderedDict({
   
            'fc1': nn.Linear(16*5*5, 120),
            'relu3': nn.ReLU(),
            'fc2': nn.Linear(120, 84),
            'relu4': nn.ReLU(inplace=True),
            'fc3': nn.Linear(84, classes)
        }))

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size()[0], -1)
        x = self.classifier(x)
        return x

3.2.2 nn.ModuleList

nn.ModuleListnn.module 的容器,用于包装一组网络层,以 迭代 方式调用网络层,主要方法如下:

  • append():在ModoleList 后面 添加网络层
  • extend() 拼接 两个ModuleList
  • insert():指定在ModuleList 中位置 插入 网络层
class ModuleList(nn.Module):
    def __init__(self):
        super(ModuleList, self).__init__()
        # 列表生成式,生成20个全连接层,每个全连接层是 10个神经元的网络
        self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(20)])

    def forward(self, x):
        for i, linear in enumerate(self.linears):
            x = linear(x)
        return x

3.2.3 nn.ModuleDict

nn.ModuleDictnn.module 的容器,用于包装一组网络层,以 索引 方式调用网络层,主要方法如下:

  • clear():清空 ModoleDict
  • items():返回可迭代的键值对 (Key-value)
  • keys():返回字典的键(key)
  • values():返回字典的值 (values)
  • pop():返回一对键值,并从字典中删除
class ModuleDict(nn.Module):
    def __init__(self):
        super(ModuleDict, self).__init__()
        self.choices = nn.ModuleDict({
   
            'conv': nn.Conv2d(10, 10, 3),
            'pool': nn.MaxPool2d(3)
        })

        self.activations = nn.ModuleDict({
   
            'relu': nn.ReLU(),
            'prelu': nn.PReLU()   # prelu:有正有负, relu:仅有正
        })

    def forward(self, x, choice, act):
        x = self.choices[choice](x)
        x = self.activations[act](x)
        return x

3.3 卷积层

  对CNN卷积神经网络的描述可参考这篇博文CNN-卷积神经网络

3.3.1 卷积维度

一般情况下,卷积核在几个维度上滑动,就是几维卷积。下面图片引用链接

一维卷积

二维卷积

三维卷积

3.3.2 nn.Conv2d

  对多个二维信号进行二维卷积

nn.Conv2d(in_channels= ,    # 输入通道数
          out_channels= ,   # 输出通道数,等价于卷积核数
          kernel_size= ,    # 卷积核尺寸
          stride=1,         # 步长
          padding=0,        # 填充个数
          dilation=1,       # 空洞卷积大小
          groups=1,         # 分组卷积设置
          bias=True,        # 偏置
          padding_mode='zeros')

转置卷积 Transpose Convolution
  转置卷积(nn.ConvTranspose2d)和部分跨越卷积 (Fractionally-strided Convolution),用于对图像进行上采样 。转置矩阵形状上是一个转置关系,权值完全不一样,则正常矩阵与转置卷积是不可逆的。

详细理解可参考这篇博文一文搞懂反卷积,转置卷积
公式推导细节可参考知乎文章 转置卷积(Transpose Convolution)

正常卷积

转置卷积

3.4 池化层

  池化层函数参数具体参考链接
nn.MaxPool2d 是对二维信号(图像)进行最大化池化。

nn.MaxPool2d(kernel_size,   # 池化核尺寸
             stride=None,     # 步长
             padding=0,       # 填充个数
             dilation=1,      # 池化核间隔大小
             return_indices=False,   # 记录池化像素索引。记录最大值像素所在位置的索引,在最大值反池化上采样时使用
             ceil_mode=False)        # 默认为 False,尺寸向下取整。为 True 时,尺寸向上取整

在这里插入图片描述

nn.AvgPool2d 是对二维信号(图像)进行平均值池化。
nn.MaxUnPool2d 是对二维信号(图像)进行最大值池化上采样。

3.4.1 线性层 nn.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值