-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix categorical random shape #3060
Fix categorical random shape #3060
Conversation
I am fine with it
distribution.dist_math might be better |
Also rebase needed. |
3ee36c5
to
7252674
Compare
@junpenglao Currently running linting and coverage overnight but do let me know if anything is missing. I still do have a question about the comment on the shapes. Given the test_scalar_parameter_shape test does it still make sense to have random_choice return an (x,1) shape array? Thanks for the quick comment |
Some tests are failing. I'll check them out |
7252674
to
9a84dac
Compare
One last thing, I still need to run the examples in docs/source/notebooks, but wanted to make sure my implementation at the code level was ok before proceeding. |
Cool. |
pymc3/distributions/dist_math.py
Outdated
samples = np.row_stack([np.random.choice(k, p=p_) for p_ in p]) | ||
else: | ||
samples = np.random.choice(k, p=p, size=size) | ||
return samples |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing new-line
@junpenglao and @twiecki thanks for the feedback In regards to the shape, I think an input size of (10,5) matrix with an output size of (10,) would break the below but I could be mistaken. Is my understanding correct? Below is a screenshot as well showing how the test expects random_choice to output the same size array as the input. Lastly I'll be away for the next week but can finish this when I get back! |
ac5d6f2
to
51c7f1b
Compare
Yes you should change that test for Categorical - the shape of the output from Categorical random is not the same as parameters. |
Hello, I'm back and will be working on this again this weekend! Just wanted to give a heads up |
pymc3/distributions/discrete.py
Outdated
) | ||
else: | ||
return np.asarray(np.random.choice(k, p=p, size=size)) | ||
|
||
def random(self, point=None, size=None): | ||
p, k = draw_values([self.p, self.k], point=point, size=size) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@junpenglao @twiecki Just for my own understanding why is draw_values called here? Why can't we just use generate_samples
directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize this may be a really basic question, but I'm biasing towards asking rather than assuming as I learn more about pymc3 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, i think this was a question for me: draw_values
is generally to get the parameters of a distribution to the right shape (size=size
), with the right conditioning (point=point
). The generate_samples
function actually draws new samples for an RV.
If you trace the code, draw_values
will call .random
on each of the variables, which will (usually) end up at generate_samples
. This is how we traverse back up the computation graph.
51c7f1b
to
efa5816
Compare
def test_scalar_parameter_shape(self): | ||
rv = self.get_random_variable(None) | ||
# for size, expected in ((None, (1,)), (5, (5, 1)), ((4, 5), (4, 1))): | ||
for size, expected in (((4, 5), (4, 1)),): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So while I fixed the original inciting case in the issue, I don't know enough about all the possible ways that categorical.random could be called to know how to modify these tests correctly.
The original example passes p
as a parameter to dist.random
and that case is handled
This test passes size
to dist.random
and I don't understand how that should be handled by Categorical.random
or if this ever happens during nominal use of this library.
Any guidance would be appreciated and thanks for bearing with me while I learn the ropes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to be clear, in this example, you expected v.shape
to be (10, 5)
, right? I tried to get draw_values
and generate_samples
to return something shaped roughly the following way:
- broadcast the parameters together using
np.broadcast
to get their shape. Call itd1
. - look at the
shape
argument passed to the random variable, and call itd2
. Try to combined1
andd2
in a sensible way, and throw an exception instead of guessing too much. This is the bulk of thedraw_values
code. We'll sayd3
is the combination ofd1
andd2
- return something of shape
size x d3
Explicitly, consider `x = pm.Normal.dist(mu=np.random.rand(5), sd=1, shape=(2, 5)).random(size=10)
- The size of
mu
is(5,)
, andsd
is()
, and broadcasting them gives(5,)
- The shape argument (
(2, 5)
) fits nicely with the broadcast shape, sod3
above is(2, 5)
. Note thatshape=(2, 4)
throws an exception. - We return an array of shape
(10, 2, 5)
, since the size argument was 10.
I hope this helps!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @ColCarroll
I believe v.shape should be (10,1) per the issue @junpenglao filed? #3035
I've read your comments and want to read them a couple more times before asking any other follow up questions. This is very helpful!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would either of you mind if I put the deduplication of random_choice
on another pull request so it can be merged independently of the shape issue? All tests were passing for that portion of the code.
I ask because I think it'll streamline the code changes and reduce the risk of conflicts later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing. Which PR is that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just created it here. Pending CI tests at time of writing
#3084
efa5816
to
cadee9c
Compare
@junpenglao and @ColCarroll Starting a new thread since I jumbled the last one. I also updated the commit tree with code that only relevant to the discussion around shape. To summarize To directly address @ColCarroll's statement. I do not expect However I have no idea if this change breaks people's code. I certainly broke a number of tests. The tests all ensure that the correct I tried reading a bunch of closed issues but I ended up a little more confused than I originally started. So starting off with my first question Lastly, if it becomes too much to answer my questions please let me know. My intention is to help contribute to pymc3 but if it takes 5 hours of questions from me to get 1 hour of work done then it's may have ended up detracting from you guys :( I truly do appreciate the help thus far. Thank you |
Looking at the failed test, I think you are getting really close :-) Currently, most of the test fail is matching (n, ) with (n, 1). I dont have a strong feeling of this, I guess if you modify it to return a (n, ) is fine as well. Not sure which one makes more sense tho... I asked twitter https://twitter.com/junpenglao/status/1018242975682453504 the test mismatch of (4, 5) and (4, 1) you should just go ahead and modify the test. the test mismatch of (5, 10, 5) and (50, 5) would need some investigation. |
1c19ce1
to
be8c44b
Compare
@ColCarroll @junpenglao |
Did you implement a new test for this? |
I did not but should have, I'll change this back to WIP and do that sometime before Sunday, My apologies |
be8c44b
to
1263e02
Compare
@junpenglao I think I'm ready for what I hope is the final code review! Hopefully this is the one that makes it |
Awesome! One less shape issue ;-) |
Hello,
This pull request is for #3035 and is very much in WIP.
To summarize I tried to hit two objectives per @junpenglao request, one was removing duplication of random draws from categorical, the other was address the shape.
For removing duplication
I created a function in distribution called random_choice and pointed the previous methods to it. All tests are passing in this structure.
Questions I have
Is this name good or should it be called categorical_random_choice?
Is distributions.py a good place for it?
For the shape comment
I believe there is an expectation that if a (10,5) size is requested, the method returns a (10,5) array.
These tests specifically seem to test for that behavior.
pymc3.tests.test_distributions_random.BaseTestCases.BaseTestCase#test_scalar_parameter_shape
pymc3.tests.test_distributions_random.BaseTestCases.BaseTestCase#test_scalar_shape
Given that I don't understand how this test reconciles with the original issue, but this is not to suggest the request was wrong. I'm very much at the edge of my understanding and feel like I'm missing something.
How should I proceed?
I've attached some supporting screenshots that may help. Thanks for the chance to participate and leanr