我使用SimpleITK在Python中制作了一个模块,我试图通过在C++中重新实现来加快速度。结果它慢了很多。
瓶颈是位移字段雅可比行列式过滤器的使用。
这两个片段给出了过滤器使用的示例。
1000代:C++=55s,python=8s
我应该期待c++更快吗?
def test_DJD(label_path, ngen):
im = sitk.ReadImage(label_path)
for i in range(ngen):
jacobian = sitk.DisplacementFieldJacobianDeterminant(im)
if __name__ == '__main__':
label = sys.argv[1]
ngen = int(sys.argv[2])
test_DJD(label, ngen)
和c++代码
typedef itk::Vector<float, 3> VectorType;
typedef itk::Image<VectorType, 3> VectorImageType;
typedef itk::DisplacementFieldJacobianDeterminantFilter<VectorImageType > JacFilterType;
typedef itk::Image<float, 3> FloatImageType;
int main(int argc, char** argv) {
std::string idealJacPath = argv[1];
std::string numGensString = argv[2];
int numGens;
istringstream ( numGensString ) >> numGens;
typedef itk::ImageFileReader<VectorImageType> VectorReaderType;
VectorReaderType::Pointer reader=VectorReaderType::New();
reader->SetFileName(idealJacPath);
reader->Update();
VectorImageType::Pointer vectorImage=reader->GetOutput();
JacFilterType::Pointer jacFilter = JacFilterType::New();
FloatImageType::Pointer generatedJac = FloatImageType::New();
for (int i =0; i < numGens; i++){
jacFilter->SetInput(vectorImage);
jacFilter->Update();
jacFilter->Modified();
generatedJac = jacFilter->GetOutput();
}
return 0;
}
我使用的是c++ITK 4.8.2,在Ubuntu 15.4上以"发布"模式编译。和python SimpleITK v9.0
您似乎在使用循环进行基准测试。使用循环进行基准测试不是一种好的做法,因为编译器和解释器对它们进行了大量优化。
我相信在这里
for i in range(ngen):
jacobian = sitk.DisplacementFieldJacobianDeterminant(im)
python解释器很可能意识到,您只使用了分配给jacobian
变量的最后一个值,因此只执行循环的一次迭代。这是一个非常常见的循环优化。
另一方面,由于您在C++版本(jacFilter->Update();
)中调用了几个动态方法,编译器可能无法推断其他调用没有被使用,这使得您的C++版本变慢,因为对DisplacementFieldJacobianDeterminant::update方法的所有调用都是实际进行的。
另一个可能的原因是Python中的ITK管道没有被强制更新,因为您在C++中显式地调用了jacFilter->Modified()
,但这在Python版本中并不显式。