Pytorch学习之torch.nn.functional.pad()函数

PyTorch学习之torch.nn.functional.pad函数

一、简介

torch.nn.functional.pad 是 PyTorch 中用于对张量进行填充操作的函数。填充操作在处理图像、序列数据等任务时非常常见,它可以在张量的指定维度两端添加一定数量的元素,填充方式多样,包括零填充、常数填充、反射填充和边界填充等。

二、基本语法

torch.nn.functional.pad(input, pad, mode='xxx', value=x)

三、参数说明

  • input (Tensor): 输入的张量。
  • pad (tuple): 指定每个维度填充的数目。格式为 (left, right, top, bottom, …)。
  • mode (str, 可选): 填充模式,包括 constant(常数填充,默认)、reflect(反射填充)、replicate(边界填充)和 circular(循环填充)。
  • value (float, 可选): 常数填充模式下填充值,仅当 mode 为 ‘constant’ 时有效,其他模式时即使指定了值也会被忽略掉。

四、返回值

返回一个新的张量,对输入张量进行了指定方式的填充。

五、填充模式详解

在详细讲解和演示每一种模式的效果前,我想对填充的一些规则进行提前说明:

  • 我们会填充【 d i m = l e n ( p a d ) 2 \mathrm{dim=\frac{len(pad)}{2}} dim=2len(pad)】个维度

    举个例子:有一个(4, 4)形状的矩阵,我给的pad=(1,1),那么根据公式 d i m = 2 2 = 1 \mathrm{dim=\frac22=1} dim=22=1因此我们只填充1个维度。有人想,既然只填充1个维度,那为什么给两个值?

    矩阵是4x4的,有横向有纵向对吧,最后一个维度肯定是横向的(我们常说矩阵存储是行优先的),此时矩阵是不是有左右两边?那么给出的2个填充值分别对应于在左边(left)要填充1个像素,在右边(right)要填充一个像素。

    同样的随着维度扩展,pad可以提供更长的参数,如pad=(1, 1, 2, 2, 3, 3),根据公式填充3个维度,哪3个?(left, right, top, bottom, front, back)

  • 填充是从内向外的:例如pad=(1, 1, 2, 2, 3, 3),(1, 1)对应填充(left, right),(2, 2)对应填充(top, bottom),(3, 3)对应填充(front, back)

5.1 constant模式

在该模式下,我们必须指定参数value,value的值将填充到我们扩充的区域。

例如有如下代码:

import torch
import torch.nn as nn

data = torch.tensor([[
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16]
]])

print(data.size())
print(data)
paddata1 = nn.functional.pad(data, (1, 1, 1, 1), mode="constant", value=1)
print(paddata1.size())
print(paddata1)

输出:

torch.Size([1, 4, 4])
tensor([[[ 1,  2,  3,  4],
         [ 5,  6,  7,  8],
         [ 9, 10, 11, 12],
         [13, 14, 15, 16]]])
torch.Size([1, 6, 6])
tensor([[[ 1,  1,  1,  1,  1,  1],
         [ 1,  1,  2,  3,  4,  1],
         [ 1,  5,  6,  7,  8,  1],
         [ 1,  9, 10, 11, 12,  1],
         [ 1, 13, 14, 15, 16,  1],
         [ 1,  1,  1,  1,  1,  1]]])

可以看到,我们在(left,right,top,bottom)四个方向都填充了一个像素,像素值=value

5.2 reflect模式

该模式分我们既可以说是反射模式,也可以说是镜像模式,当然我个人认为镜像模式更形象:

我们看代码:

import torch
import torch.nn as nn

data = torch.tensor([[
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16]
]])

print(data.size())
print(data)
paddata2 = nn.functional.pad(data, (1, 1, 1, 1), mode="reflect", value=0) # value指定值将无效
print(paddata2.size())
print(paddata2)

输出:

torch.Size([1, 4, 4])
tensor([[[ 1,  2,  3,  4],
         [ 5,  6,  7,  8],
         [ 9, 10, 11, 12],
         [13, 14, 15, 16]]])
torch.Size([1, 6, 6])
tensor([[[ 6,  5,  6,  7,  8,  7],
         [ 2,  1,  2,  3,  4,  3],
         [ 6,  5,  6,  7,  8,  7],
         [10,  9, 10, 11, 12, 11],
         [14, 13, 14, 15, 16, 15],
         [10,  9, 10, 11, 12, 11]]])

