File size: 4,084 Bytes
dc2106c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# Copyright (c) ONNX Project Contributors

# SPDX-License-Identifier: Apache-2.0

import numpy as np

import onnx
from onnx.backend.test.case.base import Base
from onnx.backend.test.case.model import expect
from onnx.defs import AI_ONNX_PREVIEW_TRAINING_DOMAIN, ONNX_DOMAIN


class Gradient(Base):
    @staticmethod
    def export_gradient_scalar_add() -> None:
        add_node = onnx.helper.make_node("Add", ["a", "b"], ["c"], name="my_add")
        gradient_node = onnx.helper.make_node(
            "Gradient",
            ["a", "b"],
            ["dc_da", "dc_db"],
            name="my_gradient",
            domain=AI_ONNX_PREVIEW_TRAINING_DOMAIN,
            xs=["a", "b"],
            y="c",
        )

        a = np.array(1.0).astype(np.float32)
        b = np.array(2.0).astype(np.float32)
        c = a + b
        # dc / da = d(a+b) / da = 1
        dc_da = np.array(1).astype(np.float32)
        # db / db = d(a+b) / db = 1
        dc_db = np.array(1).astype(np.float32)

        graph = onnx.helper.make_graph(
            nodes=[add_node, gradient_node],
            name="GradientOfAdd",
            inputs=[
                onnx.helper.make_tensor_value_info("a", onnx.TensorProto.FLOAT, []),
                onnx.helper.make_tensor_value_info("b", onnx.TensorProto.FLOAT, []),
            ],
            outputs=[
                onnx.helper.make_tensor_value_info("c", onnx.TensorProto.FLOAT, []),
                onnx.helper.make_tensor_value_info("dc_da", onnx.TensorProto.FLOAT, []),
                onnx.helper.make_tensor_value_info("dc_db", onnx.TensorProto.FLOAT, []),
            ],
        )
        opsets = [
            onnx.helper.make_operatorsetid(ONNX_DOMAIN, 12),
            onnx.helper.make_operatorsetid(AI_ONNX_PREVIEW_TRAINING_DOMAIN, 1),
        ]
        model = onnx.helper.make_model_gen_version(
            graph, producer_name="backend-test", opset_imports=opsets
        )
        expect(
            model, inputs=[a, b], outputs=[c, dc_da, dc_db], name="test_gradient_of_add"
        )

    @staticmethod
    def export_gradient_scalar_add_and_mul() -> None:
        add_node = onnx.helper.make_node("Add", ["a", "b"], ["c"], name="my_add")
        mul_node = onnx.helper.make_node("Mul", ["c", "a"], ["d"], name="my_mul")
        gradient_node = onnx.helper.make_node(
            "Gradient",
            ["a", "b"],
            ["dd_da", "dd_db"],
            name="my_gradient",
            domain=AI_ONNX_PREVIEW_TRAINING_DOMAIN,
            xs=["a", "b"],
            y="d",
        )

        a = np.array(1.0).astype(np.float32)
        b = np.array(2.0).astype(np.float32)
        c = a + b
        # d = a * c = a * (a + b)
        d = a * c
        # dd / da = d(a*a+a*b) / da = 2 * a + b
        dd_da = (2 * a + b).astype(np.float32)
        # dd / db = d(a*a+a*b) / db = a
        dd_db = a

        graph = onnx.helper.make_graph(
            nodes=[add_node, mul_node, gradient_node],
            name="GradientOfTwoOperators",
            inputs=[
                onnx.helper.make_tensor_value_info("a", onnx.TensorProto.FLOAT, []),
                onnx.helper.make_tensor_value_info("b", onnx.TensorProto.FLOAT, []),
            ],
            outputs=[
                onnx.helper.make_tensor_value_info("d", onnx.TensorProto.FLOAT, []),
                onnx.helper.make_tensor_value_info("dd_da", onnx.TensorProto.FLOAT, []),
                onnx.helper.make_tensor_value_info("dd_db", onnx.TensorProto.FLOAT, []),
            ],
        )

        opsets = [
            onnx.helper.make_operatorsetid(ONNX_DOMAIN, 12),
            onnx.helper.make_operatorsetid(AI_ONNX_PREVIEW_TRAINING_DOMAIN, 1),
        ]
        model = onnx.helper.make_model_gen_version(
            graph, producer_name="backend-test", opset_imports=opsets
        )
        expect(
            model,
            inputs=[a, b],
            outputs=[d, dd_da, dd_db],
            name="test_gradient_of_add_and_mul",
        )