5 ms·
As the article says, cuBLAS is deterministic, but other CUDA primitives (eg. some of those in cudNN) are not. Yes, the non-determinism is being introduced some
by n2d4 3y ago
As the article says, cuBLAS is deterministic, but other CUDA primitives (eg. some of those in cudNN) are not.
Yes, the non-determinism is being introduced somewhere, but that is splitting hairs. The point is that the primitives that you work with on GPUs are non-deterministic by design.
I mostly take issue with you phrasing it as a bug and using it to insult the authors.
- xyzzy_plugh 3y agoHow is that splitting hairs? > The point is that the primitives that you work with on GPUs are non-deterministic by design. This is just blatantly wrong. There are _some_ operations that can be non-deterministic in some scenarios but they are not necessary. GPUs are deterministic. If you ask them to add a million floats in order, you get the same result every time. If you ask them to add a million floats in some arbitrary order, then you may get different results every time. The distinction is that someone had to ask the GPU to do that. It's a choice. > I mostly take issue with you phrasing it as a bug and using it to insult the authors. It's a bug, whether it insults the authors or not is irrelevant. It's most definitely a bug.
- spott 3y agoBasically any parallel map-reduce operation using non-commutative reduce operators[0] is non-deterministic unless you specifically sort after/during the gather, or block on the gather (and gather to a thread-determined memory location). Sorting and blocking takes time. If you remove the sort/block, you will get a non-deterministic answer when operating on floats for a wide variety of reduce operations, but it will be faster. This is true of any parallel map-reduce, done anywhere (MPI, cuda kernels, openMP, spark, etc.), and is not unique to gpus/cuda. > If you ask them to add a million floats in order, you get the same result every time. There are a bunch of ways to add a million floats in order on a gpu, but they will all get you different results.: * split the million floats into ‘n’ chunks, each chunk is summed, then you sum the ‘n’ results. * if you sum results as they are gathered (you don’t need to block) you will get a non-deterministic result, as the threads finishing (outside of a warp) is non-deterministic in order. * if you change ‘n’, your result will change. * if you sort after gathering , your result will change. TLDR: parallel race-conditions are nondeterministic. Map-reduce has an underlying race-condition that you can prevent, but it costs time/performance. Sometimes you don’t care about the non-determinism enough to pay the performance penalty to fix it. [0] https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/icsecomp14seip-seipid15-p.pdf https://www.microsoft.com/en-us/research/wp-content/uploads/...
- dlkf 3y agoYour comment, along with cpgxiii and n2d4’s are all really good. I have a question: suppose training and inference of an LLM were made to be deterministic at the cost of performance. Would the cost be “everything will take twice as long” or would it be more like “inference will take a week and training will take a couple lifetimes”? If it’s the latter, then it seems disingenuous to call this a “bug.” It’s like saying F1 cars could be horse drawn, and they only use internal combustion for “performance reasons.” If its the former, then maybe there is a more interesting discussion to be had about the potential benefits of determinism? (That said, I agree with n2d4 that it’s stupid to insult the authors. Talk is cheap and building is hard.)
- xyzzy_plugh 3y ago> That said, I agree with n2d4 that it’s stupid to insult the authors. Talk is cheap and building is hard. If your code offers an expectation of determinism then it's sloppy to not distinguish where there isn't determinism. There's nothing difficult about writing a comment to the effect of "this function is non-deterministic. For deterministic results, use X". The code is sloppy if the developers didn't consider determinism and offer nothing to consumers, or if the consumers writing software cannot know where non-determinism is introduced. If that's somehow insulting then I'd say someone has very thin skin.
- eoerl 3y agoThere are flags[1] for that indeed. It feels like half of the people commenting here don't know all that much about the topic they're commenting upon 1: https://pytorch.org/docs/stable/generated/torch.use_deterministic_algorithms.html https://pytorch.org/docs/stable/generated/torch.use_determin...
- xyzzy_plugh 3y agoNothing I said conflicts with this, though? Yes, if you eschew determinism for the sake of raw performance then the result will be non-deterministic. But you don't have to do this, nor is it inherently untenable to solve these problems in a deterministic way. Sure it may require some performance overhead, and increase development time, but it's no different than writing deterministic code elsewhere. It's disingenuous to hand-wave away the solution because of some opaque cost or overhead we're unwilling to entertain. None of the parent posts ever mention performance tradeoffs. In particular there is no indication that the problem being discussed couldn't be solved with determinism in an equivalent amount of time. You're making my point: GPUs are deterministic, software may decide not to be.
- thaw13579 3y agoI think whether it’s a bug or not depends on the software requirements and expectations. If the code has some expected bounds on runtime, switching the GPU code to sequential processing (for the sake of exact reproducibility) would break that expectation and could be considered a bug as well. If we expect performant code and exact reproducibility, that just might not be possible…
- ascar 3y agoIt's hard to call it a bug given that any concurrent float sum or product will be different in regards to changing the amount of concurrency. Even if you order the final value per thread before reducing the result will differ if you use a different amount of threads to split the problem. Because in floating point arithmetic 1 + 2 + 3 + 4 is different than (1+2) + (3+4).