def test_usage_loop_through_views_2(): x, y, z = inputs() e0 = transpose_view(transpose_view(sigmoid(x))) e = dot(add_in_place(x,y), transpose_view(e0)) g = Env([x,y,z], [e]) consistent(g) # because sigmoid can do the copy g.replace(e0, x) inconsistent(g) # we cut off the path to the sigmoid
def test_usage_loop_through_views(): x, y, z = inputs() aip = add_in_place(x, y) e = dot(aip, transpose_view(x)) g = Env([x,y,z], [e], False) inconsistent(g) g.replace_validate(aip, add(x, z)) consistent(g)
def test_misc_2(): x, y, z = inputs() tv = transpose_view(x) e = add_in_place(x, tv) g = Env([x,y], [e], False) inconsistent(g) g.replace(tv, x) inconsistent(g)
def test_value_repl_2(): x, y, z = inputs() sy = sigmoid(y) e = add_in_place(x, sy) g = Env([x,y], [e], False) consistent(g) g.replace(sy, transpose_view(MyConstant("abc"))) consistent(g)
def test_indirect_2(): x, y, z = inputs() e0 = transpose_view(x) e = dot(sigmoid(add_in_place(x, y)), e0) g = Env([x,y,z], [e], False) inconsistent(g) new_e0 = add(e0, y) g.replace(e0, new_e0) consistent(g)
def test_indestructible_through_views(): x, y, z = inputs() x.tag.indestructible = True tv = transpose_view(x) e = add_in_place(tv, y) g = Env([x,y,z], [e], False) inconsistent(g) g.replace_validate(tv, sigmoid(x)) consistent(g)
def test_repair_destroy_path(): x, y, z = inputs() e1 = transpose_view(transpose_view(x)) e2 = transpose_view(transpose_view(e1)) e3 = add_in_place(e2, y) e4 = add_in_place(e1, z) g = Env([x,y,z], [e3, e4], False) inconsistent(g) g.replace(e2, transpose_view(x)) inconsistent(g)
def test_indestructible(): x, y, z = inputs() x.tag.indestructible = True x = copy(x) assert x.tag.indestructible # checking if indestructible survives the copy! e = add_in_place(x, y) g = Env([x,y,z], [e], False) inconsistent(g) g.replace_validate(e, add(x, y)) consistent(g)
def test_match_same(self): x, y, z = inputs() e = op1(x, x) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op1, 'x', 'y'), (op3, 'x', 'y')).optimize(g) assert str(g) == "[Op3(x, x)]"
def test_expand(self): x, y, z = inputs() e = op1(op1(op1(x))) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op1, '1'), (op2, (op1, '1')), ign=True).optimize(g) assert str(g) == "[Op2(Op1(Op2(Op1(Op2(Op1(x))))))]"
def test_nested_odd(self): x, y, z = inputs() e = op1(op1(op1(op1(op1(x))))) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op1, (op1, '1')), '1').optimize(g) assert str(g) == "[Op1(x)]"
def test_nested_out_pattern(self): x, y, z = inputs() e = op1(x, y) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op1, '1', '2'), (op4, (op1, '1'), (op2, '2'), (op3, '1', '2'))).optimize(g) assert str(g) == "[Op4(Op1(x), Op2(y), Op3(x, y))]"
def test_multiple(self): # it should replace all occurrences of the pattern x, y, z = inputs() e = op1(op2(x, y), op2(x, y), op2(y, z)) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op2, '1', '2'), (op4, '1')).optimize(g) assert str(g) == "[Op1(Op4(x), Op4(x), Op4(y))]"
def test_replace_circular(self): """`FunctionGraph` allows cycles--for better or worse.""" var1 = MyVariable("var1") var2 = MyVariable("var2") var3 = op1(var2, var1) var4 = op2(var3, var2) var5 = op3(var4, var2, var2) fg = FunctionGraph([var1, var2], [var3, var5], clone=False) fg.replace_all([(var3, var4)]) # The following works (and is kind of gross), because `var4` has been # mutated in-place assert fg.apply_nodes == {var4.owner, var5.owner} assert var4.owner.inputs == [var4, var2]
def test_merge_outputs(self): x, y, z = inputs() e1 = op3(op2(x, y)) e2 = op3(op2(x, y)) g = FunctionGraph([x, y, z], [e1, e2]) MergeOptimizer().optimize(g) assert str(g) == "[*1 -> Op3(Op2(x, y)), *1]"
def test_init(self): var1 = MyVariable("var1") var2 = MyVariable("var2") var3 = op1(var1) var4 = op2(var3, var2) fg = FunctionGraph([var1, var2], [var3, var4], clone=False) assert fg.inputs == [var1, var2] assert fg.outputs == [var3, var4] assert fg.apply_nodes == {var3.owner, var4.owner} assert fg.update_mapping is None assert fg.check_integrity() is None assert fg.variables == {var1, var2, var3, var4} assert fg.get_clients(var1) == [(var3.owner, 0)] assert fg.get_clients(var2) == [(var4.owner, 1)] assert fg.get_clients(var3) == [(var4.owner, 0), ("output", 0)] assert fg.get_clients(var4) == [("output", 1)]
def test_multi(self): x, y, z = inputs() e0 = op1(x, y) e = op3(op4(e0), e0) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op4, (op1, 'x', 'y')), (op3, 'x', 'y')).optimize(g) assert str(g) == "[Op3(Op4(*1 -> Op1(x, y)), *1)]"
def est_both_assert_merge_2(self): # Merge two nodes, both have assert on different node x1 = tt.matrix("x1") x2 = tt.matrix("x2") x3 = tt.matrix("x3") e = tt.dot(tt.opt.assert_op(x1, (x1 > x3).all()), x2) + tt.dot( x1, tt.opt.assert_op(x2, (x2 > x3).all()) ) g = FunctionGraph([x1, x2, x3], [e]) MergeOptimizer().optimize(g) strg = theano.printing.debugprint(g, file="str") strref = """Elemwise{add,no_inplace} [id A] '' 7 |dot [id B] '' 6 | |Assert{msg='Theano Assert failed!'} [id C] '' 5 | | |x1 [id D] | | |All [id E] '' 3 | | |Elemwise{gt,no_inplace} [id F] '' 1 | | |x1 [id D] | | |x3 [id G] | |Assert{msg='Theano Assert failed!'} [id H] '' 4 | |x2 [id I] | |All [id J] '' 2 | |Elemwise{gt,no_inplace} [id K] '' 0 | |x2 [id I] | |x3 [id G] |dot [id B] '' 6 """ # print(strg) assert strg == strref, (strg, strref)
def test_replace_subgraph(self): # replacing inside the graph x, y, z = inputs() e = op1(op2(x, y), z) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op2, '1', '2'), (op1, '2', '1')).optimize(g) assert str(g) == "[Op1(Op1(y, x), z)]"
def test_replace_output(self): # replacing the whole graph x, y, z = inputs() e = op1(op2(x, y), z) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op1, (op2, "1", "2"), "3"), (op4, "3", "2")).optimize(g) assert str(g) == "[Op4(z, y)]"
def est_both_assert_merge_2_reverse(self): # Test case "test_both_assert_merge_2" but in reverse order x1 = T.matrix('x1') x2 = T.matrix('x2') x3 = T.matrix('x3') e = T.dot(x1, T.opt.assert_op(x2, (x2 > x3).all())) +\ T.dot(T.opt.assert_op(x1, (x1 > x3).all()), x2) g = FunctionGraph([x1, x2, x3], [e]) MergeOptimizer().optimize(g) strg = theano.printing.debugprint(g, file='str') strref = '''Elemwise{add,no_inplace} [id A] '' 7 |dot [id B] '' 6 | |Assert{msg='Theano Assert failed!'} [id C] '' 5 | | |x1 [id D] | | |All [id E] '' 3 | | |Elemwise{gt,no_inplace} [id F] '' 1 | | |x1 [id D] | | |x3 [id G] | |Assert{msg='Theano Assert failed!'} [id H] '' 4 | |x2 [id I] | |All [id J] '' 2 | |Elemwise{gt,no_inplace} [id K] '' 0 | |x2 [id I] | |x3 [id G] |dot [id B] '' 6 ''' print(strg) assert strg == strref, (strg, strref)
def test_constant_unification(self): x = Constant(MyType(), 2, name='x') y = MyVariable('y') z = Constant(MyType(), 2, name='z') e = op1(op1(x, y), y) g = FunctionGraph([y], [e]) PatternOptimizer((op1, z, '1'), (op2, '1', z)).optimize(g) assert str(g) == "[Op1(Op2(y, z), y)]"
def test_nested_even(self): # regardless of the order in which we optimize, this # should work x, y, z = inputs() e = op1(op1(op1(op1(x)))) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op1, (op1, "1")), "1").optimize(g) assert str(g) == "FunctionGraph(x)"
def test_constant_unification(self): x = Constant(MyType(), 2, name="x") y = MyVariable("y") z = Constant(MyType(), 2, name="z") e = op1(op1(x, y), y) g = FunctionGraph([y], [e]) PatternOptimizer((op1, z, "1"), (op2, "1", z)).optimize(g) assert str(g) == "FunctionGraph(Op1(Op2(y, z), y))"
def test_unification_2(self): x, y, z = inputs() e = op1(op2(x, y), z) # the arguments to op2 are different g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op1, (op2, '1', '1'), '2'), # they are the same in the pattern (op4, '2', '1')).optimize(g) # The replacement should NOT occur assert str(g) == "[Op1(Op2(x, y), z)]"
def Env(inputs, outputs, validate=True): e = FunctionGraph(inputs, outputs, clone=False) e.attach_feature(destroyhandler.DestroyHandler()) e.attach_feature(ReplaceValidate()) if validate: e.validate() return e
def test_eq(self): # replacing the whole graph x, y, z = inputs() e = op1(op_y(x, y), z) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op1, (op_z, '1', '2'), '3'), (op4, '3', '2')).optimize(g) str_g = str(g) assert str_g == "[Op4(z, y)]"
def test_eq(self): # replacing the whole graph x, y, z = inputs() e = op1(op_y(x, y), z) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op1, (op_z, "1", "2"), "3"), (op4, "3", "2")).optimize(g) str_g = str(g) assert str_g == "FunctionGraph(Op4(z, y))"
def test_ambiguous(self): # this test should always work with TopoOptimizer and the # ignore_newtrees flag set to False. Behavior with ignore_newtrees # = True or with other NavigatorOptimizers may differ. x, y, z = inputs() e = op1(op1(op1(op1(op1(x))))) g = FunctionGraph([x, y, z], [e]) TopoPatternOptimizer((op1, (op1, "1")), (op1, "1"), ign=False).optimize(g) assert str(g) == "[Op1(x)]"
def test_no_recurse(self): # if the out pattern is an acceptable in pattern # and that the ignore_newtrees flag is True, # it should do the replacement and stop x, y, z = inputs() e = op1(op2(x, y), z) g = FunctionGraph([x, y, z], [e]) PatternOptimizer((op2, "1", "2"), (op2, "2", "1"), ign=True).optimize(g) assert str(g) == "[Op1(Op2(y, x), z)]"
def test_constant_merging(self): x = MyVariable("x") y = Constant(MyType(), 2, name="y") z = Constant(MyType(), 2, name="z") e = op1(op2(x, y), op2(x, y), op2(x, z)) g = FunctionGraph([x, y, z], [e]) MergeOptimizer().optimize(g) strg = str(g) assert (strg == "FunctionGraph(Op1(*1 -> Op2(x, y), *1, *1))" or strg == "FunctionGraph(Op1(*1 -> Op2(x, z), *1, *1))")
def test_identical_constant_args(self): x = MyVariable("x") y = Constant(MyType(), 2, name="y") z = Constant(MyType(), 2, name="z") with config.change_flags(compute_test_value="off"): e1 = op1(y, z) g = FunctionGraph([x, y, z], [e1]) MergeOptimizer().optimize(g) strg = str(g) assert strg == "FunctionGraph(Op1(y, y))" or strg == "FunctionGraph(Op1(z, z))"
def test_unification_1(self): x, y, z = inputs() e = op1(op2(x, x), z) # the arguments to op2 are the same g = FunctionGraph([x, y, z], [e]) PatternOptimizer( (op1, (op2, "1", "1"), "2"), # they are the same in the pattern (op4, "2", "1"), ).optimize(g) # So the replacement should occur assert str(g) == "FunctionGraph(Op4(z, x))"
def test_straightforward(self): x, y, z = inputs() e0 = dot(y, z) e = add(add(sigmoid(x), sigmoid(sigmoid(z))), dot(add(x, y), e0)) g = Env([x, y, z], [e]) g.extend(NodeFinder()) assert hasattr(g, 'get_nodes') for type, num in ((add, 3), (sigmoid, 3), (dot, 2)): if not len([x for x in g.get_nodes(type)]) == num: raise Exception("Expected: %i times %s" % (num, type)) new_e0 = add(y, z) assert e0.owner in g.get_nodes(dot) assert new_e0.owner not in g.get_nodes(add) g.replace(e0, new_e0) assert e0.owner not in g.get_nodes(dot) assert new_e0.owner in g.get_nodes(add) for type, num in ((add, 4), (sigmoid, 3), (dot, 1)): if not len([x for x in g.get_nodes(type)]) == num: raise Exception("Expected: %i times %s" % (num, type))
def test_pre_greedy_local_optimizer(): empty_fgraph = FunctionGraph([], []) x = MyVariable("x") y = MyVariable("y") c1 = Constant(MyType(), 1, "c1") c2 = Constant(MyType(), 2, "c2") o1 = op2(c1, c2) o3 = op1(c1, y) o2 = op1(o1, c2, x, o3, o1) assert o2.owner.inputs[0].owner is not None assert o2.owner.inputs[4].owner is not None # This should fold `o1`, because it has only `Constant` arguments, and # replace it with the `Constant` result cst = pre_greedy_local_optimizer(empty_fgraph, [constant_folding], o2) assert cst.owner.inputs[0].owner is None assert cst.owner.inputs[1] is c2 assert cst.owner.inputs[2] is x assert cst.owner.inputs[3] is o3 assert cst.owner.inputs[4] is cst.owner.inputs[0] # We're going to do it again, except this time `o1` is # in the `fgraph`, so it shouldn't be folded fg = FunctionGraph([], [o1], clone=False) o2 = op1(o1, c2, x, o3, o1) cst = pre_greedy_local_optimizer(fg, [constant_folding], o2) assert cst.owner.inputs[0] is o1 assert cst.owner.inputs[4] is cst.owner.inputs[0] # What exactly is this supposed to test? ms = MakeSlice()(1) cst = pre_greedy_local_optimizer(empty_fgraph, [constant_folding], ms) assert isinstance(cst, SliceConstant) # Make sure constant of slice signature is hashable. assert isinstance(hash(cst.signature()), int)
def test_replace_test_value(self): var1 = MyVariable("var1") var1.tag.test_value = 1 var2 = MyVariable("var2") var2.tag.test_value = 2 var3 = op1(var2, var1) var4 = op2(var3, var2) var4.tag.test_value = np.array([1, 2]) var5 = op3(var4, var2, var2) fg = FunctionGraph([var1, var2], [var3, var5], clone=False) var6 = op3() var6.tag.test_value = np.array(0) assert var6.tag.test_value.shape != var4.tag.test_value.shape with pytest.raises(AssertionError, match="The replacement.*"): fg.replace(var4, var6)
def test_merge_noinput(self): # Check that identical Apply nodes without inputs will be merged x = NoInputOp(param=0)() y = NoInputOp(param=0)() z = NoInputOp(param=1)() fg = FunctionGraph([], [x, y, z]) MergeOptimizer().optimize(fg) no_input_ops = [n for n in fg.apply_nodes if isinstance(n.op, NoInputOp)] assert len(no_input_ops) == 2, fg.apply_nodes
def test_constant_merging(self): x = MyVariable('x') y = Constant(MyType(), 2, name='y') z = Constant(MyType(), 2, name='z') e = op1(op2(x, y), op2(x, y), op2(x, z)) g = FunctionGraph([x, y, z], [e]) MergeOptimizer().optimize(g) strg = str(g) assert strg == "[Op1(*1 -> Op2(x, y), *1, *1)]" \ or strg == "[Op1(*1 -> Op2(x, z), *1, *1)]"
def test_aliased_inputs_replacement(): x, y, z = inputs() tv = transpose_view(x) tvv = transpose_view(tv) sx = sigmoid(x) e = add_in_place(x, tv) g = Env([x, y], [e], False) inconsistent(g) g.replace(tv, sx) consistent(g) g.replace(sx, tv) inconsistent(g) g.replace(tv, tvv) inconsistent(g) g.replace(tv, sx) consistent(g)
def test_mvnormal_ShapeFeature(): M_tt = tt.iscalar("M") M_tt.tag.test_value = 2 d_rv = multivariate_normal(tt.ones((M_tt, )), tt.eye(M_tt), size=2) fg = FunctionGraph( [i for i in tt_inputs([d_rv]) if not isinstance(i, tt.Constant)], [d_rv], clone=False, features=[tt.opt.ShapeFeature()], ) s1, s2 = fg.shape_feature.shape_of[d_rv] assert get_test_value(s1) == 2 assert M_tt in tt_inputs([s2]) # Test broadcasted shapes mean = tt.tensor(config.floatX, [True, False]) mean.tag.test_value = np.array([[0, 1, 2]], dtype=config.floatX) test_covar = np.diag(np.array([1, 10, 100], dtype=config.floatX)) test_covar = np.stack([test_covar, test_covar * 10.0]) cov = tt.as_tensor(test_covar).type() cov.tag.test_value = test_covar d_rv = multivariate_normal(mean, cov, size=[2, 3]) fg = FunctionGraph( [i for i in tt_inputs([d_rv]) if not isinstance(i, tt.Constant)], [d_rv], clone=False, features=[tt.opt.ShapeFeature()], ) s1, s2, s3, s4 = fg.shape_feature.shape_of[d_rv] assert s1.get_test_value() == 2 assert s2.get_test_value() == 3 assert s3.get_test_value() == 2 assert s4.get_test_value() == 3
def test_misc(): x, y, z = inputs() e = transpose_view(transpose_view(transpose_view(transpose_view(x)))) g = Env([x,y,z], [e]) consistent(g) chk = g.checkpoint() PatternOptimizer((transpose_view, (transpose_view, 'x')), 'x').optimize(g) assert str(g) == "[x]" new_e = add(x,y) g.replace_validate(x, new_e) assert str(g) == "[Add(x, y)]" g.replace(new_e, dot(add_in_place(x,y), transpose_view(x))) assert str(g) == "[Dot(AddInPlace(x, y), TransposeView(x))]" inconsistent(g) g.revert(chk) consistent(g) assert str(g) == "[TransposeView(TransposeView(TransposeView(TransposeView(x))))]"
def test_destroyers_loop(): # AddInPlace(x, y) and AddInPlace(y, x) should not coexist x, y, z = inputs() e1 = add(x, y) e2 = add(y, x) g = Env([x,y,z], [e1, e2]) chk = g.checkpoint() consistent(g) g.replace_validate(e1, add_in_place(x, y)) consistent(g) try: g.replace_validate(e2, add_in_place(y, x)) raise Exception("Shouldn't have reached this point.") except InconsistencyError: pass consistent(g) g.revert(chk) g.replace_validate(e2, add_in_place(y, x)) consistent(g) try: g.replace_validate(e1, add_in_place(x, y)) raise Exception("Shouldn't have reached this point.") except InconsistencyError: pass consistent(g)