转置算子(transpose)的一种实现

article/2025/10/13 5:50:48

transpose算子也叫做permute算子,根据白嫖有道英汉大词典的结果,他俩都是转置,改变排列顺序的意思。

算法逻辑是:

  1. 通过当前输出的一维偏移量(offset)计算输入矩阵对应的高维索引

  2. 然后根据参数pos重新排列输出索引,进而得到输出索引。

  3. 将输出索引转换成输入偏移量.

  4. 最后进行数据移动,整个过程的示意图如下.

上代码,pos[]数组表示将输入矩阵的pos[i]维,映射到输出矩阵的第i维。

/** ===========================================================================================**       Filename:  transpose.c**    Description:  transpose operator impl.**        Version:   *         Create:  2021-11-07 14:08:50*       Revision:  none*       Compiler:  GCC:version 7.2.1 20170904 (release),ARM/embedded-7-branch revision 255204**         Author:  *   Organization:  Last Modified : 2021-11-07 20:22:56** ===========================================================================================*/
#include <stdio.h>
#include <stdlib.h>#define DBG(fmt, ...)   do{ printf("%s line %d, "fmt"\n", __func__, __LINE__, ##__VA_ARGS__); } while(0)void transpose_matrix(float *matrix_A, float **matrix_B, int *shape_A, int dims_A, int *pos)
{float *B;int element_count;int i;element_count = 1;for(i = 0; i < dims_A; i ++){element_count *= shape_A[i];}B = (float *)malloc(element_count * sizeof(float));if(B == NULL){DBG("malloc buffer for B failure.");return;}int* shape_B = (int *)malloc(sizeof(int) * dims_A);if(shape_B == NULL){DBG("malloc shape buffer for B failure.");return;}for(int i = 0; i < dims_A; i++){shape_B[i] = shape_A[pos[i]];}int* indexA = (int*)malloc(sizeof(int) * dims_A);if(indexA == NULL){DBG("failure to malloc matrix A index.");return;}int* indexB = (int*)malloc(sizeof(int) * dims_A);if(indexB == NULL){DBG("failure to malloc matrix B index.");return;}for(int src = 0; src < element_count; src++){int temp = src;for(i = dims_A-1; i >= 0; i--){indexA[i] = temp % shape_A[i];temp = temp / shape_A[i];}for(i = 0; i < dims_A; i++){indexB[i] = indexA[pos[i]];}int dst = 0;temp = 1;for(i = dims_A - 1; i >= 0; i--){dst = dst + indexB[i] * temp;temp = temp * shape_B[i];}B[dst] = matrix_A[src];}free(indexA);free(indexB);indexA = indexB = NULL;*matrix_B=B;return;
}void print_tensor(const float* A, int* shape, int dim)
{                     int elem = 1;     for(int i = 0; i < dim; i++){                 elem = elem * shape[i];}                 printf("Array size: %d\n", elem);for(int i = 0; i < elem; i++){                 printf( "%f ", A[i] );int split = 1;         for(int j = dim-1; j > 0; j--){                      split = split * shape[j];if( (i+1) % split == 0){printf("\n");}         }             }                 
} int main(void)
{float* B;float A[24] ={ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};  int shapeA[] = {2, 3, 4}; int dimA = 3;print_tensor(A, shapeA, dimA);// Transposeint perm[] = { 2, 0, 1}; transpose_matrix(A, &B, shapeA, dimA, perm);// Print Bint shapeB[] = {4, 2, 3}; int dimB = 3;print_tensor(B, shapeB, dimB);int shapeM[] = {2, 2, 2, 3}; int dimM = 4;print_tensor(A, shapeM, dimM);// Transposeint permM[] = {3, 0, 1, 2}; transpose_matrix(A, &B, shapeM, dimM, permM);// Print Bint shapeO[] = {3, 2, 2, 2}; int dimO = 4;print_tensor(B, shapeO, dimO); // Free memoryfree(B);return 0;
}

运行结果

(base) caozilong@caozilong-Vostro-3268:~/Workspace/transpose$ ./a.out 
Array size: 24
1.000000 2.000000 3.000000 4.000000 
5.000000 6.000000 7.000000 8.000000 
9.000000 10.000000 11.000000 12.000000 13.000000 14.000000 15.000000 16.000000 
17.000000 18.000000 19.000000 20.000000 
21.000000 22.000000 23.000000 24.000000 Array size: 24
1.000000 5.000000 9.000000 
13.000000 17.000000 21.000000 2.000000 6.000000 10.000000 
14.000000 18.000000 22.000000 3.000000 7.000000 11.000000 
15.000000 19.000000 23.000000 4.000000 8.000000 12.000000 
16.000000 20.000000 24.000000 Array size: 24
1.000000 2.000000 3.000000 
4.000000 5.000000 6.000000 7.000000 8.000000 9.000000 
10.000000 11.000000 12.000000 13.000000 14.000000 15.000000 
16.000000 17.000000 18.000000 19.000000 20.000000 21.000000 
22.000000 23.000000 24.000000 Array size: 24
1.000000 4.000000 
7.000000 10.000000 13.000000 16.000000 
19.000000 22.000000 2.000000 5.000000 
8.000000 11.000000 14.000000 17.000000 
20.000000 23.000000 3.000000 6.000000 
9.000000 12.000000 15.000000 18.000000 
21.000000 24.000000 (base) caozilong@caozilong-Vostro-3268:~/Workspace/transpose$

通过这个程序,发现一个很有意思的规律,大概描述如下,在N维空间下,<=N的tensor做转置,不需要对tensor做结构上的改变,只需要转换观察角度即可,因为空间维度容的下数据向各个方向的扩展.

以三维空间为例,对于二维矩阵的转置操作,我们只需要分别从列向量和行向量的方向上观察即可,不需要做矩阵做调整。

对于三维的物体也是一样,我们以魔方为例在说明:

 不管魔方是几阶的,它都是三维的,都可以用一个三维的数组来表示。A[M][N][P],对于,M,N,P全排列中的任何一个,我们都可以通过切换观察视角来理解它的转置操作,而不需要对它做结构上的调整。

但是,当高维矩阵在内存中存储时,由于内存模型是线性表模型,它是一维的,一维的空间容不下多个维度,所以必须要扁平化 “降维” 成1维。对于N维tensor来说,这个降维排布方式有N!种方式。对应了高维空间中的几种观察视角的变化切换。

那么四维空间中魔方该如和表示置换操作呢?我们生活的空间是三维的,对于四维空间,我们缺乏像对三维空间那样直观的认识,更别说四维的魔方了。它超出了我们的认知范围,但是从数学的角度看,我们可以通过将第四维看成是是在某个三维方向上的拓展或者对某个维度的复用,还是以魔方为例,我们可以通过将组成魔方的每个小方块在划分维度,比如1维,2维。。。等等,想象一个魔方中的魔方,每个小方块还是一个魔方,那就是3*3*3*(3*3*3)六个维度,通过这种方式,我们可以定义任意维度的魔方,构造上有点像俄罗斯套娃。

但是,理解这种构造魔方的转置还有一个局限,就是它的维度已经超过了所在空间的维度,所有,有些维度会复用,造成“冲突”,还是以魔方为例,俄罗斯套娃方式构造的魔方,每个小方框其实都是对三维空间的复用,它不存在真正的它所在的高维对应的维度,所以,如果要完成置换,可能需要对魔方的构造进行调整,而不单单是仅仅是进行视角的变化。

这是由矩阵转置联想到的一点粗浅的理解,可能有错误,但这并不重要,每个人的认识都是在不断的纠正错误中前进的,权且记录下来,以便日后思考,更正吧。 

总结:

代码中,shape和数组形式定义的维度序关系如下:

imple by myself:

#include <stdio.h>int main(void)
{static int abc = 0;int a[6][6][3];int b[3][6][6];int i,j,k;for(i = 0; i < 6; i ++){for(j = 0; j < 6; j ++){for(k = 0; k < 3; k ++)a[i][j][k] =  abc ++;}}for(i = 0; i < 6; i ++){for(j = 0; j < 6; j ++){for(k = 0; k < 3; k ++)printf("%3d ", a[i][j][k]);printf("\n");}printf("\n");printf("\n");}printf("========================================\n");for(i = 0; i < 3; i ++){for(j = 0; j < 6; j ++){for(k = 0; k < 6; k ++)b[i][j][k] =  a[j][k][i];}}for(i = 0; i < 3; i ++){for(j = 0; j < 6; j ++){for(k = 0; k < 6; k ++)printf("%3d ", b[i][j][k]);printf("\n");}printf("\n");printf("\n");}return 0;
}

