14
14
15
15
import sys
16
16
import theano .tensor as tt
17
+
17
18
# pylint: disable=unused-import
18
19
import theano
19
20
from theano .tensor import (
20
- constant , flatten , zeros_like , ones_like , stack , concatenate , sum , prod ,
21
- lt , gt , le , ge , eq , neq , switch , clip , where , and_ , or_ , abs_ , exp , log ,
22
- cos , sin , tan , cosh , sinh , tanh , sqr , sqrt , erf , erfc , erfinv , erfcinv , dot ,
23
- maximum , minimum , sgn , ceil , floor )
21
+ constant ,
22
+ flatten ,
23
+ zeros_like ,
24
+ ones_like ,
25
+ stack ,
26
+ concatenate ,
27
+ sum ,
28
+ prod ,
29
+ lt ,
30
+ gt ,
31
+ le ,
32
+ ge ,
33
+ eq ,
34
+ neq ,
35
+ switch ,
36
+ clip ,
37
+ where ,
38
+ and_ ,
39
+ or_ ,
40
+ abs_ ,
41
+ exp ,
42
+ log ,
43
+ cos ,
44
+ sin ,
45
+ tan ,
46
+ cosh ,
47
+ sinh ,
48
+ tanh ,
49
+ sqr ,
50
+ sqrt ,
51
+ erf ,
52
+ erfc ,
53
+ erfinv ,
54
+ erfcinv ,
55
+ dot ,
56
+ maximum ,
57
+ minimum ,
58
+ sgn ,
59
+ ceil ,
60
+ floor ,
61
+ )
24
62
from theano .tensor .nlinalg import det , matrix_inverse , extract_diag , matrix_dot , trace
25
63
import theano .tensor .slinalg
26
64
import theano .sparse
@@ -62,7 +100,7 @@ def cartesian(*arrays):
62
100
1D arrays where earlier arrays loop more slowly than later ones
63
101
"""
64
102
N = len (arrays )
65
- return np .stack (np .meshgrid (* arrays , indexing = 'ij' ), - 1 ).reshape (- 1 , N )
103
+ return np .stack (np .meshgrid (* arrays , indexing = "ij" ), - 1 ).reshape (- 1 , N )
66
104
67
105
68
106
def kron_matrix_op (krons , m , op ):
@@ -81,6 +119,7 @@ def kron_matrix_op(krons, m, op):
81
119
-------
82
120
numpy array
83
121
"""
122
+
84
123
def flat_matrix_op (flat_mat , mat ):
85
124
Nmat = mat .shape [1 ]
86
125
flat_shape = flat_mat .shape
@@ -93,7 +132,7 @@ def kron_vector_op(v):
93
132
if m .ndim == 1 :
94
133
m = m [:, None ] # Treat 1D array as Nx1 matrix
95
134
if m .ndim != 2 : # Has not been tested otherwise
96
- raise ValueError (' m must have ndim <= 2, not {}' .format (m .ndim ))
135
+ raise ValueError (" m must have ndim <= 2, not {}" .format (m .ndim ))
97
136
res = kron_vector_op (m )
98
137
res_shape = res .shape
99
138
return tt .reshape (res , (res_shape [1 ], res_shape [0 ])).T
@@ -104,6 +143,7 @@ def kron_vector_op(v):
104
143
kron_solve_lower = partial (kron_matrix_op , op = tt .slinalg .solve_lower_triangular )
105
144
kron_solve_upper = partial (kron_matrix_op , op = tt .slinalg .solve_upper_triangular )
106
145
146
+
107
147
def flat_outer (a , b ):
108
148
return tt .outer (a , b ).ravel ()
109
149
@@ -124,7 +164,7 @@ def tround(*args, **kwargs):
124
164
Temporary function to silence round warning in Theano. Please remove
125
165
when the warning disappears.
126
166
"""
127
- kwargs [' mode' ] = ' half_to_even'
167
+ kwargs [" mode" ] = " half_to_even"
128
168
return tt .round (* args , ** kwargs )
129
169
130
170
@@ -136,19 +176,28 @@ def logsumexp(x, axis=None):
136
176
137
177
def logaddexp (a , b ):
138
178
diff = b - a
139
- return tt .switch (diff > 0 ,
140
- b + tt .log1p (tt .exp (- diff )),
141
- a + tt .log1p (tt .exp (diff )))
179
+ return tt .switch (diff > 0 , b + tt .log1p (tt .exp (- diff )), a + tt .log1p (tt .exp (diff )))
142
180
143
181
144
182
def logdiffexp (a , b ):
145
183
"""log(exp(a) - exp(b))"""
146
184
return a + log1mexp (a - b )
147
185
148
186
187
+ def logdiffexp_numpy (a , b ):
188
+ """log(exp(a) - exp(b))"""
189
+ return a + log1mexp_numpy (a - b )
190
+
191
+
149
192
def invlogit (x , eps = sys .float_info .epsilon ):
150
193
"""The inverse of the logit function, 1 / (1 + exp(-x))."""
151
- return (1. - 2. * eps ) / (1. + tt .exp (- x )) + eps
194
+ return (1.0 - 2.0 * eps ) / (1.0 + tt .exp (- x )) + eps
195
+
196
+
197
+ def logbern (log_p ):
198
+ if np .isnan (log_p ):
199
+ raise FloatingPointError ("log_p can't be nan." )
200
+ return np .log (nr .uniform ()) < log_p
152
201
153
202
154
203
def logit (p ):
@@ -171,10 +220,16 @@ def log1mexp(x):
171
220
For details, see
172
221
https://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf
173
222
"""
174
- return tt .switch (
175
- tt .lt (x , 0.683 ),
176
- tt .log (- tt .expm1 (- x )),
177
- tt .log1p (- tt .exp (- x )))
223
+ return tt .switch (tt .lt (x , 0.683 ), tt .log (- tt .expm1 (- x )), tt .log1p (- tt .exp (- x )))
224
+
225
+
226
+ def log1mexp_numpy (x ):
227
+ """Return log(1 - exp(-x)).
228
+ This function is numerically more stable than the naive approach.
229
+ For details, see
230
+ https://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf
231
+ """
232
+ return np .where (x < 0.683 , np .log (- np .expm1 (- x )), np .log1p (- np .exp (- x )))
178
233
179
234
180
235
def flatten_list (tensors ):
@@ -191,6 +246,7 @@ class LogDet(Op):
191
246
Once PR #3959 (https://github.com/Theano/Theano/pull/3959/) by harpone is merged,
192
247
this must be removed.
193
248
"""
249
+
194
250
def make_node (self , x ):
195
251
x = theano .tensor .as_tensor_variable (x )
196
252
o = theano .tensor .scalar (dtype = x .dtype )
@@ -204,7 +260,7 @@ def perform(self, node, inputs, outputs, params=None):
204
260
log_det = np .sum (np .log (np .abs (s )))
205
261
z [0 ] = np .asarray (log_det , dtype = x .dtype )
206
262
except Exception :
207
- print (' Failed to compute logdet of {}.' .format (x ))
263
+ print (" Failed to compute logdet of {}." .format (x ))
208
264
raise
209
265
210
266
def grad (self , inputs , g_outputs ):
@@ -215,19 +271,20 @@ def grad(self, inputs, g_outputs):
215
271
def __str__ (self ):
216
272
return "LogDet"
217
273
274
+
218
275
logdet = LogDet ()
219
276
220
277
221
278
def probit (p ):
222
- return - sqrt (2. ) * erfcinv (2. * p )
279
+ return - sqrt (2.0 ) * erfcinv (2.0 * p )
223
280
224
281
225
282
def invprobit (x ):
226
- return .5 * erfc (- x / sqrt (2. ))
283
+ return 0 .5 * erfc (- x / sqrt (2.0 ))
227
284
228
285
229
286
def expand_packed_triangular (n , packed , lower = True , diagonal_only = False ):
230
- R """Convert a packed triangular matrix into a two dimensional array.
287
+ r """Convert a packed triangular matrix into a two dimensional array.
231
288
232
289
Triangular matrices can be stored with better space efficiancy by
233
290
storing the non-zero values in a one-dimensional array. We number
@@ -250,9 +307,9 @@ def expand_packed_triangular(n, packed, lower=True, diagonal_only=False):
250
307
If true, return only the diagonal of the matrix.
251
308
"""
252
309
if packed .ndim != 1 :
253
- raise ValueError (' Packed triagular is not one dimensional.' )
310
+ raise ValueError (" Packed triagular is not one dimensional." )
254
311
if not isinstance (n , int ):
255
- raise TypeError (' n must be an integer' )
312
+ raise TypeError (" n must be an integer" )
256
313
257
314
if diagonal_only and lower :
258
315
diag_idxs = np .arange (1 , n + 1 ).cumsum () - 1
@@ -274,12 +331,13 @@ class BatchedDiag(tt.Op):
274
331
"""
275
332
Fast BatchedDiag allocation
276
333
"""
334
+
277
335
__props__ = ()
278
336
279
337
def make_node (self , diag ):
280
338
diag = tt .as_tensor_variable (diag )
281
339
if diag .type .ndim != 2 :
282
- raise TypeError (' data argument must be a matrix' , diag .type )
340
+ raise TypeError (" data argument must be a matrix" , diag .type )
283
341
284
342
return tt .Apply (self , [diag ], [tt .tensor3 (dtype = diag .dtype )])
285
343
@@ -301,7 +359,7 @@ def grad(self, inputs, gout):
301
359
return [gz [..., idx , idx ]]
302
360
303
361
def infer_shape (self , nodes , shapes ):
304
- return [(shapes [0 ][0 ], ) + (shapes [0 ][1 ],) * 2 ]
362
+ return [(shapes [0 ][0 ],) + (shapes [0 ][1 ],) * 2 ]
305
363
306
364
307
365
def batched_diag (C ):
@@ -315,54 +373,60 @@ def batched_diag(C):
315
373
idx = tt .arange (dim )
316
374
return C [..., idx , idx ]
317
375
else :
318
- raise ValueError (' Input should be 2 or 3 dimensional' )
376
+ raise ValueError (" Input should be 2 or 3 dimensional" )
319
377
320
378
321
379
class BlockDiagonalMatrix (Op ):
322
- __props__ = (' sparse' , ' format' )
380
+ __props__ = (" sparse" , " format" )
323
381
324
- def __init__ (self , sparse = False , format = 'csr' ):
325
- if format not in ('csr' , 'csc' ):
326
- raise ValueError ("format must be one of: 'csr', 'csc', got {}" .format (format ))
382
+ def __init__ (self , sparse = False , format = "csr" ):
383
+ if format not in ("csr" , "csc" ):
384
+ raise ValueError (
385
+ "format must be one of: 'csr', 'csc', got {}" .format (format )
386
+ )
327
387
self .sparse = sparse
328
388
self .format = format
329
389
330
390
def make_node (self , * matrices ):
331
391
if not matrices :
332
- raise ValueError (' no matrices to allocate' )
392
+ raise ValueError (" no matrices to allocate" )
333
393
matrices = list (map (tt .as_tensor , matrices ))
334
394
if any (mat .type .ndim != 2 for mat in matrices ):
335
- raise TypeError (' all data arguments must be matrices' )
395
+ raise TypeError (" all data arguments must be matrices" )
336
396
if self .sparse :
337
- out_type = theano .sparse .matrix (self .format , dtype = largest_common_dtype (matrices ))
397
+ out_type = theano .sparse .matrix (
398
+ self .format , dtype = largest_common_dtype (matrices )
399
+ )
338
400
else :
339
401
out_type = theano .tensor .matrix (dtype = largest_common_dtype (matrices ))
340
402
return tt .Apply (self , matrices , [out_type ])
341
403
342
404
def perform (self , node , inputs , output_storage , params = None ):
343
405
dtype = largest_common_dtype (inputs )
344
406
if self .sparse :
345
- output_storage [0 ][0 ] = sp .sparse .block_diag (
346
- inputs , self .format , dtype
347
- )
407
+ output_storage [0 ][0 ] = sp .sparse .block_diag (inputs , self .format , dtype )
348
408
else :
349
409
output_storage [0 ][0 ] = scipy_block_diag (* inputs ).astype (dtype )
350
410
351
411
def grad (self , inputs , gout ):
352
412
shapes = tt .stack ([i .shape for i in inputs ])
353
413
index_end = shapes .cumsum (0 )
354
414
index_begin = index_end - shapes
355
- slices = [ix_ (tt .arange (index_begin [i , 0 ], index_end [i , 0 ]),
356
- tt .arange (index_begin [i , 1 ], index_end [i , 1 ])
357
- ) for i in range (len (inputs ))]
415
+ slices = [
416
+ ix_ (
417
+ tt .arange (index_begin [i , 0 ], index_end [i , 0 ]),
418
+ tt .arange (index_begin [i , 1 ], index_end [i , 1 ]),
419
+ )
420
+ for i in range (len (inputs ))
421
+ ]
358
422
return [gout [0 ][slc ] for slc in slices ]
359
423
360
424
def infer_shape (self , nodes , shapes ):
361
425
first , second = zip (* shapes )
362
426
return [(tt .add (* first ), tt .add (* second ))]
363
427
364
428
365
- def block_diagonal (matrices , sparse = False , format = ' csr' ):
429
+ def block_diagonal (matrices , sparse = False , format = " csr" ):
366
430
r"""See scipy.sparse.block_diag or
367
431
scipy.linalg.block_diag for reference
368
432
0 commit comments