Mercurial > pylearn
comparison nnet_ops.py @ 67:810a8e3c85e1
fixed horrible memory leak from crossentropy...
author | bergstra@is23.m |
---|---|
date | Fri, 18 Apr 2008 03:35:58 -0400 |
parents | 1b152f46ad0c |
children | 315eb36ff954 |
comparison
equal
deleted
inserted
replaced
35:2508c373cf29 | 67:810a8e3c85e1 |
---|---|
69 nll, sm = crossentropy_softmax_1hot(x, b, y_idx) | 69 nll, sm = crossentropy_softmax_1hot(x, b, y_idx) |
70 dx = CrossentropySoftmax1HotDx(g_nll, sm, y_idx).outputs[0] | 70 dx = CrossentropySoftmax1HotDx(g_nll, sm, y_idx).outputs[0] |
71 db = tensor.Sum(dx, axis = [0]).outputs[0] | 71 db = tensor.Sum(dx, axis = [0]).outputs[0] |
72 return dx, db, None | 72 return dx, db, None |
73 | 73 |
74 def c_validate_cleanup(self, (x, b, y_idx), (nll, sm), sub): | 74 def c_headers(self): return ['<iostream>'] |
75 """Not sure...""" | |
76 return "" | |
77 def c_support_code(self): | |
78 return """ | |
79 """ | |
80 def c_code(self, (x, b, y_idx), (nll, sm), sub): | 75 def c_code(self, (x, b, y_idx), (nll, sm), sub): |
81 # this implementation was lifted from | 76 # this implementation was lifted from |
82 # /u/bergstrj/cvs/bergstrj/src/feb07/nn.cxx | 77 # /u/bergstrj/cvs/bergstrj/src/feb07/nn.cxx |
83 | 78 |
84 #TODO: put this into a templated function, in the support code | 79 #TODO: put this into a templated function, in the support code |
87 #TODO: set error messages for failures in this code | 82 #TODO: set error messages for failures in this code |
88 | 83 |
89 return """ | 84 return """ |
90 npy_intp* Nx = %(x)s->dimensions; | 85 npy_intp* Nx = %(x)s->dimensions; |
91 | 86 |
92 if (%(x)s->nd != 2) { %(fail)s } | 87 if (%(x)s->nd != 2) |
93 if (%(b)s->nd != 1) { %(fail)s } | 88 { |
94 if (%(y_idx)s->nd != 1) { %(fail)s } | 89 PyErr_SetString(PyExc_ValueError, "a not 2d tensor"); |
95 if (%(x)s->descr->type_num != PyArray_DOUBLE) { %(fail)s} | 90 %(fail)s; |
96 if (%(b)s->descr->type_num != PyArray_DOUBLE) { %(fail)s} | 91 } |
97 if (%(y_idx)s->descr->type_num != PyArray_INT64) { %(fail)s} | 92 if (%(b)s->nd != 1) |
98 | 93 { |
99 %(nll)s = (PyArrayObject*)PyArray_SimpleNew(1, PyArray_DIMS(%(y_idx)s), type_num_%(x)s); | 94 PyErr_SetString(PyExc_ValueError, "b not 1d tensor"); |
100 if(!%(nll)s){%(fail)s} | 95 %(fail)s; |
101 | 96 } |
102 %(sm)s = (PyArrayObject*)PyArray_SimpleNew(2, PyArray_DIMS(%(x)s), type_num_%(x)s); | 97 if (%(y_idx)s->nd != 1) |
103 if(!%(sm)s) { | 98 { |
104 // The normal cleanup code will take care of %(nll)s | 99 PyErr_SetString(PyExc_ValueError, "y_idx not 1d tensor"); |
105 // Py_XDECREF(%(nll)s); %(nll)s=NULL; | 100 %(fail)s; |
106 %(fail)s | 101 } |
107 } | 102 if (%(x)s->descr->type_num != PyArray_DOUBLE) |
108 if (%(x)s->dimensions[1] != %(b)s->dimensions[0]) {%(fail)s} | 103 { |
109 if (%(sm)s->dimensions[0] != %(x)s->dimensions[0]) {%(fail)s} | 104 PyErr_SetString(PyExc_TypeError, "a not float64"); |
110 if (%(sm)s->dimensions[1] != %(x)s->dimensions[1]) {%(fail)s} | 105 %(fail)s; |
106 } | |
107 if (%(b)s->descr->type_num != PyArray_DOUBLE) | |
108 { | |
109 PyErr_SetString(PyExc_TypeError, "b not float64"); | |
110 %(fail)s; | |
111 } | |
112 if (%(y_idx)s->descr->type_num != PyArray_INT64) | |
113 { | |
114 PyErr_SetString(PyExc_TypeError, "y_idx not int64"); | |
115 %(fail)s; | |
116 } | |
117 if ((%(x)s->dimensions[1] != %(b)s->dimensions[0]) | |
118 || (%(x)s->dimensions[0] != %(y_idx)s->dimensions[0])) | |
119 { | |
120 PyErr_SetString(PyExc_ValueError, "dimension mismatch in arguments"); | |
121 %(fail)s; | |
122 } | |
123 | |
124 if ((NULL == %(nll)s) //initial condition | |
125 || (%(nll)s->dimensions[0] != %(y_idx)s->dimensions[0])) | |
126 { | |
127 if (NULL != %(nll)s) Py_XDECREF(%(nll)s); | |
128 %(nll)s = (PyArrayObject*)PyArray_SimpleNew(1, PyArray_DIMS(%(y_idx)s), type_num_%(x)s); | |
129 if(!%(nll)s) | |
130 { | |
131 PyErr_SetString(PyExc_MemoryError, "failed to alloc nll output"); | |
132 %(fail)s; | |
133 } | |
134 } | |
135 if ((NULL == %(sm)s) | |
136 || (%(sm)s->dimensions[0] != %(x)s->dimensions[0]) | |
137 || (%(sm)s->dimensions[1] != %(x)s->dimensions[1])) | |
138 { | |
139 if (NULL != %(sm)s) Py_XDECREF(%(sm)s); | |
140 %(sm)s = (PyArrayObject*)PyArray_SimpleNew(2, PyArray_DIMS(%(x)s), type_num_%(x)s); | |
141 if(!%(sm)s) { | |
142 // The normal cleanup code will take care of %(nll)s | |
143 // Py_XDECREF(%(nll)s); %(nll)s=NULL; | |
144 PyErr_SetString(PyExc_MemoryError, "failed to alloc sm output"); | |
145 %(fail)s | |
146 } | |
147 } | |
111 | 148 |
112 for (size_t i = 0; i < Nx[0]; ++i) | 149 for (size_t i = 0; i < Nx[0]; ++i) |
113 { | 150 { |
114 size_t j; | 151 size_t j; |
115 double sum = 0.0; | 152 double sum = 0.0; |
202 dx[i] = dy[i] * sm[i] #vector scale | 239 dx[i] = dy[i] * sm[i] #vector scale |
203 dx[i, y_idx[i]] -= dy[i] #scalar decrement | 240 dx[i, y_idx[i]] -= dy[i] #scalar decrement |
204 self.outputs[0].data = dx | 241 self.outputs[0].data = dx |
205 def grad(self, *args): | 242 def grad(self, *args): |
206 raise NotImplementedError() | 243 raise NotImplementedError() |
207 def c_validate_update(self, (dnll, sm, y_idx), (dx,), sub): | |
208 """Allocate output storage""" | |
209 return """ | |
210 if (%(dnll)s->nd != 1) { %(fail)s } | |
211 if (%(sm)s->nd != 2) { %(fail)s } | |
212 if (%(y_idx)s->nd != 1) { %(fail)s } | |
213 if (%(dnll)s->descr->type_num != PyArray_DOUBLE) { %(fail)s} | |
214 if (%(sm)s->descr->type_num != PyArray_DOUBLE) { %(fail)s} | |
215 if (%(y_idx)s->descr->type_num != PyArray_INT64) { %(fail)s} | |
216 | |
217 %(dx)s = (PyArrayObject*)PyArray_SimpleNew(2, PyArray_DIMS(%(sm)s), type_num_%(sm)s); | |
218 if(!%(dx)s){%(fail)s} | |
219 | |
220 """ % dict(locals(), **sub) | |
221 def c_validate_cleanup(self, inputs, outputs, sub): | |
222 """Not sure...""" | |
223 return "" | |
224 def c_support_code(self): | |
225 return """ | |
226 """ | |
227 def c_code(self, (dnll, sm, y_idx), (dx,), sub): | 244 def c_code(self, (dnll, sm, y_idx), (dx,), sub): |
228 return """ | 245 return """ |
229 npy_intp* shape = %(dx)s->dimensions; | 246 |
230 if (%(dnll)s->dimensions[0] != %(sm)s->dimensions[0]) {%(fail)s} | 247 if ((%(dnll)s->descr->type_num != PyArray_DOUBLE) |
231 if (%(dnll)s->dimensions[0] != %(y_idx)s->dimensions[0]) {%(fail)s} | 248 || (%(sm)s->descr->type_num != PyArray_DOUBLE) |
232 if (%(dnll)s->dimensions[0] != %(dx)s->dimensions[0]) {%(fail)s} | 249 || (%(y_idx)s->descr->type_num != PyArray_INT64)) |
233 | 250 { |
234 if (%(sm)s->dimensions[1] != %(dx)s->dimensions[1]) {%(fail)s} | 251 PyErr_SetString(PyExc_TypeError, "types should be float64, float64, int64"); |
235 | 252 %(fail)s; |
236 for (size_t i = 0; i < shape[0]; ++i) | 253 } |
254 if ((%(dnll)s->nd != 1) | |
255 || (%(sm)s->nd != 2) | |
256 || (%(y_idx)s->nd != 1)) | |
257 { | |
258 PyErr_SetString(PyExc_ValueError, "rank error"); | |
259 %(fail)s; | |
260 } | |
261 if ((%(dnll)s->dimensions[0] != %(sm)s->dimensions[0]) | |
262 || (%(dnll)s->dimensions[0] != %(y_idx)s->dimensions[0]) | |
263 || (%(dnll)s->dimensions[0] != %(dx)s->dimensions[0])) | |
264 { | |
265 PyErr_SetString(PyExc_ValueError, "dimension mismatch"); | |
266 %(fail)s; | |
267 } | |
268 if ((NULL == %(dx)s) | |
269 || (%(dx)s->dimensions[0] != %(sm)s->dimensions[0]) | |
270 || (%(dx)s->dimensions[1] != %(sm)s->dimensions[1])) | |
271 { | |
272 if (NULL != %(dx)s) Py_XDECREF(%(dx)s); | |
273 %(dx)s = (PyArrayObject*)PyArray_SimpleNew(2, PyArray_DIMS(%(x)s), type_num_%(x)s); | |
274 if(!%(dx)s) { | |
275 // The normal cleanup code will take care of %(nll)s | |
276 // Py_XDECREF(%(nll)s); %(nll)s=NULL; | |
277 PyErr_SetString(PyExc_MemoryError, "failed to alloc dx output"); | |
278 %(fail)s | |
279 } | |
280 } | |
281 | |
282 for (size_t i = 0; i < %(dx)s->dimensions[0]; ++i) | |
237 { | 283 { |
238 const double dnll_i = ((double*)(%(dnll)s->data + %(dnll)s->strides[0] * i))[0]; | 284 const double dnll_i = ((double*)(%(dnll)s->data + %(dnll)s->strides[0] * i))[0]; |
239 | 285 |
240 const long int y_i = ((long int*)(%(y_idx)s->data + %(y_idx)s->strides[0] * i))[0]; | 286 const long int y_i = ((long int*)(%(y_idx)s->data + %(y_idx)s->strides[0] * i))[0]; |
241 | 287 |
243 npy_intp Ssm = %(sm)s->strides[1]/sizeof(double); | 289 npy_intp Ssm = %(sm)s->strides[1]/sizeof(double); |
244 | 290 |
245 double* __restrict__ dx_i = (double*)(%(dx)s->data + %(dx)s->strides[0] * i); | 291 double* __restrict__ dx_i = (double*)(%(dx)s->data + %(dx)s->strides[0] * i); |
246 npy_intp Sdx = %(dx)s->strides[1]/sizeof(double); | 292 npy_intp Sdx = %(dx)s->strides[1]/sizeof(double); |
247 | 293 |
248 for (size_t j = 0; j < shape[1]; ++j) | 294 for (size_t j = 0; j < %(dx)s->dimensions[1]; ++j) |
249 { | 295 { |
250 dx_i[j * Sdx] = dnll_i * sm_i[j * Ssm]; | 296 dx_i[j * Sdx] = dnll_i * sm_i[j * Ssm]; |
251 } | 297 } |
252 if (y_i >= shape[1]) | 298 if (y_i >= %(dx)s->dimensions[1]) |
253 { | 299 { |
254 %(fail)s; | 300 %(fail)s; |
255 } | 301 } |
256 dx_i[y_i * Sdx] -= dnll_i; | 302 dx_i[y_i * Sdx] -= dnll_i; |
257 } | 303 } |