# Unstable iteration for registration

**URL:** <https://discourse.itk.org/t/unstable-iteration-for-registration/410>\
**Category:** Algorithms\
**Tags:** python\
**Created:** [November 13, 2017, 8:04am UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410 "2017-11-13T08:04:56Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![zhuangming.shen](https://discourse.itk.org/letter_avatar_proxy/v4/letter/z/4af34b/32.png) [@zhuangming.shen](https://discourse.itk.org/u/zhuangming.shen)\
**Post date:** [November 13, 2017, 8:04am UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/1 "2017-11-13T08:04:57Z")

</div>

Hi all,

I am using itk.RegularStepGradientDescentOptimizerv4 to perform a multiresolution translation registration between two images. I ran my code in the same computation environment for the same two images at different times, but I got a slightly different results (please see the attached figures) during the iterations. I checked the results and found the difference mostly starting from the middle level of a image pyramid (I used 3-level image pyramid), and then the difference would be increased and increased, something like “butterfly effect”. Actually, I have applied “ReturnBestParametersAndValueOn” for itk.RegularStepGradientDescentOptimizerv4. So I wonder is the phenomenon normal? If it is normal, how can I avoid this kind of unstable iteration as much as possible? Thanks in advance.

Regards,

Zhuangming Shen

Here is some parts of my code.

translation\_registration = itk.ImageRegistrationMethodv4[itk.Image.F3, itk.Image.F3].New()

translation\_interpolator\_fixed\_image = itk.LinearInterpolateImageFunction[itk.Image.F3, itk.D].New()  
translation\_interpolator\_moving\_image = itk.LinearInterpolateImageFunction[itk.Image.F3, itk.D].New()

translation\_metric = itk.MattesMutualInformationImageToImageMetricv4[itk.Image.F3, itk.Image.F3].New()  
translation\_metric.SetFixedInterpolator(translation\_interpolator\_fixed\_image)  
translation\_metric.SetMovingInterpolator(translation\_interpolator\_moving\_image)  
translation\_metric.SetFixedImageMask(fixed\_object)  
translation\_metric.SetNumberOfHistogramBins(32)

translation\_transform = itk.TranslationTransform[itk.D, 3].New()

translation\_optimizer\_scales = itk.OptimizerParametersitk.D  
translation\_optimizer\_scales.SetSize(translation\_transform.GetNumberOfParameters())  
translation\_optimizer\_scales.SetElement(0, 1.0) # x translation  
translation\_optimizer\_scales.SetElement(1, 1.0) # y translation  
translation\_optimizer\_scales.SetElement(2, 1.0) # z translation

translation\_optimizer = itk.RegularStepGradientDescentOptimizerv4[itk.D].New()  
translation\_optimizer.SetScales(translation\_optimizer\_scales)  
translation\_optimizer.SetNumberOfIterations(100)  
translation\_optimizer.SetLearningRate(6.0)  
translation\_optimizer.SetMinimumStepLength(1e-1)  
translation\_optimizer.SetDoEstimateLearningRateAtEachIteration(True)  
translation\_optimizer.ReturnBestParametersAndValueOn()

translation\_registration.SetFixedImage(caster\_fixed\_image.GetOutput())  
translation\_registration.SetMovingImage(caster\_moving\_image.GetOutput())  
translation\_registration.SetMetric(translation\_metric)  
translation\_registration.SetOptimizer(translation\_optimizer)  
translation\_registration.SetInitialTransform(translation\_transform)  
translation\_registration.SetShrinkFactorsPerLevel([4, 2, 1])  
translation\_registration.SetMetricSamplingPercentagePerLevel([1,1,1])

def iterationUpdate():  
current\_parameters = translation\_registration.GetOutput().Get().GetParameters()  
print "[%d] optimizer value: %f current step length: %f current parameters: %f %f %f " %(translation\_optimizer.GetCurrentIteration(), translation\_optimizer.GetValue(), translation\_optimizer.GetCurrentStepLength(), current\_parameters.GetElement(0), current\_parameters.GetElement(1), current\_parameters.GetElement(2))

iteration\_command = itk.PyCommand.New()  
iteration\_command.SetCommandCallable(iterationUpdate)  
translation\_optimizer.AddObserver(itk.IterationEvent(), iteration\_command)

translation\_registration.Update()

 ![Fig1](https://discourse.itk.org/uploads/default/original/1X/0891fab0bf0672f603c0c536242bc586a5484176.PNG)  
 ![Fig2](https://discourse.itk.org/uploads/default/original/1X/f12476f853530076c9dabf08daa13f105d13599d.PNG)

---

<div class="post-metadata">

**Author:** ![dzenanz](https://discourse.itk.org/user_avatar/discourse.itk.org/dzenanz/32/1093_2.png) [@dzenanz](https://discourse.itk.org/u/dzenanz)\
**Post date:** [November 13, 2017, 2:19pm UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/2 "2017-11-13T14:19:53Z")

</div>

Have you tried `translation_metric.ReinitializeSeed(12345);`?

[The documentation](https://itk.org/Doxygen/html/classitk_1_1ImageToImageMetric.html#a17338aa67b8766a743deca84f004b9da).

---

<div class="post-metadata">

**Author:** ![zhuangming.shen](https://discourse.itk.org/letter_avatar_proxy/v4/letter/z/4af34b/32.png) [@zhuangming.shen](https://discourse.itk.org/u/zhuangming.shen)\
**Post date:** [November 14, 2017, 1:31am UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/3 "2017-11-14T01:31:30Z")

</div>

Hi dzenanz,

I added translation\_registration.MetricSamplingReinitializeSeed(12345) to the code but still got non-deterministic results. It seems still existing random sampling in other places of the code. Any suggestion.

Regards,

Zhuangming Shen

 ![Fig3](https://discourse.itk.org/uploads/default/original/1X/4481c8f0e00afea1ffa2d790f6e746adfecc55a7.PNG)  
 ![Fig4](https://discourse.itk.org/uploads/default/original/1X/097ced333145410f633a23a99e5108ea7c5c04f5.PNG)

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [November 14, 2017, 2:39am UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/4 "2017-11-14T02:39:03Z")

</div>

What happens if you use only one thread? What happens if you use a different metric?

---

<div class="post-metadata">

**Author:** ![zhuangming.shen](https://discourse.itk.org/letter_avatar_proxy/v4/letter/z/4af34b/32.png) [@zhuangming.shen](https://discourse.itk.org/u/zhuangming.shen)\
**Post date:** [November 14, 2017, 3:24am UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/5 "2017-11-14T03:24:05Z")

</div>

Hi blowekamp,

Thank you for your reply. But I’m not sure how can I configure to use one thread? I just added translation\_registration.SetNumberOfThreads(1) to the code, but it still ran multithreads according to Linux “Top”.

The ITK 4.12.1 I used now only supports two metric for python-based image registration v4, i.e. MattesMutualInformationImageToImageMetricv4 and MeanSquaresImageToImageMetricv4. Because I need to align multimodal images, I have to use MattesMutualInformationImageToImageMetricv4.

Regards,

Zhuangming Shen

---

<div class="post-metadata">

**Author:** ![dzenanz](https://discourse.itk.org/user_avatar/discourse.itk.org/dzenanz/32/1093_2.png) [@dzenanz](https://discourse.itk.org/u/dzenanz)\
**Post date:** [November 14, 2017, 3:47am UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/6 "2017-11-14T03:47:53Z")

</div>

You tried option 3 from [here](https://public.kitware.com/pipermail/insight-users/2008-July/026850.html). You can try options 1 or 2.

---

<div class="post-metadata">

**Author:** ![zhuangming.shen](https://discourse.itk.org/letter_avatar_proxy/v4/letter/z/4af34b/32.png) [@zhuangming.shen](https://discourse.itk.org/u/zhuangming.shen)\
**Post date:** [November 14, 2017, 5:29am UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/7 "2017-11-14T05:29:36Z")

</div>

Hi dzenanz,

I tried option 1 and the code used only one thread. Now it shows deterministic results. So it seems the multi-threads cause the unstable registration. Can ITK guys fix the issue otherwise using one thread is too slow for practical medical image registration application?

Regards,

Zhuangming Shen

---

<div class="post-metadata">

**Author:** ![dzenanz](https://discourse.itk.org/user_avatar/discourse.itk.org/dzenanz/32/1093_2.png) [@dzenanz](https://discourse.itk.org/u/dzenanz)\
**Post date:** [November 14, 2017, 2:40pm UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/8 "2017-11-14T14:40:35Z")

</div>

Having the metric algorithms be deterministic while being parallel would somewhat hurt their performance. I suppose that the decision was made to have the high performance for the parallel case, and determinism for single-threaded case. Determinism is usually required for debugging only.

@blowekamp @matt.mccormick @fbudin Is this the case, or is non-determinism with multiple threads but fixed seed a bug?

---

<div class="post-metadata">

**Author:** ![blowekamp](https://discourse.itk.org/user_avatar/discourse.itk.org/blowekamp/32/79_2.png) [@blowekamp](https://discourse.itk.org/u/blowekamp)\
**Post date:** [November 14, 2017, 3:00pm UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/9 "2017-11-14T15:00:40Z")

</div>

In the MattesMutualInformation metric, I am aware that the order of accumulation is non-deterministic with multiple threads. The magnitude of the difference seems plausible for this to be the source. I would try just setting the metric to use a single thread to verify the metric is the source of the non-determinism.

You may want to try the JointHistogramMutualInformation metric I don’t believe it has the same “optimization” as the mattes metric. It does not sound like it’s available in ITK Python, but it is available in SimpleITK along with all the other ITKv4 metrics and optimizers. There is not reason it can’t be wrapped in ITK python with the appropriate application of time and effort.

IMHO determinism or bounds of error is needed for reproducible research.

---

<div class="post-metadata">

**Author:** ![zhuangming.shen](https://discourse.itk.org/letter_avatar_proxy/v4/letter/z/4af34b/32.png) [@zhuangming.shen](https://discourse.itk.org/u/zhuangming.shen)\
**Post date:** [November 15, 2017, 12:45am UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/10 "2017-11-15T00:45:02Z")

</div>

Hi dzenanz and blowekamp,

Thanks for your promptly response. I think Matt has wrapped JoinHistogramMutualInformation metric ([http://review.source.kitware.com/#/c/22738/](http://review.source.kitware.com/#/c/22738/)) for me. I will try it but I still expect you could solve the problem.

Regards,

Zhuangming Shen

---

<div class="post-metadata">

**Author:** ![zhuangming.shen](https://discourse.itk.org/letter_avatar_proxy/v4/letter/z/4af34b/32.png) [@zhuangming.shen](https://discourse.itk.org/u/zhuangming.shen)\
**Post date:** [November 15, 2017, 2:39am UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/11 "2017-11-15T02:39:40Z")

</div>

Hi blowekamp,

You’re right. I tried JointHistogramMutualInformation metric, the results for different runs are consistent. Thanks for your suggestion.

Regards,

Zhuangming Shen

---

<div class="post-metadata">

**Author:** ![matt.mccormick](https://discourse.itk.org/user_avatar/discourse.itk.org/matt.mccormick/32/7_2.png) [@matt.mccormick](https://discourse.itk.org/u/matt.mccormick)\
**Post date:** [November 16, 2017, 9:19pm UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/12 "2017-11-16T21:19:33Z")

</div>

Hi Zhuangming,

To confirm, considerable effort and improvements were made to the _v4_ registration similarity matching metrics to give consistent results. Setting the random number generator seed and using the _v4_ metrics will help ensure consistency.

Regards,  
Matt

---

<div class="post-metadata">

**Author:** ![zhuangming.shen](https://discourse.itk.org/letter_avatar_proxy/v4/letter/z/4af34b/32.png) [@zhuangming.shen](https://discourse.itk.org/u/zhuangming.shen)\
**Post date:** [November 17, 2017, 4:53am UTC](https://discourse.itk.org/t/unstable-iteration-for-registration/410/13 "2017-11-17T04:53:40Z")

</div>

Hi Matt,

I believe you have done a lot of work to make v4 registration more robust and efficient than v3 registration. Hope v4 registration can be better and better.

Regards,

Zhuangming Shen
