PyTorch: nn网络层-卷积层

news2024/12/23 11:06:33

文章和代码已经归档至【Github仓库:https://github.com/timerring/dive-into-AI 】或者公众号【AIShareLab】回复 pytorch教程 也可获取。

文章目录

  • nn网络层-卷积层
    • 1D/2D/3D 卷积
    • 一维卷积
    • 二维卷积
    • 三维卷积
  • 二维卷积:nn.Conv2d()
    • 卷积尺寸计算
      • 简化版卷积尺寸计算
      • 完整版卷积尺寸计算
    • 卷积网络示例
  • 转置卷积:nn.ConvTranspose()
    • 转置卷积尺寸计算
      • 简化版转置卷积尺寸计算
      • 完整版简化版转置卷积尺寸计算

nn网络层-卷积层

1D/2D/3D 卷积

卷积有一维卷积、二维卷积、三维卷积。一般情况下,卷积核在几个维度上滑动,就是几维卷积。比如在图片上的卷积就是二维卷积。

一维卷积

二维卷积

三维卷积

二维卷积:nn.Conv2d()

nn.Conv2d(self, in_channels, out_channels, kernel_size, stride=1,
                 padding=0, dilation=1, groups=1,
                 bias=True, padding_mode='zeros')

这个函数的功能是对多个二维信号进行二维卷积,主要参数如下:

  • in_channels:输入通道数
  • out_channels:输出通道数,等价于卷积核个数
  • kernel_size:卷积核尺寸
  • stride:步长
  • padding:填充宽度,主要是为了调整输出的特征图大小,一般把 padding 设置合适的值后,保持输入和输出的图像尺寸不变。
  • dilation:空洞卷积大小,默认为 1,这时是标准卷积,常用于图像分割任务中,主要是为了提升感受野
  • groups:分组卷积设置,主要是为了模型的轻量化,如在 ShuffleNet、MobileNet、SqueezeNet 中用到
  • bias:偏置

卷积尺寸计算

简化版卷积尺寸计算

这里不考虑空洞卷积,假设输入图片大小为 $ I \times I$,卷积核大小为 k × k k \times k k×k,stride 为 s s s,padding 的像素数为 p p p,图片经过卷积之后的尺寸 $ O $ 如下:

O = I − k + 2 × p s + 1 O = \displaystyle\frac{I -k + 2 \times p}{s} +1 O=sIk+2×p+1

下面例子的输入图片大小为 5 × 5 5 \times 5 5×5,卷积大小为 3 × 3 3 \times 3 3×3,stride 为 1,padding 为 0,所以输出图片大小为 5 − 3 + 2 × 0 1 + 1 = 3 \displaystyle\frac{5 -3 + 2 \times 0}{1} +1 = 3 153+2×0+1=3

完整版卷积尺寸计算

完整版卷积尺寸计算考虑了空洞卷积,假设输入图片大小为 $ I \times I$,卷积核大小为 k × k k \times k k×k,stride 为 s s s,padding 的像素数为 p p p,dilation 为 d d d,图片经过卷积之后的尺寸 $ O $ 如下:。

O = I − d × ( k − 1 ) + 2 × p − 1 s + 1 O = \displaystyle\frac{I - d \times (k-1) + 2 \times p -1}{s} +1 O=sId×(k1)+2×p1+1

卷积网络示例

这里使用 input * channel 为 3,output_channel 为 1 ,卷积核大小为 3 × 3 3 \times 3 3×3 的卷积核nn.Conv2d(3, 1, 3),使用nn.init.xavier_normal*()方法初始化网络的权值。代码如下:

import os
import torch.nn as nn
from PIL import Image
from torchvision import transforms
from matplotlib import pyplot as plt
from common_tools import transform_invert, set_seed

set_seed(3)  # 设置随机种子

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

