{"action":"created","issue":{"url":"https://api.github.com/repos/lisa-lab/pylearn2/issues/1508","labels_url":"https://api.github.com/repos/lisa-lab/pylearn2/issues/1508/labels{/name}","comments_url":"https://api.github.com/repos/lisa-lab/pylearn2/issues/1508/comments","events_url":"https://api.github.com/repos/lisa-lab/pylearn2/issues/1508/events","html_url":"https://github.com/lisa-lab/pylearn2/issues/1508","id":72153336,"number":1508,"title":"Infinite loops in BatchGradientDescent with flat constraints","user":{"login":"AlexisMignon","id":10117348,"avatar_url":"https://avatars.githubusercontent.com/u/10117348?v=3","gravatar_id":"","url":"https://api.github.com/users/AlexisMignon","html_url":"https://github.com/AlexisMignon","followers_url":"https://api.github.com/users/AlexisMignon/followers","following_url":"https://api.github.com/users/AlexisMignon/following{/other_user}","gists_url":"https://api.github.com/users/AlexisMignon/gists{/gist_id}","starred_url":"https://api.github.com/users/AlexisMignon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AlexisMignon/subscriptions","organizations_url":"https://api.github.com/users/AlexisMignon/orgs","repos_url":"https://api.github.com/users/AlexisMignon/repos","events_url":"https://api.github.com/users/AlexisMignon/events{/privacy}","received_events_url":"https://api.github.com/users/AlexisMignon/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-04-30T13:11:35Z","updated_at":"2015-05-11T08:08:22Z","closed_at":null,"body":"Hello,\r\n\r\nI'm encountering an issue using `BatchGradientDescent` with `param_constrainers`.\r\n\r\nHere is an example of the issue:\r\n```python\r\nfrom pylearn2.optimization.batch_gradient_descent import BatchGradientDescent\r\nimport numpy as np\r\nimport theano\r\nimport theano.tensor as T\r\n\r\nx = theano.shared(np.float32(1.0)) # my config uses GPU with float32\r\ndef non_negative_x(updates):\r\n     x_update = updates[x]\r\n     updates[x] = T.maximum(0, x_update)\r\n\r\ncost = (x + 2) ** 2\r\n\r\nbg = BatchGradientDescent(cost, [x], param_constrainers=[non_negative_x], verbose=1)\r\nbg.minimize()\r\n```\r\nThis leads to an infinite loop. Examining the output obtained with 'verbose=1', shows that the step size becomes infinite.\r\n\r\nIn the file batch_gradient_descent.py, line 353, one reads:\r\n```python\r\n                    # Use <= rather than = so if there are ties\r\n                    # the bigger step size wins\r\n                    if obj <= best_obj:\r\n                        best_obj = obj\r\n                        best_alpha = alpha\r\n                        best_alpha_ind = ind\r\n```\r\nI guess the problems comes from the '<=' instead of '<'. The comment seems to claim it is better to take the greater step size when ties occur, but in this case all values for step sizes bigger than some value lead to ties.\r\n\r\nA simple correction would be to replace '<=' by '<', but since there is a special comment about this point, I am wondering if there is a strong reason not to do so.\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/lisa-lab/pylearn2/issues/comments/100807610","html_url":"https://github.com/lisa-lab/pylearn2/issues/1508#issuecomment-100807610","issue_url":"https://api.github.com/repos/lisa-lab/pylearn2/issues/1508","id":100807610,"user":{"login":"AlexisMignon","id":10117348,"avatar_url":"https://avatars.githubusercontent.com/u/10117348?v=3","gravatar_id":"","url":"https://api.github.com/users/AlexisMignon","html_url":"https://github.com/AlexisMignon","followers_url":"https://api.github.com/users/AlexisMignon/followers","following_url":"https://api.github.com/users/AlexisMignon/following{/other_user}","gists_url":"https://api.github.com/users/AlexisMignon/gists{/gist_id}","starred_url":"https://api.github.com/users/AlexisMignon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AlexisMignon/subscriptions","organizations_url":"https://api.github.com/users/AlexisMignon/orgs","repos_url":"https://api.github.com/users/AlexisMignon/repos","events_url":"https://api.github.com/users/AlexisMignon/events{/privacy}","received_events_url":"https://api.github.com/users/AlexisMignon/received_events","type":"User","site_admin":false},"created_at":"2015-05-11T08:08:22Z","updated_at":"2015-05-11T08:08:22Z","body":"The problem comes from a side effect of the condition in [line 347](https://github.com/lisa-lab/pylearn2/blob/master/pylearn2/optimization/batch_gradient_descent.py#L347):\r\n\r\n```python\r\n                for ind, alpha in enumerate(alpha_list):\r\n                    self._goto_alpha(alpha)\r\n                    obj = self.obj(*inputs)\r\n                    if self.verbose:\r\n                        logger.info('\\t{0} {1}'.format(alpha, obj))\r\n\r\n                    # Use <= rather than = so if there are ties\r\n                    # the bigger step size wins\r\n                    if obj <= best_obj:\r\n                        best_obj = obj\r\n                        best_alpha = alpha\r\n                        best_alpha_ind = ind\r\n```\r\nwhich allows to keep growing the step size even though there is no improvement, and the condition in [line 377](https://github.com/lisa-lab/pylearn2/blob/master/pylearn2/optimization/batch_gradient_descent.py#L377):\r\n```python\r\n                elif best_alpha_ind > len(alpha_list) - 2:\r\n                    alpha_list = [alpha * 2. for alpha in alpha_list]\r\n                    if self.verbose:\r\n                        logger.info('growing the step size')\r\n```\r\n which says that is the last step size of the list was used then all step sizes in the list should be multiplied by two.\r\n\r\nIn the case of a flat function there is no way to make the algorithm stop. I see at least two solutions:\r\n\r\n1.  Go back to the strict comparison\r\n2. Specifically check that the function did not improve over the last few iterations\r\n\r\n\r\n"}}