此刻,我们来看,为什么说用镜像一词更贴切:

  • 第1列是以第2列为镜子的第3列的镜像
  • 最后1列是以倒数第2列为镜子的倒数第3列的镜像
  • 左上角的6是以1为镜子的6的镜像,右上角的7是以4为镜子的7的镜像
  • 以此类推,可以看出符合我们的说法

再看一组测试,此时我们将填充语句变更为

paddata2 = nn.functional.pad(data, (2, 1, 1, 1), mode="reflect", value=0)

输出:

torch.Size([1, 4, 4])
tensor([[[ 1,  2,  3,  4],
         [ 5,  6,  7,  8],
         [ 9, 10, 11, 12],
         [13, 14, 15, 16]]])
torch.Size([1, 6, 7])
tensor([[[ 7,  6,  5,  6,  7,  8,  7],
         [ 3,  2,  1,  2,  3,  4,  3],
         [ 7,  6,  5,  6,  7,  8,  7],
         [11, 10,  9, 10, 11, 12, 11],
         [15, 14, 13, 14, 15, 16, 15],
         [11, 10,  9, 10, 11, 12, 11]]])

读者体会一下吧,看看此时各方向的镜子是哪些列?被镜像的又是哪一列?相信读者通过这两个实例对该填充模式有比较清晰的认识。

5.3 replicate模式

该模式称为复制模式拷贝模式:其将数据的边缘(1像素)进行原封不动的拷贝。说起来抽象,直接上代码:

import torch
import torch.nn as nn

data = torch.tensor([[
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16]
]])

print(data.size())
print(data)
paddata3 = nn.functional.pad(data, (1, 1, 1, 1), mode="replicate")
print(paddata3)
print(paddata3)

输出:

torch.Size([1, 4, 4])
tensor([[[ 1,  2,  3,  4],
         [ 5,  6,  7,  8],
         [ 9, 10, 11, 12],
         [13, 14, 15, 16]]])
torch.Size([1, 6, 6])
tensor([[[ 1,  1,  2,  3,  4,  4],
         [ 1,  1,  2,  3,  4,  4],
         [ 5,  5,  6,  7,  8,  8],
         [ 9,  9, 10, 11, 12, 12],
         [13, 13, 14, 15, 16, 16],
         [13, 13, 14, 15, 16, 16]]])

从输出易得,确实是将边缘进行了复制,这样做可以使得我们对张量进行扩充填充后,张量的边缘信息不变:图像处理时,这种机制会经常用到。

如果修改pad参数,会修改拷贝的列数吗?我们对填充语句做如下修改:

paddata3 = nn.functional.pad(data, (2, 1, 4, 1), mode="replicate")

输出:

torch.Size([1, 4, 4])
tensor([[[ 1,  2,  3,  4],
         [ 5,  6,  7,  8],
         [ 9, 10, 11, 12],
         [13, 14, 15, 16]]])
torch.Size([1, 9, 7])
tensor([[[ 1,  1,  1,  2,  3,  4,  4],
         [ 1,  1,  1,  2,  3,  4,  4],
         [ 1,  1,  1,  2,  3,  4,  4],
         [ 1,  1,  1,  2,  3,  4,  4],
         [ 1,  1,  1,  2,  3,  4,  4],
         [ 5,  5,  5,  6,  7,  8,  8],
         [ 9,  9,  9, 10, 11, 12, 12],
         [13, 13, 13, 14, 15, 16, 16],
         [13, 13, 13, 14, 15, 16, 16]]])

从输出可以看出,不论你怎么修改pad参数元组,被拷贝的总是一个像素宽的边缘。而你更改的填充宽度如果大于1,至于将1像素边缘复制多次罢了。

5.4 circular模式

该模式称为循环填充模式,它是怎么干的呢?以2维矩阵上下左右均填充1个像素为例,它的填充值取自其对立面:左侧填充列的值=原矩阵最右侧1列的值,右侧填充列的值=原矩阵最左侧1列的值;上下同理,直接看代码:

import torch
import torch.nn as nn

data = torch.tensor([[
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16]
]])

print(data.size())
print(data)
paddata4 = nn.functional.pad(data, (1, 1, 1, 1), mode="circular", value=0)
print(paddata4.size())
print(paddata4)

输出:

torch.Size([1, 4, 4])
tensor([[[ 1,  2,  3,  4],
         [ 5,  6,  7,  8],
         [ 9, 10, 11, 12],
         [13, 14, 15, 16]]])
