plenoptic-org / plenoptic

Visualize/test models for visual representation by synthesizing images.
https://plenoptic.readthedocs.io/en/latest/
MIT License
61 stars 9 forks source link

ffmpeg and Flatiron Binderhub #268

Closed billbrod closed 4 months ago

billbrod commented 4 months ago

ffmpeg (which gets used as the backend for the matplotlib animation functions we use) appears to be trying to grab all the threads available, at least on the Flatiron Binderhub. This is bad when there are multiple people using the binderhub, and slows everything to a crawl.

Figure out either how to reduce the number of threads it uses (through matplotlib's interface), or switch to a different animation backend. since we're in a jupyter notebook, some javascript might be better.

billbrod commented 4 months ago

I think, broadly, there are two possible solutions here:

billbrod commented 4 months ago

When using 'jshtml', I also need to raise plt.rcParams['animation.embed_limit'] in order to render the whole animation. Even in cases where the animation that ffmpeg would save out is very small. e.g.,

mdl = po.simul.Gaussian(7)
po.tools.remove_grad(mdl)
mdl.eval()

img = po.data.einstein()
met = po.synth.Metamer(img, mdl)
met.synthesize(100, store_progress=True)

then

plt.rcParams['animation.html'] = 'jshtml'
po.synth.metamer.animate(met)

needs an embed limit of between 40 and 50 MB, whereas

plt.rcParams['animation.writer'] = 'ffmpeg'
anim=po.synth.metamer.animate(met)
anim.save('test.mp4')

creates a 320K video. presumably because ffmpeg can use the h264 codec and the javascript writer can't?

Because of that and the fact that jshtml seems to be slower than ffmpeg, it might be worth just telling ffmpeg to use a single thread (even though ffmpeg is an additional installation).

Basically:

billbrod commented 4 months ago

Okay, I think the embed issue is pretty serious (users could easily have a huge uncompressed video as the output of our animation methods), so I'm going to stick with ffmpeg, but force a single thread and set rcParams['animation.html'], which will allow me to get rid of the convert_anim_to_html helper function.

billbrod commented 4 months ago

To finish this up, the following should be added to the top of every notebook that creates an animation:

plt.rcParams['animation.html'] = 'html5'
# use single-threaded ffmpeg for animation writer
plt.rcParams['animation.writer'] = 'ffmpeg'
plt.rcParams['animation.ffmpeg_args'] = ['-threads', '1']

This is especially important for binders used during workshops, but not a bad idea to put on our docs examples as well

We can then also remove the convert_anim_to_html function as well.

billbrod commented 4 months ago

When using ffmpeg as the animation writer, ffmpeg is required both for saving and displaying in notebooks. Previously, I had thought it was only required for saving the movie.