def test_softmax(self):
        X = np.random.randn(100, 4).astype(np.float32)
        y = X.sum(axis=1) + np.random.randn(100) / 10
        y = y.astype(np.float32)
        self.assertEqual(y.shape, (100, ))
        weight = np.random.randn(4, 1).astype(np.float32)
        intercept = np.random.randn(1).astype(np.float32)

        node = OnnxAdd(OnnxMatMul('X', weight, op_version=TARGET_OPSET),
                       intercept,
                       op_version=TARGET_OPSET)
        nn_onnx = node.to_onnx({'X': X}, target_opset=TARGET_OPSET)
        with open("debug_ort_add.onnx", "wb") as f:
            f.write(nn_onnx.SerializeToString())
        self.assertEqual(len(nn_onnx.graph.output), 1)

        node = OnnxMatMul('X', weight, op_version=TARGET_OPSET)
        nn_onnx = node.to_onnx({'X': X}, target_opset=TARGET_OPSET)
        self.assertEqual(len(nn_onnx.graph.output), 1)

        node = OnnxSoftmax(OnnxAdd(OnnxMatMul('X',
                                              weight,
                                              op_version=TARGET_OPSET),
                                   intercept,
                                   op_version=TARGET_OPSET),
                           op_version=TARGET_OPSET)
        nn_onnx = node.to_onnx({'X': X}, target_opset=TARGET_OPSET)
        self.assertEqual(len(nn_onnx.graph.output), 1)
예제 #2
0
 def test_onnx_micro_runtime_matmul(self):
     opset = TestOnnxMicroRuntime.opset
     x = numpy.array([1, 2, 4, 5]).astype(numpy.float32).reshape((2, 2))
     cop = OnnxMatMul('X', 'X', op_version=opset, output_names=['Y'])
     model_def = cop.to_onnx({'X': x}, target_opset=opset)
     rt = OnnxMicroRuntime(model_def)
     out = rt.run({'X': x})
     self.assertEqual(numpy.matmul(x, x), out['Y'])
예제 #3
0
def decorrelate_transformer_converter(scope, operator, container):
    op = operator.raw_operator
    opv = container.target_opset
    out = operator.outputs

    X = operator.inputs[0]

    dtype = guess_numpy_type(X.type)
    options = container.get_options(op, dict(use_gemm=False))
    use_gemm = options['use_gemm']
    print('conversion: use_gemm=', use_gemm)

    if use_gemm:
        Y = OnnxGemm(X,
                     op.coef_.astype(dtype),
                     (-op.mean_ @ op.coef_).astype(dtype),
                     op_version=opv,
                     alpha=1.,
                     beta=1.,
                     output_names=out[:1])
    else:
        Y = OnnxMatMul(OnnxSub(X, op.mean_.astype(dtype), op_version=opv),
                       op.coef_.astype(dtype),
                       op_version=opv,
                       output_names=out[:1])
    Y.add_to(scope, container)
예제 #4
0
def _onnx_linear_regression(target_opset=None, dtype=numpy.float32):
    """
    Returns the ONNX graph for function
    :math:`Y = f(X, A, B) = A X + B`.

    .. gdot::
        :script: DOT-SECTION

        from mlprodict.onnxrt import OnnxInference
        from onnxcustom.utils.onnx_function import function_onnx_graph

        model_onnx = function_onnx_graph('linear_regression')
        oinf = OnnxInference(model_onnx, inplace=False)

        print("DOT-SECTION", oinf.to_dot())
    """
    from skl2onnx.algebra.onnx_ops import (OnnxMatMul, OnnxAdd)
    res = OnnxAdd(OnnxMatMul('X', 'A', op_version=target_opset),
                  'B',
                  op_version=target_opset,
                  output_names=['Y'])

    var_type = dtype_to_var_type(dtype)
    varsx = [('X', var_type([None, None])), ('A', var_type([None, None])),
             ('B', var_type([None, None]))]
    onx = res.to_onnx(varsx,
                      outputs=[('Y', var_type())],
                      target_opset=target_opset,
                      other_outputs=[res])
    return onx
