{"action":"created","comment":{"url":"https://api.github.com/repos/Theano/Theano/pulls/comments/39417009","id":39417009,"diff_hunk":"@@ -0,0 +1,357 @@\n+// This uses a lot of code from Caffe (http://caffe.berkeleyvision.org/);\n+// sources are clearly marked. Below we reproduce the original license of\n+// the Caffe software.\n+/*\n+Copyright (c) 2014, The Regents of the University of California (Regents)\n+All rights reserved.\n+\n+Redistribution and use in source and binary forms, with or without\n+modification, are permitted provided that the following conditions are met: \n+\n+1. Redistributions of source code must retain the above copyright notice, this\n+   list of conditions and the following disclaimer. \n+2. Redistributions in binary form must reproduce the above copyright notice,\n+   this list of conditions and the following disclaimer in the documentation\n+   and/or other materials provided with the distribution. \n+\n+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\n+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+*/\n+\n+\n+// (borrowed from Caffe: https://github.com/BVLC/caffe/blob/master/src/caffe/util/im2col.cpp)\n+// Loops for fast unfold + copy\n+void im2col(const %(float_type)s* data_im, const int channels,\n+    const int height, const int width, const int kernel_h, const int kernel_w,\n+    const int pad_h, const int pad_w,\n+    const int stride_h, const int stride_w,\n+    %(float_type)s* data_col) {\n+  int height_col = (height + 2 * pad_h - kernel_h) / stride_h + 1;\n+  int width_col = (width + 2 * pad_w - kernel_w) / stride_w + 1;\n+  int channels_col = channels * kernel_h * kernel_w;\n+  for (int c = 0; c < channels_col; ++c) {\n+    int w_offset = c %% kernel_w;\n+    int h_offset = (c / kernel_w) %% kernel_h;\n+    int c_im = c / kernel_h / kernel_w;\n+    for (int h = 0; h < height_col; ++h) {\n+      for (int w = 0; w < width_col; ++w) {\n+        int h_pad = h * stride_h - pad_h + h_offset;\n+        int w_pad = w * stride_w - pad_w + w_offset;\n+        if (h_pad >= 0 && h_pad < height && w_pad >= 0 && w_pad < width)\n+          data_col[(c * height_col + h) * width_col + w] =\n+            data_im[(c_im * height + h_pad) * width + w_pad];\n+        else\n+          data_col[(c * height_col + h) * width_col + w] = 0.;\n+      }\n+    }\n+  }\n+}\n+\n+void col2im(const %(float_type)s* data_col, const int channels,\n+    const int height, const int width, const int patch_h, const int patch_w,\n+    const int pad_h, const int pad_w, const int stride_h,\n+    const int stride_w, %(float_type)s* data_im) {\n+  int height_col = (height + 2 * pad_h - patch_h) / stride_h + 1;\n+  int width_col = (width + 2 * pad_w - patch_w) / stride_w + 1;\n+  int num_kernels = channels * height * width;\n+  int channels_col = channels * patch_h * patch_w;\n+  for (int c = 0; c < channels_col; ++c) {\n+    int w_offset = c %% patch_w;\n+    int h_offset = (c / patch_w) %% patch_h;\n+    int c_im = c / patch_h / patch_w;\n+    for (int h = 0; h < height_col; ++h) {\n+      for (int w = 0; w < width_col; ++w) {\n+        int h_pad = h * stride_h - pad_h + h_offset;\n+        int w_pad = w * stride_w - pad_w + w_offset;\n+        if (h_pad >= 0 && h_pad < height && w_pad >= 0 && w_pad < width)\n+          data_im[(c_im * height + h_pad) * width + w_pad] +=\n+            data_col[(c * height_col + h) * width_col + w];\n+          // data_im[(c_im * height + h_pad) * width + w_pad] = 0.;\n+\n+      }\n+    }\n+  }\n+}\n+\n+\n+// Theano op code\n+// GPU version authors: Arjun Jain, Frederic Bastien, Jan Schlueter\n+// Reference code: https://github.com/BVLC/caffe/blob/master/src/caffe/layers/conv_layer.cu\n+//   and https://github.com/torch/cunn/blob/master/SpatialConvolutionMM.cu\n+// CPU version author: Jesse Livezey\n+// CPU version adapted from GPU version\n+PyArrayObject* corrMM(PyArrayObject* bottom,\n+                           PyArrayObject* weight,\n+                           PyArrayObject* top,\n+                           const int direction,\n+                           const int dH = 1,\n+                           const int dW = 1,\n+                           const int padH = 0,\n+                           const int padW = 0)\n+{\n+    if (PyArray_NDIM(bottom) != 4)\n+    {\n+        PyErr_SetString(PyExc_ValueError, \"CorrMM requires bottom of 4D\");\n+        return NULL;\n+    }\n+    if (PyArray_TYPE(bottom) != %(float_typenum)s)\n+    {\n+        PyErr_SetString(PyExc_ValueError, \"CorrMM received bottom with wrong type.\");\n+        return NULL;\n+    }\n+    \n+    if (PyArray_NDIM(weight) != 4)\n+    {\n+        PyErr_SetString(PyExc_ValueError, \"CorrMM requires weight of 4D\");\n+        return NULL;\n+    }\n+    if (PyArray_TYPE(weight) != %(float_typenum)s)\n+    {\n+        PyErr_SetString(PyExc_ValueError, \"CorrMM received weight with wrong type.\");\n+        return NULL;\n+    }\n+\n+    if (PyArray_NDIM(top) != 4)\n+    {\n+        PyErr_SetString(PyExc_ValueError, \"CorrMM requires top of 4D\");\n+        return NULL;\n+    }\n+    if (PyArray_TYPE(top) != %(float_typenum)s)\n+    {\n+        PyErr_SetString(PyExc_ValueError, \"CorrMM received top with wrong type.\");\n+        return NULL;\n+    }\n+    // Ensure data is contiguous\n+    bottom = PyArray_GETCONTIGUOUS(bottom);\n+    weight = PyArray_GETCONTIGUOUS(weight);\n+    top = PyArray_GETCONTIGUOUS(top);\n+\n+    // Extract some shape information for later and check shape consistency\n+    // bottom: (batchSize, nChannels, bottomHeight, bottomWidth)\n+    const int batchSize = PyArray_DIMS(bottom)[0];\n+    const int nChannels = PyArray_DIMS(bottom)[1];\n+    const int bottomHeight = PyArray_DIMS(bottom)[2];\n+    const int bottomWidth = PyArray_DIMS(bottom)[3];\n+    // weights: (nFilters, nChannels, rows, columns)\n+    const int nFilters = PyArray_DIMS(weight)[0];\n+    const int kH = PyArray_DIMS(weight)[2];\n+    const int kW = PyArray_DIMS(weight)[3];\n+    if (nChannels != PyArray_DIMS(weight)[1]) {\n+        PyErr_SetString(PyExc_ValueError,\n+                \"CorrMM images and kernel must have the same stack size\\n\");\n+        return NULL;\n+    }\n+    // top: (batchSize, nFilters, topHeight, topWidth)\n+    const int topHeight = (bottomHeight + 2*padH - kH) / dH + 1;\n+    const int topWidth  = (bottomWidth + 2*padW - kW) / dW + 1;\n+    if (batchSize != PyArray_DIMS(top)[0] ||\n+            nFilters != PyArray_DIMS(top)[1] ||\n+            topHeight != PyArray_DIMS(top)[2] ||\n+            topWidth != PyArray_DIMS(top)[3]) {\n+        PyErr_Format(PyExc_ValueError,\n+                \"CorrMM shape inconsistency:\\n\"\n+                \"  bottom shape: %%d %%d %%d %%d\\n\"\n+                \"  weight shape: %%d %%d %%d %%d\\n\"\n+                \"  top shape: %%d %%d %%d %%d (expected %%d %%d %%d %%d)\\n\",\n+                batchSize, nChannels, bottomHeight, bottomWidth,\n+                nFilters, nChannels, kH, kW,\n+                PyArray_DIMS(top)[0], PyArray_DIMS(top)[1],\n+                PyArray_DIMS(top)[2], PyArray_DIMS(top)[3],\n+                batchSize, nFilters, topHeight, topWidth);\n+        return NULL;\n+    }\n+\n+    // Create temporary columns\n+    npy_intp col_dim[2];\n+    col_dim[0] = (npy_intp)(nChannels * kW * kH);\n+    col_dim[1] = (npy_intp)(topHeight * topWidth);\n+    PyArrayObject* col = (PyArrayObject*)PyArray_EMPTY(2,\n+\t\t                           col_dim,\n+                                           PyArray_TYPE(top),\n+\t\t\t\t\t   0);\n+    if (NULL == col)\n+    {\n+        PyErr_Format(PyExc_RuntimeError,\n+                \"CorrMM failed to allocate working memory of %%d x %%d\\n\",\n+                col_dim[0], col_dim[1]);\n+        return NULL;\n+    }\n+\n+    // Define some useful variables\n+    const int bottom_stride = PyArray_STRIDES(bottom)[0]/%(n_bytes)f;\n+    const int top_stride = PyArray_STRIDES(top)[0]/%(n_bytes)f;\n+    const int K_ = col_dim[0];\n+    const int N_ = col_dim[1];\n+    const int M_ = nFilters;\n+    const %(c_float_type)s one = 1.0;\n+    const %(c_float_type)s zero = 0.0;\n+    char NTrans = 'N';\n+    char Trans = 'T';\n+\n+    PyArrayObject *output;\n+    if (direction == 0) {  // forward pass\n+        output = top;\n+        // valid correlation: im2col, then gemm\n+        // Iterate over batch\n+        for (int n = 0; n < batchSize; n++) {\n+            // First, im2col\n+            im2col((%(float_type)s*)PyArray_DATA(bottom) + n * bottom_stride, nChannels, bottomHeight,\n+                    bottomWidth, kH, kW, padH, padW, dH, dW, (%(float_type)s*)PyArray_DATA(col));\n+            // Second, gemm\n+            %(gemm)s(&NTrans, &NTrans,\n+                   &N_, &M_, &K_,\n+                   &one,\n+                   (%(float_type)s*)PyArray_DATA(col), &N_,\n+                   (%(float_type)s*)PyArray_DATA(weight), &K_,\n+                   &zero,\n+                   (%(float_type)s*)PyArray_DATA(top) + n * top_stride, &N_);\n+        }\n+        /*\n+        // Original caffe code for comparison\n+        // Note that this code was translated from the Theano GPU code,\n+        // not the Caffe CPU code.\n+        // https://github.com/BVLC/caffe/blob/master/src/caffe/layers/conv_layer.cu\n+        // Note that this is for grouped convolution; we can ignore groups here,\n+        // but the group-related offsets help explain what M_, N_ and K_ are\n+        int weight_offset = M_ * K_;\n+        int col_offset = K_ * N_;\n+        int top_offset = M_ * N_;\n+        for (int n = 0; n < num_; ++n) {\n+          // First, im2col\n+          im2col_gpu(bottom_data + bottom[i]->offset(n), channels_, height_,\n+              width_, kernel_h_, kernel_w_, pad_h_, pad_w_, stride_h_, stride_w_,\n+              col_data);\n+          // Second, innerproduct with groups\n+          for (int g = 0; g < group_; ++g) {\n+            caffe_gpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, M_, N_, K_,\n+              (Dtype)1., weight + weight_offset * g, col_data + col_offset * g,\n+              (Dtype)0., top_data + (*top)[i]->offset(n) + top_offset * g);\n+            == (see https://github.com/BVLC/caffe/blob/master/src/caffe/util/math_functions.cu#L16)\n+            cublasSgemm(CUBLAS_OP_N, CUBLAS_OP_N,\n+              N_, M_, K_,\n+              1.,\n+              col_data + col_offset * g, N_,\n+              weight + weight_offset * g, K_,\n+              0.,\n+              top_data + (*top)[i]->offset(n) + top_offset * g, N_);\n+          }\n+        }\n+        */\n+    }\n+    else if (direction == 1) {  // backprop wrt. weights\n+        output = weight;\n+        // valid convolution: im2col, then gemm\n+        // Iterate over batch\n+        for (int n = 0; n < batchSize; n++) {\n+            // First, im2col\n+            im2col((%(float_type)s*)PyArray_DATA(bottom) + n * bottom_stride, nChannels, bottomHeight,\n+                    bottomWidth, kH, kW, padH, padW, dH, dW, (%(float_type)s*)PyArray_DATA(col));\n+            // Second, gemm\n+            // Note that we accumulate into weight. We do so by setting beta = 0\n+            // for the first iteration and beta = 1 for subsequent ones. (This\n+            // is faster than setting weight to all zeros before the loop.)\n+            %(gemm)s(&Trans, &NTrans,\n+                   &K_, &M_, &N_,\n+                   &one,\n+                   (%(float_type)s*)PyArray_DATA(col), &N_,\n+                   (%(float_type)s*)PyArray_DATA(top) + n * top_stride, &N_,\n+                   (n == 0) ? &zero : &one,\n+                   (%(float_type)s*)PyArray_DATA(weight), &K_);\n+        }\n+        /*\n+        // Original caffe code for comparison\n+        // Note that this code was translated from the Theano GPU code,\n+        // not the Caffe CPU code.\n+        // https://github.com/BVLC/caffe/blob/master/src/caffe/layers/conv_layer.cu\n+        // Note that this is for grouped convolution; we can ignore groups\n+        for (int n = 0; n < num_; ++n) {\n+          // Since we saved memory in the forward pass by not storing all col\n+          // data, we will need to recompute them.\n+          im2col_gpu(bottom_data + (*bottom)[i]->offset(n), channels_, height_,\n+                     width_, kernel_h_, kernel_w_, pad_h_, pad_w_,\n+                     stride_h_, stride_w_, col_data);\n+          // gradient w.r.t. weight. Note that we will accumulate diffs.\n+          for (int g = 0; g < group_; ++g) {\n+            caffe_gpu_gemm<Dtype>(CblasNoTrans, CblasTrans, M_, K_, N_,\n+                (Dtype)1., top_diff + top[i]->offset(n) + top_offset * g,\n+                col_data + col_offset * g, (Dtype)1.,\n+                weight_diff + weight_offset * g);\n+            == (see https://github.com/BVLC/caffe/blob/master/src/caffe/util/math_functions.cu#L16)\n+            cublasSgemm(CUBLAS_OP_T, CUBLAS_OP_N, K_, M_, N_,\n+                1.0,\n+                col_data + col_offset * g, N_,\n+                top_diff + top[i]->offset(n) + top_offset * g, N_,\n+                1.0,\n+                weight_diff + weight_offset * g, K_);\n+          }\n+        }\n+        */\n+    }\n+    else if (direction == 2) {  // backprop wrt. inputs\n+        output = bottom;\n+        PyArray_FILLWBYTE(bottom, 0);","path":"theano/tensor/nnet/corr_gemm.c","position":300,"original_position":300,"commit_id":"3912661a31350251effb6e313c43cc7df0a06600","original_commit_id":"3912661a31350251effb6e313c43cc7df0a06600","user":{"login":"JesseLivezey","id":2081702,"avatar_url":"https://avatars.githubusercontent.com/u/2081702?v=3","gravatar_id":"","url":"https://api.github.com/users/JesseLivezey","html_url":"https://github.com/JesseLivezey","followers_url":"https://api.github.com/users/JesseLivezey/followers","following_url":"https://api.github.com/users/JesseLivezey/following{/other_user}","gists_url":"https://api.github.com/users/JesseLivezey/gists{/gist_id}","starred_url":"https://api.github.com/users/JesseLivezey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JesseLivezey/subscriptions","organizations_url":"https://api.github.com/users/JesseLivezey/orgs","repos_url":"https://api.github.com/users/JesseLivezey/repos","events_url":"https://api.github.com/users/JesseLivezey/events{/privacy}","received_events_url":"https://api.github.com/users/JesseLivezey/received_events","type":"User","site_admin":false},"body":"It's mostly just a result of the caffe col2im and the available calls in the numpy C-API.\r\n\r\nThe ```col2im_cpu``` function that caffe uses calls ```caffe_set``` on one slice of the output array:\r\nhttps://github.com/BVLC/caffe/blob/4f8775c1e88604879edef0698acab7b0d8a2ab43/src/caffe/util/im2col.cpp#L53\r\nI looked through the numpy C-API and there didn't seem to be an equivalent call.\r\n\r\nAnd in the GPU version you worked on, the result at each output location is accumulated in each thread (```val```) and then the value in the output array is overwritten. To do this on CPU would require allocating an extra array and accumulating into it, which seems more complicated.\r\n\r\nSince col2im won't be used outside of this file, setting the array to zero outside of col2im seemed reasonable. I'll add a comment though so it's clear why that is happening.","created_at":"2015-09-14T16:49:02Z","updated_at":"2015-09-14T16:49:02Z","html_url":"https://github.com/Theano/Theano/pull/3285#discussion_r39417009","pull_request_url":"https://api.github.com/repos/Theano/Theano/pulls/3285","_links":{"self":{"href":"https://api.github.com/repos/Theano/Theano/pulls/comments/39417009"},"html":{"href":"https://github.com/Theano/Theano/pull/3285#discussion_r39417009"},"pull_request":{"href":"https://api.github.com/repos/Theano/Theano/pulls/3285"}}},"pull_request":{"url":"https://api.github.com/repos/Theano/Theano/pulls/3285","id":42512806,"html_url":"https://github.com/Theano/Theano/pull/3285","diff_url":"https://github.com/Theano/Theano/pull/3285.diff","patch_url":"https://github.com/Theano/Theano/pull/3285.patch","issue_url":"https://api.github.com/repos/Theano/Theano/issues/3285","number":3285,"state":"open","locked":false,"title":"[WIP] CpuCorrMM closes #3026 - redux","user":{"login":"JesseLivezey","id":2081702,"avatar_url":"https://avatars.githubusercontent.com/u/2081702?v=3","gravatar_id":"","url":"https://api.github.com/users/JesseLivezey","html_url":"https://github.com/JesseLivezey","followers_url":"https://api.github.com/users/JesseLivezey/followers","following_url":"https://api.github.com/users/JesseLivezey/following{/other_user}","gists_url":"https://api.github.com/users/JesseLivezey/gists{/gist_id}","starred_url":"https://api.github.com/users/JesseLivezey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JesseLivezey/subscriptions","organizations_url":"https://api.github.com/users/JesseLivezey/orgs","repos_url":"https://api.github.com/users/JesseLivezey/repos","events_url":"https://api.github.com/users/JesseLivezey/events{/privacy}","received_events_url":"https://api.github.com/users/JesseLivezey/received_events","type":"User","site_admin":false},"body":"First PR was in strange state. Local commit history was different than github history and I couldn't reconcile them. Trying again...\r\n\r\nCPU implementation of the CorrMM style convolutions for #3026.\r\n\r\nGeneral\r\n- [x] Write real tests, current 'tests' are just copied from tensor.nnet, not sure if they make any sense\r\n- [x] Get tests to pass\r\n- [x] Move code out of sandbox and into final location (tensor.nnet?)\r\n\r\nC code\r\n - [x] write im2col and col2im for cpu\r\n - [x] write cormm for cpu\r\n - [x] float 32 and 64 versions\r\n\r\nTheano\r\n- [x] write ops\r\n - [x] BaseCpuCorrMM\r\n - [x] CpuCorrMM\r\n - [x] CpuCorrMM_gradWeights\r\n - [x] CpuCorrMM_gradInputs\r\n\r\nLater PRs\r\n- Write optimization to swap conv ops (waiting on #2665)","created_at":"2015-08-15T03:21:12Z","updated_at":"2015-09-14T16:49:02Z","closed_at":null,"merged_at":null,"merge_commit_sha":"450c9133b8d68a1d769150626c73e62c7dc5b40b","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Theano/Theano/pulls/3285/commits","review_comments_url":"https://api.github.com/repos/Theano/Theano/pulls/3285/comments","review_comment_url":"https://api.github.com/repos/Theano/Theano/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Theano/Theano/issues/3285/comments","statuses_url":"https://api.github.com/repos/Theano/Theano/statuses/3912661a31350251effb6e313c43cc7df0a06600","head":{"label":"JesseLivezey:cpu_corr3","ref":"cpu_corr3","sha":"3912661a31350251effb6e313c43cc7df0a06600","user":{"login":"JesseLivezey","id":2081702,"avatar_url":"https://avatars.githubusercontent.com/u/2081702?v=3","gravatar_id":"","url":"https://api.github.com/users/JesseLivezey","html_url":"https://github.com/JesseLivezey","followers_url":"https://api.github.com/users/JesseLivezey/followers","following_url":"https://api.github.com/users/JesseLivezey/following{/other_user}","gists_url":"https://api.github.com/users/JesseLivezey/gists{/gist_id}","starred_url":"https://api.github.com/users/JesseLivezey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JesseLivezey/subscriptions","organizations_url":"https://api.github.com/users/JesseLivezey/orgs","repos_url":"https://api.github.com/users/JesseLivezey/repos","events_url":"https://api.github.com/users/JesseLivezey/events{/privacy}","received_events_url":"https://api.github.com/users/JesseLivezey/received_events","type":"User","site_admin":false},"repo":{"id":24728885,"name":"Theano","full_name":"JesseLivezey/Theano","owner":{"login":"JesseLivezey","id":2081702,"avatar_url":"https://avatars.githubusercontent.com/u/2081702?v=3","gravatar_id":"","url":"https://api.github.com/users/JesseLivezey","html_url":"https://github.com/JesseLivezey","followers_url":"https://api.github.com/users/JesseLivezey/followers","following_url":"https://api.github.com/users/JesseLivezey/following{/other_user}","gists_url":"https://api.github.com/users/JesseLivezey/gists{/gist_id}","starred_url":"https://api.github.com/users/JesseLivezey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JesseLivezey/subscriptions","organizations_url":"https://api.github.com/users/JesseLivezey/orgs","repos_url":"https://api.github.com/users/JesseLivezey/repos","events_url":"https://api.github.com/users/JesseLivezey/events{/privacy}","received_events_url":"https://api.github.com/users/JesseLivezey/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/JesseLivezey/Theano","description":"Optimizing GPU-meta-programming code generating array oriented optimizing math compiler in Python","fork":true,"url":"https://api.github.com/repos/JesseLivezey/Theano","forks_url":"https://api.github.com/repos/JesseLivezey/Theano/forks","keys_url":"https://api.github.com/repos/JesseLivezey/Theano/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JesseLivezey/Theano/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JesseLivezey/Theano/teams","hooks_url":"https://api.github.com/repos/JesseLivezey/Theano/hooks","issue_events_url":"https://api.github.com/repos/JesseLivezey/Theano/issues/events{/number}","events_url":"https://api.github.com/repos/JesseLivezey/Theano/events","assignees_url":"https://api.github.com/repos/JesseLivezey/Theano/assignees{/user}","branches_url":"https://api.github.com/repos/JesseLivezey/Theano/branches{/branch}","tags_url":"https://api.github.com/repos/JesseLivezey/Theano/tags","blobs_url":"https://api.github.com/repos/JesseLivezey/Theano/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JesseLivezey/Theano/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JesseLivezey/Theano/git/refs{/sha}","trees_url":"https://api.github.com/repos/JesseLivezey/Theano/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JesseLivezey/Theano/statuses/{sha}","languages_url":"https://api.github.com/repos/JesseLivezey/Theano/languages","stargazers_url":"https://api.github.com/repos/JesseLivezey/Theano/stargazers","contributors_url":"https://api.github.com/repos/JesseLivezey/Theano/contributors","subscribers_url":"https://api.github.com/repos/JesseLivezey/Theano/subscribers","subscription_url":"https://api.github.com/repos/JesseLivezey/Theano/subscription","commits_url":"https://api.github.com/repos/JesseLivezey/Theano/commits{/sha}","git_commits_url":"https://api.github.com/repos/JesseLivezey/Theano/git/commits{/sha}","comments_url":"https://api.github.com/repos/JesseLivezey/Theano/comments{/number}","issue_comment_url":"https://api.github.com/repos/JesseLivezey/Theano/issues/comments{/number}","contents_url":"https://api.github.com/repos/JesseLivezey/Theano/contents/{+path}","compare_url":"https://api.github.com/repos/JesseLivezey/Theano/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JesseLivezey/Theano/merges","archive_url":"https://api.github.com/repos/JesseLivezey/Theano/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JesseLivezey/Theano/downloads","issues_url":"https://api.github.com/repos/JesseLivezey/Theano/issues{/number}","pulls_url":"https://api.github.com/repos/JesseLivezey/Theano/pulls{/number}","milestones_url":"https://api.github.com/repos/JesseLivezey/Theano/milestones{/number}","notifications_url":"https://api.github.com/repos/JesseLivezey/Theano/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JesseLivezey/Theano/labels{/name}","releases_url":"https://api.github.com/repos/JesseLivezey/Theano/releases{/id}","created_at":"2014-10-02T17:26:27Z","updated_at":"2015-05-05T22:45:56Z","pushed_at":"2015-09-09T04:05:31Z","git_url":"git://github.com/JesseLivezey/Theano.git","ssh_url":"git@github.com:JesseLivezey/Theano.git","clone_url":"https://github.com/JesseLivezey/Theano.git","svn_url":"https://github.com/JesseLivezey/Theano","homepage":"http://www.deeplearning.net/software/theano","size":38980,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"Theano:master","ref":"master","sha":"c042a9c49ac6516b74668747d1e6e6bbe832efba","user":{"login":"Theano","id":970517,"avatar_url":"https://avatars.githubusercontent.com/u/970517?v=3","gravatar_id":"","url":"https://api.github.com/users/Theano","html_url":"https://github.com/Theano","followers_url":"https://api.github.com/users/Theano/followers","following_url":"https://api.github.com/users/Theano/following{/other_user}","gists_url":"https://api.github.com/users/Theano/gists{/gist_id}","starred_url":"https://api.github.com/users/Theano/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Theano/subscriptions","organizations_url":"https://api.github.com/users/Theano/orgs","repos_url":"https://api.github.com/users/Theano/repos","events_url":"https://api.github.com/users/Theano/events{/privacy}","received_events_url":"https://api.github.com/users/Theano/received_events","type":"Organization","site_admin":false},"repo":{"id":2183193,"name":"Theano","full_name":"Theano/Theano","owner":{"login":"Theano","id":970517,"avatar_url":"https://avatars.githubusercontent.com/u/970517?v=3","gravatar_id":"","url":"https://api.github.com/users/Theano","html_url":"https://github.com/Theano","followers_url":"https://api.github.com/users/Theano/followers","following_url":"https://api.github.com/users/Theano/following{/other_user}","gists_url":"https://api.github.com/users/Theano/gists{/gist_id}","starred_url":"https://api.github.com/users/Theano/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Theano/subscriptions","organizations_url":"https://api.github.com/users/Theano/orgs","repos_url":"https://api.github.com/users/Theano/repos","events_url":"https://api.github.com/users/Theano/events{/privacy}","received_events_url":"https://api.github.com/users/Theano/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Theano/Theano","description":"Theano is a Python library that allows you to define, optimize, and evaluate mathematical expressions involving multi-dimensional arrays efficiently. It can use GPUs and perform efficient symbolic differentiation.","fork":false,"url":"https://api.github.com/repos/Theano/Theano","forks_url":"https://api.github.com/repos/Theano/Theano/forks","keys_url":"https://api.github.com/repos/Theano/Theano/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Theano/Theano/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Theano/Theano/teams","hooks_url":"https://api.github.com/repos/Theano/Theano/hooks","issue_events_url":"https://api.github.com/repos/Theano/Theano/issues/events{/number}","events_url":"https://api.github.com/repos/Theano/Theano/events","assignees_url":"https://api.github.com/repos/Theano/Theano/assignees{/user}","branches_url":"https://api.github.com/repos/Theano/Theano/branches{/branch}","tags_url":"https://api.github.com/repos/Theano/Theano/tags","blobs_url":"https://api.github.com/repos/Theano/Theano/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Theano/Theano/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Theano/Theano/git/refs{/sha}","trees_url":"https://api.github.com/repos/Theano/Theano/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Theano/Theano/statuses/{sha}","languages_url":"https://api.github.com/repos/Theano/Theano/languages","stargazers_url":"https://api.github.com/repos/Theano/Theano/stargazers","contributors_url":"https://api.github.com/repos/Theano/Theano/contributors","subscribers_url":"https://api.github.com/repos/Theano/Theano/subscribers","subscription_url":"https://api.github.com/repos/Theano/Theano/subscription","commits_url":"https://api.github.com/repos/Theano/Theano/commits{/sha}","git_commits_url":"https://api.github.com/repos/Theano/Theano/git/commits{/sha}","comments_url":"https://api.github.com/repos/Theano/Theano/comments{/number}","issue_comment_url":"https://api.github.com/repos/Theano/Theano/issues/comments{/number}","contents_url":"https://api.github.com/repos/Theano/Theano/contents/{+path}","compare_url":"https://api.github.com/repos/Theano/Theano/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Theano/Theano/merges","archive_url":"https://api.github.com/repos/Theano/Theano/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Theano/Theano/downloads","issues_url":"https://api.github.com/repos/Theano/Theano/issues{/number}","pulls_url":"https://api.github.com/repos/Theano/Theano/pulls{/number}","milestones_url":"https://api.github.com/repos/Theano/Theano/milestones{/number}","notifications_url":"https://api.github.com/repos/Theano/Theano/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Theano/Theano/labels{/name}","releases_url":"https://api.github.com/repos/Theano/Theano/releases{/id}","created_at":"2011-08-10T03:48:06Z","updated_at":"2015-09-14T11:31:55Z","pushed_at":"2015-09-14T14:26:20Z","git_url":"git://github.com/Theano/Theano.git","ssh_url":"git@github.com:Theano/Theano.git","clone_url":"https://github.com/Theano/Theano.git","svn_url":"https://github.com/Theano/Theano","homepage":"http://www.deeplearning.net/software/theano","size":63100,"stargazers_count":2015,"watchers_count":2015,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":710,"mirror_url":null,"open_issues_count":475,"forks":710,"open_issues":475,"watchers":2015,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Theano/Theano/pulls/3285"},"html":{"href":"https://github.com/Theano/Theano/pull/3285"},"issue":{"href":"https://api.github.com/repos/Theano/Theano/issues/3285"},"comments":{"href":"https://api.github.com/repos/Theano/Theano/issues/3285/comments"},"review_comments":{"href":"https://api.github.com/repos/Theano/Theano/pulls/3285/comments"},"review_comment":{"href":"https://api.github.com/repos/Theano/Theano/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Theano/Theano/pulls/3285/commits"},"statuses":{"href":"https://api.github.com/repos/Theano/Theano/statuses/3912661a31350251effb6e313c43cc7df0a06600"}}}}