# convert to tensor
img_transform = transforms.Compose([transforms.ToTensor()])
img_tensor = img_transform(img)
# 添加 batch 维度
img_tensor.unsqueeze_(dim=0)    # C*H*W to B*C*H*W

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

# ================ 2d
flag = 1
# flag = 0
if flag:
    conv_layer = nn.Conv2d(3, 1, 3)   # input:(i, o, size) weights:(o, i , h, w)
    # 初始化卷积层权值
    nn.init.xavier_normal_(conv_layer.weight.data)
	# nn.init.xavier_uniform_(conv_layer.weight.data)
    # calculation
    img_conv = conv_layer(img_tensor)

# ================ transposed
# flag = 1
flag = 0
if flag:
    conv_layer = nn.ConvTranspose2d(3, 1, 3, stride=2)   # input:(input_channel, output_channel, size)
    # 初始化网络层的权值
    nn.init.xavier_normal_(conv_layer.weight.data)

    # calculation
    img_conv = conv_layer(img_tensor)

# ================================= visualization ==================================
print("卷积前尺寸:{}\n卷积后尺寸:{}".format(img_tensor.shape, img_conv.shape))
img_conv = transform_invert(img_conv[0, 0:1, ...], img_transform)
img_raw = transform_invert(img_tensor.squeeze(), img_transform)
plt.subplot(122).imshow(img_conv, cmap='gray')
plt.subplot(121).imshow(img_raw)
plt.show()

通过conv_layer.weight.shape查看卷积核的 shape 是(1, 3, 3, 3),对应是(output_channel, input_channel, kernel_size, kernel_size)。所以第一个维度对应的是卷积核的个数,每个卷积核都是(3,3,3)。虽然每个卷积核都是 3 维的,执行的却是 2 维卷积。下面这个图展示了这个过程。

也就是每个卷积核在 input_channel 维度再划分,这里 input_channel 为 3,那么这时每个卷积核的 shape 是(3, 3)。3 个卷积核在输入图像的每个 channel 上卷积后得到 3 个数,把这 3 个数相加,再加上 bias,得到最后的一个输出。

转置卷积:nn.ConvTranspose()

转置卷积又称为反卷积 (Deconvolution) 和部分跨越卷积 (Fractionally strided Convolution),用于对图像进行上采样。

正常卷积如下:

原始的图片尺寸为 4 × 4 4 \times 4 4×4,卷积核大小为 3 × 3 3 \times 3 3×3 p a d d i n g = 0 padding =0 padding=0 s t r i d e = 1 stride = 1 stride=1。由于卷积操作可以通过矩阵运算来解决,因此原始图片可以看作 16 × 1 16 \times 1 16×1 的矩阵 I 16 × 1 I_{16 \times 1} I16×1

为什么是16 * 1,因为16是它所有的像素点个数,1是它的图片张数。

卷积核可以看作 4 × 16 4 \times 16 4×16 的矩阵 K 4 × 16 K_{4 \times 16} K4×16,其中,那么输出是 K 4 × 16 × I 16 × 1 = O 4 × 1 K_{4 \times 16} \times I_{16 \times 1} = O_{4 \times 1} K4×16×I16×1=O4×1 。(是卷积核 * 图像)

这里的4是输出特征图像素值的总个数,16是通过卷积核补零,符合原图片像素点个数得到的。

转置卷积如下:

原始的图片尺寸为 2 × 2 2 \times 2 2×2,卷积核大小为 3 × 3 3 \times 3 3×3 p a d d i n g = 0 padding =0 padding=0 s t r i d e = 1 stride = 1 stride=1。由于卷积操作可以通过矩阵运算来解决,因此原始图片可以看作 4 × 1 4 \times 1 4×1 的矩阵 I 4 × 1 I_{4 \times 1} I4×1

这里的4同样是原图的像素点个数。

卷积核可以看作 4 × 16 4 \times 16 4×16 的矩阵 K 16 × 4 K_{16 \times 4} K16×4