torch.Size([1, 6, 6])
tensor([[[16, 13, 14, 15, 16, 13],
         [ 4,  1,  2,  3,  4,  1],
         [ 8,  5,  6,  7,  8,  5],
         [12,  9, 10, 11, 12,  9],
         [16, 13, 14, 15, 16, 13],
         [ 4,  1,  2,  3,  4,  1]]])

从输出可得,我们的解释是正确的。

哪如果我要填充多个像素又是什么样的效果?我们将填充语句进行修改如下:

paddata4 = nn.functional.pad(data, (2, 3, 1, 1), mode="circular", value=0)

输出:

torch.Size([1, 4, 4])
tensor([[[ 1,  2,  3,  4],
         [ 5,  6,  7,  8],
         [ 9, 10, 11, 12],
         [13, 14, 15, 16]]])
torch.Size([1, 6, 9])
tensor([[[15, 16, 13, 14, 15, 16, 13, 14, 15],
         [ 3,  4,  1,  2,  3,  4,  1,  2,  3],
         [ 7,  8,  5,  6,  7,  8,  5,  6,  7],
         [11, 12,  9, 10, 11, 12,  9, 10, 11],
         [15, 16, 13, 14, 15, 16, 13, 14, 15],
         [ 3,  4,  1,  2,  3,  4,  1,  2,  3]]])

读者可以自行体会一下,该模式下,它的多像素填充有什么规律。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DIYGW UniApp低代码可视化平台:高效、灵活、安全的应用开发新途径

一、引言 在数字化快速发展的今天,企业对于快速构建多端应用的需求日益增长。然而,传统的应用开发方式往往面临周期长、成本高、技术门槛高等问题。为了解决这些问题,DIYGW UniApp低代码可视化平台应运而生,它以高效率、多端使用…

动态人物抠图换背景 MediaPipe

pip下载 MediaPipe pip install mediapipe -i 手部特征点模型包包含一个手掌检测模型和一个手部特征点检测模型。手掌检测模型在输入图片中定位手部,手部特征点检测模型可识别手掌检测模型定义的被剪裁手掌图片上的特定手部特征点。 由于运行手掌检测模型非常耗时&…

面试突击:HashMap 源码详解

本文已收录于:https://github.com/danmuking/all-in-one(持续更新) 数据结构 JDK1.8 之前 JDK1.8 之前 HashMap 采用 数组和链表 结合的数据结构。如下图: HashMap 将 key 的 hashCode 经过扰动函数处理过后得到 hash 值&#…

用C/C++写一个客户端和服务器之间进行TCP通信的DEMO

目录 一、Visual Sudio 2022 二、配置 三、说明 四、客户端 五、服务端 六、演示 一、Visual Sudio 2022 Visual Studio 2022是微软公司推出的一款集成开发环境(IDE),旨在为开发人员提供全面的工具集,支持从Windows到MacOS…

【算法专题--链表】两数相加 -- 高频面试题(图文详解,小白一看就懂!!)

目录 一、前言 二、题目描述 三、解题方法 ⭐双指针 -- 模拟进位 (使用哨兵位头节点) 🥝 什么是哨兵位头节点? 🍇思路解析 🍍案例图解 四、总结与提炼 五、共勉 一、前言 两数相加 这道题,可以说是--…

Linux Swap

Swap: 页面换出:就是在 Swap 机制下,当内存资源紧张时,内核就会把不经常使用的这些匿名页中的数据写入到 Swap 分区或者 Swap 文件中。从而释放这些数据所占用的内存空间。 页面换入:就是当进程再次访问那些被换出的数据时&…

如何修复Power BI【View usage metrics report】指标报表数据源更新问题?

故事背景 有朋友留言询问:通过我之前写的 想知道Power BI用户访问报告的次数?快来学习! 这篇文章,了解了如何查看Power BI用户访问报告的详情。 但是最近由于创建【View usage metrics report】指标报表的小伙伴离职了&#x…

【数据可视化技术】1、如何使用Matplotlib和Seaborn库在Python中绘制热力图

热力图是一种数据可视化技术,可以显示变量之间的相关性。这个代码段是数据分析和可视化的常用方法,特别适合于展示变量之间的相关性,对于数据科学和机器学习项目非常有帮助。 1、 导入必要的库 首先,确保你已经安装了matplotlib…