예제 #5
0
    def test_onnx_rename_weights(self):
        N, D_in, D_out, H = 3, 3, 3, 3
        var = [('X', FloatTensorType([N, D_in]))]
        w1 = numpy.random.randn(D_in, H).astype(numpy.float32)
        w2 = numpy.random.randn(H, D_out).astype(numpy.float32)
        opv = 14
        onx_alg = OnnxMatMul(
            OnnxRelu(OnnxMatMul(*var, w1, op_version=opv),
                     op_version=opv),
            w2, op_version=opv, output_names=['Y'])
        onx = onx_alg.to_onnx(
            var, target_opset=opv, outputs=[('Y', FloatTensorType())])

        onx = onnx_rename_weights(onx)
        names = [init.name for init in onx.graph.initializer]
        self.assertEqual(['I0_Ma_MatMulcst', 'I1_Ma_MatMulcst1'], names)
        self.assertEqual(get_onnx_opset(onx), 14)
        self.assertRaise(lambda: get_onnx_opset(onx, "H"), ValueError)
예제 #6
0
def decorrelate_transformer_converter2(scope, operator, container):
    op = operator.raw_operator
    opv = container.target_opset
    out = operator.outputs
    X = operator.inputs[0]
    dtype = guess_numpy_type(X.type)
    m = OnnxMatMul(OnnxSub(X, op.pca_.mean_.astype(dtype), op_version=opv),
                   op.pca_.components_.T.astype(dtype),
                   op_version=opv)
    Y = OnnxIdentity(m, op_version=opv, output_names=out[:1])
    Y.add_to(scope, container)
예제 #7
0
def custom_linear_regressor_converter(scope, operator, container):
    op = operator.raw_operator
    opv = container.target_opset
    out = operator.outputs
    X = operator.inputs[0]
    dtype = guess_numpy_type(X.type)
    m = OnnxAdd(OnnxMatMul(X, op.coef_.astype(dtype), op_version=opv),
                numpy.array([op.intercept_]),
                op_version=opv)
    Y = OnnxIdentity(m, op_version=opv, output_names=out[:1])
    Y.add_to(scope, container)
예제 #8
0
def custom_cluster_converter(scope, operator, container):
    op = operator.raw_operator
    opv = container.target_opset
    out = operator.outputs
    X = operator.inputs[0]
    dtype = guess_numpy_type(X.type)
    dist = OnnxMatMul(X, op.clusters_.astype(dtype), op_version=opv)
    label = OnnxArgMax(dist, axis=1, op_version=opv)
    Yl = OnnxIdentity(label, op_version=opv, output_names=out[:1])
    Yp = OnnxIdentity(dist, op_version=opv, output_names=out[1:])
    Yl.add_to(scope, container)
    Yp.add_to(scope, container)
예제 #9
0
def decorrelate_transformer_converter(scope, operator, container):
    op = operator.raw_operator
    opv = container.target_opset
    out = operator.outputs

    # We retrieve the unique input.
    X = operator.inputs[0]

    # In most case, computation happen in floats.
    # But it might be with double. ONNX is very strict
    # about types, every constant should have the same
    # type as the input.
    dtype = guess_numpy_type(X.type)

    # We tell in ONNX language how to compute the unique output.
    # op_version=opv tells which opset is requested
    Y = OnnxMatMul(OnnxSub(X, op.mean_.astype(dtype), op_version=opv),
                   op.coef_.astype(dtype),
                   op_version=opv,
                   output_names=out[:1])
    Y.add_to(scope, container)
예제 #10
0
def decorrelate_transformer_converter(scope, operator, container):
    op = operator.raw_operator
    opv = container.target_opset
    out = operator.outputs

    X = operator.inputs[0]

    dtype = guess_numpy_type(X.type)

    Y1 = OnnxMatMul(
        OnnxSub(X, op.mean_.astype(dtype), op_version=opv),
        op.coef_.astype(dtype),
        op_version=opv, output_names=out[:1])

    Y2 = OnnxGemm(X, op.coef_.astype(dtype),
                  (- op.mean_ @ op.coef_).astype(dtype),
                  op_version=opv, alpha=1., beta=1.,
                  output_names=out[1:2])

    Y1.add_to(scope, container)
    Y2.add_to(scope, container)
 def test_algebra_to_onnx(self):
     X = numpy.random.randn(5, 4)
     beta = numpy.array([1, 2, 3, 4]) / 10
     beta32 = beta.astype(numpy.float32)
     onnxExpM = OnnxExp(OnnxMatMul('X', beta32))
     cst = numpy.ones((1, 3), dtype=numpy.float32)
     onnxExpM1 = OnnxAdd(onnxExpM, cst)
     onnxPred = OnnxDiv(onnxExpM, onnxExpM1)
     inputs = {'X': X[:1].astype(numpy.float32)}
     model_onnx = onnxPred.to_onnx(inputs)
     s1 = str(model_onnx)
     model_onnx = onnxPred.to_onnx(inputs)
     s2 = str(model_onnx)
     assert s1 == s2
예제 #12
0
    def test_algebra_converter(self):

        coef = numpy.array([[1, 2], [3, 4]], dtype=numpy.float64)
        intercept = 1
        X_test = numpy.array([[1, -2], [3, -4]], dtype=numpy.float64)

        onnx_fct = OnnxSub(OnnxMatMul('X', coef),
                           numpy.array([intercept], dtype=numpy.float64),
                           output_names=['Y'])
        onnx_model = onnx_fct.to_onnx({'X': X_test}, dtype=numpy.float64)

        sess = InferenceSession(onnx_model.SerializeToString())
        ort_pred = sess.run(None, {'X': X_test})[0]
        assert_almost_equal(ort_pred, numpy.array([[-6., -7.], [-10., -11.]]))
예제 #13
0
def custom_linear_classifier_converter(scope, operator, container):
    op = operator.raw_operator
    opv = container.target_opset
    out = operator.outputs
    X = operator.inputs[0]
    dtype = guess_numpy_type(X.type)
    raw = OnnxAdd(OnnxMatMul(X, op.coef_.astype(dtype), op_version=opv),
                  op.intercept_.astype(dtype),
                  op_version=opv)
    prob = OnnxSigmoid(raw, op_version=opv)
    label = OnnxArgMax(prob, axis=1, op_version=opv)
    Yl = OnnxIdentity(label, op_version=opv, output_names=out[:1])
    Yp = OnnxIdentity(prob, op_version=opv, output_names=out[1:])
    Yl.add_to(scope, container)
    Yp.add_to(scope, container)
예제 #14
0
    def test_bug_add(self):
        coef = numpy.array([-8.43436238e-02, 5.47765517e-02, 6.77578341e-02, 1.56675273e+00,
                            -1.45737317e+01, 3.78662574e+00 - 6.52943746e-03 - 1.39463522e+00,
                            2.89157796e-01 - 1.53753213e-02 - 9.88045749e-01, 1.00224585e-02,
                            -4.96820220e-01], dtype=numpy.float64)
        intercept = 35.672858515632

        X_test = (coef + 1.).reshape((1, coef.shape[0]))

        onnx_fct = OnnxAdd(
            OnnxMatMul('X', coef.astype(numpy.float64),
                       op_version=TARGET_OPSET),
            numpy.array([intercept]), output_names=['Y'],
            op_version=TARGET_OPSET)
        onnx_model64 = onnx_fct.to_onnx({'X': X_test.astype(numpy.float64)})

        oinf = OnnxInference(onnx_model64)
        ort_pred = oinf.run({'X': X_test.astype(numpy.float64)})['Y']
        self.assertEqualArray(ort_pred, numpy.array([245.19907295849504]))
예제 #15
0
 def test_algebra_to_onnx(self):
     X = numpy.random.randn(5, 4)
     beta = numpy.array([1, 2, 3, 4]) / 10
     beta32 = beta.astype(numpy.float32)
     onnxExpM = OnnxExp(OnnxMatMul('X', beta32))
     cst = numpy.ones((1, 3), dtype=numpy.float32)
     onnxExpM1 = OnnxAdd(onnxExpM, cst)
     onnxPred = OnnxDiv(onnxExpM, onnxExpM1)
     inputs = {'X': X[:1].astype(numpy.float32)}
     model_onnx = onnxPred.to_onnx(inputs)
     s1 = str(model_onnx)
     model_onnx = onnxPred.to_onnx(inputs)
     s2 = str(model_onnx)
     assert s1 == s2
     nin = list(onnxExpM1.enumerate_initial_types())
     nno = list(onnxExpM1.enumerate_nodes())
     nva = list(onnxExpM1.enumerate_variables())
     self.assertEqual(len(nin), 0)
     self.assertEqual(len(nno), 3)
     self.assertEqual(len(nva), 0)
예제 #16
0
def model_convert(onnx_filename):
    'make the model'

    if "cifar" in onnx_filename:
        mean_list = [0.4914, 0.4822, 0.4465]
        sigma_list = [0.2023, 0.1994, 0.2010]
    else:
        assert 'mnist' in onnx_filename
        mean_list = [0.1307]
        sigma_list = [0.3081]

    onnx_model = onnx.load(onnx_filename + ".onnx")
    onnx_model = remove_unused_initializers(onnx_model)

    onnx_input = onnx_model.graph.input[0].name
    print(f"onnx input: {onnx_input}")

    inp = onnx_model.graph.input[0]
    image_shape = tuple(
        d.dim_value if d.dim_value != 0 else 1
        for d in inp.type.tensor_type.shape.dim)  # single input

    print(f"using input shape: {image_shape}")
    print(
        f"orig input shape: {tuple(d.dim_value for d in inp.type.tensor_type.shape.dim)}"
    )

    image_cols = image_shape[-1]
    image_rows = image_shape[-2]

    b_mats = []
    c_mats = []

    for mean, sigma in zip(mean_list, sigma_list):
        b_mats.append(np.identity(image_cols, dtype=np.float32) / sigma)
        c_mats.append(
            np.ones((image_rows, image_cols), dtype=np.float32) * (-mean))

    c_mats = np.array(c_mats)

    while len(c_mats.shape) != len(image_shape):
        c_mats = np.expand_dims(c_mats, axis=0)

    print(f"c_mats shape: {c_mats.shape}")

    b_mats = np.array(b_mats)

    while len(b_mats.shape) != len(image_shape):
        b_mats = np.expand_dims(b_mats, axis=0)

    print(f"b_mats shape: {b_mats.shape}")

    input_name = 'unscaled_input'
    add_node = OnnxAdd(input_name, c_mats)
    matmul_node = OnnxMatMul(add_node, b_mats, output_names=[onnx_input])

    i = onnx.helper.make_tensor_value_info('i', TensorProto.FLOAT, image_shape)

    # test matmul model
    matmul_model = matmul_node.to_onnx({input_name: i})
    onnx.checker.check_model(matmul_model)

    zero_in = np.zeros(image_shape, dtype=np.float32)
    o = predict_with_onnxruntime(matmul_model, zero_in)
    olist = [o[0, 0, 5, 7], o[0, 1, 5, 7], o[0, 2, 5, 7]]
    print(f"output mat_mul zeros: {olist}")

    zero_val_list = [(0 - mean) / sigma
                     for mean, sigma in zip(mean_list, sigma_list)]
    print(f"expected zero vals = {zero_val_list}")
    assert np.allclose(olist, zero_val_list)

    one_in = np.ones(image_shape, dtype=np.float32)
    o = predict_with_onnxruntime(matmul_model, one_in)
    olist = [o[0, 0, 5, 7], o[0, 1, 5, 7], o[0, 2, 5, 7]]
    print(f"output mat_mul zeros: {olist}")
    one_val_list = [(1 - mean) / sigma
                    for mean, sigma in zip(mean_list, sigma_list)]
    print(f"expected one vals = {one_val_list}")
    assert np.allclose(olist, one_val_list)

    print("zero and one vals matches with prefix network!")

    # only shapes are used
    model2_def = matmul_node.to_onnx({input_name: i})

    #print('The model is:\n{}'.format(model2_def))

    onnx.checker.check_model(model2_def)

    print('The models are checked!')
    combined = glue_models(model2_def, onnx_model)

    converted_filename = f"{onnx_filename}_noscale.onnx"
    onnx.save_model(combined, converted_filename)
    print(f"Saved unscaled model to: {converted_filename}\n")
