yuxiang-gao / PySocialForce

Extended Social Force Model in Python for social navigation research
MIT License
128 stars 36 forks source link

Improve Overall Performance #6

Open Bonifatius94 opened 1 year ago

Bonifatius94 commented 1 year ago

Hi guys,

I'm using your PySocialForce package to model a robot / pedestrian interaction in a 2D world. It's really a great effort from your side to create this package and put it on PyPI. Unfortunately, it's a bit too slow for my reinforcement learning purposes in order to achieve a reasonable amount of training episodes for my robot. (I know I could scale out with A3C, but I'm just a poor student :joy:)

I've seen you've already put Numba optimizations into your code and modeled everything as NumPy array, so you're probably aware of the fact that performance is critical to a simulation environment. Have you ever profiled your package, e.g. with cProfile or the new Scalene? (I know, silly question, but I'll have to ask anyways. I can create a profile for you if you want :joy:)

I think you've still got lots of Python C-API overhead in your routines which could easily be eliminated by more Numba vectorizations. For example, you're computing the forces sequentially (https://github.com/yuxiang-gao/PySocialForce/blob/master/pysocialforce/simulator.py#L78). And for modeling the forces you're using OOP inheritance which could be replaced by a single function returning a float (https://github.com/yuxiang-gao/PySocialForce/blob/master/pysocialforce/forces.py#L39).

I'm willing to make a major contribution to your project in the near future in case I can figure out some sensible optimizations. Are you interested in a collaboration of any kind? I'll be carrying out this optimization anyways because I need a faster training for my master thesis :joy:

Best wishes, Marco

Bonifatius94 commented 1 year ago

Your obstacle force seems to take 98% of computation time when I instantiate a 80x80 world with 10 random obstacles. This linspace in scene.py is really bad for performance.

With actual 2D vector math this is almost for free. Just a bit of unit circle rotations to compute orthogonal directions to the obstacle lines, shifted by 90 deg, then intersecting the obstacle line with its orthogonal projection starting from the point to be checked. Line/line intersection can be programmed like so: https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection

I'll send you an updated version soon :wink:

yuxiang-gao commented 1 year ago

Hi @Bonifatius94 , Thanks for your interests in this project. That sounds amazing. I've been meaning to going back to this project for a while but never found the right time. I definitely would like to take up on your offer for a collaboration of some sort. Regarding the obstacle force calculation, I think issue #2 also touched on this. I agree the linespace thing is not very optimal representation of the obstacles. My original thoughts was to precompute the potential field for the obstacles instead of calculating them on the fly but I never got around to implement it as we internally use another simulator for training and finding the closest obstacle was handled by the simulator. Your proposal sounds reasonable for obstacles of geometric shapes and I think it is an pretty elegant solution for small maps. Please let me know what kind of assistance I can provide.

Best, Yuxiang

Bonifatius94 commented 1 year ago

@yuxiang-gao Oh that would be great if we could collaborate :smile: I'm currently getting into this repulsive force theory which I'm not familiar with. Let's see if I can figure out a more lightweight approach to this algorithm, shouldn't be too hard, I think :smile:

And yeah, as already said, I really need better performance because it's a show stopper for my RL trainings :sweat_smile:

Bonifatius94 commented 1 year ago

I'm trying the approach from this video with those two formulas for line/point distance and/or line segment/line intersection :smile:

I'm currently a bit occupied with calculating the partial derivative by x / y coords of the pedestrian's position, but this should at least work. What's your opinion on this approach? :wink:

Bonifatius94 commented 1 year ago

One question: You're initializing the forces with following. Is this meant to represent the forces for each pedestrian in separate x / y components? I'm just wondering, but it would totally make sense if I'm thinking about it because of the partial derivatives to compute the force in the first place :joy:

force = np.zeros((self.peds.size(), 2))
Bonifatius94 commented 1 year ago

I think I figured it out. At least it's now so fast that the SocialForce dominates. See here on my fork.

I didn't check if the force does the right thing though. We might need to experiment a bit and verify my math proofs :joy:

Bonifatius94 commented 1 year ago

I've debugged my obstacle force in a Jupyter notebook and it seems to work as expected. I'll try to convert those examples into unit tests. But now, some of your unit test scenarios seem to fail. Can you help me with debugging @yuxiang-gao ? 😉

And there is also an inherent issue with the potential field approach because it produces really weird behavior in a "walk through gate" scenario. Are you familiar with this problem and know an answer to this? 🤔

Bonifatius94 commented 1 year ago

I've created a branch where I removed all my bold refactorings and just made the minimal effort to put my new obstacle force in. You can have a look at it and merge if you like. I'm now working towards training my robot AI :smile: