最近,我一直在处理从原始缓冲区派生的本征矩阵,我注意到这种奇怪的情况:
#include <eigen3/Eigen/Dense>
int main(int argc, char const *argv[]) {
/* code */
const int M = 320;
const int N = 640;
const int K = 320;
const int alpha = 2;
const int beta = 1;
Eigen::Matrix<int32_t, Eigen::Dynamic,Eigen::Dynamic> A = Eigen::Matrix<int32_t, Eigen::Dynamic,Eigen::Dynamic>::Random(M,K);
Eigen::Matrix<int32_t, Eigen::Dynamic,Eigen::Dynamic> B = Eigen::Matrix<int32_t, Eigen::Dynamic,Eigen::Dynamic>::Random(K,N);
Eigen::Matrix<int32_t, Eigen::Dynamic,Eigen::Dynamic> C = Eigen::Matrix<int32_t, Eigen::Dynamic,Eigen::Dynamic>::Random(M,N);
//Following http://eigen.tuxfamily.org/dox/TopicWritingEfficientProductExpression.html
C.noalias() += (A*alpha)*(B*beta); //WORKS
C.noalias() += A*B;
Eigen::Map<Eigen::Matrix<int32_t, M, K, Eigen::ColMajor> > map_a(A.data());
Eigen::Map<Eigen::Matrix<int32_t, K, N, Eigen::ColMajor> > map_b(B.data());
Eigen::Map<Eigen::Matrix<int32_t, M, N, Eigen::ColMajor> > map_c(C.data());
map_c.noalias() += map_a*map_b; //WORKS
map_c.noalias() += (map_a*alpha)*(map_b*beta); //COMPILE ERROR HERE
return 0;
}
如果矩阵尺寸较大,则无法在堆栈上进行分配,否则会得到OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG
,因此我使用Eigen动态分配器。
但是,似乎如果我有一个原始缓冲区并将其映射到矩阵,由于编译错误,我将无法执行像gemm乘法(C+= (alpha*A)*(beta*B)
)这样的BLAS 3: 。如果我做一个简单的OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG
,一切都会按预期进行。
在示例情况下,我映射了Eigen分配的矩阵中的原始缓冲区,但原则上它可以是任何东西(例如C += A*B
)中的原始缓冲区。
有什么想法吗?据我所知,这里的所有内容都应该是堆分配的,即使没有分配,为什么std::vector
不能与映射的内存矩阵一起工作,而C += A*B
却不能呢?
干杯
尼克
答案 0 :(得分:3)
对于大矩阵,最好使用Avi Ginsburg的答案中的运行时大小。话虽如此,我现在将解释Eigen内部的情况。问题是在矩阵产品实现中,我们有一个类似的分支(简化):
if(<too small>)
lazyproduct::eval(dst, lhs, rhs);
else
gemm::eval(dst,lhs, rhs);
如果乘积太小,则无需调用繁琐的“ gemm”例程,而是返回到基于系数的实现,在您的情况下:
map_c.noalias() += (map_a*alpha).lazyProduct(map_b*beta);
此路径不会将表达式重写为(alpha*beta)*(map_a*map_b)
,因此,为了避免多次重新计算map_a*alpha
和map_b*beta
,该策略应支持它们在临时范围内...因此导致编译错误。
当然,在您的情况下,此路径将永远不会采用,并且如果您增加EIGEN_STACK_ALLOCATION_LIMIT
,甚至会被编译器完全删除,因为条件if(<too small>)
在编译时是已知的。真伤心。
答案 1 :(得分:1)
您的Map
正在包装静态大小的矩阵,例如:
Eigen::Map<Eigen::Matrix<int32_t, M, K, Eigen::ColMajor> >
^ ^
使用动态尺寸的Map
代替:
Eigen::Map<Eigen::Matrix<int32_t, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor> > map_a(A.data(), M, K);
Eigen::Map<Eigen::Matrix<int32_t, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor> > map_b(B.data(), K, N);
Eigen::Map<Eigen::Matrix<int32_t, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor> > map_c(C.data(), M, N);
这并不意味着您可以更改Map
的大小,而只是表明临时的最终分配方式。