def local_inv_1_plus_exp(node): """ 1/(1+exp(x)) -> sigm(-x) """ # this optimization should be done for numerical stability # so we don't care to check client counts if node.op == tensor.inv: inv_arg = node.inputs[0] if inv_arg.owner and inv_arg.owner.op == tensor.add: scalars, scalar_inputs, nonconsts = opt.scalarconsts_rest( inv_arg.owner.inputs, only_process_constants=True) # scalar_inputs are potentially dimshuffled and fill'd scalars if len(nonconsts) == 1: if nonconsts[0].owner and nonconsts[0].owner.op == tensor.exp: if scalars and np.allclose(np.sum(scalars), 1): out = opt._fill_chain( sigmoid(tensor.neg(nonconsts[0].owner.inputs[0])), scalar_inputs, ) # keep combined stack traces of # exp(x): nonconsts[0], # 1 + exp(x): inv_arg, # 1 / (1 + exp(x)): node.outputs[0] copy_stack_trace( [nonconsts[0], inv_arg, node.outputs[0]], out) return out
def is_1pexp(t): """ If 't' is of the form (1+exp(x)), return (False, x). Else return None. """ if t.owner and t.owner.op == tensor.add: scalars, scalar_inputs, nonconsts = \ opt.scalarconsts_rest(t.owner.inputs) # scalar_inputs are potentially dimshuffled and fill'd scalars if len(nonconsts) == 1: maybe_exp = nonconsts[0] if maybe_exp.owner and maybe_exp.owner.op == tensor.exp: # Verify that the constant terms sum to 1. if scalars: scal_sum = scalars[0] for s in scalars[1:]: scal_sum = scal_sum + s if numpy.allclose(scal_sum, 1): return False, maybe_exp.owner.inputs[0] # Before 7987b51 there used to be a bug where *any* constant # was considered as if it was equal to 1, and thus this # function would incorrectly identify it as (1 + exp(x)). if config.warn.identify_1pexp_bug: warnings.warn( 'Although your current code is fine, please note that ' 'Theano versions prior to 0.5 (more specifically, ' 'prior to commit 7987b51 on 2011-12-18) may have ' 'yielded an incorrect result. To remove this warning, ' 'either set the `warn.identify_1pexp_bug` config ' 'option to False, or `warn.ignore_bug_before` to at ' 'least \'0.4.1\'.') return None
def local_inv_1_plus_exp(node): """ 1/(1+exp(x)) -> sigm(-x) """ # this optimization should be done for numerical stability # so we don't care to check client counts if node.op == tensor.inv: inv_arg = node.inputs[0] if inv_arg.owner and inv_arg.owner.op == tensor.add: scalars, scalar_inputs, nonconsts = \ opt.scalarconsts_rest(inv_arg.owner.inputs, only_process_constants=True) # scalar_inputs are potentially dimshuffled and fill'd scalars if len(nonconsts) == 1: if nonconsts[0].owner and nonconsts[0].owner.op == tensor.exp: if scalars and numpy.allclose(numpy.sum(scalars), 1): out = opt._fill_chain( sigmoid( tensor.neg(nonconsts[0].owner.inputs[0])), scalar_inputs) # keep combined stack traces of # exp(x): nonconsts[0], # 1 + exp(x): inv_arg, # 1 / (1 + exp(x)): node.outputs[0] copy_stack_trace( [nonconsts[0], inv_arg, node.outputs[0]], out) return out
def is_1pexp(t): # if t is of form (1+exp(x)), return x # else return None if t.owner and t.owner.op == tensor.add: scalars, scalar_inputs, nonconsts = \ opt.scalarconsts_rest(t.owner.inputs) # scalar_inputs are potentially dimshuffled and fill'd scalars if len(nonconsts) == 1: maybe_exp = nonconsts[0] if maybe_exp.owner and maybe_exp.owner.op == tensor.exp: return False, maybe_exp.owner.inputs[0] return None
def local_inv_1_plus_exp(node): """ 1/(1+exp(x)) -> sigm(-x) """ # this optimization should be done for numerical stability # so we don't care to check client counts if node.op == tensor.inv: inv_arg = node.inputs[0] if inv_arg.owner and inv_arg.owner.op == tensor.add: scalars, scalar_inputs, nonconsts = opt.scalarconsts_rest(inv_arg.owner.inputs) # scalar_inputs are potentially dimshuffled and fill'd scalars if len(nonconsts) == 1: if nonconsts[0].owner and nonconsts[0].owner.op == tensor.exp: if scalars and numpy.allclose(numpy.sum(scalars), 1): return opt._fill_chain(sigmoid(tensor.neg(nonconsts[0].owner.inputs[0])), scalar_inputs)
def local_inv_1_plus_exp(node): """ 1/(1+exp(x)) -> sigm(-x) """ # this optimization should be done for numerical stability # so we don't care to check client counts if node.op == tensor.inv: inv_arg = node.inputs[0] if inv_arg.owner and inv_arg.owner.op == tensor.add: scalars, scalar_inputs, nonconsts = \ opt.scalarconsts_rest(inv_arg.owner.inputs) # scalar_inputs are potentially dimshuffled and fill'd scalars if len(nonconsts) == 1: if nonconsts[0].owner and nonconsts[0].owner.op == tensor.exp: if scalars and numpy.allclose(numpy.sum(scalars), 1): return opt._fill_chain( sigmoid(tensor.neg(nonconsts[0].owner.inputs[0])), scalar_inputs)