理解张量拼接(torch.cat)

拼接

维度顺序:对于 3D 张量,通常可以理解为 (深度, 行, 列) 或 (批次, 行, 列)。 选择一个dim进行拼接的时候其他两个维度大小要相等
![[Pasted image 20240808214248.png]]

对于三维张量,理解 torch.catdim 参数确实变得更加抽象,但原理是相同的。让我们通过一个具体的例子来说明这一点。

import torch# 创建两个 3D 张量
a = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
b = torch.tensor([[[9, 10], [11, 12]], [[13, 14], [15, 16]]])print("Tensor a shape:", a.shape)
print(a)
print("\nTensor b shape:", b.shape)
print(b)# dim=0 连接
c_dim0 = torch.cat([a, b], dim=0)
print("\nResult of torch.cat([a, b], dim=0):")
print("Shape:", c_dim0.shape)
print(c_dim0)# dim=1 连接
c_dim1 = torch.cat([a, b], dim=1)
print("\nResult of torch.cat([a, b], dim=1):")
print("Shape:", c_dim1.shape)
print(c_dim1)# dim=2 连接
c_dim2 = torch.cat([a, b], dim=2)
print("\nResult of torch.cat([a, b], dim=2):")
print("Shape:", c_dim2.shape)
print(c_dim2)

现在让我们详细解释这个三维张量的例子:

  1. 初始张量:

    • ab 都是形状为 (2, 2, 2) 的 3D 张量。
    • 可以将它们想象成两个 2x2 的矩阵堆叠在一起。
  2. dim=0 连接:

    • 结果形状:(4, 2, 2)
    • 这相当于在第一个维度上堆叠张量。
    • 可以理解为将 b 放在 a 的"下面",增加了第一个维度的大小。
  3. dim=1 连接:

    • 结果形状:(2, 4, 2)
    • 这相当于在第二个维度上堆叠张量。
    • 可以理解为在每个 2x2 矩阵的"行"方向上扩展,将 b 的行添加到 a 的每个对应部分的下方。
  4. dim=2 连接:

    • 结果形状:(2, 2, 4)
    • 这相当于在第三个维度(最内层)上堆叠张量。
    • 可以理解为在每个 2x2 矩阵的"列"方向上扩展,将 b 的列添加到 a 的每个对应部分的右侧。

理解三维张量 torch.cat 的关键点:

  1. 维度顺序:对于 3D 张量,通常可以理解为 (深度, 行, 列) 或 (批次, 行, 列)。

  2. dim=0:增加"深度"或"批次"的数量。

  3. dim=1:增加每个"深度"层或"批次"中的行数。

  4. dim=2:增加每行中的元素数量(列数)。

  5. 保持其他维度:除了被连接的维度,其他维度的大小保持不变。

  6. 形状变化:只有指定的 dim 对应的维度大小会改变(增加),其他维度大小保持不变。

  7. 一致性:要连接的张量在非连接维度上的大小必须相同。

3D Matrix Visualization

Let’s visualize the 3D matrices a and b, and their concatenation results.

Matrix a (2x2x2):
Depth 0:    Depth 1:
+---+---+   +---+---+
| 1 | 2 |   | 5 | 6 |
+---+---+   +---+---+
| 3 | 4 |   | 7 | 8 |
+---+---+   +---+---+
Matrix b (2x2x2):
Depth 0:    Depth 1:
+----+----+ +----+----+
| 9  | 10 | | 13 | 14 |
+----+----+ +----+----+
| 11 | 12 | | 15 | 16 |
+----+----+ +----+----+

Concatenation Results:

dim=0 (4x2x2):
Depth 0:    Depth 1:    Depth 2:    Depth 3:
+---+---+   +---+---+   +----+----+ +----+----+
| 1 | 2 |   | 5 | 6 |   | 9  | 10 | | 13 | 14 |
+---+---+   +---+---+   +----+----+ +----+----+
| 3 | 4 |   | 7 | 8 |   | 11 | 12 | | 15 | 16 |
+---+---+   +---+---+   +----+----+ +----+----+
dim=1 (2x4x2):
Depth 0:        Depth 1:
+---+---+       +---+---+
| 1 | 2 |       | 5 | 6 |
+---+---+       +---+---+
| 3 | 4 |       | 7 | 8 |
+---+---+       +---+---+
| 9 | 10 |      | 13| 14|
+---+---+       +---+---+
| 11| 12 |      | 15| 16|
+---+---+       +---+---+
dim=2 (2x2x4):
Depth 0:        Depth 1:
+---+---+---+---+   +---+---+---+---+
| 1 | 2 | 9 | 10|   | 5 | 6 | 13| 14|
+---+---+---+---+   +---+---+---+---+
| 3 | 4 | 11| 12|   | 7 | 8 | 15| 16|
+---+---+---+---+   +---+---+---+---+

