-
Notifications
You must be signed in to change notification settings - Fork 951
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
Shape error message #271
Shape error message #271
Conversation
👍 to more friendly error messages. I think |
@@ -249,6 +249,9 @@ def create_param(spec, shape, name=None): | |||
support initialization with numpy arrays, existing Theano shared | |||
variables, and callables for generating initial parameter values. | |||
""" | |||
if any([d == 0 for d in shape]): |
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.
You can omit the square brackets to make it a generator expression instead of a list comprehension.
/edit: And if 0 in shape
would be even more concise. But maybe we should change it to d < 0 for d in shape
to catch more problems.
Small changes are definitely okay! We just have to make sure that all the small changes add up to something consistent and coherent over time :) It seems that the original error message you quote would only come up with the I would formulate the error message slightly differently. Currently it only states the fact that a shape tuple has a zero in it. Something more informative would be "all shape elements should be > 0, but received (...)", I think. Maybe we need a better name for "shape element" as well. Is there any convention for this used by numpy / Theano? Also make sure to follow the Python PEP8 style guide, which we try to adhere to. Otherwise the Travis build will fail because it runs these checks. In this case, the line that raises the error is too long (lines should be 79 characters max). You can verify this by running our test suite, which will also run the PEP8 checks. Have a look at the development docs for more info: http://lasagne.readthedocs.org/en/latest/user/development.html |
@@ -249,6 +249,9 @@ def create_param(spec, shape, name=None): | |||
support initialization with numpy arrays, existing Theano shared | |||
variables, and callables for generating initial parameter values. | |||
""" | |||
if any([d == 0 for d in shape]): | |||
raise RuntimeError('An element in param shape is 0. shape=%r, name=%r' % (shape, name)) |
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.
That line is too long for pep8, please break it apart a bit. Plus, as Eben said, a ValueError
would be more appropriate. We need to change all those RuntimeError
s into something more suitable (#196)!
Finally, I'd slightly change the error message to: "Tried to create param %r with shape containing zeros: %r"
This hints at the fact that the creation of a parameter failed (as opposed to an existing parameter being found with a funny shape).
I've edited the commit based on comments. I went back and tested on non-Orthogonal initialization. It turns out that it fails silently if the shape becomes 0 or negative if the default initialization is used. I believe this is an error. To fix it I added a similar check on the lasagne.layers.base.Layer.init function. When running the tests I'm getting several failures because the Mock object is not iterable. |
Do we need both additions though? I guess one is for the parameter shapes, and one is for the layer input shapes, but maybe they both handle the same issues. One thing to consider is whether we want a layer to complain about its input shape like this - maybe the layer before it should instead be guaranteed to have a correct output shape. It's not entirely clear to me where we should put this responsibility. I guess ensuring correct input shapes is much easier than ensuring correct output shapes, because we can do it in the base class. Regarding the errors: mock objects are used in tests to replace 'real' objects and to be able to check how they are used by the code (which fields are accessed, which methods were called on them, etc.). Unfortunately they are not iterable, and your addition tries to iterate over If you don't think you can do this, I would suggest leaving the second error message out of this PR for now, we can always add that later. Alternatively someone could create a PR to your PR, but I don't know if anyone will be up for that right now. EDIT: also, while I'm in favour of defensive programming and good error messages, I'm a bit wary of sprinkling all these if statements around the code - there may be a point where it starts hampering code readability. We should take that into consideration as well. |
I'm also unsure if it needs to be put in both add_param and Layer.init. I was also unsure of the who's responsibility it was to raise the error. I think that it is necessary to have the error somewhere. Its very easy to create a convolutional network with too small of an input layer. That error should be caught when the layers are connected or created. The other option for where the error message could go is the output_shape property. It could check the output shape before it is returned. I don't think it should go in get_output_shape_for because that will be overridden and the error message should not have to be re-implemented. The problem with putting it in the output_shape property is that no checks will occur if get_output_shape_for is called. On the other hand, if the check is on Layer creation, then it is guaranteed to be called, and called once. However, I do agree that it should not be the a Layer's responsibility to check the integrity of its input. An alternative is that on Layer.init it checks its own output_shape property. This is slightly different than the current state of the commit because the Layer checks its own output, once, on creation. I think this is the correct solution. I think adding a param and creating a Layer are enough different that the error should exist in both places. However, I've only been programming with Lasagne for a few weeks, so I could be wrong here. Lastly, in terms of code readability, I'm all for keeping that as a primary consideration. I'm a buyer of the Tim Peters philosophy. However, without these messages, the error was only caught by a call to np.linalg.svd, and it was silent when Orthogonal initialization was not being used. Readability counts, but errors should never pass silently (or be caught by a cpu intensive singular value decomposition). |
I think it should be checked both in
That's not possible, unfortunately: When the base class constructor is called, the subclass usually has not finished (or even begun) initializing its attributes, so
One way would be replacing |
I was able to fix the failing tests. The coverage went down because there are currently no test cases specifically triggering the errors. |
Nice, thanks! It would be great to have those tests though, so we know they are triggered only in the right occasions and not otherwise :) EDIT: as an example, I just added a bunch of tests checking for exceptions for the convolution layers, maybe those are handy to use as inspiration: https://github.com/Lasagne/Lasagne/blob/master/lasagne/tests/layers/test_conv.py#L329 |
Wow, coveralls even marks this as a failure. I think I like that. It really urges us to include tests with all our PRs. Sorry if it makes contributions harder even for seemingly simple changes, but we've benefitted from our tests a couple times and you will learn to love them as well when you contribute more :) Don't hesitate to ask us if you need some more guidance! |
I added tests which brought the coverage back up. |
Looks good to me :) It's a bit unfortunate that we have to have Other than that it would be nice to squash the commits for this PR, there are quite a few corrections and merge commits. If you don't know how to do that I will defer to @f0k for an explanation, because I don't know off the top of my head either :p |
row=c01b[:, r, c, x], | ||
k=k, n=n, alpha=alpha, beta=beta) | ||
row=c01b[:, r, c, x], | ||
k=k, n=n, alpha=alpha, beta=beta) |
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.
Please don't do random code style changes as part of a PR. I know some editors are set to do that, but please don't commit such changes. The previous version was better anyway, because the extra indentation level makes clear it's not the next level of control.
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 changed this because I got a pep8 failure when running py.test
/home/joncrall/code/Lasagne/lasagne/tests/layers/test_normalization.py:53:25: E126 continuation line over-indented for hanging indent
row=c01b[:, r, c, x],
I'll try undoing that and committing. Maybe Travis CI doesn't have that check enabled.
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 have actually seen the same PEP8 error on some machines but not others. It doesn't occur on my laptop for example, where I do most of my development (nor on Travis). It might be related to what version of pep8 is installed.
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.
Ah, I remember, you had the same problem while you were here, right? Shall we add --ignore=E126
to our configuration so we can have hanging indents with 8 spaces, or shall we generally change all hanging indents to 4 spaces?
Sorry for blaming you, Jon, in the past we had various whitespace/linebreak changes in commits that were just a matter of taste rather than a matter of pep8 compliance. We should put up a general "commit etiquette" for Lasagne somewhere.
Thanks for the tests! So that "small change" required a lot more changes than we thought...
The |
Also added approprate tests.
I rebased and squashed all of the commits into a single commit (first time I've done this, but I think it went ok). The extra spacing is still in there. I don't have any particular opinion on hanging indentation. It might be easier to just add the pep8 ignore. Its odd that some machines fail on that and other's don't. These are the versions of the python linters on my machine: flake8 2.2.5 (pep8: 1.5.7, mccabe: 0.2.1, pyflakes: 0.8.1) CPython 2.7.6 on Linux |
Here are the version numbers on my laptop (no failure): and on the machine which does show the error: Looks like it might be related to which pep8 version is installed. 1.5.7 fails on those lines, 1.6.1 doesn't. |
Duh. I guess this means we need an extra |
Looks like this one is also ready for merging, sorry for the wait! |
This is a small change, I'm not sure if there are guidelines for contributions and how involved they should be. If small changes like this are ok, then I'll continue to make pull requests as I modify the library. If larger changes are preferred I'll hold off until I feel I've made a more substantial progress.
I added an error message to catch the scenario where the conv+max pooling layers reduce an image size to 0 for smaller images.
Previous error messages looked like this, and had a delay due to the SVD call during orthogonal initialization.
They the error messages are shorter and there is no delay.