#include <Eigen/Dense>
#include <iostream>
#include <random>
#include <chrono>
int main()
{
const int num_points = 300000000;
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> init_points(num_points, 3);
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> transformed_points(num_points, 3);
std::mt19937 rng(42);
std::uniform_real_distribution<float> dist(-100.0f, 100.0f);
for (int i = 0; i < num_points; ++i)
{
init_points(i, 0) = dist(rng); // x
init_points(i, 1) = dist(rng); // y
init_points(i, 2) = dist(rng); // z
}
float theta = 3.14159265358 / 4; // pi/4
Eigen::Matrix3f rotation;
rotation = Eigen::AngleAxisf(theta, Eigen::Vector3f::UnitZ());
Eigen::Vector3f translation(10.0f, 20.0f, 30.0f);
auto start_time = std::chrono::high_resolution_clock::now();
//transformed_points = init_points * rotation; //uncomment this line to use the Matrix multiply version
//transformed_points.rowwise() += translation.transpose(); //uncomment this line to use the Matrix multiply version
for (int i = 0; i < num_points; ++i) //comment this for loop to use the Matrix multiply version
{
Eigen::Vector3f v = init_points.row(i).transpose();
v = rotation * v;
v += translation;
transformed_points.row(i) = v.transpose();
}
auto end_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> duration_ms = end_time - start_time;
std::cout << "total consume: " << duration_ms.count() << "ms" << std::endl;
std::cout << "first 5 points:(x,y,z)" << std::endl;
for (int i = 0; i < 5; ++i)
{
std::cout << "("<< transformed_points(i, 0) << ","<< transformed_points(i, 1) << ", " << transformed_points(i, 2) << ")" << std::endl;
}
return 0;
}
I当前在通过点云采样获得的对象上执行坐标转换。我需要先旋转一组点,然后翻译它们以获得转换的点云。
这个点云数据总共包含300,000,000点,我正在使用eigen的动态阵列进行存储。上面的代码是一个测试示例,我在其中初始数字初始化了300,000,000点,然后执行旋转和翻译操作。该代码既包括循环遍历版本和矩阵乘法版本。要使用矩阵乘法,您只需要删除我发表评论的两行并评论前循环部分。 the是对循环遍历和矩阵乘法版本所消耗的时间的比较:
1。对于旋转和翻译操作,我尝试将所有300,000,000点乘以旋转矩阵,然后添加翻译向量。此操作在我的i7-13700k cpu上大约需要2044ms
。2。我写了一个循环遍历每个点并逐一旋转和翻译。总时间仅为600ms。 我知道eigen使用许多CPU指令集来优化矩阵乘法,并且我正在使用启用了各种SIMD和AVX优化的英特尔ICC编译器。为什么在这里的前横梁比矩阵乘法快3倍?
加上,是否有任何空间可以进一步优化上述代码? 有人可以帮助分析吗?我非常感谢它。 PS:我确实有优化的打开,因为在优化的情况下关闭了所花费的时间比现在要高得多。我的意思是,当我打开优化时,for循环比单独进行矩阵乘法更快
我刚刚进行了一些时间测量。由于我没有与您相同的CPU,并且您没有指定所使用的确切编译器选项,因此效果可能会或可能不会有所不同。 我测试了: Intel(R)Oneapi DPC ++/C ++编译器2025.0.4
编译器标志:-dndebug -o3 -march =i7-9850H上的本机 以下所有值是3个测量值的中间:
逐行的弯曲率花费了1247.91ms。 矩阵乘版本最初采用2583.93ms。 使用Noalias(如transformed_points.noalias() = init_points * rotation;
noalias
当将行和列切换时,将固定尺寸从Eigen::Dynamic
切换到3时,iThe矩阵乘法版本花费了1278.85ms。由于eigen默认为列是列 - 这意味着每个点的x,y和z现在彼此隔绝。
其他优化可能是可能的,但至少现在是初始的逐行环和矩阵乘法所需(几乎)运行时间的时间。
这是最终代码:
const int num_points = 300000000;
Eigen::Matrix<float, 3, Eigen::Dynamic> init_points(3, num_points);
Eigen::Matrix<float, 3, Eigen::Dynamic> transformed_points(3, num_points);
std::mt19937 rng(42);
std::uniform_real_distribution<float> dist(-100.0f, 100.0f);
for (int i = 0; i < num_points; ++i)
{
init_points(0, i) = dist(rng); // x
init_points(1, i) = dist(rng); // y
init_points(2, i) = dist(rng); // z
}
float theta = -3.14159265358 / 4; // minus to transpose/invert rotation
Eigen::Matrix3f rotation;
rotation = Eigen::AngleAxisf(theta, Eigen::Vector3f::UnitZ());
Eigen::Vector3f translation(10.0f, 20.0f, 30.0f);
auto start_time = std::chrono::high_resolution_clock::now();
transformed_points.noalias() = rotation * init_points;
transformed_points.colwise() += translation;
auto end_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> duration_ms = end_time - start_time;
std::cout << "total consume: " << duration_ms.count() << "ms" << std::endl;
std::cout << "first 5 points:(x,y,z)" << std::endl;
for (int i = 0; i < 5; ++i)
{
std::cout << "("<< transformed_points(0, i) << ","<< transformed_points(1, i) << ", " << transformed_points(2, i) << ")" << std::endl;
}