当然可以!让我们通过具体的例子来形象地解释不同维度上的拼接。

定义张量

首先,定义三个张量 x, y, z,它们分别具有如下形状:

  • x 的形状是 [2, 1, 3]
  • y 的形状是 [2, 3, 3]
  • z 的形状是 [2, 2, 3]
import torchx = torch.tensor([[[0, 0, 0]], [[0, 0, 0]]])
y = torch.tensor([[[0, 0, 0], [0, 0, 0], [0, 0, 0]],[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
])
z = torch.tensor([[[0, 0, 0], [0, 0, 0]],[[0, 0, 0], [0, 0, 0]]
])

(1) 在 dim=0 上拼接

dim=0 上拼接,相当于增加“深度”或“批次”的数量。每个张量的“深度”都会堆叠起来。

w_dim0 = torch.cat([x, y, z], dim=0)
print(w_dim0.shape)

形象解释

x:
[[[0, 0, 0]],  # 第一层深度[[0, 0, 0]]   # 第二层深度
]y:
[[[0, 0, 0], [0, 0, 0], [0, 0, 0]],  # 第一层深度[[0, 0, 0], [0, 0, 0], [0, 0, 0]]   # 第二层深度
]z:
[[[0, 0, 0], [0, 0, 0]],  # 第一层深度[[0, 0, 0], [0, 0, 0]]   # 第二层深度
]拼接结果 w_dim0:
[[[0, 0, 0]],  # x 第一层深度[[0, 0, 0]],  # x 第二层深度[[0, 0, 0], [0, 0, 0], [0, 0, 0]],  # y 第一层深度[[0, 0, 0], [0, 0, 0], [0, 0, 0]],  # y 第二层深度[[0, 0, 0], [0, 0, 0]],  # z 第一层深度[[0, 0, 0], [0, 0, 0]]   # z 第二层深度
]

形状:[6, 3, 3]

(2)dim=1 上拼接

dim=1 上拼接,相当于增加每个“深度”层中的行数。每个深度层的行数会拼接起来。

w_dim1 = torch.cat([x, y, z], dim=1)
print(w_dim1.shape)

形象解释

x:
[[[0, 0, 0]],  # 第一层深度的第一行[[0, 0, 0]]   # 第二层深度的第一行
]y:
[[[0, 0, 0], [0, 0, 0], [0, 0, 0]],  # 第一层深度的三行[[0, 0, 0], [0, 0, 0], [0, 0, 0]]   # 第二层深度的三行
]z:
[[[0, 0, 0], [0, 0, 0]],  # 第一层深度的两行[[0, 0, 0], [0, 0, 0]]   # 第二层深度的两行
]拼接结果 w_dim1:
[[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],  # 第一层深度的六行[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]   # 第二层深度的六行
]

形状:[2, 6, 3]

当然可以!为了展示如何在 dim=2(第三个维度)上拼接张量,我们需要确保这些张量在前两个维度上的大小是相同的,而在第三个维度上的大小可以不同。

假设我们定义三个张量 a, b, c,它们分别具有如下形状:

  • a 的形状是 [2, 2, 2]
  • b 的形状是 [2, 2, 3]
  • c 的形状是 [2, 2, 1]
import torcha = torch.tensor([[[1, 2], [3, 4]],[[5, 6], [7, 8]]
])b = torch.tensor([[[9, 10, 11], [12, 13, 14]],[[15, 16, 17], [18, 19, 20]]
])c = torch.tensor([[[21], [22]],[[23], [24]]
])

(3)在 dim=2 上拼接

dim=2 上拼接,相当于增加每行中的元素数量(列数)。每个深度层中的列数会拼接起来:

w_dim2 = torch.cat([a, b, c], dim=2)
print(w_dim2)
print(w_dim2.shape)

形象解释

a:
[[[1, 2],      [3, 4]],     # 第一层深度的两行两列[[5, 6],      [7, 8]]      # 第二层深度的两行两列
]b:
[[[9, 10, 11], [12, 13, 14]], # 第一层深度的两行三列[[15, 16, 17], [18, 19, 20]] # 第二层深度的两行三列
]c:
[[[21],        [22]],       # 第一层深度的两行一列[[23],        [24]]        # 第二层深度的两行一列
]拼接结果 w_dim2:
[[[1, 2, 9, 10, 11, 21], [3, 4, 12, 13, 14, 22]],       # 第一层深度的两行六列[[5, 6, 15, 16, 17, 23], [7, 8, 18, 19, 20, 24]]       # 第二层深度的两行六列
]w_dim2 的形状为:[2, 2, 6]

通过在 dim=2 上拼接,结果张量 w_dim2 的第三个维度是各个张量第三个维度的和:2 + 3 + 1 = 6

# 代码输出:
# tensor([[[ 1,  2,  9, 10, 11, 21],
#          [ 3,  4, 12, 13, 14, 22]],
# 
#         [[ 5,  6, 15, 16, 17, 23],
#          [ 7,  8, 18, 19, 20, 24]]])
# 
# 形状: torch.Size([2, 2, 6])

希望这个例子能帮助你更好地理解如何在 dim=2 上拼接张量。
非常好的问题!让我们用书架的比喻来解释这个例子,这将有助于更直观地理解张量的维度。

在这个比喻中:

  • dim=0(第一个维度)代表书架的数量
  • dim=1(第二个维度)代表每个书架的层板数
  • dim=2(第三个维度)代表每个层板可以放置的书本数量(即层板的宽度)

让我们用这个比喻来解释 a, b, 和 c 这三个张量:

  1. 张量 a [2, 2, 2]:

    • 2个书架
    • 每个书架有2层层板
    • 每个层板可以放2本书
  2. 张量 b [2, 2, 3]:

    • 2个书架
    • 每个书架有2层层板
    • 每个层板可以放3本书
  3. 张量 c [2, 2, 1]:

    • 2个书架
    • 每个书架有2层层板
    • 每个层板可以放1本书

当我们在 dim=2 上拼接这些张量时,相当于我们在不改变书架数量和层板数量的情况下,将每个层板变宽,使其可以容纳更多的书。

拼接后的结果 w_dim2 [2, 2, 6]:

  • 仍然是2个书架(dim=0 没变)
  • 每个书架仍然有2层层板(dim=1 没变)
  • 但是现在每个层板可以放6本书了(dim=2 变成了 2+3+1=6)

形象地说:

原来的书架 a:    原来的书架 b:    原来的书架 c:
[□□]            [□□□]           [□]
[□□]            [□□□]           [□][□□]            [□□□]           [□]
[□□]            [□□□]           [□]拼接后的新书架 w_dim2:
[□□□□□□]  (2+3+1 = 6本书)
[□□□□□□][□□□□□□]
[□□□□□□]

每个 □ 代表一本书(或者说张量中的一个元素)。

这个比喻展示了我们如何在不增加书架数量(dim=0)或层板数量(dim=1)的情况下,通过拼接来增加每个层板可以放置的书本数量(dim=2)。这就是在 dim=2 上进行张量拼接的直观理解。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法力扣刷题记录 六十九【动态规划基础及509. 斐波那契数】

前言 调整一下做题顺序,多个章节同步进行,穿插练习。可以在各章节的专栏中找同一类。 记录 六十九【动态规划基础】。 一、动态规划理论基础学习 参考学习链接 二、509. 斐波那契数 2.1 题目阅读 斐波那契数 (通常用 F(n) 表示&#x…

html+css+js网页设计 中国移动5个页面(带js)

htmlcssjs网页设计 中国移动5个页面(带js) 网页作品代码简单,可使用任意HTML编辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xf…

Cpp中的this指针--复习记录

1.什么是this指针? 每个类都有一个this指针,我们的非静态成员函数可以通过这个this指针来操作对象的成员属性。this指针存储的就是类的实例的地址,this指针时时刻刻指向的都是这个实例对象本身。 由下图可知: 我在主函数中栈上创建了一个类的实例(由操…

【Python-实操】LabelMe to YOLOv8 Converter

LabelMe to YOLOv8 Converter 这是一个 Python 脚本,用于将 LabelMe 标注工具导出的 JSON 文件转换为 YOLOv8 格式的标注文件,并同时在图像上绘制标注的多边形。 功能 读取 LabelMe JSON 文件。解码并显示图像。从 classes.txt 文件加载类别标签。将多…

Java | Leetcode Java题解之第327题区间和的个数

题目&#xff1a; 题解&#xff1a; class Solution {public int countRangeSum(int[] nums, int lower, int upper) {long sum 0;long[] preSum new long[nums.length 1];for (int i 0; i < nums.length; i) {sum nums[i];preSum[i 1] sum;}BalancedTree treap ne…

Java参数传递

Java参数传递 一、 方法重载 一个类中可以存在多个同名的方法&#xff0c;只要这些方法的参数列表不同即可。 参数列表不同&#xff1a;参数个数或者参数类型不同方法重载与修饰符、返回值类型等统统无关&#xff0c;只看参数列表 二、 可变个数的形参 从Java5.0开始&…

陶瓷材质的防静电架空地板越来越受欢迎的原因

目前市面上的陶瓷防静电架空地板主要分为两种&#xff1a;钢基和硫酸钙基。前者是以全钢冲孔裸板作为板基&#xff0c;经粘接、固定整型和灌浆的方式加工而成&#xff0c;后者是以复合硫酸钙板为基材&#xff0c;表面粘接防静电陶瓷砖&#xff0c;四周导电PVC边条封边。近年来陶…

【C++】vector 的模拟实现

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

02_快速启动 Demo 创建 Electron 项目、electron-forge 搭建一个 electron 项目、手动创建electron项目

快速启动 Demo 创建 Electron 项目 一、克隆一个仓库、快速启动一个项目二、electron-forge 搭建一个 electron 项目三、手动搭建一个 electron 项目四、开发工具中配置 Eslint 一、克隆一个仓库、快速启动一个项目 要使用 git 的话首先电脑上面需要安装 git //克隆示例项目的…

Qt3D给圆环等立体图形添加纹理图片

添加纹理图片&#xff0c;首先需要自己找一个纹理图&#xff0c;当然了&#xff0c;随便什么图片都行。 创建3D图形的主要步骤查看另一篇文章。 这里主要代码如下&#xff1a; 使用QTextureLoader加载图片&#xff0c;图片路径需为qrc:/的路径。 auto *planeTransform1 ne…

嵌入式学习day13(C高级Linux命令)

一丶进程管理命令 1.grep 功能&#xff1a;从文件中查找字符串 格式&#xff1a;grep "要查找的字符串" 文件名 精确查找&#xff1a;grep "\<要查找的字符串\>" 文件名 结合ps以及管道&#xff1a;ps -ef | grep a.out: 从进程信息中查找带…

10个理由告诉你,为什么鸿蒙是下一个职业风口!

在当今科技飞速发展的时代&#xff0c;新的技术和趋势不断涌现&#xff0c;为人们带来了前所未有的机遇和挑战。鸿蒙操作系统作为我国自主研发的创新成果&#xff0c;正逐渐成为科技领域的焦点&#xff0c;被认为是下一个职业风口。 10个理由告诉你&#xff0c;为什么鸿蒙是下一…

【海贼王航海日志:前端技术探索】CSS你了解多少?(二)

目录 1 -> 字体属性 1.1 -> 设置字体 1.2 -> 字体大小 1.3 -> 字体粗细 1.4 -> 文字样式 2 -> 文本属性 2.1 -> 文本颜色 2.1.1 -> 认识RGB 2.1.2 -> 设置文本颜色 2.2 -> 文本对齐 2.3 -> 文本装饰 2.4 -> 文本缩进 2.5 -&g…

vue的nextTick是下一次事件循环吗

如题&#xff0c;nextTick的回调是在下一次事件循环被执行的吗&#xff1f; 是不是下一次事件循环取决于nextTick的实现&#xff0c;如果是用的微任务&#xff0c;那么就是本次事件循环&#xff1b;否则如果用的是宏任务&#xff0c;那么就是下一次事件循环。 我们看下Vue3中…

【Canvas与艺术】黄色立体感放射光芒五角星

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>黄色立体感放射光芒五角星</title><style type"text/c…

Html详解——Vue基础

HTML是什么&#xff1f; 超文本标记语言&#xff08;英语&#xff1a;HyperText Markup Language&#xff0c;简称&#xff1a;HTML&#xff09;是一种用来结构化 Web 网页及其内容的标记语言。网页内容可以是&#xff1a;一组段落、一个重点信息列表、也可以含有图片和数据表…

[Vue]Vue3从入门到精通-综合案例分析

一.Vue是什么&#xff1a; 概念&#xff1a;Vue是一个用于构建用户界面的渐进式的框架 以下的内容是自里向外的 声明式渲染(Vuejs核心包)组件系统(Vuejs核心包)客户端路由VueRouter大规模状态管理Vuex构建工具Webpack/Vite Vue的两种使用方式&#xff1a; Vue核心包开发-&…

DSL domain specific language of Kola

How we design Kola - ApiHugKola background, Kola a consumer driver tester frameworkhttps://apihug.com/zhCN-docs/kola/003_dsl_contract Concept 在 Kola 定位中 Kola 是什么, 是致力于提供一个让相关各方都能够理解共同创造的测试框架和工具。 同时 Kola 是建立于业界…

node中使用http创建web服务器

1.案例代码 // 1.导入http模块 const http require(http)// 2.创建web服务器实例 const server http.createServer()// 3.为服务器实例绑定request事件&#xff0c;监听客户的请求 server.on(request,function(req,res){console.log(欢迎来到服务器);// req.url是客户端请求…

Kubernets(k8s) 网络原理二:Pod访问外网

上一篇文章中&#xff0c;我们介绍了pod与宿主机通信&#xff0c;并且通过network namespace模拟了通信过程。回顾整个流程&#xff0c;无非就涉及到两个东西&#xff0c;通信设备和路由规则。 本文要讲的&#xff0c;也离不开这两个东西&#xff0c;只不过需要对容器IP进行额…