这里的4不再是通过补零得到的,而是通过剔除得到的。如上图,本来卷积核有9个像素点,但是在实际的情况中卷积核最大只能计算到4个像素点,因此这里就是4。

16是根据输入公式计算得到的输出图片的大小。

那么输出是 K 16 × 4 × I 4 × 1 = O 16 × 1 K_{16 \times 4} \times I_{4 \times 1} = O_{16 \times 1} K16×4×I4×1=O16×1

正常卷积核转置卷积矩阵的形状刚好是转置关系,因此称为转置卷积,但里面的权值不是一样的,卷积操作也是不可逆的,简单来讲,就是一张图片经过卷积,然后再经过转置卷积,无法得到原来的图片。

PyTorch 中的转置卷积函数如下:

nn.ConvTranspose2d(self, in_channels, out_channels, kernel_size, stride=1,
                 padding=0, output_padding=0, groups=1, bias=True,
                 dilation=1, padding_mode='zeros')

和普通卷积的参数基本相同。

转置卷积尺寸计算

简化版转置卷积尺寸计算

这里不考虑空洞卷积,假设输入图片大小为 $ I \times I$,卷积核大小为 k × k k \times k k×k,stride 为 s s s,padding 的像素数为 p p p,图片经过卷积之后的尺寸 $ O $ 如下,刚好和普通卷积的计算是相反的:

O = ( I − 1 ) × s + k O = (I-1) \times s + k O=(I1)×s+k

 out  size  = (  in  size  − 1 ) ∗ s t r i d e +  kernel  size  \text { out } _{\text {size }}=\left(\text { in }_{\text {size }}-1\right) * s t r i d e+\text { kernel }_{\text {size }}  out size =( in size 1)stride+ kernel size 

完整版简化版转置卷积尺寸计算

O = ( I − 1 ) × s − 2 × p + d × ( k − 1 ) + o u t p a d d i n g + 1 O = (I-1) \times s - 2 \times p + d \times (k-1) + out_padding + 1 O=(I1)×s2×p+d×(k1)+outpadding+1

转置卷积代码示例如下:

import os
import torch.nn as nn
from PIL import Image
from torchvision import transforms
from matplotlib import pyplot as plt
from common_tools import transform_invert, set_seed

set_seed(3)  # 设置随机种子

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

# convert to tensor
img_transform = transforms.Compose([transforms.ToTensor()])
img_tensor = img_transform(img)
# 添加 batch 维度
img_tensor.unsqueeze_(dim=0)    # C*H*W to B*C*H*W

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

# ================ 2d
# flag = 1
flag = 0
if flag:
    conv_layer = nn.Conv2d(3, 1, 3)   # input:(i, o, size) weights:(o, i , h, w)
    # 初始化卷积层权值
    nn.init.xavier_normal_(conv_layer.weight.data)
    # nn.init.xavier_uniform_(conv_layer.weight.data)

    # calculation
    img_conv = conv_layer(img_tensor)

# ================ transposed
flag = 1
# flag = 0
if flag:
    conv_layer = nn.ConvTranspose2d(3, 1, 3, stride=2)   # input:(input_channel, output_channel, size)
    # 初始化网络层的权值
    nn.init.xavier_normal_(conv_layer.weight.data)

    # calculation
    img_conv = conv_layer(img_tensor)

# ================================= visualization ==================================
print("卷积前尺寸:{}\n卷积后尺寸:{}".format(img_tensor.shape, img_conv.shape))
img_conv = transform_invert(img_conv[0, 0:1, ...], img_transform)
img_raw = transform_invert(img_tensor.squeeze(), img_transform)
plt.subplot(122).imshow(img_conv, cmap='gray')
plt.subplot(121).imshow(img_raw)
plt.show()

转置卷积前后图片显示如下,左边原图片的尺寸是 (512, 512),右边转置卷积后的图片尺寸是 (1025, 1025)。

