def test_proto_type(self):
     dtypes = [
         (np.int32, Int32TensorType, onnx_proto.TensorProto.INT32),
         (np.int64, Int64TensorType, onnx_proto.TensorProto.INT64),
         (np.float32, FloatTensorType, onnx_proto.TensorProto.FLOAT),
         (np.float64, DoubleTensorType, onnx_proto.TensorProto.DOUBLE),
         (np.str_, StringTensorType, onnx_proto.TensorProto.STRING),
         (np.bool_, BooleanTensorType, onnx_proto.TensorProto.BOOL),
         (np.int8, Int8TensorType, onnx_proto.TensorProto.INT8),
         (np.uint8, UInt8TensorType, onnx_proto.TensorProto.UINT8)
     ]
     if Complex64TensorType is not None:
         dtypes.append((np.complex64, Complex64TensorType,
                        onnx_proto.TensorProto.COMPLEX64))
     if Complex128TensorType is not None:
         dtypes.append((np.complex128, Complex128TensorType,
                        onnx_proto.TensorProto.COMPLEX128))
     for dtype, exp, pt in dtypes:
         nt2 = guess_proto_type(exp([None, 1]))
         self.assertEqual(nt2, pt)
         nt1 = _guess_type_proto(pt, [None, 1])
         self.assertEqual(nt1.__class__, exp)
def decorrelate_transformer_converter(scope, operator, container):
    op = operator.raw_operator
    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.
    proto_dtype = guess_proto_type(X.type)

    mean_name = scope.get_unique_variable_name('mean')
    container.add_initializer(mean_name, proto_dtype, op.mean_.shape,
                              list(op.mean_.ravel()))

    coef_name = scope.get_unique_variable_name('coef')
    container.add_initializer(coef_name, proto_dtype, op.coef_.shape,
                              list(op.coef_.ravel()))

    op_name = scope.get_unique_operator_name('sub')
    sub_name = scope.get_unique_variable_name('sub')
    # This function is defined in package onnxconverter_common.
    # Most common operators can be added to the graph with
    # these functions. It handles the case when specifications
    # changed accross opsets (a parameter becomes an input
    # for example).
    apply_sub(scope, [X.full_name, mean_name],
              sub_name,
              container,
              operator_name=op_name)

    op_name = scope.get_unique_operator_name('matmul')
    container.add_node('MatMul', [sub_name, coef_name],
                       out[0].full_name,
                       name=op_name)
Beispiel #3
0
def converter_lightgbm_concat(scope, operator, container):
    """
    Converter for operator *LightGBMConcat*.
    """
    op = operator.raw_operator
    options = container.get_options(op, dict(cast=False))
    proto_dtype = guess_proto_type(operator.inputs[0].type)
    if proto_dtype != onnx_proto.TensorProto.DOUBLE:  # pylint: disable=E1101
        proto_dtype = onnx_proto.TensorProto.FLOAT  # pylint: disable=E1101
    if options['cast']:
        concat_name = scope.get_unique_variable_name('cast_lgbm')
        apply_cast(scope,
                   concat_name,
                   operator.outputs[0].full_name,
                   container,
                   operator_name=scope.get_unique_operator_name('cast_lgmb'),
                   to=proto_dtype)
    else:
        concat_name = operator.outputs[0].full_name

    apply_concat(scope, [_.full_name for _ in operator.inputs],
                 concat_name,
                 container,
                 axis=1)
Beispiel #4
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)
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)