来自原始缓冲区的 Eigen::Map' 矩阵给出 OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG
Eigen::Map'd matrix from raw buffer gives OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG
最近我一直在处理从原始缓冲区派生的特征矩阵,我注意到了这个奇怪的情况:
#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
.如果我做一个简单的 C += A*B
一切都按预期工作。
在示例中,我从 Eigen 分配的矩阵映射原始缓冲区,但原则上它可以是任何东西(例如 std::vector
)的原始缓冲区。
知道这里发生了什么吗?据我所知,这里的所有内容都应该是堆分配的,即使不是,为什么 C += A*B
可以使用映射内存矩阵而 C+= (alpha*A)*(beta*B)
不能?
干杯,
尼克
您的 Map
正在包装静态大小的矩阵,例如:
Eigen::Map<Eigen::Matrix<int32_t, M, K, Eigen::ColMajor> >
^ ^
改为使用动态大小的 Map
s:
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
的大小,只是表明临时文件最终是如何分配的。
对于如此大的矩阵,最好使用 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>)
在编译时是已知的.好难过
最近我一直在处理从原始缓冲区派生的特征矩阵,我注意到了这个奇怪的情况:
#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
.如果我做一个简单的 C += A*B
一切都按预期工作。
在示例中,我从 Eigen 分配的矩阵映射原始缓冲区,但原则上它可以是任何东西(例如 std::vector
)的原始缓冲区。
知道这里发生了什么吗?据我所知,这里的所有内容都应该是堆分配的,即使不是,为什么 C += A*B
可以使用映射内存矩阵而 C+= (alpha*A)*(beta*B)
不能?
干杯,
尼克
您的 Map
正在包装静态大小的矩阵,例如:
Eigen::Map<Eigen::Matrix<int32_t, M, K, Eigen::ColMajor> >
^ ^
改为使用动态大小的 Map
s:
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
的大小,只是表明临时文件最终是如何分配的。
对于如此大的矩阵,最好使用 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>)
在编译时是已知的.好难过