苏州网站建设好做吗

苏州网站建设是一个非常热门的行业,由于苏州地理位置优越、经济发达、人口众多,所以网站建设市场也非常火爆。但是在苏州网站建设这个行业中,竞争也是非常激烈的,所以想要在这个市场中脱颖而出并不是件容易的事情。 首先&#xff…

break和continue的标签使用

break标签的使用 break label是退出label对应的循环 //BreakDetail.java //2024.06.29 public class BreakDetail{public static void main(String[] args) {label1:for(int j 0; j < 4; j){label2:for(int i 0; i < 10; i){if(i 2){//break; //情况1//break label2…

信息系统项目管理师(项目整合管理)补充

项目管理信息系统&#xff1a;给项目提供了IT软件工具&#xff0c;例如进度计划软件工具、工作授权系统、配置管理系统、信息收集与发布系统&#xff0c;或其他基于IT技术的工具。以及进入其他在线信息系统&#xff08;如知识库&#xff09;的登录界面&#xff0c;支持自动收集…

应用部署方式演变

应用部署方式演变 1.传统部署2.虚拟化部署3.容器化部署 1.传统部署 传统的应用程序部署是将多个应用程序直接部署在操作系统上&#xff0c;一旦其中的某个应用程序出现内存泄漏&#xff0c;那么该程序就会大量吞噬系统内容空间&#xff0c;导致其他应用程序无法正常运行。 2.虚…

docker 学习之路

文章目录 1、官方文档2、常用命令挂载Docker容器内运行的脚本或命令常用 3、介绍4、Dockerfile5、问题6、链接 ​ 1、官方文档 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的 Linux…

人工智能在多模态多组学领域的最新研究进展|顶刊速递·24-06-29

小罗碎碎念 本期推文主题&#xff1a;人工智能在多模态与多组学中的最新研究进展 今天这期推文比较特殊&#xff0c;起来就开始干活&#xff0c;只能跑来会场写了。 小罗观点 今天这期推文覆盖面挺广的&#xff0c;前四篇与肿瘤治疗相关&#xff0c;并且两篇都直接与免疫微环境…

【算法学习】射线法判断点在多边形内外(C#)以及确定内外两点连线与边界的交点

1.前言&#xff1a; 在GIS开发中&#xff0c;经常会遇到确定一个坐标点是否在一块区域的内部这一问题。 如果这个问题不是一个单纯的数学问题&#xff0c;例如&#xff1a;在判断DEM、二维图像像素点、3D点云点等含有自身特征信息的这些点是否在一个区域范围内部的时候&#x…

eclipse基础工程配置( tomcat配置JRE环境)

文章目录 I eclipse1.1 工程配置1.2 编译工程1.3 添加 JRE for the project build pathII tomcat配置JRE环境2.1 Eclipse编辑tomcat运行环境(Mac版本)2.2 Eclipse编辑tomcat运行环境(windows版本)2.3 通过tomcat7W.exe配置运行环境(windows系统)I eclipse 1.1 工程配置 …

C++笔记:实现一个字符串类(构造函数、拷贝构造函数、拷贝赋值函数)

实现一个字符串类String&#xff0c;为其提供可接受C风格字符串的构造函数、析构函数、拷贝构造函数和拷贝赋值函数。 声明依赖文件 其中ostream库用于打印标准输入输出&#xff0c;cstring库为C风格的字符串库 #include <iostream> #include <cstring> 声明命…

Matplotlib绘制并列的条形图:每个类别有多个条形并排显示

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

大语言模型LLM基础:推理/不同模型/量化对显存、推理速度和性能的影响

通过本文&#xff0c;你将了解以下几个方面的内容&#xff1a; 要运行一个LLM需要多少显存&#xff1f;&#xff08;我的GPU可以运行多大LLM&#xff1f;&#xff09;不同LLM推理速度如何&#xff1f;量化对显存、推理速度和性能的影响&#xff1f;vLLM、DeepSeed等工具的加速…

您还在为企业无公网独立IP而烦恼吗?

#IBCS虚拟专线# 企业对于高效、稳定且经济实惠的网络解决方案的需求愈发迫切。作为一家企业的技术负责人&#xff0c;我有幸接触并采用了 IBCS 虚拟专线&#xff0c;它的出现&#xff0c;犹如一道曙光&#xff0c;解决了我们长期以来面临的诸多网络难题。 我们企业是一家处于…