RGB图像transform的一种方式。

RGB图像的三个维度是长,宽,和 色彩(可以理解为高),长宽转置没有意义(也不能完全说没有意义,内存是一维的,存储方向肯定发生了变化),所以可以将长宽看成一个维度,所以,RGBRGBRGB。。。。排列方式和RRRRR。。。GGGGG。。。BBBBB两种方式的区别在于颜色和【XY】的转置。


结束!


http://chatgpt.dhexx.cn/article/kAq7U0Xl.shtml

相关文章

论文笔记——TransPose

目录 摘要 一、前言 二、相关工作 2.1 人体姿态估计 2.2 可解释性 三、TransPose 3.1 网络结构 3.2 分辨率设置 3.3 attentions是定位关键点的依赖 四、实验 4.1 COCO实验数据对比 4.2 迁移到MPII数据对比 4.3 消融实验​编辑 4.4 量化分析 五、总结 摘要 虽然基…

numpy中的transpose函数使用

二维矩阵的transpose函数 &#xff1a; transpose&#xff08;&#xff09;简单来说&#xff0c;就相当于数学中的转置&#xff0c;在矩阵中&#xff0c;转置就是把行与列相互调换位置&#xff1b; 例如&#xff1a;随机生成一个三行五列的二维矩阵&#xff1a; arr np.aran…

transpose()函数的理解

图1 输入如图1所示语句&#xff0c;输出如下&#xff1a; 图2 由以上两图说明transpose()函数的作用&#xff1a; 假设shape(z,x,y),在RGB图像中可以理解为z代表通道数&#xff0c;x代表图像的第几行&#xff0c;y代表图像的第几列&#xff0c;x和y组合而成所代表的像素构成…

详解Python的transpose函数

