Fallback for missing attribute `Parameter.ds_numel`
#22193 added a parameter count for Deepspeed sharded models (i.e. using the `Parameter` attribute `ds_numel`). However, `Parameter` Tensors don't always have the `ds_numel` attribute (even when the model is sharded with Zero stage 3).

We can see how this is [alternatively handled in Deepspeed](https://github.com/microsoft/DeepSpeed/blob/ceccfa3ef68182384c6db1349fab43b9af3ed7f3/deepspeed/runtime/engine.py#L3220), by falling back to `Parameter.numel()` if `ds_numel` is not an attribute. I've added this fix to the function in question.

Fixes #24792

@stas00 @pacman100
Sure -- imo my rewrite was more readable but I guess that's subjective 👍 

Anyway, I've reverted the other changes and added the fix. Lmk, thanks!<|||||>> Sure -- imo my rewrite was more readable but I guess that's subjective +1
> 
> Anyway, I've reverted the other changes and added the fix. Lmk, thanks!

If I may share why I wrote it this way:

From the perspective of a user who doesn't know anything about deepspeed the current version is easier to understand since they don't need to go into that branch. 

From the perspective of a deepspeed user your original version is easier to read.

As there are many more non-deepspeed users the former version is preferred.

We could actually rewrite all of this code into a single line of 

```
p.ds_numel if hasattr(p, "ds_numel") else p.numel()
```
and not even need to check if it's running under deepspeed zero-3, but then the reader will wonder what in the world `ds_numel` is ;)

Thank you again for your contribution, @apoorvkh 
<|||||>_The documentation is not available anymore as the PR was closed or merged._