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

Vectorise particle filter #365

Merged
merged 37 commits into from
Feb 18, 2021

Conversation

idorrington-dstl
Copy link
Contributor

Vectorised and optimised the particle filter.

Did this by creating a new particles object where the state_vector, weight, and parent attributes are vectors/arrays corresponding to the same attributes of the individual particles.

The most significant of the other optimisations made is that the pdf function now optionally outputs the indexes to sort the particles by size order. This saves us running np.argsort on the particle weights in the resample step leading to a ~35% decrease in run time (though it does make the code slightly harder to follow as the order of the particles is calculated in a different function to where it is used).

Sometimes the addition of noise to the last measurement call led to a target being out of the fov of the radar.
@sdhiscocks sdhiscocks requested review from a team, sdhiscocks, oharrald-Dstl and jmbarr and removed request for a team February 3, 2021 17:13
@sdhiscocks sdhiscocks added breaking A breaking change that required other to modify their code enhancement labels Feb 3, 2021
@sdhiscocks
Copy link
Member

sdhiscocks commented Feb 4, 2021

The most significant of the other optimisations made is that the pdf function now optionally outputs the indexes to sort the particles by size order. This saves us running np.argsort on the particle weights in the resample step leading to a ~35% decrease in run time (though it does make the code slightly harder to follow as the order of the particles is calculated in a different function to where it is used).

I took a look at this and agree that it's harder to read, and also would be better not too pass weights orders around. Out of interest, I tried using the log values to sort, to avoid overhead of the custom type, and then pure NumPy C optimised code could do the sort. I found applying the following to f4a1966 (commit before pdf change) yielded similar gains (which was a little unexpected TBH).

diff --git a/stonesoup/resampler/particle.py b/stonesoup/resampler/particle.py
index bb275766..77c11eb1 100644
--- a/stonesoup/resampler/particle.py
+++ b/stonesoup/resampler/particle.py
@@ -26,7 +26,8 @@ class SystematicResampler(Resampler):
             particles = Particles(particle_list=particles)
         n_particles = len(particles)
         weight = Probability(1/n_particles)
-        weight_order = np.argsort(particles.weight, kind='stable')
+        weights = np.array([weight.log_value for weight in particles.weight])
+        weight_order = np.argsort(weights, kind='stable')
         cdf = [v.log_value for v in np.cumsum([particles.weight[i] for i in weight_order])]

         # Pick random starting point

state_vector: StateVectors = Property(default=None, doc="State vectors of particles")
weight: MutableSequence[Probability] = Property(default=None, doc='Weights of particles')
parent: 'Particles' = Property(default=None, doc='Parent particles')
particle_list: MutableSequence[Particle] = Property(default=None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need a collection of StateVectors and a list of Particles? Could we do away with Particle altogether?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The list of particles was for backwards compatibility. In particular many of the unit tests loop over lists of particles so this was a good sanity check. I guess now I have finished vectorising and am confident I've not changed the output we could get rid of Particle and edit all the unit tests to use the new class?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So little on the fence either way with this one. The only thought I had, is there may be cases where you can't easily vectorise a function or operation, and therefore being able to loop over particles (as Particle states) to run a function/calculation, and use that list to repopulate the Particles, could be useful.

We probably should encourage people not to do this however, so should update our code/tests.

@codecov
Copy link

codecov bot commented Feb 5, 2021

Codecov Report

Merging #365 (0c42bd9) into master (35dae24) will increase coverage by 0.08%.
The diff coverage is 96.93%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #365      +/-   ##
==========================================
+ Coverage   94.09%   94.18%   +0.08%     
==========================================
  Files         133      133              
  Lines        6168     6222      +54     
  Branches      894      911      +17     
==========================================
+ Hits         5804     5860      +56     
+ Misses        263      262       -1     
+ Partials      101      100       -1     
Flag Coverage Δ
integration 65.98% <79.59%> (+0.20%) ⬆️
unittests 91.56% <94.89%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
stonesoup/types/state.py 99.22% <90.00%> (+0.02%) ⬆️
stonesoup/types/particle.py 94.33% <94.73%> (+0.58%) ⬆️
stonesoup/models/base.py 100.00% <100.00%> (ø)
stonesoup/models/measurement/nonlinear.py 98.93% <100.00%> (+0.03%) ⬆️
stonesoup/predictor/particle.py 85.71% <100.00%> (-1.79%) ⬇️
stonesoup/resampler/particle.py 100.00% <100.00%> (ø)
stonesoup/types/array.py 83.62% <100.00%> (+3.79%) ⬆️
stonesoup/types/numeric.py 100.00% <100.00%> (ø)
stonesoup/updater/particle.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 35dae24...0c42bd9. Read the comment docs.

Copy link
Member

@sdhiscocks sdhiscocks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great contribution, with significant performance improvement. A few suggestions and think one model missing being vectorised.

Would also be good to squash commits down as there a number of changes that were done and then undone, and rebase onto master.

stonesoup/models/base.py Outdated Show resolved Hide resolved
stonesoup/models/measurement/nonlinear.py Outdated Show resolved Hide resolved
stonesoup/models/measurement/nonlinear.py Outdated Show resolved Hide resolved
stonesoup/models/measurement/nonlinear.py Outdated Show resolved Hide resolved
stonesoup/resampler/particle.py Outdated Show resolved Hide resolved
stonesoup/types/numeric.py Outdated Show resolved Hide resolved
stonesoup/types/particle.py Show resolved Hide resolved
stonesoup/types/particle.py Outdated Show resolved Hide resolved
stonesoup/updater/particle.py Outdated Show resolved Hide resolved
@sdhiscocks sdhiscocks added this to the v0.1b4 milestone Feb 16, 2021
…r each particle.

Particles behaves like Particle when there is only one particle, so that we only need Particles.

Made the particles weights a list of probablilities to make it more like particle
…ist of particles. This makes it backwards compatible
idorrington-dstl and others added 7 commits February 18, 2021 14:10
…This method doesn't get called often, so doesn't affect run time significantly.
…n ParticleState (the weights are made as an array when the Particles object is made, so this never does anything)
…rticles class.

Check that either all particles have parents or none do and return ValueError otherwise.
Added tests to check that the Particles object will give ValueErrors when input is wrong.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking A breaking change that required other to modify their code enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants