Example #1
0
def test_reducemin_training(op_tester):
    data = np.random.rand(2, 5, 3).astype(np.float32)
    axes_list = [[0], [1], [2], [0, 1], [0, 2], [1, 2], [0, 1, 2],
                 USE_DEFAULT_AXES]
    keepdims_list = [False, True]

    def init_builder(builder):
        result = []
        axes_reduce = []
        for axes, keepdims in itertools.product(axes_list, keepdims_list):
            tensor = builder.addInputTensor(data)
            if axes is USE_DEFAULT_AXES:
                out = builder.aiOnnx.reducemin(
                    [tensor],
                    keepdims=keepdims,
                    debugContext="test_reducemin_default_{0}".format(keepdims))
            else:
                out = builder.aiOnnx.reducemin(
                    [tensor],
                    axes=axes,
                    keepdims=keepdims,
                    debugContext="test_reducemin_{0}_{1}".format(
                        axes, keepdims))
            result.append(out)
            result.append(popart.reservedGradientPrefix() + tensor)
            axes_len = len(axes) if axes is not USE_DEFAULT_AXES else 3
            axes_reduce.append(range(3 - (0 if keepdims else axes_len)))
        sum = builder.aiOnnx.sum([
            builder.aiOnnx.reducesum([r],
                                     axes=axes,
                                     keepdims=False,
                                     debugContext="test_reducesum_all")
            for r, axes in zip(result[0::2], axes_reduce)
        ],
                                 debugContext="test_sum")
        reshaped_sum = builder.aiOnnx.unsqueeze([sum],
                                                axes=[0],
                                                debugContext="test_reshape")
        builder.addOutputTensor(reshaped_sum)
        result = [
            reshaped_sum,
            popart.reservedGradientPrefix() + reshaped_sum
        ] + result
        return result

    def reference(ref_data):
        result = []
        for axes, keepdims in itertools.product(axes_list, keepdims_list):
            tensor = torch.tensor(data, requires_grad=True)
            out = tensor
            sorted_axes = axes if axes is not USE_DEFAULT_AXES else [0, 1, 2]
            sorted_axes.sort(reverse=True)
            for dim in sorted_axes:
                out = torch.min(out, dim=dim, keepdim=keepdims)[0]
            result.append(out)
            result.append(tensor)

        sum = torch.unsqueeze(torch.sum(
            torch.stack([torch.sum(r) for r in result[0::2]])),
                              dim=0)

        d__o = ref_data.getOutputTensorGrad(0)
        sum.backward(torch.tensor(d__o))
        result[1::2] = [r.grad for r in result[1::2]]

        result = [sum, sum.grad] + result
        return result

    op_tester.setPatterns(['OpToIdentity'], enableRuntimeAsserts=False)
    op_tester.run(init_builder, reference, 'train')
Example #2
0
def test_dynamicslice_overlap_correct(op_tester):
    data = np.random.rand(10).astype(np.float32)
    axes = [0]
    sizes = [5]

    def init_builder(builder):
        tensor = builder.addInitializedInputTensor(data)
        outputs = []
        result = []
        for sliceid in range(2):
            index = builder.addInputTensor(np.asarray([sliceid * 3],
                                                      np.uint32))
            out = builder.aiGraphcore.dynamicslice([tensor, index],
                                                   axes=axes,
                                                   sizes=sizes,
                                                   noOverlap=False)
            out = builder.aiGraphcore.scale([out], float(1 + sliceid))

            # TODO T46821: The shape given by getTensorShape is wrong
            # Check the shape inference has run.
            # assert builder.getTensorShape(out) == list(data.shape)

            outputs.append(out)
            result.append(out)

        sum = builder.aiOnnx.sum(outputs)
        sum = builder.aiOnnx.reducesum([sum], axes=[0], keepdims=False)
        sum = builder.aiOnnx.unsqueeze([sum], axes=[0])

        builder.addOutputTensor(sum)
        result = [
            sum,
            popart.reservedGradientPrefix() + sum,
            popart.reservedGradientPrefix() + tensor
        ] + result
        return result

    def reference(ref_data):
        tensor = torch.tensor(data, requires_grad=True)
        outputs = []
        result = []
        for sliceid in range(2):
            out = tensor[sliceid * 3:sliceid * 3 + sizes[0]]
            out = out * float(1 + sliceid)
            outputs.append(out)
            result.append(out)

        sum = torch.unsqueeze(torch.sum(torch.stack(outputs)), dim=0)

        d__o = ref_data.getOutputTensorGrad(0)
        sum.backward(torch.tensor(d__o))

        # Note: Comparison equal with noOverlap=False handles overlapping
        # slices correctly (at higher computational cost). No correction needed.
        tensor.grad += torch.tensor(
            np.asarray([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]))

        result = [sum, torch.tensor(d__o), tensor.grad] + result
        return result

    op_tester.setPatterns(popart.PatternsLevel.All, enableRuntimeAsserts=False)
    op_tester.run(init_builder, reference, 'train')
Example #3
0
def test_reducemin_training_negative_axis(op_tester):
    """Test the above but with equivalent negative axes.

    Args:
        op_tester (OpTester): OpTEster object, see op_tester.py

    Returns:
        Nothing
    """
    data = np.random.rand(2, 5, 3).astype(np.float32)
    axes_list = [[0], [-1], [-2], [0, -1], [0, -2], [1, -3], [0, -1, -2],
                 USE_DEFAULT_AXES]
    keepdims_list = [False, True]

    def init_builder(builder):
        result = []
        axes_reduce = []
        for axes, keepdims in itertools.product(axes_list, keepdims_list):
            tensor = builder.addInputTensor(data)
            if axes is USE_DEFAULT_AXES:
                out = builder.aiOnnx.reducemin(
                    [tensor],
                    keepdims=keepdims,
                    debugContext="test_reducemin_default_{0}".format(keepdims))
            else:
                out = builder.aiOnnx.reducemin(
                    [tensor],
                    axes=axes,
                    keepdims=keepdims,
                    debugContext="test_reducemin_{0}_{1}".format(
                        axes, keepdims))
            result.append(out)
            result.append(popart.reservedGradientPrefix() + tensor)
            axes_len = len(axes) if axes is not USE_DEFAULT_AXES else 3
            axes_reduce.append(range(3 - (0 if keepdims else axes_len)))
        sum = builder.aiOnnx.sum([
            builder.aiOnnx.reducesum([r],
                                     axes=axes,
                                     keepdims=False,
                                     debugContext="test_reducesum_all")
            for r, axes in zip(result[0::2], axes_reduce)
        ],
                                 debugContext="test_sum")
        reshaped_sum = builder.aiOnnx.unsqueeze([sum],
                                                axes=[0],
                                                debugContext="test_reshape")
        builder.addOutputTensor(reshaped_sum)
        result = [
            reshaped_sum,
            popart.reservedGradientPrefix() + reshaped_sum
        ] + result
        return result

    def reference(ref_data):
        result = []
        for axes, keepdims in itertools.product(axes_list, keepdims_list):
            tensor = torch.tensor(data, requires_grad=True)
            out = tensor
            sorted_axes = axes if axes is not USE_DEFAULT_AXES else [0, 1, 2]
            print(sorted_axes)
            # Have to manually norm the axes as torch doesn't like -1 * rank
            # axes.
            for i in range(len(sorted_axes)):
                axis = sorted_axes[i]
                if axis < 0:
                    sorted_axes[i] = len(out.size()) + axis

            sorted_axes.sort(reverse=True)
            print("\t", sorted_axes)
            for dim in sorted_axes:
                out = torch.min(out, dim=dim, keepdim=keepdims)[0]
            result.append(out)
            result.append(tensor)

        sum = torch.unsqueeze(torch.sum(
            torch.stack([torch.sum(r) for r in result[0::2]])),
                              dim=0)

        d__o = ref_data.getOutputTensorGrad(0)
        sum.backward(torch.tensor(d__o))
        result[1::2] = [r.grad for r in result[1::2]]

        result = [sum, sum.grad] + result
        return result

    op_tester.setPatterns(['OpToIdentity'], enableRuntimeAsserts=False)
    op_tester.run(init_builder, reference, 'train')
Example #4
0
def test_call_grad_1(op_tester):
    shape = [4, 4]
    d0 = np.random.normal(size=shape).astype(np.float32)
    d1 = np.random.normal(size=shape).astype(np.float32)
    d2 = np.random.normal(size=shape).astype(np.float32)

    def get_init_builder(input_tensor_method):
        def init_builder(builder):
            i0 = builder.addInputTensor(d0)
            i1 = builder.addInputTensor(d1)
            i2 = builder.addInputTensor(d2)

            subgraph_builder = builder.createSubgraphBuilder()

            if input_tensor_method == "untyped":
                sgi0 = subgraph_builder.addUntypedInputTensor()
                sgi1 = subgraph_builder.addUntypedInputTensor()
            elif input_tensor_method == "with_info":
                info = popart.TensorInfo("FLOAT", shape)
                sgi0 = subgraph_builder.addInputTensor(info)
                sgi1 = subgraph_builder.addInputTensor(info)
            elif input_tensor_method == "from_higher_scope":
                subgraph_builder.addInputTensorFromParentGraph(i0)
                subgraph_builder.addInputTensorFromParentGraph(i1)

            if input_tensor_method == "from_higher_scope":
                subgraph_builder.addOutputTensor(
                    subgraph_builder.aiOnnx.matmul([i0, i1]))
            else:
                subgraph_builder.addOutputTensor(
                    subgraph_builder.aiOnnx.matmul([sgi0, sgi1]))

            act = builder.aiGraphcore.call([i0, i1], 1, subgraph_builder)[0]
            out = builder.aiGraphcore.call([act, i2], 1, subgraph_builder)[0]

            builder.addOutputTensor(out)
            return [
                out,
                popart.reservedGradientPrefix() + out,
                popart.reservedGradientPrefix() + i0,
                popart.reservedGradientPrefix() + i1,
                popart.reservedGradientPrefix() + i2
            ]

        return init_builder

    def reference(ref_data):
        t0 = torch.tensor(d0, requires_grad=True)
        t1 = torch.tensor(d1, requires_grad=True)
        t2 = torch.tensor(d2, requires_grad=True)
        o = torch.chain_matmul(t0, t1, t2)
        d__o = ref_data.getOutputTensorGrad(0)
        o.backward(torch.tensor(d__o))

        return [o, d__o, t0.grad, t1.grad, t2.grad]

    op_tester.setPatterns(popart.PatternsLevel.Default,
                          enableRuntimeAsserts=False)
    op_tester.run(get_init_builder("untyped"), reference, 'train')
    op_tester.run(get_init_builder("with_info"), reference, 'train')
    op_tester.run(get_init_builder("from_higher_scope"), reference, 'train')