def _onnx_zero(target_opset=None, dtype=numpy.float32): """ Returns the ONNX graph for function :math:`Y = X * 0`. .. gdot:: :script: DOT-SECTION from mlprodict.onnxrt import OnnxInference from onnxcustom.utils.onnx_function import function_onnx_graph model_onnx = function_onnx_graph('zero') oinf = OnnxInference(model_onnx, inplace=False) print("DOT-SECTION", oinf.to_dot()) """ from skl2onnx.algebra.onnx_ops import OnnxMul res = OnnxMul('X', numpy.array([0], dtype=dtype), op_version=target_opset, output_names=['Y']) var_type = dtype_to_var_type(dtype) varsx = [('X', var_type())] onx = res.to_onnx(varsx, outputs=[('Y', var_type())], target_opset=target_opset) return onx
def test_grad_helper_mul(self): opv = opset xi = OnnxIdentity('X', op_version=opv) node = OnnxMul(xi, xi, op_version=opv, output_names=['Y']) onx = node.to_onnx({'X': FloatTensorType([None, 10])}, {'Y': FloatTensorType([None, 10])}, target_opset=opv) new_onx = onnx_derivative(onx) self.check_runtime(new_onx, 'test_grad_helper_mul')
def build_leaky_relu_decomposed_greater(alpha=0.5, target_opset=15): signo = OnnxGreater('X', numpy.array([0], dtype=numpy.float32), op_version=target_opset) sign = OnnxCast(signo, to=TensorProto.FLOAT, op_version=target_opset) fact = OnnxAdd(OnnxMul(sign, numpy.array([1 - alpha], dtype=numpy.float32), op_version=target_opset), numpy.array([alpha], dtype=numpy.float32), op_version=target_opset) x = OnnxMul('X', fact, op_version=target_opset, output_names=['Y']) return x.to_onnx({'X': FloatTensorType()}, outputs={'Y': FloatTensorType()}, target_opset=target_opset)
def test_onnxruntime_bug(self): rnd = numpy.random.randn(3, 20, 20).astype(numpy.float32) bni = (numpy.random.random((20, 20)).astype( # pylint: disable=E1101 numpy.float32) >= 0.7).astype(numpy.float32) mul = rnd * bni isn = any(numpy.isnan(mul.ravel())) self.assertFalse(isn) node = OnnxMul('X', bni, output_names=['Y4'], op_version=TARGET_OPSET) onx = node.to_onnx({'X': rnd}) for rt in ['python', 'onnxruntime1']: with self.subTest(runtime=rt): oinf = OnnxInference(onx, runtime=rt) y = oinf.run({'X': rnd})['Y4'] self.assertEqualArray(mul, y)
def build_leaky_relu_decomposed(alpha=0.5, target_opset=15): signo = OnnxSign('X', op_version=target_opset) sign = OnnxDiv(OnnxAdd(signo, numpy.array([1], dtype=numpy.float32), op_version=target_opset), numpy.array([2], dtype=numpy.float32), op_version=target_opset) fact = OnnxAdd(OnnxMul(sign, numpy.array([1 - alpha], dtype=numpy.float32), op_version=target_opset), numpy.array([alpha], dtype=numpy.float32), op_version=target_opset) x = OnnxMul('X', fact, op_version=target_opset, output_names=['Y']) return x.to_onnx({'X': FloatTensorType()}, outputs={'Y': FloatTensorType()}, target_opset=target_opset)
def _onnx_grad_square_error(target_opset=None, dtype=numpy.float32, weight_name=None): """ Returns the ONNX graph for the gradient of function :math:`Y = f(X1, X2) = \\lVert X1 - X2 \\rVert ^2` or :math:`Y = f(X1, X2) = \\lVert X1 - X2 \\rVert ^2 w` if *weight_name* is not None .. gdot:: :script: DOT-SECTION from mlprodict.onnxrt import OnnxInference from onnxcustom.utils.onnx_function import function_onnx_graph model_onnx = function_onnx_graph('grad_square_error') oinf = OnnxInference(model_onnx, inplace=False) print("DOT-SECTION", oinf.to_dot()) """ from skl2onnx.algebra.onnx_ops import OnnxSub, OnnxMul, OnnxReshape diff = OnnxSub('X1', 'X2', op_version=target_opset) if weight_name is None: res = OnnxMul(diff, numpy.array([-2], dtype=dtype), op_version=target_opset, output_names=['Y_grad']) else: res = OnnxMul(OnnxMul(diff, numpy.array([-2], dtype=dtype), op_version=target_opset), OnnxReshape(weight_name, numpy.array([-1, 1], dtype=numpy.int64), op_version=target_opset), op_version=target_opset, output_names=['Y_grad']) var_type = dtype_to_var_type(dtype) varsx = [('X1', var_type([None, None])), ('X2', var_type([None, None]))] if weight_name is not None: varsx.append((weight_name, var_type([None]))) onx = res.to_onnx(varsx, outputs=[('Y_grad', var_type())], target_opset=target_opset) if weight_name is not None: onx = add_initializer(onx, weight_name, numpy.array([1], dtype=dtype)) return onx
def build_ort_op(op_version=14, save=None, slices=None): # opset=13, 14, ... if slices is None: starts = numpy.array([1, 1], dtype=numpy.int64) ends = numpy.array([-1, -1], dtype=numpy.int64) axes = None else: starts, ends = slices if starts[0] is None: indexes = [i for i in range(len(starts)) if starts[i] is not None] starts = numpy.array([n for n in starts if n is not None], dtype=numpy.int64) ends = numpy.array([n for n in ends if n is not None], dtype=numpy.int64) axes = numpy.array(indexes, dtype=numpy.int64) else: starts = numpy.array(starts, dtype=numpy.int64) ends = numpy.array(ends, dtype=numpy.int64) axes = None if axes is None: node1 = OnnxSlice('X', starts, ends, op_version=op_version) else: node1 = OnnxSlice('X', starts, ends, axes, op_version=op_version) node2 = OnnxAdd(node1, numpy.array([1], dtype=numpy.float32), op_version=op_version) if axes is None: node3 = OnnxSlice(node2, starts, ends, op_version=op_version) else: node3 = OnnxSlice(node2, starts, ends, axes, op_version=op_version) node4 = OnnxMul(node3, numpy.array([2], dtype=numpy.float32), op_version=op_version, output_names=['Y']) onx = node4.to_onnx(inputs=[('X', FloatTensorType([None, None]))], target_opset=op_version) return onx
def get_onnx_mul(self): mul = OnnxMul('X', 'X', output_names=['Y']) onx = mul.to_onnx(inputs=[('X', FloatTensorType())]) return onx.SerializeToString()
def build_ort_op(op_version=14, save=None, **kwargs): # opset=13, 14, ... slices = kwargs['slices'] slice1, slice2 = slices slice1 = slice(0, None) if slice1 is None else slice(*slice1) slice2 = slice(0, None) if slice2 is None else slice(*slice2) axes = [] starts = [] ends = [] for i in [0, 1]: if slices[i] is None: continue axes.append(i) starts.append(slices[i][0]) ends.append(slices[i][1]) starts = numpy.array(starts, dtype=numpy.int64) ends = numpy.array(ends, dtype=numpy.int64) axes = numpy.array(axes, dtype=numpy.int64) node1 = OnnxSlice('X', starts, ends, axes, op_version=op_version) node2 = OnnxAdd(node1, numpy.array([1], dtype=numpy.float32), op_version=op_version) node3 = OnnxSlice(node2, starts, ends, axes, op_version=op_version) node4 = OnnxMul(node3, numpy.array([2], dtype=numpy.float32), op_version=op_version, output_names=['Y']) onx = node4.to_onnx(inputs=[('X', FloatTensorType([None, None]))], target_opset=op_version) sess = InferenceSession(onx.SerializeToString(), providers=["CPUExecutionProvider"]) if save is not None: with open(save, "wb") as f: f.write(onx.SerializeToString()) def npy_fct(x): return ((x[slice1, slice2] + 1)[slice1, slice2] * 2).copy() rnd = numpy.random.randn(10, 10).astype(numpy.float32) expected = npy_fct(rnd) got = sess.run(None, {'X': rnd})[0] try: assert_almost_equal(expected, got) except AssertionError as e: raise AssertionError("kwargs=%r slice1=%r slice2=%r shapes=%r ? %r " "(x[slice1, slice2].shape)=%r" % (kwargs, slice1, slice2, expected.shape, got.shape, rnd[slice1, slice2].shape)) from e if get_device().upper() == 'GPU': sessg = InferenceSession(onx.SerializeToString(), providers=["CUDAExecutionProvider"]) io_binding = sessg.io_binding()._iobinding device = get_ort_device('cuda:0') def run_gpu(x): io_binding.bind_input('X', device, numpy.float32, x.shape(), x.data_ptr()) io_binding.bind_output('Y', device) return sessg._sess.run_with_iobinding(io_binding, None) return onx, lambda x: sess.run(None, {'X': x}), npy_fct, run_gpu else: return onx, lambda x: sess.run(None, {'X': x}), npy_fct, None
def _onnx_grad_loss_square_error(target_opset=None, dtype=numpy.float32, weight_name=None, multiply=2): """ Returns the ONNX graph for function :math:`Y = f(X1, X2) = \\lVert (X1 - X2) \\rVert ^2` or :math:`Y = f(X1, X2) = \\lVert (\\sqrt{w}(X1 - X2) \\rVert ^2 w` if *weight_name* is not None and its gradient. .. gdot:: :script: DOT-SECTION from mlprodict.onnxrt import OnnxInference from onnxcustom.utils.onnx_function import function_onnx_graph model_onnx = function_onnx_graph('grad_loss_square_error') oinf = OnnxInference(model_onnx, inplace=False) print("DOT-SECTION", oinf.to_dot()) """ from skl2onnx.algebra.onnx_ops import (OnnxSub, OnnxReduceSumSquare, OnnxMul, OnnxReduceSum, OnnxReshape) diff = OnnxSub('X1', 'X2', op_version=target_opset) if weight_name is None: res = OnnxMul(OnnxReduceSumSquare(diff, op_version=target_opset), numpy.array([multiply * 0.5], dtype=numpy.float32), op_version=target_opset) res2 = OnnxMul(diff, numpy.array([-multiply], dtype=dtype), op_version=target_opset, output_names=['Y_grad']) else: resh = OnnxReshape(weight_name, numpy.array([-1, 1], dtype=numpy.int64), op_version=target_opset) mul = OnnxMul(OnnxMul(diff, diff, op_version=target_opset), resh, op_version=target_opset) res = OnnxMul(OnnxReduceSum(mul, op_version=target_opset), numpy.array([multiply * 0.5], dtype=numpy.float32), op_version=target_opset) res2 = OnnxMul(OnnxMul(diff, numpy.array([-multiply], dtype=dtype), op_version=target_opset), resh, op_version=target_opset, output_names=['Y_grad']) res = OnnxReshape(res, numpy.array([-1], numpy.int64), op_version=target_opset, output_names=['Y']) var_type = dtype_to_var_type(dtype) varsx = [('X1', var_type([None, None])), ('X2', var_type([None, None]))] if weight_name is not None: varsx.append((weight_name, var_type([None]))) onx = res.to_onnx(varsx, outputs=[('Y', var_type()), ('Y_grad', var_type())], target_opset=target_opset, other_outputs=[res2]) if weight_name is not None: onx = add_initializer(onx, weight_name, numpy.array([1], dtype=dtype)) return onx
def get_onnx_mul(self): mul = OnnxMul('X', 'X', output_names=[ 'Y'], op_version=get_opset_number_from_onnx()) onx = mul.to_onnx(inputs=[('X', FloatTensorType())]) return onx.SerializeToString()