转置卷积后的图片一般都会有棋盘效应,像一格一格的棋盘,这是转置卷积的通病。

关于棋盘效应的解释以及解决方法,推荐阅读Deconvolution And Checkerboard Artifacts。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/747641.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为路由器如何通过Console口进行基本配置

华为HCIA试听课程:不会传输层协议,HCIA都考不过https://mp.weixin.qq.com/s/oKAL8GvdrcHEb5O_8bEZZQ 思科CCNA试听课程:适合初学者:VLAN原理与配置https://mp.weixin.qq.com/s/toIJg1EVFImalrwzbTONTQ 组网图形 组网需求 通过Cons…

【2023,学点儿新Java-31】测试:整型和浮点型变量的使用 | 附:计算机存储单位(转换关系)| 企业真题:为什么0.1+0.2不等于0.3

前情提要: 【2023,学点儿新Java-30】变量的基本使用:变量的意义 | 变量的构成要素 | Java中变量的数据类型、变量的使用 | 附:Java中变量的作用域 | 数据类型、变量名和变量值哪个最重要?【2023,学点儿新J…

vue中使用v-for实现两次嵌套循环,判断某子元素是否显示,进行复杂表单校验

一、需求场景: 有以下一个使用场景,名称111、名称222、名称333,是放在一个大数组里的,然后通过第一层for循环显示出来的。名称333数组里又包含自己的子数组,子数组再通过第二次for循环展示出来。当我们选择发放方式的…

基于Javaweb实现ATM机系统开发实战(七)用户密码修改

接下来我们完成密码修改的功能&#xff0c;还是老规矩先看前端界面&#xff1a;这里我们先把需要的变量进行修改&#xff0c;然后把卡号变成不可修改&#xff1a; <% page language"java" contentType"text/html; charsetUTF-8" pageEncoding"UTF-…

深度挖掘文物价值,VR博物馆讲好文物故事

文物不言&#xff0c;自有春秋。丝绸、字画、瓷器、古玩等&#xff0c;铺陈的是传奇&#xff0c;激荡的是灵魂。历史文物珍贵的莫过于其历史与文化的价值&#xff0c;倘若不能被更多的人欣赏、研究、传承&#xff0c;那么这些文物就很难实现“价值外溢”。 单纯的去读历史课本&…

分层解耦-三层架构

三层架构 在上篇文章的案例中写文章-CSDN创作中心 的Controller类承担了对于数据操作&#xff08;访问&#xff09;、对于对于数据的逻辑处理、以及接受请求响应数据的工作&#xff0c;对于类似的小项目来说冗杂程度还可以接收&#xff0c;但是如果项目更加复杂&#xff0c;就…

QT使用同一按钮实现打开/关闭新窗口

QT使用同一按钮实现【打开/关闭】新窗口&#xff0c;实现方案如下&#xff1a; 使用一个全局状态变量记录窗口打开状态通过该状态实现新窗口的show和close 实现代码如下&#xff1a; #include "mainwindow.h" #include "ui_mainwindow.h" #include "…

怎么用PDF24 Tools工具在线进行PDF文件合并

PDF文件是经常会被用到&#xff0c;它在我们的日常生活和工作中扮演着重要的角色。PDF文件合并是将多个PDF文件合并为单个文件&#xff0c;这个过程通常是为了方便管理多个PDF文件&#xff0c;或者将多个PDF文件合并为一个整体以便于共享或打印。既然如此&#xff0c;如何快速合…

达梦sql执行计划、HINT、索引简单应用

目录 收集统计信息. 3 1. 通过DBMS_STATS包中的方法. 3 2、删除指定表的统计信息. 3 执行计划. 3 常用执行计划操作符. 4 统计指定sql执行号的所有操作符的执行时间. 5 HINT 5 并行操作&#xff1a;. 6 查询计划重用、结果集重用. 7 示例. 8 1、收集统计信息&#x…

Comparable/Comparator

