Skip to content

Implement ATen Distributions.cu + Poisson#58

Closed
rachtsingh wants to merge 7 commits into
probtorch:masterfrom
rachtsingh:poisson
Closed

Implement ATen Distributions.cu + Poisson#58
rachtsingh wants to merge 7 commits into
probtorch:masterfrom
rachtsingh:poisson

Conversation

@rachtsingh

@rachtsingh rachtsingh commented Dec 31, 2017

Copy link
Copy Markdown

I got a bit into the weeds and the scope expanded, but I think this is the right way to do it. This PR (will) implement a pointwise Poisson sampling method for CPU/CUDA, and should be followed up quickly with ports of the Gamma / Dirichlet samplers, and other things we might want to use from distributions.c.

So far:

  • Renames Generator inside THCRandomTensor.h to be THCGenerator, and fix CUDAGenerator instantiation
  • Implement Poisson distribution + torch.poisson (Variable only for now, but we can wrap it).
  • Write tests for the distribution.
  • Implement a Philox-based sampler for rejection sampling.

@rachtsingh

rachtsingh commented Jan 2, 2018

Copy link
Copy Markdown
Author

Ah, not quite ready for review yet, by the way - I still need to debug this CUDA issue and write tests.

I tried refactoring to use ATen instead (which is much cleaner), but I can't figure out how to sample a uniform given a CUDAGenerator reference (which doesn't seem to have a reference to any curandState*-types). If anyone has a pointer that would be great.

@fritzo fritzo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note you should register this in the EXAMPLES list in test_distributions.py. When you do so, tests will fail because you do not implement .entropy(). If you don't want to implement .entropy() (which as I understand has no closed form for Poisson), you should allow NotImplementedError in TestDistributionShapes.test_entropy_shape():

- actual_shape = dist.entropy().size()
+ try:
+     actual_shape = dist.entropy().size()
+ except NotImplementedError:
+     continue

Comment thread aten/src/THC/THCTensorRandom.cu Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Consider reverting unnecessary whitespace changes to ease review by PyTorch folks.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I usually squash before review but I'll be more on top of it.

@rachtsingh rachtsingh changed the title Implementation of Poisson distribution + torch.poisson(...) Implement ATen Distributions.cu + Distributions.cpp Jan 3, 2018
@gchanan

gchanan commented Jan 3, 2018

Copy link
Copy Markdown

On your question, I don't think we should add calls to get random numbers directly to the generator; the normal pattern is to pass in the generator to a function that generates the random numbers, right?

@rachtsingh

rachtsingh commented Jan 3, 2018

Copy link
Copy Markdown
Author

Yeah, that sounds right. I'm not sure about casting the result of unsafeGetTH from void * to be able to sample though - is it ok to change the generator to output the specialized Generator when parsing native_functions.yaml?

EDIT: taken care of, I didn't realize how at::globalContext works. I poked around with CUDA pointers for a bit and realized it's the same as the type's context, at least on my machine. Let me know if there's a multi-GPU issue.

@rachtsingh rachtsingh changed the title Implement ATen Distributions.cu + Distributions.cpp Implement ATen Distributions.cu + Poisson Jan 6, 2018
Comment thread aten/src/ATen/cuda/CUDAApplyUtils.cuh Outdated
//g if (!getApplyGrid(totalElements, grid)) {
//g return false;
//g }
//g grid = dim3(1);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is temporary - looking for advice on how to best limit the blockDim to 256 when calling CUDA_tensor_apply2

@rachtsingh

Copy link
Copy Markdown
Author

Ok, I think it's probably ready for review. @fritzo, given the C++/CUDA changes, it's probably best to ask someone from PyTorch to review as well? I don't know what exactly the plans are for CUDAGenerator, etc.

@fritzo fritzo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python code looks good. just one comment on parameter name. I have not reviewed CUDA code; let's do that review on pytorch/pytorch.

Comment thread torch/distributions/poisson.py Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: preceding underscore usually denotes a private variable. It's probably safer to call this lam or lambda_. Alternatively it would be nice to call it rate which is both semantically meaningful and improves compatibility with tensorflow distributions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example self._lambda would be the obvious member name but that looks private. Instead self.lambda_ or self.rate are clearly public.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both sound good to me. Let's use rate since that's more evocative? I.e. like mean/std in Normal already, and matches up with Exponential, which is the right idea.

@fritzo

fritzo commented Jan 8, 2018

Copy link
Copy Markdown

@apaszke How should we test the CUDA sampler? Do we use the same tests in test_distributions.py that we use for CPU samplers, or should these new tests live in test_cuda.py?

@apaszke

apaszke commented Jan 8, 2018

Copy link
Copy Markdown

I think test_distributions.py is ok. Just make unittest skip the tests if CUDA is unavailable (look at test_nn.py and test_autograd.py for examples).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to use tensor instead of zeros if you don't depend on the initial values of the tensor (it will be uninitialized)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this unstable in fp32? fp64 math is extremely slow on non-Tesla GPUs, and we should avoid it

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the right place for this copyright notice?

Comment thread torch/csrc/Module.cpp Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid adding more of the sampling methods to the global namespace. torch.distributions is the way to expose those samplers

@rachtsingh

rachtsingh commented Jan 8, 2018

Copy link
Copy Markdown
Author

Ok, think I addressed comments (thanks for the review!), and am removing poisson from the global namespace [running tests locally right now]. I'll move this PR to pytorch/pytorch afterwards.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you are having trouble with half, try DISPATCH_ALL_FLOATING_TYPES; dispatch_all uses Half and DISPATCH_ALL_FLOATING_TYPES uses half; we should resolve this, probably always using Half (and providing device conversion functions?). CC @colesbury

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that works!

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we would always use half for device functions and at::Half for host functions.

@rachtsingh

Copy link
Copy Markdown
Author

After doing some checks, it looks like curand_poisson without using the more robust API uses either an inverse CDF sampler or the transformed rejection method, neither of which are accurate for low values of lambda. So, it fails the distribution tests (good thing they work!).

I think there's 3 options - (1) to merge as-is (by raising the threshold on the CUDA version), but to warn that for low values of lambda, the results may be biased, or (2) merge the CPU version, not the GPU version, or (3) punt on this until we get Philox-based PRNGs up, which was what I was planning to tackle next.

@apaszke

apaszke commented Jan 9, 2018

Copy link
Copy Markdown

I'm fine with all options. I'll leave the decision to @fritzo

@fritzo

fritzo commented Jan 9, 2018

Copy link
Copy Markdown

Option 1 sounds very reasonable. You could also file an issue at probtorch/pytorch noting that we should revisit this.

@rachtsingh

rachtsingh commented Jan 15, 2018

Copy link
Copy Markdown
Author

OK, fixed the issues and added a Philox-based RNG. I don't think the sampling algorithm is the most accurate, but we can work on it in the future I think.

Also, I think there's a bug in the handling of failure_rate (note that I decreased that to make the tests pass), but I'll have to double check the math before fixing.

Let me know if this is good, I'll squash the commits to be 1 (or whatever you think is semantic), and then update the pytorch PR.

@rachtsingh

Copy link
Copy Markdown
Author

(discussing in pytorch#4556)

@rachtsingh rachtsingh closed this Jan 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants