THLongStorage *THTensor_(newSizeOf)(THTensor *self);
THLongStorage *THTensor_(newStrideOf)(THTensor *self);
把THTensor的size/stride數據提取出來,賦值給一個新的THLongStorage並返回
TH_API void THTensor_(narrow)(THTensor *self, THTensor *src, int dimension, long firstIndex, long size);
從src里找到第dimension個維度,從這個維度的firstIndex開始,連續取size個子tensor
self復制於src,通過修改self->storageOffset和self->size[dimension]來維持視圖的正確。
TH_API void THTensor_(select)(THTensor *self, THTensor *src, int dimension, long sliceIndex);
去src里的第dimension維度里的第sliceIndex個子tensor, 結果在self上進行修改
self通過前移size、stride,修改nDimesion來維持視圖正確。
調用了THTensor_(narrow)
void THTensor_(resize)(THTensor *self, THLongStorage *size, THLongStorage *stride);
先做一些檢查,size不能為NULL,stride可以為NULL,也可以存在,
如果stride存在,size -> size 和 stride -> size 必須一樣,這個是由tensor的構造決定的,檢查完畢后,調用resizeNd
void THTensor_(resizeNd)(THTensor *self, int nDimension, long *size, long *stride);
重置一個THTensor維度的函數,和newView不一樣,這個不是要求元素總量一致的情況下修改視圖,
而是直接把指定THTensor變成新的指定size/stride,視情況還會修改底層的THStorage
對nDimension循環,檢查現在self的stride和size是否能夠與目標的stride和size對應,
其實就是逐維檢查size[d]、stride[d]和 self->size[d]、self->stride[d]是否一致,如果完全一致就直接沿用不需要resize了
size的最后幾個維度可能會有負數,遇到這種負數一律跳出,並且修改nDimension為實際要變換的數量。
如果self現有的屬性和指定的dimension不符合,那就重分配size和stride數組的長度,然后重賦值
如果計算發現底層THStorage儲存不夠,或者THStorage直接為NULL,就重分配或者new一個THStorage
void THTensor_(indexSelect)(THTensor *tensor, THTensor *src, int dim, THLongTensor *index);
把src里的第dim維的index個子張量取出,在tensor中儲存
如,src是3x4x5x6,dim=1,index=[2, 0, 1],取出后的tensor維度是3x3x5x6
void THTensor_(indexCopy)(THTensor *tensor, int dim, THLongTensor *index, THTensor *src);
tensor里的數據的第dim維,按index的順序,被src的dim維按自然數順序賦值
比如,src是3x4x5x6,dim=1,index=[2, 0, 3, 1],此時tensor的dim1index2被src的dim1index0賦值,dim1index0被dim1index1賦值,以此類推
這便要求index的長度與src -> size[dim]必須相等,
index里的數字不重復也不報錯,但是實際執行並不會如意,當index=[0, 0, 0, 0]時,
並不是tensor的每一個子張量都等於src[:, 0, :, :],而是循環中tensor第0個、0個、0個、0個子張量被賦予src的第1、2、3、4個子張量
最后實際上相當於把tensor的第0個子張量賦為src的第4個子張量
【務必注意】這個分配順序和indexSelect是相反的
void THTensor_(gather)(THTensor *tensor, THTensor *src, int dim, THLongTensor *index);
void THTensor_(scatter)(THTensor *tensor, int dim, THLongTensor *index, THTensor *src);
這兩個也是剛好相反的,gather是用index的順序,從src中收集數據,賦值給按自然數循環的tensor
scatter是把tensor的index位置數據,用src以自然數循環的值填充,相當於把src“打散”了
這兩個名字也非常形象
TH_API void THTensor_(validXCorr2Dptr)(real *r_, real alpha,real *t_, long ir, long ic,real *k_, long kr, long kc, long sr, long sc);
二維卷積操作
t_: input || ir, ic: data rows, cols || kr, kc: kernel rows, cols || sr, sc: stride rows, cols || r_: output
#define THNN_resizeAs_indices(I1, I2)
I1, I2兩個TensorIndexTensor(TensorLongTensor),對I1做resize成I2的維度
#define THNN_CHECK_SHAPE(I1, I2)
檢查I1, I2兩個的size是否相同
#define THNN_CHECK_SHAPE_INDICES(I1, I2)
和CHECK_SHAPE基本一樣,不同的是它先用THStorage存I2的size2信息,用I1和I2的size2比較,比較完以后再釋放
非常奇怪,為什么要這樣做,和上一個宏在應用中的差別在哪里?
#define THNN_CHECK_NELEMENT(I1, I2)
檢查I1, I2是否具有同等數量的元素
#define THNN_CHECK_DIM_SIZE(T, DIM, DIM_SIZE, SIZE)
#define THNN_CHECK_DIM_SIZE_INDICES(T, DIM, DIM_SIZE, SIZE)
要求T的維度等於DIM,T的第DIM_SIZE個維度大小等於SIZE