将代码从 Eigen2 移植到 Eigen3 时的奇怪行为
Strange behaviours in porting code from Eigen2 to Eigen3
我正在考虑使用 this 库在我的研究项目中执行光谱聚类。
但是,为此,我需要将它从 Eigen2 移植到 Eigen3(这是我在代码中使用的)。
有一部分代码给我带来了一些麻烦。
这是针对 Eigen2 的:
double Evrot::evqual(Eigen::MatrixXd& X) {
// take the square of all entries and find max of each row
Eigen::MatrixXd X2 = X.cwise().pow(2);
Eigen::VectorXd max_values = X2.rowwise().maxCoeff();
// compute cost
for (int i=0; i<mNumData; i++ ) {
X2.row(i) = X2.row(i) / max_values[i];
}
double J = 1.0 - (X2.sum()/mNumData -1.0)/mNumDims;
if( DEBUG )
std::cout << "Computed quality = "<< J << std::endl;
return J;
}
如 here 所述,Eigen3 用略有不同的 .array() 功能替换了 .cwise()。
所以,我写道:
double Evrot::evqual(Eigen::MatrixXd& X) {
// take the square of all entries and find max of each row
Eigen::MatrixXd X2 = X.array().pow(2);
Eigen::VectorXd max_values = X2.rowwise().maxCoeff();
// compute cost
for (int i=0; i<mNumData; i++ ) {
X2.row(i) = X2.row(i) / max_values[i];
}
double J = 1.0 - (X2.sum()/mNumData -1.0)/mNumDims;
if( DEBUG )
std::cout << "Computed quality = "<< J << std::endl;
return J;
}
而且我没有遇到编译器错误。
但是,如果我给两个程序相同的输入(并检查它们实际上得到一致的输入),在第一种情况下我得到数字,在第二种情况下我只得到 NAN。
我的想法是,这是由于 max_values
计算错误,然后在除法中使用此向量导致所有 NAN。但是我不知道如何解决这个问题。
谁能告诉我如何解决这个问题?
谢谢!
您是否检查过值何时开始出现差异?您确定没有空行或 X^2 没有下溢吗?无论如何,在除以 max_values[i]
之前你应该有一个守卫。此外,为了避免平方中的下溢,您可以这样重写它:
VectorXd max_values = X.array().abs().rowwise().maxCoeff();
double sum = 0;
for (int i=0; i<mNumData; i++ ) {
if(max_values[i]>0)
sum += (X.row(i)/max_values[i]).squaredNorm();
}
double J = 1.0 - (sum/mNumData -1.0)/mNumDims;
即使 X.abs().maxCoeff()==1e-170
这也会起作用,而您的代码将下溢并产生 NaN。当然,如果您遇到这种情况,也许您应该先检查您的输入,因为您在数字问题上已经处于危险的一面。
我正在考虑使用 this 库在我的研究项目中执行光谱聚类。
但是,为此,我需要将它从 Eigen2 移植到 Eigen3(这是我在代码中使用的)。
有一部分代码给我带来了一些麻烦。
这是针对 Eigen2 的:
double Evrot::evqual(Eigen::MatrixXd& X) {
// take the square of all entries and find max of each row
Eigen::MatrixXd X2 = X.cwise().pow(2);
Eigen::VectorXd max_values = X2.rowwise().maxCoeff();
// compute cost
for (int i=0; i<mNumData; i++ ) {
X2.row(i) = X2.row(i) / max_values[i];
}
double J = 1.0 - (X2.sum()/mNumData -1.0)/mNumDims;
if( DEBUG )
std::cout << "Computed quality = "<< J << std::endl;
return J;
}
如 here 所述,Eigen3 用略有不同的 .array() 功能替换了 .cwise()。
所以,我写道:
double Evrot::evqual(Eigen::MatrixXd& X) {
// take the square of all entries and find max of each row
Eigen::MatrixXd X2 = X.array().pow(2);
Eigen::VectorXd max_values = X2.rowwise().maxCoeff();
// compute cost
for (int i=0; i<mNumData; i++ ) {
X2.row(i) = X2.row(i) / max_values[i];
}
double J = 1.0 - (X2.sum()/mNumData -1.0)/mNumDims;
if( DEBUG )
std::cout << "Computed quality = "<< J << std::endl;
return J;
}
而且我没有遇到编译器错误。
但是,如果我给两个程序相同的输入(并检查它们实际上得到一致的输入),在第一种情况下我得到数字,在第二种情况下我只得到 NAN。
我的想法是,这是由于 max_values
计算错误,然后在除法中使用此向量导致所有 NAN。但是我不知道如何解决这个问题。
谁能告诉我如何解决这个问题?
谢谢!
您是否检查过值何时开始出现差异?您确定没有空行或 X^2 没有下溢吗?无论如何,在除以 max_values[i]
之前你应该有一个守卫。此外,为了避免平方中的下溢,您可以这样重写它:
VectorXd max_values = X.array().abs().rowwise().maxCoeff();
double sum = 0;
for (int i=0; i<mNumData; i++ ) {
if(max_values[i]>0)
sum += (X.row(i)/max_values[i]).squaredNorm();
}
double J = 1.0 - (sum/mNumData -1.0)/mNumDims;
即使 X.abs().maxCoeff()==1e-170
这也会起作用,而您的代码将下溢并产生 NaN。当然,如果您遇到这种情况,也许您应该先检查您的输入,因为您在数字问题上已经处于危险的一面。