最近实现tensorflow模型转换为caffe前向计算的时候存在一个数据维度的问题,即tf的数据格式一般习惯把channel放在最后一维,caffe一般放在第一维;即将一个dxc的二维矩阵转置成为cxd;如何不需要额外内存的情况下,完成这一操作;
具体如图所示:
可以按照上图找一下规律,发现:
可以发现,数据的移动可以演变为一个循坏;遍历完每个“环”,那么任务就完成了;
循环过程需要找到后继节点;
int getNext(int i, int m, int n) //m为转置后的行数,n为转置后的列数
{
return (i%n)*m + i/n;
}
填补的时候需要找到前驱节点;
int getPre(int i, int m, int n) // m为转置后的行数,n为转置后的列数
{
return (i%m)*n + i/m;
}
遍历数组,判断当前节点是否为所在环的初始点,初始点的定义为:环中节点在数组(一维)中的index 最小值,例如上图中的1号节点;
void transpose(int *mtx, int m, int n)
{
for(int i=0; i<m*n; ++i)
{
int next = getNext(i, m, n);
while(next > i) // 若存在后继小于i说明已经出现之前的环中;
next = getNext(next, m, n);
if(next == i) // 当前节点i就是环的初始节点,处理当前环
movedata(mtx, i, m, n);
}
}
下面开始处理该环的赋值操作,赋值是由前驱节点的值赋值到当前节点所在的位置:
void movedata(int *mtx, int i, int m, int n)
{
int temp = mtx[i]; // 备份
int cur = i; // 当前下标
int pre = getPre(cur, m, n);
while(pre != i)
{
mtx[cur] = mtx[pre];
cur = pre;
pre = getPre(cur, m, n);
}
mtx[cur] = temp;
}
以上是关于任意二维矩阵的原地转置操作,下面介绍方形矩阵的原地旋转90度操作,是leetcode中的一道中等难度的一道题;
力扣leetcode-cn.comclass Solution {
public:
void swap(int& i, int& j)
{
int temp = i;
i = j;
j = temp;
return;
}
void rotate(vector<vector<int>>& matrix)
{
int n = matrix.size();
for(int i = 0; i < n/2; ++i)
{
for(int j = 0; j < n/2; ++j)
{
swap(matrix[i][j], matrix[j][n-1-i]);
swap(matrix[i][j], matrix[n-1-i][n-1-j]);
swap(matrix[i][j], matrix[n-1-j][i]);
}
}
if(n%2==1)
{
for(int i = 0; i < n/2+1; ++i)
{
swap(matrix[i][n/2], matrix[n/2][n-1-i]);
swap(matrix[i][n/2], matrix[n-1-i][n-1-n/2]);
swap(matrix[i][n/2], matrix[n-1-n/2][i]);
}
}
return;
}
};
分成奇数和偶数两种情况分别考虑,逻辑更加清晰;
与之前的转置有异曲同工之妙在于 也是一组 四个位置的数字循环,不过这里的“环”坐标之间存在对应关系;
[i][j]--->[j][n-1-i]---->[n-1-i][n-1-j]---->[n-1-j][i]
可以看出:后驱节点的行数等于前驱节点的列数,后驱节点的列数等于前驱节点的(n-1-行数);
该博客主要作用在于工作中的记录;之前认为的所有的算法题都是无中生有。真正用到的时候还是真香!!!其中:
原地矩阵转置的代码参考博客:
矩阵--原地转置--面试题_网络_戎码人生-CSDN博客
原地方形矩阵的旋转是我在leetcode上的实现;