Registration Algorithm or Evolution Optimizer Not Deterministic

I am following the example registration11 found here: ITK: Examples/RegistrationITKv3/ImageRegistration11.cxx

Everything works, except the results are not deterministic. When I run it multiple times, I am getting different answers. I copied the code exactly except that I made the minor changes from 2d to 3d optimization to cover registering CBCT to CT (two 3d datasets).

When I say it isn’t deterministic, I mean that the answer can vary quite a lot between runs, sometimes more than 6 or 7 mm. In the example, it mentions to set a seed value of 12345 for the generator. I would have thought that would ensure it is deterministic, but it doesn’t. Maybe there is an issue with floating point precision or something?

Or maybe this optimizer in this example is non-deterministic? Even if true, I would expect the results to vary so much, unless it is very easy to fall into local minima?


Is there any particular reason you are using the legacy “ITKv3” registration framework?

I tried the newer example 11 from ITK 4 here: ITK: Examples/RegistrationITKv4/ImageRegistration11.cxx

This new version of the algorithm seems to not compile with short data (like CTs) and expects floats. The v3 version works with shorts. I can try creating new float versions of the CT short images and trying again with that v4 example and let you know.

As far as examples from ITK 5, I see the example here: Perform Multi Modality Registration With Viola Wells Mutual Information — v5.4.0
But this example uses Gradient Descent, which seemed a bit slower than the Evo in my initial testing. I guess I can try that example of similar code with a different optimizer. The example, as written, seems to support shorts though.

So, yes, I have lots of things to try, but I am still curious about the question of the non-deterministic results of my current approach.


Take a look at this discussion about registration reproducibility:

I was afraid that this was a threading issue…

Still, I tried setting the number of threads =1 using
export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=1 as done in the forum thread in the previous discussion you linked. Although this slowed down the registration considerably, it did not make the optimizer have consistent results.

As suggested earlier, I will abandon this current approach as demonstrated in the example from v3 and try to refactor my code to use v4 or later examples and see if that improves.


Using 1 thread and setting the random seed to a constant is both required for full reproducibility. Just using 1 thread is not enough.

v3 registration framework was choosing a different random sample in each iteration, v4 uses the same random sample for all iterations (if memory serves me well), but both should be reproducible with 1 thread and a set seed.

I was already initializing the random seed to a constant value as shown in the example with and without single threading it via code: generator->Initialize(12345);

Are you referring to something else (another seed or method)?

I think there is just one seed in ITK. Registration framework v3 might have some further non-determinism. Trying v4 sounds like the obvious next step.