Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reset random seed for deterministic registration #279

Open
Pedro-Filipe opened this issue Apr 16, 2024 · 7 comments
Open

Reset random seed for deterministic registration #279

Pedro-Filipe opened this issue Apr 16, 2024 · 7 comments

Comments

@Pedro-Filipe
Copy link

Hi, I was wondering if there is a way to reset the random seed used by ITKElastix.

In my Python code if I register a set of images, and then if I repeat this registration in the same dataset in the next loop iteration, I get slightly different pixel values for the registered images. I believe at least some of the randomness comes from this part of my bspline registration recipe:

// **************** Image sampling **********************
(NumberOfSpatialSamples 2048)
(NewSamplesEveryIteration "true")
(ImageSampler "Random")
//(ImageSampler "Full")

If I set sampler to (ImageSampler "Full") then the registration is deterministic, and I get the same results every iteration, but unfortunately it also takes significantly longer to register.

So my question is: is there a way to reset the random seed in the python code?

@dzenanz
Copy link
Member

dzenanz commented Apr 16, 2024

How about parameter_map['RandomSeed'] = ['30101983']? In the parameter file that might be (RandomSeed 30101983).

@dzenanz
Copy link
Member

dzenanz commented Apr 16, 2024

You should be able too look up all the Elastix parameters here, but the page is not working for me right now. @N-Dekker @ViktorvdValk Is that just me, or is the page really down?

@N-Dekker
Copy link
Collaborator

@Pedro-Filipe Thanks for asking! It may be helpful to reset the global ITK random number generator before each registration.

Which version of itk-elastix do you have installed? ITK v5.4rc02 introduces a new function, MersenneTwisterRandomVariateGenerator.ResetNextSeed(), which should be of help. I think it should be available with the latest itk-elastix release.

The idea is to call MersenneTwisterRandomVariateGenerator.ResetNextSeed() before each registration. Please let us know if that does indeed solve the problem!

@N-Dekker
Copy link
Collaborator

You should be able too look up all the Elastix parameters here, but the page is not working for me right now. @N-Dekker @ViktorvdValk Is that just me, or is the page really down?

Thanks for reporting this problem @dzenanz It's hopefully back online soon. For the time being, you may use the Internet Archive: https://web.archive.org/web/20230204115458/https://elastix.lumc.nl/doxygen/parameter.html

@Pedro-Filipe
Copy link
Author

Thank you both for your comments. Really appreciate the support.

How about parameter_map['RandomSeed'] = ['30101983']? In the parameter file that might be (RandomSeed 30101983).

@dzenanz The parameter RandomSeed sounds like an obvious answer to the problem but in practice it doesn't seem to do anything. I found a couple of posts on the SimpleElastix GitHub reporting similar behaviour.

Make SimpleElastix more deterministic by setting RandomSeed #460

multiple SimpleElastix instances/runs ignore RandomSeed in ParameterFile #122


@Pedro-Filipe Thanks for asking! It may be helpful to reset the global ITK random number generator before each registration.

Which version of itk-elastix do you have installed? ITK v5.4rc02 introduces a new function, MersenneTwisterRandomVariateGenerator.ResetNextSeed(), which should be of help. I think it should be available with the latest itk-elastix release.

The idea is to call MersenneTwisterRandomVariateGenerator.ResetNextSeed() before each registration. Please let us know if that does indeed solve the problem!

@N-Dekker I have these versions currently installed:

itk                          5.4rc2
itk-core                     5.4rc2
itk-elastix                  0.19.1
itk-filtering                5.4rc2
itk-io                       5.4rc2
itk-numerics                 5.4rc2
itk-registration             5.4rc2
itk-segmentation             5.4rc2

I have added this line of code before calling each registration:

itk.MersenneTwisterRandomVariateGenerator.ResetNextSeed()

It does reduce significantly the variation, although unfortunately not 100%. The values of the registered images differ after a few decimal places.

@N-Dekker
Copy link
Collaborator

@Pedro-Filipe I'm glad to hear that ResetNextSeed() reduces the variation significantly. You might consider to also do a SetSeed (while calling ResetNextSeed() as well), using a fixed constant seed, something like:

itk.MersenneTwisterRandomVariateGenerator.GetInstance().SetSeed(1)

(Not 100% sure about the syntax.) Does that further reduce the variation?

Another cause of variation could be multi-threading. You see, internally, elastix may do some floating point operations in a different order, depending on the order in which the threads process the work units. Mathematically, it should not matter, but the order of those floating point operations might affect the floating point rounding errors. You may eliminate those effects by setting the number of threads to one, globally:

itk.MultiThreaderBase.SetGlobalMaximumNumberOfThreads(1)

Obviously this may slow down the registration process. But it might still be interesting to know if that will totally eliminate all variations... I'm interested to hear what you will find!

@Pedro-Filipe
Copy link
Author

Pedro-Filipe commented Apr 17, 2024

Thanks for the additional suggestions @N-Dekker .

Results

Also using itk.MersenneTwisterRandomVariateGenerator.GetInstance().SetSeed(1)

Syntax seems OK, but didn't seem to have a significant effect.

Reducing threads with itk.MultiThreaderBase.SetGlobalMaximumNumberOfThreads(1)

Slows down registration as expected, but no effect on the randomness. I was sort of expecting this, as I use multithreading with the parameter (ImageSampler "Full") and I get reproducible results.


So at the moment, if I want deterministic results I can use:

  • (ImageSampler "Full") although you get a slower registration even with multithreading.
  • (ImageSampler "Grid") registration faster than full as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants