提交 fc39f6ba authored 作者: abergeron's avatar abergeron

Merge pull request #4472 from nouiz/ifelse_grad

[CRASH, ENH] Ifelse grad and speed up perform
......@@ -213,17 +213,24 @@ class IfElse(PureOp):
gpu=self.gpu,
name=nw_name_f)
if_true = ([ins[0]] + grads + [theano.tensor.zeros_like(t)
for t in ts])
if_false = ([ins[0]] + [theano.tensor.zeros_like(f)
for f in fs] + grads)
# The grads can have a different dtype then the inputs.
# As inputs true/false pair must have the same dtype,
# we must cast the zeros to the corresponding grad dtype
# and not the input dtype.
if_true = ([ins[0]] +
grads +
[theano.tensor.zeros_like(t, dtype=grads[i].dtype)
for i, t in enumerate(ts)])
if_false = ([ins[0]] +
[theano.tensor.zeros_like(f, dtype=grads[i].dtype)
for i, f in enumerate(fs)] +
grads)
condition = ins[0]
# condition does affect the elements of the output so it is connected.
# For the sake of making the gradient convenient we assume that
# condition + epsilon always triggers the same branch as condition
condition_grad = condition.zeros_like().astype(theano.config.floatX)
return ([condition_grad] +
if_true_op(*if_true, **dict(return_list=True)) +
if_false_op(*if_false, **dict(return_list=True)))
......
......@@ -172,28 +172,43 @@ class MultinomialFromUniform(Op):
unis.shape[0], pvals.shape[0], n_samples)
if z[0] is None or z[0].shape != pvals.shape:
z[0] = numpy.zeros(pvals.shape, dtype=node.outputs[0].dtype)
else:
z[0].fill(0)
nb_multi = pvals.shape[0]
nb_outcomes = pvals.shape[1]
# Original version that is not vectorized. I keep it here as
# it is more readable.
# For each multinomial, loop over each possible outcome
# nb_outcomes = pvals.shape[1]
# for c in range(n_samples):
# for n in range(nb_multi):
# waiting = True
# cummul = 0
# unis_n = unis[c * nb_multi + n]
# for m in range(nb_outcomes):
# cummul += pvals[n, m]
# if c == 0:
# if (waiting and (cummul > unis_n)):
# z[0][n, m] = 1
# waiting = False
# else:
# # Only needed if we don't init the output to 0
# z[0][n, m] = 0
# else:
# if (cummul > unis_n):
# z[0][n, m] += 1
# break
# Vectorized version that is much faster as all the looping is
# done in C even if this make extra work.
for c in range(n_samples):
for n in range(nb_multi):
waiting = True
cummul = 0
unis_n = unis[c * nb_multi + n]
for m in range(nb_outcomes):
cummul += pvals[n, m]
if c == 0:
if (waiting and (cummul > unis_n)):
z[0][n, m] = 1
waiting = False
else:
z[0][n, m] = 0
else:
if (cummul > unis_n):
z[0][n, m] += 1
break
# The dtype='float64' is important. Otherwise we don't
# have the same answer as the c code as in the c code
# the cumul is in double precission.
cumsum = pvals[n].cumsum(dtype='float64')
z[0][n, numpy.searchsorted(cumsum, unis_n)] += 1
class MultinomialWOReplacementFromUniform(MultinomialFromUniform):
......
......@@ -482,6 +482,21 @@ class test_ifelse(unittest.TestCase, utt.TestOptimizationMixin):
finally:
theano.config.compute_test_value = backup
def test_grad_int_value(self):
w = theano.shared(numpy.random.rand(10))
b = theano.shared(numpy.random.rand())
params = [w, b]
x = tensor.vector()
y = tensor.scalar()
score = w.dot(x) + b
correct = (score * y > 0)
loss = ifelse(correct, 0, 1)
[(param, param - 0.5 * tensor.grad(cost=loss, wrt=param))
for param in params]
if __name__ == '__main__':
print(' Use nosetests to run these tests ')
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论