Add functions to compute and combine Gaussian statistics (contribution from Samsung, AI Center, Cambridge) - #2857
Conversation
8ecb922 to
6543aff
Compare
|
This code looks good, its clean and fits the speechbrain design philosophy of providing clear reference algorithms. I admit that its a bit wordy for my taste and handles edge cases that I feel are unnecessary, but perhaps that's for the best. I'm not sure we really need to support |
|
Great. I've started to add support for masks, which I should be able to get in by Tuesday. What edge cases could I get rid of you think? I do agree it has ended up wordy. |
| if dim == (): | ||
| return 1, x, torch.zeros_like(x) |
There was a problem hiding this comment.
Mainly I was thinking of this edge case, I'm not too concerned about someone passing an empty tuple here, and if they did I'm guessing it would break in predictable ways. But honestly this is only two lines, so, who cares?
There was a problem hiding this comment.
Meaning we can probably just leave it as-is.
6543aff to
57bbb9b
Compare
rogiervd
left a comment
There was a problem hiding this comment.
@pplantinga sorry about the delay. This should now be ready. Adding support for masks was a bit more of a hassle than I thought.
| This tensor should have the same number of dimensions as "x". | ||
| The dimensions indicated by "dim" should have the same size as the | ||
| matching dimensions in "x". | ||
| The other dimensions should have size 1. |
There was a problem hiding this comment.
@pplantinga would you mind checking that this is indeed the correct specification for the mask?
There was a problem hiding this comment.
Thinking about this more, especially with the number of checks we would have to do, I wonder if we shouldn't actually just pass the relative lengths here and create the mask in the correct format. This is a pretty complex mask structure that may confuse anyone trying to use this.
There was a problem hiding this comment.
I think the problem is dim. I feel like writing down and checking the shape of the lengths tensor is going to be just as complicated.
| If None, then statistics will be computed over all dimensions and | ||
| scalar-valued statistics will be returned. | ||
| () has the same effect as None, which is nonsensical but it consistent | ||
| with torch.sum and friends. |
There was a problem hiding this comment.
I realised that dim=() worked strangely since this is what torch.sum implements. Now I just inherit this behaviour.
There was a problem hiding this comment.
Makes sense, but perhaps we don't need to mention that out in our doctsring -- I don't know if anyone will ever call this function directly (only through input norm) and if they do I doubt they would call it with dim=()
There was a problem hiding this comment.
Well the function is general enough! Why restrict use to input normalisation?
pplantinga
left a comment
There was a problem hiding this comment.
I am of the opinion that we should re-think the way the masks are done. This also still doesn't support skipping the variance calculation.
| If None, then statistics will be computed over all dimensions and | ||
| scalar-valued statistics will be returned. | ||
| () has the same effect as None, which is nonsensical but it consistent | ||
| with torch.sum and friends. |
There was a problem hiding this comment.
Makes sense, but perhaps we don't need to mention that out in our doctsring -- I don't know if anyone will ever call this function directly (only through input norm) and if they do I doubt they would call it with dim=()
| This tensor should have the same number of dimensions as "x". | ||
| The dimensions indicated by "dim" should have the same size as the | ||
| matching dimensions in "x". | ||
| The other dimensions should have size 1. |
There was a problem hiding this comment.
Thinking about this more, especially with the number of checks we would have to do, I wonder if we shouldn't actually just pass the relative lengths here and create the mask in the correct format. This is a pretty complex mask structure that may confuse anyone trying to use this.
| ], | ||
| ) | ||
| @pytest.mark.parametrize("use_mask", [False, True]) | ||
| @pytest.mark.parametrize("random_seed", [20250304, 20250326, 20250327]) |
There was a problem hiding this comment.
Do we really need to parameterize the seed? It seems like this multiplies the tests by 3 without a good cause. In general, I found it harder to debug the tests when there were too many of them because I had to scroll through so many to find the one I was debugging.
There was a problem hiding this comment.
It did make a difference in the tests. Would you prefer a for-loop and an extra level of indentation? (I don't, hence the current format.)
There was a problem hiding this comment.
Okay, this is fair if it makes a difference.
Isn't this how masks are done all across SpeechBrain, apart from swapping True/False maybe? For the case where I would personally have left
Earlier you said
so I left out support for the variance calculation. My main problem with it is that I don't know how to express in the type system that if you put in a Tensor for |
Perhaps you're right that the problem is |
pplantinga
left a comment
There was a problem hiding this comment.
I think we should just go ahead with the mask version because it is more flexible -- handles more cases than just using the length, even if it is a little more complex.
| ], | ||
| ) | ||
| @pytest.mark.parametrize("use_mask", [False, True]) | ||
| @pytest.mark.parametrize("random_seed", [20250304, 20250326, 20250327]) |
There was a problem hiding this comment.
Okay, this is fair if it makes a difference.
|
Feel free to merge @pplantinga |
What does this PR do?
This adds functions to compute and combines Gaussian statistics (mean and variance) on data. This comes out of me reviewing #2835, which also implements this.
However, I'm not clever enough to be confident that I fully understand this aspect of #2835, so I hereby offer an implementation which is simple enough that even I can understand it. Since the code is split up into different functions that each do one thing and can easily be tested and each require a docstring, the line count is a bit higher.
combine_gaussian_statisticsandcombine_gaussian_statistics_distributedcompute the overall mean and variance from multiple means and variances exactly as if they were computed on all the data concatenated. After formulating the desired behaviour this way, the unit tests can test exactly this. For the DDP tests, I've copy-pasted from #2835.@pplantinga if this looks interesting, I will still add support for
std=None(assuming this is really necessary), and for masks.Before submitting
PR review
Reviewer checklist