现在有一个自定义学生的学生类,里面有name属性,和age属性,我们如何去比较大小? class Student{public String name;public int age;public Student(String name, int age) {this.name name;this.age age;}Overridepublic String toString() {return "Student{" &…

路径规划算法:基于广义正态分布优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于广义正态分布优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于广义正态分布优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用…

关于博客更新的二三事

原文链接&#xff1a;关于博客更新的二三事 前言 很显然&#xff0c;正如大家所见到的&#xff0c;这一版本主题v4.7.0进行了大量的删减工作。可能正如 “大道至简” 吧&#xff0c;相比于前一版本 v3.7.1 &#xff0c;个人认为可能有点花哨&#xff08;仅个人认为&#xff09…

uni-app使用plus本地推送通知栏信息,不使用第三方个推实现消息在线统一推送、消息通知(MQTT、WebSocket、setInterval定时器)

plus.push.createMessage() 因项目一直是运行在内网&#xff0c;所以不支持使用uni-push等运行在公网的第三方个推渠道。 那就只能使用plus.push.createMessage()&#xff0c;示例代码如下&#xff1a; let content "您有一条新的消息~"; let options {"cov…

玩转CSS基础:CSS盒模型

CSS盒模型 什么是CSS盒模型&#xff1f; 完整的 CSS 盒模型应用于块级盒子&#xff0c;内联盒子只使用盒模型中定义的部分内容。模型定义了盒的每个部分 —— margin, border, padding, and content &#xff0c;合在一起就是在页面上看到的内容。为了增加一些额外的复杂性&a…

操作系统Linuxday04

Linux用户相关 Linux是多用户多任务&#xff0c;可以支持多个用户同时登录&#xff0c;并且多个用户可以执行不同的任务&#xff0c;互不影响。 不同的用户&#xff0c;有不同的权限&#xff0c;可以完成权限以内的不同的任务 用户组 如果一次性用户太多&#xff0c;分别给…

【嵌入式Linux项目】基于Linux的全志H616开发板智能垃圾桶项目

目录 一、功能需求 二、涵盖的知识点 1、wiringPi库下的相关硬件操作函数调用 2、线程&#xff08;未使用互斥锁和条件&#xff09; 3、父子进程 4、网络编程&#xff08;socket套接字&#xff09; 5、进程间通信&#xff08;共享内存和信号量&#xff09; 三、开发环境…

[MySQL]MySQL内置函数

[MySQL]MySQL内置函数 文章目录 [MySQL]MySQL内置函数1. 日期函数2. 字符串函数3. 数学函数4. 其他函数 1. 日期函数 常用日期函数如下&#xff1a; 函数名称描述current_date()获取当前日期current_time()获取当前时间current_timestamp()获取当前时间戳now()获取当前日期时…

Redis_安装配置(2)

目录 一、安装redis 1、安装gcc依赖 2、下载并解压安装包 3、编译 4、安装 5、设置全局命令 二、启动redis 1、前台启动 2、后台启动 2.1 修改redis.conf文件 2.2 使用指定配置启动redis 2.3 kill redis的进程 3、开机启动 三、配置redis 远程访问设置 设置密码…

Magic3D: High-Resolution Text-to-3D Content Creation(高分辨率文本到3d内容创建)

Magic3D: High-Resolution Text-to-3D Content Creation&#xff08;高分辨率文本到3d内容创建&#xff09; Paper&#xff1a;https://readpaper.com/pdf-annotate/note?pdfId4738271534435532801&noteId1848084184935912192 Project&#xff1a;https://research.nvidia…

InstructGPT:语言模型的人类反馈指令对齐

论文标题&#xff1a;Training language models to follow instructions with human feedback论文链接&#xff1a;https://arxiv.org/abs/2203.02155论文来源&#xff1a;OpenAI 一、概述 大型语言模型&#xff08;Large language models&#xff0c;LLMs&#xff09;可以通过…