예제 #17
0
def live_decorrelate_transformer_converter(scope, operator, container):
    # shortcuts
    op = operator.raw_operator
    opv = container.target_opset
    out = operator.outputs

    # We retrieve the unique input.
    X = operator.inputs[0]

    # We guess its type. If the operator ingests float (or double),
    # it outputs float (or double).
    proto_dtype = guess_proto_type(X.type)
    dtype = guess_numpy_type(X.type)

    # Lines in comment specify the numpy computation
    # the ONNX code implements.
    # mean_ = numpy.mean(X, axis=0, keepdims=True)
    mean = OnnxReduceMean(X, axes=[0], keepdims=1, op_version=opv)

    # This is trick I often use. The converter automatically
    # chooses a name for every output. In big graph,
    # it is difficult to know which operator is producing which output.
    # This line just tells every node must prefix its ouputs with this string.
    # It also applies to all inputs nodes unless this method
    # was called for one of these nodes.
    mean.set_onnx_name_prefix('mean')

    # X2 = X - mean_
    X2 = OnnxSub(X, mean, op_version=opv)

    # V = X2.T @ X2 / X2.shape[0]
    N = OnnxGatherElements(OnnxShape(X, op_version=opv),
                           numpy.array([0], dtype=numpy.int64),
                           op_version=opv)
    Nf = OnnxCast(N, to=proto_dtype, op_version=opv)

    # Every output involved in N and Nf is prefixed by 'N'.
    Nf.set_onnx_name_prefix('N')

    V = OnnxDiv(OnnxMatMul(OnnxTranspose(X2, op_version=opv),
                           X2,
                           op_version=opv),
                Nf,
                op_version=opv)
    V.set_onnx_name_prefix('V1')

    # V += numpy.identity(V.shape[0]) * self.alpha
    V = OnnxAdd(V,
                op.alpha * numpy.identity(op.nf_, dtype=dtype),
                op_version=opv)
    V.set_onnx_name_prefix('V2')

    # L, P = numpy.linalg.eig(V)
    LP = OnnxEig(V, eigv=True, op_version=opv)
    LP.set_onnx_name_prefix('LP')

    # Linv = L ** (-0.5)
    # Notation LP[0] means OnnxPow is taking the first output
    # of operator OnnxEig, LP[1] would mean the second one
    # LP is not allowed as it is ambiguous
    Linv = OnnxPow(LP[0], numpy.array([-0.5], dtype=dtype), op_version=opv)
    Linv.set_onnx_name_prefix('Linv')

    # diag = numpy.diag(Linv)
    diag = OnnxMul(OnnxEyeLike(numpy.zeros((op.nf_, op.nf_),
                                           dtype=numpy.int64),
                               k=0,
                               op_version=opv),
                   Linv,
                   op_version=opv)
    diag.set_onnx_name_prefix('diag')

    # root = P @ diag @ P.transpose()
    trv = OnnxTranspose(LP[1], op_version=opv)
    coef_left = OnnxMatMul(LP[1], diag, op_version=opv)
    coef_left.set_onnx_name_prefix('coef_left')
    coef = OnnxMatMul(coef_left, trv, op_version=opv)
    coef.set_onnx_name_prefix('coef')

    # Same part as before.
    Y = OnnxMatMul(X2, coef, op_version=opv, output_names=out[:1])
    Y.set_onnx_name_prefix('Y')

    # The last line specifies the final output.
    # Every node involved in the computation is added to the ONNX
    # graph at this stage.
    Y.add_to(scope, container)
예제 #18
0
def live_decorrelate_transformer_converter(scope, operator, container):
    op = operator.raw_operator
    opv = container.target_opset
    out = operator.outputs

    # We retrieve the unique input.
    X = operator.inputs[0]
    proto_dtype = guess_proto_type(X.type)

    dtype = guess_numpy_type(X.type)

    # new part

    # mean_ = numpy.mean(X, axis=0, keepdims=True)
    mean = OnnxReduceMean(X, axes=[0], keepdims=1, op_version=opv)
    mean.set_onnx_name_prefix('mean')

    # X2 = X - mean_
    X2 = OnnxSub(X, mean, op_version=opv)

    # V = X2.T @ X2 / X2.shape[0]
    N = OnnxGatherElements(OnnxShape(X, op_version=opv),
                           numpy.array([0], dtype=numpy.int64),
                           op_version=opv)
    Nf = OnnxCast(N, to=proto_dtype, op_version=opv)
    Nf.set_onnx_name_prefix('N')

    V = OnnxDiv(OnnxMatMul(OnnxTranspose(X2, op_version=opv),
                           X2,
                           op_version=opv),
                Nf,
                op_version=opv)
    V.set_onnx_name_prefix('V1')

    # V += numpy.identity(V.shape[0]) * self.alpha
    V = OnnxAdd(V,
                op.alpha * numpy.identity(op.nf_, dtype=dtype),
                op_version=opv)
    V.set_onnx_name_prefix('V2')

    # L, P = numpy.linalg.eig(V)
    LP = OnnxEig(V, eigv=True, op_version=opv)
    LP.set_onnx_name_prefix('LP')

    # Linv = L ** (-0.5)
    Linv = OnnxPow(LP[0], numpy.array([-0.5], dtype=dtype), op_version=opv)
    Linv.set_onnx_name_prefix('Linv')

    # diag = numpy.diag(Linv)
    diag = OnnxMul(OnnxEyeLike(numpy.array([op.nf_, op.nf_],
                                           dtype=numpy.int64),
                               k=0,
                               op_version=opv),
                   Linv,
                   op_version=opv)
    diag.set_onnx_name_prefix('diag')

    # root = P @ diag @ P.transpose()
    trv = OnnxTranspose(LP[1], op_version=opv)
    coef_left = OnnxMatMul(LP[1], diag, op_version=opv)
    coef_left.set_onnx_name_prefix('coef_left')
    coef = OnnxMatMul(coef_left, trv, op_version=opv)
    coef.set_onnx_name_prefix('coef')

    # Same part as before.
    Y = OnnxMatMul(X2, coef, op_version=opv, output_names=out[:1])
    Y.set_onnx_name_prefix('Y')
    Y.add_to(scope, container)