数组转置和换轴 import numpy as np >>> arr np.arange(16).reshape((2,2,4)) array([[[ 0, 1, 2, 3],[ 4, 5, 6, 7]],[[ 8, 9, 10, 11],[12, 13, 14, 15]]])>>> arr.transpose((1, 0, 2)) array([[[ 0, 1, 2, 3],[ 8, 9, 10, 11]],[[ 4, 5, …

np.transpose

最近看代码的时候&#xff0c;老是出现np.transpose()这个用法&#xff0c;但是对其中的原理还是不甚了解&#xff0c;今天就来总结一下&#xff0c;以及这个用法对图像的结果及效果。 参数 a:输入数组 axis: int类型的列表&#xff0c;这个参数是可选的。默认情况下&#xff…

np.transpose()函数详解

1. 碰见 numpy.transpose 用于高维数组时挺让人费解&#xff0c;通过分析和代码验证&#xff0c;发现 transpose 用法还是很简单的。说白了就是映射坐标轴 2. 举个例子&#xff1a; x np.arange(12).reshape((2,3,2))创建一个2 * 3 * 2的数组&#xff1a; 使用 numpy.trans…

【Python学习】transpose函数

shape:(batch_size * x * y ) 有batch_size个二维矩阵&#xff08;x * y&#xff09;相当于(z * x * y) 1. 多维数组的索引 import numpy as np # 创建 x np.arange(12).reshape((2,2,3)) print(x)# 得到三维数组 [[[ 0 1 2][ 3 4 5]][[ 6 7 8][ 9 10 11]]] # 相当于 b…

最简单例子解释python的transpose函数

目录 一&#xff0c;我们要弄清楚transpose的轴是什么意思&#xff1f;二&#xff0c;(x,y,z)的物理含义:三&#xff0c;transpose变换的例子四&#xff0c;代码验证五&#xff0c;关于经过了transpose变换之后&#xff0c;这个三维数组的形状是如何变化确定的&#xff1f; 二维…

转置(transpose)的理解

目录 1 .T,适用于一、二维数组 arr.T #求转置 transpose 的原理其实是根据维度&#xff08;shape&#xff09;索引决定的&#xff0c;举个栗子&#xff1a; 2. 高维数组 3. swapaxes 转置可以对数组进行重置&#xff0c;返回的是源数据的视图&#xff08;不会进行任何复制…

Python numpy.transpose 详解

前言 看Python代码时&#xff0c;碰见 numpy.transpose 用于高维数组时挺让人费解&#xff0c;通过一番画图分析和代码验证&#xff0c;发现 transpose 函数的使用方法还是很简单的。 注&#xff1a;评论中说的三维坐标图中的 0 1 2 3 标反了&#xff0c;已经修正&#xff0c…

2020年最新可用的谷歌镜像站

g.vovososo.com 谷歌镜像入口 不用翻&#xff0c;墙&#xff0c;就可实现访问谷歌搜索 &#xff0c;也可以通过扫描以下二维码下载APP进行访问

谷歌搜索镜像

分享自己收藏的谷歌搜索镜像 可自由在谷歌查询信息 http://ac.scmor.com/ 转载于:https://www.cnblogs.com/aeip/p/9506344.html

谷歌引擎镜像网址

谷歌引擎镜像网址 当前可用的网址 链接: https://gfsoso.xz95.top/ 若是显示我们的系统检测到您的计算机网络中存在异常流量&#xff0c;可重新搜索或者选择图片进行搜索&#xff0c;然后在点开全部搜索&#xff08;有时候可能会崩吧&#xff0c;我个人感觉用图片搜索再点全…

谷歌镜像地址分享

谷歌镜像地址分享 谷歌镜像地址分享谷歌应用商店参考文档 谷歌镜像地址分享 使用搜索引擎来查找所需要的资料是一件很普遍的事&#xff0c;而搜索引擎主要有百度、必应、雅虎和谷歌等等。 每个搜索引擎各有利弊&#xff0c;而一般大家公认的是谷歌搜索引擎搜索准确率更高一些&…

分享27个谷歌(Google)镜像

为什么80%的码农都做不了架构师&#xff1f;>>> 多年来搜集的谷歌镜像&#xff0c;大多数都能打开&#xff0c;打不开的也许过一段上一段时间能打开。真诚希望这些神奇的搜索引擎&#xff0c;能助你在前端界有所建树。有空关注下面前端相关公众账号jsdig(及时挖掘&…

谷歌学术镜像_Google镜像站

在国外留学要想毕业顺利, 论文可是其中很重要的一环. 相比于国内, 英国对于论文的要求更为严格, 要有一定的格式和学术要求. 除此之外, 还要有理有据, 要用高质量的引文作为对自己观点的论证. 这时就要查文献了. 要说查文献, 谷歌学术绝对是最佳帮手, 免费还操作简单. 当然全面…

国内最新可用Google谷歌镜像网站入口网站网址

很多同学都需要使用谷歌搜索来查找一些英文的学习资料&#xff0c;但是由于某些原因国内无法使用。办公人导航就和大家分享另外一种在国内可以使用谷歌搜索的方法那就使用使用谷歌镜像网站。 Google谷歌镜像网站可以帮助我们在国内访问和使用谷歌搜索&#xff0c;但这并不是真…

Google谷歌搜索引擎镜像入口网址大全导航,谷歌搜索引擎镜像站

当我们需要使用谷歌搜索一些学习资料的时候&#xff0c;就需要借助Google谷歌搜索引擎镜像网站&#xff0c;很多同学不知道有哪些可以使用的谷歌搜索引擎镜像站&#xff0c;下面办公人导航就和大家分享Google谷歌搜索引擎镜像入口网址大全导航。 1.google谷歌搜索引擎镜像站网址…

[2023-01 持续更新] 谷歌学术google镜像/Sci-Hub可用网址/Github镜像可用网址总结

目录 一、谷歌学术镜像二、Sci-Hub三、Github镜像四、GitHub下载文件加速 一、谷歌学术镜像 首先强烈推荐谷歌hub 网址一&#xff1a;谷歌学术-谷歌镜像网址https://www.google-hub.com/ 网址二&#xff1a;http://scholar.scqylaw.com/ (附 sci-hub) 网址三&#xff1a;htt…

Python求最大公约数和最小公倍数

大家好&#xff0c;我是Python领域的博主&#xff0c;如果觉得我的写的不错的话&#xff0c; 请点赞关注支持我一下。如果你是初学者&#xff0c;可以和小编一起学习&#xff0c;在这里我每天都会发Python的基础知识&#xff0c;以及相关的代码 解题思路&#xff1a; 最大公因数…