From 2e80e003539ea2261e9ea1607cbb553a192ed2bb Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 25 Jul 2023 15:42:52 -0400 Subject: [PATCH 001/232] Add macos and windows shared libraries to `.gitignore` --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 9e024c07..7f19df11 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ __pycache__/ # C extensions *.so +*.dylib +*.dll +*.lib # Distribution / packaging .Python From b277cc9a34104b582227d797a936681794f17e1c Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 25 Jul 2023 16:08:11 -0400 Subject: [PATCH 002/232] Add skeleton and tests for ggml onnx backend --- ggml/contrib/__init__.py | 0 ggml/contrib/onnx.py | 6 ++ pyproject.toml | 2 + tests/test_onnx.py | 193 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 201 insertions(+) create mode 100644 ggml/contrib/__init__.py create mode 100644 ggml/contrib/onnx.py create mode 100644 tests/test_onnx.py diff --git a/ggml/contrib/__init__.py b/ggml/contrib/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py new file mode 100644 index 00000000..6ae3f90e --- /dev/null +++ b/ggml/contrib/onnx.py @@ -0,0 +1,6 @@ +import onnx +from onnx.backend.base import Backend + + +class GgmlRuntimeBackend(Backend): + pass diff --git a/pyproject.toml b/pyproject.toml index a0f8f8d0..a3fc310b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,8 @@ convert = [ "torchvision==0.15.2", "transformers==4.29.2" ] +onnx = ["onnx==1.14.0"] +onnx-dev = ["tabulate==0.9.0", "pytest-cov==4.1.0", "pytest-runner==6.0.0"] [project.urls] Homepage = "https://github.com/abetlen/ggml-python" diff --git a/tests/test_onnx.py b/tests/test_onnx.py new file mode 100644 index 00000000..d7d2179f --- /dev/null +++ b/tests/test_onnx.py @@ -0,0 +1,193 @@ +import os +import unittest + +import onnx.backend.test + +from ggml.contrib.onnx import GgmlRuntimeBackend as ggml_onnx + +# This is a pytest magic variable to load extra plugins +pytest_plugins = ("onnx.backend.test.report",) + +backend_test = onnx.backend.test.BackendTest(ggml_onnx, __name__) + +backend_test.exclude( + r"(test_hardsigmoid" # Does not support Hardsigmoid. + "|test_hardmax" # Does not support Hardmax. + "|test_.*FLOAT16.*" # Does not support Cast on Float16. + "|test_depthtospace.*" # Does not support DepthToSpace. + "|test_reduce_l1.*" # Does not support ReduceL1. + "|test_reduce_l2.*" # Does not support ReduceL2. + "|test_reduce_log_sum.*" # Does not support ReduceLogSum. + "|test_reduce_prod.*" # Does not support ReduceProd. + "|test_reduce_sum_square.*" # Does not support ReduceSumSquare + "|test_det.*" # Does not support Det + "|test_range.*" # Does not support Range + "|test_tile.*" # Tile's Caffe2 implementation needs some tweak + "|test_lstm.*" # Seems LSTM case has some problem + "|test_simple_rnn.*" # Seems simple RNN case has some problem + "|test_gru.*" # Seems GRU case has some problem + "|test_prelu.*" # PRelu is not compliant with ONNX yet + "|test_operator_repeat.*" # Tile is not compliant with ONNX yet + "|test_.*pool_.*same.*" # Does not support pool same. + "|test_.*pool_.*ceil.*" # Does not support pool same. + "|test_maxpool_with_argmax.*" # MaxPool outputs indices in different format. + "|test_maxpool.*dilation.*" # MaxPool doesn't support dilation yet. + "|test_maxpool.*uint8.*" # MaxPool doesn't support uint8 yet. + "|test_convtranspose.*" # ConvTranspose needs some more complicated translation + "|test_mvn.*" # MeanVarianceNormalization is experimental and not supported. + "|test_dynamic_slice.*" # MeanVarianceNormalization is experimental and not supported. + "|test_eyelike.*" # Needs implementation + "|test_maxunpool.*" # Needs implementation + "|test_acosh.*" # Needs implementation + "|test_asinh.*" # Needs implementation + "|test_atanh.*" # Needs implementation + "|test_onehot.*" # Needs implementation + "|test_scan.*" # Needs implementation + "|test_isnan.*" # Needs implementation + "|test_scatter.*" # Should be similar to ScatterAssign + "|test_constantofshape_int.*" # Needs implementation + "|test_shrink.*" # Needs implementation + "|test_strnorm.*" # Needs implementation + "|test_nonzero.*" # Needs implementation + "|test_tfidfvectorizer.*" # Needs implementation + "|test_top_k.*" # opset 10 is not supported yet + "|test_resize.*" # opset 10 is not supported yet + "|test_slice.*" # opset 10 is not supported yet + "|test_.*qlinear.*" # Skip quantized op test + "|test_.*quantize.*" # Skip quantized op test + "|test_.*matmulinteger.*" # Skip quantized op test + "|test_.*convinteger.*" # Skip quantized op test + "|test_isinf.*" # Needs implementation + "|test_mod.*" # Needs implementation + "|test_nonmaxsuppression.*" # Needs implementation + "|test_reversesequence.*" # Needs implementation + "|test_roialign.*" # Needs implementation + "|test_bitshift.*" # Needs implementation + "|test_round.*" # Needs implementation + "|test_cumsum.*" # Needs implementation + "|test_clip.*" # opset 11 is not supported yet + "|test_gather_elements.*" # opset 11 is not supported yet + "|test_scatter.*" # opset 11 is not supported yet + "|test_unique.*" # opset 11 is not supported yet + "|test_gathernd.*" # opset 11 is not supported yet + "|test_dropout_random.*" # opset 12 is not supported + "|test_dropout_default.*" # opset 12 is not supported + "|test_einsum.*" # opset 12 is not supported + "|test_.*training.*" # training is not supported + "|test_.*_loss.*" # training is not supported + "|test_split_zero_size.*" # unsupported case + "|test_constantofshape_int_shape_zero.*" # unsupported case + "|test_constant_pad.*" # 1d pad is not supported + "|test_edge_pad.*" # 1d pad is not supported + "|test_reflect_pad.*" # 1d pad is not supported + "|test_gemm_default_no_bias.*" # no bias is not supported + "|test_gemm_default_scalar_bias.*" # incorrect type + "|test_sequence_.*" # type sequence is not supported yet + "|test_.*negative_ax.*" # negative axis is not supported yet + "|test_.*negative_ind.*" # negative axis is not supported yet + "|test_argmax_.*select_last_index.*" # unsupported case + "|test_argmin_.*select_last_index_.*" # unsupported case + "|test_celu.*" # unsupported case + "|test_gathernd.*" # unsupported case + "|test_greater_equal.*" # unsupported case + "|test_less_equal.*" # unsupported case + "|test_max_.*" # unsupported case + "|test_min_.*" # unsupported case + "|test_.*momentum_.*" # unsupported case + "|test_sce.*" # unsupported case + "|test_nllloss.*" # unsupported case + "|test_unfoldtodepth.*" # unsupported case + "|test_.*gradient.*" # no support for gradient op in c2-onnx + "|test_.*adagrad.*" # no support for gradient op in c2-onnx + "|test_.*loss.*" # no support for loss op in c2-onnx + "|test_.*adam.*" # no support for adam op + "|test_.*identity.*" # no support for adam op + ")" +) + +# Quick patch to unbreak master CI, is working on the debugging. +backend_test.exclude( + "(test_cast_.*" + "|test_compress_.*" + "|test_Conv1d_.*cuda" + "|test_Conv3d_groups_cuda" + "|test_rnn_seq_length" + "|test_operator_add.*_cuda" + "|test_operator_lstm_cuda" + "|test_operator_rnn.*_cuda" + "|test_lrn_default_cuda)" +) + +# Temporarily skip some ONNX backend tests with broadcasting. +backend_test.exclude("(test_pow_bcast" "|test_pow_types.*" ")") + +# Temporarily skip some ONNX backend tests due to updates in opset 13. +backend_test.exclude( + "(test_if_.*" # added support for sequence type inputs + "|test_if_seq_.*" # added support for sequence type inputs + "|test_logsoftmax_.*" # axis attr default value changed from 1 to -1 + "|test_loop11_.*" # seg fault issue + "|test_loop16_.*" # seg fault issue + "|test_loop13_seq_.*" # no support for sequence inputs for scan input + "|test_reduce_sum_.*" # axes is now an input (not attr), added noop_with_empty_axes + "|test_softmax_.*" # axis attr default value changed from 1 to -1 + "|test_split_variable_parts_.*" # axes is now an input (not attr) + "|test_squeeze_.*" # axes is now an input (not attr) + "|test_unsqueeze_.*" # axes is now an input (not attr) + "|test_MaxPool1d_stride_padding_dilation_.*" + "|test_MaxPool2d_stride_padding_dilation_.*" + ")" +) + +# Temporarily skip some ONNX backend tests due to updates in opset 14. +backend_test.exclude( + "(test_add_uint8_.*" # uint8 dtype added + "|test_div_uint8_.*" # uint8 dtype added + "|test_hardswish_.*" # new operator added + "|test_mul_uint8_.*" # uint8 dtype added + "|test_sub_uint8_.*" # uint8 dtype added + "|test_tril_.*" # new operator added + "|test_triu_.*" # new operator added + "|test_identity_sequence_.*" # new operator added + "|test_reshape_allowzero_reordered_.*" + "|test_conv_with_autopad_same_.*" + ")" +) + +# Unsupported ops in opset 15 +backend_test.exclude( + "(test_bernoulli_.*" + "|test_castlike_.*" + "|test_optional_.*" + "|test_shape_end_.*" + "|test_shape_start_.*" + "|test_identity_opt_*" + "|test_loop16_seq_none_*" + "|test_if_opt_*" + ")" +) + +# Unsupported ops in opset 16 +backend_test.exclude("(test_gridsample_.*" "|test_spacetodepth_.*" ")") + +# Unsupported ops in opset 17 +backend_test.exclude( + "(test_layer_normalization_.*" + "|test_blackmanwindow_.*" + "|test_dft_.*" + "|test_hammingwindow_.*" + "|test_hannwindow_.*" + "|test_melweightmatrix_.*" + "|test_stft_.*" + "|test_sequencemap_.*" + ")" +) + +# Unsupported ops in opset 18 +backend_test.exclude("(test_center_crop_pad_.*" "|test_col2im*" "|test_bitwise*)") + +# import all test cases at global scope to make them visible to python.unittest +globals().update(backend_test.enable_report().test_cases) + +if __name__ == "__main__": + unittest.main() From b2803fb18e542a014e333ffb20e3c809e4cfe0d1 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 25 Jul 2023 16:17:02 -0400 Subject: [PATCH 003/232] Add ggml onnx runtime method skeletons --- ggml/contrib/onnx.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 6ae3f90e..dc0bfab9 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3,4 +3,33 @@ class GgmlRuntimeBackend(Backend): - pass + @classmethod + def prepare(cls, model, device=None, **kwargs): + pass + + @classmethod + def run_model(cls, model, inputs, device=None, **kwargs): + """ + Compute the prediction. + + :param model: :class:`onnxruntime.InferenceSession` returned + by function *prepare* + :param inputs: inputs + :param device: requested device for the computation, + None means the default one which depends on + the compilation settings + :param kwargs: see :class:`onnxruntime.RunOptions` + :return: predictions + """ + rep = cls.prepare(model, device, **kwargs) + return rep.run(inputs, **kwargs) + + @classmethod + def run_node(cls, node, inputs, device=None, outputs_info=None, **kwargs): + """ + This method is not implemented as it is much more efficient + to run a whole model than every node independently. + """ + raise NotImplementedError( + "It is much more efficient to run a whole model than every node independently." + ) From 482c1113730c9d727a1aeeaeab015061b38a2373 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 26 Jul 2023 16:46:49 -0400 Subject: [PATCH 004/232] Add GgmlBackendRep to load model graph and weights --- ggml/contrib/onnx.py | 118 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 4 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index dc0bfab9..d6fc9ee3 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1,11 +1,121 @@ -import onnx -from onnx.backend.base import Backend +from typing import Any, Tuple + +from onnx import defs +from onnx.backend.base import Backend, BackendRep +from onnx.helper import make_opsetid +from onnx.onnx_ml_pb2 import GraphProto + + +class GgmlBackendRep(BackendRep): + def __init__(self, graph=None, inputs=None, outputs=None, tensor_dict=None): + super(GgmlRuntimeBackend, self).__init__() + self._graph = graph + self._inputs = inputs or {} + self._outputs = outputs or {} + self._tensor_dict = tensor_dict or {} + + @property + def graph(self): + return self._graph + + @graph.setter + def graph(self, graph): + self._graph = graph + + @property + def inputs(self): + return self._inputs + + @inputs.setter + def inputs(self, inputs): + self._inputs = inputs + + @property + def outputs(self): + return self._outputs + + @outputs.setter + def outputs(self, outputs): + self._outputs = outputs + + @property + def tensor_dict(self): + return self._tensor_dict + + @tensor_dict.setter + def tensor_dict(self, tensor_dict): + self._tensor_dict = tensor_dict + + def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: + """Abstract function.""" + + # check where data is should be on CPU + return (None,) class GgmlRuntimeBackend(Backend): @classmethod - def prepare(cls, model, device=None, **kwargs): - pass + def is_opset_supported(cls, model): # pylint: disable=unused-argument + return True, "" + + @classmethod + def prepare(cls, model, device="CPU", **kwargs): + """ + Load the model and creates a :class:`onnxruntime.InferenceSession` + ready to be used as a backend. + + :param model: ModelProto (returned by `onnx.load`), + string for a filename or bytes for a serialized model + :param device: requested device for the computation, + None means the default one which depends on + the compilation settings + :param kwargs: see :class:`onnxruntime.SessionOptions` + :return: :class:`onnxruntime.InferenceSession` + """ + + super(GgmlRuntimeBackend, cls).prepare(model, device, **kwargs) + ggml_rep = cls.onnx_model_to_ggml_rep(model, **kwargs) + + return ggml_rep + + @classmethod + def onnx_model_to_ggml_rep(cls, model, **kwargs): + """Convert ONNX model to GgmlRep. + + :param model: ONNX ModelProto object. + and the converted tensorflow model. + :return: GgmlRep object. + """ + + # Models with IR_VERSION less than 3 does not have opset_import set. + # We default to minimum opset, this behavior is consistent with + # onnx checker. + # c.f. https://github.com/onnx/onnx/blob/427ac0c1b792363d373e3d7e4eef97fa46458420/onnx/checker.cc#L478 + if model.ir_version < 3: + opset_import = [make_opsetid(defs.ONNX_DOMAIN, 1)] + else: + opset_import = model.opset_import + + return cls._onnx_graph_to_ggml_rep(model.graph, opset_import, **kwargs) + + @classmethod + def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): + inputs = {} + outputs = {} + weights = {} + + for node in graph_def.node: + inputs[node.name] = list(node.input) + outputs[node.name] = list(node.output) + + for initializer in graph_def.initializer: + weights[initializer.name] = initializer.raw_data + + # ggml_rep -> GgmlBackendRep() -> return + + return GgmlBackendRep( + graph_def, inputs=inputs, outputs=outputs, tensor_dict=weights + ) @classmethod def run_model(cls, model, inputs, device=None, **kwargs): From a8dc94abbbee11e7b9595959189c610004979aa7 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 26 Jul 2023 16:50:38 -0400 Subject: [PATCH 005/232] Remove unwanted comment --- ggml/contrib/onnx.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index d6fc9ee3..827f5194 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -111,8 +111,6 @@ def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): for initializer in graph_def.initializer: weights[initializer.name] = initializer.raw_data - # ggml_rep -> GgmlBackendRep() -> return - return GgmlBackendRep( graph_def, inputs=inputs, outputs=outputs, tensor_dict=weights ) From cab37c20515d558bdef3905f48520071a2190df4 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 27 Jul 2023 13:58:35 -0400 Subject: [PATCH 006/232] Load weights into ggml tensors --- ggml/contrib/onnx.py | 70 +++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 827f5194..107de0d7 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1,18 +1,23 @@ +import ctypes from typing import Any, Tuple +import onnx from onnx import defs from onnx.backend.base import Backend, BackendRep from onnx.helper import make_opsetid -from onnx.onnx_ml_pb2 import GraphProto +from onnx.onnx_ml_pb2 import GraphProto, ModelProto + +import ggml +import ggml.utils class GgmlBackendRep(BackendRep): - def __init__(self, graph=None, inputs=None, outputs=None, tensor_dict=None): - super(GgmlRuntimeBackend, self).__init__() + def __init__(self, graph=None, inputs=None, outputs=None, weights=None): + super(GgmlBackendRep, self).__init__() self._graph = graph - self._inputs = inputs or {} - self._outputs = outputs or {} - self._tensor_dict = tensor_dict or {} + self._inputs = inputs or [] + self._outputs = outputs or [] + self._weights = weights or {} @property def graph(self): @@ -39,12 +44,12 @@ def outputs(self, outputs): self._outputs = outputs @property - def tensor_dict(self): - return self._tensor_dict + def weights(self): + return self._weights - @tensor_dict.setter - def tensor_dict(self, tensor_dict): - self._tensor_dict = tensor_dict + @weights.setter + def weights(self, weights): + self._weights = weights def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: """Abstract function.""" @@ -59,7 +64,7 @@ def is_opset_supported(cls, model): # pylint: disable=unused-argument return True, "" @classmethod - def prepare(cls, model, device="CPU", **kwargs): + def prepare(cls, model: ModelProto, device="CPU", **kwargs): """ Load the model and creates a :class:`onnxruntime.InferenceSession` ready to be used as a backend. @@ -79,7 +84,7 @@ def prepare(cls, model, device="CPU", **kwargs): return ggml_rep @classmethod - def onnx_model_to_ggml_rep(cls, model, **kwargs): + def onnx_model_to_ggml_rep(cls, model: ModelProto, **kwargs): """Convert ONNX model to GgmlRep. :param model: ONNX ModelProto object. @@ -100,19 +105,44 @@ def onnx_model_to_ggml_rep(cls, model, **kwargs): @classmethod def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): - inputs = {} - outputs = {} weights = {} - for node in graph_def.node: - inputs[node.name] = list(node.input) - outputs[node.name] = list(node.output) + n_tensors = len(graph_def.initializer) + init_params = ggml.ggml_init_params( + mem_size=n_tensors * ggml.ggml_tensor_overhead(), + no_alloc=True, + ) + + context = ggml.ggml_init(init_params) + total_nbytes = 0 + + pairs = [] for initializer in graph_def.initializer: - weights[initializer.name] = initializer.raw_data + name = initializer.name + np_array = onnx.numpy_helper.to_array(initializer) + tensor = ggml.utils.from_numpy(x=np_array, ctx=context) + ggml.ggml_set_name(tensor=tensor, name=name.encode()) + total_nbytes += ggml.ggml_nbytes(tensor) + weights[name] = tensor + pairs.append((tensor, initializer)) + + buffer = (ctypes.c_uint8 * total_nbytes)() + offset = 0 + + for tensor, initializer in pairs: + nbytes = ggml.ggml_nbytes(tensor) + tensor.contents.data = ctypes.cast( + ctypes.addressof(buffer) + offset, ctypes.c_void_p + ) + ggml.utils.to_numpy(tensor)[:] = onnx.numpy_helper.to_array(initializer) + offset += nbytes return GgmlBackendRep( - graph_def, inputs=inputs, outputs=outputs, tensor_dict=weights + graph_def, + inputs=graph_def.input, + outputs=graph_def.output, + weights=weights, ) @classmethod From 2804f5d69f65cae6cc6acc4528e50b6b25b4de1e Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 27 Jul 2023 16:44:22 -0400 Subject: [PATCH 007/232] Add simple onnx expression test --- ggml/contrib/onnx.py | 48 ++++++++++++++++++++++++++++++++++-- tests/test_ggml_onnx.py | 54 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 tests/test_ggml_onnx.py diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 107de0d7..0da1cc77 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -12,7 +12,9 @@ class GgmlBackendRep(BackendRep): - def __init__(self, graph=None, inputs=None, outputs=None, weights=None): + def __init__( + self, graph: GraphProto = None, inputs=None, outputs=None, weights=None + ): super(GgmlBackendRep, self).__init__() self._graph = graph self._inputs = inputs or [] @@ -55,7 +57,49 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: """Abstract function.""" # check where data is should be on CPU - return (None,) + + model_graph = self._graph + exit_node = None + ggml_tensors = {} + + tensor_types = {1: ggml.ggml_new_tensor_1d, 2: ggml.ggml_new_tensor_2d} + operation_types = {"Mul": ggml.ggml_mul, "Add": ggml.ggml_add} + + # Define context + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + ctx = ggml.ggml_init(params=params) + + # Create entry inputs + for model_input in model_graph.input: + inp = ggml.ggml_new_tensor_1d( + ctx, + ggml.GGML_TYPE_F32, + 1, + ) + ggml_tensors[model_input.name] = inp + + # Build layers + for node in model_graph.node: + node_inputs = [ggml_tensors[inp] for inp in node.input] + layer = operation_types[node.op_type]( + ctx, + *node_inputs, + ) + ggml_tensors[node.output[0]] = layer + if node.output[-1] == self._graph.output[-1].name: + exit_node = layer + + # Build graph + gf = ggml.ggml_build_forward(exit_node) + + # Set user inputs + for key, value in inputs.items(): + ggml.ggml_set_f32(ggml_tensors[key], value) + + # Compute graph + ggml.ggml_graph_compute_with_ctx(ctx, ctypes.pointer(gf), 1) + + return ggml.ggml_get_f32_1d(exit_node, 0) class GgmlRuntimeBackend(Backend): diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py new file mode 100644 index 00000000..edbc2afa --- /dev/null +++ b/tests/test_ggml_onnx.py @@ -0,0 +1,54 @@ +import onnx +from ggml.contrib.onnx import GgmlRuntimeBackend +import numpy as np +import onnx +import numpy as np +from onnx import helper + + +def test_onnx_run(): + x = helper.make_tensor_value_info("x", onnx.TensorProto.FLOAT, [1]) + a = helper.make_tensor_value_info("a", onnx.TensorProto.FLOAT, [1]) + x_constant = helper.make_tensor_value_info( + "x_constant", onnx.TensorProto.FLOAT, [1] + ) + b_constant = helper.make_tensor_value_info( + "b_constant", onnx.TensorProto.FLOAT, [1] + ) + + f_output = helper.make_tensor_value_info("f", onnx.TensorProto.FLOAT, [1]) + + square_node = helper.make_node("Mul", ["x", "x"], ["squared"], name="square_node") + first_mul_node = helper.make_node( + "Mul", ["squared", "a"], ["first_mul"], name="first_mul_node" + ) + second_mul_node = helper.make_node( + "Add", ["first_mul", "b_constant"], ["f"], name="second_mul_node" + ) + + graph_def = helper.make_graph( + [square_node, first_mul_node, second_mul_node], + "expression_graph", + [x, a, x_constant, b_constant], + [f_output], + ) + + onnx_model = helper.make_model(graph_def, producer_name="ONNX_expression_model") + + output = GgmlRuntimeBackend.prepare(onnx_model) + + x_val = np.array([2.0], dtype=np.float32) + a_val = np.array([3.0], dtype=np.float32) + x_constant_val = np.array([1.0], dtype=np.float32) + b_constant_val = np.array([4.0], dtype=np.float32) + + input_data = { + "x": x_val, + "a": a_val, + "x_constant": x_constant_val, + "b_constant": b_constant_val, + } + + print() + print() + print(output.run(input_data)) From a92db90b1cce9b079058735c42a4f681257aba80 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 28 Jul 2023 16:19:51 -0400 Subject: [PATCH 008/232] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 46a8b773..d0ef75fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ convert = [ "transformers==4.29.2" ] onnx = ["onnx==1.14.0"] -onnx-dev = ["tabulate==0.9.0", "pytest-cov==4.1.0", "pytest-runner==6.0.0"] +onnx-tests = ["tabulate==0.9.0", "pytest-cov==4.1.0", "pytest-runner==6.0.0", "onnxruntime==1.15.1"] [project.urls] Homepage = "https://github.com/abetlen/ggml-python" From 9bf022ba5a191adb400cce0a85936f5e0103ff90 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 28 Jul 2023 16:20:10 -0400 Subject: [PATCH 009/232] Fix garbage collection and load weights --- ggml/contrib/onnx.py | 70 +++++++++------------------- tests/test_ggml_onnx.py | 101 ++++++++++++++++++++++++++-------------- 2 files changed, 87 insertions(+), 84 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 0da1cc77..4d1666d8 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -12,55 +12,21 @@ class GgmlBackendRep(BackendRep): - def __init__( - self, graph: GraphProto = None, inputs=None, outputs=None, weights=None - ): + def __init__(self): super(GgmlBackendRep, self).__init__() - self._graph = graph - self._inputs = inputs or [] - self._outputs = outputs or [] - self._weights = weights or {} - @property - def graph(self): - return self._graph - - @graph.setter - def graph(self, graph): - self._graph = graph - - @property - def inputs(self): - return self._inputs - - @inputs.setter - def inputs(self, inputs): - self._inputs = inputs - - @property - def outputs(self): - return self._outputs - - @outputs.setter - def outputs(self, outputs): - self._outputs = outputs - - @property - def weights(self): - return self._weights - - @weights.setter - def weights(self, weights): - self._weights = weights + def __del__(self): + if hasattr(self, "ggml_context"): + ggml.ggml_free(self.ggml_context) def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: """Abstract function.""" # check where data is should be on CPU - model_graph = self._graph + model_graph = self.graph exit_node = None - ggml_tensors = {} + ggml_tensors = self.weights tensor_types = {1: ggml.ggml_new_tensor_1d, 2: ggml.ggml_new_tensor_2d} operation_types = {"Mul": ggml.ggml_mul, "Add": ggml.ggml_add} @@ -86,7 +52,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: *node_inputs, ) ggml_tensors[node.output[0]] = layer - if node.output[-1] == self._graph.output[-1].name: + if node.output[-1] == self.graph.output[-1].name: exit_node = layer # Build graph @@ -99,7 +65,9 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Compute graph ggml.ggml_graph_compute_with_ctx(ctx, ctypes.pointer(gf), 1) - return ggml.ggml_get_f32_1d(exit_node, 0) + output = ggml.utils.to_numpy(exit_node) + + return [output] class GgmlRuntimeBackend(Backend): @@ -149,6 +117,9 @@ def onnx_model_to_ggml_rep(cls, model: ModelProto, **kwargs): @classmethod def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): + ggml_backend_rep = GgmlBackendRep() + ggml_backend_rep.graph = graph_def + weights = {} n_tensors = len(graph_def.initializer) @@ -158,6 +129,8 @@ def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): ) context = ggml.ggml_init(init_params) + ggml_backend_rep.ggml_context = context + ggml_backend_rep.ggml_init_params = init_params total_nbytes = 0 pairs = [] @@ -166,6 +139,7 @@ def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): name = initializer.name np_array = onnx.numpy_helper.to_array(initializer) tensor = ggml.utils.from_numpy(x=np_array, ctx=context) + ggml.ggml_set_name(tensor=tensor, name=name.encode()) total_nbytes += ggml.ggml_nbytes(tensor) weights[name] = tensor @@ -182,12 +156,12 @@ def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): ggml.utils.to_numpy(tensor)[:] = onnx.numpy_helper.to_array(initializer) offset += nbytes - return GgmlBackendRep( - graph_def, - inputs=graph_def.input, - outputs=graph_def.output, - weights=weights, - ) + ggml_backend_rep.ggml_buffer = buffer + ggml_backend_rep.weights = weights + ggml_backend_rep.inputs = graph_def.input + ggml_backend_rep.outputs = graph_def.output + + return ggml_backend_rep @classmethod def run_model(cls, model, inputs, device=None, **kwargs): diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index edbc2afa..7ce14ecd 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -1,54 +1,83 @@ -import onnx -from ggml.contrib.onnx import GgmlRuntimeBackend +import io + import numpy as np import onnx -import numpy as np -from onnx import helper +from onnx import TensorProto, helper +from onnxruntime import InferenceSession + +from ggml.contrib.onnx import GgmlRuntimeBackend -def test_onnx_run(): - x = helper.make_tensor_value_info("x", onnx.TensorProto.FLOAT, [1]) - a = helper.make_tensor_value_info("a", onnx.TensorProto.FLOAT, [1]) - x_constant = helper.make_tensor_value_info( - "x_constant", onnx.TensorProto.FLOAT, [1] +def test_ggml_onnx_runtime_basic(): + # The name of the input tensor + input_name = "X" + + # The name of the weights tensor + weight_name_a = "A" + weight_name_b = "B" + + # The name of the output + output_name = "Y" + + # Create the nodes (operations) in our graph + node1 = helper.make_node( + "Mul", [input_name, input_name], ["X_squared"], name="node1" + ) # X^2 + node2 = helper.make_node( + "Mul", ["X_squared", weight_name_a], ["X_squared_times_a"], name="node2" + ) # X^2 * A + node3 = helper.make_node( + "Add", ["X_squared_times_a", weight_name_b], [output_name], name="node3" + ) # X^2 * A + B + + # Define the tensors (values) in our graph + X_value_info = helper.make_tensor_value_info( + input_name, TensorProto.FLOAT, [None, 1] ) - b_constant = helper.make_tensor_value_info( - "b_constant", onnx.TensorProto.FLOAT, [1] + + output_value_info = helper.make_tensor_value_info( + output_name, TensorProto.FLOAT, [None, 1] ) - f_output = helper.make_tensor_value_info("f", onnx.TensorProto.FLOAT, [1]) + # Set A and B as parameters/weights + weights_a = np.ones(1, dtype=float).astype(np.float32) + weights_b = np.ones(1, dtype=float).astype(np.float32) - square_node = helper.make_node("Mul", ["x", "x"], ["squared"], name="square_node") - first_mul_node = helper.make_node( - "Mul", ["squared", "a"], ["first_mul"], name="first_mul_node" + A_init = helper.make_tensor( + weight_name_a, + TensorProto.FLOAT, + [ + 1, + ], + weights_a, ) - second_mul_node = helper.make_node( - "Add", ["first_mul", "b_constant"], ["f"], name="second_mul_node" + B_init = helper.make_tensor( + weight_name_b, + TensorProto.FLOAT, + [ + 1, + ], + weights_b, ) + # Create the graph (model). graph_def = helper.make_graph( - [square_node, first_mul_node, second_mul_node], - "expression_graph", - [x, a, x_constant, b_constant], - [f_output], + [node1, node2, node3], + "simple_expression_model", + [X_value_info], + [output_value_info], + [A_init, B_init], ) - onnx_model = helper.make_model(graph_def, producer_name="ONNX_expression_model") + model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") - output = GgmlRuntimeBackend.prepare(onnx_model) + input_data = {"X": np.array([[6.0]], dtype=np.float32)} - x_val = np.array([2.0], dtype=np.float32) - a_val = np.array([3.0], dtype=np.float32) - x_constant_val = np.array([1.0], dtype=np.float32) - b_constant_val = np.array([4.0], dtype=np.float32) + f = io.BytesIO() + onnx.save(model_def, f) - input_data = { - "x": x_val, - "a": a_val, - "x_constant": x_constant_val, - "b_constant": b_constant_val, - } + runtime_result = InferenceSession(f.getvalue()).run(None, input_data) - print() - print() - print(output.run(input_data)) + ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) + ggml_result = ggml_dummy_model.run(input_data) + assert ggml_result == runtime_result From 75d4b1e8f8d258d17183c6da9e6a7e4f44dc1de7 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 28 Jul 2023 16:39:43 -0400 Subject: [PATCH 010/232] Add instructor example notebook --- examples/instructor/.gitignore | 1 + examples/instructor/example.ipynb | 175 ++ examples/instructor/poetry.lock | 4292 ++++++++++++++++++++++++++++ examples/instructor/pyproject.toml | 29 + tests/test_ggml_onnx.py | 4 + 5 files changed, 4501 insertions(+) create mode 100644 examples/instructor/.gitignore create mode 100644 examples/instructor/example.ipynb create mode 100644 examples/instructor/poetry.lock create mode 100644 examples/instructor/pyproject.toml diff --git a/examples/instructor/.gitignore b/examples/instructor/.gitignore new file mode 100644 index 00000000..4a19405e --- /dev/null +++ b/examples/instructor/.gitignore @@ -0,0 +1 @@ +instructor_base_onnx/ \ No newline at end of file diff --git a/examples/instructor/example.ipynb b/examples/instructor/example.ipynb new file mode 100644 index 00000000..cad8518d --- /dev/null +++ b/examples/instructor/example.ipynb @@ -0,0 +1,175 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using OnnxRuntime with instructor-base\n", + "- Run `optimum-cli export onnx --model hkunlp/instructor-base instructor_base_onnx/`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load onnx model" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from onnxruntime import InferenceSession\n", + "import numpy as np\n", + "\n", + "\n", + "# only need encoder\n", + "instructor_encoder_sess = InferenceSession('./instructor_base_onnx/encoder_model.onnx')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load Instructor model" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/mrezanvari/_MyFiles/Programs/Patagona-technologies/ggml-python/examples/instructor/.venv/lib/python3.8/site-packages/InstructorEmbedding/instructor.py:7: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)\n", + " from tqdm.autonotebook import trange\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "load INSTRUCTOR_Transformer\n", + "max_seq_length 512\n", + "load INSTRUCTOR_Transformer\n", + "max_seq_length 512\n" + ] + } + ], + "source": [ + "from InstructorEmbedding import INSTRUCTOR\n", + "\n", + "# OG model\n", + "instructor_model = INSTRUCTOR('hkunlp/instructor-base')\n", + "\n", + "# onnx test model\n", + "instructor_onnx = INSTRUCTOR('hkunlp/instructor-base')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Custom onnx model" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import torch.nn as nn\n", + "\n", + "class OnnxModule(nn.Module):\n", + " def __init__(self, inference_session):\n", + " super().__init__()\n", + " self._inference_session = inference_session\n", + " \n", + " def forward(self, *args, **kwargs):\n", + "\n", + " kwargs = {'input_ids': np.array(kwargs['input_ids']), 'attention_mask': np.array(kwargs['attention_mask'])}\n", + " return self._inference_session.run(None, kwargs)\n", + "\n", + "\n", + "# replace transfromer model forward call with custom onnx model\n", + "\n", + "for i in instructor_onnx.modules():\n", + " if i._get_name() == 'INSTRUCTOR_Transformer':\n", + " i.auto_model.__call__ = OnnxModule(instructor_encoder_sess).forward\n", + " \n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Compare embeddings" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "sentence = \"This is a sentence to test instructor embedding model\"\n", + "instruction = \"\"\n", + "\n", + "\n", + "real_embeddings = instructor_model.encode([[instruction, sentence]])\n", + "onnx_embeddings = instructor_onnx.encode([[instruction, sentence]])" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[1.]], dtype=float32)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from sklearn.metrics.pairwise import cosine_similarity\n", + "\n", + "\n", + "cosine_similarity(onnx_embeddings, real_embeddings)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/instructor/poetry.lock b/examples/instructor/poetry.lock new file mode 100644 index 00000000..b0caf768 --- /dev/null +++ b/examples/instructor/poetry.lock @@ -0,0 +1,4292 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + +[[package]] +name = "aiohttp" +version = "3.8.5" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "aiohttp-3.8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a94159871304770da4dd371f4291b20cac04e8c94f11bdea1c3478e557fbe0d8"}, + {file = "aiohttp-3.8.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:13bf85afc99ce6f9ee3567b04501f18f9f8dbbb2ea11ed1a2e079670403a7c84"}, + {file = "aiohttp-3.8.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ce2ac5708501afc4847221a521f7e4b245abf5178cf5ddae9d5b3856ddb2f3a"}, + {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96943e5dcc37a6529d18766597c491798b7eb7a61d48878611298afc1fca946c"}, + {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ad5c3c4590bb3cc28b4382f031f3783f25ec223557124c68754a2231d989e2b"}, + {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c413c633d0512df4dc7fd2373ec06cc6a815b7b6d6c2f208ada7e9e93a5061d"}, + {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df72ac063b97837a80d80dec8d54c241af059cc9bb42c4de68bd5b61ceb37caa"}, + {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c48c5c0271149cfe467c0ff8eb941279fd6e3f65c9a388c984e0e6cf57538e14"}, + {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:368a42363c4d70ab52c2c6420a57f190ed3dfaca6a1b19afda8165ee16416a82"}, + {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7607ec3ce4993464368505888af5beb446845a014bc676d349efec0e05085905"}, + {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0d21c684808288a98914e5aaf2a7c6a3179d4df11d249799c32d1808e79503b5"}, + {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:312fcfbacc7880a8da0ae8b6abc6cc7d752e9caa0051a53d217a650b25e9a691"}, + {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad093e823df03bb3fd37e7dec9d4670c34f9e24aeace76808fc20a507cace825"}, + {file = "aiohttp-3.8.5-cp310-cp310-win32.whl", hash = "sha256:33279701c04351a2914e1100b62b2a7fdb9a25995c4a104259f9a5ead7ed4802"}, + {file = "aiohttp-3.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:6e4a280e4b975a2e7745573e3fc9c9ba0d1194a3738ce1cbaa80626cc9b4f4df"}, + {file = "aiohttp-3.8.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae871a964e1987a943d83d6709d20ec6103ca1eaf52f7e0d36ee1b5bebb8b9b9"}, + {file = "aiohttp-3.8.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:461908b2578955045efde733719d62f2b649c404189a09a632d245b445c9c975"}, + {file = "aiohttp-3.8.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:72a860c215e26192379f57cae5ab12b168b75db8271f111019509a1196dfc780"}, + {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc14be025665dba6202b6a71cfcdb53210cc498e50068bc088076624471f8bb9"}, + {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8af740fc2711ad85f1a5c034a435782fbd5b5f8314c9a3ef071424a8158d7f6b"}, + {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:841cd8233cbd2111a0ef0a522ce016357c5e3aff8a8ce92bcfa14cef890d698f"}, + {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed1c46fb119f1b59304b5ec89f834f07124cd23ae5b74288e364477641060ff"}, + {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84f8ae3e09a34f35c18fa57f015cc394bd1389bce02503fb30c394d04ee6b938"}, + {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62360cb771707cb70a6fd114b9871d20d7dd2163a0feafe43fd115cfe4fe845e"}, + {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:23fb25a9f0a1ca1f24c0a371523546366bb642397c94ab45ad3aedf2941cec6a"}, + {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0ba0d15164eae3d878260d4c4df859bbdc6466e9e6689c344a13334f988bb53"}, + {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5d20003b635fc6ae3f96d7260281dfaf1894fc3aa24d1888a9b2628e97c241e5"}, + {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0175d745d9e85c40dcc51c8f88c74bfbaef9e7afeeeb9d03c37977270303064c"}, + {file = "aiohttp-3.8.5-cp311-cp311-win32.whl", hash = "sha256:2e1b1e51b0774408f091d268648e3d57f7260c1682e7d3a63cb00d22d71bb945"}, + {file = "aiohttp-3.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:043d2299f6dfdc92f0ac5e995dfc56668e1587cea7f9aa9d8a78a1b6554e5755"}, + {file = "aiohttp-3.8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cae533195e8122584ec87531d6df000ad07737eaa3c81209e85c928854d2195c"}, + {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f21e83f355643c345177a5d1d8079f9f28b5133bcd154193b799d380331d5d3"}, + {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a75ef35f2df54ad55dbf4b73fe1da96f370e51b10c91f08b19603c64004acc"}, + {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e2e9839e14dd5308ee773c97115f1e0a1cb1d75cbeeee9f33824fa5144c7634"}, + {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44e65da1de4403d0576473e2344828ef9c4c6244d65cf4b75549bb46d40b8dd"}, + {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d847e4cde6ecc19125ccbc9bfac4a7ab37c234dd88fbb3c5c524e8e14da543"}, + {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:c7a815258e5895d8900aec4454f38dca9aed71085f227537208057853f9d13f2"}, + {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:8b929b9bd7cd7c3939f8bcfffa92fae7480bd1aa425279d51a89327d600c704d"}, + {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:5db3a5b833764280ed7618393832e0853e40f3d3e9aa128ac0ba0f8278d08649"}, + {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:a0215ce6041d501f3155dc219712bc41252d0ab76474615b9700d63d4d9292af"}, + {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fd1ed388ea7fbed22c4968dd64bab0198de60750a25fe8c0c9d4bef5abe13824"}, + {file = "aiohttp-3.8.5-cp36-cp36m-win32.whl", hash = "sha256:6e6783bcc45f397fdebc118d772103d751b54cddf5b60fbcc958382d7dd64f3e"}, + {file = "aiohttp-3.8.5-cp36-cp36m-win_amd64.whl", hash = "sha256:b5411d82cddd212644cf9360879eb5080f0d5f7d809d03262c50dad02f01421a"}, + {file = "aiohttp-3.8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:01d4c0c874aa4ddfb8098e85d10b5e875a70adc63db91f1ae65a4b04d3344cda"}, + {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5980a746d547a6ba173fd5ee85ce9077e72d118758db05d229044b469d9029a"}, + {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a482e6da906d5e6e653be079b29bc173a48e381600161c9932d89dfae5942ef"}, + {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80bd372b8d0715c66c974cf57fe363621a02f359f1ec81cba97366948c7fc873"}, + {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1161b345c0a444ebcf46bf0a740ba5dcf50612fd3d0528883fdc0eff578006a"}, + {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd56db019015b6acfaaf92e1ac40eb8434847d9bf88b4be4efe5bfd260aee692"}, + {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:153c2549f6c004d2754cc60603d4668899c9895b8a89397444a9c4efa282aaf4"}, + {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4a01951fabc4ce26ab791da5f3f24dca6d9a6f24121746eb19756416ff2d881b"}, + {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bfb9162dcf01f615462b995a516ba03e769de0789de1cadc0f916265c257e5d8"}, + {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:7dde0009408969a43b04c16cbbe252c4f5ef4574ac226bc8815cd7342d2028b6"}, + {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4149d34c32f9638f38f544b3977a4c24052042affa895352d3636fa8bffd030a"}, + {file = "aiohttp-3.8.5-cp37-cp37m-win32.whl", hash = "sha256:68c5a82c8779bdfc6367c967a4a1b2aa52cd3595388bf5961a62158ee8a59e22"}, + {file = "aiohttp-3.8.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2cf57fb50be5f52bda004b8893e63b48530ed9f0d6c96c84620dc92fe3cd9b9d"}, + {file = "aiohttp-3.8.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:eca4bf3734c541dc4f374ad6010a68ff6c6748f00451707f39857f429ca36ced"}, + {file = "aiohttp-3.8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1274477e4c71ce8cfe6c1ec2f806d57c015ebf84d83373676036e256bc55d690"}, + {file = "aiohttp-3.8.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:28c543e54710d6158fc6f439296c7865b29e0b616629767e685a7185fab4a6b9"}, + {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:910bec0c49637d213f5d9877105d26e0c4a4de2f8b1b29405ff37e9fc0ad52b8"}, + {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5443910d662db951b2e58eb70b0fbe6b6e2ae613477129a5805d0b66c54b6cb7"}, + {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e460be6978fc24e3df83193dc0cc4de46c9909ed92dd47d349a452ef49325b7"}, + {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb1558def481d84f03b45888473fc5a1f35747b5f334ef4e7a571bc0dfcb11f8"}, + {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34dd0c107799dcbbf7d48b53be761a013c0adf5571bf50c4ecad5643fe9cfcd0"}, + {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aa1990247f02a54185dc0dff92a6904521172a22664c863a03ff64c42f9b5410"}, + {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0e584a10f204a617d71d359fe383406305a4b595b333721fa50b867b4a0a1548"}, + {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a3cf433f127efa43fee6b90ea4c6edf6c4a17109d1d037d1a52abec84d8f2e42"}, + {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c11f5b099adafb18e65c2c997d57108b5bbeaa9eeee64a84302c0978b1ec948b"}, + {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:84de26ddf621d7ac4c975dbea4c945860e08cccde492269db4e1538a6a6f3c35"}, + {file = "aiohttp-3.8.5-cp38-cp38-win32.whl", hash = "sha256:ab88bafedc57dd0aab55fa728ea10c1911f7e4d8b43e1d838a1739f33712921c"}, + {file = "aiohttp-3.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:5798a9aad1879f626589f3df0f8b79b3608a92e9beab10e5fda02c8a2c60db2e"}, + {file = "aiohttp-3.8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a6ce61195c6a19c785df04e71a4537e29eaa2c50fe745b732aa937c0c77169f3"}, + {file = "aiohttp-3.8.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:773dd01706d4db536335fcfae6ea2440a70ceb03dd3e7378f3e815b03c97ab51"}, + {file = "aiohttp-3.8.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f83a552443a526ea38d064588613aca983d0ee0038801bc93c0c916428310c28"}, + {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f7372f7341fcc16f57b2caded43e81ddd18df53320b6f9f042acad41f8e049a"}, + {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea353162f249c8097ea63c2169dd1aa55de1e8fecbe63412a9bc50816e87b761"}, + {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d47ae48db0b2dcf70bc8a3bc72b3de86e2a590fc299fdbbb15af320d2659de"}, + {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d827176898a2b0b09694fbd1088c7a31836d1a505c243811c87ae53a3f6273c1"}, + {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3562b06567c06439d8b447037bb655ef69786c590b1de86c7ab81efe1c9c15d8"}, + {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4e874cbf8caf8959d2adf572a78bba17cb0e9d7e51bb83d86a3697b686a0ab4d"}, + {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6809a00deaf3810e38c628e9a33271892f815b853605a936e2e9e5129762356c"}, + {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:33776e945d89b29251b33a7e7d006ce86447b2cfd66db5e5ded4e5cd0340585c"}, + {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:eaeed7abfb5d64c539e2db173f63631455f1196c37d9d8d873fc316470dfbacd"}, + {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e91d635961bec2d8f19dfeb41a539eb94bd073f075ca6dae6c8dc0ee89ad6f91"}, + {file = "aiohttp-3.8.5-cp39-cp39-win32.whl", hash = "sha256:00ad4b6f185ec67f3e6562e8a1d2b69660be43070bd0ef6fcec5211154c7df67"}, + {file = "aiohttp-3.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:c0a9034379a37ae42dea7ac1e048352d96286626251862e448933c0f59cbd79c"}, + {file = "aiohttp-3.8.5.tar.gz", hash = "sha256:b9552ec52cc147dbf1944ac7ac98af7602e51ea2dcd076ed194ca3c0d1c7d0bc"}, +] + +[package.dependencies] +aiosignal = ">=1.1.2" +async-timeout = ">=4.0.0a3,<5.0" +attrs = ">=17.3.0" +charset-normalizer = ">=2.0,<4.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +yarl = ">=1.0,<2.0" + +[package.extras] +speedups = ["Brotli", "aiodns", "cchardet"] + +[[package]] +name = "aiosignal" +version = "1.3.1" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.7" +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" + +[[package]] +name = "anyio" +version = "3.7.1" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.7" +files = [ + {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, + {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, +] + +[package.dependencies] +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] +test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (<0.22)"] + +[[package]] +name = "appnope" +version = "0.1.3" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = "*" +files = [ + {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, + {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, +] + +[[package]] +name = "argon2-cffi" +version = "21.3.0" +description = "The secure Argon2 password hashing algorithm." +optional = false +python-versions = ">=3.6" +files = [ + {file = "argon2-cffi-21.3.0.tar.gz", hash = "sha256:d384164d944190a7dd7ef22c6aa3ff197da12962bd04b17f64d4e93d934dba5b"}, + {file = "argon2_cffi-21.3.0-py3-none-any.whl", hash = "sha256:8c976986f2c5c0e5000919e6de187906cfd81fb1c72bf9d88c01177e77da7f80"}, +] + +[package.dependencies] +argon2-cffi-bindings = "*" + +[package.extras] +dev = ["cogapp", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "pre-commit", "pytest", "sphinx", "sphinx-notfound-page", "tomli"] +docs = ["furo", "sphinx", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pytest"] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +description = "Low-level CFFI bindings for Argon2" +optional = false +python-versions = ">=3.6" +files = [ + {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, + {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, +] + +[package.dependencies] +cffi = ">=1.0.1" + +[package.extras] +dev = ["cogapp", "pre-commit", "pytest", "wheel"] +tests = ["pytest"] + +[[package]] +name = "arrow" +version = "1.2.3" +description = "Better dates & times for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "arrow-1.2.3-py3-none-any.whl", hash = "sha256:5a49ab92e3b7b71d96cd6bfcc4df14efefc9dfa96ea19045815914a6ab6b1fe2"}, + {file = "arrow-1.2.3.tar.gz", hash = "sha256:3934b30ca1b9f292376d9db15b19446088d12ec58629bc3f0da28fd55fb633a1"}, +] + +[package.dependencies] +python-dateutil = ">=2.7.0" + +[[package]] +name = "asttokens" +version = "2.2.1" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = "*" +files = [ + {file = "asttokens-2.2.1-py2.py3-none-any.whl", hash = "sha256:6b0ac9e93fb0335014d382b8fa9b3afa7df546984258005da0b9e7095b3deb1c"}, + {file = "asttokens-2.2.1.tar.gz", hash = "sha256:4622110b2a6f30b77e1473affaa97e711bc2f07d3f10848420ff1898edbe94f3"}, +] + +[package.dependencies] +six = "*" + +[package.extras] +test = ["astroid", "pytest"] + +[[package]] +name = "async-lru" +version = "2.0.3" +description = "Simple LRU cache for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "async-lru-2.0.3.tar.gz", hash = "sha256:b714c9d1415fca4e264da72a9e2abc66880ce7430e03a973341f88ea4c0d4869"}, + {file = "async_lru-2.0.3-py3-none-any.whl", hash = "sha256:00c0a8899c20b9c88663a47732689ff98189c9fa08ad9f734d7722f934d250b1"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "async-timeout" +version = "4.0.2" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.6" +files = [ + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, +] + +[[package]] +name = "attrs" +version = "23.1.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] + +[[package]] +name = "babel" +version = "2.12.1" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, + {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, +] + +[package.dependencies] +pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} + +[[package]] +name = "backcall" +version = "0.2.0" +description = "Specifications for callback functions passed in to an API" +optional = false +python-versions = "*" +files = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] + +[[package]] +name = "beautifulsoup4" +version = "4.12.2" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, + {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, +] + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "bleach" +version = "6.0.0" +description = "An easy safelist-based HTML-sanitizing tool." +optional = false +python-versions = ">=3.7" +files = [ + {file = "bleach-6.0.0-py3-none-any.whl", hash = "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4"}, + {file = "bleach-6.0.0.tar.gz", hash = "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414"}, +] + +[package.dependencies] +six = ">=1.9.0" +webencodings = "*" + +[package.extras] +css = ["tinycss2 (>=1.1.0,<1.2)"] + +[[package]] +name = "certifi" +version = "2023.7.22" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, + {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, +] + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.2.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, + {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, +] + +[[package]] +name = "click" +version = "8.1.6" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"}, + {file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coloredlogs" +version = "15.0.1" +description = "Colored terminal output for Python's logging module" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, + {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, +] + +[package.dependencies] +humanfriendly = ">=9.1" + +[package.extras] +cron = ["capturer (>=2.4)"] + +[[package]] +name = "comm" +version = "0.1.3" +description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." +optional = false +python-versions = ">=3.6" +files = [ + {file = "comm-0.1.3-py3-none-any.whl", hash = "sha256:16613c6211e20223f215fc6d3b266a247b6e2641bf4e0a3ad34cb1aff2aa3f37"}, + {file = "comm-0.1.3.tar.gz", hash = "sha256:a61efa9daffcfbe66fd643ba966f846a624e4e6d6767eda9cf6e993aadaab93e"}, +] + +[package.dependencies] +traitlets = ">=5.3" + +[package.extras] +lint = ["black (>=22.6.0)", "mdformat (>0.7)", "mdformat-gfm (>=0.3.5)", "ruff (>=0.0.156)"] +test = ["pytest"] +typing = ["mypy (>=0.990)"] + +[[package]] +name = "contourpy" +version = "1.1.0" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = false +python-versions = ">=3.8" +files = [ + {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"}, + {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, + {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, + {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, + {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, + {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, + {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, + {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, + {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, + {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, + {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, + {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, + {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, + {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, + {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, + {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"}, + {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"}, +] + +[package.dependencies] +numpy = ">=1.16" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "wurlitzer"] + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +optional = false +python-versions = ">=3.6" +files = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] + +[[package]] +name = "datasets" +version = "2.14.0" +description = "HuggingFace community-driven open-source library of datasets" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "datasets-2.14.0-py3-none-any.whl", hash = "sha256:93081cc3d9d0ce860c81f950a3ba23d24704da2eacbe2722092ef4f6ae0ada96"}, + {file = "datasets-2.14.0.tar.gz", hash = "sha256:1bb3d1c992a593949a8d3e445b358ac1db4ead00e6619ea2e5e7b6dfc222dde1"}, +] + +[package.dependencies] +aiohttp = "*" +dill = ">=0.3.0,<0.3.8" +fsspec = {version = ">=2021.11.1", extras = ["http"]} +huggingface-hub = ">=0.14.0,<1.0.0" +multiprocess = "*" +numpy = ">=1.17" +packaging = "*" +pandas = "*" +pyarrow = ">=8.0.0" +pyyaml = ">=5.1" +requests = ">=2.19.0" +tqdm = ">=4.62.1" +xxhash = "*" + +[package.extras] +apache-beam = ["apache-beam (>=2.26.0,<2.44.0)"] +audio = ["librosa", "soundfile (>=0.12.1)"] +benchmarks = ["tensorflow (==2.12.0)", "torch (==2.0.1)", "transformers (==4.30.1)"] +dev = ["Pillow (>=6.2.1)", "absl-py", "apache-beam (>=2.26.0,<2.44.0)", "black (>=23.1,<24.0)", "elasticsearch (<8.0.0)", "faiss-cpu (>=1.6.4)", "joblib (<1.3.0)", "joblibspark", "librosa", "lz4", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "pyyaml (>=5.3.1)", "rarfile (>=4.0)", "ruff (>=0.0.241)", "s3fs", "s3fs (>=2021.11.1)", "soundfile (>=0.12.1)", "sqlalchemy (<2.0.0)", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "tensorflow-macos", "tiktoken", "torch", "transformers", "zstandard"] +docs = ["s3fs"] +jax = ["jax (>=0.2.8,!=0.3.2,<=0.3.25)", "jaxlib (>=0.1.65,<=0.3.25)"] +metrics-tests = ["Werkzeug (>=1.0.1)", "accelerate", "bert-score (>=0.3.6)", "jiwer", "langdetect", "mauve-text", "nltk", "requests-file (>=1.5.1)", "rouge-score", "sacrebleu", "sacremoses", "scikit-learn", "scipy", "sentencepiece", "seqeval", "six (>=1.15.0,<1.16.0)", "spacy (>=3.0.0)", "texttable (>=1.6.3)", "tldextract", "tldextract (>=3.1.0)", "toml (>=0.10.1)", "typer (<0.5.0)"] +quality = ["black (>=23.1,<24.0)", "pyyaml (>=5.3.1)", "ruff (>=0.0.241)"] +s3 = ["s3fs"] +tensorflow = ["tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow-macos"] +tensorflow-gpu = ["tensorflow-gpu (>=2.2.0,!=2.6.0,!=2.6.1)"] +tests = ["Pillow (>=6.2.1)", "absl-py", "apache-beam (>=2.26.0,<2.44.0)", "elasticsearch (<8.0.0)", "faiss-cpu (>=1.6.4)", "joblib (<1.3.0)", "joblibspark", "librosa", "lz4", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "rarfile (>=4.0)", "s3fs (>=2021.11.1)", "soundfile (>=0.12.1)", "sqlalchemy (<2.0.0)", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "tensorflow-macos", "tiktoken", "torch", "transformers", "zstandard"] +torch = ["torch"] +vision = ["Pillow (>=6.2.1)"] + +[[package]] +name = "debugpy" +version = "1.6.7" +description = "An implementation of the Debug Adapter Protocol for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "debugpy-1.6.7-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b3e7ac809b991006ad7f857f016fa92014445085711ef111fdc3f74f66144096"}, + {file = "debugpy-1.6.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3876611d114a18aafef6383695dfc3f1217c98a9168c1aaf1a02b01ec7d8d1e"}, + {file = "debugpy-1.6.7-cp310-cp310-win32.whl", hash = "sha256:33edb4afa85c098c24cc361d72ba7c21bb92f501104514d4ffec1fb36e09c01a"}, + {file = "debugpy-1.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:ed6d5413474e209ba50b1a75b2d9eecf64d41e6e4501977991cdc755dc83ab0f"}, + {file = "debugpy-1.6.7-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:38ed626353e7c63f4b11efad659be04c23de2b0d15efff77b60e4740ea685d07"}, + {file = "debugpy-1.6.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:279d64c408c60431c8ee832dfd9ace7c396984fd7341fa3116aee414e7dcd88d"}, + {file = "debugpy-1.6.7-cp37-cp37m-win32.whl", hash = "sha256:dbe04e7568aa69361a5b4c47b4493d5680bfa3a911d1e105fbea1b1f23f3eb45"}, + {file = "debugpy-1.6.7-cp37-cp37m-win_amd64.whl", hash = "sha256:f90a2d4ad9a035cee7331c06a4cf2245e38bd7c89554fe3b616d90ab8aab89cc"}, + {file = "debugpy-1.6.7-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:5224eabbbeddcf1943d4e2821876f3e5d7d383f27390b82da5d9558fd4eb30a9"}, + {file = "debugpy-1.6.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bae1123dff5bfe548ba1683eb972329ba6d646c3a80e6b4c06cd1b1dd0205e9b"}, + {file = "debugpy-1.6.7-cp38-cp38-win32.whl", hash = "sha256:9cd10cf338e0907fdcf9eac9087faa30f150ef5445af5a545d307055141dd7a4"}, + {file = "debugpy-1.6.7-cp38-cp38-win_amd64.whl", hash = "sha256:aaf6da50377ff4056c8ed470da24632b42e4087bc826845daad7af211e00faad"}, + {file = "debugpy-1.6.7-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:0679b7e1e3523bd7d7869447ec67b59728675aadfc038550a63a362b63029d2c"}, + {file = "debugpy-1.6.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de86029696e1b3b4d0d49076b9eba606c226e33ae312a57a46dca14ff370894d"}, + {file = "debugpy-1.6.7-cp39-cp39-win32.whl", hash = "sha256:d71b31117779d9a90b745720c0eab54ae1da76d5b38c8026c654f4a066b0130a"}, + {file = "debugpy-1.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:c0ff93ae90a03b06d85b2c529eca51ab15457868a377c4cc40a23ab0e4e552a3"}, + {file = "debugpy-1.6.7-py2.py3-none-any.whl", hash = "sha256:53f7a456bc50706a0eaabecf2d3ce44c4d5010e46dfc65b6b81a518b42866267"}, + {file = "debugpy-1.6.7.zip", hash = "sha256:c4c2f0810fa25323abfdfa36cbbbb24e5c3b1a42cb762782de64439c575d67f2"}, +] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + +[[package]] +name = "dill" +version = "0.3.7" +description = "serialize all of Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"}, + {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] + +[[package]] +name = "exceptiongroup" +version = "1.1.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, + {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "executing" +version = "1.2.0" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = "*" +files = [ + {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"}, + {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"}, +] + +[package.extras] +tests = ["asttokens", "littleutils", "pytest", "rich"] + +[[package]] +name = "fastjsonschema" +version = "2.18.0" +description = "Fastest Python implementation of JSON schema" +optional = false +python-versions = "*" +files = [ + {file = "fastjsonschema-2.18.0-py3-none-any.whl", hash = "sha256:128039912a11a807068a7c87d0da36660afbfd7202780db26c4aa7153cfdc799"}, + {file = "fastjsonschema-2.18.0.tar.gz", hash = "sha256:e820349dd16f806e4bd1467a138dced9def4bc7d6213a34295272a6cac95b5bd"}, +] + +[package.extras] +devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] + +[[package]] +name = "filelock" +version = "3.12.2" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.7" +files = [ + {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, + {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, +] + +[package.extras] +docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "flatbuffers" +version = "23.5.26" +description = "The FlatBuffers serialization format for Python" +optional = false +python-versions = "*" +files = [ + {file = "flatbuffers-23.5.26-py2.py3-none-any.whl", hash = "sha256:c0ff356da363087b915fde4b8b45bdda73432fc17cddb3c8157472eab1422ad1"}, + {file = "flatbuffers-23.5.26.tar.gz", hash = "sha256:9ea1144cac05ce5d86e2859f431c6cd5e66cd9c78c558317c7955fb8d4c78d89"}, +] + +[[package]] +name = "fonttools" +version = "4.41.1" +description = "Tools to manipulate font files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fonttools-4.41.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a7bbb290d13c6dd718ec2c3db46fe6c5f6811e7ea1e07f145fd8468176398224"}, + {file = "fonttools-4.41.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec453a45778524f925a8f20fd26a3326f398bfc55d534e37bab470c5e415caa1"}, + {file = "fonttools-4.41.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2071267deaa6d93cb16288613419679c77220543551cbe61da02c93d92df72f"}, + {file = "fonttools-4.41.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e3334d51f0e37e2c6056e67141b2adabc92613a968797e2571ca8a03bd64773"}, + {file = "fonttools-4.41.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cac73bbef7734e78c60949da11c4903ee5837168e58772371bd42a75872f4f82"}, + {file = "fonttools-4.41.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:edee0900cf0eedb29d17c7876102d6e5a91ee333882b1f5abc83e85b934cadb5"}, + {file = "fonttools-4.41.1-cp310-cp310-win32.whl", hash = "sha256:2a22b2c425c698dcd5d6b0ff0b566e8e9663172118db6fd5f1941f9b8063da9b"}, + {file = "fonttools-4.41.1-cp310-cp310-win_amd64.whl", hash = "sha256:547ab36a799dded58a46fa647266c24d0ed43a66028cd1cd4370b246ad426cac"}, + {file = "fonttools-4.41.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:849ec722bbf7d3501a0e879e57dec1fc54919d31bff3f690af30bb87970f9784"}, + {file = "fonttools-4.41.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:38cdecd8f1fd4bf4daae7fed1b3170dfc1b523388d6664b2204b351820aa78a7"}, + {file = "fonttools-4.41.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ae64303ba670f8959fdaaa30ba0c2dabe75364fdec1caeee596c45d51ca3425"}, + {file = "fonttools-4.41.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14f3ccea4cc7dd1b277385adf3c3bf18f9860f87eab9c2fb650b0af16800f55"}, + {file = "fonttools-4.41.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:33191f062549e6bb1a4782c22a04ebd37009c09360e2d6686ac5083774d06d95"}, + {file = "fonttools-4.41.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:704bccd69b0abb6fab9f5e4d2b75896afa48b427caa2c7988792a2ffce35b441"}, + {file = "fonttools-4.41.1-cp311-cp311-win32.whl", hash = "sha256:4edc795533421e98f60acee7d28fc8d941ff5ac10f44668c9c3635ad72ae9045"}, + {file = "fonttools-4.41.1-cp311-cp311-win_amd64.whl", hash = "sha256:aaaef294d8e411f0ecb778a0aefd11bb5884c9b8333cc1011bdaf3b58ca4bd75"}, + {file = "fonttools-4.41.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3d1f9471134affc1e3b1b806db6e3e2ad3fa99439e332f1881a474c825101096"}, + {file = "fonttools-4.41.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:59eba8b2e749a1de85760da22333f3d17c42b66e03758855a12a2a542723c6e7"}, + {file = "fonttools-4.41.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9b3cc10dc9e0834b6665fd63ae0c6964c6bc3d7166e9bc84772e0edd09f9fa2"}, + {file = "fonttools-4.41.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2c2964bdc827ba6b8a91dc6de792620be4da3922c4cf0599f36a488c07e2b2"}, + {file = "fonttools-4.41.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7763316111df7b5165529f4183a334aa24c13cdb5375ffa1dc8ce309c8bf4e5c"}, + {file = "fonttools-4.41.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b2d1ee95be42b80d1f002d1ee0a51d7a435ea90d36f1a5ae331be9962ee5a3f1"}, + {file = "fonttools-4.41.1-cp38-cp38-win32.whl", hash = "sha256:f48602c0b3fd79cd83a34c40af565fe6db7ac9085c8823b552e6e751e3a5b8be"}, + {file = "fonttools-4.41.1-cp38-cp38-win_amd64.whl", hash = "sha256:b0938ebbeccf7c80bb9a15e31645cf831572c3a33d5cc69abe436e7000c61b14"}, + {file = "fonttools-4.41.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e5c2b0a95a221838991e2f0e455dec1ca3a8cc9cd54febd68cc64d40fdb83669"}, + {file = "fonttools-4.41.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:891cfc5a83b0307688f78b9bb446f03a7a1ad981690ac8362f50518bc6153975"}, + {file = "fonttools-4.41.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73ef0bb5d60eb02ba4d3a7d23ada32184bd86007cb2de3657cfcb1175325fc83"}, + {file = "fonttools-4.41.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f240d9adf0583ac8fc1646afe7f4ac039022b6f8fa4f1575a2cfa53675360b69"}, + {file = "fonttools-4.41.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bdd729744ae7ecd7f7311ad25d99da4999003dcfe43b436cf3c333d4e68de73d"}, + {file = "fonttools-4.41.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b927e5f466d99c03e6e20961946314b81d6e3490d95865ef88061144d9f62e38"}, + {file = "fonttools-4.41.1-cp39-cp39-win32.whl", hash = "sha256:afce2aeb80be72b4da7dd114f10f04873ff512793d13ce0b19d12b2a4c44c0f0"}, + {file = "fonttools-4.41.1-cp39-cp39-win_amd64.whl", hash = "sha256:1df1b6f4c7c4bc8201eb47f3b268adbf2539943aa43c400f84556557e3e109c0"}, + {file = "fonttools-4.41.1-py3-none-any.whl", hash = "sha256:952cb405f78734cf6466252fec42e206450d1a6715746013f64df9cbd4f896fa"}, + {file = "fonttools-4.41.1.tar.gz", hash = "sha256:e16a9449f21a93909c5be2f5ed5246420f2316e94195dbfccb5238aaa38f9751"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "scipy"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.0.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + +[[package]] +name = "fqdn" +version = "1.5.1" +description = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers" +optional = false +python-versions = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4" +files = [ + {file = "fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"}, + {file = "fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f"}, +] + +[[package]] +name = "frozenlist" +version = "1.4.0" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.8" +files = [ + {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:764226ceef3125e53ea2cb275000e309c0aa5464d43bd72abd661e27fffc26ab"}, + {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d6484756b12f40003c6128bfcc3fa9f0d49a687e171186c2d85ec82e3758c559"}, + {file = "frozenlist-1.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9ac08e601308e41eb533f232dbf6b7e4cea762f9f84f6357136eed926c15d12c"}, + {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d081f13b095d74b67d550de04df1c756831f3b83dc9881c38985834387487f1b"}, + {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71932b597f9895f011f47f17d6428252fc728ba2ae6024e13c3398a087c2cdea"}, + {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:981b9ab5a0a3178ff413bca62526bb784249421c24ad7381e39d67981be2c326"}, + {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e41f3de4df3e80de75845d3e743b3f1c4c8613c3997a912dbf0229fc61a8b963"}, + {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6918d49b1f90821e93069682c06ffde41829c346c66b721e65a5c62b4bab0300"}, + {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e5c8764c7829343d919cc2dfc587a8db01c4f70a4ebbc49abde5d4b158b007b"}, + {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8d0edd6b1c7fb94922bf569c9b092ee187a83f03fb1a63076e7774b60f9481a8"}, + {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e29cda763f752553fa14c68fb2195150bfab22b352572cb36c43c47bedba70eb"}, + {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:0c7c1b47859ee2cac3846fde1c1dc0f15da6cec5a0e5c72d101e0f83dcb67ff9"}, + {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:901289d524fdd571be1c7be054f48b1f88ce8dddcbdf1ec698b27d4b8b9e5d62"}, + {file = "frozenlist-1.4.0-cp310-cp310-win32.whl", hash = "sha256:1a0848b52815006ea6596c395f87449f693dc419061cc21e970f139d466dc0a0"}, + {file = "frozenlist-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:b206646d176a007466358aa21d85cd8600a415c67c9bd15403336c331a10d956"}, + {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de343e75f40e972bae1ef6090267f8260c1446a1695e77096db6cfa25e759a95"}, + {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad2a9eb6d9839ae241701d0918f54c51365a51407fd80f6b8289e2dfca977cc3"}, + {file = "frozenlist-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd7bd3b3830247580de99c99ea2a01416dfc3c34471ca1298bccabf86d0ff4dc"}, + {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdf1847068c362f16b353163391210269e4f0569a3c166bc6a9f74ccbfc7e839"}, + {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38461d02d66de17455072c9ba981d35f1d2a73024bee7790ac2f9e361ef1cd0c"}, + {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5a32087d720c608f42caed0ef36d2b3ea61a9d09ee59a5142d6070da9041b8f"}, + {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd65632acaf0d47608190a71bfe46b209719bf2beb59507db08ccdbe712f969b"}, + {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261b9f5d17cac914531331ff1b1d452125bf5daa05faf73b71d935485b0c510b"}, + {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b89ac9768b82205936771f8d2eb3ce88503b1556324c9f903e7156669f521472"}, + {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01"}, + {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e74b0506fa5aa5598ac6a975a12aa8928cbb58e1f5ac8360792ef15de1aa848f"}, + {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:490132667476f6781b4c9458298b0c1cddf237488abd228b0b3650e5ecba7467"}, + {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:76d4711f6f6d08551a7e9ef28c722f4a50dd0fc204c56b4bcd95c6cc05ce6fbb"}, + {file = "frozenlist-1.4.0-cp311-cp311-win32.whl", hash = "sha256:a02eb8ab2b8f200179b5f62b59757685ae9987996ae549ccf30f983f40602431"}, + {file = "frozenlist-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:515e1abc578dd3b275d6a5114030b1330ba044ffba03f94091842852f806f1c1"}, + {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f0ed05f5079c708fe74bf9027e95125334b6978bf07fd5ab923e9e55e5fbb9d3"}, + {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca265542ca427bf97aed183c1676e2a9c66942e822b14dc6e5f42e038f92a503"}, + {file = "frozenlist-1.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:491e014f5c43656da08958808588cc6c016847b4360e327a62cb308c791bd2d9"}, + {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17ae5cd0f333f94f2e03aaf140bb762c64783935cc764ff9c82dff626089bebf"}, + {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e78fb68cf9c1a6aa4a9a12e960a5c9dfbdb89b3695197aa7064705662515de2"}, + {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5655a942f5f5d2c9ed93d72148226d75369b4f6952680211972a33e59b1dfdc"}, + {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c11b0746f5d946fecf750428a95f3e9ebe792c1ee3b1e96eeba145dc631a9672"}, + {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e66d2a64d44d50d2543405fb183a21f76b3b5fd16f130f5c99187c3fb4e64919"}, + {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:88f7bc0fcca81f985f78dd0fa68d2c75abf8272b1f5c323ea4a01a4d7a614efc"}, + {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5833593c25ac59ede40ed4de6d67eb42928cca97f26feea219f21d0ed0959b79"}, + {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e"}, + {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:b826d97e4276750beca7c8f0f1a4938892697a6bcd8ec8217b3312dad6982781"}, + {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ceb6ec0a10c65540421e20ebd29083c50e6d1143278746a4ef6bcf6153171eb8"}, + {file = "frozenlist-1.4.0-cp38-cp38-win32.whl", hash = "sha256:2b8bcf994563466db019fab287ff390fffbfdb4f905fc77bc1c1d604b1c689cc"}, + {file = "frozenlist-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:a6c8097e01886188e5be3e6b14e94ab365f384736aa1fca6a0b9e35bd4a30bc7"}, + {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6c38721585f285203e4b4132a352eb3daa19121a035f3182e08e437cface44bf"}, + {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a0c6da9aee33ff0b1a451e867da0c1f47408112b3391dd43133838339e410963"}, + {file = "frozenlist-1.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93ea75c050c5bb3d98016b4ba2497851eadf0ac154d88a67d7a6816206f6fa7f"}, + {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1"}, + {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa384489fefeb62321b238e64c07ef48398fe80f9e1e6afeff22e140e0850eef"}, + {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10ff5faaa22786315ef57097a279b833ecab1a0bfb07d604c9cbb1c4cdc2ed87"}, + {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:007df07a6e3eb3e33e9a1fe6a9db7af152bbd8a185f9aaa6ece10a3529e3e1c6"}, + {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4f399d28478d1f604c2ff9119907af9726aed73680e5ed1ca634d377abb087"}, + {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5374b80521d3d3f2ec5572e05adc94601985cc526fb276d0c8574a6d749f1b3"}, + {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ce31ae3e19f3c902de379cf1323d90c649425b86de7bbdf82871b8a2a0615f3d"}, + {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7211ef110a9194b6042449431e08c4d80c0481e5891e58d429df5899690511c2"}, + {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:556de4430ce324c836789fa4560ca62d1591d2538b8ceb0b4f68fb7b2384a27a"}, + {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7645a8e814a3ee34a89c4a372011dcd817964ce8cb273c8ed6119d706e9613e3"}, + {file = "frozenlist-1.4.0-cp39-cp39-win32.whl", hash = "sha256:19488c57c12d4e8095a922f328df3f179c820c212940a498623ed39160bc3c2f"}, + {file = "frozenlist-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:6221d84d463fb110bdd7619b69cb43878a11d51cbb9394ae3105d082d5199167"}, + {file = "frozenlist-1.4.0.tar.gz", hash = "sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251"}, +] + +[[package]] +name = "fsspec" +version = "2023.6.0" +description = "File-system specification" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fsspec-2023.6.0-py3-none-any.whl", hash = "sha256:1cbad1faef3e391fba6dc005ae9b5bdcbf43005c9167ce78c915549c352c869a"}, + {file = "fsspec-2023.6.0.tar.gz", hash = "sha256:d0b2f935446169753e7a5c5c55681c54ea91996cc67be93c39a154fb3a2742af"}, +] + +[package.dependencies] +aiohttp = {version = "<4.0.0a0 || >4.0.0a0,<4.0.0a1 || >4.0.0a1", optional = true, markers = "extra == \"http\""} +requests = {version = "*", optional = true, markers = "extra == \"http\""} + +[package.extras] +abfs = ["adlfs"] +adl = ["adlfs"] +arrow = ["pyarrow (>=1)"] +dask = ["dask", "distributed"] +devel = ["pytest", "pytest-cov"] +dropbox = ["dropbox", "dropboxdrivefs", "requests"] +full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"] +fuse = ["fusepy"] +gcs = ["gcsfs"] +git = ["pygit2"] +github = ["requests"] +gs = ["gcsfs"] +gui = ["panel"] +hdfs = ["pyarrow (>=1)"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "requests"] +libarchive = ["libarchive-c"] +oci = ["ocifs"] +s3 = ["s3fs"] +sftp = ["paramiko"] +smb = ["smbprotocol"] +ssh = ["paramiko"] +tqdm = ["tqdm"] + +[[package]] +name = "graphviz" +version = "0.20.1" +description = "Simple Python interface for Graphviz" +optional = false +python-versions = ">=3.7" +files = [ + {file = "graphviz-0.20.1-py3-none-any.whl", hash = "sha256:587c58a223b51611c0cf461132da386edd896a029524ca61a1462b880bf97977"}, + {file = "graphviz-0.20.1.zip", hash = "sha256:8c58f14adaa3b947daf26c19bc1e98c4e0702cdc31cf99153e6f06904d492bf8"}, +] + +[package.extras] +dev = ["flake8", "pep8-naming", "tox (>=3)", "twine", "wheel"] +docs = ["sphinx (>=5)", "sphinx-autodoc-typehints", "sphinx-rtd-theme"] +test = ["coverage", "mock (>=4)", "pytest (>=7)", "pytest-cov", "pytest-mock (>=3)"] + +[[package]] +name = "huggingface-hub" +version = "0.16.4" +description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "huggingface_hub-0.16.4-py3-none-any.whl", hash = "sha256:0d3df29932f334fead024afc7cb4cc5149d955238b8b5e42dcf9740d6995a349"}, + {file = "huggingface_hub-0.16.4.tar.gz", hash = "sha256:608c7d4f3d368b326d1747f91523dbd1f692871e8e2e7a4750314a2dd8b63e14"}, +] + +[package.dependencies] +filelock = "*" +fsspec = "*" +packaging = ">=20.9" +pyyaml = ">=5.1" +requests = "*" +tqdm = ">=4.42.1" +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "black (>=23.1,<24.0)", "gradio", "jedi", "mypy (==0.982)", "numpy", "pydantic", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-vcr", "pytest-xdist", "ruff (>=0.0.241)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "urllib3 (<2.0)"] +cli = ["InquirerPy (==0.3.4)"] +dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "black (>=23.1,<24.0)", "gradio", "jedi", "mypy (==0.982)", "numpy", "pydantic", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-vcr", "pytest-xdist", "ruff (>=0.0.241)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "urllib3 (<2.0)"] +fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] +inference = ["aiohttp", "pydantic"] +quality = ["black (>=23.1,<24.0)", "mypy (==0.982)", "ruff (>=0.0.241)"] +tensorflow = ["graphviz", "pydot", "tensorflow"] +testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "numpy", "pydantic", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] +torch = ["torch"] +typing = ["pydantic", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3"] + +[[package]] +name = "humanfriendly" +version = "10.0" +description = "Human friendly output for text interfaces using Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, + {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, +] + +[package.dependencies] +pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""} + +[[package]] +name = "humanize" +version = "4.7.0" +description = "Python humanize utilities" +optional = false +python-versions = ">=3.8" +files = [ + {file = "humanize-4.7.0-py3-none-any.whl", hash = "sha256:df7c429c2d27372b249d3f26eb53b07b166b661326e0325793e0a988082e3889"}, + {file = "humanize-4.7.0.tar.gz", hash = "sha256:7ca0e43e870981fa684acb5b062deb307218193bca1a01f2b2676479df849b3a"}, +] + +[package.extras] +tests = ["freezegun", "pytest", "pytest-cov"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "importlib-metadata" +version = "6.8.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, + {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] + +[[package]] +name = "importlib-resources" +version = "6.0.0" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.0.0-py3-none-any.whl", hash = "sha256:d952faee11004c045f785bb5636e8f885bed30dc3c940d5d42798a2a4541c185"}, + {file = "importlib_resources-6.0.0.tar.gz", hash = "sha256:4cf94875a8368bd89531a756df9a9ebe1f150e0f885030b461237bc7f2d905f2"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[[package]] +name = "instructorembedding" +version = "1.0.1" +description = "Text embedding tool" +optional = false +python-versions = "*" +files = [ + {file = "InstructorEmbedding-1.0.1-py2.py3-none-any.whl", hash = "sha256:c8d0c11d0bab3ede023104e1f3de6a3471bf71208cc272d1ef72bae771e7d1a3"}, + {file = "InstructorEmbedding-1.0.1.tar.gz", hash = "sha256:886495ddd561bad57e8e7d5e8ee44c4243b1d80b538a25d32d37350f6082ee62"}, +] + +[[package]] +name = "ipykernel" +version = "6.25.0" +description = "IPython Kernel for Jupyter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ipykernel-6.25.0-py3-none-any.whl", hash = "sha256:f0042e867ac3f6bca1679e6a88cbd6a58ed93a44f9d0866aecde6efe8de76659"}, + {file = "ipykernel-6.25.0.tar.gz", hash = "sha256:e342ce84712861be4b248c4a73472be4702c1b0dd77448bfd6bcfb3af9d5ddf9"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "platform_system == \"Darwin\""} +comm = ">=0.1.1" +debugpy = ">=1.6.5" +ipython = ">=7.23.1" +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +matplotlib-inline = ">=0.1" +nest-asyncio = "*" +packaging = "*" +psutil = "*" +pyzmq = ">=20" +tornado = ">=6.1" +traitlets = ">=5.4.0" + +[package.extras] +cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] +pyqt5 = ["pyqt5"] +pyside6 = ["pyside6"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "ipython" +version = "8.12.2" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ipython-8.12.2-py3-none-any.whl", hash = "sha256:ea8801f15dfe4ffb76dea1b09b847430ffd70d827b41735c64a0638a04103bfc"}, + {file = "ipython-8.12.2.tar.gz", hash = "sha256:c7b80eb7f5a855a88efc971fda506ff7a91c280b42cdae26643e0f601ea281ea"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "sys_platform == \"darwin\""} +backcall = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pickleshare = "*" +prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5" +typing-extensions = {version = "*", markers = "python_version < \"3.10\""} + +[package.extras] +all = ["black", "curio", "docrepr", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +black = ["black"] +doc = ["docrepr", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] + +[[package]] +name = "ipython-genutils" +version = "0.2.0" +description = "Vestigial utilities from IPython" +optional = false +python-versions = "*" +files = [ + {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, + {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, +] + +[[package]] +name = "ipywidgets" +version = "8.0.7" +description = "Jupyter interactive widgets" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ipywidgets-8.0.7-py3-none-any.whl", hash = "sha256:e0aed0c95a1e55b6a123f64305245578bdc09e52965a34941c2b6a578b8c64a0"}, + {file = "ipywidgets-8.0.7.tar.gz", hash = "sha256:50ace0a8886e9a0d68b980db82f94c25d55d21ff2340ed36f802dd9365e94acf"}, +] + +[package.dependencies] +ipykernel = ">=4.5.1" +ipython = ">=6.1.0" +jupyterlab-widgets = ">=3.0.7,<3.1.0" +traitlets = ">=4.3.1" +widgetsnbextension = ">=4.0.7,<4.1.0" + +[package.extras] +test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] + +[[package]] +name = "isoduration" +version = "20.11.0" +description = "Operations with ISO 8601 durations" +optional = false +python-versions = ">=3.7" +files = [ + {file = "isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042"}, + {file = "isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9"}, +] + +[package.dependencies] +arrow = ">=0.15.0" + +[[package]] +name = "jedi" +version = "0.18.2" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.18.2-py2.py3-none-any.whl", hash = "sha256:203c1fd9d969ab8f2119ec0a3342e0b49910045abe6af0a3ae83a5764d54639e"}, + {file = "jedi-0.18.2.tar.gz", hash = "sha256:bae794c30d07f6d910d32a7048af09b5a39ed740918da923c6b780790ebac612"}, +] + +[package.dependencies] +parso = ">=0.8.0,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + +[[package]] +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "joblib" +version = "1.3.1" +description = "Lightweight pipelining with Python functions" +optional = false +python-versions = ">=3.7" +files = [ + {file = "joblib-1.3.1-py3-none-any.whl", hash = "sha256:89cf0529520e01b3de7ac7b74a8102c90d16d54c64b5dd98cafcd14307fdf915"}, + {file = "joblib-1.3.1.tar.gz", hash = "sha256:1f937906df65329ba98013dc9692fe22a4c5e4a648112de500508b18a21b41e3"}, +] + +[[package]] +name = "json5" +version = "0.9.14" +description = "A Python implementation of the JSON5 data format." +optional = false +python-versions = "*" +files = [ + {file = "json5-0.9.14-py2.py3-none-any.whl", hash = "sha256:740c7f1b9e584a468dbb2939d8d458db3427f2c93ae2139d05f47e453eae964f"}, + {file = "json5-0.9.14.tar.gz", hash = "sha256:9ed66c3a6ca3510a976a9ef9b8c0787de24802724ab1860bc0153c7fdd589b02"}, +] + +[package.extras] +dev = ["hypothesis"] + +[[package]] +name = "jsonpointer" +version = "2.4" +description = "Identify specific nodes in a JSON document (RFC 6901)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, + {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, +] + +[[package]] +name = "jsonschema" +version = "4.18.4" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.18.4-py3-none-any.whl", hash = "sha256:971be834317c22daaa9132340a51c01b50910724082c2c1a2ac87eeec153a3fe"}, + {file = "jsonschema-4.18.4.tar.gz", hash = "sha256:fb3642735399fa958c0d2aad7057901554596c63349f4f6b283c493cf692a25d"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +fqdn = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +idna = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} +isoduration = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +jsonpointer = {version = ">1.13", optional = true, markers = "extra == \"format-nongpl\""} +jsonschema-specifications = ">=2023.03.6" +pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""} +referencing = ">=0.28.4" +rfc3339-validator = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +rfc3986-validator = {version = ">0.1.0", optional = true, markers = "extra == \"format-nongpl\""} +rpds-py = ">=0.7.1" +uri-template = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +webcolors = {version = ">=1.11", optional = true, markers = "extra == \"format-nongpl\""} + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.7.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.7.1-py3-none-any.whl", hash = "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1"}, + {file = "jsonschema_specifications-2023.7.1.tar.gz", hash = "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb"}, +] + +[package.dependencies] +importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} +referencing = ">=0.28.0" + +[[package]] +name = "jupyter" +version = "1.0.0" +description = "Jupyter metapackage. Install all the Jupyter components in one go." +optional = false +python-versions = "*" +files = [ + {file = "jupyter-1.0.0-py2.py3-none-any.whl", hash = "sha256:5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78"}, + {file = "jupyter-1.0.0.tar.gz", hash = "sha256:d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f"}, + {file = "jupyter-1.0.0.zip", hash = "sha256:3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7"}, +] + +[package.dependencies] +ipykernel = "*" +ipywidgets = "*" +jupyter-console = "*" +nbconvert = "*" +notebook = "*" +qtconsole = "*" + +[[package]] +name = "jupyter-client" +version = "8.3.0" +description = "Jupyter protocol implementation and client libraries" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_client-8.3.0-py3-none-any.whl", hash = "sha256:7441af0c0672edc5d28035e92ba5e32fadcfa8a4e608a434c228836a89df6158"}, + {file = "jupyter_client-8.3.0.tar.gz", hash = "sha256:3af69921fe99617be1670399a0b857ad67275eefcfa291e2c81a160b7b650f5f"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +python-dateutil = ">=2.8.2" +pyzmq = ">=23.0" +tornado = ">=6.2" +traitlets = ">=5.3" + +[package.extras] +docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] + +[[package]] +name = "jupyter-console" +version = "6.6.3" +description = "Jupyter terminal console" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485"}, + {file = "jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539"}, +] + +[package.dependencies] +ipykernel = ">=6.14" +ipython = "*" +jupyter-client = ">=7.0.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +prompt-toolkit = ">=3.0.30" +pygments = "*" +pyzmq = ">=17" +traitlets = ">=5.4" + +[package.extras] +test = ["flaky", "pexpect", "pytest"] + +[[package]] +name = "jupyter-core" +version = "5.3.1" +description = "Jupyter core package. A base package on which Jupyter projects rely." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_core-5.3.1-py3-none-any.whl", hash = "sha256:ae9036db959a71ec1cac33081eeb040a79e681f08ab68b0883e9a676c7a90dce"}, + {file = "jupyter_core-5.3.1.tar.gz", hash = "sha256:5ba5c7938a7f97a6b0481463f7ff0dbac7c15ba48cf46fa4035ca6e838aa1aba"}, +] + +[package.dependencies] +platformdirs = ">=2.5" +pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} +traitlets = ">=5.3" + +[package.extras] +docs = ["myst-parser", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] +test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "jupyter-events" +version = "0.6.3" +description = "Jupyter Event System library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jupyter_events-0.6.3-py3-none-any.whl", hash = "sha256:57a2749f87ba387cd1bfd9b22a0875b889237dbf2edc2121ebb22bde47036c17"}, + {file = "jupyter_events-0.6.3.tar.gz", hash = "sha256:9a6e9995f75d1b7146b436ea24d696ce3a35bfa8bfe45e0c33c334c79464d0b3"}, +] + +[package.dependencies] +jsonschema = {version = ">=3.2.0", extras = ["format-nongpl"]} +python-json-logger = ">=2.0.4" +pyyaml = ">=5.3" +rfc3339-validator = "*" +rfc3986-validator = ">=0.1.1" +traitlets = ">=5.3" + +[package.extras] +cli = ["click", "rich"] +docs = ["jupyterlite-sphinx", "myst-parser", "pydata-sphinx-theme", "sphinxcontrib-spelling"] +test = ["click", "coverage", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.19.0)", "pytest-console-scripts", "pytest-cov", "rich"] + +[[package]] +name = "jupyter-lsp" +version = "2.2.0" +description = "Multi-Language Server WebSocket proxy for Jupyter Notebook/Lab server" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter-lsp-2.2.0.tar.gz", hash = "sha256:8ebbcb533adb41e5d635eb8fe82956b0aafbf0fd443b6c4bfa906edeeb8635a1"}, + {file = "jupyter_lsp-2.2.0-py3-none-any.whl", hash = "sha256:9e06b8b4f7dd50300b70dd1a78c0c3b0c3d8fa68e0f2d8a5d1fbab62072aca3f"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +jupyter-server = ">=1.1.2" + +[[package]] +name = "jupyter-server" +version = "2.7.0" +description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_server-2.7.0-py3-none-any.whl", hash = "sha256:6a77912aff643e53fa14bdb2634884b52b784a4be77ce8e93f7283faed0f0849"}, + {file = "jupyter_server-2.7.0.tar.gz", hash = "sha256:36da0a266d31a41ac335a366c88933c17dfa5bb817a48f5c02c16d303bc9477f"}, +] + +[package.dependencies] +anyio = ">=3.1.0" +argon2-cffi = "*" +jinja2 = "*" +jupyter-client = ">=7.4.4" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +jupyter-events = ">=0.6.0" +jupyter-server-terminals = "*" +nbconvert = ">=6.4.4" +nbformat = ">=5.3.0" +overrides = "*" +packaging = "*" +prometheus-client = "*" +pywinpty = {version = "*", markers = "os_name == \"nt\""} +pyzmq = ">=24" +send2trash = "*" +terminado = ">=0.8.3" +tornado = ">=6.2.0" +traitlets = ">=5.6.0" +websocket-client = "*" + +[package.extras] +docs = ["ipykernel", "jinja2", "jupyter-client", "jupyter-server", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] +test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0)", "pytest-console-scripts", "pytest-jupyter[server] (>=0.4)", "pytest-timeout", "requests"] + +[[package]] +name = "jupyter-server-terminals" +version = "0.4.4" +description = "A Jupyter Server Extension Providing Terminals." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_server_terminals-0.4.4-py3-none-any.whl", hash = "sha256:75779164661cec02a8758a5311e18bb8eb70c4e86c6b699403100f1585a12a36"}, + {file = "jupyter_server_terminals-0.4.4.tar.gz", hash = "sha256:57ab779797c25a7ba68e97bcfb5d7740f2b5e8a83b5e8102b10438041a7eac5d"}, +] + +[package.dependencies] +pywinpty = {version = ">=2.0.3", markers = "os_name == \"nt\""} +terminado = ">=0.8.3" + +[package.extras] +docs = ["jinja2", "jupyter-server", "mistune (<3.0)", "myst-parser", "nbformat", "packaging", "pydata-sphinx-theme", "sphinxcontrib-github-alt", "sphinxcontrib-openapi", "sphinxcontrib-spelling", "sphinxemoji", "tornado"] +test = ["coverage", "jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-cov", "pytest-jupyter[server] (>=0.5.3)", "pytest-timeout"] + +[[package]] +name = "jupyterlab" +version = "4.0.3" +description = "JupyterLab computational environment" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyterlab-4.0.3-py3-none-any.whl", hash = "sha256:d369944391b1d15f2d1f3cb965fb67352956279b2ae6f03ce7947a43940a8301"}, + {file = "jupyterlab-4.0.3.tar.gz", hash = "sha256:e14d1ce46a613028111d0d476a1d7d6b094003b7462bac669f5b478317abcb39"}, +] + +[package.dependencies] +async-lru = ">=1.0.0" +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +importlib-resources = {version = ">=1.4", markers = "python_version < \"3.9\""} +ipykernel = "*" +jinja2 = ">=3.0.3" +jupyter-core = "*" +jupyter-lsp = ">=2.0.0" +jupyter-server = ">=2.4.0,<3" +jupyterlab-server = ">=2.19.0,<3" +notebook-shim = ">=0.2" +packaging = "*" +tomli = {version = "*", markers = "python_version < \"3.11\""} +tornado = ">=6.2.0" +traitlets = "*" + +[package.extras] +dev = ["black[jupyter] (==23.3.0)", "build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.0.271)"] +docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-tornasync", "sphinx (>=1.8)", "sphinx-copybutton"] +docs-screenshots = ["altair (==5.0.1)", "ipython (==8.14.0)", "ipywidgets (==8.0.6)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.0.post0)", "matplotlib (==3.7.1)", "nbconvert (>=7.0.0)", "pandas (==2.0.2)", "scipy (==1.10.1)", "vega-datasets (==0.9.0)"] +test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] + +[[package]] +name = "jupyterlab-pygments" +version = "0.2.2" +description = "Pygments theme using JupyterLab CSS variables" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jupyterlab_pygments-0.2.2-py2.py3-none-any.whl", hash = "sha256:2405800db07c9f770863bcf8049a529c3dd4d3e28536638bd7c1c01d2748309f"}, + {file = "jupyterlab_pygments-0.2.2.tar.gz", hash = "sha256:7405d7fde60819d905a9fa8ce89e4cd830e318cdad22a0030f7a901da705585d"}, +] + +[[package]] +name = "jupyterlab-server" +version = "2.24.0" +description = "A set of server components for JupyterLab and JupyterLab like applications." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jupyterlab_server-2.24.0-py3-none-any.whl", hash = "sha256:5f077e142bb8dc9b843d960f940c513581bceca3793a0d80f9c67d9522c4e876"}, + {file = "jupyterlab_server-2.24.0.tar.gz", hash = "sha256:4e6f99e0a5579bbbc32e449c4dbb039561d4f1a7827d5733273ed56738f21f07"}, +] + +[package.dependencies] +babel = ">=2.10" +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +jinja2 = ">=3.0.3" +json5 = ">=0.9.0" +jsonschema = ">=4.17.3" +jupyter-server = ">=1.21,<3" +packaging = ">=21.3" +requests = ">=2.28" + +[package.extras] +docs = ["autodoc-traits", "jinja2 (<3.2.0)", "mistune (<4)", "myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-copybutton", "sphinxcontrib-openapi (>0.8)"] +openapi = ["openapi-core (>=0.16.1,<0.17.0)", "ruamel-yaml"] +test = ["hatch", "ipykernel", "jupyterlab-server[openapi]", "openapi-spec-validator (>=0.5.1,<0.7.0)", "pytest (>=7.0)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"] + +[[package]] +name = "jupyterlab-widgets" +version = "3.0.8" +description = "Jupyter interactive widgets for JupyterLab" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jupyterlab_widgets-3.0.8-py3-none-any.whl", hash = "sha256:4715912d6ceab839c9db35953c764b3214ebbc9161c809f6e0510168845dfdf5"}, + {file = "jupyterlab_widgets-3.0.8.tar.gz", hash = "sha256:d428ab97b8d87cc7c54cbf37644d6e0f0e662f23876e05fa460a73ec3257252a"}, +] + +[[package]] +name = "jyquickhelper" +version = "0.4.220" +description = "Helpers for Jupyter notebooks: automated menu, JSON visualizer, plug javascript" +optional = false +python-versions = "*" +files = [ + {file = "jyquickhelper-0.4.220-py3-none-any.whl", hash = "sha256:d26c039e6432907292daa07a6b7a16796ab7833a97f96877f9de55f82cf1a4b3"}, +] + +[package.dependencies] +ipython = "*" +jupyter = "*" +notebook = "*" + +[[package]] +name = "kiwisolver" +version = "1.4.4" +description = "A fast implementation of the Cassowary constraint solver" +optional = false +python-versions = ">=3.7" +files = [ + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, + {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, + {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, + {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, + {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, + {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, + {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, + {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, + {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, + {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, +] + +[[package]] +name = "markupsafe" +version = "2.1.3" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, + {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, +] + +[[package]] +name = "matplotlib" +version = "3.7.2" +description = "Python plotting package" +optional = false +python-versions = ">=3.8" +files = [ + {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:2699f7e73a76d4c110f4f25be9d2496d6ab4f17345307738557d345f099e07de"}, + {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a8035ba590658bae7562786c9cc6ea1a84aa49d3afab157e414c9e2ea74f496d"}, + {file = "matplotlib-3.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f8e4a49493add46ad4a8c92f63e19d548b2b6ebbed75c6b4c7f46f57d36cdd1"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71667eb2ccca4c3537d9414b1bc00554cb7f91527c17ee4ec38027201f8f1603"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:152ee0b569a37630d8628534c628456b28686e085d51394da6b71ef84c4da201"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070f8dddd1f5939e60aacb8fa08f19551f4b0140fab16a3669d5cd6e9cb28fc8"}, + {file = "matplotlib-3.7.2-cp310-cp310-win32.whl", hash = "sha256:fdbb46fad4fb47443b5b8ac76904b2e7a66556844f33370861b4788db0f8816a"}, + {file = "matplotlib-3.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:23fb1750934e5f0128f9423db27c474aa32534cec21f7b2153262b066a581fd1"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:30e1409b857aa8a747c5d4f85f63a79e479835f8dffc52992ac1f3f25837b544"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:50e0a55ec74bf2d7a0ebf50ac580a209582c2dd0f7ab51bc270f1b4a0027454e"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac60daa1dc83e8821eed155796b0f7888b6b916cf61d620a4ddd8200ac70cd64"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e3da477dc8607336ba10bac96986d6308d614706cae2efe7d3ffa60465b24"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c308b255efb9b06b23874236ec0f10f026673ad6515f602027cc8ac7805352d"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60c521e21031632aa0d87ca5ba0c1c05f3daacadb34c093585a0be6780f698e4"}, + {file = "matplotlib-3.7.2-cp311-cp311-win32.whl", hash = "sha256:26bede320d77e469fdf1bde212de0ec889169b04f7f1179b8930d66f82b30cbc"}, + {file = "matplotlib-3.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:af4860132c8c05261a5f5f8467f1b269bf1c7c23902d75f2be57c4a7f2394b3e"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a1733b8e84e7e40a9853e505fe68cc54339f97273bdfe6f3ed980095f769ddc7"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d9881356dc48e58910c53af82b57183879129fa30492be69058c5b0d9fddf391"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f081c03f413f59390a80b3e351cc2b2ea0205839714dbc364519bcf51f4b56ca"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cd120fca3407a225168238b790bd5c528f0fafde6172b140a2f3ab7a4ea63e9"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c1590b90aa7bd741b54c62b78de05d4186271e34e2377e0289d943b3522273"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d2ff3c984b8a569bc1383cd468fc06b70d7b59d5c2854ca39f1436ae8394117"}, + {file = "matplotlib-3.7.2-cp38-cp38-win32.whl", hash = "sha256:5dea00b62d28654b71ca92463656d80646675628d0828e08a5f3b57e12869e13"}, + {file = "matplotlib-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f506a1776ee94f9e131af1ac6efa6e5bc7cb606a3e389b0ccb6e657f60bb676"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6515e878f91894c2e4340d81f0911857998ccaf04dbc1bba781e3d89cbf70608"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:71f7a8c6b124e904db550f5b9fe483d28b896d4135e45c4ea381ad3b8a0e3256"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12f01b92ecd518e0697da4d97d163b2b3aa55eb3eb4e2c98235b3396d7dad55f"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7e28d6396563955f7af437894a36bf2b279462239a41028323e04b85179058b"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbcf59334ff645e6a67cd5f78b4b2cdb76384cdf587fa0d2dc85f634a72e1a3e"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:318c89edde72ff95d8df67d82aca03861240512994a597a435a1011ba18dbc7f"}, + {file = "matplotlib-3.7.2-cp39-cp39-win32.whl", hash = "sha256:ce55289d5659b5b12b3db4dc9b7075b70cef5631e56530f14b2945e8836f2d20"}, + {file = "matplotlib-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:2ecb5be2b2815431c81dc115667e33da0f5a1bcf6143980d180d09a717c4a12e"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdcd28360dbb6203fb5219b1a5658df226ac9bebc2542a9e8f457de959d713d0"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3cca3e842b11b55b52c6fb8bd6a4088693829acbfcdb3e815fa9b7d5c92c1b"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebf577c7a6744e9e1bd3fee45fc74a02710b214f94e2bde344912d85e0c9af7c"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:936bba394682049919dda062d33435b3be211dc3dcaa011e09634f060ec878b2"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bc221ffbc2150458b1cd71cdd9ddd5bb37962b036e41b8be258280b5b01da1dd"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35d74ebdb3f71f112b36c2629cf32323adfbf42679e2751252acd468f5001c07"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717157e61b3a71d3d26ad4e1770dc85156c9af435659a25ee6407dc866cb258d"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:20f844d6be031948148ba49605c8b96dfe7d3711d1b63592830d650622458c11"}, + {file = "matplotlib-3.7.2.tar.gz", hash = "sha256:a8cdb91dddb04436bd2f098b8fdf4b81352e68cf4d2c6756fcc414791076569b"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} +kiwisolver = ">=1.0.1" +numpy = ">=1.20" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.3.1,<3.1" +python-dateutil = ">=2.7" + +[[package]] +name = "matplotlib-inline" +version = "0.1.6" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.5" +files = [ + {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, + {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, +] + +[package.dependencies] +traitlets = "*" + +[[package]] +name = "mistune" +version = "3.0.1" +description = "A sane and fast Markdown parser with useful plugins and renderers" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mistune-3.0.1-py3-none-any.whl", hash = "sha256:b9b3e438efbb57c62b5beb5e134dab664800bdf1284a7ee09e8b12b13eb1aac6"}, + {file = "mistune-3.0.1.tar.gz", hash = "sha256:e912116c13aa0944f9dc530db38eb88f6a77087ab128f49f84a48f4c05ea163c"}, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +description = "Python library for arbitrary-precision floating-point arithmetic" +optional = false +python-versions = "*" +files = [ + {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, + {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, +] + +[package.extras] +develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"] +docs = ["sphinx"] +gmpy = ["gmpy2 (>=2.1.0a4)"] +tests = ["pytest (>=4.6)"] + +[[package]] +name = "multidict" +version = "6.0.4" +description = "multidict implementation" +optional = false +python-versions = ">=3.7" +files = [ + {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, + {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, + {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, + {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, + {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, + {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, + {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, + {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, + {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, + {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, + {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, + {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, + {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, +] + +[[package]] +name = "multiprocess" +version = "0.70.15" +description = "better multiprocessing and multithreading in Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "multiprocess-0.70.15-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:aa36c7ed16f508091438687fe9baa393a7a8e206731d321e443745e743a0d4e5"}, + {file = "multiprocess-0.70.15-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:20e024018c46d0d1602024c613007ac948f9754659e3853b0aa705e83f6931d8"}, + {file = "multiprocess-0.70.15-pp37-pypy37_pp73-manylinux_2_24_i686.whl", hash = "sha256:e576062981c91f0fe8a463c3d52506e598dfc51320a8dd8d78b987dfca91c5db"}, + {file = "multiprocess-0.70.15-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:e73f497e6696a0f5433ada2b3d599ae733b87a6e8b008e387c62ac9127add177"}, + {file = "multiprocess-0.70.15-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:73db2e7b32dcc7f9b0f075c2ffa45c90b6729d3f1805f27e88534c8d321a1be5"}, + {file = "multiprocess-0.70.15-pp38-pypy38_pp73-manylinux_2_24_i686.whl", hash = "sha256:4271647bd8a49c28ecd6eb56a7fdbd3c212c45529ad5303b40b3c65fc6928e5f"}, + {file = "multiprocess-0.70.15-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:cf981fb998d6ec3208cb14f0cf2e9e80216e834f5d51fd09ebc937c32b960902"}, + {file = "multiprocess-0.70.15-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:18f9f2c7063346d1617bd1684fdcae8d33380ae96b99427260f562e1a1228b67"}, + {file = "multiprocess-0.70.15-pp39-pypy39_pp73-manylinux_2_24_i686.whl", hash = "sha256:0eac53214d664c49a34695e5824872db4006b1a465edd7459a251809c3773370"}, + {file = "multiprocess-0.70.15-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:1a51dd34096db47fb21fa2b839e615b051d51b97af9a67afbcdaa67186b44883"}, + {file = "multiprocess-0.70.15-py310-none-any.whl", hash = "sha256:7dd58e33235e83cf09d625e55cffd7b0f0eede7ee9223cdd666a87624f60c21a"}, + {file = "multiprocess-0.70.15-py311-none-any.whl", hash = "sha256:134f89053d82c9ed3b73edd3a2531eb791e602d4f4156fc92a79259590bd9670"}, + {file = "multiprocess-0.70.15-py37-none-any.whl", hash = "sha256:f7d4a1629bccb433114c3b4885f69eccc200994323c80f6feee73b0edc9199c5"}, + {file = "multiprocess-0.70.15-py38-none-any.whl", hash = "sha256:bee9afba476c91f9ebee7beeee0601face9eff67d822e893f9a893725fbd6316"}, + {file = "multiprocess-0.70.15-py39-none-any.whl", hash = "sha256:3e0953f5d52b4c76f1c973eaf8214554d146f2be5decb48e928e55c7a2d19338"}, + {file = "multiprocess-0.70.15.tar.gz", hash = "sha256:f20eed3036c0ef477b07a4177cf7c1ba520d9a2677870a4f47fe026f0cd6787e"}, +] + +[package.dependencies] +dill = ">=0.3.7" + +[[package]] +name = "nbclient" +version = "0.8.0" +description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "nbclient-0.8.0-py3-none-any.whl", hash = "sha256:25e861299e5303a0477568557c4045eccc7a34c17fc08e7959558707b9ebe548"}, + {file = "nbclient-0.8.0.tar.gz", hash = "sha256:f9b179cd4b2d7bca965f900a2ebf0db4a12ebff2f36a711cb66861e4ae158e55"}, +] + +[package.dependencies] +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +nbformat = ">=5.1" +traitlets = ">=5.4" + +[package.extras] +dev = ["pre-commit"] +docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] +test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] + +[[package]] +name = "nbconvert" +version = "7.7.3" +description = "Converting Jupyter Notebooks" +optional = false +python-versions = ">=3.8" +files = [ + {file = "nbconvert-7.7.3-py3-none-any.whl", hash = "sha256:3022adadff3f86578a47fab7c2228bb3ca9c56a24345642a22f917f6168b48fc"}, + {file = "nbconvert-7.7.3.tar.gz", hash = "sha256:4a5996bf5f3cd16aa0431897ba1aa4c64842c2079f434b3dc6b8c4b252ef3355"}, +] + +[package.dependencies] +beautifulsoup4 = "*" +bleach = "!=5.0.0" +defusedxml = "*" +importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} +jinja2 = ">=3.0" +jupyter-core = ">=4.7" +jupyterlab-pygments = "*" +markupsafe = ">=2.0" +mistune = ">=2.0.3,<4" +nbclient = ">=0.5.0" +nbformat = ">=5.7" +packaging = "*" +pandocfilters = ">=1.4.1" +pygments = ">=2.4.1" +tinycss2 = "*" +traitlets = ">=5.1" + +[package.extras] +all = ["nbconvert[docs,qtpdf,serve,test,webpdf]"] +docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (==5.0.2)", "sphinxcontrib-spelling"] +qtpdf = ["nbconvert[qtpng]"] +qtpng = ["pyqtwebengine (>=5.15)"] +serve = ["tornado (>=6.1)"] +test = ["flaky", "ipykernel", "ipywidgets (>=7)", "pre-commit", "pytest", "pytest-dependency"] +webpdf = ["playwright"] + +[[package]] +name = "nbformat" +version = "5.9.1" +description = "The Jupyter Notebook format" +optional = false +python-versions = ">=3.8" +files = [ + {file = "nbformat-5.9.1-py3-none-any.whl", hash = "sha256:b7968ebf4811178a4108ee837eae1442e3f054132100f0359219e9ed1ce3ca45"}, + {file = "nbformat-5.9.1.tar.gz", hash = "sha256:3a7f52d040639cbd8a3890218c8b0ffb93211588c57446c90095e32ba5881b5d"}, +] + +[package.dependencies] +fastjsonschema = "*" +jsonschema = ">=2.6" +jupyter-core = "*" +traitlets = ">=5.1" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["pep440", "pre-commit", "pytest", "testpath"] + +[[package]] +name = "nest-asyncio" +version = "1.5.6" +description = "Patch asyncio to allow nested event loops" +optional = false +python-versions = ">=3.5" +files = [ + {file = "nest_asyncio-1.5.6-py3-none-any.whl", hash = "sha256:b9a953fb40dceaa587d109609098db21900182b16440652454a146cffb06e8b8"}, + {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"}, +] + +[[package]] +name = "networkx" +version = "3.1" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.8" +files = [ + {file = "networkx-3.1-py3-none-any.whl", hash = "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36"}, + {file = "networkx-3.1.tar.gz", hash = "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61"}, +] + +[package.extras] +default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"] +developer = ["mypy (>=1.1)", "pre-commit (>=3.2)"] +doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.13)", "sphinx (>=6.1)", "sphinx-gallery (>=0.12)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"] +test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] + +[[package]] +name = "nltk" +version = "3.8.1" +description = "Natural Language Toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "nltk-3.8.1-py3-none-any.whl", hash = "sha256:fd5c9109f976fa86bcadba8f91e47f5e9293bd034474752e92a520f81c93dda5"}, + {file = "nltk-3.8.1.zip", hash = "sha256:1834da3d0682cba4f2cede2f9aad6b0fafb6461ba451db0efb6f9c39798d64d3"}, +] + +[package.dependencies] +click = "*" +joblib = "*" +regex = ">=2021.8.3" +tqdm = "*" + +[package.extras] +all = ["matplotlib", "numpy", "pyparsing", "python-crfsuite", "requests", "scikit-learn", "scipy", "twython"] +corenlp = ["requests"] +machine-learning = ["numpy", "python-crfsuite", "scikit-learn", "scipy"] +plot = ["matplotlib"] +tgrep = ["pyparsing"] +twitter = ["twython"] + +[[package]] +name = "notebook" +version = "7.0.0" +description = "Jupyter Notebook - A web-based notebook environment for interactive computing" +optional = false +python-versions = ">=3.8" +files = [ + {file = "notebook-7.0.0-py3-none-any.whl", hash = "sha256:71b4e695e658763a2766613176491854708fb46fbe7664bf5e494deeeab92d60"}, + {file = "notebook-7.0.0.tar.gz", hash = "sha256:38b55e6939df0ba73b53212c3b234e41102f1789e0158606cedaebf00abef6c8"}, +] + +[package.dependencies] +importlib-resources = {version = ">=5.0", markers = "python_version < \"3.9\""} +jupyter-server = ">=2.4.0,<3" +jupyterlab = ">=4.0.2,<5" +jupyterlab-server = ">=2.22.1,<3" +notebook-shim = ">=0.2,<0.3" +tornado = ">=6.2.0" + +[package.extras] +dev = ["hatch", "pre-commit"] +docs = ["myst-parser", "nbsphinx", "pydata-sphinx-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.22.1,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] + +[[package]] +name = "notebook-shim" +version = "0.2.3" +description = "A shim layer for notebook traits and config" +optional = false +python-versions = ">=3.7" +files = [ + {file = "notebook_shim-0.2.3-py3-none-any.whl", hash = "sha256:a83496a43341c1674b093bfcebf0fe8e74cbe7eda5fd2bbc56f8e39e1486c0c7"}, + {file = "notebook_shim-0.2.3.tar.gz", hash = "sha256:f69388ac283ae008cd506dda10d0288b09a017d822d5e8c7129a152cbd3ce7e9"}, +] + +[package.dependencies] +jupyter-server = ">=1.8,<3" + +[package.extras] +test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync"] + +[[package]] +name = "numpy" +version = "1.24.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, + {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, + {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, + {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, + {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, + {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, + {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, + {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, + {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, + {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, + {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, +] + +[[package]] +name = "onnx" +version = "1.14.0" +description = "Open Neural Network Exchange" +optional = false +python-versions = "*" +files = [ + {file = "onnx-1.14.0-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:fb35c2c347486416f87f41557242c05d7ee804d3676c6c8c98eef6f5b1889e7b"}, + {file = "onnx-1.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd683d4aa6d55365582055a6c1e10a55d6c08a59e9216cbb67e37ad3a5b2b980"}, + {file = "onnx-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00b0d2620c10dcb9ec33441e807dc5851d2843d445e0faab5e22c8ad6874a67a"}, + {file = "onnx-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01893a4a2d70b68e8ee20269ccde4069a6fd243dc9e296643e2afeb0050527bc"}, + {file = "onnx-1.14.0-cp310-cp310-win32.whl", hash = "sha256:0753b0f118be71ff109dd994a3d6769e5871e9feaddfada77931c63f9de534b3"}, + {file = "onnx-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:d8c3a2354d9d997c7a4a5e467b5373c98dc549d4a33c77d5723e1eda7e87559c"}, + {file = "onnx-1.14.0-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:5e780fd1ed25493596a141e93303d0b2897acb9ebfdee7047a916d8f8e525ab3"}, + {file = "onnx-1.14.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9d28d64cbac3ebdc0c9761a300340c60ec60316099906e354e5059e90335fb3b"}, + {file = "onnx-1.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba92fed1aa27cba385bc3890fbbe6484603e837e67c957b22899f93c70990cc4"}, + {file = "onnx-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fab7e6e1c2d9d6479edad8e9088cdfd87ea293cb08f31565adabfb33c6e5789"}, + {file = "onnx-1.14.0-cp311-cp311-win32.whl", hash = "sha256:6e966f5ef38a0521595cad6a1d14d9ae205c593d2824d8c1fa044fa5ba15370d"}, + {file = "onnx-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:1fe8ba794d261d722018bd1385f02f966aace0fcb5448881ab5dd55ab0ebb81b"}, + {file = "onnx-1.14.0-cp37-cp37m-macosx_10_12_universal2.whl", hash = "sha256:c16dacf577700ff9cb076c61c880d1a4bc612eed96280396a54ee1e1bd7e2d68"}, + {file = "onnx-1.14.0-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:bbdca51da9fa9ec43eebd8c640bf71c05daa2afbeaa2c6478466470e28e41111"}, + {file = "onnx-1.14.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3315c304d23a06ebd07fffe2456ab7f1e0a8dba317393d5c17a671ae2da6645e"}, + {file = "onnx-1.14.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1545159f2e7fbc5b4a3ae032cd4d9ddeafc62c4f27fe22cbc3ecff49338992"}, + {file = "onnx-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:18cd98f7e234e268cb60c47a1f8ea5f6ffba50fe11de924b17498b1571d0cd2c"}, + {file = "onnx-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a8f7454acded506b6359ee0837c8527c64964973d7d25ed6b16b7d4314599502"}, + {file = "onnx-1.14.0-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a9702e7dd120bca421a820020151cbb1003077e17ded29cc8d44ff32a9a57ad8"}, + {file = "onnx-1.14.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:369c3ecace7e8c7df6efbcbc712b262626796ae4a83decd29111afafa025a30c"}, + {file = "onnx-1.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fbcdc1a0c1057785bc5f7254aca0cf0b49d19c74696f1ade107638054157315"}, + {file = "onnx-1.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed099fbdada4accead109a4479d5f73fb974566cce8d3c6fca94774f9645934c"}, + {file = "onnx-1.14.0-cp38-cp38-win32.whl", hash = "sha256:296e689aa54a9ae4e560b2bb149a64e96775699a0624af5f631665b9cda90482"}, + {file = "onnx-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:e1607f97007515df303c1f40b77363545af99a1f32d2f73240c8aa526cdbd109"}, + {file = "onnx-1.14.0-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:7800b6ec74b1fe3fbb3bf4a2380e2f4007c1a7f2d6927599ad40eead6eae5e19"}, + {file = "onnx-1.14.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:45d3effe59e20d0a9fdc51f5bb8f38299086c79576b894ed945e6a058c4b210a"}, + {file = "onnx-1.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a593b46015326feb949781d030cb1d0d5d388cca52bff2e2995badf55d56b38d"}, + {file = "onnx-1.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54614942574415ef3f0bce0800c6f41ecea8201f8042754e204ee8c0a8e473e1"}, + {file = "onnx-1.14.0-cp39-cp39-win32.whl", hash = "sha256:dcfaeb2d15e93c456003fac13ffa35144ba9d2666a83e2cef650dd5c90a2b768"}, + {file = "onnx-1.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:0639427ac61e5a0181f4f7c89f9fc82b3c9715c95071f9c3de79bbe303a4ae65"}, + {file = "onnx-1.14.0.tar.gz", hash = "sha256:43b85087c6b919de66872a043c7f4899fe6f840e11ffca7e662b2ce9e4cc2927"}, +] + +[package.dependencies] +numpy = "*" +protobuf = ">=3.20.2" +typing-extensions = ">=3.6.2.1" + +[package.extras] +lint = ["lintrunner (>=0.10.0)", "lintrunner-adapters (>=0.3)"] + +[[package]] +name = "onnxruntime" +version = "1.15.1" +description = "ONNX Runtime is a runtime accelerator for Machine Learning models" +optional = false +python-versions = "*" +files = [ + {file = "onnxruntime-1.15.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:baad59e6a763237fa39545325d29c16f98b8a45d2dfc524c67631e2e3ba44d16"}, + {file = "onnxruntime-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:568c2db848f619a0a93e843c028e9fb4879929d40b04bd60f9ba6eb8d2e93421"}, + {file = "onnxruntime-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69088d7784bb04dedfd9e883e2c96e4adf8ae0451acdd0abb78d68f59ecc6d9d"}, + {file = "onnxruntime-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cef43737b2cd886d5d718d100f56ec78c9c476c5db5f8f946e95024978fe754"}, + {file = "onnxruntime-1.15.1-cp310-cp310-win32.whl", hash = "sha256:79d7e65abb44a47c633ede8e53fe7b9756c272efaf169758c482c983cca98d7e"}, + {file = "onnxruntime-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:8bc4c47682933a7a2c79808688aad5f12581305e182be552de50783b5438e6bd"}, + {file = "onnxruntime-1.15.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:652b2cb777f76446e3cc41072dd3d1585a6388aeff92b9de656724bc22e241e4"}, + {file = "onnxruntime-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:89b86dbed15740abc385055a29c9673a212600248d702737ce856515bdeddc88"}, + {file = "onnxruntime-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed5cdd9ee748149a57f4cdfa67187a0d68f75240645a3c688299dcd08742cc98"}, + {file = "onnxruntime-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f748cce6a70ed38c19658615c55f4eedb9192765a4e9c4bd2682adfe980698d"}, + {file = "onnxruntime-1.15.1-cp311-cp311-win32.whl", hash = "sha256:e0312046e814c40066e7823da58075992d51364cbe739eeeb2345ec440c3ac59"}, + {file = "onnxruntime-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:f0980969689cb956c22bd1318b271e1be260060b37f3ddd82c7d63bd7f2d9a79"}, + {file = "onnxruntime-1.15.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:345986cfdbd6f4b20a89b6a6cd9abd3e2ced2926ae0b6e91fefa8149f95c0f09"}, + {file = "onnxruntime-1.15.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d7b3ad75e040f1e95757f69826a11051737b31584938a26d466a0234c6de98"}, + {file = "onnxruntime-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3603d07b829bcc1c14963a76103e257aade8861eb208173b300cc26e118ec2f8"}, + {file = "onnxruntime-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3df0625b9295daf1f7409ea55f72e1eeb38d54f5769add53372e79ddc3cf98d"}, + {file = "onnxruntime-1.15.1-cp38-cp38-win32.whl", hash = "sha256:f68b47fdf1a0406c0292f81ac993e2a2ae3e8b166b436d590eb221f64e8e187a"}, + {file = "onnxruntime-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:52d762d297cc3f731f54fa65a3e329b813164970671547bef6414d0ed52765c9"}, + {file = "onnxruntime-1.15.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:99228f9f03dc1fc8af89a28c9f942e8bd3e97e894e263abe1a32e4ddb1f6363b"}, + {file = "onnxruntime-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:45db7f96febb0cf23e3af147f35c4f8de1a37dd252d1cef853c242c2780250cd"}, + {file = "onnxruntime-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bafc112a36db25c821b90ab747644041cb4218f6575889775a2c12dd958b8c3"}, + {file = "onnxruntime-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:985693d18f2d46aa34fd44d7f65ff620660b2c8fa4b8ec365c2ca353f0fbdb27"}, + {file = "onnxruntime-1.15.1-cp39-cp39-win32.whl", hash = "sha256:708eb31b0c04724bf0f01c1309a9e69bbc09b85beb750e5662c8aed29f1ff9fd"}, + {file = "onnxruntime-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:73d6de4c42dfde1e9dbea04773e6dc23346c8cda9c7e08c6554fafc97ac60138"}, +] + +[package.dependencies] +coloredlogs = "*" +flatbuffers = "*" +numpy = ">=1.21.6" +packaging = "*" +protobuf = "*" +sympy = "*" + +[[package]] +name = "onnxt5" +version = "0.1.8" +description = "Blazing fast summarization, translation, text-generation, Q&A and more using T5 in ONNX" +optional = false +python-versions = ">=3.5, <4" +files = [ + {file = "onnxt5-0.1.8.tar.gz", hash = "sha256:bba2e5ac9861dd49c7154d26f17330547925704ea8030cb6decd97096a57d539"}, +] + +[package.dependencies] +onnxruntime = ">=1.4.0" +requests = ">=2.22.0" +sentencepiece = "*" +torch = ">=1.4.0" +tqdm = ">=4.48.2" +transformers = ">=3.0.2" + +[package.extras] +dev = ["unittest"] + +[[package]] +name = "optimum" +version = "1.10.0" +description = "Optimum Library is an extension of the Hugging Face Transformers library, providing a framework to integrate third-party libraries from Hardware Partners and interface with their specific functionality." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "optimum-1.10.0.tar.gz", hash = "sha256:cc80371dcd38c1748aeb60d6b7b300e81726e95e2c4ccc0e4e53e62a4e36801a"}, +] + +[package.dependencies] +coloredlogs = "*" +datasets = "*" +huggingface_hub = ">=0.8.0" +numpy = "*" +onnx = {version = "*", optional = true, markers = "extra == \"exporters\""} +onnxruntime = {version = "*", optional = true, markers = "extra == \"exporters\""} +packaging = "*" +sympy = "*" +timm = {version = "*", optional = true, markers = "extra == \"exporters\""} +torch = ">=1.9" +transformers = {version = ">=4.26.0", extras = ["sentencepiece"]} + +[package.extras] +benchmark = ["evaluate (>=0.2.0)", "optuna", "scikit-learn", "seqeval", "torchvision", "tqdm"] +dev = ["Pillow", "black (>=23.1,<24.0)", "diffusers (>=0.17.0)", "einops", "invisible-watermark", "parameterized", "pytest", "pytest-xdist", "requests", "ruff (>=0.0.241,<=0.0.259)", "sacremoses", "torchaudio", "torchvision"] +diffusers = ["diffusers"] +exporters = ["onnx", "onnxruntime", "timm"] +exporters-gpu = ["onnx", "onnxruntime-gpu", "timm"] +exporters-tf = ["h5py", "numpy (<1.24.0)", "onnx", "onnxruntime", "tensorflow (>=2.4)", "tf2onnx", "timm"] +furiosa = ["optimum-furiosa"] +graphcore = ["optimum-graphcore"] +habana = ["optimum-habana", "transformers (<4.29.0)"] +intel = ["optimum-intel"] +neural-compressor = ["optimum-intel[neural-compressor]"] +neuron = ["optimum-neuron[neuron]"] +neuronx = ["optimum-neuron[neuronx]"] +nncf = ["optimum-intel[nncf]"] +onnxruntime = ["datasets (>=1.2.1)", "evaluate", "onnx", "onnxruntime (>=1.9.0)", "protobuf (>=3.20.1)"] +onnxruntime-gpu = ["datasets (>=1.2.1)", "evaluate", "onnx", "onnxruntime-gpu (>=1.9.0)", "protobuf (>=3.20.1)"] +openvino = ["optimum-intel[openvino]"] +quality = ["black (>=23.1,<24.0)", "ruff (>=0.0.241,<=0.0.259)"] +tests = ["Pillow", "diffusers (>=0.17.0)", "einops", "invisible-watermark", "parameterized", "pytest", "pytest-xdist", "requests", "sacremoses", "torchaudio", "torchvision"] + +[[package]] +name = "overrides" +version = "7.3.1" +description = "A decorator to automatically detect mismatch when overriding a method." +optional = false +python-versions = ">=3.6" +files = [ + {file = "overrides-7.3.1-py3-none-any.whl", hash = "sha256:6187d8710a935d09b0bcef8238301d6ee2569d2ac1ae0ec39a8c7924e27f58ca"}, + {file = "overrides-7.3.1.tar.gz", hash = "sha256:8b97c6c1e1681b78cbc9424b138d880f0803c2254c5ebaabdde57bb6c62093f2"}, +] + +[[package]] +name = "packaging" +version = "23.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, +] + +[[package]] +name = "pandas" +version = "2.0.3" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pandas-2.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c7c9f27a4185304c7caf96dc7d91bc60bc162221152de697c98eb0b2648dd8"}, + {file = "pandas-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f167beed68918d62bffb6ec64f2e1d8a7d297a038f86d4aed056b9493fca407f"}, + {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0c6f76a0f1ba361551f3e6dceaff06bde7514a374aa43e33b588ec10420183"}, + {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba619e410a21d8c387a1ea6e8a0e49bb42216474436245718d7f2e88a2f8d7c0"}, + {file = "pandas-2.0.3-cp310-cp310-win32.whl", hash = "sha256:3ef285093b4fe5058eefd756100a367f27029913760773c8bf1d2d8bebe5d210"}, + {file = "pandas-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:9ee1a69328d5c36c98d8e74db06f4ad518a1840e8ccb94a4ba86920986bb617e"}, + {file = "pandas-2.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b084b91d8d66ab19f5bb3256cbd5ea661848338301940e17f4492b2ce0801fe8"}, + {file = "pandas-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37673e3bdf1551b95bf5d4ce372b37770f9529743d2498032439371fc7b7eb26"}, + {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9cb1e14fdb546396b7e1b923ffaeeac24e4cedd14266c3497216dd4448e4f2d"}, + {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9cd88488cceb7635aebb84809d087468eb33551097d600c6dad13602029c2df"}, + {file = "pandas-2.0.3-cp311-cp311-win32.whl", hash = "sha256:694888a81198786f0e164ee3a581df7d505024fbb1f15202fc7db88a71d84ebd"}, + {file = "pandas-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:6a21ab5c89dcbd57f78d0ae16630b090eec626360085a4148693def5452d8a6b"}, + {file = "pandas-2.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4da0d45e7f34c069fe4d522359df7d23badf83abc1d1cef398895822d11061"}, + {file = "pandas-2.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:32fca2ee1b0d93dd71d979726b12b61faa06aeb93cf77468776287f41ff8fdc5"}, + {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:258d3624b3ae734490e4d63c430256e716f488c4fcb7c8e9bde2d3aa46c29089"}, + {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eae3dc34fa1aa7772dd3fc60270d13ced7346fcbcfee017d3132ec625e23bb0"}, + {file = "pandas-2.0.3-cp38-cp38-win32.whl", hash = "sha256:f3421a7afb1a43f7e38e82e844e2bca9a6d793d66c1a7f9f0ff39a795bbc5e02"}, + {file = "pandas-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:69d7f3884c95da3a31ef82b7618af5710dba95bb885ffab339aad925c3e8ce78"}, + {file = "pandas-2.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5247fb1ba347c1261cbbf0fcfba4a3121fbb4029d95d9ef4dc45406620b25c8b"}, + {file = "pandas-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81af086f4543c9d8bb128328b5d32e9986e0c84d3ee673a2ac6fb57fd14f755e"}, + {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1994c789bf12a7c5098277fb43836ce090f1073858c10f9220998ac74f37c69b"}, + {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ec591c48e29226bcbb316e0c1e9423622bc7a4eaf1ef7c3c9fa1a3981f89641"}, + {file = "pandas-2.0.3-cp39-cp39-win32.whl", hash = "sha256:04dbdbaf2e4d46ca8da896e1805bc04eb85caa9a82e259e8eed00254d5e0c682"}, + {file = "pandas-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:1168574b036cd8b93abc746171c9b4f1b83467438a5e45909fed645cf8692dbc"}, + {file = "pandas-2.0.3.tar.gz", hash = "sha256:c02f372a88e0d17f36d3093a644c73cfc1788e876a7c4bcb4020a77512e2043c"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.20.3", markers = "python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, +] +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.1" + +[package.extras] +all = ["PyQt5 (>=5.15.1)", "SQLAlchemy (>=1.4.16)", "beautifulsoup4 (>=4.9.3)", "bottleneck (>=1.3.2)", "brotlipy (>=0.7.0)", "fastparquet (>=0.6.3)", "fsspec (>=2021.07.0)", "gcsfs (>=2021.07.0)", "html5lib (>=1.1)", "hypothesis (>=6.34.2)", "jinja2 (>=3.0.0)", "lxml (>=4.6.3)", "matplotlib (>=3.6.1)", "numba (>=0.53.1)", "numexpr (>=2.7.3)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pandas-gbq (>=0.15.0)", "psycopg2 (>=2.8.6)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "python-snappy (>=0.6.0)", "pyxlsb (>=1.0.8)", "qtpy (>=2.2.0)", "s3fs (>=2021.08.0)", "scipy (>=1.7.1)", "tables (>=3.6.1)", "tabulate (>=0.8.9)", "xarray (>=0.21.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)", "zstandard (>=0.15.2)"] +aws = ["s3fs (>=2021.08.0)"] +clipboard = ["PyQt5 (>=5.15.1)", "qtpy (>=2.2.0)"] +compression = ["brotlipy (>=0.7.0)", "python-snappy (>=0.6.0)", "zstandard (>=0.15.2)"] +computation = ["scipy (>=1.7.1)", "xarray (>=0.21.0)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pyxlsb (>=1.0.8)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)"] +feather = ["pyarrow (>=7.0.0)"] +fss = ["fsspec (>=2021.07.0)"] +gcp = ["gcsfs (>=2021.07.0)", "pandas-gbq (>=0.15.0)"] +hdf5 = ["tables (>=3.6.1)"] +html = ["beautifulsoup4 (>=4.9.3)", "html5lib (>=1.1)", "lxml (>=4.6.3)"] +mysql = ["SQLAlchemy (>=1.4.16)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.0.0)", "tabulate (>=0.8.9)"] +parquet = ["pyarrow (>=7.0.0)"] +performance = ["bottleneck (>=1.3.2)", "numba (>=0.53.1)", "numexpr (>=2.7.1)"] +plot = ["matplotlib (>=3.6.1)"] +postgresql = ["SQLAlchemy (>=1.4.16)", "psycopg2 (>=2.8.6)"] +spss = ["pyreadstat (>=1.1.2)"] +sql-other = ["SQLAlchemy (>=1.4.16)"] +test = ["hypothesis (>=6.34.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.6.3)"] + +[[package]] +name = "pandocfilters" +version = "1.5.0" +description = "Utilities for writing pandoc filters in python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pandocfilters-1.5.0-py2.py3-none-any.whl", hash = "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f"}, + {file = "pandocfilters-1.5.0.tar.gz", hash = "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38"}, +] + +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + +[[package]] +name = "pexpect" +version = "4.8.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pickleshare" +version = "0.7.5" +description = "Tiny 'shelve'-like database with concurrency support" +optional = false +python-versions = "*" +files = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] + +[[package]] +name = "pillow" +version = "10.0.0" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"}, + {file = "Pillow-10.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf"}, + {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3"}, + {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"}, + {file = "Pillow-10.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de"}, + {file = "Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"}, + {file = "Pillow-10.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629"}, + {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, + {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"}, + {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, + {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, + {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"}, + {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff"}, + {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"}, + {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"}, + {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"}, + {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, + {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"}, + {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51"}, + {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"}, + {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7"}, + {file = "Pillow-10.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0"}, + {file = "Pillow-10.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa"}, + {file = "Pillow-10.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba"}, + {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3"}, + {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"}, + {file = "Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3"}, + {file = "Pillow-10.0.0.tar.gz", hash = "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "pkgutil-resolve-name" +version = "1.3.10" +description = "Resolve a name to an object." +optional = false +python-versions = ">=3.6" +files = [ + {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"}, + {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"}, +] + +[[package]] +name = "platformdirs" +version = "3.9.1" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.9.1-py3-none-any.whl", hash = "sha256:ad8291ae0ae5072f66c16945166cb11c63394c7a3ad1b1bc9828ca3162da8c2f"}, + {file = "platformdirs-3.9.1.tar.gz", hash = "sha256:1b42b450ad933e981d56e59f1b97495428c9bd60698baab9f3eb3d00d5822421"}, +] + +[package.extras] +docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] + +[[package]] +name = "prometheus-client" +version = "0.17.1" +description = "Python client for the Prometheus monitoring system." +optional = false +python-versions = ">=3.6" +files = [ + {file = "prometheus_client-0.17.1-py3-none-any.whl", hash = "sha256:e537f37160f6807b8202a6fc4764cdd19bac5480ddd3e0d463c3002b34462101"}, + {file = "prometheus_client-0.17.1.tar.gz", hash = "sha256:21e674f39831ae3f8acde238afd9a27a37d0d2fb5a28ea094f0ce25d2cbf2091"}, +] + +[package.extras] +twisted = ["twisted"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.39" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, + {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "protobuf" +version = "4.23.4" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "protobuf-4.23.4-cp310-abi3-win32.whl", hash = "sha256:5fea3c64d41ea5ecf5697b83e41d09b9589e6f20b677ab3c48e5f242d9b7897b"}, + {file = "protobuf-4.23.4-cp310-abi3-win_amd64.whl", hash = "sha256:7b19b6266d92ca6a2a87effa88ecc4af73ebc5cfde194dc737cf8ef23a9a3b12"}, + {file = "protobuf-4.23.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8547bf44fe8cec3c69e3042f5c4fb3e36eb2a7a013bb0a44c018fc1e427aafbd"}, + {file = "protobuf-4.23.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fee88269a090ada09ca63551bf2f573eb2424035bcf2cb1b121895b01a46594a"}, + {file = "protobuf-4.23.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:effeac51ab79332d44fba74660d40ae79985901ac21bca408f8dc335a81aa597"}, + {file = "protobuf-4.23.4-cp37-cp37m-win32.whl", hash = "sha256:c3e0939433c40796ca4cfc0fac08af50b00eb66a40bbbc5dee711998fb0bbc1e"}, + {file = "protobuf-4.23.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9053df6df8e5a76c84339ee4a9f5a2661ceee4a0dab019e8663c50ba324208b0"}, + {file = "protobuf-4.23.4-cp38-cp38-win32.whl", hash = "sha256:e1c915778d8ced71e26fcf43c0866d7499891bca14c4368448a82edc61fdbc70"}, + {file = "protobuf-4.23.4-cp38-cp38-win_amd64.whl", hash = "sha256:351cc90f7d10839c480aeb9b870a211e322bf05f6ab3f55fcb2f51331f80a7d2"}, + {file = "protobuf-4.23.4-cp39-cp39-win32.whl", hash = "sha256:6dd9b9940e3f17077e820b75851126615ee38643c2c5332aa7a359988820c720"}, + {file = "protobuf-4.23.4-cp39-cp39-win_amd64.whl", hash = "sha256:0a5759f5696895de8cc913f084e27fd4125e8fb0914bb729a17816a33819f474"}, + {file = "protobuf-4.23.4-py3-none-any.whl", hash = "sha256:e9d0be5bf34b275b9f87ba7407796556abeeba635455d036c7351f7c183ef8ff"}, + {file = "protobuf-4.23.4.tar.gz", hash = "sha256:ccd9430c0719dce806b93f89c91de7977304729e55377f872a92465d548329a9"}, +] + +[[package]] +name = "psutil" +version = "5.9.5" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "psutil-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"}, + {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"}, + {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"}, + {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"}, + {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"}, + {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"}, + {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"}, + {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "pyarrow" +version = "12.0.1" +description = "Python library for Apache Arrow" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyarrow-12.0.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:6d288029a94a9bb5407ceebdd7110ba398a00412c5b0155ee9813a40d246c5df"}, + {file = "pyarrow-12.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345e1828efdbd9aa4d4de7d5676778aba384a2c3add896d995b23d368e60e5af"}, + {file = "pyarrow-12.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d6009fdf8986332b2169314da482baed47ac053311c8934ac6651e614deacd6"}, + {file = "pyarrow-12.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d3c4cbbf81e6dd23fe921bc91dc4619ea3b79bc58ef10bce0f49bdafb103daf"}, + {file = "pyarrow-12.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:cdacf515ec276709ac8042c7d9bd5be83b4f5f39c6c037a17a60d7ebfd92c890"}, + {file = "pyarrow-12.0.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:749be7fd2ff260683f9cc739cb862fb11be376de965a2a8ccbf2693b098db6c7"}, + {file = "pyarrow-12.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6895b5fb74289d055c43db3af0de6e16b07586c45763cb5e558d38b86a91e3a7"}, + {file = "pyarrow-12.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1887bdae17ec3b4c046fcf19951e71b6a619f39fa674f9881216173566c8f718"}, + {file = "pyarrow-12.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c9cb8eeabbadf5fcfc3d1ddea616c7ce893db2ce4dcef0ac13b099ad7ca082"}, + {file = "pyarrow-12.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:ce4aebdf412bd0eeb800d8e47db854f9f9f7e2f5a0220440acf219ddfddd4f63"}, + {file = "pyarrow-12.0.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:e0d8730c7f6e893f6db5d5b86eda42c0a130842d101992b581e2138e4d5663d3"}, + {file = "pyarrow-12.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43364daec02f69fec89d2315f7fbfbeec956e0d991cbbef471681bd77875c40f"}, + {file = "pyarrow-12.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:051f9f5ccf585f12d7de836e50965b3c235542cc896959320d9776ab93f3b33d"}, + {file = "pyarrow-12.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:be2757e9275875d2a9c6e6052ac7957fbbfc7bc7370e4a036a9b893e96fedaba"}, + {file = "pyarrow-12.0.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:cf812306d66f40f69e684300f7af5111c11f6e0d89d6b733e05a3de44961529d"}, + {file = "pyarrow-12.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:459a1c0ed2d68671188b2118c63bac91eaef6fc150c77ddd8a583e3c795737bf"}, + {file = "pyarrow-12.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85e705e33eaf666bbe508a16fd5ba27ca061e177916b7a317ba5a51bee43384c"}, + {file = "pyarrow-12.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9120c3eb2b1f6f516a3b7a9714ed860882d9ef98c4b17edcdc91d95b7528db60"}, + {file = "pyarrow-12.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:c780f4dc40460015d80fcd6a6140de80b615349ed68ef9adb653fe351778c9b3"}, + {file = "pyarrow-12.0.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:a3c63124fc26bf5f95f508f5d04e1ece8cc23a8b0af2a1e6ab2b1ec3fdc91b24"}, + {file = "pyarrow-12.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b13329f79fa4472324f8d32dc1b1216616d09bd1e77cfb13104dec5463632c36"}, + {file = "pyarrow-12.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb656150d3d12ec1396f6dde542db1675a95c0cc8366d507347b0beed96e87ca"}, + {file = "pyarrow-12.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6251e38470da97a5b2e00de5c6a049149f7b2bd62f12fa5dbb9ac674119ba71a"}, + {file = "pyarrow-12.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:3de26da901216149ce086920547dfff5cd22818c9eab67ebc41e863a5883bac7"}, + {file = "pyarrow-12.0.1.tar.gz", hash = "sha256:cce317fc96e5b71107bf1f9f184d5e54e2bd14bbf3f9a3d62819961f0af86fec"}, +] + +[package.dependencies] +numpy = ">=1.16.6" + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pydot" +version = "1.4.2" +description = "Python interface to Graphviz's Dot" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pydot-1.4.2-py2.py3-none-any.whl", hash = "sha256:66c98190c65b8d2e2382a441b4c0edfdb4f4c025ef9cb9874de478fb0793a451"}, + {file = "pydot-1.4.2.tar.gz", hash = "sha256:248081a39bcb56784deb018977e428605c1c758f10897a339fce1dd728ff007d"}, +] + +[package.dependencies] +pyparsing = ">=2.1.4" + +[[package]] +name = "pygments" +version = "2.15.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, + {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, +] + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pygraphviz" +version = "1.11" +description = "Python interface to Graphviz" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygraphviz-1.11.zip", hash = "sha256:a97eb5ced266f45053ebb1f2c6c6d29091690503e3a5c14be7f908b37b06f2d4"}, +] + +[[package]] +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pyreadline3" +version = "3.4.1" +description = "A python implementation of GNU readline." +optional = false +python-versions = "*" +files = [ + {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, + {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, +] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-json-logger" +version = "2.0.7" +description = "A python library adding a json log formatter" +optional = false +python-versions = ">=3.6" +files = [ + {file = "python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c"}, + {file = "python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd"}, +] + +[[package]] +name = "pytz" +version = "2023.3" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, + {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, +] + +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + +[[package]] +name = "pywinpty" +version = "2.0.11" +description = "Pseudo terminal support for Windows from Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pywinpty-2.0.11-cp310-none-win_amd64.whl", hash = "sha256:452f10ac9ff8ab9151aa8cea9e491a9612a12250b1899278c6a56bc184afb47f"}, + {file = "pywinpty-2.0.11-cp311-none-win_amd64.whl", hash = "sha256:6701867d42aec1239bc0fedf49a336570eb60eb886e81763db77ea2b6c533cc3"}, + {file = "pywinpty-2.0.11-cp38-none-win_amd64.whl", hash = "sha256:0ffd287751ad871141dc9724de70ea21f7fc2ff1af50861e0d232cf70739d8c4"}, + {file = "pywinpty-2.0.11-cp39-none-win_amd64.whl", hash = "sha256:e4e7f023c28ca7aa8e1313e53ba80a4d10171fe27857b7e02f99882dfe3e8638"}, + {file = "pywinpty-2.0.11.tar.gz", hash = "sha256:e244cffe29a894876e2cd251306efd0d8d64abd5ada0a46150a4a71c0b9ad5c5"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "pyzmq" +version = "25.1.0" +description = "Python bindings for 0MQ" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyzmq-25.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:1a6169e69034eaa06823da6a93a7739ff38716142b3596c180363dee729d713d"}, + {file = "pyzmq-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:19d0383b1f18411d137d891cab567de9afa609b214de68b86e20173dc624c101"}, + {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1e931d9a92f628858a50f5bdffdfcf839aebe388b82f9d2ccd5d22a38a789dc"}, + {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97d984b1b2f574bc1bb58296d3c0b64b10e95e7026f8716ed6c0b86d4679843f"}, + {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:154bddda2a351161474b36dba03bf1463377ec226a13458725183e508840df89"}, + {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cb6d161ae94fb35bb518b74bb06b7293299c15ba3bc099dccd6a5b7ae589aee3"}, + {file = "pyzmq-25.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:90146ab578931e0e2826ee39d0c948d0ea72734378f1898939d18bc9c823fcf9"}, + {file = "pyzmq-25.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:831ba20b660b39e39e5ac8603e8193f8fce1ee03a42c84ade89c36a251449d80"}, + {file = "pyzmq-25.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3a522510e3434e12aff80187144c6df556bb06fe6b9d01b2ecfbd2b5bfa5c60c"}, + {file = "pyzmq-25.1.0-cp310-cp310-win32.whl", hash = "sha256:be24a5867b8e3b9dd5c241de359a9a5217698ff616ac2daa47713ba2ebe30ad1"}, + {file = "pyzmq-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:5693dcc4f163481cf79e98cf2d7995c60e43809e325b77a7748d8024b1b7bcba"}, + {file = "pyzmq-25.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:13bbe36da3f8aaf2b7ec12696253c0bf6ffe05f4507985a8844a1081db6ec22d"}, + {file = "pyzmq-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:69511d604368f3dc58d4be1b0bad99b61ee92b44afe1cd9b7bd8c5e34ea8248a"}, + {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a983c8694667fd76d793ada77fd36c8317e76aa66eec75be2653cef2ea72883"}, + {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:332616f95eb400492103ab9d542b69d5f0ff628b23129a4bc0a2fd48da6e4e0b"}, + {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58416db767787aedbfd57116714aad6c9ce57215ffa1c3758a52403f7c68cff5"}, + {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cad9545f5801a125f162d09ec9b724b7ad9b6440151b89645241d0120e119dcc"}, + {file = "pyzmq-25.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d6128d431b8dfa888bf51c22a04d48bcb3d64431caf02b3cb943269f17fd2994"}, + {file = "pyzmq-25.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b15247c49d8cbea695b321ae5478d47cffd496a2ec5ef47131a9e79ddd7e46c"}, + {file = "pyzmq-25.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:442d3efc77ca4d35bee3547a8e08e8d4bb88dadb54a8377014938ba98d2e074a"}, + {file = "pyzmq-25.1.0-cp311-cp311-win32.whl", hash = "sha256:65346f507a815a731092421d0d7d60ed551a80d9b75e8b684307d435a5597425"}, + {file = "pyzmq-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:8b45d722046fea5a5694cba5d86f21f78f0052b40a4bbbbf60128ac55bfcc7b6"}, + {file = "pyzmq-25.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f45808eda8b1d71308c5416ef3abe958f033fdbb356984fabbfc7887bed76b3f"}, + {file = "pyzmq-25.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b697774ea8273e3c0460cf0bba16cd85ca6c46dfe8b303211816d68c492e132"}, + {file = "pyzmq-25.1.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b324fa769577fc2c8f5efcd429cef5acbc17d63fe15ed16d6dcbac2c5eb00849"}, + {file = "pyzmq-25.1.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5873d6a60b778848ce23b6c0ac26c39e48969823882f607516b91fb323ce80e5"}, + {file = "pyzmq-25.1.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f0d9e7ba6a815a12c8575ba7887da4b72483e4cfc57179af10c9b937f3f9308f"}, + {file = "pyzmq-25.1.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:414b8beec76521358b49170db7b9967d6974bdfc3297f47f7d23edec37329b00"}, + {file = "pyzmq-25.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:01f06f33e12497dca86353c354461f75275a5ad9eaea181ac0dc1662da8074fa"}, + {file = "pyzmq-25.1.0-cp36-cp36m-win32.whl", hash = "sha256:b5a07c4f29bf7cb0164664ef87e4aa25435dcc1f818d29842118b0ac1eb8e2b5"}, + {file = "pyzmq-25.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:968b0c737797c1809ec602e082cb63e9824ff2329275336bb88bd71591e94a90"}, + {file = "pyzmq-25.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:47b915ba666c51391836d7ed9a745926b22c434efa76c119f77bcffa64d2c50c"}, + {file = "pyzmq-25.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5af31493663cf76dd36b00dafbc839e83bbca8a0662931e11816d75f36155897"}, + {file = "pyzmq-25.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5489738a692bc7ee9a0a7765979c8a572520d616d12d949eaffc6e061b82b4d1"}, + {file = "pyzmq-25.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1fc56a0221bdf67cfa94ef2d6ce5513a3d209c3dfd21fed4d4e87eca1822e3a3"}, + {file = "pyzmq-25.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:75217e83faea9edbc29516fc90c817bc40c6b21a5771ecb53e868e45594826b0"}, + {file = "pyzmq-25.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3830be8826639d801de9053cf86350ed6742c4321ba4236e4b5568528d7bfed7"}, + {file = "pyzmq-25.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3575699d7fd7c9b2108bc1c6128641a9a825a58577775ada26c02eb29e09c517"}, + {file = "pyzmq-25.1.0-cp37-cp37m-win32.whl", hash = "sha256:95bd3a998d8c68b76679f6b18f520904af5204f089beebb7b0301d97704634dd"}, + {file = "pyzmq-25.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:dbc466744a2db4b7ca05589f21ae1a35066afada2f803f92369f5877c100ef62"}, + {file = "pyzmq-25.1.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:3bed53f7218490c68f0e82a29c92335daa9606216e51c64f37b48eb78f1281f4"}, + {file = "pyzmq-25.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb52e826d16c09ef87132c6e360e1879c984f19a4f62d8a935345deac43f3c12"}, + {file = "pyzmq-25.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ddbef8b53cd16467fdbfa92a712eae46dd066aa19780681a2ce266e88fbc7165"}, + {file = "pyzmq-25.1.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9301cf1d7fc1ddf668d0abbe3e227fc9ab15bc036a31c247276012abb921b5ff"}, + {file = "pyzmq-25.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e23a8c3b6c06de40bdb9e06288180d630b562db8ac199e8cc535af81f90e64b"}, + {file = "pyzmq-25.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4a82faae00d1eed4809c2f18b37f15ce39a10a1c58fe48b60ad02875d6e13d80"}, + {file = "pyzmq-25.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c8398a1b1951aaa330269c35335ae69744be166e67e0ebd9869bdc09426f3871"}, + {file = "pyzmq-25.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d40682ac60b2a613d36d8d3a0cd14fbdf8e7e0618fbb40aa9fa7b796c9081584"}, + {file = "pyzmq-25.1.0-cp38-cp38-win32.whl", hash = "sha256:33d5c8391a34d56224bccf74f458d82fc6e24b3213fc68165c98b708c7a69325"}, + {file = "pyzmq-25.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:c66b7ff2527e18554030319b1376d81560ca0742c6e0b17ff1ee96624a5f1afd"}, + {file = "pyzmq-25.1.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:af56229ea6527a849ac9fb154a059d7e32e77a8cba27e3e62a1e38d8808cb1a5"}, + {file = "pyzmq-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bdca18b94c404af6ae5533cd1bc310c4931f7ac97c148bbfd2cd4bdd62b96253"}, + {file = "pyzmq-25.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0b6b42f7055bbc562f63f3df3b63e3dd1ebe9727ff0f124c3aa7bcea7b3a00f9"}, + {file = "pyzmq-25.1.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c2fc7aad520a97d64ffc98190fce6b64152bde57a10c704b337082679e74f67"}, + {file = "pyzmq-25.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be86a26415a8b6af02cd8d782e3a9ae3872140a057f1cadf0133de685185c02b"}, + {file = "pyzmq-25.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:851fb2fe14036cfc1960d806628b80276af5424db09fe5c91c726890c8e6d943"}, + {file = "pyzmq-25.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2a21fec5c3cea45421a19ccbe6250c82f97af4175bc09de4d6dd78fb0cb4c200"}, + {file = "pyzmq-25.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bad172aba822444b32eae54c2d5ab18cd7dee9814fd5c7ed026603b8cae2d05f"}, + {file = "pyzmq-25.1.0-cp39-cp39-win32.whl", hash = "sha256:4d67609b37204acad3d566bb7391e0ecc25ef8bae22ff72ebe2ad7ffb7847158"}, + {file = "pyzmq-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:71c7b5896e40720d30cd77a81e62b433b981005bbff0cb2f739e0f8d059b5d99"}, + {file = "pyzmq-25.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cb27ef9d3bdc0c195b2dc54fcb8720e18b741624686a81942e14c8b67cc61a6"}, + {file = "pyzmq-25.1.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0c4fc2741e0513b5d5a12fe200d6785bbcc621f6f2278893a9ca7bed7f2efb7d"}, + {file = "pyzmq-25.1.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fc34fdd458ff77a2a00e3c86f899911f6f269d393ca5675842a6e92eea565bae"}, + {file = "pyzmq-25.1.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8751f9c1442624da391bbd92bd4b072def6d7702a9390e4479f45c182392ff78"}, + {file = "pyzmq-25.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:6581e886aec3135964a302a0f5eb68f964869b9efd1dbafdebceaaf2934f8a68"}, + {file = "pyzmq-25.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5482f08d2c3c42b920e8771ae8932fbaa0a67dff925fc476996ddd8155a170f3"}, + {file = "pyzmq-25.1.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7fbcafa3ea16d1de1f213c226005fea21ee16ed56134b75b2dede5a2129e62"}, + {file = "pyzmq-25.1.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:adecf6d02b1beab8d7c04bc36f22bb0e4c65a35eb0b4750b91693631d4081c70"}, + {file = "pyzmq-25.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6d39e42a0aa888122d1beb8ec0d4ddfb6c6b45aecb5ba4013c27e2f28657765"}, + {file = "pyzmq-25.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7018289b402ebf2b2c06992813523de61d4ce17bd514c4339d8f27a6f6809492"}, + {file = "pyzmq-25.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9e68ae9864d260b18f311b68d29134d8776d82e7f5d75ce898b40a88df9db30f"}, + {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e21cc00e4debe8f54c3ed7b9fcca540f46eee12762a9fa56feb8512fd9057161"}, + {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f666ae327a6899ff560d741681fdcdf4506f990595201ed39b44278c471ad98"}, + {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f5efcc29056dfe95e9c9db0dfbb12b62db9c4ad302f812931b6d21dd04a9119"}, + {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:48e5e59e77c1a83162ab3c163fc01cd2eebc5b34560341a67421b09be0891287"}, + {file = "pyzmq-25.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:108c96ebbd573d929740d66e4c3d1bdf31d5cde003b8dc7811a3c8c5b0fc173b"}, + {file = "pyzmq-25.1.0.tar.gz", hash = "sha256:80c41023465d36280e801564a69cbfce8ae85ff79b080e1913f6e90481fb8957"}, +] + +[package.dependencies] +cffi = {version = "*", markers = "implementation_name == \"pypy\""} + +[[package]] +name = "qtconsole" +version = "5.4.3" +description = "Jupyter Qt console" +optional = false +python-versions = ">= 3.7" +files = [ + {file = "qtconsole-5.4.3-py3-none-any.whl", hash = "sha256:35fd6e87b1f6d1fd41801b07e69339f8982e76afd4fa8ef35595bc6036717189"}, + {file = "qtconsole-5.4.3.tar.gz", hash = "sha256:5e4082a86a201796b2a5cfd4298352d22b158b51b57736531824715fc2a979dd"}, +] + +[package.dependencies] +ipykernel = ">=4.1" +ipython-genutils = "*" +jupyter-client = ">=4.1" +jupyter-core = "*" +packaging = "*" +pygments = "*" +pyzmq = ">=17.1" +qtpy = ">=2.0.1" +traitlets = "<5.2.1 || >5.2.1,<5.2.2 || >5.2.2" + +[package.extras] +doc = ["Sphinx (>=1.3)"] +test = ["flaky", "pytest", "pytest-qt"] + +[[package]] +name = "qtpy" +version = "2.3.1" +description = "Provides an abstraction layer on top of the various Qt bindings (PyQt5/6 and PySide2/6)." +optional = false +python-versions = ">=3.7" +files = [ + {file = "QtPy-2.3.1-py3-none-any.whl", hash = "sha256:5193d20e0b16e4d9d3bc2c642d04d9f4e2c892590bd1b9c92bfe38a95d5a2e12"}, + {file = "QtPy-2.3.1.tar.gz", hash = "sha256:a8c74982d6d172ce124d80cafd39653df78989683f760f2281ba91a6e7b9de8b"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +test = ["pytest (>=6,!=7.0.0,!=7.0.1)", "pytest-cov (>=3.0.0)", "pytest-qt"] + +[[package]] +name = "referencing" +version = "0.30.0" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.30.0-py3-none-any.whl", hash = "sha256:c257b08a399b6c2f5a3510a50d28ab5dbc7bbde049bcaf954d43c446f83ab548"}, + {file = "referencing-0.30.0.tar.gz", hash = "sha256:47237742e990457f7512c7d27486394a9aadaf876cbfaa4be65b27b4f4d47c6b"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + +[[package]] +name = "regex" +version = "2023.6.3" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.6" +files = [ + {file = "regex-2023.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:824bf3ac11001849aec3fa1d69abcb67aac3e150a933963fb12bda5151fe1bfd"}, + {file = "regex-2023.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:05ed27acdf4465c95826962528f9e8d41dbf9b1aa8531a387dee6ed215a3e9ef"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b49c764f88a79160fa64f9a7b425620e87c9f46095ef9c9920542ab2495c8bc"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8e3f1316c2293e5469f8f09dc2d76efb6c3982d3da91ba95061a7e69489a14ef"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43e1dd9d12df9004246bacb79a0e5886b3b6071b32e41f83b0acbf293f820ee8"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4959e8bcbfda5146477d21c3a8ad81b185cd252f3d0d6e4724a5ef11c012fb06"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af4dd387354dc83a3bff67127a124c21116feb0d2ef536805c454721c5d7993d"}, + {file = "regex-2023.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2239d95d8e243658b8dbb36b12bd10c33ad6e6933a54d36ff053713f129aa536"}, + {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:890e5a11c97cf0d0c550eb661b937a1e45431ffa79803b942a057c4fb12a2da2"}, + {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a8105e9af3b029f243ab11ad47c19b566482c150c754e4c717900a798806b222"}, + {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:25be746a8ec7bc7b082783216de8e9473803706723b3f6bef34b3d0ed03d57e2"}, + {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:3676f1dd082be28b1266c93f618ee07741b704ab7b68501a173ce7d8d0d0ca18"}, + {file = "regex-2023.6.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:10cb847aeb1728412c666ab2e2000ba6f174f25b2bdc7292e7dd71b16db07568"}, + {file = "regex-2023.6.3-cp310-cp310-win32.whl", hash = "sha256:dbbbfce33cd98f97f6bffb17801b0576e653f4fdb1d399b2ea89638bc8d08ae1"}, + {file = "regex-2023.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:c5f8037000eb21e4823aa485149f2299eb589f8d1fe4b448036d230c3f4e68e0"}, + {file = "regex-2023.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c123f662be8ec5ab4ea72ea300359023a5d1df095b7ead76fedcd8babbedf969"}, + {file = "regex-2023.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9edcbad1f8a407e450fbac88d89e04e0b99a08473f666a3f3de0fd292badb6aa"}, + {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcba6dae7de533c876255317c11f3abe4907ba7d9aa15d13e3d9710d4315ec0e"}, + {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29cdd471ebf9e0f2fb3cac165efedc3c58db841d83a518b082077e612d3ee5df"}, + {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12b74fbbf6cbbf9dbce20eb9b5879469e97aeeaa874145517563cca4029db65c"}, + {file = "regex-2023.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c29ca1bd61b16b67be247be87390ef1d1ef702800f91fbd1991f5c4421ebae8"}, + {file = "regex-2023.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77f09bc4b55d4bf7cc5eba785d87001d6757b7c9eec237fe2af57aba1a071d9"}, + {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ea353ecb6ab5f7e7d2f4372b1e779796ebd7b37352d290096978fea83c4dba0c"}, + {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:10590510780b7541969287512d1b43f19f965c2ece6c9b1c00fc367b29d8dce7"}, + {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e2fbd6236aae3b7f9d514312cdb58e6494ee1c76a9948adde6eba33eb1c4264f"}, + {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:6b2675068c8b56f6bfd5a2bda55b8accbb96c02fd563704732fd1c95e2083461"}, + {file = "regex-2023.6.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74419d2b50ecb98360cfaa2974da8689cb3b45b9deff0dcf489c0d333bcc1477"}, + {file = "regex-2023.6.3-cp311-cp311-win32.whl", hash = "sha256:fb5ec16523dc573a4b277663a2b5a364e2099902d3944c9419a40ebd56a118f9"}, + {file = "regex-2023.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:09e4a1a6acc39294a36b7338819b10baceb227f7f7dbbea0506d419b5a1dd8af"}, + {file = "regex-2023.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0654bca0cdf28a5956c83839162692725159f4cda8d63e0911a2c0dc76166525"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:463b6a3ceb5ca952e66550a4532cef94c9a0c80dc156c4cc343041951aec1697"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87b2a5bb5e78ee0ad1de71c664d6eb536dc3947a46a69182a90f4410f5e3f7dd"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6343c6928282c1f6a9db41f5fd551662310e8774c0e5ebccb767002fcf663ca9"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6192d5af2ccd2a38877bfef086d35e6659566a335b1492786ff254c168b1693"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74390d18c75054947e4194019077e243c06fbb62e541d8817a0fa822ea310c14"}, + {file = "regex-2023.6.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:742e19a90d9bb2f4a6cf2862b8b06dea5e09b96c9f2df1779e53432d7275331f"}, + {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8abbc5d54ea0ee80e37fef009e3cec5dafd722ed3c829126253d3e22f3846f1e"}, + {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:c2b867c17a7a7ae44c43ebbeb1b5ff406b3e8d5b3e14662683e5e66e6cc868d3"}, + {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:d831c2f8ff278179705ca59f7e8524069c1a989e716a1874d6d1aab6119d91d1"}, + {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ee2d1a9a253b1729bb2de27d41f696ae893507c7db224436abe83ee25356f5c1"}, + {file = "regex-2023.6.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:61474f0b41fe1a80e8dfa70f70ea1e047387b7cd01c85ec88fa44f5d7561d787"}, + {file = "regex-2023.6.3-cp36-cp36m-win32.whl", hash = "sha256:0b71e63226e393b534105fcbdd8740410dc6b0854c2bfa39bbda6b0d40e59a54"}, + {file = "regex-2023.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bbb02fd4462f37060122e5acacec78e49c0fbb303c30dd49c7f493cf21fc5b27"}, + {file = "regex-2023.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b862c2b9d5ae38a68b92e215b93f98d4c5e9454fa36aae4450f61dd33ff48487"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:976d7a304b59ede34ca2921305b57356694f9e6879db323fd90a80f865d355a3"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:83320a09188e0e6c39088355d423aa9d056ad57a0b6c6381b300ec1a04ec3d16"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9427a399501818a7564f8c90eced1e9e20709ece36be701f394ada99890ea4b3"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178bbc1b2ec40eaca599d13c092079bf529679bf0371c602edaa555e10b41c3"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:837328d14cde912af625d5f303ec29f7e28cdab588674897baafaf505341f2fc"}, + {file = "regex-2023.6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d44dc13229905ae96dd2ae2dd7cebf824ee92bc52e8cf03dcead37d926da019"}, + {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d54af539295392611e7efbe94e827311eb8b29668e2b3f4cadcfe6f46df9c777"}, + {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7117d10690c38a622e54c432dfbbd3cbd92f09401d622902c32f6d377e2300ee"}, + {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bb60b503ec8a6e4e3e03a681072fa3a5adcbfa5479fa2d898ae2b4a8e24c4591"}, + {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:65ba8603753cec91c71de423a943ba506363b0e5c3fdb913ef8f9caa14b2c7e0"}, + {file = "regex-2023.6.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:271f0bdba3c70b58e6f500b205d10a36fb4b58bd06ac61381b68de66442efddb"}, + {file = "regex-2023.6.3-cp37-cp37m-win32.whl", hash = "sha256:9beb322958aaca059f34975b0df135181f2e5d7a13b84d3e0e45434749cb20f7"}, + {file = "regex-2023.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fea75c3710d4f31389eed3c02f62d0b66a9da282521075061ce875eb5300cf23"}, + {file = "regex-2023.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f56fcb7ff7bf7404becdfc60b1e81a6d0561807051fd2f1860b0d0348156a07"}, + {file = "regex-2023.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d2da3abc88711bce7557412310dfa50327d5769a31d1c894b58eb256459dc289"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a99b50300df5add73d307cf66abea093304a07eb017bce94f01e795090dea87c"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5708089ed5b40a7b2dc561e0c8baa9535b77771b64a8330b684823cfd5116036"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:687ea9d78a4b1cf82f8479cab23678aff723108df3edeac098e5b2498879f4a7"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3850beab9f527f06ccc94b446c864059c57651b3f911fddb8d9d3ec1d1b25d"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8915cc96abeb8983cea1df3c939e3c6e1ac778340c17732eb63bb96247b91d2"}, + {file = "regex-2023.6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:841d6e0e5663d4c7b4c8099c9997be748677d46cbf43f9f471150e560791f7ff"}, + {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9edce5281f965cf135e19840f4d93d55b3835122aa76ccacfd389e880ba4cf82"}, + {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b956231ebdc45f5b7a2e1f90f66a12be9610ce775fe1b1d50414aac1e9206c06"}, + {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:36efeba71c6539d23c4643be88295ce8c82c88bbd7c65e8a24081d2ca123da3f"}, + {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:cf67ca618b4fd34aee78740bea954d7c69fdda419eb208c2c0c7060bb822d747"}, + {file = "regex-2023.6.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b4598b1897837067a57b08147a68ac026c1e73b31ef6e36deeeb1fa60b2933c9"}, + {file = "regex-2023.6.3-cp38-cp38-win32.whl", hash = "sha256:f415f802fbcafed5dcc694c13b1292f07fe0befdb94aa8a52905bd115ff41e88"}, + {file = "regex-2023.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:d4f03bb71d482f979bda92e1427f3ec9b220e62a7dd337af0aa6b47bf4498f72"}, + {file = "regex-2023.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ccf91346b7bd20c790310c4147eee6ed495a54ddb6737162a36ce9dbef3e4751"}, + {file = "regex-2023.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b28f5024a3a041009eb4c333863d7894d191215b39576535c6734cd88b0fcb68"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0bb18053dfcfed432cc3ac632b5e5e5c5b7e55fb3f8090e867bfd9b054dbcbf"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a5bfb3004f2144a084a16ce19ca56b8ac46e6fd0651f54269fc9e230edb5e4a"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c6b48d0fa50d8f4df3daf451be7f9689c2bde1a52b1225c5926e3f54b6a9ed1"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:051da80e6eeb6e239e394ae60704d2b566aa6a7aed6f2890a7967307267a5dc6"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4c3b7fa4cdaa69268748665a1a6ff70c014d39bb69c50fda64b396c9116cf77"}, + {file = "regex-2023.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:457b6cce21bee41ac292d6753d5e94dcbc5c9e3e3a834da285b0bde7aa4a11e9"}, + {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aad51907d74fc183033ad796dd4c2e080d1adcc4fd3c0fd4fd499f30c03011cd"}, + {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0385e73da22363778ef2324950e08b689abdf0b108a7d8decb403ad7f5191938"}, + {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c6a57b742133830eec44d9b2290daf5cbe0a2f1d6acee1b3c7b1c7b2f3606df7"}, + {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3e5219bf9e75993d73ab3d25985c857c77e614525fac9ae02b1bebd92f7cecac"}, + {file = "regex-2023.6.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e5087a3c59eef624a4591ef9eaa6e9a8d8a94c779dade95d27c0bc24650261cd"}, + {file = "regex-2023.6.3-cp39-cp39-win32.whl", hash = "sha256:20326216cc2afe69b6e98528160b225d72f85ab080cbdf0b11528cbbaba2248f"}, + {file = "regex-2023.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:bdff5eab10e59cf26bc479f565e25ed71a7d041d1ded04ccf9aee1d9f208487a"}, + {file = "regex-2023.6.3.tar.gz", hash = "sha256:72d1a25bf36d2050ceb35b517afe13864865268dfb45910e2e17a84be6cbfeb0"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +description = "A pure python RFC3339 validator" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"}, + {file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"}, +] + +[package.dependencies] +six = "*" + +[[package]] +name = "rfc3986-validator" +version = "0.1.1" +description = "Pure python rfc3986 validator" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9"}, + {file = "rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055"}, +] + +[[package]] +name = "rpds-py" +version = "0.9.2" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.9.2-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:ab6919a09c055c9b092798ce18c6c4adf49d24d4d9e43a92b257e3f2548231e7"}, + {file = "rpds_py-0.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d55777a80f78dd09410bd84ff8c95ee05519f41113b2df90a69622f5540c4f8b"}, + {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a216b26e5af0a8e265d4efd65d3bcec5fba6b26909014effe20cd302fd1138fa"}, + {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29cd8bfb2d716366a035913ced99188a79b623a3512292963d84d3e06e63b496"}, + {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44659b1f326214950a8204a248ca6199535e73a694be8d3e0e869f820767f12f"}, + {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:745f5a43fdd7d6d25a53ab1a99979e7f8ea419dfefebcab0a5a1e9095490ee5e"}, + {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a987578ac5214f18b99d1f2a3851cba5b09f4a689818a106c23dbad0dfeb760f"}, + {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf4151acb541b6e895354f6ff9ac06995ad9e4175cbc6d30aaed08856558201f"}, + {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:03421628f0dc10a4119d714a17f646e2837126a25ac7a256bdf7c3943400f67f"}, + {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:13b602dc3e8dff3063734f02dcf05111e887f301fdda74151a93dbbc249930fe"}, + {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fae5cb554b604b3f9e2c608241b5d8d303e410d7dfb6d397c335f983495ce7f6"}, + {file = "rpds_py-0.9.2-cp310-none-win32.whl", hash = "sha256:47c5f58a8e0c2c920cc7783113df2fc4ff12bf3a411d985012f145e9242a2764"}, + {file = "rpds_py-0.9.2-cp310-none-win_amd64.whl", hash = "sha256:4ea6b73c22d8182dff91155af018b11aac9ff7eca085750455c5990cb1cfae6e"}, + {file = "rpds_py-0.9.2-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:e564d2238512c5ef5e9d79338ab77f1cbbda6c2d541ad41b2af445fb200385e3"}, + {file = "rpds_py-0.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f411330a6376fb50e5b7a3e66894e4a39e60ca2e17dce258d53768fea06a37bd"}, + {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e7521f5af0233e89939ad626b15278c71b69dc1dfccaa7b97bd4cdf96536bb7"}, + {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8d3335c03100a073883857e91db9f2e0ef8a1cf42dc0369cbb9151c149dbbc1b"}, + {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d25b1c1096ef0447355f7293fbe9ad740f7c47ae032c2884113f8e87660d8f6e"}, + {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a5d3fbd02efd9cf6a8ffc2f17b53a33542f6b154e88dd7b42ef4a4c0700fdad"}, + {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5934e2833afeaf36bd1eadb57256239785f5af0220ed8d21c2896ec4d3a765f"}, + {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:095b460e117685867d45548fbd8598a8d9999227e9061ee7f012d9d264e6048d"}, + {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:91378d9f4151adc223d584489591dbb79f78814c0734a7c3bfa9c9e09978121c"}, + {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:24a81c177379300220e907e9b864107614b144f6c2a15ed5c3450e19cf536fae"}, + {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:de0b6eceb46141984671802d412568d22c6bacc9b230174f9e55fc72ef4f57de"}, + {file = "rpds_py-0.9.2-cp311-none-win32.whl", hash = "sha256:700375326ed641f3d9d32060a91513ad668bcb7e2cffb18415c399acb25de2ab"}, + {file = "rpds_py-0.9.2-cp311-none-win_amd64.whl", hash = "sha256:0766babfcf941db8607bdaf82569ec38107dbb03c7f0b72604a0b346b6eb3298"}, + {file = "rpds_py-0.9.2-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:b1440c291db3f98a914e1afd9d6541e8fc60b4c3aab1a9008d03da4651e67386"}, + {file = "rpds_py-0.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0f2996fbac8e0b77fd67102becb9229986396e051f33dbceada3debaacc7033f"}, + {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f30d205755566a25f2ae0382944fcae2f350500ae4df4e795efa9e850821d82"}, + {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:159fba751a1e6b1c69244e23ba6c28f879a8758a3e992ed056d86d74a194a0f3"}, + {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1f044792e1adcea82468a72310c66a7f08728d72a244730d14880cd1dabe36b"}, + {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9251eb8aa82e6cf88510530b29eef4fac825a2b709baf5b94a6094894f252387"}, + {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01899794b654e616c8625b194ddd1e5b51ef5b60ed61baa7a2d9c2ad7b2a4238"}, + {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0c43f8ae8f6be1d605b0465671124aa8d6a0e40f1fb81dcea28b7e3d87ca1e1"}, + {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:207f57c402d1f8712618f737356e4b6f35253b6d20a324d9a47cb9f38ee43a6b"}, + {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b52e7c5ae35b00566d244ffefba0f46bb6bec749a50412acf42b1c3f402e2c90"}, + {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:978fa96dbb005d599ec4fd9ed301b1cc45f1a8f7982d4793faf20b404b56677d"}, + {file = "rpds_py-0.9.2-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:6aa8326a4a608e1c28da191edd7c924dff445251b94653988efb059b16577a4d"}, + {file = "rpds_py-0.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aad51239bee6bff6823bbbdc8ad85136c6125542bbc609e035ab98ca1e32a192"}, + {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd4dc3602370679c2dfb818d9c97b1137d4dd412230cfecd3c66a1bf388a196"}, + {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd9da77c6ec1f258387957b754f0df60766ac23ed698b61941ba9acccd3284d1"}, + {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:190ca6f55042ea4649ed19c9093a9be9d63cd8a97880106747d7147f88a49d18"}, + {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:876bf9ed62323bc7dcfc261dbc5572c996ef26fe6406b0ff985cbcf460fc8a4c"}, + {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa2818759aba55df50592ecbc95ebcdc99917fa7b55cc6796235b04193eb3c55"}, + {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9ea4d00850ef1e917815e59b078ecb338f6a8efda23369677c54a5825dbebb55"}, + {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5855c85eb8b8a968a74dc7fb014c9166a05e7e7a8377fb91d78512900aadd13d"}, + {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:14c408e9d1a80dcb45c05a5149e5961aadb912fff42ca1dd9b68c0044904eb32"}, + {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:65a0583c43d9f22cb2130c7b110e695fff834fd5e832a776a107197e59a1898e"}, + {file = "rpds_py-0.9.2-cp38-none-win32.whl", hash = "sha256:71f2f7715935a61fa3e4ae91d91b67e571aeb5cb5d10331ab681256bda2ad920"}, + {file = "rpds_py-0.9.2-cp38-none-win_amd64.whl", hash = "sha256:674c704605092e3ebbbd13687b09c9f78c362a4bc710343efe37a91457123044"}, + {file = "rpds_py-0.9.2-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:07e2c54bef6838fa44c48dfbc8234e8e2466d851124b551fc4e07a1cfeb37260"}, + {file = "rpds_py-0.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fdf55283ad38c33e35e2855565361f4bf0abd02470b8ab28d499c663bc5d7c"}, + {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:890ba852c16ace6ed9f90e8670f2c1c178d96510a21b06d2fa12d8783a905193"}, + {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50025635ba8b629a86d9d5474e650da304cb46bbb4d18690532dd79341467846"}, + {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:517cbf6e67ae3623c5127206489d69eb2bdb27239a3c3cc559350ef52a3bbf0b"}, + {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0836d71ca19071090d524739420a61580f3f894618d10b666cf3d9a1688355b1"}, + {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c439fd54b2b9053717cca3de9583be6584b384d88d045f97d409f0ca867d80f"}, + {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f68996a3b3dc9335037f82754f9cdbe3a95db42bde571d8c3be26cc6245f2324"}, + {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7d68dc8acded354c972116f59b5eb2e5864432948e098c19fe6994926d8e15c3"}, + {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f963c6b1218b96db85fc37a9f0851eaf8b9040aa46dec112611697a7023da535"}, + {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a46859d7f947061b4010e554ccd1791467d1b1759f2dc2ec9055fa239f1bc26"}, + {file = "rpds_py-0.9.2-cp39-none-win32.whl", hash = "sha256:e07e5dbf8a83c66783a9fe2d4566968ea8c161199680e8ad38d53e075df5f0d0"}, + {file = "rpds_py-0.9.2-cp39-none-win_amd64.whl", hash = "sha256:682726178138ea45a0766907957b60f3a1bf3acdf212436be9733f28b6c5af3c"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:196cb208825a8b9c8fc360dc0f87993b8b260038615230242bf18ec84447c08d"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c7671d45530fcb6d5e22fd40c97e1e1e01965fc298cbda523bb640f3d923b387"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83b32f0940adec65099f3b1c215ef7f1d025d13ff947975a055989cb7fd019a4"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f67da97f5b9eac838b6980fc6da268622e91f8960e083a34533ca710bec8611"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03975db5f103997904c37e804e5f340c8fdabbb5883f26ee50a255d664eed58c"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:987b06d1cdb28f88a42e4fb8a87f094e43f3c435ed8e486533aea0bf2e53d931"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c861a7e4aef15ff91233751619ce3a3d2b9e5877e0fcd76f9ea4f6847183aa16"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02938432352359805b6da099c9c95c8a0547fe4b274ce8f1a91677401bb9a45f"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef1f08f2a924837e112cba2953e15aacfccbbfcd773b4b9b4723f8f2ddded08e"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:35da5cc5cb37c04c4ee03128ad59b8c3941a1e5cd398d78c37f716f32a9b7f67"}, + {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:141acb9d4ccc04e704e5992d35472f78c35af047fa0cfae2923835d153f091be"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79f594919d2c1a0cc17d1988a6adaf9a2f000d2e1048f71f298b056b1018e872"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:a06418fe1155e72e16dddc68bb3780ae44cebb2912fbd8bb6ff9161de56e1798"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b2eb034c94b0b96d5eddb290b7b5198460e2d5d0c421751713953a9c4e47d10"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b08605d248b974eb02f40bdcd1a35d3924c83a2a5e8f5d0fa5af852c4d960af"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0805911caedfe2736935250be5008b261f10a729a303f676d3d5fea6900c96a"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab2299e3f92aa5417d5e16bb45bb4586171c1327568f638e8453c9f8d9e0f020"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c8d7594e38cf98d8a7df25b440f684b510cf4627fe038c297a87496d10a174f"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b9ec12ad5f0a4625db34db7e0005be2632c1013b253a4a60e8302ad4d462afd"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1fcdee18fea97238ed17ab6478c66b2095e4ae7177e35fb71fbe561a27adf620"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:933a7d5cd4b84f959aedeb84f2030f0a01d63ae6cf256629af3081cf3e3426e8"}, + {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:686ba516e02db6d6f8c279d1641f7067ebb5dc58b1d0536c4aaebb7bf01cdc5d"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0173c0444bec0a3d7d848eaeca2d8bd32a1b43f3d3fde6617aac3731fa4be05f"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d576c3ef8c7b2d560e301eb33891d1944d965a4d7a2eacb6332eee8a71827db6"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed89861ee8c8c47d6beb742a602f912b1bb64f598b1e2f3d758948721d44d468"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1054a08e818f8e18910f1bee731583fe8f899b0a0a5044c6e680ceea34f93876"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e7c4bb27ff1aab90dcc3e9d37ee5af0231ed98d99cb6f5250de28889a3d502"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c545d9d14d47be716495076b659db179206e3fd997769bc01e2d550eeb685596"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9039a11bca3c41be5a58282ed81ae422fa680409022b996032a43badef2a3752"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fb39aca7a64ad0c9490adfa719dbeeb87d13be137ca189d2564e596f8ba32c07"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2d8b3b3a2ce0eaa00c5bbbb60b6713e94e7e0becab7b3db6c5c77f979e8ed1f1"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:99b1c16f732b3a9971406fbfe18468592c5a3529585a45a35adbc1389a529a03"}, + {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c27ee01a6c3223025f4badd533bea5e87c988cb0ba2811b690395dfe16088cfe"}, + {file = "rpds_py-0.9.2.tar.gz", hash = "sha256:8d70e8f14900f2657c249ea4def963bed86a29b81f81f5b76b5a9215680de945"}, +] + +[[package]] +name = "safetensors" +version = "0.3.1" +description = "Fast and Safe Tensor serialization" +optional = false +python-versions = "*" +files = [ + {file = "safetensors-0.3.1-cp310-cp310-macosx_10_11_x86_64.whl", hash = "sha256:2ae9b7dd268b4bae6624729dac86deb82104820e9786429b0583e5168db2f770"}, + {file = "safetensors-0.3.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:08c85c1934682f1e2cd904d38433b53cd2a98245a7cc31f5689f9322a2320bbf"}, + {file = "safetensors-0.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba625c7af9e1c5d0d91cb83d2fba97d29ea69d4db2015d9714d24c7f6d488e15"}, + {file = "safetensors-0.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b57d5890c619ec10d9f1b6426b8690d0c9c2868a90dc52f13fae6f6407ac141f"}, + {file = "safetensors-0.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c9f562ea696d50b95cadbeb1716dc476714a87792ffe374280c0835312cbfe2"}, + {file = "safetensors-0.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c115951b3a865ece8d98ee43882f2fd0a999c0200d6e6fec24134715ebe3b57"}, + {file = "safetensors-0.3.1-cp310-cp310-win32.whl", hash = "sha256:118f8f7503ea312fc7af27e934088a1b589fb1eff5a7dea2cd1de6c71ee33391"}, + {file = "safetensors-0.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:54846eaae25fded28a7bebbb66be563cad221b4c80daee39e2f55df5e5e0266f"}, + {file = "safetensors-0.3.1-cp311-cp311-macosx_10_11_universal2.whl", hash = "sha256:5af82e10946c4822506db0f29269f43147e889054704dde994d4e22f0c37377b"}, + {file = "safetensors-0.3.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:626c86dd1d930963c8ea7f953a3787ae85322551e3a5203ac731d6e6f3e18f44"}, + {file = "safetensors-0.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12e30677e6af1f4cc4f2832546e91dbb3b0aa7d575bfa473d2899d524e1ace08"}, + {file = "safetensors-0.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d534b80bc8d39945bb902f34b0454773971fe9e5e1f2142af451759d7e52b356"}, + {file = "safetensors-0.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ddd0ddd502cf219666e7d30f23f196cb87e829439b52b39f3e7da7918c3416df"}, + {file = "safetensors-0.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997a2cc14023713f423e6d16536d55cb16a3d72850f142e05f82f0d4c76d383b"}, + {file = "safetensors-0.3.1-cp311-cp311-win32.whl", hash = "sha256:6ae9ca63d9e22f71ec40550207bd284a60a6b4916ae6ca12c85a8d86bf49e0c3"}, + {file = "safetensors-0.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:62aa7421ca455418423e35029524489480adda53e3f702453580180ecfebe476"}, + {file = "safetensors-0.3.1-cp37-cp37m-macosx_10_11_x86_64.whl", hash = "sha256:6d54b3ed367b6898baab75dfd057c24f36ec64d3938ffff2af981d56bfba2f42"}, + {file = "safetensors-0.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:262423aeda91117010f8c607889066028f680fbb667f50cfe6eae96f22f9d150"}, + {file = "safetensors-0.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10efe2513a8327fd628cea13167089588acc23093ba132aecfc536eb9a4560fe"}, + {file = "safetensors-0.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:689b3d6a7ebce70ee9438267ee55ea89b575c19923876645e927d08757b552fe"}, + {file = "safetensors-0.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14cd9a87bc73ce06903e9f8ee8b05b056af6f3c9f37a6bd74997a16ed36ff5f4"}, + {file = "safetensors-0.3.1-cp37-cp37m-win32.whl", hash = "sha256:a77cb39624480d5f143c1cc272184f65a296f573d61629eff5d495d2e0541d3e"}, + {file = "safetensors-0.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9eff3190bfbbb52eef729911345c643f875ca4dbb374aa6c559675cfd0ab73db"}, + {file = "safetensors-0.3.1-cp38-cp38-macosx_10_11_x86_64.whl", hash = "sha256:05cbfef76e4daa14796db1bbb52072d4b72a44050c368b2b1f6fd3e610669a89"}, + {file = "safetensors-0.3.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:c49061461f4a81e5ec3415070a3f135530834c89cbd6a7db7cd49e3cb9d9864b"}, + {file = "safetensors-0.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22cf7e73ca42974f098ce0cf4dd8918983700b6b07a4c6827d50c8daefca776e"}, + {file = "safetensors-0.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04f909442d6223ff0016cd2e1b2a95ef8039b92a558014627363a2e267213f62"}, + {file = "safetensors-0.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c573c5a0d5d45791ae8c179e26d74aff86e719056591aa7edb3ca7be55bc961"}, + {file = "safetensors-0.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6994043b12e717cf2a6ba69077ac41f0d3675b2819734f07f61819e854c622c7"}, + {file = "safetensors-0.3.1-cp38-cp38-win32.whl", hash = "sha256:158ede81694180a0dbba59422bc304a78c054b305df993c0c6e39c6330fa9348"}, + {file = "safetensors-0.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:afdc725beff7121ea8d39a7339f5a6abcb01daa189ea56290b67fe262d56e20f"}, + {file = "safetensors-0.3.1-cp39-cp39-macosx_10_11_x86_64.whl", hash = "sha256:cba910fcc9e5e64d32d62b837388721165e9c7e45d23bc3a38ad57694b77f40d"}, + {file = "safetensors-0.3.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:a4f7dbfe7285573cdaddd85ef6fa84ebbed995d3703ab72d71257944e384612f"}, + {file = "safetensors-0.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54aed0802f9eaa83ca7b1cbb986bfb90b8e2c67b6a4bcfe245627e17dad565d4"}, + {file = "safetensors-0.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34b75a766f3cfc99fd4c33e329b76deae63f5f388e455d863a5d6e99472fca8e"}, + {file = "safetensors-0.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a0f31904f35dc14919a145b2d7a2d8842a43a18a629affe678233c4ea90b4af"}, + {file = "safetensors-0.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcf527ecc5f58907fd9031510378105487f318cc91ecdc5aee3c7cc8f46030a8"}, + {file = "safetensors-0.3.1-cp39-cp39-win32.whl", hash = "sha256:e2f083112cf97aa9611e2a05cc170a2795eccec5f6ff837f4565f950670a9d83"}, + {file = "safetensors-0.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:5f4f614b8e8161cd8a9ca19c765d176a82b122fa3d3387b77862145bfe9b4e93"}, + {file = "safetensors-0.3.1.tar.gz", hash = "sha256:571da56ff8d0bec8ae54923b621cda98d36dcef10feb36fd492c4d0c2cd0e869"}, +] + +[package.extras] +all = ["black (==22.3)", "click (==8.0.4)", "flake8 (>=3.8.3)", "flax (>=0.6.3)", "h5py (>=3.7.0)", "huggingface-hub (>=0.12.1)", "isort (>=5.5.4)", "jax (>=0.3.25)", "jaxlib (>=0.3.25)", "numpy (>=1.21.6)", "paddlepaddle (>=2.4.1)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "setuptools-rust (>=1.5.2)", "tensorflow (>=2.11.0)", "torch (>=1.10)"] +dev = ["black (==22.3)", "click (==8.0.4)", "flake8 (>=3.8.3)", "flax (>=0.6.3)", "h5py (>=3.7.0)", "huggingface-hub (>=0.12.1)", "isort (>=5.5.4)", "jax (>=0.3.25)", "jaxlib (>=0.3.25)", "numpy (>=1.21.6)", "paddlepaddle (>=2.4.1)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "setuptools-rust (>=1.5.2)", "tensorflow (>=2.11.0)", "torch (>=1.10)"] +jax = ["flax (>=0.6.3)", "jax (>=0.3.25)", "jaxlib (>=0.3.25)"] +numpy = ["numpy (>=1.21.6)"] +paddlepaddle = ["paddlepaddle (>=2.4.1)"] +quality = ["black (==22.3)", "click (==8.0.4)", "flake8 (>=3.8.3)", "isort (>=5.5.4)"] +tensorflow = ["tensorflow (>=2.11.0)"] +testing = ["h5py (>=3.7.0)", "huggingface-hub (>=0.12.1)", "numpy (>=1.21.6)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "setuptools-rust (>=1.5.2)"] +torch = ["torch (>=1.10)"] + +[[package]] +name = "scikit-learn" +version = "1.3.0" +description = "A set of python modules for machine learning and data mining" +optional = false +python-versions = ">=3.8" +files = [ + {file = "scikit-learn-1.3.0.tar.gz", hash = "sha256:8be549886f5eda46436b6e555b0e4873b4f10aa21c07df45c4bc1735afbccd7a"}, + {file = "scikit_learn-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:981287869e576d42c682cf7ca96af0c6ac544ed9316328fd0d9292795c742cf5"}, + {file = "scikit_learn-1.3.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:436aaaae2c916ad16631142488e4c82f4296af2404f480e031d866863425d2a2"}, + {file = "scikit_learn-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7e28d8fa47a0b30ae1bd7a079519dd852764e31708a7804da6cb6f8b36e3630"}, + {file = "scikit_learn-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae80c08834a473d08a204d966982a62e11c976228d306a2648c575e3ead12111"}, + {file = "scikit_learn-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:552fd1b6ee22900cf1780d7386a554bb96949e9a359999177cf30211e6b20df6"}, + {file = "scikit_learn-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79970a6d759eb00a62266a31e2637d07d2d28446fca8079cf9afa7c07b0427f8"}, + {file = "scikit_learn-1.3.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:850a00b559e636b23901aabbe79b73dc604b4e4248ba9e2d6e72f95063765603"}, + {file = "scikit_learn-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee04835fb016e8062ee9fe9074aef9b82e430504e420bff51e3e5fffe72750ca"}, + {file = "scikit_learn-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d953531f5d9f00c90c34fa3b7d7cfb43ecff4c605dac9e4255a20b114a27369"}, + {file = "scikit_learn-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:151ac2bf65ccf363664a689b8beafc9e6aae36263db114b4ca06fbbbf827444a"}, + {file = "scikit_learn-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6a885a9edc9c0a341cab27ec4f8a6c58b35f3d449c9d2503a6fd23e06bbd4f6a"}, + {file = "scikit_learn-1.3.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:9877af9c6d1b15486e18a94101b742e9d0d2f343d35a634e337411ddb57783f3"}, + {file = "scikit_learn-1.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c470f53cea065ff3d588050955c492793bb50c19a92923490d18fcb637f6383a"}, + {file = "scikit_learn-1.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6e2d7389542eae01077a1ee0318c4fec20c66c957f45c7aac0c6eb0fe3c612"}, + {file = "scikit_learn-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:3a11936adbc379a6061ea32fa03338d4ca7248d86dd507c81e13af428a5bc1db"}, + {file = "scikit_learn-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:998d38fcec96584deee1e79cd127469b3ad6fefd1ea6c2dfc54e8db367eb396b"}, + {file = "scikit_learn-1.3.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ded35e810438a527e17623ac6deae3b360134345b7c598175ab7741720d7ffa7"}, + {file = "scikit_learn-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8102d5036e28d08ab47166b48c8d5e5810704daecf3a476a4282d562be9a28"}, + {file = "scikit_learn-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7617164951c422747e7c32be4afa15d75ad8044f42e7d70d3e2e0429a50e6718"}, + {file = "scikit_learn-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:1d54fb9e6038284548072df22fd34777e434153f7ffac72c8596f2d6987110dd"}, +] + +[package.dependencies] +joblib = ">=1.1.1" +numpy = ">=1.17.3" +scipy = ">=1.5.0" +threadpoolctl = ">=2.0.0" + +[package.extras] +benchmark = ["matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.10.1)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] +examples = ["matplotlib (>=3.1.3)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"] +tests = ["black (>=23.3.0)", "matplotlib (>=3.1.3)", "mypy (>=1.3)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.0.272)", "scikit-image (>=0.16.2)"] + +[[package]] +name = "scipy" +version = "1.9.3" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "scipy-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1884b66a54887e21addf9c16fb588720a8309a57b2e258ae1c7986d4444d3bc0"}, + {file = "scipy-1.9.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:83b89e9586c62e787f5012e8475fbb12185bafb996a03257e9675cd73d3736dd"}, + {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a72d885fa44247f92743fc20732ae55564ff2a519e8302fb7e18717c5355a8b"}, + {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01e1dd7b15bd2449c8bfc6b7cc67d630700ed655654f0dfcf121600bad205c9"}, + {file = "scipy-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:68239b6aa6f9c593da8be1509a05cb7f9efe98b80f43a5861cd24c7557e98523"}, + {file = "scipy-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b41bc822679ad1c9a5f023bc93f6d0543129ca0f37c1ce294dd9d386f0a21096"}, + {file = "scipy-1.9.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:90453d2b93ea82a9f434e4e1cba043e779ff67b92f7a0e85d05d286a3625df3c"}, + {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c06e62a390a9167da60bedd4575a14c1f58ca9dfde59830fc42e5197283dab"}, + {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abaf921531b5aeaafced90157db505e10345e45038c39e5d9b6c7922d68085cb"}, + {file = "scipy-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:06d2e1b4c491dc7d8eacea139a1b0b295f74e1a1a0f704c375028f8320d16e31"}, + {file = "scipy-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a04cd7d0d3eff6ea4719371cbc44df31411862b9646db617c99718ff68d4840"}, + {file = "scipy-1.9.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:545c83ffb518094d8c9d83cce216c0c32f8c04aaf28b92cc8283eda0685162d5"}, + {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d54222d7a3ba6022fdf5773931b5d7c56efe41ede7f7128c7b1637700409108"}, + {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cff3a5295234037e39500d35316a4c5794739433528310e117b8a9a0c76d20fc"}, + {file = "scipy-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:2318bef588acc7a574f5bfdff9c172d0b1bf2c8143d9582e05f878e580a3781e"}, + {file = "scipy-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d644a64e174c16cb4b2e41dfea6af722053e83d066da7343f333a54dae9bc31c"}, + {file = "scipy-1.9.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:da8245491d73ed0a994ed9c2e380fd058ce2fa8a18da204681f2fe1f57f98f95"}, + {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4db5b30849606a95dcf519763dd3ab6fe9bd91df49eba517359e450a7d80ce2e"}, + {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c68db6b290cbd4049012990d7fe71a2abd9ffbe82c0056ebe0f01df8be5436b0"}, + {file = "scipy-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:5b88e6d91ad9d59478fafe92a7c757d00c59e3bdc3331be8ada76a4f8d683f58"}, + {file = "scipy-1.9.3.tar.gz", hash = "sha256:fbc5c05c85c1a02be77b1ff591087c83bc44579c6d2bd9fb798bb64ea5e1a027"}, +] + +[package.dependencies] +numpy = ">=1.18.5,<1.26.0" + +[package.extras] +dev = ["flake8", "mypy", "pycodestyle", "typing_extensions"] +doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-panels (>=0.5.2)", "sphinx-tabs"] +test = ["asv", "gmpy2", "mpmath", "pytest", "pytest-cov", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "send2trash" +version = "1.8.2" +description = "Send file to trash natively under Mac OS X, Windows and Linux" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "Send2Trash-1.8.2-py3-none-any.whl", hash = "sha256:a384719d99c07ce1eefd6905d2decb6f8b7ed054025bb0e618919f945de4f679"}, + {file = "Send2Trash-1.8.2.tar.gz", hash = "sha256:c132d59fa44b9ca2b1699af5c86f57ce9f4c5eb56629d5d55fbb7a35f84e2312"}, +] + +[package.extras] +nativelib = ["pyobjc-framework-Cocoa", "pywin32"] +objc = ["pyobjc-framework-Cocoa"] +win32 = ["pywin32"] + +[[package]] +name = "sentence-transformers" +version = "2.2.2" +description = "Multilingual text embeddings" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "sentence-transformers-2.2.2.tar.gz", hash = "sha256:dbc60163b27de21076c9a30d24b5b7b6fa05141d68cf2553fa9a77bf79a29136"}, +] + +[package.dependencies] +huggingface-hub = ">=0.4.0" +nltk = "*" +numpy = "*" +scikit-learn = "*" +scipy = "*" +sentencepiece = "*" +torch = ">=1.6.0" +torchvision = "*" +tqdm = "*" +transformers = ">=4.6.0,<5.0.0" + +[[package]] +name = "sentencepiece" +version = "0.1.99" +description = "SentencePiece python wrapper" +optional = false +python-versions = "*" +files = [ + {file = "sentencepiece-0.1.99-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0eb528e70571b7c02723e5804322469b82fe7ea418c96051d0286c0fa028db73"}, + {file = "sentencepiece-0.1.99-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:77d7fafb2c4e4659cbdf303929503f37a26eabc4ff31d3a79bf1c5a1b338caa7"}, + {file = "sentencepiece-0.1.99-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be9cf5b9e404c245aeb3d3723c737ba7a8f5d4ba262ef233a431fa6c45f732a0"}, + {file = "sentencepiece-0.1.99-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baed1a26464998f9710d20e52607c29ffd4293e7c71c6a1f83f51ad0911ec12c"}, + {file = "sentencepiece-0.1.99-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9832f08bb372d4c8b567612f8eab9e36e268dff645f1c28f9f8e851be705f6d1"}, + {file = "sentencepiece-0.1.99-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:019e7535108e309dae2b253a75834fc3128240aa87c00eb80732078cdc182588"}, + {file = "sentencepiece-0.1.99-cp310-cp310-win32.whl", hash = "sha256:fa16a830416bb823fa2a52cbdd474d1f7f3bba527fd2304fb4b140dad31bb9bc"}, + {file = "sentencepiece-0.1.99-cp310-cp310-win_amd64.whl", hash = "sha256:14b0eccb7b641d4591c3e12ae44cab537d68352e4d3b6424944f0c447d2348d5"}, + {file = "sentencepiece-0.1.99-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6d3c56f24183a1e8bd61043ff2c58dfecdc68a5dd8955dc13bab83afd5f76b81"}, + {file = "sentencepiece-0.1.99-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed6ea1819fd612c989999e44a51bf556d0ef6abfb553080b9be3d347e18bcfb7"}, + {file = "sentencepiece-0.1.99-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2a0260cd1fb7bd8b4d4f39dc2444a8d5fd4e0a0c4d5c899810ef1abf99b2d45"}, + {file = "sentencepiece-0.1.99-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a1abff4d1ff81c77cac3cc6fefa34fa4b8b371e5ee51cb7e8d1ebc996d05983"}, + {file = "sentencepiece-0.1.99-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:004e6a621d4bc88978eecb6ea7959264239a17b70f2cbc348033d8195c9808ec"}, + {file = "sentencepiece-0.1.99-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db361e03342c41680afae5807590bc88aa0e17cfd1a42696a160e4005fcda03b"}, + {file = "sentencepiece-0.1.99-cp311-cp311-win32.whl", hash = "sha256:2d95e19168875b70df62916eb55428a0cbcb834ac51d5a7e664eda74def9e1e0"}, + {file = "sentencepiece-0.1.99-cp311-cp311-win_amd64.whl", hash = "sha256:f90d73a6f81248a909f55d8e6ef56fec32d559e1e9af045f0b0322637cb8e5c7"}, + {file = "sentencepiece-0.1.99-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:62e24c81e74bd87a6e0d63c51beb6527e4c0add67e1a17bac18bcd2076afcfeb"}, + {file = "sentencepiece-0.1.99-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57efcc2d51caff20d9573567d9fd3f854d9efe613ed58a439c78c9f93101384a"}, + {file = "sentencepiece-0.1.99-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a904c46197993bd1e95b93a6e373dca2f170379d64441041e2e628ad4afb16f"}, + {file = "sentencepiece-0.1.99-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d89adf59854741c0d465f0e1525b388c0d174f611cc04af54153c5c4f36088c4"}, + {file = "sentencepiece-0.1.99-cp36-cp36m-win32.whl", hash = "sha256:47c378146928690d1bc106fdf0da768cebd03b65dd8405aa3dd88f9c81e35dba"}, + {file = "sentencepiece-0.1.99-cp36-cp36m-win_amd64.whl", hash = "sha256:9ba142e7a90dd6d823c44f9870abdad45e6c63958eb60fe44cca6828d3b69da2"}, + {file = "sentencepiece-0.1.99-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b7b1a9ae4d7c6f1f867e63370cca25cc17b6f4886729595b885ee07a58d3cec3"}, + {file = "sentencepiece-0.1.99-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0f644c9d4d35c096a538507b2163e6191512460035bf51358794a78515b74f7"}, + {file = "sentencepiece-0.1.99-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8843d23a0f686d85e569bd6dcd0dd0e0cbc03731e63497ca6d5bacd18df8b85"}, + {file = "sentencepiece-0.1.99-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33e6f690a1caebb4867a2e367afa1918ad35be257ecdb3455d2bbd787936f155"}, + {file = "sentencepiece-0.1.99-cp37-cp37m-win32.whl", hash = "sha256:8a321866c2f85da7beac74a824b4ad6ddc2a4c9bccd9382529506d48f744a12c"}, + {file = "sentencepiece-0.1.99-cp37-cp37m-win_amd64.whl", hash = "sha256:c42f753bcfb7661c122a15b20be7f684b61fc8592c89c870adf52382ea72262d"}, + {file = "sentencepiece-0.1.99-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:85b476406da69c70586f0bb682fcca4c9b40e5059814f2db92303ea4585c650c"}, + {file = "sentencepiece-0.1.99-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cfbcfe13c69d3f87b7fcd5da168df7290a6d006329be71f90ba4f56bc77f8561"}, + {file = "sentencepiece-0.1.99-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:445b0ec381af1cd4eef95243e7180c63d9c384443c16c4c47a28196bd1cda937"}, + {file = "sentencepiece-0.1.99-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6890ea0f2b4703f62d0bf27932e35808b1f679bdb05c7eeb3812b935ba02001"}, + {file = "sentencepiece-0.1.99-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb71af492b0eefbf9f2501bec97bcd043b6812ab000d119eaf4bd33f9e283d03"}, + {file = "sentencepiece-0.1.99-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27b866b5bd3ddd54166bbcbf5c8d7dd2e0b397fac8537991c7f544220b1f67bc"}, + {file = "sentencepiece-0.1.99-cp38-cp38-win32.whl", hash = "sha256:b133e8a499eac49c581c3c76e9bdd08c338cc1939e441fee6f92c0ccb5f1f8be"}, + {file = "sentencepiece-0.1.99-cp38-cp38-win_amd64.whl", hash = "sha256:0eaf3591dd0690a87f44f4df129cf8d05d8a4029b5b6709b489b8e27f9a9bcff"}, + {file = "sentencepiece-0.1.99-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38efeda9bbfb55052d482a009c6a37e52f42ebffcea9d3a98a61de7aee356a28"}, + {file = "sentencepiece-0.1.99-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6c030b081dc1e1bcc9fadc314b19b740715d3d566ad73a482da20d7d46fd444c"}, + {file = "sentencepiece-0.1.99-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84dbe53e02e4f8a2e45d2ac3e430d5c83182142658e25edd76539b7648928727"}, + {file = "sentencepiece-0.1.99-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b0f55d0a0ee1719b4b04221fe0c9f0c3461dc3dabd77a035fa2f4788eb3ef9a"}, + {file = "sentencepiece-0.1.99-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18e800f206cd235dc27dc749299e05853a4e4332e8d3dfd81bf13d0e5b9007d9"}, + {file = "sentencepiece-0.1.99-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ae1c40cda8f9d5b0423cfa98542735c0235e7597d79caf318855cdf971b2280"}, + {file = "sentencepiece-0.1.99-cp39-cp39-win32.whl", hash = "sha256:c84ce33af12ca222d14a1cdd37bd76a69401e32bc68fe61c67ef6b59402f4ab8"}, + {file = "sentencepiece-0.1.99-cp39-cp39-win_amd64.whl", hash = "sha256:350e5c74d739973f1c9643edb80f7cc904dc948578bcb1d43c6f2b173e5d18dd"}, + {file = "sentencepiece-0.1.99.tar.gz", hash = "sha256:189c48f5cb2949288f97ccdb97f0473098d9c3dcf5a3d99d4eabe719ec27297f"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "soupsieve" +version = "2.4.1" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"}, + {file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"}, +] + +[[package]] +name = "stack-data" +version = "0.6.2" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"}, + {file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + +[[package]] +name = "sympy" +version = "1.12" +description = "Computer algebra system (CAS) in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"}, + {file = "sympy-1.12.tar.gz", hash = "sha256:ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8"}, +] + +[package.dependencies] +mpmath = ">=0.19" + +[[package]] +name = "terminado" +version = "0.17.1" +description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." +optional = false +python-versions = ">=3.7" +files = [ + {file = "terminado-0.17.1-py3-none-any.whl", hash = "sha256:8650d44334eba354dd591129ca3124a6ba42c3d5b70df5051b6921d506fdaeae"}, + {file = "terminado-0.17.1.tar.gz", hash = "sha256:6ccbbcd3a4f8a25a5ec04991f39a0b8db52dfcd487ea0e578d977e6752380333"}, +] + +[package.dependencies] +ptyprocess = {version = "*", markers = "os_name != \"nt\""} +pywinpty = {version = ">=1.1.0", markers = "os_name == \"nt\""} +tornado = ">=6.1.0" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["pre-commit", "pytest (>=7.0)", "pytest-timeout"] + +[[package]] +name = "threadpoolctl" +version = "3.2.0" +description = "threadpoolctl" +optional = false +python-versions = ">=3.8" +files = [ + {file = "threadpoolctl-3.2.0-py3-none-any.whl", hash = "sha256:2b7818516e423bdaebb97c723f86a7c6b0a83d3f3b0970328d66f4d9104dc032"}, + {file = "threadpoolctl-3.2.0.tar.gz", hash = "sha256:c96a0ba3bdddeaca37dc4cc7344aafad41cdb8c313f74fdfe387a867bba93355"}, +] + +[[package]] +name = "timm" +version = "0.9.2" +description = "PyTorch Image Models" +optional = false +python-versions = ">=3.7" +files = [ + {file = "timm-0.9.2-py3-none-any.whl", hash = "sha256:8da40cc58ed32b0622bf87d8714f9b7023398ba4cfa8fa678578d2aefde4a909"}, + {file = "timm-0.9.2.tar.gz", hash = "sha256:d0977cc5e02c69bda979fca8b52aa315a5f2cb64ebf8ad2c4631b1e452762c14"}, +] + +[package.dependencies] +huggingface-hub = "*" +pyyaml = "*" +safetensors = "*" +torch = ">=1.7" +torchvision = "*" + +[[package]] +name = "tinycss2" +version = "1.2.1" +description = "A tiny CSS parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tinycss2-1.2.1-py3-none-any.whl", hash = "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847"}, + {file = "tinycss2-1.2.1.tar.gz", hash = "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"}, +] + +[package.dependencies] +webencodings = ">=0.4" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["flake8", "isort", "pytest"] + +[[package]] +name = "tokenizers" +version = "0.13.3" +description = "Fast and Customizable Tokenizers" +optional = false +python-versions = "*" +files = [ + {file = "tokenizers-0.13.3-cp310-cp310-macosx_10_11_x86_64.whl", hash = "sha256:f3835c5be51de8c0a092058a4d4380cb9244fb34681fd0a295fbf0a52a5fdf33"}, + {file = "tokenizers-0.13.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4ef4c3e821730f2692489e926b184321e887f34fb8a6b80b8096b966ba663d07"}, + {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5fd1a6a25353e9aa762e2aae5a1e63883cad9f4e997c447ec39d071020459bc"}, + {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee0b1b311d65beab83d7a41c56a1e46ab732a9eed4460648e8eb0bd69fc2d059"}, + {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ef4215284df1277dadbcc5e17d4882bda19f770d02348e73523f7e7d8b8d396"}, + {file = "tokenizers-0.13.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4d53976079cff8a033f778fb9adca2d9d69d009c02fa2d71a878b5f3963ed30"}, + {file = "tokenizers-0.13.3-cp310-cp310-win32.whl", hash = "sha256:1f0e3b4c2ea2cd13238ce43548959c118069db7579e5d40ec270ad77da5833ce"}, + {file = "tokenizers-0.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:89649c00d0d7211e8186f7a75dfa1db6996f65edce4b84821817eadcc2d3c79e"}, + {file = "tokenizers-0.13.3-cp311-cp311-macosx_10_11_universal2.whl", hash = "sha256:56b726e0d2bbc9243872b0144515ba684af5b8d8cd112fb83ee1365e26ec74c8"}, + {file = "tokenizers-0.13.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:cc5c022ce692e1f499d745af293ab9ee6f5d92538ed2faf73f9708c89ee59ce6"}, + {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f55c981ac44ba87c93e847c333e58c12abcbb377a0c2f2ef96e1a266e4184ff2"}, + {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f247eae99800ef821a91f47c5280e9e9afaeed9980fc444208d5aa6ba69ff148"}, + {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b3e3215d048e94f40f1c95802e45dcc37c5b05eb46280fc2ccc8cd351bff839"}, + {file = "tokenizers-0.13.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ba2b0bf01777c9b9bc94b53764d6684554ce98551fec496f71bc5be3a03e98b"}, + {file = "tokenizers-0.13.3-cp311-cp311-win32.whl", hash = "sha256:cc78d77f597d1c458bf0ea7c2a64b6aa06941c7a99cb135b5969b0278824d808"}, + {file = "tokenizers-0.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:ecf182bf59bd541a8876deccf0360f5ae60496fd50b58510048020751cf1724c"}, + {file = "tokenizers-0.13.3-cp37-cp37m-macosx_10_11_x86_64.whl", hash = "sha256:0527dc5436a1f6bf2c0327da3145687d3bcfbeab91fed8458920093de3901b44"}, + {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07cbb2c307627dc99b44b22ef05ff4473aa7c7cc1fec8f0a8b37d8a64b1a16d2"}, + {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4560dbdeaae5b7ee0d4e493027e3de6d53c991b5002d7ff95083c99e11dd5ac0"}, + {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64064bd0322405c9374305ab9b4c07152a1474370327499911937fd4a76d004b"}, + {file = "tokenizers-0.13.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8c6e2ab0f2e3d939ca66aa1d596602105fe33b505cd2854a4c1717f704c51de"}, + {file = "tokenizers-0.13.3-cp37-cp37m-win32.whl", hash = "sha256:6cc29d410768f960db8677221e497226e545eaaea01aa3613fa0fdf2cc96cff4"}, + {file = "tokenizers-0.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fc2a7fdf864554a0dacf09d32e17c0caa9afe72baf9dd7ddedc61973bae352d8"}, + {file = "tokenizers-0.13.3-cp38-cp38-macosx_10_11_x86_64.whl", hash = "sha256:8791dedba834c1fc55e5f1521be325ea3dafb381964be20684b92fdac95d79b7"}, + {file = "tokenizers-0.13.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:d607a6a13718aeb20507bdf2b96162ead5145bbbfa26788d6b833f98b31b26e1"}, + {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3791338f809cd1bf8e4fee6b540b36822434d0c6c6bc47162448deee3f77d425"}, + {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2f35f30e39e6aab8716f07790f646bdc6e4a853816cc49a95ef2a9016bf9ce6"}, + {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310204dfed5aa797128b65d63538a9837cbdd15da2a29a77d67eefa489edda26"}, + {file = "tokenizers-0.13.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0f9b92ea052305166559f38498b3b0cae159caea712646648aaa272f7160963"}, + {file = "tokenizers-0.13.3-cp38-cp38-win32.whl", hash = "sha256:9a3fa134896c3c1f0da6e762d15141fbff30d094067c8f1157b9fdca593b5806"}, + {file = "tokenizers-0.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:8e7b0cdeace87fa9e760e6a605e0ae8fc14b7d72e9fc19c578116f7287bb873d"}, + {file = "tokenizers-0.13.3-cp39-cp39-macosx_10_11_x86_64.whl", hash = "sha256:00cee1e0859d55507e693a48fa4aef07060c4bb6bd93d80120e18fea9371c66d"}, + {file = "tokenizers-0.13.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:a23ff602d0797cea1d0506ce69b27523b07e70f6dda982ab8cf82402de839088"}, + {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ce07445050b537d2696022dafb115307abdffd2a5c106f029490f84501ef97"}, + {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:280ffe95f50eaaf655b3a1dc7ff1d9cf4777029dbbc3e63a74e65a056594abc3"}, + {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97acfcec592f7e9de8cadcdcda50a7134423ac8455c0166b28c9ff04d227b371"}, + {file = "tokenizers-0.13.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7730c98a3010cd4f523465867ff95cd9d6430db46676ce79358f65ae39797b"}, + {file = "tokenizers-0.13.3-cp39-cp39-win32.whl", hash = "sha256:48625a108029cb1ddf42e17a81b5a3230ba6888a70c9dc14e81bc319e812652d"}, + {file = "tokenizers-0.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:bc0a6f1ba036e482db6453571c9e3e60ecd5489980ffd95d11dc9f960483d783"}, + {file = "tokenizers-0.13.3.tar.gz", hash = "sha256:2e546dbb68b623008a5442353137fbb0123d311a6d7ba52f2667c8862a75af2e"}, +] + +[package.extras] +dev = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"] +docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"] +testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "torch" +version = "2.0.1" +description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "torch-2.0.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:8ced00b3ba471856b993822508f77c98f48a458623596a4c43136158781e306a"}, + {file = "torch-2.0.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:359bfaad94d1cda02ab775dc1cc386d585712329bb47b8741607ef6ef4950747"}, + {file = "torch-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:7c84e44d9002182edd859f3400deaa7410f5ec948a519cc7ef512c2f9b34d2c4"}, + {file = "torch-2.0.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:567f84d657edc5582d716900543e6e62353dbe275e61cdc36eda4929e46df9e7"}, + {file = "torch-2.0.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:787b5a78aa7917465e9b96399b883920c88a08f4eb63b5a5d2d1a16e27d2f89b"}, + {file = "torch-2.0.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:e617b1d0abaf6ced02dbb9486803abfef0d581609b09641b34fa315c9c40766d"}, + {file = "torch-2.0.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b6019b1de4978e96daa21d6a3ebb41e88a0b474898fe251fd96189587408873e"}, + {file = "torch-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:dbd68cbd1cd9da32fe5d294dd3411509b3d841baecb780b38b3b7b06c7754434"}, + {file = "torch-2.0.1-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:ef654427d91600129864644e35deea761fb1fe131710180b952a6f2e2207075e"}, + {file = "torch-2.0.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:25aa43ca80dcdf32f13da04c503ec7afdf8e77e3a0183dd85cd3e53b2842e527"}, + {file = "torch-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5ef3ea3d25441d3957348f7e99c7824d33798258a2bf5f0f0277cbcadad2e20d"}, + {file = "torch-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:0882243755ff28895e8e6dc6bc26ebcf5aa0911ed81b2a12f241fc4b09075b13"}, + {file = "torch-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:f66aa6b9580a22b04d0af54fcd042f52406a8479e2b6a550e3d9f95963e168c8"}, + {file = "torch-2.0.1-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:1adb60d369f2650cac8e9a95b1d5758e25d526a34808f7448d0bd599e4ae9072"}, + {file = "torch-2.0.1-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:1bcffc16b89e296826b33b98db5166f990e3b72654a2b90673e817b16c50e32b"}, + {file = "torch-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:e10e1597f2175365285db1b24019eb6f04d53dcd626c735fc502f1e8b6be9875"}, + {file = "torch-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:423e0ae257b756bb45a4b49072046772d1ad0c592265c5080070e0767da4e490"}, + {file = "torch-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:8742bdc62946c93f75ff92da00e3803216c6cce9b132fbca69664ca38cfb3e18"}, + {file = "torch-2.0.1-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:c62df99352bd6ee5a5a8d1832452110435d178b5164de450831a3a8cc14dc680"}, + {file = "torch-2.0.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:671a2565e3f63b8fe8e42ae3e36ad249fe5e567435ea27b94edaa672a7d0c416"}, +] + +[package.dependencies] +filelock = "*" +jinja2 = "*" +networkx = "*" +sympy = "*" +typing-extensions = "*" + +[package.extras] +opt-einsum = ["opt-einsum (>=3.3)"] + +[[package]] +name = "torchvision" +version = "0.15.2" +description = "image and video datasets and models for torch deep learning" +optional = false +python-versions = ">=3.8" +files = [ + {file = "torchvision-0.15.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7754088774e810c5672b142a45dcf20b1bd986a5a7da90f8660c43dc43fb850c"}, + {file = "torchvision-0.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37eb138e13f6212537a3009ac218695483a635c404b6cc1d8e0d0d978026a86d"}, + {file = "torchvision-0.15.2-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:54143f7cc0797d199b98a53b7d21c3f97615762d4dd17ad45a41c7e80d880e73"}, + {file = "torchvision-0.15.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:1eefebf5fbd01a95fe8f003d623d941601c94b5cec547b420da89cb369d9cf96"}, + {file = "torchvision-0.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:96fae30c5ca8423f4b9790df0f0d929748e32718d88709b7b567d2f630c042e3"}, + {file = "torchvision-0.15.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5f35f6bd5bcc4568e6522e4137fa60fcc72f4fa3e615321c26cd87e855acd398"}, + {file = "torchvision-0.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:757505a0ab2be7096cb9d2bf4723202c971cceddb72c7952a7e877f773de0f8a"}, + {file = "torchvision-0.15.2-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:012ad25cfd9019ff9b0714a168727e3845029be1af82296ff1e1482931fa4b80"}, + {file = "torchvision-0.15.2-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b02a7ffeaa61448737f39a4210b8ee60234bda0515a0c0d8562f884454105b0f"}, + {file = "torchvision-0.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:10be76ceded48329d0a0355ac33da131ee3993ff6c125e4a02ab34b5baa2472c"}, + {file = "torchvision-0.15.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f12415b686dba884fb086f53ac803f692be5a5cdd8a758f50812b30fffea2e4"}, + {file = "torchvision-0.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:31211c01f8b8ec33b8a638327b5463212e79a03e43c895f88049f97af1bd12fd"}, + {file = "torchvision-0.15.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c55f9889e436f14b4f84a9c00ebad0d31f5b4626f10cf8018e6c676f92a6d199"}, + {file = "torchvision-0.15.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:9a192f2aa979438f23c20e883980b23d13268ab9f819498774a6d2eb021802c2"}, + {file = "torchvision-0.15.2-cp38-cp38-win_amd64.whl", hash = "sha256:c07071bc8d02aa8fcdfe139ab6a1ef57d3b64c9e30e84d12d45c9f4d89fb6536"}, + {file = "torchvision-0.15.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4790260fcf478a41c7ecc60a6d5200a88159fdd8d756e9f29f0f8c59c4a67a68"}, + {file = "torchvision-0.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:987ab62225b4151a11e53fd06150c5258ced24ac9d7c547e0e4ab6fbca92a5ce"}, + {file = "torchvision-0.15.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:63df26673e66cba3f17e07c327a8cafa3cce98265dbc3da329f1951d45966838"}, + {file = "torchvision-0.15.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b85f98d4cc2f72452f6792ab4463a3541bc5678a8cdd3da0e139ba2fe8b56d42"}, + {file = "torchvision-0.15.2-cp39-cp39-win_amd64.whl", hash = "sha256:07c462524cc1bba5190c16a9d47eac1fca024d60595a310f23c00b4ffff18b30"}, +] + +[package.dependencies] +numpy = "*" +pillow = ">=5.3.0,<8.3.dev0 || >=8.4.dev0" +requests = "*" +torch = "2.0.1" + +[package.extras] +scipy = ["scipy"] + +[[package]] +name = "tornado" +version = "6.3.2" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +optional = false +python-versions = ">= 3.8" +files = [ + {file = "tornado-6.3.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:c367ab6c0393d71171123ca5515c61ff62fe09024fa6bf299cd1339dc9456829"}, + {file = "tornado-6.3.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b46a6ab20f5c7c1cb949c72c1994a4585d2eaa0be4853f50a03b5031e964fc7c"}, + {file = "tornado-6.3.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2de14066c4a38b4ecbbcd55c5cc4b5340eb04f1c5e81da7451ef555859c833f"}, + {file = "tornado-6.3.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05615096845cf50a895026f749195bf0b10b8909f9be672f50b0fe69cba368e4"}, + {file = "tornado-6.3.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b17b1cf5f8354efa3d37c6e28fdfd9c1c1e5122f2cb56dac121ac61baa47cbe"}, + {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:29e71c847a35f6e10ca3b5c2990a52ce38b233019d8e858b755ea6ce4dcdd19d"}, + {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:834ae7540ad3a83199a8da8f9f2d383e3c3d5130a328889e4cc991acc81e87a0"}, + {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6a0848f1aea0d196a7c4f6772197cbe2abc4266f836b0aac76947872cd29b411"}, + {file = "tornado-6.3.2-cp38-abi3-win32.whl", hash = "sha256:7efcbcc30b7c654eb6a8c9c9da787a851c18f8ccd4a5a3a95b05c7accfa068d2"}, + {file = "tornado-6.3.2-cp38-abi3-win_amd64.whl", hash = "sha256:0c325e66c8123c606eea33084976c832aa4e766b7dff8aedd7587ea44a604cdf"}, + {file = "tornado-6.3.2.tar.gz", hash = "sha256:4b927c4f19b71e627b13f3db2324e4ae660527143f9e1f2e2fb404f3a187e2ba"}, +] + +[[package]] +name = "tqdm" +version = "4.65.0" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tqdm-4.65.0-py3-none-any.whl", hash = "sha256:c4f53a17fe37e132815abceec022631be8ffe1b9381c2e6e30aa70edc99e9671"}, + {file = "tqdm-4.65.0.tar.gz", hash = "sha256:1871fb68a86b8fb3b59ca4cdd3dcccbc7e6d613eeed31f4c332531977b89beb5"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["py-make (>=0.1.0)", "twine", "wheel"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "traitlets" +version = "5.9.0" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.7" +files = [ + {file = "traitlets-5.9.0-py3-none-any.whl", hash = "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8"}, + {file = "traitlets-5.9.0.tar.gz", hash = "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] + +[[package]] +name = "transformers" +version = "4.31.0" +description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "transformers-4.31.0-py3-none-any.whl", hash = "sha256:8487aab0195ce1c2a5ae189305118b9720daddbc7b688edb09ccd79e3b149f6b"}, + {file = "transformers-4.31.0.tar.gz", hash = "sha256:4302fba920a1c24d3a429a29efff6a63eac03f3f3cf55b55927fc795d01cb273"}, +] + +[package.dependencies] +filelock = "*" +huggingface-hub = ">=0.14.1,<1.0" +numpy = ">=1.17" +packaging = ">=20.0" +protobuf = {version = "*", optional = true, markers = "extra == \"sentencepiece\""} +pyyaml = ">=5.1" +regex = "!=2019.12.17" +requests = "*" +safetensors = ">=0.3.1" +sentencepiece = {version = ">=0.1.91,<0.1.92 || >0.1.92", optional = true, markers = "extra == \"sentencepiece\""} +tokenizers = ">=0.11.1,<0.11.3 || >0.11.3,<0.14" +tqdm = ">=4.27" + +[package.extras] +accelerate = ["accelerate (>=0.20.3)"] +agents = ["Pillow (<10.0.0)", "accelerate (>=0.20.3)", "datasets (!=2.5.0)", "diffusers", "opencv-python", "sentencepiece (>=0.1.91,!=0.1.92)", "torch (>=1.9,!=1.12.0)"] +all = ["Pillow (<10.0.0)", "accelerate (>=0.20.3)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.2.8,!=0.3.2,<=0.4.13)", "jaxlib (>=0.1.65,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune]", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision"] +audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +codecarbon = ["codecarbon (==1.2.0)"] +deepspeed = ["accelerate (>=0.20.3)", "deepspeed (>=0.9.3)"] +deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.20.3)", "beautifulsoup4", "black (>=23.1,<24.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "optuna", "parameterized", "protobuf", "psutil", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "timeout-decorator"] +dev = ["GitPython (<3.1.19)", "Pillow (<10.0.0)", "accelerate (>=0.20.3)", "av (==9.2.0)", "beautifulsoup4", "black (>=23.1,<24.0)", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "decord (==0.6.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.2.8,!=0.3.2,<=0.4.13)", "jaxlib (>=0.1.65,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "ray[tune]", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (>=0.0.241,<=0.0.259)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timeout-decorator", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (<10.0.0)", "beautifulsoup4", "black (>=23.1,<24.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (>=0.0.241,<=0.0.259)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "urllib3 (<2.0.0)"] +dev-torch = ["GitPython (<3.1.19)", "Pillow (<10.0.0)", "accelerate (>=0.20.3)", "beautifulsoup4", "black (>=23.1,<24.0)", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "librosa", "nltk", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "ray[tune]", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (>=0.0.241,<=0.0.259)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "timeout-decorator", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +docs = ["Pillow (<10.0.0)", "accelerate (>=0.20.3)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "hf-doc-builder", "jax (>=0.2.8,!=0.3.2,<=0.4.13)", "jaxlib (>=0.1.65,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune]", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision"] +docs-specific = ["hf-doc-builder"] +fairscale = ["fairscale (>0.3)"] +flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.2.8,!=0.3.2,<=0.4.13)", "jaxlib (>=0.1.65,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)"] +flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +ftfy = ["ftfy"] +integrations = ["optuna", "ray[tune]", "sigopt"] +ja = ["fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "rhoknp (>=1.1.0,<1.3.1)", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)"] +modelcreation = ["cookiecutter (==1.7.3)"] +natten = ["natten (>=0.14.6)"] +onnx = ["onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "tf2onnx"] +onnxruntime = ["onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)"] +optuna = ["optuna"] +quality = ["GitPython (<3.1.19)", "black (>=23.1,<24.0)", "datasets (!=2.5.0)", "hf-doc-builder (>=0.3.0)", "isort (>=5.5.4)", "ruff (>=0.0.241,<=0.0.259)", "urllib3 (<2.0.0)"] +ray = ["ray[tune]"] +retrieval = ["datasets (!=2.5.0)", "faiss-cpu"] +sagemaker = ["sagemaker (>=2.31.0)"] +sentencepiece = ["protobuf", "sentencepiece (>=0.1.91,!=0.1.92)"] +serving = ["fastapi", "pydantic (<2)", "starlette", "uvicorn"] +sigopt = ["sigopt"] +sklearn = ["scikit-learn"] +speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] +testing = ["GitPython (<3.1.19)", "beautifulsoup4", "black (>=23.1,<24.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "parameterized", "protobuf", "psutil", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "timeout-decorator"] +tf = ["keras-nlp (>=0.3.1)", "onnxconverter-common", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx"] +tf-cpu = ["keras-nlp (>=0.3.1)", "onnxconverter-common", "tensorflow-cpu (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx"] +tf-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +timm = ["timm"] +tokenizers = ["tokenizers (>=0.11.1,!=0.11.3,<0.14)"] +torch = ["accelerate (>=0.20.3)", "torch (>=1.9,!=1.12.0)"] +torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] +torch-vision = ["Pillow (<10.0.0)", "torchvision"] +torchhub = ["filelock", "huggingface-hub (>=0.14.1,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "tqdm (>=4.27)"] +video = ["av (==9.2.0)", "decord (==0.6.0)"] +vision = ["Pillow (<10.0.0)"] + +[[package]] +name = "typing-extensions" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +] + +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, +] + +[[package]] +name = "uri-template" +version = "1.3.0" +description = "RFC 6570 URI Template Processor" +optional = false +python-versions = ">=3.7" +files = [ + {file = "uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7"}, + {file = "uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363"}, +] + +[package.extras] +dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake8-commas", "flake8-comprehensions", "flake8-continuation", "flake8-datetimez", "flake8-docstrings", "flake8-import-order", "flake8-literal", "flake8-modern-annotations", "flake8-noqa", "flake8-pyproject", "flake8-requirements", "flake8-typechecking-import", "flake8-use-fstring", "mypy", "pep8-naming", "types-PyYAML"] + +[[package]] +name = "urllib3" +version = "2.0.4" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.7" +files = [ + {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, + {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "wcwidth" +version = "0.2.6" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, + {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, +] + +[[package]] +name = "webcolors" +version = "1.13" +description = "A library for working with the color formats defined by HTML and CSS." +optional = false +python-versions = ">=3.7" +files = [ + {file = "webcolors-1.13-py3-none-any.whl", hash = "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf"}, + {file = "webcolors-1.13.tar.gz", hash = "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a"}, +] + +[package.extras] +docs = ["furo", "sphinx", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-notfound-page", "sphinxext-opengraph"] +tests = ["pytest", "pytest-cov"] + +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +optional = false +python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] + +[[package]] +name = "websocket-client" +version = "1.6.1" +description = "WebSocket client for Python with low level API options" +optional = false +python-versions = ">=3.7" +files = [ + {file = "websocket-client-1.6.1.tar.gz", hash = "sha256:c951af98631d24f8df89ab1019fc365f2227c0892f12fd150e935607c79dd0dd"}, + {file = "websocket_client-1.6.1-py3-none-any.whl", hash = "sha256:f1f9f2ad5291f0225a49efad77abf9e700b6fef553900623060dad6e26503b9d"}, +] + +[package.extras] +docs = ["Sphinx (>=3.4)", "sphinx-rtd-theme (>=0.5)"] +optional = ["python-socks", "wsaccel"] +test = ["websockets"] + +[[package]] +name = "widgetsnbextension" +version = "4.0.8" +description = "Jupyter interactive widgets for Jupyter Notebook" +optional = false +python-versions = ">=3.7" +files = [ + {file = "widgetsnbextension-4.0.8-py3-none-any.whl", hash = "sha256:2e37f0ce9da11651056280c7efe96f2db052fe8fc269508e3724f5cbd6c93018"}, + {file = "widgetsnbextension-4.0.8.tar.gz", hash = "sha256:9ec291ba87c2dfad42c3d5b6f68713fa18be1acd7476569516b2431682315c17"}, +] + +[[package]] +name = "xxhash" +version = "3.2.0" +description = "Python binding for xxHash" +optional = false +python-versions = ">=3.6" +files = [ + {file = "xxhash-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:af44b9e59c4b2926a4e3c7f9d29949ff42fcea28637ff6b8182e654461932be8"}, + {file = "xxhash-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1bdd57973e2b802ef32553d7bebf9402dac1557874dbe5c908b499ea917662cd"}, + {file = "xxhash-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b7c9aa77bbce61a5e681bd39cb6a804338474dcc90abe3c543592aa5d6c9a9b"}, + {file = "xxhash-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11bf87dc7bb8c3b0b5e24b7b941a9a19d8c1f88120b6a03a17264086bc8bb023"}, + {file = "xxhash-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2783d41487ce6d379fdfaa7332fca5187bf7010b9bddcf20cafba923bc1dc665"}, + {file = "xxhash-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:561076ca0dcef2fbc20b2bc2765bff099e002e96041ae9dbe910a863ca6ee3ea"}, + {file = "xxhash-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a26eeb4625a6e61cedc8c1b39b89327c9c7e1a8c2c4d786fe3f178eb839ede6"}, + {file = "xxhash-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d93a44d0104d1b9b10de4e7aadf747f6efc1d7ec5ed0aa3f233a720725dd31bd"}, + {file = "xxhash-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:89585adc73395a10306d2e2036e50d6c4ac0cf8dd47edf914c25488871b64f6d"}, + {file = "xxhash-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a892b4b139126a86bfdcb97cd912a2f8c4e8623869c3ef7b50871451dd7afeb0"}, + {file = "xxhash-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e998efb190653f70e0f30d92b39fc645145369a4823bee46af8ddfc244aa969d"}, + {file = "xxhash-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8ed3bd2b8bb3277710843ca63e4f5c3ee6f8f80b083be5b19a7a9905420d11e"}, + {file = "xxhash-3.2.0-cp310-cp310-win32.whl", hash = "sha256:20181cbaed033c72cb881b2a1d13c629cd1228f113046133469c9a48cfcbcd36"}, + {file = "xxhash-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:a0f7a16138279d707db778a63264d1d6016ac13ffd3f1e99f54b2855d6c0d8e1"}, + {file = "xxhash-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5daff3fb5bfef30bc5a2cb143810d376d43461445aa17aece7210de52adbe151"}, + {file = "xxhash-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75bb5be3c5de702a547715f320ecf5c8014aeca750ed5147ca75389bd22e7343"}, + {file = "xxhash-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01f36b671ff55cb1d5c2f6058b799b697fd0ae4b4582bba6ed0999678068172a"}, + {file = "xxhash-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4d4519123aac73c93159eb8f61db9682393862dd669e7eae034ecd0a35eadac"}, + {file = "xxhash-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:994e4741d5ed70fc2a335a91ef79343c6b1089d7dfe6e955dd06f8ffe82bede6"}, + {file = "xxhash-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:919bc1b010aa6ff0eb918838ff73a435aed9e9a19c3202b91acecd296bf75607"}, + {file = "xxhash-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17b65454c5accbb079c45eca546c27c4782f5175aa320758fafac896b1549d27"}, + {file = "xxhash-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b0c094d5e65a46dbf3fe0928ff20873a747e6abfd2ed4b675beeb2750624bc2e"}, + {file = "xxhash-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f94163ebe2d5546e6a5977e96d83621f4689c1054053428cf8d4c28b10f92f69"}, + {file = "xxhash-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cead7c0307977a00b3f784cff676e72c147adbcada19a2e6fc2ddf54f37cf387"}, + {file = "xxhash-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:a0e1bd0260c1da35c1883321ce2707ceea07127816ab625e1226ec95177b561a"}, + {file = "xxhash-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc8878935671490efe9275fb4190a6062b73277bd273237179b9b5a2aa436153"}, + {file = "xxhash-3.2.0-cp311-cp311-win32.whl", hash = "sha256:a433f6162b18d52f7068175d00bd5b1563b7405f926a48d888a97b90a160c40d"}, + {file = "xxhash-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:a32d546a1752e4ee7805d6db57944f7224afa7428d22867006b6486e4195c1f3"}, + {file = "xxhash-3.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:82daaab720866bf690b20b49de5640b0c27e3b8eea2d08aa75bdca2b0f0cfb63"}, + {file = "xxhash-3.2.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3126df6520cbdbaddd87ce74794b2b6c45dd2cf6ac2b600a374b8cdb76a2548c"}, + {file = "xxhash-3.2.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e172c1ee40507ae3b8d220f4048aaca204f203e1e4197e8e652f5c814f61d1aa"}, + {file = "xxhash-3.2.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5384f1d9f30876f5d5b618464fb19ff7ce6c0fe4c690fbaafd1c52adc3aae807"}, + {file = "xxhash-3.2.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26cb52174a7e96a17acad27a3ca65b24713610ac479c99ac9640843822d3bebf"}, + {file = "xxhash-3.2.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbcd613a5e76b1495fc24db9c37a6b7ee5f214fd85979187ec4e032abfc12ded"}, + {file = "xxhash-3.2.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f988daf25f31726d5b9d0be6af636ca9000898f9ea43a57eac594daea25b0948"}, + {file = "xxhash-3.2.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:bbc30c98ab006ab9fc47e5ed439c00f706bc9d4441ff52693b8b6fea335163e0"}, + {file = "xxhash-3.2.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:2408d49260b0a4a7cc6ba445aebf38e073aeaf482f8e32767ca477e32ccbbf9e"}, + {file = "xxhash-3.2.0-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:3f4152fd0bf8b03b79f2f900fd6087a66866537e94b5a11fd0fd99ef7efe5c42"}, + {file = "xxhash-3.2.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0eea848758e4823a01abdbcccb021a03c1ee4100411cbeeb7a5c36a202a0c13c"}, + {file = "xxhash-3.2.0-cp36-cp36m-win32.whl", hash = "sha256:77709139af5123c578ab06cf999429cdb9ab211047acd0c787e098dcb3f1cb4d"}, + {file = "xxhash-3.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:91687671fd9d484a4e201ad266d366b695a45a1f2b41be93d116ba60f1b8f3b3"}, + {file = "xxhash-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e4af8bc5c3fcc2192c266421c6aa2daab1a18e002cb8e66ef672030e46ae25cf"}, + {file = "xxhash-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8be562e2ce3e481d9209b6f254c3d7c5ff920eb256aba2380d2fb5ba75d4f87"}, + {file = "xxhash-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9eba0c7c12126b12f7fcbea5513f28c950d28f33d2a227f74b50b77789e478e8"}, + {file = "xxhash-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2198c4901a0223c48f6ec0a978b60bca4f4f7229a11ca4dc96ca325dd6a29115"}, + {file = "xxhash-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50ce82a71b22a3069c02e914bf842118a53065e2ec1c6fb54786e03608ab89cc"}, + {file = "xxhash-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5019fb33711c30e54e4e57ae0ca70af9d35b589d385ac04acd6954452fa73bb"}, + {file = "xxhash-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0d54ac023eef7e3ac9f0b8841ae8a376b933043bc2ad428121346c6fa61c491c"}, + {file = "xxhash-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c55fa832fc3fe64e0d29da5dc9b50ba66ca93312107cec2709300ea3d3bab5c7"}, + {file = "xxhash-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f4ce006215497993ae77c612c1883ca4f3973899573ce0c52fee91f0d39c4561"}, + {file = "xxhash-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1afb9b9d27fd675b436cb110c15979976d92d761ad6e66799b83756402f3a974"}, + {file = "xxhash-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:baa99cebf95c1885db21e119395f222a706a2bb75a545f0672880a442137725e"}, + {file = "xxhash-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:75aa692936942ccb2e8fd6a386c81c61630ac1b6d6e921698122db8a930579c3"}, + {file = "xxhash-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:0a2cdfb5cae9fafb9f7b65fd52ecd60cf7d72c13bb2591ea59aaefa03d5a8827"}, + {file = "xxhash-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a68d1e8a390b660d94b9360ae5baa8c21a101bd9c4790a8b30781bada9f1fc6"}, + {file = "xxhash-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ce7c3ce28f94302df95eaea7c9c1e2c974b6d15d78a0c82142a97939d7b6c082"}, + {file = "xxhash-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dcb419bf7b0bc77d366e5005c25682249c5521a63fd36c51f584bd91bb13bd5"}, + {file = "xxhash-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae521ed9287f86aac979eeac43af762f03d9d9797b2272185fb9ddd810391216"}, + {file = "xxhash-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d16775094423088ffa357d09fbbb9ab48d2fb721d42c0856b801c86f616eec"}, + {file = "xxhash-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe454aeab348c42f56d6f7434ff758a3ef90787ac81b9ad5a363cd61b90a1b0b"}, + {file = "xxhash-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:052fd0efdd5525c2dbc61bebb423d92aa619c4905bba605afbf1e985a562a231"}, + {file = "xxhash-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:02badf3754e2133de254a4688798c4d80f0060635087abcb461415cb3eb82115"}, + {file = "xxhash-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:66b8a90b28c13c2aae7a71b32638ceb14cefc2a1c8cf23d8d50dfb64dfac7aaf"}, + {file = "xxhash-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:649cdf19df175925ad87289ead6f760cd840730ee85abc5eb43be326a0a24d97"}, + {file = "xxhash-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4b948a03f89f5c72d69d40975af8af241111f0643228796558dc1cae8f5560b0"}, + {file = "xxhash-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49f51fab7b762da7c2cee0a3d575184d3b9be5e2f64f26cae2dd286258ac9b3c"}, + {file = "xxhash-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1a42994f0d42b55514785356722d9031f064fd34e495b3a589e96db68ee0179d"}, + {file = "xxhash-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0a6d58ba5865475e53d6c2c4fa6a62e2721e7875e146e2681e5337a6948f12e7"}, + {file = "xxhash-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aabdbc082030f8df613e2d2ea1f974e7ad36a539bdfc40d36f34e55c7e4b8e94"}, + {file = "xxhash-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:498843b66b9ca416e9d03037e5875c8d0c0ab9037527e22df3b39aa5163214cd"}, + {file = "xxhash-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a910b1193cd90af17228f5d6069816646df0148f14f53eefa6b2b11a1dedfcd0"}, + {file = "xxhash-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb6d8ce31dc25faf4da92991320e211fa7f42de010ef51937b1dc565a4926501"}, + {file = "xxhash-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:883dc3d3942620f4c7dbc3fd6162f50a67f050b714e47da77444e3bcea7d91cc"}, + {file = "xxhash-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59dc8bfacf89b8f5be54d55bc3b4bd6d74d0c5320c8a63d2538ac7df5b96f1d5"}, + {file = "xxhash-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61e6aa1d30c2af692aa88c4dd48709426e8b37bff6a574ee2de677579c34a3d6"}, + {file = "xxhash-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:314ec0bd21f0ee8d30f2bd82ed3759314bd317ddbbd8555668f3d20ab7a8899a"}, + {file = "xxhash-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dad638cde3a5357ad3163b80b3127df61fb5b5e34e9e05a87697144400ba03c7"}, + {file = "xxhash-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:eaa3ea15025b56076d806b248948612289b093e8dcda8d013776b3848dffff15"}, + {file = "xxhash-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7deae3a312feb5c17c97cbf18129f83cbd3f1f9ec25b0f50e2bd9697befb22e7"}, + {file = "xxhash-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:add774341c09853b1612c64a526032d95ab1683053325403e1afbe3ad2f374c5"}, + {file = "xxhash-3.2.0-cp39-cp39-win32.whl", hash = "sha256:9b94749130ef3119375c599bfce82142c2500ef9ed3280089157ee37662a7137"}, + {file = "xxhash-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:e57d94a1552af67f67b27db5dba0b03783ea69d5ca2af2f40e098f0ba3ce3f5f"}, + {file = "xxhash-3.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92fd765591c83e5c5f409b33eac1d3266c03d3d11c71a7dbade36d5cdee4fbc0"}, + {file = "xxhash-3.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8970f6a411a9839a02b23b7e90bbbba4a6de52ace009274998566dc43f36ca18"}, + {file = "xxhash-3.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5f3e33fe6cbab481727f9aeb136a213aed7e33cd1ca27bd75e916ffacc18411"}, + {file = "xxhash-3.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:368265392cb696dd53907e2328b5a8c1bee81cf2142d0cc743caf1c1047abb36"}, + {file = "xxhash-3.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3b1f3c6d67fa9f49c4ff6b25ce0e7143bab88a5bc0f4116dd290c92337d0ecc7"}, + {file = "xxhash-3.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c5e8db6e1ee7267b7c412ad0afd5863bf7a95286b8333a5958c8097c69f94cf5"}, + {file = "xxhash-3.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:761df3c7e2c5270088b691c5a8121004f84318177da1ca1db64222ec83c44871"}, + {file = "xxhash-3.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2d15a707e7f689531eb4134eccb0f8bf3844bb8255ad50823aa39708d9e6755"}, + {file = "xxhash-3.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6b2ba4ff53dd5f57d728095e3def7375eb19c90621ce3b41b256de84ec61cfd"}, + {file = "xxhash-3.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:61b0bcf946fdfd8ab5f09179dc2b5c74d1ef47cedfc6ed0ec01fdf0ee8682dd3"}, + {file = "xxhash-3.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f7b79f0f302396d8e0d444826ceb3d07b61977793886ebae04e82796c02e42dc"}, + {file = "xxhash-3.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0773cd5c438ffcd5dbff91cdd503574f88a4b960e70cedeb67736583a17a918"}, + {file = "xxhash-3.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ec1f57127879b419a2c8d2db9d9978eb26c61ae17e5972197830430ae78d25b"}, + {file = "xxhash-3.2.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d4b15c00e807b1d3d0b612338c814739dec310b80fb069bd732b98ddc709ad7"}, + {file = "xxhash-3.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9d3f686e3d1c8900c5459eee02b60c7399e20ec5c6402364068a343c83a61d90"}, + {file = "xxhash-3.2.0.tar.gz", hash = "sha256:1afd47af8955c5db730f630ad53ae798cf7fae0acb64cebb3cf94d35c47dd088"}, +] + +[[package]] +name = "yarl" +version = "1.9.2" +description = "Yet another URL library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82"}, + {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8"}, + {file = "yarl-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528"}, + {file = "yarl-1.9.2-cp310-cp310-win32.whl", hash = "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3"}, + {file = "yarl-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a"}, + {file = "yarl-1.9.2-cp311-cp311-win32.whl", hash = "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8"}, + {file = "yarl-1.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051"}, + {file = "yarl-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582"}, + {file = "yarl-1.9.2-cp37-cp37m-win32.whl", hash = "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b"}, + {file = "yarl-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b"}, + {file = "yarl-1.9.2-cp38-cp38-win32.whl", hash = "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"}, + {file = "yarl-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80"}, + {file = "yarl-1.9.2-cp39-cp39-win32.whl", hash = "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623"}, + {file = "yarl-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18"}, + {file = "yarl-1.9.2.tar.gz", hash = "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + +[[package]] +name = "zipp" +version = "3.16.2" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, + {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "a35a5317de1c077588121cb0c3fb6b1a079f0e9615ed5776f4f3ff5ed9aaaf60" diff --git a/examples/instructor/pyproject.toml b/examples/instructor/pyproject.toml new file mode 100644 index 00000000..4d11b28f --- /dev/null +++ b/examples/instructor/pyproject.toml @@ -0,0 +1,29 @@ +[tool.poetry] +name = "onnx-instructor-dev" +version = "0.1.0" +description = "" +authors = ["Mohammadreza Anvari "] +readme = "README.md" +packages = [{include = "onnx-instructor-dev"}] + +[tool.poetry.dependencies] +python = "^3.8" +ipykernel = "^6.24.0" +optimum = {extras = ["exporters"], version = "^1.9.1"} +onnxruntime = "^1.15.1" +onnxt5 = "^0.1.8" +instructorembedding = "^1.0.1" +sentence-transformers = "^2.2.2" +nltk = "^3.8.1" +jyquickhelper = "^0.4.220" +networkx = "^3.1" +graphviz = "^0.20.1" +matplotlib = "^3.7.2" +pydot = "^1.4.2" +pygraphviz = "^1.11" +humanize = "^4.7.0" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 7ce14ecd..01a8e466 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -81,3 +81,7 @@ def test_ggml_onnx_runtime_basic(): ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) ggml_result = ggml_dummy_model.run(input_data) assert ggml_result == runtime_result + + +def test_ggml_onnx_runtime_instructor(): + pass From 65b0cdc453565b5073bc58973c6a8ab6316362b3 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 28 Jul 2023 16:58:57 -0400 Subject: [PATCH 011/232] Update pyproject.toml --- pyproject.toml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d0ef75fd..e6c8b2e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,15 @@ convert = [ "transformers==4.29.2" ] onnx = ["onnx==1.14.0"] -onnx-tests = ["tabulate==0.9.0", "pytest-cov==4.1.0", "pytest-runner==6.0.0", "onnxruntime==1.15.1"] +onnx-tests = [ + "tabulate==0.9.0", + "pytest-cov==4.1.0", + "pytest-runner==6.0.0", + "onnxruntime==1.15.1", + "InstructorEmbedding==1.0.1", + "sentence_transformers==2.2.2", + "sentencepiece==0.1.99" +] [project.urls] Homepage = "https://github.com/abetlen/ggml-python" From 3ef11ed4bd10c650cbbdccd0a44f220f4fd37ec6 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 28 Jul 2023 16:59:41 -0400 Subject: [PATCH 012/232] Add `test_ggml_onnx_runtime_instructor` --- tests/test_ggml_onnx.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 01a8e466..b0a93497 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -4,6 +4,8 @@ import onnx from onnx import TensorProto, helper from onnxruntime import InferenceSession +from transformers import AutoTokenizer +from InstructorEmbedding import INSTRUCTOR from ggml.contrib.onnx import GgmlRuntimeBackend @@ -84,4 +86,26 @@ def test_ggml_onnx_runtime_basic(): def test_ggml_onnx_runtime_instructor(): - pass + instructor_model = INSTRUCTOR("hkunlp/instructor-base") + + onnx_instructor_model = onnx.load("instructor_base_onnx/encoder_model.onnx") + ggml_onnx_instructor_model = GgmlRuntimeBackend.prepare(onnx_instructor_model) + + instructor_tokenizer = AutoTokenizer.from_pretrained("t5-large") + + sentence = "This is a sentence" + instruction = "Represent the follwing sentence:" + + sentence_tokens = instructor_tokenizer.encode( + [instruction, sentence], return_tensors="np" + ) + + input_data = { + "input_ids": sentence_tokens, + "attention_mask": [np.ones(len(sentence_tokens))], + } + + instructor_output = instructor_model.encode([[instruction, sentence]]) + ggml_output = ggml_onnx_instructor_model.run(input_data) + + assert instructor_output == ggml_output From ff5fd53e1fe2ed69ae8975e99aeecd4e6492e5a9 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 31 Jul 2023 15:54:07 -0400 Subject: [PATCH 013/232] Add operator and input skeletons --- ggml/contrib/onnx.py | 253 +++++++++++++++++++++++++++++++++++++--- tests/test_ggml_onnx.py | 2 + 2 files changed, 236 insertions(+), 19 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 4d1666d8..24f2e4a8 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1,14 +1,233 @@ import ctypes +import struct from typing import Any, Tuple +import numpy as np import onnx from onnx import defs from onnx.backend.base import Backend, BackendRep from onnx.helper import make_opsetid -from onnx.onnx_ml_pb2 import GraphProto, ModelProto +from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto import ggml import ggml.utils +import torch + + +ggml_operators = {} +ggml_inputs = {} + +onnx_ggml_dtype = { + 1: ggml.GGML_TYPE_F32, # torch.float32 + 2: ggml.GGML_FTYPE_UNKNOWN, # torch.uint8 + 3: ggml.GGML_TYPE_I8, # torch.int8 + 4: ggml.GGML_FTYPE_UNKNOWN, # torch.uint16 + 5: ggml.GGML_TYPE_I16, # torch.int16 + 6: ggml.GGML_TYPE_I32, # torch.int32 + 7: ggml.GGML_FTYPE_UNKNOWN, # torch.int64 +} + + +def ggml_operator(operator): + def inner(func): + ggml_operators[operator] = func + return func + + return inner + + +def ggml_input_tensor(tensor_type): + def inner(func): + ggml_inputs[tensor_type] = func + return func + + return inner + + +@ggml_operator("Add") +def ggml_operator_add(node: NodeProto, tensors_dict, context): + node_inputs = [tensors_dict[inp] for inp in node.input] + + add_result = ggml.ggml_add( + context, + *node_inputs, + ) + tensors_dict[node.output[0]] = add_result + return add_result + + +@ggml_operator("Shape") +def ggml_operator_shape(node: NodeProto, tensors_dict, context): + # raise NotImplementedError(f'Operator "Shape" not implemented') + pass + + +@ggml_operator("Constant") +def ggml_operator_constant(node: NodeProto, tensors_dict, context): + data_type_to_struct_format = { + 1: "f", # FLOAT (4 bytes) + 2: "b", # INT8 (1 byte) + 3: "h", # INT16 (2 bytes) + 4: "i", # INT32 (4 bytes) + 5: "q", # INT64 (8 bytes) + 6: "B", # UINT8 (1 byte) + 7: "Q", # UINT64 (8 bytes) + 10: "e", # FLOAT16 (half-precision floating-point) (2 bytes) + 11: "d", # DOUBLE (8 bytes) + } + + node_attributes = node.attribute + raw_data = node_attributes[0].t.raw_data + data_type = node_attributes[0].t.data_type + + constant_tensor_data = np.array( + struct.unpack( + f"={len(raw_data)//struct.calcsize(data_type_to_struct_format[data_type][0])}{data_type_to_struct_format[data_type][0]}", + raw_data, + ), + dtype=data_type_to_struct_format[data_type][0], + ) + + tensors_dict[node.output[0]] = constant_tensor_data + return constant_tensor_data + + +# ------ Operators ------ + + +@ggml_operator("Mul") +def ggml_operator_mul(node: NodeProto, tensors_dict, context): + node_inputs = [tensors_dict[inp] for inp in node.input] + + mul_result = ggml.ggml_mul( + context, + *node_inputs, + ) + tensors_dict[node.output[0]] = mul_result + return mul_result + + +@ggml_operator("ConstantOfShape") +def ggml_operator_constant_of_shape(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "ConstantOfShape" not implemented') + + +@ggml_operator("Softmax") +def ggml_operator_softmax(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Softmax" not implemented') + + +@ggml_operator("Gather") +def ggml_operator_gather(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Gather" not implemented') + + +@ggml_operator("Relu") +def ggml_operator_relu(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Relu" not implemented') + + +@ggml_operator("MatMul") +def ggml_operator_mat_mul(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "MatMul" not implemented') + + +@ggml_operator("Abs") +def ggml_operator_abs(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Abs" not implemented') + + +@ggml_operator("Unsqueeze") +def ggml_operator_unsqueeze(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Unsqueeze" not implemented') + + +@ggml_operator("Sqrt") +def ggml_operator_sqrt(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Sqrt" not implemented') + + +@ggml_operator("ReduceMean") +def ggml_operator_reduce_mean(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "ReduceMean" not implemented') + + +@ggml_operator("Less") +def ggml_operator_less(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Less" not implemented') + + +@ggml_operator("Where") +def ggml_operator_where(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Where" not implemented') + + +@ggml_operator("Concat") +def ggml_operator_concat(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Concat" not implemented') + + +@ggml_operator("Div") +def ggml_operator_div(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Div" not implemented') + + +@ggml_operator("Range") +def ggml_operator_range(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Range" not implemented') + + +@ggml_operator("Sub") +def ggml_operator_sub(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Sub" not implemented') + + +@ggml_operator("Pow") +def ggml_operator_pow(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Pow" not implemented') + + +@ggml_operator("Cast") +def ggml_operator_cast(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Cast" not implemented') + + +@ggml_operator("Reshape") +def ggml_operator_reshape(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Reshape" not implemented') + + +@ggml_operator("Transpose") +def ggml_operator_transpose(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Transpose" not implemented') + + +@ggml_operator("Log") +def ggml_operator_log(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Log" not implemented') + + +@ggml_operator("Greater") +def ggml_operator_greater(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Greater" not implemented') + + +@ggml_operator("Min") +def ggml_operator_min(node: NodeProto, tensors_dict, context): + raise NotImplementedError(f'Operator "Min" not implemented') + + +## ------- Inputs -------- +@ggml_input_tensor("1") +def ggml_input_1d(node: NodeProto, tensors_dict, context): + ggml_type = node.type.tensor_type.elem_type + + inp = ggml.ggml_new_tensor_1d( + context, + onnx_ggml_dtype[ggml_type], + 1, + ) + tensors_dict[node.name] = inp class GgmlBackendRep(BackendRep): @@ -28,32 +247,28 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: exit_node = None ggml_tensors = self.weights + # handle types same as operators tensor_types = {1: ggml.ggml_new_tensor_1d, 2: ggml.ggml_new_tensor_2d} - operation_types = {"Mul": ggml.ggml_mul, "Add": ggml.ggml_add} # Define context params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - ctx = ggml.ggml_init(params=params) + context = ggml.ggml_init(params=params) # Create entry inputs for model_input in model_graph.input: - inp = ggml.ggml_new_tensor_1d( - ctx, - ggml.GGML_TYPE_F32, - 1, - ) - ggml_tensors[model_input.name] = inp + shape_dim_value = [ + dim.dim_value + for dim in model_input.type.tensor_type.shape.dim + if dim.dim_value > 0 + ][-1] + ggml_inputs[str(shape_dim_value)](model_input, ggml_tensors, context) # Build layers for node in model_graph.node: - node_inputs = [ggml_tensors[inp] for inp in node.input] - layer = operation_types[node.op_type]( - ctx, - *node_inputs, - ) - ggml_tensors[node.output[0]] = layer + node_output = ggml_operators[node.op_type](node, ggml_tensors, context) + if node.output[-1] == self.graph.output[-1].name: - exit_node = layer + exit_node = node_output # Build graph gf = ggml.ggml_build_forward(exit_node) @@ -63,11 +278,11 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml.ggml_set_f32(ggml_tensors[key], value) # Compute graph - ggml.ggml_graph_compute_with_ctx(ctx, ctypes.pointer(gf), 1) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - output = ggml.utils.to_numpy(exit_node) + graph_output = ggml.utils.to_numpy(exit_node) - return [output] + return [graph_output] class GgmlRuntimeBackend(Backend): diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index b0a93497..84f851c2 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -11,6 +11,7 @@ def test_ggml_onnx_runtime_basic(): + # return # The name of the input tensor input_name = "X" @@ -86,6 +87,7 @@ def test_ggml_onnx_runtime_basic(): def test_ggml_onnx_runtime_instructor(): + return instructor_model = INSTRUCTOR("hkunlp/instructor-base") onnx_instructor_model = onnx.load("instructor_base_onnx/encoder_model.onnx") From 280d99413a6b9027d2aad87729bc07377f5c5553 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 1 Aug 2023 17:13:11 -0400 Subject: [PATCH 014/232] Fix inputs and add Shape operator --- ggml/contrib/onnx.py | 204 ++++++++++++++++++++++++++++--------------- 1 file changed, 136 insertions(+), 68 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 24f2e4a8..d86a470e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -15,16 +15,10 @@ ggml_operators = {} -ggml_inputs = {} - -onnx_ggml_dtype = { - 1: ggml.GGML_TYPE_F32, # torch.float32 - 2: ggml.GGML_FTYPE_UNKNOWN, # torch.uint8 - 3: ggml.GGML_TYPE_I8, # torch.int8 - 4: ggml.GGML_FTYPE_UNKNOWN, # torch.uint16 - 5: ggml.GGML_TYPE_I16, # torch.int16 - 6: ggml.GGML_TYPE_I32, # torch.int32 - 7: ggml.GGML_FTYPE_UNKNOWN, # torch.int64 + +onnx_dtype_map = { + elem_type: np_dtype + for elem_type, np_dtype in onnx.mapping.TENSOR_TYPE_TO_NP_TYPE.items() } @@ -36,16 +30,10 @@ def inner(func): return inner -def ggml_input_tensor(tensor_type): - def inner(func): - ggml_inputs[tensor_type] = func - return func - - return inner - - @ggml_operator("Add") -def ggml_operator_add(node: NodeProto, tensors_dict, context): +def ggml_operator_add( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): node_inputs = [tensors_dict[inp] for inp in node.input] add_result = ggml.ggml_add( @@ -57,13 +45,29 @@ def ggml_operator_add(node: NodeProto, tensors_dict, context): @ggml_operator("Shape") -def ggml_operator_shape(node: NodeProto, tensors_dict, context): - # raise NotImplementedError(f'Operator "Shape" not implemented') - pass +def ggml_operator_shape( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + tensor = ggml.utils.to_numpy(node_inputs[0]) + start = ggml.utils.to_numpy(node_inputs[1]) if len(node_inputs) > 1 else [None] + end = ggml.utils.to_numpy(node_inputs[2]) if len(node_inputs) > 2 else [None] + + start = start[0] if len(start) > 0 else None + end = end[0] if len(end) > 0 else None + + shaped_tensor = tensor[start:end] + new_tensor = ggml.utils.from_numpy(shaped_tensor, context) + tensors_dict[node.name] = new_tensor + + return new_tensor @ggml_operator("Constant") -def ggml_operator_constant(node: NodeProto, tensors_dict, context): +def ggml_operator_constant( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): data_type_to_struct_format = { 1: "f", # FLOAT (4 bytes) 2: "b", # INT8 (1 byte) @@ -96,7 +100,9 @@ def ggml_operator_constant(node: NodeProto, tensors_dict, context): @ggml_operator("Mul") -def ggml_operator_mul(node: NodeProto, tensors_dict, context): +def ggml_operator_mul( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): node_inputs = [tensors_dict[inp] for inp in node.input] mul_result = ggml.ggml_mul( @@ -108,128 +114,159 @@ def ggml_operator_mul(node: NodeProto, tensors_dict, context): @ggml_operator("ConstantOfShape") -def ggml_operator_constant_of_shape(node: NodeProto, tensors_dict, context): +def ggml_operator_constant_of_shape( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "ConstantOfShape" not implemented') @ggml_operator("Softmax") -def ggml_operator_softmax(node: NodeProto, tensors_dict, context): +def ggml_operator_softmax( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Softmax" not implemented') @ggml_operator("Gather") -def ggml_operator_gather(node: NodeProto, tensors_dict, context): +def ggml_operator_gather( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Gather" not implemented') @ggml_operator("Relu") -def ggml_operator_relu(node: NodeProto, tensors_dict, context): +def ggml_operator_relu( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Relu" not implemented') @ggml_operator("MatMul") -def ggml_operator_mat_mul(node: NodeProto, tensors_dict, context): +def ggml_operator_mat_mul( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "MatMul" not implemented') @ggml_operator("Abs") -def ggml_operator_abs(node: NodeProto, tensors_dict, context): +def ggml_operator_abs( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Abs" not implemented') @ggml_operator("Unsqueeze") -def ggml_operator_unsqueeze(node: NodeProto, tensors_dict, context): +def ggml_operator_unsqueeze( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Unsqueeze" not implemented') @ggml_operator("Sqrt") -def ggml_operator_sqrt(node: NodeProto, tensors_dict, context): +def ggml_operator_sqrt( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Sqrt" not implemented') @ggml_operator("ReduceMean") -def ggml_operator_reduce_mean(node: NodeProto, tensors_dict, context): +def ggml_operator_reduce_mean( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "ReduceMean" not implemented') @ggml_operator("Less") -def ggml_operator_less(node: NodeProto, tensors_dict, context): +def ggml_operator_less( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Less" not implemented') @ggml_operator("Where") -def ggml_operator_where(node: NodeProto, tensors_dict, context): +def ggml_operator_where( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Where" not implemented') @ggml_operator("Concat") -def ggml_operator_concat(node: NodeProto, tensors_dict, context): +def ggml_operator_concat( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Concat" not implemented') @ggml_operator("Div") -def ggml_operator_div(node: NodeProto, tensors_dict, context): +def ggml_operator_div( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Div" not implemented') @ggml_operator("Range") -def ggml_operator_range(node: NodeProto, tensors_dict, context): +def ggml_operator_range( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Range" not implemented') @ggml_operator("Sub") -def ggml_operator_sub(node: NodeProto, tensors_dict, context): +def ggml_operator_sub( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Sub" not implemented') @ggml_operator("Pow") -def ggml_operator_pow(node: NodeProto, tensors_dict, context): +def ggml_operator_pow( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Pow" not implemented') @ggml_operator("Cast") -def ggml_operator_cast(node: NodeProto, tensors_dict, context): +def ggml_operator_cast( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Cast" not implemented') @ggml_operator("Reshape") -def ggml_operator_reshape(node: NodeProto, tensors_dict, context): +def ggml_operator_reshape( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Reshape" not implemented') @ggml_operator("Transpose") -def ggml_operator_transpose(node: NodeProto, tensors_dict, context): +def ggml_operator_transpose( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Transpose" not implemented') @ggml_operator("Log") -def ggml_operator_log(node: NodeProto, tensors_dict, context): +def ggml_operator_log( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Log" not implemented') @ggml_operator("Greater") -def ggml_operator_greater(node: NodeProto, tensors_dict, context): +def ggml_operator_greater( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Greater" not implemented') @ggml_operator("Min") -def ggml_operator_min(node: NodeProto, tensors_dict, context): +def ggml_operator_min( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p +): raise NotImplementedError(f'Operator "Min" not implemented') -## ------- Inputs -------- -@ggml_input_tensor("1") -def ggml_input_1d(node: NodeProto, tensors_dict, context): - ggml_type = node.type.tensor_type.elem_type - - inp = ggml.ggml_new_tensor_1d( - context, - onnx_ggml_dtype[ggml_type], - 1, - ) - tensors_dict[node.name] = inp - - class GgmlBackendRep(BackendRep): def __init__(self): super(GgmlBackendRep, self).__init__() @@ -247,21 +284,52 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: exit_node = None ggml_tensors = self.weights - # handle types same as operators - tensor_types = {1: ggml.ggml_new_tensor_1d, 2: ggml.ggml_new_tensor_2d} - # Define context params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) context = ggml.ggml_init(params=params) # Create entry inputs for model_input in model_graph.input: - shape_dim_value = [ - dim.dim_value - for dim in model_input.type.tensor_type.shape.dim - if dim.dim_value > 0 - ][-1] - ggml_inputs[str(shape_dim_value)](model_input, ggml_tensors, context) + input_name = model_input.name + input_data = np.array(inputs[input_name]) + + # Check if the input includes expected values + if input_name not in inputs: + raise KeyError(f'"{input_name}" must be included in the inputs.') + + # Check for rank of input + expected_rank = len(list(model_input.type.tensor_type.shape.dim)) + actual_rank = input_data.ndim + + if expected_rank != actual_rank: + raise ValueError( + f"INVALID_ARGUMENT : Invalid rank for input: {input_name} Got: {actual_rank} Expected: {expected_rank} Please fix either the inputs or the model." + ) + + # Check for input types + allow for type casting + expected_dtype = onnx_dtype_map[model_input.type.tensor_type.elem_type] + + try: + input_data.astype(expected_dtype) + except: + raise ValueError( + f'INVALID_ARGUMENT : Unexpected input data type for "{input_name}". Actual: {input_data.dtype}, expected: {expected_dtype}' + ) + + # Create the input tensors with the correct type/shape + ggml_type = ggml.utils.NUMPY_DTYPE_TO_GGML_TYPE.get( + input_data.dtype.type, + ggml.utils.GGML_TYPE.I32, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 + ) + shape = tuple(reversed(input_data.shape)) + tensor = ggml.ggml_new_tensor( + context, + ggml_type.value, + len(shape), + (ctypes.c_int64 * len(shape))(*shape), + ) + + ggml_tensors[input_name] = tensor # Build layers for node in model_graph.node: From ce82c9cd17eb99fa1a014247934f451e7ba7a9de Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 3 Aug 2023 11:35:15 -0400 Subject: [PATCH 015/232] Add Gather, Unsqueeze operators and input checks --- ggml/contrib/onnx.py | 106 +++++++++++++++++++++++++++++++++++++--- tests/test_ggml_onnx.py | 2 +- 2 files changed, 101 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index d86a470e..16c8ad3e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -36,11 +36,18 @@ def ggml_operator_add( ): node_inputs = [tensors_dict[inp] for inp in node.input] + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Add" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + add_result = ggml.ggml_add( context, *node_inputs, ) - tensors_dict[node.output[0]] = add_result + tensors_dict[output_name] = add_result return add_result @@ -50,6 +57,13 @@ def ggml_operator_shape( ): node_inputs = [tensors_dict[inp] for inp in node.input] + if len(node_inputs) == 0 or len(node_inputs) > 3: + raise ValueError( + f'Error for node "{node.name}": Operation "Shape" requires at least 1 and maximum of 3 inputs. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + tensor = ggml.utils.to_numpy(node_inputs[0]) start = ggml.utils.to_numpy(node_inputs[1]) if len(node_inputs) > 1 else [None] end = ggml.utils.to_numpy(node_inputs[2]) if len(node_inputs) > 2 else [None] @@ -57,9 +71,16 @@ def ggml_operator_shape( start = start[0] if len(start) > 0 else None end = end[0] if len(end) > 0 else None + og_dtype = tensor.dtype + shaped_tensor = tensor[start:end] + + # clamp the rank to two + shaped_tensor = np.array([shaped_tensor], dtype=og_dtype) + shaped_tensor = np.reshape(shaped_tensor, [1, -1]) + new_tensor = ggml.utils.from_numpy(shaped_tensor, context) - tensors_dict[node.name] = new_tensor + tensors_dict[output_name] = new_tensor return new_tensor @@ -83,6 +104,7 @@ def ggml_operator_constant( node_attributes = node.attribute raw_data = node_attributes[0].t.raw_data data_type = node_attributes[0].t.data_type + output_name = node.output[0] constant_tensor_data = np.array( struct.unpack( @@ -92,7 +114,10 @@ def ggml_operator_constant( dtype=data_type_to_struct_format[data_type][0], ) - tensors_dict[node.output[0]] = constant_tensor_data + # clamp the rank to two + constant_tensor_data = np.reshape(constant_tensor_data, [1, -1]) + + tensors_dict[output_name] = constant_tensor_data return constant_tensor_data @@ -105,11 +130,20 @@ def ggml_operator_mul( ): node_inputs = [tensors_dict[inp] for inp in node.input] + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Mul" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + mul_result = ggml.ggml_mul( context, *node_inputs, ) - tensors_dict[node.output[0]] = mul_result + + tensors_dict[output_name] = mul_result + return mul_result @@ -131,7 +165,37 @@ def ggml_operator_softmax( def ggml_operator_gather( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p ): - raise NotImplementedError(f'Operator "Gather" not implemented') + ## For now only handles axis = 0 TODO: add axis=1 case + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Gather" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + input_array = ( + ggml.utils.to_numpy(node_inputs[0]) + if type(node_inputs[0]) + != np.ndarray # better to check if its ggml.ggml_tensor_p but it doesnt work like that TODO: make type(tensor) work with ggml.ggml_tensor_p + else node_inputs[0] + ) + index_array = ( + ggml.utils.to_numpy(node_inputs[1]) + if type(node_inputs[1]) != np.ndarray + else node_inputs[1] + ) + + og_dtype = input_array.dtype + new_array = np.take(input_array, index_array.astype(og_dtype), axis=-1) + + # clamp the rank to two + new_array = np.array([new_array], dtype=og_dtype) + new_array = np.reshape(new_array, [1, -1]) + + new_tensor = ggml.utils.from_numpy(new_array, context) + tensors_dict[node.output[0]] = new_tensor + + return new_tensor @ggml_operator("Relu") @@ -159,7 +223,37 @@ def ggml_operator_abs( def ggml_operator_unsqueeze( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p ): - raise NotImplementedError(f'Operator "Unsqueeze" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' + ) + + x = ( + ggml.utils.to_numpy(node_inputs[0]) + if type(node_inputs[0]) != np.ndarray + else node_inputs[0] + ) + axes = ( + ggml.utils.to_numpy(node_inputs[1]) + if type(node_inputs[1]) != np.ndarray + else node_inputs[1] + ) + + og_dtype = x.dtype + + for axis in np.nditer(axes): + x = np.expand_dims(x, axis=axis) + + # clamp the rank to 3 + x = np.array([x], dtype=og_dtype) + # x = np.reshape(x, (1, 1, -1)) + + new_tensor = ggml.utils.from_numpy(x, context) + tensors_dict[node.output[0]] = new_tensor + + return new_tensor @ggml_operator("Sqrt") diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 84f851c2..b21fc2d1 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -87,7 +87,7 @@ def test_ggml_onnx_runtime_basic(): def test_ggml_onnx_runtime_instructor(): - return + # return instructor_model = INSTRUCTOR("hkunlp/instructor-base") onnx_instructor_model = onnx.load("instructor_base_onnx/encoder_model.onnx") From ec27357c7f38ffb2343860ee5ca8d40225e47f40 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 3 Aug 2023 16:38:25 -0400 Subject: [PATCH 016/232] Update test_ggml_onnx.py --- tests/test_ggml_onnx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index b21fc2d1..9eb06d30 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -104,7 +104,7 @@ def test_ggml_onnx_runtime_instructor(): input_data = { "input_ids": sentence_tokens, - "attention_mask": [np.ones(len(sentence_tokens))], + "attention_mask": [np.ones(sentence_tokens.shape[1])], } instructor_output = instructor_model.encode([[instruction, sentence]]) From 40a8b459869d0a45e01f5b16ab00ae6b699c65e8 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 3 Aug 2023 16:38:51 -0400 Subject: [PATCH 017/232] Add tests for operations (temporary) --- tests/test_ggml_onnx_ops.py | 362 ++++++++++++++++++++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 tests/test_ggml_onnx_ops.py diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py new file mode 100644 index 00000000..95b72d6b --- /dev/null +++ b/tests/test_ggml_onnx_ops.py @@ -0,0 +1,362 @@ +import io +from io import BytesIO + +import numpy as np +import onnx +import onnxruntime as ort +import pytest +import torch +import torch.onnx + +from onnx import TensorProto, helper +from onnxruntime import InferenceSession + +import ggml +import ggml.utils +from ggml.contrib.onnx import GgmlRuntimeBackend, ggml_operators + + +def test_ggml_onnx_runtime_shape_operator(): + tensors_dict = {} + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + + test_list = [0, 1, 2, 3, 5, 6, 7, 8, 9, 10] + + input_data1 = np.array(test_list, dtype=np.int32) + + tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_data1, context) + + tensors_dict["start1"] = ggml.utils.from_numpy( + np.array([], dtype=np.int32), context + ) + tensors_dict["end1"] = ggml.utils.from_numpy(np.array([], dtype=np.int32), context) + + tensors_dict["start2"] = ggml.utils.from_numpy( + np.array([], dtype=np.int32), context + ) + tensors_dict["end2"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) + + tensors_dict["start3"] = ggml.utils.from_numpy( + np.array([2], dtype=np.int32), context + ) + tensors_dict["end3"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) + + shape_node1 = onnx.NodeProto() + shape_node1.op_type = "Shape" + shape_node1.input.extend(["input_tensor"]) + shape_node1.output.extend(["output_tensor1"]) + + shape_node2 = onnx.NodeProto() + shape_node2.op_type = "Shape" + shape_node2.input.extend(["input_tensor", "start1", "end1"]) + shape_node2.output.extend(["output_tensor2"]) + + shape_node3 = onnx.NodeProto() + shape_node3.op_type = "Shape" + shape_node3.input.extend(["input_tensor", "start2", "end2"]) + shape_node3.output.extend(["output_tensor3"]) + + shape_node4 = onnx.NodeProto() + shape_node4.op_type = "Shape" + shape_node4.input.extend(["input_tensor", "start3", "end3"]) + shape_node4.output.extend(["output_tensor4"]) + + result1 = ggml_operators["Shape"](shape_node1, tensors_dict, context) + result2 = ggml_operators["Shape"](shape_node2, tensors_dict, context) + result3 = ggml_operators["Shape"](shape_node3, tensors_dict, context) + result4 = ggml_operators["Shape"](shape_node4, tensors_dict, context) + + assert list(ggml.utils.to_numpy(result1) == test_list) + assert list(ggml.utils.to_numpy(result2) == test_list) + assert list(ggml.utils.to_numpy(result3) == test_list[:6]) + assert list(ggml.utils.to_numpy(result4) == test_list[2:6]) + + ggml.ggml_free(context) + + +def test_ggml_onnx_runtime_unsqueeze_operator(): + return + + def onnx_unsqueeze(x, axes): + # Create a simple PyTorch model + class UnsqueezeModel(torch.nn.Module): + def forward(self, input): + for axis in axes: + input = torch.unsqueeze(input, dim=axis) + return input + + model = UnsqueezeModel() + + # Create a sample input tensor + x_tensor = torch.tensor(x, dtype=torch.int32) + + # Export the PyTorch model to ONNX + f = BytesIO() + torch.onnx.export( + model, + x_tensor, + f, + input_names=["data"], + output_names=["output"], + verbose=False, + ) + + # Save the ONNX model to BytesIO object + onnx_model_bytes = BytesIO(f.getvalue()) + + # Load the ONNX model from BytesIO + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + # Convert the input array to ONNX format (numpy to list) + x_list = x.tolist() + input_feed = {"data": x_list} + + # Execute the ONNX model + output = sess.run(None, input_feed) + + return np.array(output) + + tensors_dict = {} + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + + test_x = [0, 1, 2, 3, 5, 6] + test_axes1 = np.array([1], dtype=np.int32) + test_axes2 = np.array([0], dtype=np.int32) + test_axes3 = np.array([1, 2], dtype=np.int32) + + input_data1 = np.array(test_x, dtype=np.int32) + + tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_data1, context) + + tensors_dict["axes1"] = ggml.utils.from_numpy(test_axes1, context) + tensors_dict["axes2"] = ggml.utils.from_numpy(test_axes2, context) + tensors_dict["axes3"] = ggml.utils.from_numpy(test_axes3, context) + + unsqueeze_node1 = onnx.NodeProto() + unsqueeze_node1.name = "Input error Test" + unsqueeze_node1.op_type = "Unsqueeze" + unsqueeze_node1.input.extend(["input_tensor"]) + unsqueeze_node1.output.extend(["output_tensor1"]) + + unsqueeze_node2 = onnx.NodeProto() + unsqueeze_node2.op_type = "Unsqueeze" + unsqueeze_node2.input.extend(["input_tensor", "axes1"]) + unsqueeze_node2.output.extend(["output_tensor2"]) + + unsqueeze_node3 = onnx.NodeProto() + unsqueeze_node3.op_type = "Unsqueeze" + unsqueeze_node3.input.extend(["input_tensor", "axes2"]) + unsqueeze_node3.output.extend(["output_tensor3"]) + + unsqueeze_node4 = onnx.NodeProto() + unsqueeze_node4.op_type = "Unsqueeze" + unsqueeze_node4.input.extend(["input_tensor", "axes3"]) + unsqueeze_node4.output.extend(["output_tensor4"]) + + with pytest.raises(ValueError) as ex_input_error: + ggml_operators["Unsqueeze"](unsqueeze_node1, tensors_dict, context) + result2 = ggml_operators["Unsqueeze"](unsqueeze_node2, tensors_dict, context) + result3 = ggml_operators["Unsqueeze"](unsqueeze_node3, tensors_dict, context) + result4 = ggml_operators["Unsqueeze"](unsqueeze_node4, tensors_dict, context) + + assert ( + str(ex_input_error.value) + == 'Error for node "Input error Test": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: 1' + ) + + print(ggml.utils.to_numpy(result2), onnx_unsqueeze(input_data1, test_axes1)) + print(ggml.utils.to_numpy(result3), onnx_unsqueeze(input_data1, test_axes2)) + print(ggml.utils.to_numpy(result4), onnx_unsqueeze(input_data1, test_axes3)) + + assert np.array_equal( + ggml.utils.to_numpy(result2), onnx_unsqueeze(input_data1, test_axes1) + ) + assert np.array_equal( + ggml.utils.to_numpy(result3), onnx_unsqueeze(input_data1, test_axes2) + ) + assert np.array_equal( + ggml.utils.to_numpy(result4), onnx_unsqueeze(input_data1, test_axes3) + ) + + ggml.ggml_free(context) + + +def test_ggml_onnx_runtime_gather_operator(): + def onnx_gather(x, indices, axis): + # Adjust the axis value to handle negative axis + if axis < 0: + axis += len(x.shape) + + # Create ONNX model for Gather operation with specified axis + node_def = onnx.helper.make_node( + "Gather", inputs=["data", "indices"], outputs=["output"], axis=axis + ) + graph_def = onnx.helper.make_graph( + [node_def], + "gather_model", + inputs=[ + onnx.helper.make_tensor_value_info( + "data", onnx.TensorProto.INT32, list(x.shape) + ), + onnx.helper.make_tensor_value_info( + "indices", onnx.TensorProto.INT32, list(indices.shape) + ), + ], + outputs=[ + onnx.helper.make_tensor_value_info( + "output", onnx.TensorProto.INT32, list(x.shape) + ) + ], + ) + model_def = onnx.helper.make_model( + graph_def, producer_name="onnx_gather_example" + ) + + # Save the ONNX model to BytesIO object + onnx_model_bytes = BytesIO() + onnx.save_model(model_def, onnx_model_bytes) + + # Load the ONNX model from BytesIO + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + # Convert the input arrays to ONNX format (numpy to list) + x_list = x.tolist() + indices_list = indices.tolist() + + # Prepare the input feeds with the two arrays + input_feed = {"data": x_list, "indices": indices_list} + + # Execute the ONNX model + output = sess.run(None, input_feed) + + return np.array(output) + + tensors_dict = {} + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + + test_x = [ + [ + 1046676483, + -1102854076, + -1089318038, + 1023432841, + 1041114519, + -1099187814, + 1040889675, + -1088007423, + -1096868517, + -1131772615, + -1103856891, + -1097108246, + -1098364964, + 1024061975, + -1102637477, + ] + ] + test_indices1 = np.array([1], dtype=np.int32) + + input_data1 = np.array(test_x, dtype=np.int32) + + tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_data1, context) + tensors_dict["indices"] = ggml.utils.from_numpy(test_indices1, context) + + gather_node2 = onnx.helper.make_node( + "Gather", + name="/Gather", + inputs=["input_tensor", "indices"], + outputs=["output_tensor2"], + axis=0, + ) + + result4 = ggml_operators["Gather"](gather_node2, tensors_dict, context) + + print(ggml.utils.to_numpy(result4), onnx_gather(input_data1, test_indices1, 0)) + + assert np.array_equal( + ggml.utils.to_numpy(result4), onnx_gather(input_data1, test_indices1, 0) + ) + + ggml.ggml_free(context) + + +def test_ggml_onnx_runtime_basic(): + # The name of the input tensor + input_name = "X" + + # The name of the weights tensor + weight_name_a = "A" + weight_name_b = "B" + + # The name of the output + output_name = "Y" + + # Create the nodes (operations) in our graph + node1 = helper.make_node( + "Mul", [input_name, input_name], ["X_squared"], name="node1" + ) # X^2 + node2 = helper.make_node( + "Mul", ["X_squared", weight_name_a], ["X_squared_times_a"], name="node2" + ) # X^2 * A + node3 = helper.make_node( + "Add", ["X_squared_times_a", weight_name_b], [output_name], name="node3" + ) # X^2 * A + B + + # Define the tensors (values) in our graph + X_value_info = helper.make_tensor_value_info( + input_name, TensorProto.FLOAT, [None, 1] + ) + + output_value_info = helper.make_tensor_value_info( + output_name, TensorProto.FLOAT, [None, 1] + ) + + # Set A and B as parameters/weights + weights_a = np.ones(1, dtype=float).astype(np.float32) + weights_b = np.ones(1, dtype=float).astype(np.float32) + + A_init = helper.make_tensor( + weight_name_a, + TensorProto.FLOAT, + [ + 1, + ], + weights_a, + ) + B_init = helper.make_tensor( + weight_name_b, + TensorProto.FLOAT, + [ + 1, + ], + weights_b, + ) + + # Create the graph (model). + graph_def = helper.make_graph( + [node1, node2, node3], + "simple_expression_model", + [X_value_info], + [output_value_info], + [A_init, B_init], + ) + + model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") + + input_data = {"X": np.array([[6.0]], dtype=np.float32)} + + f = io.BytesIO() + onnx.save(model_def, f) + + runtime_result = InferenceSession(f.getvalue()).run(None, input_data) + + ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) + ggml_result = ggml_dummy_model.run(input_data) + assert ggml_result == runtime_result From 20ccf0e509ed34eb5d335513348392aee2227f37 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 3 Aug 2023 16:44:34 -0400 Subject: [PATCH 018/232] Fix Constant types, remove reshapes, rework Gather Operators no longer manipulate the shape of the output tensors, however, Gather no longer works with the new axis values which are pulled from the node. The tests also prove that ONNX Gather fails to operate on the input data if data is of rank 2, index is of rank 1 and axes=0. Before this change axis was set to a fixed -1. --- ggml/contrib/onnx.py | 120 +++++++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 45 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 16c8ad3e..1d0ea28c 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -30,6 +30,9 @@ def inner(func): return inner +# ------ Operators ------ + + @ggml_operator("Add") def ggml_operator_add( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p @@ -57,6 +60,8 @@ def ggml_operator_shape( ): node_inputs = [tensors_dict[inp] for inp in node.input] + print(node) + if len(node_inputs) == 0 or len(node_inputs) > 3: raise ValueError( f'Error for node "{node.name}": Operation "Shape" requires at least 1 and maximum of 3 inputs. Actual number of inputs: {len(node_inputs)}' @@ -71,14 +76,8 @@ def ggml_operator_shape( start = start[0] if len(start) > 0 else None end = end[0] if len(end) > 0 else None - og_dtype = tensor.dtype - shaped_tensor = tensor[start:end] - # clamp the rank to two - shaped_tensor = np.array([shaped_tensor], dtype=og_dtype) - shaped_tensor = np.reshape(shaped_tensor, [1, -1]) - new_tensor = ggml.utils.from_numpy(shaped_tensor, context) tensors_dict[output_name] = new_tensor @@ -89,41 +88,40 @@ def ggml_operator_shape( def ggml_operator_constant( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p ): + print(node) data_type_to_struct_format = { - 1: "f", # FLOAT (4 bytes) - 2: "b", # INT8 (1 byte) - 3: "h", # INT16 (2 bytes) - 4: "i", # INT32 (4 bytes) - 5: "q", # INT64 (8 bytes) - 6: "B", # UINT8 (1 byte) - 7: "Q", # UINT64 (8 bytes) - 10: "e", # FLOAT16 (half-precision floating-point) (2 bytes) - 11: "d", # DOUBLE (8 bytes) + 1: ("f", np.float32), # FLOAT (4 bytes) + 2: ("b", np.int8), # INT8 (1 byte) + 3: ("h", np.int16), # INT16 (2 bytes) + 4: ("i", np.int32), # INT32 (4 bytes) + 5: ("q", np.int32), # INT64 (8 bytes) must be np.int64 but 32 for now + 6: ("B", np.int8), # UINT8 (1 byte) + 7: ("Q", np.int32), # UINT64 (8 bytes) must be np.int64 but 32 for now + 10: ("e", np.float16), # FLOAT16 (half-precision floating-point) (2 bytes) + 11: ("d", np.int32), # DOUBLE (8 bytes) must be np.int64 but 32 for now } node_attributes = node.attribute raw_data = node_attributes[0].t.raw_data data_type = node_attributes[0].t.data_type output_name = node.output[0] + constant_type = data_type_to_struct_format[data_type] + + dtype = constant_type[1] constant_tensor_data = np.array( struct.unpack( - f"={len(raw_data)//struct.calcsize(data_type_to_struct_format[data_type][0])}{data_type_to_struct_format[data_type][0]}", + f"={len(raw_data)//struct.calcsize(constant_type[0])}{constant_type[0]}", raw_data, ), - dtype=data_type_to_struct_format[data_type][0], + dtype=dtype, ) - # clamp the rank to two - constant_tensor_data = np.reshape(constant_tensor_data, [1, -1]) - - tensors_dict[output_name] = constant_tensor_data + new_tensor = ggml.utils.from_numpy(constant_tensor_data, context) + tensors_dict[output_name] = new_tensor return constant_tensor_data -# ------ Operators ------ - - @ggml_operator("Mul") def ggml_operator_mul( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p @@ -143,7 +141,6 @@ def ggml_operator_mul( ) tensors_dict[output_name] = mul_result - return mul_result @@ -165,32 +162,35 @@ def ggml_operator_softmax( def ggml_operator_gather( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p ): - ## For now only handles axis = 0 TODO: add axis=1 case node_inputs = [tensors_dict[inp] for inp in node.input] + print("Gather attribs:") + print(node.attribute) + if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Gather" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Gather" requires exactly two inputs and one axis. Actual number of inputs: {len(node_inputs)}' ) - input_array = ( - ggml.utils.to_numpy(node_inputs[0]) - if type(node_inputs[0]) - != np.ndarray # better to check if its ggml.ggml_tensor_p but it doesnt work like that TODO: make type(tensor) work with ggml.ggml_tensor_p - else node_inputs[0] - ) - index_array = ( - ggml.utils.to_numpy(node_inputs[1]) - if type(node_inputs[1]) != np.ndarray - else node_inputs[1] - ) + print(node) + + input_array = ggml.utils.to_numpy(node_inputs[0]) + index_array = ggml.utils.to_numpy(node_inputs[1]) + + axis = node.attribute[0].i if len(node.attribute) > 0 else -1 og_dtype = input_array.dtype - new_array = np.take(input_array, index_array.astype(og_dtype), axis=-1) + + print(input_array, index_array) + + # create + # check test_ggml.py + + new_array = np.take(input_array, index_array, axis=axis) # clamp the rank to two - new_array = np.array([new_array], dtype=og_dtype) - new_array = np.reshape(new_array, [1, -1]) + # new_array = np.array([new_array], dtype=og_dtype) + # new_array = np.reshape(new_array, [1, -1]) new_tensor = ggml.utils.from_numpy(new_array, context) tensors_dict[node.output[0]] = new_tensor @@ -225,6 +225,9 @@ def ggml_operator_unsqueeze( ): node_inputs = [tensors_dict[inp] for inp in node.input] + print("Unsqueeze attribs:") + print(node.attribute) + if len(node_inputs) != 2: raise ValueError( f'Error for node "{node.name}": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' @@ -246,10 +249,6 @@ def ggml_operator_unsqueeze( for axis in np.nditer(axes): x = np.expand_dims(x, axis=axis) - # clamp the rank to 3 - x = np.array([x], dtype=og_dtype) - # x = np.reshape(x, (1, 1, -1)) - new_tensor = ggml.utils.from_numpy(x, context) tensors_dict[node.output[0]] = new_tensor @@ -288,6 +287,37 @@ def ggml_operator_where( def ggml_operator_concat( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p ): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2 or len(node.attribute) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Concat" requires exactly two inputs and an axis attribute. Actual number of inputs: {len(node_inputs)}' + ) + + axis = node.attribute[0].i + + a = ( + ggml.utils.to_numpy(node_inputs[0]) + if type(node_inputs[0]) != np.ndarray + else node_inputs[0] + ) + + b = ( + ggml.utils.to_numpy(node_inputs[1]) + if type(node_inputs[1]) != np.ndarray + else node_inputs[1] + ) + + print(node) + print(a, b, axis) + + # shapes = [tensor.shape for tensor in tensors] + # if not all(shape[:axis] == shapes[0][:axis] and shape[axis + 1:] == shapes[0][axis + 1:] for shape in shapes): + # raise ValueError("All tensors must have the same shape along the specified axis.") + + # # Perform concatenation along the specified axis + # result = np.concatenate(tensors, axis=axis) + raise NotImplementedError(f'Operator "Concat" not implemented') From ee89871517e170b0e64e957c3fea581ab29f6001 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 8 Aug 2023 14:22:03 -0400 Subject: [PATCH 019/232] Use `ggml_custom_op_t` for operators, rework Constant - Implement `ggml_custom_op_t` for current operators - Fix/rework Shape operator - Rework Constant operator - Improve all tests --- ggml/contrib/onnx.py | 332 ++++++++++++++++++++++-------------- tests/test_ggml_onnx_ops.py | 235 +++++++++++++++++-------- 2 files changed, 368 insertions(+), 199 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 1d0ea28c..9a7fde16 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1,6 +1,6 @@ import ctypes import struct -from typing import Any, Tuple +from typing import Any, Tuple, List import numpy as np import onnx @@ -8,10 +8,12 @@ from onnx.backend.base import Backend, BackendRep from onnx.helper import make_opsetid from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto +from onnx.helper import tensor_dtype_to_np_dtype import ggml import ggml.utils import torch +from typing import Optional ggml_operators = {} @@ -35,7 +37,7 @@ def inner(func): @ggml_operator("Add") def ggml_operator_add( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -54,77 +56,132 @@ def ggml_operator_add( return add_result +class ShapeUserInput(ctypes.Structure): + _fields_ = [("start", ctypes.c_int), ("end", ctypes.c_int)] + + +@ggml.ggml_custom2_op_t +def custom_shape( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ShapeUserInput)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + start = userdata_data.start + end = userdata_data.end + + shaped_tensor = tensor[start:end] + tensor_shape = np.array(shaped_tensor.shape, dtype=np.int32) + + ggml.utils.to_numpy(tensor_out)[:] = tensor_shape + + @ggml_operator("Shape") def ggml_operator_shape( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] - print(node) - if len(node_inputs) == 0 or len(node_inputs) > 3: raise ValueError( f'Error for node "{node.name}": Operation "Shape" requires at least 1 and maximum of 3 inputs. Actual number of inputs: {len(node_inputs)}' ) - output_name = node.output[0] - tensor = ggml.utils.to_numpy(node_inputs[0]) - start = ggml.utils.to_numpy(node_inputs[1]) if len(node_inputs) > 1 else [None] - end = ggml.utils.to_numpy(node_inputs[2]) if len(node_inputs) > 2 else [None] + start = ( + ggml.utils.to_numpy(node_inputs[1]) + if len(node_inputs) > 1 + else [ctypes.c_int(0)] + ) + end = ( + ggml.utils.to_numpy(node_inputs[2]) + if len(node_inputs) > 2 + else [ctypes.c_int(tensor.shape[-1])] + ) - start = start[0] if len(start) > 0 else None - end = end[0] if len(end) > 0 else None + start = start[0] if len(start) else ctypes.c_int(0) + end = end[0] if len(end) else ctypes.c_int(tensor.shape[-1]) - shaped_tensor = tensor[start:end] + shape_userdata = ShapeUserInput(start, end) + userdata_p = ctypes.cast(ctypes.pointer(shape_userdata), ctypes.c_void_p) + + output_shape = len(list(tensor.shape)) + + x = np.empty(output_shape, dtype=tensor.dtype) + + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + node_inputs[0], + custom_shape, + 1, + userdata_p, + ) - new_tensor = ggml.utils.from_numpy(shaped_tensor, context) - tensors_dict[output_name] = new_tensor + refs.append(shape_userdata) return new_tensor +@ggml.ggml_custom2_op_t +def custom_constant( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + shape = ggml.utils.to_numpy(tensor_in_1).shape + constant_data = ggml.utils.to_numpy(tensor_in_2) + + new_tenor = constant_data.reshape(shape) + + ggml.utils.to_numpy(tensor_out)[:] = new_tenor + + @ggml_operator("Constant") def ggml_operator_constant( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - print(node) - data_type_to_struct_format = { - 1: ("f", np.float32), # FLOAT (4 bytes) - 2: ("b", np.int8), # INT8 (1 byte) - 3: ("h", np.int16), # INT16 (2 bytes) - 4: ("i", np.int32), # INT32 (4 bytes) - 5: ("q", np.int32), # INT64 (8 bytes) must be np.int64 but 32 for now - 6: ("B", np.int8), # UINT8 (1 byte) - 7: ("Q", np.int32), # UINT64 (8 bytes) must be np.int64 but 32 for now - 10: ("e", np.float16), # FLOAT16 (half-precision floating-point) (2 bytes) - 11: ("d", np.int32), # DOUBLE (8 bytes) must be np.int64 but 32 for now - } - node_attributes = node.attribute - raw_data = node_attributes[0].t.raw_data - data_type = node_attributes[0].t.data_type - output_name = node.output[0] - constant_type = data_type_to_struct_format[data_type] - dtype = constant_type[1] + value_attr = next(attr for attr in node_attributes if attr.name == "value") + tensor = value_attr.t + data_type = tensor.data_type + np_data_type = tensor_dtype_to_np_dtype(data_type) - constant_tensor_data = np.array( - struct.unpack( - f"={len(raw_data)//struct.calcsize(constant_type[0])}{constant_type[0]}", - raw_data, - ), - dtype=dtype, + data_tensor = ggml.utils.from_numpy( + np.frombuffer(tensor.raw_data, dtype=np_data_type), context ) - new_tensor = ggml.utils.from_numpy(constant_tensor_data, context) - tensors_dict[output_name] = new_tensor - return constant_tensor_data + x = np.empty(tensor.dims, dtype=np_data_type) + + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + data_tensor, + custom_constant, + 1, + None, + ) + + return new_tensor @ggml_operator("Mul") def ggml_operator_mul( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -146,247 +203,253 @@ def ggml_operator_mul( @ggml_operator("ConstantOfShape") def ggml_operator_constant_of_shape( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "ConstantOfShape" not implemented') @ggml_operator("Softmax") def ggml_operator_softmax( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Softmax" not implemented') +@ggml.ggml_custom3_op_t +def custom_gather( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + input_array = ggml.utils.to_numpy(tensor_in_2) + index_array = ggml.utils.to_numpy(tensor_in_3) + axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + + new_array = np.take(input_array, index_array, axis=axis) + + ggml.utils.to_numpy(tensor_out)[:] = new_array + + @ggml_operator("Gather") def ggml_operator_gather( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] - print("Gather attribs:") - print(node.attribute) - if len(node_inputs) != 2: raise ValueError( f'Error for node "{node.name}": Operation "Gather" requires exactly two inputs and one axis. Actual number of inputs: {len(node_inputs)}' ) - print(node) + axis = node.attribute[0].i if len(node.attribute) > 0 else -1 + + axis_c = ctypes.c_int(axis) input_array = ggml.utils.to_numpy(node_inputs[0]) index_array = ggml.utils.to_numpy(node_inputs[1]) - axis = node.attribute[0].i if len(node.attribute) > 0 else -1 - - og_dtype = input_array.dtype - - print(input_array, index_array) + output_shape = (input_array.ndim - 1) * (1,) + index_array.shape - # create - # check test_ggml.py + x = np.empty(output_shape, dtype=input_array.dtype) - new_array = np.take(input_array, index_array, axis=axis) + x_t = ggml.utils.from_numpy(x, context) - # clamp the rank to two - # new_array = np.array([new_array], dtype=og_dtype) - # new_array = np.reshape(new_array, [1, -1]) + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_gather, + 1, + ctypes.pointer(axis_c), + ) - new_tensor = ggml.utils.from_numpy(new_array, context) - tensors_dict[node.output[0]] = new_tensor + refs.append(axis_c) return new_tensor @ggml_operator("Relu") def ggml_operator_relu( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Relu" not implemented') @ggml_operator("MatMul") def ggml_operator_mat_mul( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "MatMul" not implemented') @ggml_operator("Abs") def ggml_operator_abs( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Abs" not implemented') +@ggml.ggml_custom3_op_t +def custom_unsqueeze( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_2) + axes = ggml.utils.to_numpy(tensor_in_3) + + for axis in np.nditer(axes): + x = np.expand_dims(x, axis=axis) + + ggml.utils.to_numpy(tensor_out)[:] = x + + @ggml_operator("Unsqueeze") def ggml_operator_unsqueeze( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] - print("Unsqueeze attribs:") - print(node.attribute) - if len(node_inputs) != 2: raise ValueError( f'Error for node "{node.name}": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' ) - x = ( - ggml.utils.to_numpy(node_inputs[0]) - if type(node_inputs[0]) != np.ndarray - else node_inputs[0] - ) - axes = ( - ggml.utils.to_numpy(node_inputs[1]) - if type(node_inputs[1]) != np.ndarray - else node_inputs[1] - ) + x = ggml.utils.to_numpy(node_inputs[0]) + axes = ggml.utils.to_numpy(node_inputs[1]) - og_dtype = x.dtype + output_shape = x.shape for axis in np.nditer(axes): - x = np.expand_dims(x, axis=axis) + output_shape = np.insert(output_shape, axis, 1) + + x = np.empty(output_shape, dtype=x.dtype) - new_tensor = ggml.utils.from_numpy(x, context) - tensors_dict[node.output[0]] = new_tensor + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_unsqueeze, + 1, + None, + ) return new_tensor @ggml_operator("Sqrt") def ggml_operator_sqrt( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Sqrt" not implemented') @ggml_operator("ReduceMean") def ggml_operator_reduce_mean( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "ReduceMean" not implemented') @ggml_operator("Less") def ggml_operator_less( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Less" not implemented') @ggml_operator("Where") def ggml_operator_where( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Where" not implemented') @ggml_operator("Concat") def ggml_operator_concat( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - node_inputs = [tensors_dict[inp] for inp in node.input] - - if len(node_inputs) != 2 or len(node.attribute) != 1: - raise ValueError( - f'Error for node "{node.name}": Operation "Concat" requires exactly two inputs and an axis attribute. Actual number of inputs: {len(node_inputs)}' - ) - - axis = node.attribute[0].i - - a = ( - ggml.utils.to_numpy(node_inputs[0]) - if type(node_inputs[0]) != np.ndarray - else node_inputs[0] - ) - - b = ( - ggml.utils.to_numpy(node_inputs[1]) - if type(node_inputs[1]) != np.ndarray - else node_inputs[1] - ) - - print(node) - print(a, b, axis) - - # shapes = [tensor.shape for tensor in tensors] - # if not all(shape[:axis] == shapes[0][:axis] and shape[axis + 1:] == shapes[0][axis + 1:] for shape in shapes): - # raise ValueError("All tensors must have the same shape along the specified axis.") - - # # Perform concatenation along the specified axis - # result = np.concatenate(tensors, axis=axis) - raise NotImplementedError(f'Operator "Concat" not implemented') @ggml_operator("Div") def ggml_operator_div( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Div" not implemented') @ggml_operator("Range") def ggml_operator_range( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Range" not implemented') @ggml_operator("Sub") def ggml_operator_sub( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Sub" not implemented') @ggml_operator("Pow") def ggml_operator_pow( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Pow" not implemented') @ggml_operator("Cast") def ggml_operator_cast( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Cast" not implemented') @ggml_operator("Reshape") def ggml_operator_reshape( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Reshape" not implemented') @ggml_operator("Transpose") def ggml_operator_transpose( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Transpose" not implemented') @ggml_operator("Log") def ggml_operator_log( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Log" not implemented') @ggml_operator("Greater") def ggml_operator_greater( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Greater" not implemented') @ggml_operator("Min") def ggml_operator_min( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): raise NotImplementedError(f'Operator "Min" not implemented') @@ -412,6 +475,8 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) context = ggml.ggml_init(params=params) + refs: List[Any] = [] + # Create entry inputs for model_input in model_graph.input: input_name = model_input.name @@ -457,7 +522,12 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Build layers for node in model_graph.node: - node_output = ggml_operators[node.op_type](node, ggml_tensors, context) + node_output = ggml_operators[node.op_type]( + node, + ggml_tensors, + context, + refs, + ) if node.output[-1] == self.graph.output[-1].name: exit_node = node_output diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 95b72d6b..4cbbaf13 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -1,3 +1,4 @@ +import ctypes import io from io import BytesIO @@ -7,8 +8,7 @@ import pytest import torch import torch.onnx - -from onnx import TensorProto, helper +from onnx import TensorProto, helper, numpy_helper from onnxruntime import InferenceSession import ggml @@ -17,6 +17,7 @@ def test_ggml_onnx_runtime_shape_operator(): + # return tensors_dict = {} params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) @@ -43,41 +44,54 @@ def test_ggml_onnx_runtime_shape_operator(): ) tensors_dict["end3"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) - shape_node1 = onnx.NodeProto() - shape_node1.op_type = "Shape" - shape_node1.input.extend(["input_tensor"]) - shape_node1.output.extend(["output_tensor1"]) + shape_node1 = onnx.helper.make_node( + "Shape", + name="Shape1", + inputs=["input_tensor"], + outputs=["output_tensor1"], + ) - shape_node2 = onnx.NodeProto() - shape_node2.op_type = "Shape" - shape_node2.input.extend(["input_tensor", "start1", "end1"]) - shape_node2.output.extend(["output_tensor2"]) + shape_node2 = onnx.helper.make_node( + "Shape", + name="Shape2", + inputs=["input_tensor", "start1", "end1"], + outputs=["output_tensor2"], + ) - shape_node3 = onnx.NodeProto() - shape_node3.op_type = "Shape" - shape_node3.input.extend(["input_tensor", "start2", "end2"]) - shape_node3.output.extend(["output_tensor3"]) + shape_node3 = onnx.helper.make_node( + "Shape", + name="Shape3", + inputs=["input_tensor", "start2", "end2"], + outputs=["output_tensor3"], + ) + + shape_node4 = onnx.helper.make_node( + "Shape", + name="Shape4", + inputs=["input_tensor", "start3", "end3"], + outputs=["output_tensor4"], + ) - shape_node4 = onnx.NodeProto() - shape_node4.op_type = "Shape" - shape_node4.input.extend(["input_tensor", "start3", "end3"]) - shape_node4.output.extend(["output_tensor4"]) + nodes = [shape_node1, shape_node2, shape_node3, shape_node4] + results = [] + refs = [] - result1 = ggml_operators["Shape"](shape_node1, tensors_dict, context) - result2 = ggml_operators["Shape"](shape_node2, tensors_dict, context) - result3 = ggml_operators["Shape"](shape_node3, tensors_dict, context) - result4 = ggml_operators["Shape"](shape_node4, tensors_dict, context) + for shape_node in nodes: + output_tensor = ggml_operators["Shape"](shape_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + results.append(ggml.utils.to_numpy(output_tensor)) - assert list(ggml.utils.to_numpy(result1) == test_list) - assert list(ggml.utils.to_numpy(result2) == test_list) - assert list(ggml.utils.to_numpy(result3) == test_list[:6]) - assert list(ggml.utils.to_numpy(result4) == test_list[2:6]) + assert results[0] == list(input_data1.shape) + assert results[1] == list(input_data1.shape) + assert results[2] == list(input_data1[:6].shape) + assert results[3] == list(input_data1[2:6].shape) ggml.ggml_free(context) def test_ggml_onnx_runtime_unsqueeze_operator(): - return + # return def onnx_unsqueeze(x, axes): # Create a simple PyTorch model @@ -117,7 +131,7 @@ def forward(self, input): # Execute the ONNX model output = sess.run(None, input_feed) - return np.array(output) + return output[0] tensors_dict = {} @@ -158,35 +172,39 @@ def forward(self, input): unsqueeze_node4.input.extend(["input_tensor", "axes3"]) unsqueeze_node4.output.extend(["output_tensor4"]) + refs = [] + nodes = [unsqueeze_node2, unsqueeze_node3, unsqueeze_node4] + results = [] + with pytest.raises(ValueError) as ex_input_error: - ggml_operators["Unsqueeze"](unsqueeze_node1, tensors_dict, context) - result2 = ggml_operators["Unsqueeze"](unsqueeze_node2, tensors_dict, context) - result3 = ggml_operators["Unsqueeze"](unsqueeze_node3, tensors_dict, context) - result4 = ggml_operators["Unsqueeze"](unsqueeze_node4, tensors_dict, context) + ggml_operators["Unsqueeze"](unsqueeze_node1, tensors_dict, context, refs) + + for shape_node in nodes: + output_tensor = ggml_operators["Unsqueeze"]( + shape_node, tensors_dict, context, refs + ) + + gf = ggml.ggml_build_forward(output_tensor) + + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + + results.append(ggml.utils.to_numpy(output_tensor)) assert ( str(ex_input_error.value) == 'Error for node "Input error Test": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: 1' ) - print(ggml.utils.to_numpy(result2), onnx_unsqueeze(input_data1, test_axes1)) - print(ggml.utils.to_numpy(result3), onnx_unsqueeze(input_data1, test_axes2)) - print(ggml.utils.to_numpy(result4), onnx_unsqueeze(input_data1, test_axes3)) - - assert np.array_equal( - ggml.utils.to_numpy(result2), onnx_unsqueeze(input_data1, test_axes1) - ) - assert np.array_equal( - ggml.utils.to_numpy(result3), onnx_unsqueeze(input_data1, test_axes2) - ) - assert np.array_equal( - ggml.utils.to_numpy(result4), onnx_unsqueeze(input_data1, test_axes3) - ) + assert np.array_equal(results[0], onnx_unsqueeze(input_data1, test_axes1)) + assert np.array_equal(results[1], onnx_unsqueeze(input_data1, test_axes2)) + assert np.array_equal(results[2], onnx_unsqueeze(input_data1, test_axes3)) ggml.ggml_free(context) def test_ggml_onnx_runtime_gather_operator(): + # return + def onnx_gather(x, indices, axis): # Adjust the axis value to handle negative axis if axis < 0: @@ -235,7 +253,7 @@ def onnx_gather(x, indices, axis): # Execute the ONNX model output = sess.run(None, input_feed) - return np.array(output) + return output[0] tensors_dict = {} @@ -243,30 +261,31 @@ def onnx_gather(x, indices, axis): context = ggml.ggml_init(params=params) test_x = [ - [ - 1046676483, - -1102854076, - -1089318038, - 1023432841, - 1041114519, - -1099187814, - 1040889675, - -1088007423, - -1096868517, - -1131772615, - -1103856891, - -1097108246, - -1098364964, - 1024061975, - -1102637477, - ] + 1046676483, + -1102854076, + -1089318038, + 1023432841, + 1041114519, + -1099187814, + 1040889675, + -1088007423, + -1096868517, + -1131772615, + -1103856891, + -1097108246, + -1098364964, + 1024061975, + -1102637477, ] test_indices1 = np.array([1], dtype=np.int32) input_data1 = np.array(test_x, dtype=np.int32) - tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_data1, context) - tensors_dict["indices"] = ggml.utils.from_numpy(test_indices1, context) + input_tensor = ggml.utils.from_numpy(input_data1, context) + indices_tensor = ggml.utils.from_numpy(test_indices1, context) + + tensors_dict["input_tensor"] = input_tensor + tensors_dict["indices"] = indices_tensor gather_node2 = onnx.helper.make_node( "Gather", @@ -276,18 +295,97 @@ def onnx_gather(x, indices, axis): axis=0, ) - result4 = ggml_operators["Gather"](gather_node2, tensors_dict, context) + refs = [] + + output_tensor = ggml_operators["Gather"](gather_node2, tensors_dict, context, refs) + + gf = ggml.ggml_build_forward(output_tensor) - print(ggml.utils.to_numpy(result4), onnx_gather(input_data1, test_indices1, 0)) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + output_tensor = ggml.ggml_get_tensor(context, ggml.ggml_get_name(output_tensor)) assert np.array_equal( - ggml.utils.to_numpy(result4), onnx_gather(input_data1, test_indices1, 0) + ggml.utils.to_numpy(output_tensor), onnx_gather(input_data1, test_indices1, 0) ) ggml.ggml_free(context) +def test_ggml_onnx_constant_operator(): + def onnx_constant(value, dtype, shape): + tensor = numpy_helper.from_array(value) + constant_node = onnx.helper.make_node( + "Constant", inputs=[], outputs=["constant_output"], value=tensor + ) + graph = onnx.helper.make_graph( + [constant_node], + "constant_graph", + inputs=[], + outputs=[ + onnx.helper.make_tensor_value_info("constant_output", dtype, shape) + ], + ) + model = onnx.helper.make_model(graph) + + return numpy_helper.to_array(model.graph.node[0].attribute[0].t) + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + + constant1 = np.array([1], dtype=np.int32) + constant2 = np.array([[1]], dtype=np.int32) + constant3 = np.array([[1, 2], [3, 4], [6, 6]], dtype=np.int32) + + dtype = onnx.TensorProto.INT32 + + constant_numpy1 = onnx_constant(constant1, dtype, constant1.shape) + constant_numpy2 = onnx_constant(constant2, dtype, constant2.shape) + constant_numpy3 = onnx_constant(constant3, dtype, constant3.shape) + + constant_node1 = onnx.helper.make_node( + "Constant", + inputs=[], + name="constant_node1", + outputs=["constant_output1"], + value=numpy_helper.from_array(constant1), + ) + constant_node2 = onnx.helper.make_node( + "Constant", + name="constant_node2", + inputs=[], + outputs=["constant_output2"], + value=numpy_helper.from_array(constant2), + ) + constant_node3 = onnx.helper.make_node( + "Constant", + name="constant_node3", + inputs=[], + outputs=["constant_output3"], + value=numpy_helper.from_array(constant3), + ) + + nodes = [constant_node1, constant_node2, constant_node3] + results = [] + refs = [] + + for shape_node in nodes: + output_tensor = ggml_operators["Constant"]( + shape_node, tensors_dict, context, refs + ) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + results.append(ggml.utils.to_numpy(output_tensor)) + + assert np.array_equal(results[0], constant_numpy1) + assert np.array_equal(results[1], constant_numpy2) + assert np.array_equal(results[2], constant_numpy3) + + ggml.ggml_free(context) + + def test_ggml_onnx_runtime_basic(): + # return # The name of the input tensor input_name = "X" @@ -359,4 +457,5 @@ def test_ggml_onnx_runtime_basic(): ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) ggml_result = ggml_dummy_model.run(input_data) + assert ggml_result == runtime_result From 5f9f952022be8b4b44f498742efa983b0e83148a Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 8 Aug 2023 14:57:01 -0400 Subject: [PATCH 020/232] Fix Constant dtype and default shape issues --- ggml/contrib/onnx.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 9a7fde16..b6148cd3 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -159,12 +159,16 @@ def ggml_operator_constant( data_type = tensor.data_type np_data_type = tensor_dtype_to_np_dtype(data_type) + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + data_tensor = ggml.utils.from_numpy( - np.frombuffer(tensor.raw_data, dtype=np_data_type), context + np.frombuffer(tensor.raw_data, dtype=np_data_type).astype(np_data_type_limit), + context, ) - x = np.empty(tensor.dims, dtype=np_data_type) + tensor_shape = tensor.dims or (1,) + x = np.empty(tensor_shape, dtype=np_data_type_limit) x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( From f4eb3caec7cf7b8d0a823848f8c01ef29e10b751 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 8 Aug 2023 16:55:21 -0400 Subject: [PATCH 021/232] Fix scalar constants, add scalar test case --- ggml/contrib/onnx.py | 15 +++++++++++---- tests/test_ggml_onnx_ops.py | 13 ++++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index b6148cd3..65b7167d 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -142,10 +142,12 @@ def custom_constant( ): shape = ggml.utils.to_numpy(tensor_in_1).shape constant_data = ggml.utils.to_numpy(tensor_in_2) - new_tenor = constant_data.reshape(shape) - ggml.utils.to_numpy(tensor_out)[:] = new_tenor + if shape == (): + ggml.utils.to_numpy(tensor_out)[()] = new_tenor + else: + ggml.utils.to_numpy(tensor_out)[:] = new_tenor @ggml_operator("Constant") @@ -166,10 +168,15 @@ def ggml_operator_constant( context, ) - tensor_shape = tensor.dims or (1,) + tensor_shape = tensor.dims or () x = np.empty(tensor_shape, dtype=np_data_type_limit) - x_t = ggml.utils.from_numpy(x, context) + x_t = None + + if tensor_shape == (): + x_t = ggml.ggml_new_i32(context, -1) + else: + x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( context, diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 4cbbaf13..20b704e0 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -336,12 +336,14 @@ def onnx_constant(value, dtype, shape): constant1 = np.array([1], dtype=np.int32) constant2 = np.array([[1]], dtype=np.int32) constant3 = np.array([[1, 2], [3, 4], [6, 6]], dtype=np.int32) + constant4 = np.array(6, dtype=np.int64) dtype = onnx.TensorProto.INT32 constant_numpy1 = onnx_constant(constant1, dtype, constant1.shape) constant_numpy2 = onnx_constant(constant2, dtype, constant2.shape) constant_numpy3 = onnx_constant(constant3, dtype, constant3.shape) + constant_numpy4 = onnx_constant(constant4, dtype, constant4.shape) constant_node1 = onnx.helper.make_node( "Constant", @@ -365,7 +367,15 @@ def onnx_constant(value, dtype, shape): value=numpy_helper.from_array(constant3), ) - nodes = [constant_node1, constant_node2, constant_node3] + constant_node4 = onnx.helper.make_node( + "Constant", + name="constant_node3", + inputs=[], + outputs=["constant_output3"], + value=numpy_helper.from_array(constant4), + ) + + nodes = [constant_node1, constant_node2, constant_node3, constant_node4] results = [] refs = [] @@ -380,6 +390,7 @@ def onnx_constant(value, dtype, shape): assert np.array_equal(results[0], constant_numpy1) assert np.array_equal(results[1], constant_numpy2) assert np.array_equal(results[2], constant_numpy3) + assert results[3] == constant_numpy4 ggml.ggml_free(context) From 3fd14ee0aef596381fee8414ba3d9dd0c9dca04d Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 10:53:33 -0400 Subject: [PATCH 022/232] Handle scalar values --- ggml/utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ggml/utils.py b/ggml/utils.py index 63428223..0f8a4bff 100644 --- a/ggml/utils.py +++ b/ggml/utils.py @@ -87,7 +87,10 @@ def from_numpy(x: npt.NDArray[Any], ctx: ggml.ggml_context_p) -> ggml.ggml_tenso *tuple(reversed(x.strides)) ) if tensor.contents.data is not None: - to_numpy(tensor)[:] = x + if shape == (): + to_numpy(tensor)[()] = x + else: + to_numpy(tensor)[:] = x return tensor From cfbf2926fbb1aac1e4f3d0c0bdc372a47b085176 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 11:01:40 -0400 Subject: [PATCH 023/232] Fix scalar constants --- ggml/contrib/onnx.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 65b7167d..099d9b8e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -32,6 +32,15 @@ def inner(func): return inner +def map_to_ggml_type(NDArray: np.ndarray): + ggml_type = ggml.utils.NUMPY_DTYPE_TO_GGML_TYPE.get( + NDArray.dtype.type, + ggml.utils.GGML_TYPE.I32, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 + ) + + return ggml_type + + # ------ Operators ------ @@ -163,8 +172,10 @@ def ggml_operator_constant( np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) + data_tensor = ggml.utils.from_numpy( - np.frombuffer(tensor.raw_data, dtype=np_data_type).astype(np_data_type_limit), + data_value.astype(np_data_type_limit), context, ) @@ -174,7 +185,15 @@ def ggml_operator_constant( x_t = None if tensor_shape == (): - x_t = ggml.ggml_new_i32(context, -1) + ggml_type = map_to_ggml_type(data_value.astype(np_data_type_limit)) + + x_t = ggml.ggml_new_tensor( + context, + ggml_type.value, + len(tensor_shape), + (ctypes.c_int64 * len(tensor_shape))(*tensor_shape), + ) + else: x_t = ggml.utils.from_numpy(x, context) @@ -335,16 +354,17 @@ def ggml_operator_unsqueeze( f'Error for node "{node.name}": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' ) - x = ggml.utils.to_numpy(node_inputs[0]) + x_input = ggml.utils.to_numpy(node_inputs[0]) axes = ggml.utils.to_numpy(node_inputs[1]) - output_shape = x.shape + output_shape = x_input.shape for axis in np.nditer(axes): output_shape = np.insert(output_shape, axis, 1) - x = np.empty(output_shape, dtype=x.dtype) + output_shape = output_shape.astype(np.int32) + x = np.empty(output_shape, dtype=x_input.dtype) x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( @@ -517,10 +537,8 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ) # Create the input tensors with the correct type/shape - ggml_type = ggml.utils.NUMPY_DTYPE_TO_GGML_TYPE.get( - input_data.dtype.type, - ggml.utils.GGML_TYPE.I32, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 - ) + ggml_type = map_to_ggml_type(input_data) + shape = tuple(reversed(input_data.shape)) tensor = ggml.ggml_new_tensor( context, From b50583af5a4b62a2fd9bc875df284ca388b5e446 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 12:43:12 -0400 Subject: [PATCH 024/232] Add test_ggml_onnx_concat_operator --- tests/test_ggml_onnx_ops.py | 117 ++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 20b704e0..3fff6ca5 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -395,6 +395,123 @@ def onnx_constant(value, dtype, shape): ggml.ggml_free(context) +def test_ggml_onnx_concat_operator(): + def onnx_concat(inputs, axis): + # Determine the input data type + input_data_type = inputs[0].dtype + + # Create ONNX graph + graph = onnx.GraphProto() + + input_names = [] + for i, input_array in enumerate(inputs): + input_name = f"input{i}" + input_names.append(input_name) + + input_value_info = onnx.helper.make_tensor_value_info( + input_name, + onnx.TensorProto.FLOAT + if input_data_type == np.float32 + else onnx.TensorProto.INT32, + input_array.shape, + ) + graph.input.extend([input_value_info]) + + # Create Concat node + concat_node = onnx.NodeProto() + concat_node.op_type = "Concat" + concat_node.name = "concat_node" + concat_node.output.extend(["output"]) + concat_node.attribute.extend([onnx.helper.make_attribute("axis", axis)]) + concat_node.input.extend(input_names) # Use input names + + # Create output tensor value info + output_value_info = onnx.helper.make_tensor_value_info( + "output", + onnx.TensorProto.FLOAT + if input_data_type == np.float32 + else onnx.TensorProto.INT32, + None, + ) + graph.output.extend([output_value_info]) + + # Finalize the graph + graph.node.extend([concat_node]) + model = onnx.helper.make_model(graph) + + # Save the ONNX model to BytesIO object + onnx_model_bytes = BytesIO() + onnx.save_model(model, onnx_model_bytes) + + # Load the ONNX model from BytesIO + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + # Prepare the input feeds with the input arrays + input_feed = { + input_name: input_array + for input_name, input_array in zip(input_names, inputs) + } + + # Execute the ONNX model + output = sess.run(["output"], input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + + array1 = np.array([1], dtype=np.int32) + array2 = np.array([2, 3, 4, 5], dtype=np.int32) + array3 = np.array([6], dtype=np.int32) + array4 = np.array([7, 8, 9, 10], dtype=np.int32) + + tensors_dict["array1"] = ggml.utils.from_numpy(array1, context) + tensors_dict["array2"] = ggml.utils.from_numpy(array2, context) + tensors_dict["array3"] = ggml.utils.from_numpy(array3, context) + tensors_dict["array4"] = ggml.utils.from_numpy(array4, context) + + test1 = ["array1", "array2"] + inputs1 = [array1, array2] + test2 = ["array1", "array2", "array3", "array4"] + inputs2 = [array1, array2, array3, array4] + axis = 0 + + concat_node1 = onnx.helper.make_node( + "Concat", + inputs=test1, + name="concat_node1", + outputs=["concat_output1"], + axis=axis, + ) + concat_node2 = onnx.helper.make_node( + "Concat", + inputs=test2, + name="concat_node2", + outputs=["concat_output2"], + axis=axis, + ) + + concat_onnx_result1 = onnx_concat(inputs1, axis) + concat_onnx_result2 = onnx_concat(inputs2, axis) + + nodes = [concat_node1, concat_node2] + results = [] + refs = [] + + for concat_node in nodes: + output_tensor = ggml_operators["Concat"]( + concat_node, tensors_dict, context, refs + ) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + results.append(ggml.utils.to_numpy(output_tensor)) + + assert np.array_equal(results[0], concat_onnx_result1) + assert np.array_equal(results[1], concat_onnx_result2) + + def test_ggml_onnx_runtime_basic(): # return # The name of the input tensor From 4ac4d5ca2c1b2dbd0ce2abf402dd87ec9876b204 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 13:42:00 -0400 Subject: [PATCH 025/232] Add Concat operator --- ggml/contrib/onnx.py | 99 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 099d9b8e..6c82b03d 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4,7 +4,7 @@ import numpy as np import onnx -from onnx import defs +from onnx import defs, helper from onnx.backend.base import Backend, BackendRep from onnx.helper import make_opsetid from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto @@ -408,11 +408,106 @@ def ggml_operator_where( raise NotImplementedError(f'Operator "Where" not implemented') +@ggml.ggml_custom3_op_t +def custom_concat( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + + x = np.concatenate([a, b], axis=axis) + x = np.resize(x, ggml.utils.to_numpy(tensor_out).shape) + ggml.utils.to_numpy(tensor_out)[:] = x + + @ggml_operator("Concat") def ggml_operator_concat( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Concat" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Concat" requires at least two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + axis = node.attribute[0].i if len(node.attribute) > 0 else 0 + tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + + axis_c = ctypes.c_int(axis) + + shapes = [tensor.shape for tensor in tensors] + if not all( + shape[:axis] == shapes[0][:axis] and shape[axis + 1 :] == shapes[0][axis + 1 :] + for shape in shapes + ): + raise ValueError( + "All tensors must have the same shape along the specified axis." + ) + + total_dim = sum(shape[axis] for shape in shapes) + output_shape = list(shapes[0]) + output_shape[axis] = total_dim + + x = np.empty(output_shape, dtype=tensors[0].dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_concat, + 1, + ctypes.pointer(axis_c), + ) + + refs.append(axis_c) + + if len(node_inputs) == 2: + return new_tensor + else: + mid = len(node.input) // 2 + recursive_node_left = helper.make_node( + op_type=node.op_type, + inputs=node.input[:mid], + outputs=node.output, + name=node.name, + axis=axis, + ) + recursive_node_right = helper.make_node( + op_type=node.op_type, + inputs=node.input[mid:], + outputs=node.output, + name=node.name, + axis=axis, + ) + + new_tensors_dict = tensors_dict.copy() + + new_tensors_dict["left"] = ggml_operator_concat( + recursive_node_left, tensors_dict, context, refs + ) + new_tensors_dict["right"] = ggml_operator_concat( + recursive_node_right, tensors_dict, context, refs + ) + + recursive_node = helper.make_node( + op_type=node.op_type, + inputs=["left", "right"], + outputs=node.output, + name=node.name, + axis=axis, + ) + + return ggml_operator_concat(recursive_node, new_tensors_dict, context, refs) @ggml_operator("Div") From 073eeedd9d8f254d597d9155341403cbad8b2161 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 15:42:07 -0400 Subject: [PATCH 026/232] Add reshape test case, deactivate concat test case --- tests/test_ggml_onnx_ops.py | 84 +++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 3fff6ca5..89968127 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -18,6 +18,7 @@ def test_ggml_onnx_runtime_shape_operator(): # return + tensors_dict = {} params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) @@ -312,6 +313,8 @@ def onnx_gather(x, indices, axis): def test_ggml_onnx_constant_operator(): + # return + def onnx_constant(value, dtype, shape): tensor = numpy_helper.from_array(value) constant_node = onnx.helper.make_node( @@ -396,6 +399,8 @@ def onnx_constant(value, dtype, shape): def test_ggml_onnx_concat_operator(): + return + def onnx_concat(inputs, axis): # Determine the input data type input_data_type = inputs[0].dtype @@ -512,8 +517,87 @@ def onnx_concat(inputs, axis): assert np.array_equal(results[1], concat_onnx_result2) +def test_ggml_onnx_reshape_operation(): + return + + def onnx_reshape(input_tensor, shape): + class DynamicReshapeModel(torch.nn.Module): + def __init__(self, shape): + super(DynamicReshapeModel, self).__init__() + self.shape = tuple(shape) + + def forward(self, x): + reshaped = torch.reshape(x, self.shape) + return reshaped + + if not isinstance(input_tensor, np.ndarray): + raise ValueError("Input tensor must be a NumPy array") + + if not isinstance(shape, np.ndarray): + shape = np.array(shape) + + if len(shape) != len(input_tensor.shape): + raise ValueError( + "Input shape must have the same number of dimensions as the input tensor" + ) + + # Create a PyTorch model with dynamic reshape + model = DynamicReshapeModel(shape) + + # Perform dynamic reshape using PyTorch + input_tensor = torch.tensor(input_tensor, dtype=torch.int32) + + # Export the model to ONNX + f = BytesIO() + torch.onnx.export( + model, input_tensor, f, opset_version=12, do_constant_folding=True + ) + f.seek(0) + + # Run the ONNX model using ONNX Runtime + sess = ort.InferenceSession(f.getvalue()) + input_name = sess.get_inputs()[0].name + output_name = sess.get_outputs()[0].name + + result = sess.run([output_name], {input_name: input_tensor.numpy()}) + + return result[0] + + input_tensor = np.array([[1, 2, 3, 4, 5, 6]], dtype=np.int32) + new_shape = np.array([2, 3], dtype=np.int32) + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + + tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_tensor, context) + tensors_dict["new_shape"] = ggml.utils.from_numpy(new_shape, context) + + reshape_node1 = onnx.helper.make_node( + "Reshape", + inputs=["input_tensor", "new_shape"], + name="reshape_node1", + outputs=["reshape_output1"], + ) + + nodes = [reshape_node1] + results = [] + refs = [] + + for reshape_node in nodes: + output_tensor = ggml_operators["Reshape"]( + reshape_node, tensors_dict, context, refs + ) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + results.append(ggml.utils.to_numpy(output_tensor)) + + assert np.array_equal(results[0], onnx_reshape(input_tensor, new_shape)) + + def test_ggml_onnx_runtime_basic(): # return + # The name of the input tensor input_name = "X" From 4fd80d513d61b46ebd99ec2cff7b920c8065dc81 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 15:44:27 -0400 Subject: [PATCH 027/232] Remove Concat operator Concat operator requires more work so its skipped for now --- ggml/contrib/onnx.py | 97 +------------------------------------------- 1 file changed, 1 insertion(+), 96 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 6c82b03d..96163e78 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -408,106 +408,11 @@ def ggml_operator_where( raise NotImplementedError(f'Operator "Where" not implemented') -@ggml.ggml_custom3_op_t -def custom_concat( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) - axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value - - x = np.concatenate([a, b], axis=axis) - x = np.resize(x, ggml.utils.to_numpy(tensor_out).shape) - ggml.utils.to_numpy(tensor_out)[:] = x - - @ggml_operator("Concat") def ggml_operator_concat( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - node_inputs = [tensors_dict[inp] for inp in node.input] - - if len(node_inputs) < 2: - raise ValueError( - f'Error for node "{node.name}": Operation "Concat" requires at least two inputs. Actual number of inputs: {len(node_inputs)}' - ) - - axis = node.attribute[0].i if len(node.attribute) > 0 else 0 - tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] - - axis_c = ctypes.c_int(axis) - - shapes = [tensor.shape for tensor in tensors] - if not all( - shape[:axis] == shapes[0][:axis] and shape[axis + 1 :] == shapes[0][axis + 1 :] - for shape in shapes - ): - raise ValueError( - "All tensors must have the same shape along the specified axis." - ) - - total_dim = sum(shape[axis] for shape in shapes) - output_shape = list(shapes[0]) - output_shape[axis] = total_dim - - x = np.empty(output_shape, dtype=tensors[0].dtype) - x_t = ggml.utils.from_numpy(x, context) - - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - context, - x_t, - node_inputs[0], - node_inputs[1], - custom_concat, - 1, - ctypes.pointer(axis_c), - ) - - refs.append(axis_c) - - if len(node_inputs) == 2: - return new_tensor - else: - mid = len(node.input) // 2 - recursive_node_left = helper.make_node( - op_type=node.op_type, - inputs=node.input[:mid], - outputs=node.output, - name=node.name, - axis=axis, - ) - recursive_node_right = helper.make_node( - op_type=node.op_type, - inputs=node.input[mid:], - outputs=node.output, - name=node.name, - axis=axis, - ) - - new_tensors_dict = tensors_dict.copy() - - new_tensors_dict["left"] = ggml_operator_concat( - recursive_node_left, tensors_dict, context, refs - ) - new_tensors_dict["right"] = ggml_operator_concat( - recursive_node_right, tensors_dict, context, refs - ) - - recursive_node = helper.make_node( - op_type=node.op_type, - inputs=["left", "right"], - outputs=node.output, - name=node.name, - axis=axis, - ) - - return ggml_operator_concat(recursive_node, new_tensors_dict, context, refs) + raise NotImplementedError(f'Operator "Concat" not implemented') @ggml_operator("Div") From 68438770d28b1d6cbb274fe4c5d48cec1b31d593 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 15:57:10 -0400 Subject: [PATCH 028/232] Add Div and Sub operations to the basic test case --- tests/test_ggml_onnx_ops.py | 58 +++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 89968127..3eebefe8 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -596,28 +596,36 @@ def forward(self, x): def test_ggml_onnx_runtime_basic(): - # return - # The name of the input tensor input_name = "X" # The name of the weights tensor weight_name_a = "A" weight_name_b = "B" + weight_name_c = "C" + weight_name_d = "D" + + # The name of the intermediate tensors + intermediate_name1 = "intermediate1" + intermediate_name2 = "intermediate2" + intermediate_name3 = "intermediate3" # The name of the output output_name = "Y" # Create the nodes (operations) in our graph node1 = helper.make_node( - "Mul", [input_name, input_name], ["X_squared"], name="node1" - ) # X^2 + "Mul", [input_name, weight_name_a], [intermediate_name1], name="node1" + ) # X * A node2 = helper.make_node( - "Mul", ["X_squared", weight_name_a], ["X_squared_times_a"], name="node2" - ) # X^2 * A + "Div", [intermediate_name1, weight_name_b], [intermediate_name2], name="node2" + ) # (X * A) / B node3 = helper.make_node( - "Add", ["X_squared_times_a", weight_name_b], [output_name], name="node3" - ) # X^2 * A + B + "Add", [intermediate_name2, weight_name_c], [intermediate_name3], name="node3" + ) # (X * A / B) + C + node4 = helper.make_node( + "Sub", [intermediate_name3, weight_name_d], [output_name], name="node4" + ) # (X * A / B) + C - D # Define the tensors (values) in our graph X_value_info = helper.make_tensor_value_info( @@ -628,9 +636,11 @@ def test_ggml_onnx_runtime_basic(): output_name, TensorProto.FLOAT, [None, 1] ) - # Set A and B as parameters/weights - weights_a = np.ones(1, dtype=float).astype(np.float32) - weights_b = np.ones(1, dtype=float).astype(np.float32) + # Set weights A, B, C, and D + weights_a = np.array([5.6], dtype=float).astype(np.float32) + weights_b = np.array([3.0013], dtype=float).astype(np.float32) + weights_c = np.array([8.1], dtype=float).astype(np.float32) + weights_d = np.array([13.22], dtype=float).astype(np.float32) A_init = helper.make_tensor( weight_name_a, @@ -648,17 +658,33 @@ def test_ggml_onnx_runtime_basic(): ], weights_b, ) + C_init = helper.make_tensor( + weight_name_c, + TensorProto.FLOAT, + [ + 1, + ], + weights_c, + ) + D_init = helper.make_tensor( + weight_name_d, + TensorProto.FLOAT, + [ + 1, + ], + weights_d, + ) # Create the graph (model). graph_def = helper.make_graph( - [node1, node2, node3], - "simple_expression_model", + [node1, node2, node3, node4], + "complex_expression_model", [X_value_info], [output_value_info], - [A_init, B_init], + [A_init, B_init, C_init, D_init], ) - model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") + model_def = helper.make_model(graph_def, producer_name="onnx-complex-expression") input_data = {"X": np.array([[6.0]], dtype=np.float32)} @@ -670,4 +696,4 @@ def test_ggml_onnx_runtime_basic(): ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) ggml_result = ggml_dummy_model.run(input_data) - assert ggml_result == runtime_result + assert np.allclose(ggml_result, runtime_result) From 0ddcd71e9c9915285b4a21b27ceda2ebaeae8d2e Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 15:57:22 -0400 Subject: [PATCH 029/232] Add Div and Sub operations --- ggml/contrib/onnx.py | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 96163e78..b08d9d08 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -419,7 +419,21 @@ def ggml_operator_concat( def ggml_operator_div( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Div" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Add" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + + div_result = ggml.ggml_div( + context, + *node_inputs, + ) + tensors_dict[output_name] = div_result + return div_result @ggml_operator("Range") @@ -433,7 +447,21 @@ def ggml_operator_range( def ggml_operator_sub( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Sub" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Add" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + + sub_result = ggml.ggml_sub( + context, + *node_inputs, + ) + tensors_dict[output_name] = sub_result + return sub_result @ggml_operator("Pow") From e9e2f74ecdf52f51453a4bee4170deb899c1664d Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 16:45:19 -0400 Subject: [PATCH 030/232] Add Abs and Sqrt operators --- ggml/contrib/onnx.py | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index b08d9d08..a51280b2 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -321,7 +321,21 @@ def ggml_operator_mat_mul( def ggml_operator_abs( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Abs" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Abs" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + + abs_result = ggml.ggml_abs( + context, + *node_inputs, + ) + tensors_dict[output_name] = abs_result + return abs_result @ggml.ggml_custom3_op_t @@ -384,7 +398,21 @@ def ggml_operator_unsqueeze( def ggml_operator_sqrt( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Sqrt" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Sqrt" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + + sqrt_result = ggml.ggml_sqrt( + context, + *node_inputs, + ) + tensors_dict[output_name] = sqrt_result + return sqrt_result @ggml_operator("ReduceMean") @@ -423,7 +451,7 @@ def ggml_operator_div( if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Add" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Div" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) output_name = node.output[0] @@ -451,7 +479,7 @@ def ggml_operator_sub( if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Add" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Sub" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) output_name = node.output[0] From a75bc26aafb503095d3041689679baf01647c5ca Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 16:45:22 -0400 Subject: [PATCH 031/232] Update test_ggml_onnx_ops.py --- tests/test_ggml_onnx_ops.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 3eebefe8..3cc1440a 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -596,6 +596,8 @@ def forward(self, x): def test_ggml_onnx_runtime_basic(): + # return + # The name of the input tensor input_name = "X" @@ -609,6 +611,9 @@ def test_ggml_onnx_runtime_basic(): intermediate_name1 = "intermediate1" intermediate_name2 = "intermediate2" intermediate_name3 = "intermediate3" + intermediate_name4 = "intermediate4" + intermediate_name5 = "intermediate5" + intermediate_name6 = "intermediate6" # The name of the output output_name = "Y" @@ -624,8 +629,14 @@ def test_ggml_onnx_runtime_basic(): "Add", [intermediate_name2, weight_name_c], [intermediate_name3], name="node3" ) # (X * A / B) + C node4 = helper.make_node( - "Sub", [intermediate_name3, weight_name_d], [output_name], name="node4" + "Sub", [intermediate_name3, weight_name_d], [intermediate_name4], name="node4" ) # (X * A / B) + C - D + node5 = helper.make_node( + "Sqrt", [intermediate_name4], [intermediate_name5], name="node5" + ) # Sqrt((X * A / B) + C - D) + node6 = helper.make_node( + "Abs", [intermediate_name5], [output_name], name="node6" + ) # Abs(Sqrt((X * A / B) + C - D)) # Define the tensors (values) in our graph X_value_info = helper.make_tensor_value_info( @@ -637,7 +648,7 @@ def test_ggml_onnx_runtime_basic(): ) # Set weights A, B, C, and D - weights_a = np.array([5.6], dtype=float).astype(np.float32) + weights_a = np.array([20.6], dtype=float).astype(np.float32) weights_b = np.array([3.0013], dtype=float).astype(np.float32) weights_c = np.array([8.1], dtype=float).astype(np.float32) weights_d = np.array([13.22], dtype=float).astype(np.float32) @@ -677,7 +688,7 @@ def test_ggml_onnx_runtime_basic(): # Create the graph (model). graph_def = helper.make_graph( - [node1, node2, node3, node4], + [node1, node2, node3, node4, node5, node6], "complex_expression_model", [X_value_info], [output_value_info], From 81ba86d6d2b1fdc89ee7c98157ca5eee761981bd Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 16:52:39 -0400 Subject: [PATCH 032/232] Add Log operators and update tests --- ggml/contrib/onnx.py | 16 +++++++++++++++- tests/test_ggml_onnx_ops.py | 17 +++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index a51280b2..e9afe462 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -524,7 +524,21 @@ def ggml_operator_transpose( def ggml_operator_log( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Log" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Log" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + + log_result = ggml.ggml_log( + context, + *node_inputs, + ) + tensors_dict[output_name] = log_result + return log_result @ggml_operator("Greater") diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 3cc1440a..3c7cd868 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -614,6 +614,7 @@ def test_ggml_onnx_runtime_basic(): intermediate_name4 = "intermediate4" intermediate_name5 = "intermediate5" intermediate_name6 = "intermediate6" + intermediate_name7 = "intermediate7" # The name of the output output_name = "Y" @@ -635,8 +636,11 @@ def test_ggml_onnx_runtime_basic(): "Sqrt", [intermediate_name4], [intermediate_name5], name="node5" ) # Sqrt((X * A / B) + C - D) node6 = helper.make_node( - "Abs", [intermediate_name5], [output_name], name="node6" - ) # Abs(Sqrt((X * A / B) + C - D)) + "Log", [intermediate_name5], [intermediate_name6], name="node6" + ) # Log(Sqrt((X * A / B) + C - D)) + node7 = helper.make_node( + "Abs", [intermediate_name6], [output_name], name="node7" + ) # Abs(Log(Sqrt((X * A / B) + C - D))) # Define the tensors (values) in our graph X_value_info = helper.make_tensor_value_info( @@ -648,8 +652,8 @@ def test_ggml_onnx_runtime_basic(): ) # Set weights A, B, C, and D - weights_a = np.array([20.6], dtype=float).astype(np.float32) - weights_b = np.array([3.0013], dtype=float).astype(np.float32) + weights_a = np.array([50.6], dtype=float).astype(np.float32) + weights_b = np.array([0.0013], dtype=float).astype(np.float32) weights_c = np.array([8.1], dtype=float).astype(np.float32) weights_d = np.array([13.22], dtype=float).astype(np.float32) @@ -688,8 +692,8 @@ def test_ggml_onnx_runtime_basic(): # Create the graph (model). graph_def = helper.make_graph( - [node1, node2, node3, node4, node5, node6], - "complex_expression_model", + [node1, node2, node3, node4, node5, node6, node7], + "complex_expression_model_with_log", [X_value_info], [output_value_info], [A_init, B_init, C_init, D_init], @@ -706,5 +710,6 @@ def test_ggml_onnx_runtime_basic(): ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) ggml_result = ggml_dummy_model.run(input_data) + print(ggml_result, runtime_result) assert np.allclose(ggml_result, runtime_result) From 14ab70bbe62b7a0fa481f24f9c8ba239668183c5 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 9 Aug 2023 16:55:53 -0400 Subject: [PATCH 033/232] Remove unwanted print --- tests/test_ggml_onnx_ops.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 3c7cd868..fb58b9c1 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -710,6 +710,5 @@ def test_ggml_onnx_runtime_basic(): ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) ggml_result = ggml_dummy_model.run(input_data) - print(ggml_result, runtime_result) assert np.allclose(ggml_result, runtime_result) From f572c643674c698453f80757ae6a0057c150c3cc Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 10 Aug 2023 09:24:06 -0400 Subject: [PATCH 034/232] Add softmax test and remove unwanted comments --- tests/test_ggml_onnx_ops.py | 64 ++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index fb58b9c1..0a2dfd16 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -95,7 +95,6 @@ def test_ggml_onnx_runtime_unsqueeze_operator(): # return def onnx_unsqueeze(x, axes): - # Create a simple PyTorch model class UnsqueezeModel(torch.nn.Module): def forward(self, input): for axis in axes: @@ -104,10 +103,8 @@ def forward(self, input): model = UnsqueezeModel() - # Create a sample input tensor x_tensor = torch.tensor(x, dtype=torch.int32) - # Export the PyTorch model to ONNX f = BytesIO() torch.onnx.export( model, @@ -118,18 +115,14 @@ def forward(self, input): verbose=False, ) - # Save the ONNX model to BytesIO object onnx_model_bytes = BytesIO(f.getvalue()) - # Load the ONNX model from BytesIO onnx_model_bytes.seek(0) sess = ort.InferenceSession(onnx_model_bytes.read()) - # Convert the input array to ONNX format (numpy to list) x_list = x.tolist() input_feed = {"data": x_list} - # Execute the ONNX model output = sess.run(None, input_feed) return output[0] @@ -207,11 +200,9 @@ def test_ggml_onnx_runtime_gather_operator(): # return def onnx_gather(x, indices, axis): - # Adjust the axis value to handle negative axis if axis < 0: axis += len(x.shape) - # Create ONNX model for Gather operation with specified axis node_def = onnx.helper.make_node( "Gather", inputs=["data", "indices"], outputs=["output"], axis=axis ) @@ -236,22 +227,17 @@ def onnx_gather(x, indices, axis): graph_def, producer_name="onnx_gather_example" ) - # Save the ONNX model to BytesIO object onnx_model_bytes = BytesIO() onnx.save_model(model_def, onnx_model_bytes) - # Load the ONNX model from BytesIO onnx_model_bytes.seek(0) sess = ort.InferenceSession(onnx_model_bytes.read()) - # Convert the input arrays to ONNX format (numpy to list) x_list = x.tolist() indices_list = indices.tolist() - # Prepare the input feeds with the two arrays input_feed = {"data": x_list, "indices": indices_list} - # Execute the ONNX model output = sess.run(None, input_feed) return output[0] @@ -598,28 +584,22 @@ def forward(self, x): def test_ggml_onnx_runtime_basic(): # return - # The name of the input tensor input_name = "X" - # The name of the weights tensor weight_name_a = "A" weight_name_b = "B" weight_name_c = "C" weight_name_d = "D" - # The name of the intermediate tensors intermediate_name1 = "intermediate1" intermediate_name2 = "intermediate2" intermediate_name3 = "intermediate3" intermediate_name4 = "intermediate4" intermediate_name5 = "intermediate5" intermediate_name6 = "intermediate6" - intermediate_name7 = "intermediate7" - # The name of the output output_name = "Y" - # Create the nodes (operations) in our graph node1 = helper.make_node( "Mul", [input_name, weight_name_a], [intermediate_name1], name="node1" ) # X * A @@ -642,7 +622,6 @@ def test_ggml_onnx_runtime_basic(): "Abs", [intermediate_name6], [output_name], name="node7" ) # Abs(Log(Sqrt((X * A / B) + C - D))) - # Define the tensors (values) in our graph X_value_info = helper.make_tensor_value_info( input_name, TensorProto.FLOAT, [None, 1] ) @@ -651,7 +630,6 @@ def test_ggml_onnx_runtime_basic(): output_name, TensorProto.FLOAT, [None, 1] ) - # Set weights A, B, C, and D weights_a = np.array([50.6], dtype=float).astype(np.float32) weights_b = np.array([0.0013], dtype=float).astype(np.float32) weights_c = np.array([8.1], dtype=float).astype(np.float32) @@ -690,7 +668,6 @@ def test_ggml_onnx_runtime_basic(): weights_d, ) - # Create the graph (model). graph_def = helper.make_graph( [node1, node2, node3, node4, node5, node6, node7], "complex_expression_model_with_log", @@ -712,3 +689,44 @@ def test_ggml_onnx_runtime_basic(): ggml_result = ggml_dummy_model.run(input_data) assert np.allclose(ggml_result, runtime_result) + + +def test_ggml_onnx_softmax_operator(): + # return + + input_name = "X" + + output_name = "Softmax_Output" + + input_data = { + input_name: np.array([[-1.5, 0.001, 3.73, 5.1, 6, 6.0001]], dtype=np.float32) + } + + node1 = helper.make_node( + "Softmax", [input_name], [output_name], name="softmax_node" + ) + + X_value_info = helper.make_tensor_value_info( + input_name, TensorProto.FLOAT, [None, 6] + ) + + softmax_value_info = helper.make_tensor_value_info( + output_name, TensorProto.FLOAT, [None, 6] + ) + + graph_def = helper.make_graph( + [node1], "softmax_model", [X_value_info], [softmax_value_info] + ) + + model_def = helper.make_model(graph_def, producer_name="onnx-softmax") + + f = io.BytesIO() + onnx.save(model_def, f) + + runtime_result = InferenceSession(f.getvalue()).run(None, input_data) + + ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) + + ggml_result = ggml_dummy_model.run(input_data) + + assert np.allclose(ggml_result, runtime_result, rtol=0.001) From ea479cd5a11a69b2a43f7642d7c4147554370845 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 10 Aug 2023 09:24:26 -0400 Subject: [PATCH 035/232] Add Softmax operator and fix inputs --- ggml/contrib/onnx.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index e9afe462..bd90fff9 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -242,7 +242,20 @@ def ggml_operator_constant_of_shape( def ggml_operator_softmax( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Softmax" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Softmax" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + soft_max_result = ggml.ggml_soft_max( + context, + *node_inputs, + ) + tensors_dict[output_name] = soft_max_result + return soft_max_result @ggml.ggml_custom3_op_t @@ -636,7 +649,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Set user inputs for key, value in inputs.items(): - ggml.ggml_set_f32(ggml_tensors[key], value) + ggml.utils.to_numpy(ggml_tensors[key])[:] = value # Compute graph ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) From 47542f17bc5bf61a815f40ac3b2e9388104f4a06 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 10 Aug 2023 12:34:59 -0400 Subject: [PATCH 036/232] Add RedueMean operator and tests --- ggml/contrib/onnx.py | 88 ++++++++++++++++++- tests/test_ggml_onnx_ops.py | 170 +++++++++++++++++++++++++++--------- 2 files changed, 213 insertions(+), 45 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index bd90fff9..9ab23d4c 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -65,7 +65,7 @@ def ggml_operator_add( return add_result -class ShapeUserInput(ctypes.Structure): +class ShapeUserData(ctypes.Structure): _fields_ = [("start", ctypes.c_int), ("end", ctypes.c_int)] @@ -78,7 +78,7 @@ def custom_shape( nth: int, userdata: Optional[ctypes.c_void_p], ): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ShapeUserInput)) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ShapeUserData)) userdata_data = userdata_data_ptr.contents tensor = ggml.utils.to_numpy(tensor_in_2) @@ -117,7 +117,7 @@ def ggml_operator_shape( start = start[0] if len(start) else ctypes.c_int(0) end = end[0] if len(end) else ctypes.c_int(tensor.shape[-1]) - shape_userdata = ShapeUserInput(start, end) + shape_userdata = ShapeUserData(start, end) userdata_p = ctypes.cast(ctypes.pointer(shape_userdata), ctypes.c_void_p) output_shape = len(list(tensor.shape)) @@ -428,11 +428,91 @@ def ggml_operator_sqrt( return sqrt_result +class RedueMeanUserData(ctypes.Structure): + _fields_ = [ + ("axes", ctypes.POINTER(ctypes.c_int)), + ("axes_length", ctypes.c_int), + ("keepdims", ctypes.c_int), + ] + + def __init__(self, axes, keepdims): + if isinstance(axes, list): + self.axes_length = len(axes) + self.axes = (ctypes.c_int * self.axes_length)(*axes) + else: + raise ValueError("axes should be a list of integers") + + self.keepdims = keepdims + + +@ggml.ggml_custom2_op_t +def custom_reducemean( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(RedueMeanUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + tensor_out_shape = ggml.utils.to_numpy(tensor_out).shape + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + rmean_result = np.mean(tensor, tuple(axes), keepdims=keepdims) + + if tensor_out_shape == (): + ggml.utils.to_numpy(tensor_out)[()] = rmean_result + else: + ggml.utils.to_numpy(tensor_out)[:] = rmean_result + + @ggml_operator("ReduceMean") def ggml_operator_reduce_mean( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "ReduceMean" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceMean" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + tensor = ggml.utils.to_numpy(node_inputs[0]) + axes = next(attr for attr in node.attribute if attr.name == "axes").ints + keepdims = next(attr for attr in node.attribute if attr.name == "keepdims").i + + rmean_userdata = RedueMeanUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) + + output_shape = list(tensor.shape) + for axis in axes: + output_shape[axis] = 1 + for axis in axes: + if not keepdims: + output_shape.pop(0) + + output_shape = tuple(output_shape) + + x = np.empty(output_shape, dtype=tensor.dtype) + + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + node_inputs[0], + custom_reducemean, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor @ggml_operator("Less") diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 0a2dfd16..0bbce714 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -581,6 +581,135 @@ def forward(self, x): assert np.array_equal(results[0], onnx_reshape(input_tensor, new_shape)) +def test_ggml_onnx_softmax_operator(): + # return + + input_name = "X" + + output_name = "Softmax_Output" + + input_data = { + input_name: np.array([[-1.5, 0.001, 3.73, 5.1, 6, 6.0001]], dtype=np.float32) + } + + node1 = helper.make_node( + "Softmax", [input_name], [output_name], name="softmax_node" + ) + + X_value_info = helper.make_tensor_value_info( + input_name, TensorProto.FLOAT, [None, 6] + ) + + softmax_value_info = helper.make_tensor_value_info( + output_name, TensorProto.FLOAT, [None, 6] + ) + + graph_def = helper.make_graph( + [node1], "softmax_model", [X_value_info], [softmax_value_info] + ) + + model_def = helper.make_model(graph_def, producer_name="onnx-softmax") + + f = io.BytesIO() + onnx.save(model_def, f) + + runtime_result = InferenceSession(f.getvalue()).run(None, input_data) + + ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) + + ggml_result = ggml_dummy_model.run(input_data) + + assert np.allclose(ggml_result, runtime_result, rtol=0.001) + + +def test_ggml_onnx_reducemean_operator(): + # return + + def onnx_reducemean(x, axes): + class ReduceMeanModel(torch.nn.Module): + def forward(self, input): + return torch.mean(input, dim=axes.tolist(), keepdim=False) + + model = ReduceMeanModel() + + x_tensor = torch.tensor(x, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + x_tensor, + f, + input_names=["data"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + x_list = x.tolist() + input_feed = {"data": x_list} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + # Define input arrays and axes + input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) + axes1 = np.array([0, 1], dtype=np.int32) + + input_array2 = np.array([[1, 2, 3, 4]], dtype=np.float32) + axes2 = np.array([1], dtype=np.int32) + + # Compute ONNX ReduceMean using GGML + reducemean_numpy1 = onnx_reducemean(input_array1, axes1) + reducemean_numpy2 = onnx_reducemean(input_array2, axes2) + + tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) + tensors_dict["axes1"] = ggml.utils.from_numpy(axes1, context) + tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) + tensors_dict["axes2"] = ggml.utils.from_numpy(axes2, context) + + reducemean_node1 = onnx.helper.make_node( + "ReduceMean", + inputs=["input_array1"], + outputs=["reducemean_output1"], + axes=axes1, + keepdims=0, + ) + + reducemean_node2 = onnx.helper.make_node( + "ReduceMean", + inputs=["input_array2"], + outputs=["reducemean_output2"], + axes=axes2, + keepdims=0, + ) + + nodes = [reducemean_node1, reducemean_node2] + results = [] + + for reducemean_node in nodes: + output_tensor = ggml_operators["ReduceMean"]( + reducemean_node, tensors_dict, context, refs + ) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + results.append(ggml.utils.to_numpy(output_tensor)) + + assert np.allclose(results[0], reducemean_numpy1) + assert np.allclose(results[1], reducemean_numpy2) + + ggml.ggml_free(context) + + def test_ggml_onnx_runtime_basic(): # return @@ -689,44 +818,3 @@ def test_ggml_onnx_runtime_basic(): ggml_result = ggml_dummy_model.run(input_data) assert np.allclose(ggml_result, runtime_result) - - -def test_ggml_onnx_softmax_operator(): - # return - - input_name = "X" - - output_name = "Softmax_Output" - - input_data = { - input_name: np.array([[-1.5, 0.001, 3.73, 5.1, 6, 6.0001]], dtype=np.float32) - } - - node1 = helper.make_node( - "Softmax", [input_name], [output_name], name="softmax_node" - ) - - X_value_info = helper.make_tensor_value_info( - input_name, TensorProto.FLOAT, [None, 6] - ) - - softmax_value_info = helper.make_tensor_value_info( - output_name, TensorProto.FLOAT, [None, 6] - ) - - graph_def = helper.make_graph( - [node1], "softmax_model", [X_value_info], [softmax_value_info] - ) - - model_def = helper.make_model(graph_def, producer_name="onnx-softmax") - - f = io.BytesIO() - onnx.save(model_def, f) - - runtime_result = InferenceSession(f.getvalue()).run(None, input_data) - - ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) - - ggml_result = ggml_dummy_model.run(input_data) - - assert np.allclose(ggml_result, runtime_result, rtol=0.001) From 95ecb107c9438bd88671fce7be6e6eeaa894c616 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 10 Aug 2023 13:17:44 -0400 Subject: [PATCH 037/232] Add Greater, Less, Max and Min operators and tests --- ggml/contrib/onnx.py | 225 ++++++++++++++++++++++++++---- tests/test_ggml_onnx_ops.py | 266 ++++++++++++++++++++++++++++++++++++ 2 files changed, 468 insertions(+), 23 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 9ab23d4c..aa41fdbe 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -32,15 +32,24 @@ def inner(func): return inner -def map_to_ggml_type(NDArray: np.ndarray): +def map_to_ggml_type(dtype: np.dtype): ggml_type = ggml.utils.NUMPY_DTYPE_TO_GGML_TYPE.get( - NDArray.dtype.type, + dtype.type, ggml.utils.GGML_TYPE.I32, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 ) return ggml_type +def set_tensor_out(tensor, ndarray): + output_shape = ggml.utils.to_numpy(tensor).shape + + if output_shape == (): + ggml.utils.to_numpy(tensor)[()] = ndarray + else: + ggml.utils.to_numpy(tensor)[:] = ndarray + + # ------ Operators ------ @@ -153,10 +162,7 @@ def custom_constant( constant_data = ggml.utils.to_numpy(tensor_in_2) new_tenor = constant_data.reshape(shape) - if shape == (): - ggml.utils.to_numpy(tensor_out)[()] = new_tenor - else: - ggml.utils.to_numpy(tensor_out)[:] = new_tenor + set_tensor_out(tensor_out, new_tenor) @ggml_operator("Constant") @@ -185,7 +191,7 @@ def ggml_operator_constant( x_t = None if tensor_shape == (): - ggml_type = map_to_ggml_type(data_value.astype(np_data_type_limit)) + ggml_type = map_to_ggml_type(np_data_type_limit) x_t = ggml.ggml_new_tensor( context, @@ -458,16 +464,12 @@ def custom_reducemean( userdata_data = userdata_data_ptr.contents tensor = ggml.utils.to_numpy(tensor_in_2) - tensor_out_shape = ggml.utils.to_numpy(tensor_out).shape axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims rmean_result = np.mean(tensor, tuple(axes), keepdims=keepdims) - if tensor_out_shape == (): - ggml.utils.to_numpy(tensor_out)[()] = rmean_result - else: - ggml.utils.to_numpy(tensor_out)[:] = rmean_result + set_tensor_out(tensor_out, rmean_result) @ggml_operator("ReduceMean") @@ -515,13 +517,6 @@ def ggml_operator_reduce_mean( return new_tensor -@ggml_operator("Less") -def ggml_operator_less( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] -): - raise NotImplementedError(f'Operator "Less" not implemented') - - @ggml_operator("Where") def ggml_operator_where( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] @@ -634,18 +629,202 @@ def ggml_operator_log( return log_result +@ggml.ggml_custom3_op_t +def custom_greater( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.greater(a, b) + + set_tensor_out(tensor_out, x) + + @ggml_operator("Greater") def ggml_operator_greater( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Greater" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Greater" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a = ggml.utils.to_numpy(node_inputs[0]) + b = ggml.utils.to_numpy(node_inputs[1]) + + output_shape = min(a.shape, b.shape) + + x = np.empty(output_shape, dtype=a.dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_greater, + 1, + None, + ) + + return new_tensor + + +@ggml.ggml_custom3_op_t +def custom_less( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.less(a, b) + + set_tensor_out(tensor_out, x) + + +@ggml_operator("Less") +def ggml_operator_greater( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a = ggml.utils.to_numpy(node_inputs[0]) + b = ggml.utils.to_numpy(node_inputs[1]) + + output_shape = min(a.shape, b.shape) + + x = np.empty(output_shape, dtype=a.dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_less, + 1, + None, + ) + + return new_tensor + + +@ggml.ggml_custom2_op_t +def custom_min( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + x = np.min(a) + set_tensor_out(tensor_out, np.array(x)) @ggml_operator("Min") -def ggml_operator_min( +def ggml_operator_greater( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Min" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a = ggml.utils.to_numpy(node_inputs[0]) + + output_shape = () + ggml_type = map_to_ggml_type(a.dtype) + + x_t = ggml.ggml_new_tensor( + context, + ggml_type.value, + len(output_shape), + (ctypes.c_int64 * len(output_shape))(*output_shape), + ) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + node_inputs[0], + custom_min, + 1, + None, + ) + + return new_tensor + + +@ggml.ggml_custom2_op_t +def custom_max( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + x = np.max(a) + set_tensor_out(tensor_out, np.array(x)) + + +@ggml_operator("Max") +def ggml_operator_greater( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Min" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Max" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a = ggml.utils.to_numpy(node_inputs[0]) + + output_shape = () + ggml_type = map_to_ggml_type(a.dtype) + + x_t = ggml.ggml_new_tensor( + context, + ggml_type.value, + len(output_shape), + (ctypes.c_int64 * len(output_shape))(*output_shape), + ) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + node_inputs[0], + custom_max, + 1, + None, + ) + + return new_tensor class GgmlBackendRep(BackendRep): @@ -700,7 +879,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ) # Create the input tensors with the correct type/shape - ggml_type = map_to_ggml_type(input_data) + ggml_type = map_to_ggml_type(input_data.dtype) shape = tuple(reversed(input_data.shape)) tensor = ggml.ggml_new_tensor( diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 0bbce714..0883ff7e 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -710,6 +710,272 @@ def forward(self, input): ggml.ggml_free(context) +def test_ggml_onnx_less_operator(): + # return + + def onnx_less(x, y): + class LessModel(torch.nn.Module): + def forward(self, input1, input2): + return torch.less(input1, input2) + + model = LessModel() + + x_tensor = torch.tensor(x, dtype=torch.float32) + y_tensor = torch.tensor(y, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + (x_tensor, y_tensor), + f, + input_names=["input1", "input2"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + x_list = x.tolist() + y_list = y.tolist() + input_feed = {"input1": x_list, "input2": y_list} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + # Define input arrays + input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) + input_array2 = np.array([[2, 2, 2], [5, 5, 5], [8, 8, 8]], dtype=np.float32) + + # Compute ONNX Less using GGML + less_numpy = onnx_less(input_array1, input_array2) + + tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) + tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) + + less_node = onnx.helper.make_node( + "Less", + inputs=["input_array1", "input_array2"], + outputs=["less_output"], + ) + + nodes = [less_node] + results = [] + + for less_node in nodes: + output_tensor = ggml_operators["Less"](less_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + results.append(ggml.utils.to_numpy(output_tensor)) + + assert np.allclose(results[0], less_numpy) + + ggml.ggml_free(context) + + +def test_ggml_onnx_greater_operator(): + # return + + def onnx_greater(x, y): + class GreaterModel(torch.nn.Module): + def forward(self, input1, input2): + return torch.gt(input1, input2) + + model = GreaterModel() + + x_tensor = torch.tensor(x, dtype=torch.float32) + y_tensor = torch.tensor(y, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + (x_tensor, y_tensor), + f, + input_names=["input1", "input2"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + x_list = x.tolist() + y_list = y.tolist() + input_feed = {"input1": x_list, "input2": y_list} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + # Define input arrays + input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) + input_array2 = np.array([[2, 2, 2], [5, 5, 5], [8, 8, 8]], dtype=np.float32) + + # Compute ONNX Greater using GGML + greater_numpy = onnx_greater(input_array1, input_array2) + + tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) + tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) + + greater_node = onnx.helper.make_node( + "Greater", + inputs=["input_array1", "input_array2"], + outputs=["greater_output"], + ) + + output_tensor = ggml_operators["Greater"](greater_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + result = ggml.utils.to_numpy(output_tensor) + + assert np.allclose(result, greater_numpy) + + ggml.ggml_free(context) + + +def test_ggml_onnx_min_operator(): + # return + + def onnx_min(x): + class MinModel(torch.nn.Module): + def forward(self, input1): + return torch.min(input1) + + model = MinModel() + + x_tensor = torch.tensor(x, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + (x_tensor), + f, + input_names=["input1"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + x_list = x.tolist() + input_feed = {"input1": x_list} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + # Define input arrays + input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) + + # Compute ONNX Min using GGML + min_numpy = onnx_min(input_array1) + + tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) + # tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) + + min_node = onnx.helper.make_node( + "Min", + inputs=["input_array1"], + outputs=["min_output"], + ) + + output_tensor = ggml_operators["Min"](min_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + result = ggml.utils.to_numpy(output_tensor) + + assert np.allclose(result, min_numpy) + + ggml.ggml_free(context) + + +def test_ggml_onnx_max_operator(): + # return + + def onnx_max(x): + class MaxModel(torch.nn.Module): + def forward(self, input1): + return torch.max(input1) + + model = MaxModel() + + x_tensor = torch.tensor(x, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + (x_tensor), + f, + input_names=["input1"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + x_list = x.tolist() + input_feed = {"input1": x_list} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + # Define input arrays + input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) + + # Compute ONNX Min using GGML + min_numpy = onnx_max(input_array1) + + tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) + # tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) + + min_node = onnx.helper.make_node( + "Min", + inputs=["input_array1"], + outputs=["min_output"], + ) + + output_tensor = ggml_operators["Max"](min_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + result = ggml.utils.to_numpy(output_tensor) + + assert np.allclose(result, min_numpy) + + ggml.ggml_free(context) + + def test_ggml_onnx_runtime_basic(): # return From 569462d6babffdbace5bb68eb72f1324c7809f0e Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 10 Aug 2023 13:35:52 -0400 Subject: [PATCH 038/232] Fix Less and Greater output_shape --- ggml/contrib/onnx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index aa41fdbe..97499162 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -661,7 +661,7 @@ def ggml_operator_greater( a = ggml.utils.to_numpy(node_inputs[0]) b = ggml.utils.to_numpy(node_inputs[1]) - output_shape = min(a.shape, b.shape) + output_shape = np.broadcast(np.empty(a.shape), np.empty(b.shape)).shape x = np.empty(output_shape, dtype=a.dtype) x_t = ggml.utils.from_numpy(x, context) @@ -711,7 +711,7 @@ def ggml_operator_greater( a = ggml.utils.to_numpy(node_inputs[0]) b = ggml.utils.to_numpy(node_inputs[1]) - output_shape = min(a.shape, b.shape) + output_shape = np.broadcast(np.empty(a.shape), np.empty(b.shape)).shape x = np.empty(output_shape, dtype=a.dtype) x_t = ggml.utils.from_numpy(x, context) From 0e8cfa460a088c19bae2109123903a49403e71f5 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 10 Aug 2023 16:03:13 -0400 Subject: [PATCH 039/232] Add Relu operator --- ggml/contrib/onnx.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 97499162..efe4a5bc 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -326,7 +326,21 @@ def ggml_operator_gather( def ggml_operator_relu( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Relu" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Relu" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + + relu_result = ggml.ggml_relu( + context, + *node_inputs, + ) + tensors_dict[output_name] = relu_result + return relu_result @ggml_operator("MatMul") From bbf5cf26e07852aeafa21f37b6001f55b29d2493 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 10 Aug 2023 16:31:33 -0400 Subject: [PATCH 040/232] Add Transpose --- ggml/contrib/onnx.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index efe4a5bc..dacc69d5 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -619,7 +619,22 @@ def ggml_operator_reshape( def ggml_operator_transpose( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Transpose" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Transpose" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + perm = next(attr for attr in node.attribute if attr.name == "perm").ints + # Add missing axes -> normally is 1, 0, 2, 3 + perm.extend([i for i in range(4) if i not in perm]) + perm = perm[:4] + + transpose_result = ggml.ggml_permute(context, node_inputs[0], *perm) + tensors_dict[output_name] = transpose_result + return transpose_result @ggml_operator("Log") From 27f8bdf0f5324a686b0ba9a7144b7461242fef1b Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 10 Aug 2023 16:32:43 -0400 Subject: [PATCH 041/232] Add new tests --- tests/test_ggml_onnx_ops.py | 295 ++++++++++++++++++++++++++++++++---- 1 file changed, 268 insertions(+), 27 deletions(-) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 0883ff7e..12a49012 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -388,10 +388,8 @@ def test_ggml_onnx_concat_operator(): return def onnx_concat(inputs, axis): - # Determine the input data type input_data_type = inputs[0].dtype - # Create ONNX graph graph = onnx.GraphProto() input_names = [] @@ -408,15 +406,13 @@ def onnx_concat(inputs, axis): ) graph.input.extend([input_value_info]) - # Create Concat node concat_node = onnx.NodeProto() concat_node.op_type = "Concat" concat_node.name = "concat_node" concat_node.output.extend(["output"]) concat_node.attribute.extend([onnx.helper.make_attribute("axis", axis)]) - concat_node.input.extend(input_names) # Use input names + concat_node.input.extend(input_names) - # Create output tensor value info output_value_info = onnx.helper.make_tensor_value_info( "output", onnx.TensorProto.FLOAT @@ -426,11 +422,9 @@ def onnx_concat(inputs, axis): ) graph.output.extend([output_value_info]) - # Finalize the graph graph.node.extend([concat_node]) model = onnx.helper.make_model(graph) - # Save the ONNX model to BytesIO object onnx_model_bytes = BytesIO() onnx.save_model(model, onnx_model_bytes) @@ -438,13 +432,11 @@ def onnx_concat(inputs, axis): onnx_model_bytes.seek(0) sess = ort.InferenceSession(onnx_model_bytes.read()) - # Prepare the input feeds with the input arrays input_feed = { input_name: input_array for input_name, input_array in zip(input_names, inputs) } - # Execute the ONNX model output = sess.run(["output"], input_feed) return output[0] @@ -527,20 +519,16 @@ def forward(self, x): "Input shape must have the same number of dimensions as the input tensor" ) - # Create a PyTorch model with dynamic reshape model = DynamicReshapeModel(shape) - # Perform dynamic reshape using PyTorch input_tensor = torch.tensor(input_tensor, dtype=torch.int32) - # Export the model to ONNX f = BytesIO() torch.onnx.export( model, input_tensor, f, opset_version=12, do_constant_folding=True ) f.seek(0) - # Run the ONNX model using ONNX Runtime sess = ort.InferenceSession(f.getvalue()) input_name = sess.get_inputs()[0].name output_name = sess.get_outputs()[0].name @@ -661,14 +649,12 @@ def forward(self, input): tensors_dict = {} refs = [] - # Define input arrays and axes input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) axes1 = np.array([0, 1], dtype=np.int32) input_array2 = np.array([[1, 2, 3, 4]], dtype=np.float32) axes2 = np.array([1], dtype=np.int32) - # Compute ONNX ReduceMean using GGML reducemean_numpy1 = onnx_reducemean(input_array1, axes1) reducemean_numpy2 = onnx_reducemean(input_array2, axes2) @@ -751,11 +737,9 @@ def forward(self, input1, input2): tensors_dict = {} refs = [] - # Define input arrays input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) input_array2 = np.array([[2, 2, 2], [5, 5, 5], [8, 8, 8]], dtype=np.float32) - # Compute ONNX Less using GGML less_numpy = onnx_less(input_array1, input_array2) tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) @@ -822,11 +806,9 @@ def forward(self, input1, input2): tensors_dict = {} refs = [] - # Define input arrays input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) input_array2 = np.array([[2, 2, 2], [5, 5, 5], [8, 8, 8]], dtype=np.float32) - # Compute ONNX Greater using GGML greater_numpy = onnx_greater(input_array1, input_array2) tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) @@ -887,14 +869,11 @@ def forward(self, input1): tensors_dict = {} refs = [] - # Define input arrays input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - # Compute ONNX Min using GGML min_numpy = onnx_min(input_array1) tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - # tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) min_node = onnx.helper.make_node( "Min", @@ -951,14 +930,9 @@ def forward(self, input1): tensors_dict = {} refs = [] - # Define input arrays input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - - # Compute ONNX Min using GGML min_numpy = onnx_max(input_array1) - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - # tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) min_node = onnx.helper.make_node( "Min", @@ -976,6 +950,273 @@ def forward(self, input1): ggml.ggml_free(context) +def test_ggml_onnx_matmul_operator(): + return + + def onnx_matmul(x1, x2): + class MatMulModel(torch.nn.Module): + def forward(self, input1, input2): + return torch.matmul(input1, input2) + + model = MatMulModel() + + x1_tensor = torch.tensor(x1, dtype=torch.float32) + x2_tensor = torch.tensor(x2, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + (x1_tensor, x2_tensor), + f, + input_names=["input1", "input2"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + x1_list = x1.tolist() + x2_list = x2.tolist() + input_feed = {"input1": x1_list, "input2": x2_list} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + # Define input arrays + input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) + input_array2 = np.array([[9, 8, 7], [6, 5, 4], [3, 2, 1]], dtype=np.float32) + + # Compute ONNX MatMul using GGML + matmul_numpy = onnx_matmul(input_array1, input_array2) + + tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) + tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) + + matmul_node = onnx.helper.make_node( + "MatMul", + inputs=["input_array1", "input_array2"], + outputs=["matmul_output"], + ) + + output_tensor = ggml_operators["MatMul"](matmul_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + result = ggml.utils.to_numpy(output_tensor) + + assert np.allclose(result, matmul_numpy) + + ggml.ggml_free(context) + + +def test_ggml_onnx_pow_operator(): + return + + def onnx_pow(x, y): + class PowModel(torch.nn.Module): + def forward(self, input1, input2): + return torch.pow(input1, input2) + + model = PowModel() + + x_tensor = torch.tensor(x, dtype=torch.float32) + y_tensor = torch.tensor(y, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + (x_tensor, y_tensor), + f, + input_names=["input1", "input2"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + x_list = x.tolist() + y_list = y.tolist() + input_feed = {"input1": x_list, "input2": y_list} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) + input_array2 = np.array([[2, 2, 2], [3, 3, 3], [4, 4, 4]], dtype=np.float32) + + pow_numpy = onnx_pow(input_array1, input_array2) + + tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) + tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) + + pow_node = onnx.helper.make_node( + "Pow", + inputs=["input_array1", "input_array2"], + outputs=["pow_output"], + ) + + nodes = [pow_node] + results = [] + + for pow_node in nodes: + output_tensor = ggml_operators["Pow"](pow_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + results.append(ggml.utils.to_numpy(output_tensor)) + + assert np.allclose(results[0], pow_numpy) + + ggml.ggml_free(context) + + +def test_ggml_onnx_relu_operator(): + # return + + def onnx_relu(x): + class ReluModel(torch.nn.Module): + def forward(self, input): + return torch.relu(input) + + model = ReluModel() + + x_tensor = torch.tensor(x, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + (x_tensor,), + f, + input_names=["input"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + x_list = x.tolist() + input_feed = {"input": x_list} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + input_array = np.array([[1, -2, 3], [-4, 5, -6], [7, -8, 9]], dtype=np.float32) + + relu_numpy = onnx_relu(input_array) + + tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) + + relu_node = onnx.helper.make_node( + "Relu", + inputs=["input_array"], + outputs=["relu_output"], + ) + + nodes = [relu_node] + results = [] + + for relu_node in nodes: + output_tensor = ggml_operators["Relu"](relu_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + results.append(ggml.utils.to_numpy(output_tensor)) + + assert np.allclose(results[0], relu_numpy) + + ggml.ggml_free(context) + + +def test_ggml_onnx_transpose_operator(): + # return + + def onnx_transpose(x, dim0=1, dim1=0): + class TransposeModel(torch.nn.Module): + def forward(self, input): + return torch.transpose(input, dim0, dim1) + + model = TransposeModel() + + x_tensor = torch.tensor(x, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + (x_tensor,), + f, + input_names=["input"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + x_list = x.tolist() + input_feed = {"input": x_list} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + input_array = np.array([[1, -2, 3], [-4, 5, -6], [7, -8, 9]], dtype=np.float32) + + transpose_numpy = onnx_transpose(input_array, 1, 0) + + tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) + + transpose_node = onnx.helper.make_node( + "Transpose", + inputs=["input_array"], + outputs=["transpose_output"], + perm=[1, 0], + ) + + nodes = [transpose_node] + results = [] + + for node in nodes: + output_tensor = ggml_operators["Transpose"](node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + results.append(ggml.utils.to_numpy(output_tensor)) + + assert np.allclose(results[0], transpose_numpy) + + ggml.ggml_free(context) + + def test_ggml_onnx_runtime_basic(): # return From 5f5ab8b0b85c1831afca83d08a6d2a3fe22ab4a4 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 11 Aug 2023 10:49:11 -0400 Subject: [PATCH 042/232] Use ONNX Transpose for testing --- tests/test_ggml_onnx_ops.py | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 12a49012..a5cd2bc5 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -1155,31 +1155,36 @@ def test_ggml_onnx_transpose_operator(): # return def onnx_transpose(x, dim0=1, dim1=0): - class TransposeModel(torch.nn.Module): - def forward(self, input): - return torch.transpose(input, dim0, dim1) + transpose_node = onnx.helper.make_node( + "Transpose", inputs=["input"], outputs=["output"], perm=[dim0, dim1] + ) - model = TransposeModel() + graph = onnx.helper.make_graph( + [transpose_node], + "transpose_graph", + inputs=[ + onnx.helper.make_tensor_value_info( + "input", onnx.TensorProto.FLOAT, list(x.shape) + ) + ], + outputs=[ + onnx.helper.make_tensor_value_info( + "output", onnx.TensorProto.FLOAT, list(x.shape) + ) + ], + ) - x_tensor = torch.tensor(x, dtype=torch.float32) + model = onnx.helper.make_model(graph) f = BytesIO() - torch.onnx.export( - model, - (x_tensor,), - f, - input_names=["input"], - output_names=["output"], - verbose=False, - ) + onnx.save_model(model, f) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) sess = ort.InferenceSession(onnx_model_bytes.read()) - x_list = x.tolist() - input_feed = {"input": x_list} + input_feed = {"input": x} output = sess.run(None, input_feed) From 9a32d934650b591a70acbab0572ec994e8cd0bad Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 11 Aug 2023 11:10:34 -0400 Subject: [PATCH 043/232] Add ConstantOfShape operator and tests --- ggml/contrib/onnx.py | 67 ++++++++++++++++++++++++++++++---- tests/test_ggml_onnx_ops.py | 73 +++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index dacc69d5..b5311206 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -215,6 +215,66 @@ def ggml_operator_constant( return new_tensor +@ggml.ggml_custom2_op_t +def custom_constant_of_shape( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + shape = ggml.utils.to_numpy(tensor_out).shape + value = ggml.utils.to_numpy(tensor_in_2) + new_tenor = np.full(tuple(shape), value) + + set_tensor_out(tensor_out, new_tenor) + + +@ggml_operator("ConstantOfShape") +def ggml_operator_constant_of_shape( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ConstantOfShape" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + node_attributes = node.attribute + + value_attr = next(attr for attr in node_attributes if attr.name == "value") + tensor = value_attr.t + data_type = tensor.data_type + np_data_type = tensor_dtype_to_np_dtype(data_type) + + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + + data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) + + data_tensor = ggml.utils.from_numpy( + data_value.astype(np_data_type_limit), + context, + ) + + shape = ggml.utils.to_numpy(node_inputs[0]) + + x = np.empty(shape, dtype=np_data_type_limit) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + data_tensor, + custom_constant_of_shape, + 1, + None, + ) + + return new_tensor + + @ggml_operator("Mul") def ggml_operator_mul( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] @@ -237,13 +297,6 @@ def ggml_operator_mul( return mul_result -@ggml_operator("ConstantOfShape") -def ggml_operator_constant_of_shape( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] -): - raise NotImplementedError(f'Operator "ConstantOfShape" not implemented') - - @ggml_operator("Softmax") def ggml_operator_softmax( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index a5cd2bc5..53e2c05c 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -384,6 +384,79 @@ def onnx_constant(value, dtype, shape): ggml.ggml_free(context) +def test_ggml_onnx_constant_of_shape_operator(): + # return + + def onnx_constant(value, other): + shape = list(other.shape) + value = numpy_helper.from_array(value) + constant_node = onnx.helper.make_node( + "ConstantOfShape", inputs=["data"], outputs=["constant_output"], value=value + ) + graph = onnx.helper.make_graph( + [constant_node], + "constant_graph", + inputs=[ + onnx.helper.make_tensor_value_info( + "data", onnx.TensorProto.INT64, shape + ) + ], + outputs=[ + onnx.helper.make_tensor_value_info( + "constant_output", onnx.TensorProto.FLOAT, shape + ) + ], + ) + model = onnx.helper.make_model(graph) + + onnx_model_bytes = BytesIO() + onnx.save_model(model, onnx_model_bytes) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + x_list = other.tolist() + input_feed = {"data": x_list} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + + shape1 = np.array([2, 3, 4], dtype=np.int32) + value_tensor = np.array([15], dtype=np.float32) + + cof_node1 = onnx.helper.make_node( + "ConstantOfShape", + inputs=["shape1"], + name="cof_node1", + outputs=["cof_output"], + value=numpy_helper.from_array(value_tensor), + ) + + tensors_dict["shape1"] = ggml.utils.from_numpy(shape1, context) + + constant_onnx = onnx_constant(value_tensor, shape1) + + nodes = [cof_node1] + results = [] + refs = [] + + for shape_node in nodes: + output_tensor = ggml_operators["ConstantOfShape"]( + shape_node, tensors_dict, context, refs + ) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + results.append(ggml.utils.to_numpy(output_tensor)) + assert np.array_equal(results[0], constant_onnx) + + ggml.ggml_free(context) + + def test_ggml_onnx_concat_operator(): return From a772fd95c8a0b063ad7f2214ca197e48759333c0 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 11 Aug 2023 11:49:44 -0400 Subject: [PATCH 044/232] Fix Transpose operator --- ggml/contrib/onnx.py | 12 ++++++++---- tests/test_ggml_onnx_ops.py | 9 ++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index b5311206..bd5fc745 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -680,10 +680,14 @@ def ggml_operator_transpose( ) output_name = node.output[0] - perm = next(attr for attr in node.attribute if attr.name == "perm").ints - # Add missing axes -> normally is 1, 0, 2, 3 - perm.extend([i for i in range(4) if i not in perm]) - perm = perm[:4] + input_shape = ggml.utils.to_numpy(node_inputs[0]).shape + perm_map = {1: [1, 0, 2, 3], 2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} + + perm_attr = next((attr for attr in node.attribute if attr.name == "perm"), None) + perm = perm_attr.ints if perm_attr else [] + + if len(perm) < len(input_shape): + perm = perm_map.get(len(input_shape), [1, 0, 2, 3]) transpose_result = ggml.ggml_permute(context, node_inputs[0], *perm) tensors_dict[output_name] = transpose_result diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 53e2c05c..410ae902 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -1227,9 +1227,9 @@ def forward(self, input): def test_ggml_onnx_transpose_operator(): # return - def onnx_transpose(x, dim0=1, dim1=0): + def onnx_transpose(x): transpose_node = onnx.helper.make_node( - "Transpose", inputs=["input"], outputs=["output"], perm=[dim0, dim1] + "Transpose", inputs=["input"], outputs=["output"] ) graph = onnx.helper.make_graph( @@ -1268,9 +1268,9 @@ def onnx_transpose(x, dim0=1, dim1=0): tensors_dict = {} refs = [] - input_array = np.array([[1, -2, 3], [-4, 5, -6], [7, -8, 9]], dtype=np.float32) + input_array = np.random.rand(3, 3, 3, 3).astype(np.float32) - transpose_numpy = onnx_transpose(input_array, 1, 0) + transpose_numpy = onnx_transpose(input_array) tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) @@ -1278,7 +1278,6 @@ def onnx_transpose(x, dim0=1, dim1=0): "Transpose", inputs=["input_array"], outputs=["transpose_output"], - perm=[1, 0], ) nodes = [transpose_node] From 833e2487264b3e921576ca84dee4b1957bbfdda9 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 14 Aug 2023 09:38:02 -0400 Subject: [PATCH 045/232] Improve Transpose and inputs for all operations --- ggml/contrib/onnx.py | 48 ++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index bd5fc745..b374d24f 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -66,9 +66,13 @@ def ggml_operator_add( output_name = node.output[0] + a = node_inputs[0] + b = node_inputs[1] + add_result = ggml.ggml_add( context, - *node_inputs, + a, + b, ) tensors_dict[output_name] = add_result return add_result @@ -287,10 +291,13 @@ def ggml_operator_mul( ) output_name = node.output[0] + a = node_inputs[0] + b = node_inputs[1] mul_result = ggml.ggml_mul( context, - *node_inputs, + a, + b, ) tensors_dict[output_name] = mul_result @@ -309,9 +316,11 @@ def ggml_operator_softmax( ) output_name = node.output[0] + a = node_inputs[0] + soft_max_result = ggml.ggml_soft_max( context, - *node_inputs, + a, ) tensors_dict[output_name] = soft_max_result return soft_max_result @@ -387,10 +396,11 @@ def ggml_operator_relu( ) output_name = node.output[0] + a = node_inputs[0] relu_result = ggml.ggml_relu( context, - *node_inputs, + a, ) tensors_dict[output_name] = relu_result return relu_result @@ -415,10 +425,11 @@ def ggml_operator_abs( ) output_name = node.output[0] + a = node_inputs[0] abs_result = ggml.ggml_abs( context, - *node_inputs, + a, ) tensors_dict[output_name] = abs_result return abs_result @@ -492,10 +503,11 @@ def ggml_operator_sqrt( ) output_name = node.output[0] + a = node_inputs[0] sqrt_result = ggml.ggml_sqrt( context, - *node_inputs, + a, ) tensors_dict[output_name] = sqrt_result return sqrt_result @@ -610,10 +622,13 @@ def ggml_operator_div( ) output_name = node.output[0] + a = node_inputs[0] + b = node_inputs[1] div_result = ggml.ggml_div( context, - *node_inputs, + a, + b, ) tensors_dict[output_name] = div_result return div_result @@ -638,10 +653,13 @@ def ggml_operator_sub( ) output_name = node.output[0] + a = node_inputs[0] + b = node_inputs[1] sub_result = ggml.ggml_sub( context, - *node_inputs, + a, + b, ) tensors_dict[output_name] = sub_result return sub_result @@ -681,15 +699,18 @@ def ggml_operator_transpose( output_name = node.output[0] input_shape = ggml.utils.to_numpy(node_inputs[0]).shape - perm_map = {1: [1, 0, 2, 3], 2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} + perm_map = {1: [0, 1, 2, 3], 2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} perm_attr = next((attr for attr in node.attribute if attr.name == "perm"), None) - perm = perm_attr.ints if perm_attr else [] - if len(perm) < len(input_shape): + if perm_attr is None: perm = perm_map.get(len(input_shape), [1, 0, 2, 3]) + else: + perm = list(perm_attr.ints) + perm += [0, 1, 2, 3][len(perm) :] - transpose_result = ggml.ggml_permute(context, node_inputs[0], *perm) + ax0, ax1, ax2, ax3 = perm # TODO: do this for all node_inputs + transpose_result = ggml.ggml_permute(context, node_inputs[0], ax0, ax1, ax2, ax3) tensors_dict[output_name] = transpose_result return transpose_result @@ -706,10 +727,11 @@ def ggml_operator_log( ) output_name = node.output[0] + a = node_inputs[0] log_result = ggml.ggml_log( context, - *node_inputs, + a, ) tensors_dict[output_name] = log_result return log_result From 973c0028f7613b1a78a355dda0da737998909fea Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 14 Aug 2023 10:32:29 -0400 Subject: [PATCH 046/232] Add Range operator, deactivate Transpose tests --- ggml/contrib/onnx.py | 47 ++++++++++++- tests/test_ggml_onnx_ops.py | 127 ++++++++++++++++++++++++++++++++---- 2 files changed, 158 insertions(+), 16 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index b374d24f..46f9ff80 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -634,11 +634,54 @@ def ggml_operator_div( return div_result +@ggml.ggml_custom2_op_t +def custom_range( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + tensors = ggml.utils.to_numpy(tensor_in_2) + start_array, limit_array, delta_array = tensors + + new_tensor = np.arange(start_array, limit_array, delta_array) + + set_tensor_out(tensor_out, new_tensor) + + @ggml_operator("Range") def ggml_operator_range( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Range" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 3: + raise ValueError( + f'Error for node "{node.name}": Operation "Range" requires exactly three inputs. Actual number of inputs: {len(node_inputs)}' + ) + + tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + + start, stop, step = tensors + output_shape = (int(np.ceil((stop - start) / step)),) + + x = np.empty(output_shape, dtype=step.dtype) + x_t = ggml.utils.from_numpy(x, context) + + input_tensors = ggml.utils.from_numpy(np.array(tensors), context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + input_tensors, + custom_range, + 1, + None, + ) + + return new_tensor @ggml_operator("Sub") @@ -709,7 +752,7 @@ def ggml_operator_transpose( perm = list(perm_attr.ints) perm += [0, 1, 2, 3][len(perm) :] - ax0, ax1, ax2, ax3 = perm # TODO: do this for all node_inputs + ax0, ax1, ax2, ax3 = perm transpose_result = ggml.ggml_permute(context, node_inputs[0], ax0, ax1, ax2, ax3) tensors_dict[output_name] = transpose_result return transpose_result diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 410ae902..dbbfae4b 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -1225,11 +1225,11 @@ def forward(self, input): def test_ggml_onnx_transpose_operator(): - # return + return - def onnx_transpose(x): + def onnx_transpose(x, perm=[1, 0]): transpose_node = onnx.helper.make_node( - "Transpose", inputs=["input"], outputs=["output"] + "Transpose", inputs=["input"], outputs=["output"], perm=perm ) graph = onnx.helper.make_graph( @@ -1268,28 +1268,127 @@ def onnx_transpose(x): tensors_dict = {} refs = [] - input_array = np.random.rand(3, 3, 3, 3).astype(np.float32) + import itertools - transpose_numpy = onnx_transpose(input_array) + input_array = np.random.rand(3, 3, 3).astype(np.float32) + permutations = list(itertools.permutations(np.arange(len(input_array.shape)))) tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) + nodes = [] + ggml_results = [] + onnx_results = [] - transpose_node = onnx.helper.make_node( - "Transpose", - inputs=["input_array"], - outputs=["transpose_output"], - ) + for i, permutation in enumerate(permutations): + transpose_node = onnx.helper.make_node( + "Transpose", + inputs=["input_array"], + outputs=[f"transpose_output{i}"], + perm=permutation, + ) - nodes = [transpose_node] - results = [] + nodes.append(transpose_node) + onnx_results.append(onnx_transpose(input_array, permutation)) for node in nodes: output_tensor = ggml_operators["Transpose"](node, tensors_dict, context, refs) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) + ggml_results.append(ggml.utils.to_numpy(output_tensor)) + + test_results = [] + + for i, result in enumerate(ggml_results): + test_results.append(np.allclose(result, onnx_results[i])) + # if not np.allclose(result, onnx_results[i]): + # print() + # print() + # print() + # print(permutations[i]) + # print("ggml:") + # print(result) + # print("onnx:") + # print(onnx_results[i]) + # break + + print(test_results) + + ggml.ggml_free(context) + + +def test_ggml_onnx_range_operator(): + # return + + def onnx_range(start, limit, delta): + range_node = onnx.helper.make_node( + "Range", + inputs=["start", "limit", "delta"], + outputs=["output"], + ) + + graph = onnx.helper.make_graph( + [range_node], + "range_graph", + inputs=[ + onnx.helper.make_tensor_value_info( + "start", onnx.TensorProto.FLOAT, list(start.shape) + ), + onnx.helper.make_tensor_value_info( + "limit", onnx.TensorProto.FLOAT, list(limit.shape) + ), + onnx.helper.make_tensor_value_info( + "delta", onnx.TensorProto.FLOAT, list(delta.shape) + ), + ], + outputs=[ + onnx.helper.make_tensor_value_info( + "output", onnx.TensorProto.FLOAT, list(start.shape) + ), + ], + ) + + model = onnx.helper.make_model(graph) + + f = BytesIO() + onnx.save_model(model, f) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + input_feed = {"start": start, "limit": limit, "delta": delta} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + start_array = np.random.uniform(-10, 10, (1,)).astype(np.float32) + limit_array = np.random.uniform(0, 20, (1,)).astype(np.float32) + delta_array = np.random.uniform(0.1, 2, (1,)).astype(np.float32) + + range_numpy = onnx_range(start_array, limit_array, delta_array) + + tensors_dict["start_array"] = ggml.utils.from_numpy(start_array, context) + tensors_dict["limit_array"] = ggml.utils.from_numpy(limit_array, context) + tensors_dict["delta_array"] = ggml.utils.from_numpy(delta_array, context) + + range_node = onnx.helper.make_node( + "Range", + inputs=["start_array", "limit_array", "delta_array"], + outputs=["range_output"], + ) + + output_tensor = ggml_operators["Range"](range_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + result = ggml.utils.to_numpy(output_tensor) - assert np.allclose(results[0], transpose_numpy) + assert np.allclose(result, range_numpy) ggml.ggml_free(context) From c4bc15b5af663411f3e849e1b56373c019938885 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 14 Aug 2023 10:38:06 -0400 Subject: [PATCH 047/232] Fix operator names --- ggml/contrib/onnx.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 46f9ff80..d45c1515 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -531,7 +531,7 @@ def __init__(self, axes, keepdims): @ggml.ggml_custom2_op_t -def custom_reducemean( +def custom_reduce_mean( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, tensor_in_2: ggml.ggml_tensor_p, @@ -586,7 +586,7 @@ def ggml_operator_reduce_mean( context, x_t, node_inputs[0], - custom_reducemean, + custom_reduce_mean, 1, userdata_p, ) @@ -849,7 +849,7 @@ def custom_less( @ggml_operator("Less") -def ggml_operator_greater( +def ggml_operator_less( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -895,7 +895,7 @@ def custom_min( @ggml_operator("Min") -def ggml_operator_greater( +def ggml_operator_min( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -944,7 +944,7 @@ def custom_max( @ggml_operator("Max") -def ggml_operator_greater( +def ggml_operator_max( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] From 08af18b170b755d757199e4a00acabeefab7f276 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 14 Aug 2023 10:51:19 -0400 Subject: [PATCH 048/232] Sort operators --- ggml/contrib/onnx.py | 762 +++++++++++++++++++++---------------------- 1 file changed, 381 insertions(+), 381 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index d45c1515..8e47c104 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -53,6 +53,28 @@ def set_tensor_out(tensor, ndarray): # ------ Operators ------ +@ggml_operator("Abs") +def ggml_operator_abs( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Abs" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + a = node_inputs[0] + + abs_result = ggml.ggml_abs( + context, + a, + ) + tensors_dict[output_name] = abs_result + return abs_result + + @ggml_operator("Add") def ggml_operator_add( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] @@ -78,79 +100,18 @@ def ggml_operator_add( return add_result -class ShapeUserData(ctypes.Structure): - _fields_ = [("start", ctypes.c_int), ("end", ctypes.c_int)] - - -@ggml.ggml_custom2_op_t -def custom_shape( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], +@ggml_operator("Cast") +def ggml_operator_cast( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ShapeUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - start = userdata_data.start - end = userdata_data.end - - shaped_tensor = tensor[start:end] - tensor_shape = np.array(shaped_tensor.shape, dtype=np.int32) - - ggml.utils.to_numpy(tensor_out)[:] = tensor_shape + raise NotImplementedError(f'Operator "Cast" not implemented') -@ggml_operator("Shape") -def ggml_operator_shape( +@ggml_operator("Concat") +def ggml_operator_concat( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - node_inputs = [tensors_dict[inp] for inp in node.input] - - if len(node_inputs) == 0 or len(node_inputs) > 3: - raise ValueError( - f'Error for node "{node.name}": Operation "Shape" requires at least 1 and maximum of 3 inputs. Actual number of inputs: {len(node_inputs)}' - ) - - tensor = ggml.utils.to_numpy(node_inputs[0]) - start = ( - ggml.utils.to_numpy(node_inputs[1]) - if len(node_inputs) > 1 - else [ctypes.c_int(0)] - ) - end = ( - ggml.utils.to_numpy(node_inputs[2]) - if len(node_inputs) > 2 - else [ctypes.c_int(tensor.shape[-1])] - ) - - start = start[0] if len(start) else ctypes.c_int(0) - end = end[0] if len(end) else ctypes.c_int(tensor.shape[-1]) - - shape_userdata = ShapeUserData(start, end) - userdata_p = ctypes.cast(ctypes.pointer(shape_userdata), ctypes.c_void_p) - - output_shape = len(list(tensor.shape)) - - x = np.empty(output_shape, dtype=tensor.dtype) - - x_t = ggml.utils.from_numpy(x, context) - - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, - x_t, - node_inputs[0], - custom_shape, - 1, - userdata_p, - ) - - refs.append(shape_userdata) - - return new_tensor + raise NotImplementedError(f'Operator "Concat" not implemented') @ggml.ggml_custom2_op_t @@ -279,51 +240,28 @@ def ggml_operator_constant_of_shape( return new_tensor -@ggml_operator("Mul") -def ggml_operator_mul( +@ggml_operator("Div") +def ggml_operator_div( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Mul" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Div" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) output_name = node.output[0] a = node_inputs[0] b = node_inputs[1] - mul_result = ggml.ggml_mul( + div_result = ggml.ggml_div( context, a, b, ) - - tensors_dict[output_name] = mul_result - return mul_result - - -@ggml_operator("Softmax") -def ggml_operator_softmax( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] -): - node_inputs = [tensors_dict[inp] for inp in node.input] - - if len(node_inputs) != 1: - raise ValueError( - f'Error for node "{node.name}": Operation "Softmax" requires exactly one input. Actual number of inputs: {len(node_inputs)}' - ) - - output_name = node.output[0] - a = node_inputs[0] - - soft_max_result = ggml.ggml_soft_max( - context, - a, - ) - tensors_dict[output_name] = soft_max_result - return soft_max_result + tensors_dict[output_name] = div_result + return div_result @ggml.ggml_custom3_op_t @@ -384,59 +322,58 @@ def ggml_operator_gather( return new_tensor -@ggml_operator("Relu") -def ggml_operator_relu( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +@ggml.ggml_custom3_op_t +def custom_greater( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], ): - node_inputs = [tensors_dict[inp] for inp in node.input] - - if len(node_inputs) != 1: - raise ValueError( - f'Error for node "{node.name}": Operation "Relu" requires exactly one input. Actual number of inputs: {len(node_inputs)}' - ) - - output_name = node.output[0] - a = node_inputs[0] - - relu_result = ggml.ggml_relu( - context, - a, - ) - tensors_dict[output_name] = relu_result - return relu_result + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + x = np.greater(a, b) -@ggml_operator("MatMul") -def ggml_operator_mat_mul( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] -): - raise NotImplementedError(f'Operator "MatMul" not implemented') + set_tensor_out(tensor_out, x) -@ggml_operator("Abs") -def ggml_operator_abs( +@ggml_operator("Greater") +def ggml_operator_greater( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] - if len(node_inputs) != 1: + if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Abs" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Greater" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - output_name = node.output[0] - a = node_inputs[0] + a = ggml.utils.to_numpy(node_inputs[0]) + b = ggml.utils.to_numpy(node_inputs[1]) - abs_result = ggml.ggml_abs( + output_shape = np.broadcast(np.empty(a.shape), np.empty(b.shape)).shape + + x = np.empty(output_shape, dtype=a.dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( context, - a, + x_t, + node_inputs[0], + node_inputs[1], + custom_greater, + 1, + None, ) - tensors_dict[output_name] = abs_result - return abs_result + + return new_tensor @ggml.ggml_custom3_op_t -def custom_unsqueeze( +def custom_less( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, tensor_in_2: ggml.ggml_tensor_p, @@ -445,37 +382,31 @@ def custom_unsqueeze( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) - axes = ggml.utils.to_numpy(tensor_in_3) + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) - for axis in np.nditer(axes): - x = np.expand_dims(x, axis=axis) + x = np.less(a, b) - ggml.utils.to_numpy(tensor_out)[:] = x + set_tensor_out(tensor_out, x) -@ggml_operator("Unsqueeze") -def ggml_operator_unsqueeze( +@ggml_operator("Less") +def ggml_operator_less( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - x_input = ggml.utils.to_numpy(node_inputs[0]) - axes = ggml.utils.to_numpy(node_inputs[1]) - - output_shape = x_input.shape - - for axis in np.nditer(axes): - output_shape = np.insert(output_shape, axis, 1) + a = ggml.utils.to_numpy(node_inputs[0]) + b = ggml.utils.to_numpy(node_inputs[1]) - output_shape = output_shape.astype(np.int32) + output_shape = np.broadcast(np.empty(a.shape), np.empty(b.shape)).shape - x = np.empty(output_shape, dtype=x_input.dtype) + x = np.empty(output_shape, dtype=a.dtype) x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( @@ -483,7 +414,7 @@ def ggml_operator_unsqueeze( x_t, node_inputs[0], node_inputs[1], - custom_unsqueeze, + custom_less, 1, None, ) @@ -491,47 +422,37 @@ def ggml_operator_unsqueeze( return new_tensor -@ggml_operator("Sqrt") -def ggml_operator_sqrt( +@ggml_operator("Log") +def ggml_operator_log( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( - f'Error for node "{node.name}": Operation "Sqrt" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Log" requires exactly one input. Actual number of inputs: {len(node_inputs)}' ) output_name = node.output[0] a = node_inputs[0] - sqrt_result = ggml.ggml_sqrt( + log_result = ggml.ggml_log( context, a, ) - tensors_dict[output_name] = sqrt_result - return sqrt_result + tensors_dict[output_name] = log_result + return log_result -class RedueMeanUserData(ctypes.Structure): - _fields_ = [ - ("axes", ctypes.POINTER(ctypes.c_int)), - ("axes_length", ctypes.c_int), - ("keepdims", ctypes.c_int), - ] - - def __init__(self, axes, keepdims): - if isinstance(axes, list): - self.axes_length = len(axes) - self.axes = (ctypes.c_int * self.axes_length)(*axes) - else: - raise ValueError("axes should be a list of integers") - - self.keepdims = keepdims +@ggml_operator("MatMul") +def ggml_operator_mat_mul( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +): + raise NotImplementedError(f'Operator "MatMul" not implemented') @ggml.ggml_custom2_op_t -def custom_reduce_mean( +def custom_max( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, tensor_in_2: ggml.ggml_tensor_p, @@ -539,99 +460,125 @@ def custom_reduce_mean( nth: int, userdata: Optional[ctypes.c_void_p], ): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(RedueMeanUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - rmean_result = np.mean(tensor, tuple(axes), keepdims=keepdims) - - set_tensor_out(tensor_out, rmean_result) + a = ggml.utils.to_numpy(tensor_in_2) + x = np.max(a) + set_tensor_out(tensor_out, np.array(x)) -@ggml_operator("ReduceMean") -def ggml_operator_reduce_mean( +@ggml_operator("Max") +def ggml_operator_max( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( - f'Error for node "{node.name}": Operation "ReduceMean" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Max" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - tensor = ggml.utils.to_numpy(node_inputs[0]) - axes = next(attr for attr in node.attribute if attr.name == "axes").ints - keepdims = next(attr for attr in node.attribute if attr.name == "keepdims").i - - rmean_userdata = RedueMeanUserData(list(axes), keepdims) - userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) - - output_shape = list(tensor.shape) - for axis in axes: - output_shape[axis] = 1 - for axis in axes: - if not keepdims: - output_shape.pop(0) - - output_shape = tuple(output_shape) + a = ggml.utils.to_numpy(node_inputs[0]) - x = np.empty(output_shape, dtype=tensor.dtype) + output_shape = () + ggml_type = map_to_ggml_type(a.dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.ggml_new_tensor( + context, + ggml_type.value, + len(output_shape), + (ctypes.c_int64 * len(output_shape))(*output_shape), + ) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( context, x_t, node_inputs[0], - custom_reduce_mean, + custom_max, 1, - userdata_p, + None, ) - refs.append(rmean_userdata) - return new_tensor -@ggml_operator("Where") -def ggml_operator_where( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +@ggml.ggml_custom2_op_t +def custom_min( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], ): - raise NotImplementedError(f'Operator "Where" not implemented') + a = ggml.utils.to_numpy(tensor_in_2) + x = np.min(a) + set_tensor_out(tensor_out, np.array(x)) -@ggml_operator("Concat") -def ggml_operator_concat( +@ggml_operator("Min") +def ggml_operator_min( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Concat" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Min" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) -@ggml_operator("Div") -def ggml_operator_div( + a = ggml.utils.to_numpy(node_inputs[0]) + + output_shape = () + ggml_type = map_to_ggml_type(a.dtype) + + x_t = ggml.ggml_new_tensor( + context, + ggml_type.value, + len(output_shape), + (ctypes.c_int64 * len(output_shape))(*output_shape), + ) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + node_inputs[0], + custom_min, + 1, + None, + ) + + return new_tensor + + +@ggml_operator("Mul") +def ggml_operator_mul( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Div" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Mul" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) output_name = node.output[0] a = node_inputs[0] b = node_inputs[1] - div_result = ggml.ggml_div( + mul_result = ggml.ggml_mul( context, a, b, ) - tensors_dict[output_name] = div_result - return div_result + + tensors_dict[output_name] = mul_result + return mul_result + + +@ggml_operator("Pow") +def ggml_operator_pow( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +): + raise NotImplementedError(f'Operator "Pow" not implemented') @ggml.ggml_custom2_op_t @@ -684,293 +631,339 @@ def ggml_operator_range( return new_tensor -@ggml_operator("Sub") -def ggml_operator_sub( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] -): - node_inputs = [tensors_dict[inp] for inp in node.input] - - if len(node_inputs) != 2: - raise ValueError( - f'Error for node "{node.name}": Operation "Sub" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' - ) +class RedueMeanUserData(ctypes.Structure): + _fields_ = [ + ("axes", ctypes.POINTER(ctypes.c_int)), + ("axes_length", ctypes.c_int), + ("keepdims", ctypes.c_int), + ] - output_name = node.output[0] - a = node_inputs[0] - b = node_inputs[1] + def __init__(self, axes, keepdims): + if isinstance(axes, list): + self.axes_length = len(axes) + self.axes = (ctypes.c_int * self.axes_length)(*axes) + else: + raise ValueError("axes should be a list of integers") - sub_result = ggml.ggml_sub( - context, - a, - b, - ) - tensors_dict[output_name] = sub_result - return sub_result + self.keepdims = keepdims -@ggml_operator("Pow") -def ggml_operator_pow( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +@ggml.ggml_custom2_op_t +def custom_reduce_mean( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], ): - raise NotImplementedError(f'Operator "Pow" not implemented') - + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(RedueMeanUserData)) + userdata_data = userdata_data_ptr.contents -@ggml_operator("Cast") -def ggml_operator_cast( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] -): - raise NotImplementedError(f'Operator "Cast" not implemented') + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + rmean_result = np.mean(tensor, tuple(axes), keepdims=keepdims) -@ggml_operator("Reshape") -def ggml_operator_reshape( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] -): - raise NotImplementedError(f'Operator "Reshape" not implemented') + set_tensor_out(tensor_out, rmean_result) -@ggml_operator("Transpose") -def ggml_operator_transpose( +@ggml_operator("ReduceMean") +def ggml_operator_reduce_mean( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( - f'Error for node "{node.name}": Operation "Transpose" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "ReduceMean" requires exactly one input. Actual number of inputs: {len(node_inputs)}' ) - output_name = node.output[0] - input_shape = ggml.utils.to_numpy(node_inputs[0]).shape - perm_map = {1: [0, 1, 2, 3], 2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} + tensor = ggml.utils.to_numpy(node_inputs[0]) + axes = next(attr for attr in node.attribute if attr.name == "axes").ints + keepdims = next(attr for attr in node.attribute if attr.name == "keepdims").i - perm_attr = next((attr for attr in node.attribute if attr.name == "perm"), None) + rmean_userdata = RedueMeanUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) - if perm_attr is None: - perm = perm_map.get(len(input_shape), [1, 0, 2, 3]) - else: - perm = list(perm_attr.ints) - perm += [0, 1, 2, 3][len(perm) :] + output_shape = list(tensor.shape) + for axis in axes: + output_shape[axis] = 1 + for axis in axes: + if not keepdims: + output_shape.pop(0) - ax0, ax1, ax2, ax3 = perm - transpose_result = ggml.ggml_permute(context, node_inputs[0], ax0, ax1, ax2, ax3) - tensors_dict[output_name] = transpose_result - return transpose_result + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor.dtype) -@ggml_operator("Log") -def ggml_operator_log( + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + node_inputs[0], + custom_reduce_mean, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor + + +@ggml_operator("Relu") +def ggml_operator_relu( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( - f'Error for node "{node.name}": Operation "Log" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Relu" requires exactly one input. Actual number of inputs: {len(node_inputs)}' ) output_name = node.output[0] a = node_inputs[0] - log_result = ggml.ggml_log( + relu_result = ggml.ggml_relu( context, a, ) - tensors_dict[output_name] = log_result - return log_result + tensors_dict[output_name] = relu_result + return relu_result -@ggml.ggml_custom3_op_t -def custom_greater( +@ggml_operator("Reshape") +def ggml_operator_reshape( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +): + raise NotImplementedError(f'Operator "Reshape" not implemented') + + +class ShapeUserData(ctypes.Structure): + _fields_ = [("start", ctypes.c_int), ("end", ctypes.c_int)] + + +@ggml.ggml_custom2_op_t +def custom_shape( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, ith: int, nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ShapeUserData)) + userdata_data = userdata_data_ptr.contents - x = np.greater(a, b) + tensor = ggml.utils.to_numpy(tensor_in_2) + start = userdata_data.start + end = userdata_data.end - set_tensor_out(tensor_out, x) + shaped_tensor = tensor[start:end] + tensor_shape = np.array(shaped_tensor.shape, dtype=np.int32) + ggml.utils.to_numpy(tensor_out)[:] = tensor_shape -@ggml_operator("Greater") -def ggml_operator_greater( + +@ggml_operator("Shape") +def ggml_operator_shape( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] - if len(node_inputs) != 2: + if len(node_inputs) == 0 or len(node_inputs) > 3: raise ValueError( - f'Error for node "{node.name}": Operation "Greater" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Shape" requires at least 1 and maximum of 3 inputs. Actual number of inputs: {len(node_inputs)}' ) - a = ggml.utils.to_numpy(node_inputs[0]) - b = ggml.utils.to_numpy(node_inputs[1]) + tensor = ggml.utils.to_numpy(node_inputs[0]) + start = ( + ggml.utils.to_numpy(node_inputs[1]) + if len(node_inputs) > 1 + else [ctypes.c_int(0)] + ) + end = ( + ggml.utils.to_numpy(node_inputs[2]) + if len(node_inputs) > 2 + else [ctypes.c_int(tensor.shape[-1])] + ) - output_shape = np.broadcast(np.empty(a.shape), np.empty(b.shape)).shape + start = start[0] if len(start) else ctypes.c_int(0) + end = end[0] if len(end) else ctypes.c_int(tensor.shape[-1]) + + shape_userdata = ShapeUserData(start, end) + userdata_p = ctypes.cast(ctypes.pointer(shape_userdata), ctypes.c_void_p) + + output_shape = len(list(tensor.shape)) + + x = np.empty(output_shape, dtype=tensor.dtype) - x = np.empty(output_shape, dtype=a.dtype) x_t = ggml.utils.from_numpy(x, context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( context, x_t, node_inputs[0], - node_inputs[1], - custom_greater, + custom_shape, 1, - None, + userdata_p, ) + refs.append(shape_userdata) + return new_tensor -@ggml.ggml_custom3_op_t -def custom_less( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], +@ggml_operator("Softmax") +def ggml_operator_softmax( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) + node_inputs = [tensors_dict[inp] for inp in node.input] - x = np.less(a, b) + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Softmax" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) - set_tensor_out(tensor_out, x) + output_name = node.output[0] + a = node_inputs[0] + soft_max_result = ggml.ggml_soft_max( + context, + a, + ) + tensors_dict[output_name] = soft_max_result + return soft_max_result -@ggml_operator("Less") -def ggml_operator_less( + +@ggml_operator("Sqrt") +def ggml_operator_sqrt( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] - if len(node_inputs) != 2: + if len(node_inputs) != 1: raise ValueError( - f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Sqrt" requires exactly one input. Actual number of inputs: {len(node_inputs)}' ) - a = ggml.utils.to_numpy(node_inputs[0]) - b = ggml.utils.to_numpy(node_inputs[1]) - - output_shape = np.broadcast(np.empty(a.shape), np.empty(b.shape)).shape - - x = np.empty(output_shape, dtype=a.dtype) - x_t = ggml.utils.from_numpy(x, context) + output_name = node.output[0] + a = node_inputs[0] - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + sqrt_result = ggml.ggml_sqrt( context, - x_t, - node_inputs[0], - node_inputs[1], - custom_less, - 1, - None, + a, ) - - return new_tensor + tensors_dict[output_name] = sqrt_result + return sqrt_result -@ggml.ggml_custom2_op_t -def custom_min( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], +@ggml_operator("Sub") +def ggml_operator_sub( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - a = ggml.utils.to_numpy(tensor_in_2) - x = np.min(a) - set_tensor_out(tensor_out, np.array(x)) + node_inputs = [tensors_dict[inp] for inp in node.input] + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Sub" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) -@ggml_operator("Min") -def ggml_operator_min( + output_name = node.output[0] + a = node_inputs[0] + b = node_inputs[1] + + sub_result = ggml.ggml_sub( + context, + a, + b, + ) + tensors_dict[output_name] = sub_result + return sub_result + + +@ggml_operator("Transpose") +def ggml_operator_transpose( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( - f'Error for node "{node.name}": Operation "Min" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Transpose" requires exactly one input. Actual number of inputs: {len(node_inputs)}' ) - a = ggml.utils.to_numpy(node_inputs[0]) - - output_shape = () - ggml_type = map_to_ggml_type(a.dtype) + output_name = node.output[0] + input_shape = ggml.utils.to_numpy(node_inputs[0]).shape + perm_map = {1: [0, 1, 2, 3], 2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} - x_t = ggml.ggml_new_tensor( - context, - ggml_type.value, - len(output_shape), - (ctypes.c_int64 * len(output_shape))(*output_shape), - ) + perm_attr = next((attr for attr in node.attribute if attr.name == "perm"), None) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, - x_t, - node_inputs[0], - custom_min, - 1, - None, - ) + if perm_attr is None: + perm = perm_map.get(len(input_shape), [1, 0, 2, 3]) + else: + perm = list(perm_attr.ints) + perm += [0, 1, 2, 3][len(perm) :] - return new_tensor + ax0, ax1, ax2, ax3 = perm + transpose_result = ggml.ggml_permute(context, node_inputs[0], ax0, ax1, ax2, ax3) + tensors_dict[output_name] = transpose_result + return transpose_result -@ggml.ggml_custom2_op_t -def custom_max( +@ggml.ggml_custom3_op_t +def custom_unsqueeze( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, ith: int, nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) - x = np.max(a) - set_tensor_out(tensor_out, np.array(x)) + x = ggml.utils.to_numpy(tensor_in_2) + axes = ggml.utils.to_numpy(tensor_in_3) + for axis in np.nditer(axes): + x = np.expand_dims(x, axis=axis) -@ggml_operator("Max") -def ggml_operator_max( + ggml.utils.to_numpy(tensor_out)[:] = x + + +@ggml_operator("Unsqueeze") +def ggml_operator_unsqueeze( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): node_inputs = [tensors_dict[inp] for inp in node.input] - if len(node_inputs) != 1: + if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Max" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' ) - a = ggml.utils.to_numpy(node_inputs[0]) + x_input = ggml.utils.to_numpy(node_inputs[0]) + axes = ggml.utils.to_numpy(node_inputs[1]) - output_shape = () - ggml_type = map_to_ggml_type(a.dtype) + output_shape = x_input.shape - x_t = ggml.ggml_new_tensor( - context, - ggml_type.value, - len(output_shape), - (ctypes.c_int64 * len(output_shape))(*output_shape), - ) + for axis in np.nditer(axes): + output_shape = np.insert(output_shape, axis, 1) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + output_shape = output_shape.astype(np.int32) + + x = np.empty(output_shape, dtype=x_input.dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( context, x_t, node_inputs[0], - custom_max, + node_inputs[1], + custom_unsqueeze, 1, None, ) @@ -978,6 +971,13 @@ def ggml_operator_max( return new_tensor +@ggml_operator("Where") +def ggml_operator_where( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +): + raise NotImplementedError(f'Operator "Where" not implemented') + + class GgmlBackendRep(BackendRep): def __init__(self): super(GgmlBackendRep, self).__init__() From 923532e43cbf91e1e199bdae25bce2b695ce69d7 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 14 Aug 2023 10:55:28 -0400 Subject: [PATCH 049/232] Remove unused imports --- ggml/contrib/onnx.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 8e47c104..a01d2fdf 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1,10 +1,9 @@ import ctypes -import struct from typing import Any, Tuple, List import numpy as np import onnx -from onnx import defs, helper +from onnx import defs from onnx.backend.base import Backend, BackendRep from onnx.helper import make_opsetid from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto @@ -12,12 +11,9 @@ import ggml import ggml.utils -import torch from typing import Optional - ggml_operators = {} - onnx_dtype_map = { elem_type: np_dtype for elem_type, np_dtype in onnx.mapping.TENSOR_TYPE_TO_NP_TYPE.items() From 7ba5b9a190e864bf8a039a640fc51fef13b5232a Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 14 Aug 2023 16:56:00 -0400 Subject: [PATCH 050/232] Add Reshape operator --- ggml/contrib/onnx.py | 38 +++++++++++++++++++++++++- tests/test_ggml_onnx_ops.py | 54 ++++++++++++++++++++----------------- 2 files changed, 67 insertions(+), 25 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index a01d2fdf..7458c6f6 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -736,7 +736,43 @@ def ggml_operator_relu( def ggml_operator_reshape( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Reshape" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Reshape" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + a = node_inputs[0] + b = node_inputs[1] + + b_numpy_reverse: list = ggml.utils.to_numpy(b).tolist() + b_numpy_reverse.reverse() + + dims = len(b_numpy_reverse) + + if dims > 4: + raise NotImplementedError( + f'Operator "Reshape" not implemented for over 4D arrays.' + ) + + b_numpy_reverse += [0, 0, 0][:dims] + + ne0, ne1, ne2, ne3 = b_numpy_reverse + + dim_map = { + 1: (ggml.ggml_reshape_1d, (context, a, ne0)), + 2: (ggml.ggml_reshape_2d, (context, a, ne0, ne1)), + 3: (ggml.ggml_reshape_3d, (context, a, ne0, ne1, ne2)), + 4: (ggml.ggml_reshape_4d, (context, a, ne0, ne1, ne2, ne3)), + } + + func = dim_map[dims][0] + args = dim_map[dims][1] + reshape_result = func(*args) + tensors_dict[output_name] = reshape_result + return reshape_result class ShapeUserData(ctypes.Structure): diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index dbbfae4b..88d75b9b 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -569,7 +569,7 @@ def onnx_concat(inputs, axis): def test_ggml_onnx_reshape_operation(): - return + # return def onnx_reshape(input_tensor, shape): class DynamicReshapeModel(torch.nn.Module): @@ -1024,36 +1024,42 @@ def forward(self, input1): def test_ggml_onnx_matmul_operator(): - return + # return - def onnx_matmul(x1, x2): - class MatMulModel(torch.nn.Module): - def forward(self, input1, input2): - return torch.matmul(input1, input2) + def onnx_matmul(x, y): + matmul_node = onnx.helper.make_node( + "MatMul", inputs=["input1", "input2"], outputs=["output"] + ) - model = MatMulModel() + graph = onnx.helper.make_graph( + [matmul_node], + "matmul_graph", + inputs=[ + onnx.helper.make_tensor_value_info( + "input1", onnx.TensorProto.FLOAT, list(x.shape) + ), + onnx.helper.make_tensor_value_info( + "input2", onnx.TensorProto.FLOAT, list(y.shape) + ), + ], + outputs=[ + onnx.helper.make_tensor_value_info( + "output", onnx.TensorProto.FLOAT, list((x.shape[0], y.shape[1])) + ) + ], + ) - x1_tensor = torch.tensor(x1, dtype=torch.float32) - x2_tensor = torch.tensor(x2, dtype=torch.float32) + model = onnx.helper.make_model(graph) f = BytesIO() - torch.onnx.export( - model, - (x1_tensor, x2_tensor), - f, - input_names=["input1", "input2"], - output_names=["output"], - verbose=False, - ) + onnx.save_model(model, f) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) sess = ort.InferenceSession(onnx_model_bytes.read()) - x1_list = x1.tolist() - x2_list = x2.tolist() - input_feed = {"input1": x1_list, "input2": x2_list} + input_feed = {"input1": x, "input2": y} output = sess.run(None, input_feed) @@ -1225,7 +1231,7 @@ def forward(self, input): def test_ggml_onnx_transpose_operator(): - return + # return def onnx_transpose(x, perm=[1, 0]): transpose_node = onnx.helper.make_node( @@ -1367,9 +1373,9 @@ def onnx_range(start, limit, delta): tensors_dict = {} refs = [] - start_array = np.random.uniform(-10, 10, (1,)).astype(np.float32) - limit_array = np.random.uniform(0, 20, (1,)).astype(np.float32) - delta_array = np.random.uniform(0.1, 2, (1,)).astype(np.float32) + start_array = np.array([-5], np.float32) + limit_array = np.array([10], np.float32) + delta_array = np.array([0.5], np.float32) range_numpy = onnx_range(start_array, limit_array, delta_array) From 55e802a9e6adb86a6de449cad52776bfbbbccb37 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 15 Aug 2023 16:31:54 -0400 Subject: [PATCH 051/232] Add MatMul operator --- ggml/contrib/onnx.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 7458c6f6..15599d85 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -444,7 +444,38 @@ def ggml_operator_log( def ggml_operator_mat_mul( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "MatMul" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "MatMul" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + a = node_inputs[0] + b = node_inputs[1] + + b_numpy = ggml.utils.to_numpy(b) + + b_transposed = ggml.ggml_cpy( + context, + ggml.ggml_transpose(context, b), + ggml.ggml_new_tensor( + context, + map_to_ggml_type(b_numpy.dtype).value, + len(b_numpy.shape), + (ctypes.c_int64 * len(b_numpy.shape))(*b_numpy.shape), + ), + ) + + mul_mat_result = ggml.ggml_mul_mat( + context, + b_transposed, + a, + ) + + tensors_dict[output_name] = mul_mat_result + return mul_mat_result @ggml.ggml_custom2_op_t From fb1a2ece0ee884e6a4577608f0bf6f3e0127ac1b Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 16 Aug 2023 10:53:12 -0400 Subject: [PATCH 052/232] Use utils functions for shape and dtype --- ggml/contrib/onnx.py | 119 ++++++++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 40 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 15599d85..c2f8c731 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -37,8 +37,12 @@ def map_to_ggml_type(dtype: np.dtype): return ggml_type +def get_tensor_shape(tensor): + return tuple(reversed(ggml.utils.get_shape(tensor))) + + def set_tensor_out(tensor, ndarray): - output_shape = ggml.utils.to_numpy(tensor).shape + output_shape = get_tensor_shape(tensor) if output_shape == (): ggml.utils.to_numpy(tensor)[()] = ndarray @@ -46,6 +50,17 @@ def set_tensor_out(tensor, ndarray): ggml.utils.to_numpy(tensor)[:] = ndarray +def get_tensor_dtype(tensor): + ggml_type = ggml.utils.GGML_TYPE(tensor.contents.type) + if ggml_type == ggml.utils.GGML_TYPE.F16: + ctypes_type = ctypes.c_uint16 + else: + ctypes_type = np.ctypeslib.as_ctypes_type( + ggml.utils.GGML_TYPE_TO_NUMPY_DTYPE[ggml_type] + ) + return np.dtype(ctypes_type) + + # ------ Operators ------ @@ -107,6 +122,26 @@ def ggml_operator_cast( def ggml_operator_concat( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Concat" requires at least two inputs and an axis. Actual number of inputs: {len(node_inputs)}' + ) + + shapes = [get_tensor_shape(tensor) for tensor in node_inputs] + + axis = next(attr for attr in node.attribute if attr.name == "axis").i + output_shape = np.concatenate([np.empty(shape) for shape in shapes]).shape + + print() + print() + print("axis:", axis) + print("shapes:", shapes) + print("output_shape:", output_shape) + print() + print() + raise NotImplementedError(f'Operator "Concat" not implemented') @@ -119,7 +154,7 @@ def custom_constant( nth: int, userdata: Optional[ctypes.c_void_p], ): - shape = ggml.utils.to_numpy(tensor_in_1).shape + shape = get_tensor_shape(tensor_in_1) constant_data = ggml.utils.to_numpy(tensor_in_2) new_tenor = constant_data.reshape(shape) @@ -185,7 +220,7 @@ def custom_constant_of_shape( nth: int, userdata: Optional[ctypes.c_void_p], ): - shape = ggml.utils.to_numpy(tensor_out).shape + shape = get_tensor_shape(tensor_out) value = ggml.utils.to_numpy(tensor_in_2) new_tenor = np.full(tuple(shape), value) @@ -294,12 +329,13 @@ def ggml_operator_gather( axis_c = ctypes.c_int(axis) - input_array = ggml.utils.to_numpy(node_inputs[0]) - index_array = ggml.utils.to_numpy(node_inputs[1]) + input_ndim = ggml.utils.get_ndims(node_inputs[0]) + input_dtype = get_tensor_dtype(node_inputs[0]) + index_shape = get_tensor_shape(node_inputs[1]) - output_shape = (input_array.ndim - 1) * (1,) + index_array.shape + output_shape = (input_ndim - 1) * (1,) + index_shape - x = np.empty(output_shape, dtype=input_array.dtype) + x = np.empty(output_shape, dtype=input_dtype) x_t = ggml.utils.from_numpy(x, context) @@ -347,12 +383,13 @@ def ggml_operator_greater( f'Error for node "{node.name}": Operation "Greater" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - a = ggml.utils.to_numpy(node_inputs[0]) - b = ggml.utils.to_numpy(node_inputs[1]) + a_shape = get_tensor_shape(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) + b_shape = get_tensor_shape(node_inputs[1]) - output_shape = np.broadcast(np.empty(a.shape), np.empty(b.shape)).shape + output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape - x = np.empty(output_shape, dtype=a.dtype) + x = np.empty(output_shape, dtype=a_dtype) x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( @@ -397,12 +434,13 @@ def ggml_operator_less( f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - a = ggml.utils.to_numpy(node_inputs[0]) - b = ggml.utils.to_numpy(node_inputs[1]) + a_shape = get_tensor_shape(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) + b_shape = get_tensor_shape(node_inputs[1]) - output_shape = np.broadcast(np.empty(a.shape), np.empty(b.shape)).shape + output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape - x = np.empty(output_shape, dtype=a.dtype) + x = np.empty(output_shape, dtype=a_dtype) x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( @@ -454,17 +492,17 @@ def ggml_operator_mat_mul( output_name = node.output[0] a = node_inputs[0] b = node_inputs[1] - - b_numpy = ggml.utils.to_numpy(b) + b_shape = get_tensor_shape(node_inputs[1]) + b_dtype = get_tensor_dtype(node_inputs[1]) b_transposed = ggml.ggml_cpy( context, ggml.ggml_transpose(context, b), ggml.ggml_new_tensor( context, - map_to_ggml_type(b_numpy.dtype).value, - len(b_numpy.shape), - (ctypes.c_int64 * len(b_numpy.shape))(*b_numpy.shape), + map_to_ggml_type(b_dtype).value, + len(b_shape), + (ctypes.c_int64 * len(b_shape))(*b_shape), ), ) @@ -503,10 +541,10 @@ def ggml_operator_max( f'Error for node "{node.name}": Operation "Max" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - a = ggml.utils.to_numpy(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) output_shape = () - ggml_type = map_to_ggml_type(a.dtype) + ggml_type = map_to_ggml_type(a_dtype) x_t = ggml.ggml_new_tensor( context, @@ -552,10 +590,10 @@ def ggml_operator_min( f'Error for node "{node.name}": Operation "Min" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - a = ggml.utils.to_numpy(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) output_shape = () - ggml_type = map_to_ggml_type(a.dtype) + ggml_type = map_to_ggml_type(a_dtype) x_t = ggml.ggml_new_tensor( context, @@ -707,14 +745,15 @@ def ggml_operator_reduce_mean( f'Error for node "{node.name}": Operation "ReduceMean" requires exactly one input. Actual number of inputs: {len(node_inputs)}' ) - tensor = ggml.utils.to_numpy(node_inputs[0]) + tensor_shape = get_tensor_shape(node_inputs[0]) + tensor_dtype = get_tensor_dtype(node_inputs[0]) axes = next(attr for attr in node.attribute if attr.name == "axes").ints keepdims = next(attr for attr in node.attribute if attr.name == "keepdims").i rmean_userdata = RedueMeanUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) - output_shape = list(tensor.shape) + output_shape = list(tensor_shape) for axis in axes: output_shape[axis] = 1 for axis in axes: @@ -723,7 +762,7 @@ def ggml_operator_reduce_mean( output_shape = tuple(output_shape) - x = np.empty(output_shape, dtype=tensor.dtype) + x = np.empty(output_shape, dtype=tensor_dtype) x_t = ggml.utils.from_numpy(x, context) @@ -843,7 +882,8 @@ def ggml_operator_shape( f'Error for node "{node.name}": Operation "Shape" requires at least 1 and maximum of 3 inputs. Actual number of inputs: {len(node_inputs)}' ) - tensor = ggml.utils.to_numpy(node_inputs[0]) + tensor_shape = get_tensor_shape(node_inputs[0]) + tensor_dtype = get_tensor_dtype(node_inputs[0]) start = ( ggml.utils.to_numpy(node_inputs[1]) if len(node_inputs) > 1 @@ -852,18 +892,18 @@ def ggml_operator_shape( end = ( ggml.utils.to_numpy(node_inputs[2]) if len(node_inputs) > 2 - else [ctypes.c_int(tensor.shape[-1])] + else [ctypes.c_int(tensor_shape[-1])] ) start = start[0] if len(start) else ctypes.c_int(0) - end = end[0] if len(end) else ctypes.c_int(tensor.shape[-1]) + end = end[0] if len(end) else ctypes.c_int(tensor_shape[-1]) shape_userdata = ShapeUserData(start, end) userdata_p = ctypes.cast(ctypes.pointer(shape_userdata), ctypes.c_void_p) - output_shape = len(list(tensor.shape)) + output_shape = len(list(tensor_shape)) - x = np.empty(output_shape, dtype=tensor.dtype) + x = np.empty(output_shape, dtype=tensor_dtype) x_t = ggml.utils.from_numpy(x, context) @@ -961,7 +1001,7 @@ def ggml_operator_transpose( ) output_name = node.output[0] - input_shape = ggml.utils.to_numpy(node_inputs[0]).shape + input_shape = get_tensor_shape(node_inputs[0]) perm_map = {1: [0, 1, 2, 3], 2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} perm_attr = next((attr for attr in node.attribute if attr.name == "perm"), None) @@ -1008,17 +1048,16 @@ def ggml_operator_unsqueeze( f'Error for node "{node.name}": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' ) - x_input = ggml.utils.to_numpy(node_inputs[0]) + x_shape = get_tensor_shape(node_inputs[0]) + x_dtype = get_tensor_dtype(node_inputs[0]) axes = ggml.utils.to_numpy(node_inputs[1]) - output_shape = x_input.shape - for axis in np.nditer(axes): - output_shape = np.insert(output_shape, axis, 1) + x_shape = np.insert(x_shape, axis, 1) - output_shape = output_shape.astype(np.int32) + x_shape = x_shape.astype(np.int32) - x = np.empty(output_shape, dtype=x_input.dtype) + x = np.empty(x_shape, dtype=x_dtype) x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( @@ -1052,7 +1091,7 @@ def __del__(self): def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: """Abstract function.""" - # check where data is should be on CPU + # check: data is should be on CPU model_graph = self.graph exit_node = None From 20bbc6470278b54f2a291910c8ed2e4dd036fa30 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 16 Aug 2023 16:26:04 -0400 Subject: [PATCH 053/232] Add Concat operator and tests --- ggml/contrib/onnx.py | 53 +++++++++++++++++++++----------- tests/test_ggml_onnx_ops.py | 61 +++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 18 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index c2f8c731..b5634df6 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -111,37 +111,54 @@ def ggml_operator_add( return add_result -@ggml_operator("Cast") -def ggml_operator_cast( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +@ggml.ggml_custom1_op_t +def custom_cast( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], ): - raise NotImplementedError(f'Operator "Cast" not implemented') + dtype = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + tensor = ggml.utils.to_numpy(tensor_in_1) + np_data_type = tensor_dtype_to_np_dtype(dtype) + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + set_tensor_out(tensor_out, tensor.astype(np_data_type_limit)) -@ggml_operator("Concat") -def ggml_operator_concat( + +@ggml_operator("Cast") +def ggml_operator_cast( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): + # using custom operator node_inputs = [tensors_dict[inp] for inp in node.input] - if len(node_inputs) < 2: + if len(node_inputs) != 1: raise ValueError( - f'Error for node "{node.name}": Operation "Concat" requires at least two inputs and an axis. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Cast" requires exactly one input and a dtype. Actual number of inputs: {len(node_inputs)}' ) - shapes = [get_tensor_shape(tensor) for tensor in node_inputs] + onnx_type = next(attr for attr in node.attribute if attr.name == "to").i + onnx_type_c = ctypes.c_int(onnx_type) - axis = next(attr for attr in node.attribute if attr.name == "axis").i - output_shape = np.concatenate([np.empty(shape) for shape in shapes]).shape + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + node_inputs[0], + custom_cast, + 1, + ctypes.pointer(onnx_type_c), + ) - print() - print() - print("axis:", axis) - print("shapes:", shapes) - print("output_shape:", output_shape) - print() - print() + refs.append(onnx_type_c) + return new_tensor + + +@ggml_operator("Concat") +def ggml_operator_concat( + node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] +): raise NotImplementedError(f'Operator "Concat" not implemented') diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 88d75b9b..606a29ae 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -1399,6 +1399,67 @@ def onnx_range(start, limit, delta): ggml.ggml_free(context) +def test_ggml_onnx_cast_operator(): + # return + + def onnx_cast(input_data, to_dtype): + class CastModel(torch.nn.Module): + def forward(self, input): + return input.to(dtype=to_dtype) + + model = CastModel() + + x_tensor = torch.tensor(input_data, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + (x_tensor,), + f, + input_names=["input"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + input_feed = {"input": input_data} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + input_data_array = np.array([1.2, 2.5, 3.7], np.float32) + + cast_numpy = onnx_cast(input_data_array, torch.int32) + + tensors_dict["input_data_array"] = ggml.utils.from_numpy(input_data_array, context) + + cast_node = onnx.helper.make_node( + "Cast", + inputs=["input_data_array"], + outputs=["cast_output"], + to=onnx.TensorProto.INT32, + ) + + output_tensor = ggml_operators["Cast"](cast_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + result = ggml.utils.to_numpy(output_tensor) + + assert np.allclose(result, cast_numpy) + + ggml.ggml_free(context) + + def test_ggml_onnx_runtime_basic(): # return From 7f08f6774ed58fb63ce5e56c3581a64c22b6c23a Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 16 Aug 2023 17:09:37 -0400 Subject: [PATCH 054/232] Add Where operator --- ggml/contrib/onnx.py | 38 ++++++++++++++++++-- tests/test_ggml_onnx_ops.py | 72 +++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index b5634df6..152ff909 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1051,7 +1051,7 @@ def custom_unsqueeze( for axis in np.nditer(axes): x = np.expand_dims(x, axis=axis) - ggml.utils.to_numpy(tensor_out)[:] = x + set_tensor_out(tensor_out, x) @ggml_operator("Unsqueeze") @@ -1090,11 +1090,45 @@ def ggml_operator_unsqueeze( return new_tensor +@ggml.ggml_custom3_op_t +def custom_where( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_1) + y = ggml.utils.to_numpy(tensor_in_2) + condition_array = ggml.utils.to_numpy(tensor_in_3) + new_tensor = np.where(condition_array, x, y) + set_tensor_out(tensor_out, new_tensor) + + @ggml_operator("Where") def ggml_operator_where( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Where" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 3: + raise ValueError( + f'Error for node "{node.name}": Operation "Where" requires exactly three inputs. Actual number of inputs: {len(node_inputs)}' + ) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + context, + node_inputs[1], + node_inputs[2], + node_inputs[0], + custom_where, + 1, + None, + ) + + return new_tensor class GgmlBackendRep(BackendRep): diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 606a29ae..281307b3 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -1460,6 +1460,78 @@ def forward(self, input): ggml.ggml_free(context) +def test_ggml_onnx_where_operator(): + # return + + def onnx_where(condition_data, x_data, y_data): + class WhereModel(torch.nn.Module): + def forward(self, condition, x, y): + return torch.where(condition, x, y) + + model = WhereModel() + + condition_tensor = torch.tensor(condition_data, dtype=torch.bool) + x_tensor = torch.tensor(x_data, dtype=torch.float32) + y_tensor = torch.tensor(y_data, dtype=torch.float32) + + f = BytesIO() + torch.onnx.export( + model, + (condition_tensor, x_tensor, y_tensor), + f, + input_names=["condition", "x", "y"], + output_names=["output"], + verbose=False, + ) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + input_feed = { + "condition": condition_data, + "x": x_data, + "y": y_data, + } + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + condition_data_array = np.array([True, False, True], dtype=bool) + x_data_array = np.array([1.2, 2.5, 3.7], np.float32) + y_data_array = np.array([0.5, 1.0, 2.0], np.float32) + + where_numpy = onnx_where(condition_data_array, x_data_array, y_data_array) + + tensors_dict["condition_data_array"] = ggml.utils.from_numpy( + condition_data_array, context + ) + tensors_dict["x_data_array"] = ggml.utils.from_numpy(x_data_array, context) + tensors_dict["y_data_array"] = ggml.utils.from_numpy(y_data_array, context) + + where_node = onnx.helper.make_node( + "Where", + inputs=["condition_data_array", "x_data_array", "y_data_array"], + outputs=["where_output"], + ) + + output_tensor = ggml_operators["Where"](where_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + result = ggml.utils.to_numpy(output_tensor) + + assert np.array_equal(result, where_numpy) + + ggml.ggml_free(context) + + def test_ggml_onnx_runtime_basic(): # return From c58ce0df1d0fdc44dcdf8afbe10ab4c5e86fe828 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 17 Aug 2023 09:22:09 -0400 Subject: [PATCH 055/232] Add Pow operator --- ggml/contrib/onnx.py | 38 ++++++++++++++++++- tests/test_ggml_onnx_ops.py | 73 +++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 152ff909..daa89a1b 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -656,11 +656,47 @@ def ggml_operator_mul( return mul_result +@ggml.ggml_custom2_op_t +def custom_pow( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x1 = ggml.utils.to_numpy(tensor_in_1) + x2 = ggml.utils.to_numpy(tensor_in_2) + + new_tensor = np.power(x1, x2) + + set_tensor_out(tensor_out, new_tensor) + + @ggml_operator("Pow") def ggml_operator_pow( node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] ): - raise NotImplementedError(f'Operator "Pow" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Pow" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + x1 = node_inputs[0] + x2 = node_inputs[1] + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x1, + x2, + custom_pow, + 1, + None, + ) + + return new_tensor @ggml.ggml_custom2_op_t diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 281307b3..ed3ff339 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -1399,6 +1399,79 @@ def onnx_range(start, limit, delta): ggml.ggml_free(context) +def test_ggml_onnx_pow_operator(): + # return + + def onnx_pow(input, exponent): + pow_node = onnx.helper.make_node( + "Pow", + inputs=["input", "exponent"], + outputs=["output"], + ) + + graph = onnx.helper.make_graph( + [pow_node], + "pow_graph", + inputs=[ + onnx.helper.make_tensor_value_info( + "input", onnx.TensorProto.FLOAT, list(input.shape) + ), + onnx.helper.make_tensor_value_info( + "exponent", onnx.TensorProto.FLOAT, list(exponent.shape) + ), + ], + outputs=[ + onnx.helper.make_tensor_value_info( + "output", onnx.TensorProto.FLOAT, list(input.shape) + ), + ], + ) + + model = onnx.helper.make_model(graph) + + f = BytesIO() + onnx.save_model(model, f) + + onnx_model_bytes = BytesIO(f.getvalue()) + + onnx_model_bytes.seek(0) + sess = ort.InferenceSession(onnx_model_bytes.read()) + + input_feed = {"input": input, "exponent": exponent} + + output = sess.run(None, input_feed) + + return output[0] + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + context = ggml.ggml_init(params=params) + tensors_dict = {} + refs = [] + + input_array = np.array([2, 3, 4], np.float32) + exponent_array = np.array([3, 2, 1], np.float32) + + pow_numpy = onnx_pow(input_array, exponent_array) + + tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) + tensors_dict["exponent_array"] = ggml.utils.from_numpy(exponent_array, context) + + pow_node = onnx.helper.make_node( + "Pow", + inputs=["input_array", "exponent_array"], + outputs=["pow_output"], + ) + + output_tensor = ggml_operators["Pow"](pow_node, tensors_dict, context, refs) + gf = ggml.ggml_build_forward(output_tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + result = ggml.utils.to_numpy(output_tensor) + + assert np.allclose(result, pow_numpy) + + ggml.ggml_free(context) + + def test_ggml_onnx_cast_operator(): # return From 8794750077af44a236d29df57f62c1f85ee79621 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 17 Aug 2023 10:20:20 -0400 Subject: [PATCH 056/232] Use set_tensor_out --- ggml/contrib/onnx.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index daa89a1b..c1680644 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1,17 +1,15 @@ import ctypes -from typing import Any, Tuple, List +from typing import Any, List, Optional, Tuple import numpy as np import onnx from onnx import defs from onnx.backend.base import Backend, BackendRep -from onnx.helper import make_opsetid +from onnx.helper import make_opsetid, tensor_dtype_to_np_dtype from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto -from onnx.helper import tensor_dtype_to_np_dtype import ggml import ggml.utils -from typing import Optional ggml_operators = {} onnx_dtype_map = { @@ -328,7 +326,7 @@ def custom_gather( new_array = np.take(input_array, index_array, axis=axis) - ggml.utils.to_numpy(tensor_out)[:] = new_array + set_tensor_out(tensor_out, new_array) @ggml_operator("Gather") @@ -921,7 +919,7 @@ def custom_shape( shaped_tensor = tensor[start:end] tensor_shape = np.array(shaped_tensor.shape, dtype=np.int32) - ggml.utils.to_numpy(tensor_out)[:] = tensor_shape + set_tensor_out(tensor_out, tensor_shape) @ggml_operator("Shape") @@ -1248,7 +1246,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Set user inputs for key, value in inputs.items(): - ggml.utils.to_numpy(ggml_tensors[key])[:] = value + set_tensor_out(ggml_tensors[key], value) # Compute graph ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -1341,7 +1339,7 @@ def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): tensor.contents.data = ctypes.cast( ctypes.addressof(buffer) + offset, ctypes.c_void_p ) - ggml.utils.to_numpy(tensor)[:] = onnx.numpy_helper.to_array(initializer) + set_tensor_out(tensor, onnx.numpy_helper.to_array(initializer)) offset += nbytes ggml_backend_rep.ggml_buffer = buffer From 3f9198bd71feff733324db3c192a11c2d1c13454 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 17 Aug 2023 10:20:50 -0400 Subject: [PATCH 057/232] Cleanup warnings and stdout logs --- tests/test_ggml_onnx_ops.py | 234 ++++++++++++++++++------------------ 1 file changed, 115 insertions(+), 119 deletions(-) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index ed3ff339..205b9011 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -1,5 +1,7 @@ import ctypes import io +import os +import sys from io import BytesIO import numpy as np @@ -11,6 +13,7 @@ from onnx import TensorProto, helper, numpy_helper from onnxruntime import InferenceSession +import contextlib import ggml import ggml.utils from ggml.contrib.onnx import GgmlRuntimeBackend, ggml_operators @@ -31,19 +34,14 @@ def test_ggml_onnx_runtime_shape_operator(): tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_data1, context) tensors_dict["start1"] = ggml.utils.from_numpy( - np.array([], dtype=np.int32), context + np.array([0], dtype=np.int32), context ) - tensors_dict["end1"] = ggml.utils.from_numpy(np.array([], dtype=np.int32), context) + tensors_dict["end1"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) tensors_dict["start2"] = ggml.utils.from_numpy( - np.array([], dtype=np.int32), context - ) - tensors_dict["end2"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) - - tensors_dict["start3"] = ggml.utils.from_numpy( np.array([2], dtype=np.int32), context ) - tensors_dict["end3"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) + tensors_dict["end2"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) shape_node1 = onnx.helper.make_node( "Shape", @@ -66,14 +64,7 @@ def test_ggml_onnx_runtime_shape_operator(): outputs=["output_tensor3"], ) - shape_node4 = onnx.helper.make_node( - "Shape", - name="Shape4", - inputs=["input_tensor", "start3", "end3"], - outputs=["output_tensor4"], - ) - - nodes = [shape_node1, shape_node2, shape_node3, shape_node4] + nodes = [shape_node1, shape_node2, shape_node3] results = [] refs = [] @@ -84,9 +75,8 @@ def test_ggml_onnx_runtime_shape_operator(): results.append(ggml.utils.to_numpy(output_tensor)) assert results[0] == list(input_data1.shape) - assert results[1] == list(input_data1.shape) - assert results[2] == list(input_data1[:6].shape) - assert results[3] == list(input_data1[2:6].shape) + assert results[1] == list(input_data1[:6].shape) + assert results[2] == list(input_data1[2:6].shape) ggml.ggml_free(context) @@ -106,15 +96,15 @@ def forward(self, input): x_tensor = torch.tensor(x, dtype=torch.int32) f = BytesIO() - torch.onnx.export( - model, - x_tensor, - f, - input_names=["data"], - output_names=["output"], - verbose=False, - ) - + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, + x_tensor, + f, + input_names=["data"], + output_names=["output"], + verbose=False, + ) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) @@ -206,6 +196,8 @@ def onnx_gather(x, indices, axis): node_def = onnx.helper.make_node( "Gather", inputs=["data", "indices"], outputs=["output"], axis=axis ) + output_shape = list(x.shape) # Initial assumption, adjust if needed + output_shape[axis] = indices.shape[0] # Update the size along the gather axis graph_def = onnx.helper.make_graph( [node_def], "gather_model", @@ -219,7 +211,7 @@ def onnx_gather(x, indices, axis): ], outputs=[ onnx.helper.make_tensor_value_info( - "output", onnx.TensorProto.INT32, list(x.shape) + "output", onnx.TensorProto.INT32, output_shape ) ], ) @@ -387,8 +379,7 @@ def onnx_constant(value, dtype, shape): def test_ggml_onnx_constant_of_shape_operator(): # return - def onnx_constant(value, other): - shape = list(other.shape) + def onnx_constant_of_shape(value, other): value = numpy_helper.from_array(value) constant_node = onnx.helper.make_node( "ConstantOfShape", inputs=["data"], outputs=["constant_output"], value=value @@ -398,12 +389,14 @@ def onnx_constant(value, other): "constant_graph", inputs=[ onnx.helper.make_tensor_value_info( - "data", onnx.TensorProto.INT64, shape + "data", onnx.TensorProto.INT64, list(other.shape) ) ], outputs=[ onnx.helper.make_tensor_value_info( - "constant_output", onnx.TensorProto.FLOAT, shape + "constant_output", + onnx.TensorProto.FLOAT, + other.astype(np.int32).tolist(), ) ], ) @@ -439,7 +432,7 @@ def onnx_constant(value, other): tensors_dict["shape1"] = ggml.utils.from_numpy(shape1, context) - constant_onnx = onnx_constant(value_tensor, shape1) + constant_onnx = onnx_constant_of_shape(value_tensor, shape1) nodes = [cof_node1] results = [] @@ -597,11 +590,11 @@ def forward(self, x): input_tensor = torch.tensor(input_tensor, dtype=torch.int32) f = BytesIO() - torch.onnx.export( - model, input_tensor, f, opset_version=12, do_constant_folding=True - ) + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, input_tensor, f, opset_version=12, do_constant_folding=True + ) f.seek(0) - sess = ort.InferenceSession(f.getvalue()) input_name = sess.get_inputs()[0].name output_name = sess.get_outputs()[0].name @@ -696,14 +689,15 @@ def forward(self, input): x_tensor = torch.tensor(x, dtype=torch.float32) f = BytesIO() - torch.onnx.export( - model, - x_tensor, - f, - input_names=["data"], - output_names=["output"], - verbose=False, - ) + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, + x_tensor, + f, + input_names=["data"], + output_names=["output"], + verbose=False, + ) onnx_model_bytes = BytesIO(f.getvalue()) @@ -783,15 +777,15 @@ def forward(self, input1, input2): y_tensor = torch.tensor(y, dtype=torch.float32) f = BytesIO() - torch.onnx.export( - model, - (x_tensor, y_tensor), - f, - input_names=["input1", "input2"], - output_names=["output"], - verbose=False, - ) - + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, + (x_tensor, y_tensor), + f, + input_names=["input1", "input2"], + output_names=["output"], + verbose=False, + ) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) @@ -852,15 +846,15 @@ def forward(self, input1, input2): y_tensor = torch.tensor(y, dtype=torch.float32) f = BytesIO() - torch.onnx.export( - model, - (x_tensor, y_tensor), - f, - input_names=["input1", "input2"], - output_names=["output"], - verbose=False, - ) - + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, + (x_tensor, y_tensor), + f, + input_names=["input1", "input2"], + output_names=["output"], + verbose=False, + ) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) @@ -916,15 +910,15 @@ def forward(self, input1): x_tensor = torch.tensor(x, dtype=torch.float32) f = BytesIO() - torch.onnx.export( - model, - (x_tensor), - f, - input_names=["input1"], - output_names=["output"], - verbose=False, - ) - + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, + (x_tensor), + f, + input_names=["input1"], + output_names=["output"], + verbose=False, + ) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) @@ -977,15 +971,15 @@ def forward(self, input1): x_tensor = torch.tensor(x, dtype=torch.float32) f = BytesIO() - torch.onnx.export( - model, - (x_tensor), - f, - input_names=["input1"], - output_names=["output"], - verbose=False, - ) - + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, + (x_tensor), + f, + input_names=["input1"], + output_names=["output"], + verbose=False, + ) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) @@ -1110,15 +1104,15 @@ def forward(self, input1, input2): y_tensor = torch.tensor(y, dtype=torch.float32) f = BytesIO() - torch.onnx.export( - model, - (x_tensor, y_tensor), - f, - input_names=["input1", "input2"], - output_names=["output"], - verbose=False, - ) - + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, + (x_tensor, y_tensor), + f, + input_names=["input1", "input2"], + output_names=["output"], + verbose=False, + ) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) @@ -1178,15 +1172,15 @@ def forward(self, input): x_tensor = torch.tensor(x, dtype=torch.float32) f = BytesIO() - torch.onnx.export( - model, - (x_tensor,), - f, - input_names=["input"], - output_names=["output"], - verbose=False, - ) - + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, + (x_tensor,), + f, + input_names=["input"], + output_names=["output"], + verbose=False, + ) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) @@ -1347,7 +1341,9 @@ def onnx_range(start, limit, delta): ], outputs=[ onnx.helper.make_tensor_value_info( - "output", onnx.TensorProto.FLOAT, list(start.shape) + "output", + onnx.TensorProto.FLOAT, + (int(np.ceil((limit - start) / delta)),), ), ], ) @@ -1485,15 +1481,15 @@ def forward(self, input): x_tensor = torch.tensor(input_data, dtype=torch.float32) f = BytesIO() - torch.onnx.export( - model, - (x_tensor,), - f, - input_names=["input"], - output_names=["output"], - verbose=False, - ) - + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, + (x_tensor,), + f, + input_names=["input"], + output_names=["output"], + verbose=False, + ) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) @@ -1548,15 +1544,15 @@ def forward(self, condition, x, y): y_tensor = torch.tensor(y_data, dtype=torch.float32) f = BytesIO() - torch.onnx.export( - model, - (condition_tensor, x_tensor, y_tensor), - f, - input_names=["condition", "x", "y"], - output_names=["output"], - verbose=False, - ) - + with contextlib.redirect_stdout(None): + torch.onnx.export( + model, + (condition_tensor, x_tensor, y_tensor), + f, + input_names=["condition", "x", "y"], + output_names=["output"], + verbose=False, + ) onnx_model_bytes = BytesIO(f.getvalue()) onnx_model_bytes.seek(0) From caaa2fd2ed0f9180e1d21d024464fd3cca404058 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 17 Aug 2023 10:43:09 -0400 Subject: [PATCH 058/232] Remove duplicate Pow test --- tests/test_ggml_onnx_ops.py | 77 +------------------------------------ 1 file changed, 2 insertions(+), 75 deletions(-) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 205b9011..549cfc65 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -1091,7 +1091,7 @@ def onnx_matmul(x, y): def test_ggml_onnx_pow_operator(): - return + # return def onnx_pow(x, y): class PowModel(torch.nn.Module): @@ -1154,7 +1154,7 @@ def forward(self, input1, input2): ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) results.append(ggml.utils.to_numpy(output_tensor)) - assert np.allclose(results[0], pow_numpy) + assert np.array_equal(results[0], pow_numpy) ggml.ggml_free(context) @@ -1395,79 +1395,6 @@ def onnx_range(start, limit, delta): ggml.ggml_free(context) -def test_ggml_onnx_pow_operator(): - # return - - def onnx_pow(input, exponent): - pow_node = onnx.helper.make_node( - "Pow", - inputs=["input", "exponent"], - outputs=["output"], - ) - - graph = onnx.helper.make_graph( - [pow_node], - "pow_graph", - inputs=[ - onnx.helper.make_tensor_value_info( - "input", onnx.TensorProto.FLOAT, list(input.shape) - ), - onnx.helper.make_tensor_value_info( - "exponent", onnx.TensorProto.FLOAT, list(exponent.shape) - ), - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "output", onnx.TensorProto.FLOAT, list(input.shape) - ), - ], - ) - - model = onnx.helper.make_model(graph) - - f = BytesIO() - onnx.save_model(model, f) - - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = {"input": input, "exponent": exponent} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array = np.array([2, 3, 4], np.float32) - exponent_array = np.array([3, 2, 1], np.float32) - - pow_numpy = onnx_pow(input_array, exponent_array) - - tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) - tensors_dict["exponent_array"] = ggml.utils.from_numpy(exponent_array, context) - - pow_node = onnx.helper.make_node( - "Pow", - inputs=["input_array", "exponent_array"], - outputs=["pow_output"], - ) - - output_tensor = ggml_operators["Pow"](pow_node, tensors_dict, context, refs) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, pow_numpy) - - ggml.ggml_free(context) - - def test_ggml_onnx_cast_operator(): # return From 842530df7fde7c4be860217ec0ac5b80537d06b8 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 17 Aug 2023 10:59:48 -0400 Subject: [PATCH 059/232] Add support for np.bool_ --- ggml/utils.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ggml/utils.py b/ggml/utils.py index 771b8f09..e28fa068 100644 --- a/ggml/utils.py +++ b/ggml/utils.py @@ -74,6 +74,9 @@ def from_numpy(x: npt.NDArray[Any], ctx: ggml.ggml_context_p) -> ggml.ggml_tenso Returns: New ggml tensor with data copied from x """ + if x.dtype.type == np.bool_: + x = x.astype(np.int32) + ggml_type = NUMPY_DTYPE_TO_GGML_TYPE[x.dtype.type] shape = tuple(reversed(x.shape)) tensor = ggml.ggml_new_tensor( @@ -264,12 +267,12 @@ def slice_tensor( """Slice a ggml tensor along multiple dimensions. The slice is a view of the original tensor with the same number of dimensions. - + Parameters: ctx: ggml context tensor: ggml tensor indices: indices to slice along - + Returns: New ggml tensor slice view""" ndims = get_ndims(tensor) From 2812df191a43a344ef417aecb3e2d7ab1efcdd5d Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 18 Aug 2023 17:14:18 -0400 Subject: [PATCH 060/232] Add eval_tensor, can_quantize, broadcasting rules --- ggml/contrib/onnx.py | 459 ++++++++++++++++++++++++++++++------ tests/test_ggml_onnx_ops.py | 115 +++++---- 2 files changed, 455 insertions(+), 119 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index c1680644..503201de 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -59,12 +59,107 @@ def get_tensor_dtype(tensor): return np.dtype(ctypes_type) +def can_quantize( + np_array: np.ndarray, + name: str, + graph_def: GraphProto, +): + return False + + allowed_op_types = set(["MatMul"]) + + is_weight = is_2d = is_f32 = is_op_supported = False + + is_weight = name in [initializer.name for initializer in graph_def.initializer] + is_2d = np_array.ndim == 2 + is_f32 = np_array.dtype == np.float32 + is_op_supported = any( + [ + node + for node in graph_def.node + if node.op_type in allowed_op_types + and name in node.input + and node.input[0] == name + ] + ) + + return all([is_weight, is_2d, is_f32, is_op_supported]) + + +def broadcast_tensor( + ctx: ggml.ggml_context_p, tensor: ggml.ggml_tensor_p, shape: Tuple +): + ggml_type = ggml.utils.GGML_TYPE(tensor.contents.type) + + new_tensor = ggml.ggml_new_tensor( + ctx, + ggml_type.value, + len(shape), + (ctypes.c_int64 * len(shape))(*shape), + ) + + # new_tensor = ggml.ggml_repeat( + # ctx, + # tensor, + # new_tensor, + # ) + + if ggml.utils.get_shape(tensor) == (): + ggml.utils.to_numpy(new_tensor)[()] = ggml.utils.to_numpy(tensor) + else: + ggml.utils.to_numpy(new_tensor)[:] = ggml.utils.to_numpy(tensor) + + return new_tensor + + +def broadcast_shapes( + ctx: ggml.ggml_context_p, a: ggml.ggml_tensor_p, b: ggml.ggml_tensor_p +): + a_shape = get_tensor_shape(a) + b_shape = get_tensor_shape(b) + + output_shape = tuple( + reversed(np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape) + ) + + a_shaped = a + b_shaped = b + + if a_shape != output_shape: + a_shaped = broadcast_tensor(ctx, a, output_shape) + if b_shape != output_shape: + b_shaped = broadcast_tensor(ctx, b, output_shape) + + return a_shaped, b_shaped + + +@ggml.ggml_custom2_op_t +def custom_broadcast( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + context = userdata + tensor_out = ggml.ggml_repeat( + context, + tensor_in_1, + tensor_in_2, + ) + + # ------ Operators ------ @ggml_operator("Abs") def ggml_operator_abs( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -86,7 +181,11 @@ def ggml_operator_abs( @ggml_operator("Add") def ggml_operator_add( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -127,9 +226,12 @@ def custom_cast( @ggml_operator("Cast") def ggml_operator_cast( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): - # using custom operator node_inputs = [tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: @@ -137,7 +239,7 @@ def ggml_operator_cast( f'Error for node "{node.name}": Operation "Cast" requires exactly one input and a dtype. Actual number of inputs: {len(node_inputs)}' ) - onnx_type = next(attr for attr in node.attribute if attr.name == "to").i + onnx_type = next(attr.i for attr in node.attribute if attr.name == "to") onnx_type_c = ctypes.c_int(onnx_type) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( @@ -155,9 +257,61 @@ def ggml_operator_cast( @ggml_operator("Concat") def ggml_operator_concat( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): - raise NotImplementedError(f'Operator "Concat" not implemented') + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Concat" requires at least two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 0) + shapes = [get_tensor_shape(tensor) for tensor in node_inputs] + + if not all( + shape[:axis] == shapes[0][:axis] and shape[axis + 1 :] == shapes[0][axis + 1 :] + for shape in shapes + ): + raise ValueError( + "All tensors must have the same shape along the specified axis." + ) + + total_dim = sum(shape[axis] for shape in shapes) + output_shape = list(shapes[0]) + output_shape[axis] = total_dim + + x = np.empty(output_shape, dtype=get_tensor_dtype(node_inputs[0])) + x_t = ggml.utils.from_numpy(x, context) + + @ggml.ggml_custom1_op_t + def custom_concat( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + x = np.concatenate(tensors, axis=axis) + + set_tensor_out(tensor_out, x) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x_t, + custom_concat, + 1, + None, + ) + + refs.append(custom_concat) + + return new_tensor @ggml.ggml_custom2_op_t @@ -178,7 +332,11 @@ def custom_constant( @ggml_operator("Constant") def ggml_operator_constant( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_attributes = node.attribute @@ -187,6 +345,8 @@ def ggml_operator_constant( data_type = tensor.data_type np_data_type = tensor_dtype_to_np_dtype(data_type) + # print(node_attributes) + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) @@ -244,7 +404,11 @@ def custom_constant_of_shape( @ggml_operator("ConstantOfShape") def ggml_operator_constant_of_shape( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -288,7 +452,11 @@ def ggml_operator_constant_of_shape( @ggml_operator("Div") def ggml_operator_div( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -301,6 +469,8 @@ def ggml_operator_div( a = node_inputs[0] b = node_inputs[1] + a, b = broadcast_shapes(context, a, b) + div_result = ggml.ggml_div( context, a, @@ -331,7 +501,11 @@ def custom_gather( @ggml_operator("Gather") def ggml_operator_gather( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -340,18 +514,19 @@ def ggml_operator_gather( f'Error for node "{node.name}": Operation "Gather" requires exactly two inputs and one axis. Actual number of inputs: {len(node_inputs)}' ) - axis = node.attribute[0].i if len(node.attribute) > 0 else -1 - + axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 0) axis_c = ctypes.c_int(axis) - input_ndim = ggml.utils.get_ndims(node_inputs[0]) + input_shape = get_tensor_shape(node_inputs[0]) input_dtype = get_tensor_dtype(node_inputs[0]) index_shape = get_tensor_shape(node_inputs[1]) - output_shape = (input_ndim - 1) * (1,) + index_shape + Ni = input_shape[:axis] + Nk = input_shape[axis + 1 :] + Nj = index_shape + output_shape = tuple(list(Ni) + list(Nj) + list(Nk)) x = np.empty(output_shape, dtype=input_dtype) - x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( @@ -389,7 +564,11 @@ def custom_greater( @ggml_operator("Greater") def ggml_operator_greater( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -440,7 +619,11 @@ def custom_less( @ggml_operator("Less") def ggml_operator_less( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -473,7 +656,11 @@ def ggml_operator_less( @ggml_operator("Log") def ggml_operator_log( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -495,7 +682,11 @@ def ggml_operator_log( @ggml_operator("MatMul") def ggml_operator_mat_mul( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -507,9 +698,11 @@ def ggml_operator_mat_mul( output_name = node.output[0] a = node_inputs[0] b = node_inputs[1] - b_shape = get_tensor_shape(node_inputs[1]) - b_dtype = get_tensor_dtype(node_inputs[1]) + a, b = broadcast_shapes(context, a, b) + + b_shape = get_tensor_shape(b) + b_dtype = get_tensor_dtype(b) b_transposed = ggml.ggml_cpy( context, ggml.ggml_transpose(context, b), @@ -547,7 +740,11 @@ def custom_max( @ggml_operator("Max") def ggml_operator_max( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -596,7 +793,11 @@ def custom_min( @ggml_operator("Min") def ggml_operator_min( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -631,7 +832,11 @@ def ggml_operator_min( @ggml_operator("Mul") def ggml_operator_mul( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -644,6 +849,8 @@ def ggml_operator_mul( a = node_inputs[0] b = node_inputs[1] + a, b = broadcast_shapes(context, a, b) + mul_result = ggml.ggml_mul( context, a, @@ -673,7 +880,11 @@ def custom_pow( @ggml_operator("Pow") def ggml_operator_pow( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -716,7 +927,11 @@ def custom_range( @ggml_operator("Range") def ggml_operator_range( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -787,7 +1002,11 @@ def custom_reduce_mean( @ggml_operator("ReduceMean") def ggml_operator_reduce_mean( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -798,8 +1017,8 @@ def ggml_operator_reduce_mean( tensor_shape = get_tensor_shape(node_inputs[0]) tensor_dtype = get_tensor_dtype(node_inputs[0]) - axes = next(attr for attr in node.attribute if attr.name == "axes").ints - keepdims = next(attr for attr in node.attribute if attr.name == "keepdims").i + axes = next(attr.ints for attr in node.attribute if attr.name == "axes") + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) rmean_userdata = RedueMeanUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) @@ -833,7 +1052,11 @@ def ggml_operator_reduce_mean( @ggml_operator("Relu") def ggml_operator_relu( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -855,7 +1078,11 @@ def ggml_operator_relu( @ggml_operator("Reshape") def ggml_operator_reshape( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -864,36 +1091,41 @@ def ggml_operator_reshape( f'Error for node "{node.name}": Operation "Reshape" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - output_name = node.output[0] a = node_inputs[0] b = node_inputs[1] + eval_b = backend.eval_tensor(b, context) - b_numpy_reverse: list = ggml.utils.to_numpy(b).tolist() - b_numpy_reverse.reverse() - - dims = len(b_numpy_reverse) + new_shape = ggml.utils.to_numpy(eval_b).astype(dtype=np.int32) - if dims > 4: - raise NotImplementedError( - f'Operator "Reshape" not implemented for over 4D arrays.' - ) + temp_a = np.empty(get_tensor_shape(a), dtype=get_tensor_dtype(a)) + x = temp_a.reshape(new_shape) + x_t = ggml.utils.from_numpy(x, context) - b_numpy_reverse += [0, 0, 0][:dims] + @ggml.ggml_custom2_op_t + def custom_reshape( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_2) + x_reshape = np.reshape(x, new_shape) + set_tensor_out(tensor_out, x_reshape) - ne0, ne1, ne2, ne3 = b_numpy_reverse + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + a, + custom_reshape, + 1, + None, + ) - dim_map = { - 1: (ggml.ggml_reshape_1d, (context, a, ne0)), - 2: (ggml.ggml_reshape_2d, (context, a, ne0, ne1)), - 3: (ggml.ggml_reshape_3d, (context, a, ne0, ne1, ne2)), - 4: (ggml.ggml_reshape_4d, (context, a, ne0, ne1, ne2, ne3)), - } + refs.append(custom_reshape) - func = dim_map[dims][0] - args = dim_map[dims][1] - reshape_result = func(*args) - tensors_dict[output_name] = reshape_result - return reshape_result + return new_tensor class ShapeUserData(ctypes.Structure): @@ -924,7 +1156,11 @@ def custom_shape( @ggml_operator("Shape") def ggml_operator_shape( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -974,7 +1210,11 @@ def ggml_operator_shape( @ggml_operator("Softmax") def ggml_operator_softmax( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -996,7 +1236,11 @@ def ggml_operator_softmax( @ggml_operator("Sqrt") def ggml_operator_sqrt( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -1018,7 +1262,11 @@ def ggml_operator_sqrt( @ggml_operator("Sub") def ggml_operator_sub( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -1031,6 +1279,8 @@ def ggml_operator_sub( a = node_inputs[0] b = node_inputs[1] + a, b = broadcast_shapes(context, a, b) + sub_result = ggml.ggml_sub( context, a, @@ -1042,7 +1292,11 @@ def ggml_operator_sub( @ggml_operator("Transpose") def ggml_operator_transpose( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -1052,11 +1306,15 @@ def ggml_operator_transpose( ) output_name = node.output[0] - input_shape = get_tensor_shape(node_inputs[0]) - perm_map = {1: [0, 1, 2, 3], 2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} + x = node_inputs[0] + input_shape = get_tensor_shape(x) + + perm_map = {2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} perm_attr = next((attr for attr in node.attribute if attr.name == "perm"), None) + # add special case and -> fix me comments + if perm_attr is None: perm = perm_map.get(len(input_shape), [1, 0, 2, 3]) else: @@ -1064,7 +1322,9 @@ def ggml_operator_transpose( perm += [0, 1, 2, 3][len(perm) :] ax0, ax1, ax2, ax3 = perm - transpose_result = ggml.ggml_permute(context, node_inputs[0], ax0, ax1, ax2, ax3) + + transpose_result = ggml.ggml_permute(context, x, ax0, ax1, ax2, ax3) + tensors_dict[output_name] = transpose_result return transpose_result @@ -1090,7 +1350,11 @@ def custom_unsqueeze( @ggml_operator("Unsqueeze") def ggml_operator_unsqueeze( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -1143,7 +1407,11 @@ def custom_where( @ggml_operator("Where") def ggml_operator_where( - node: NodeProto, tensors_dict: dict, context: ggml.ggml_context_p, refs: List[Any] + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: dict, + context: ggml.ggml_context_p, + refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] @@ -1173,6 +1441,12 @@ def __del__(self): if hasattr(self, "ggml_context"): ggml.ggml_free(self.ggml_context) + def eval_tensor(self, tensor: ggml.ggml_tensor_p, context: ggml.ggml_context_p): + gf = ggml.ggml_build_forward(tensor) + ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + + return tensor + def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: """Abstract function.""" @@ -1229,25 +1503,40 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml_tensors[input_name] = tensor + # Set user inputs + for key, value in inputs.items(): + set_tensor_out(ggml_tensors[key], value) + # Build layers for node in model_graph.node: + # print( + # "OP:", + # node.op_type, + # "| NODE:", + # node.name, + # "| IN:", + # node.input, + # "| OUT:", + # node.output[0], + # ) node_output = ggml_operators[node.op_type]( + self, node, ggml_tensors, context, refs, ) + node_value = ggml.utils.to_numpy(self.eval_tensor(node_output, context)) + # print("OUTPUT_SHAPE:", node_value.shape) + # print() + if node.output[-1] == self.graph.output[-1].name: exit_node = node_output # Build graph gf = ggml.ggml_build_forward(exit_node) - # Set user inputs - for key, value in inputs.items(): - set_tensor_out(ggml_tensors[key], value) - # Compute graph ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -1324,7 +1613,18 @@ def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): for initializer in graph_def.initializer: name = initializer.name np_array = onnx.numpy_helper.to_array(initializer) - tensor = ggml.utils.from_numpy(x=np_array, ctx=context) + if can_quantize(np_array, name, graph_def): + ggml_qtype = ggml.utils.GGML_TYPE.Q8_0 + shape = tuple(reversed(np_array.shape)) + tensor = ggml.ggml_new_tensor( + context, + ggml_qtype.value, + len(shape), + (ctypes.c_int64 * len(shape))(*shape), + ) + + else: + tensor = ggml.utils.from_numpy(x=np_array, ctx=context) ggml.ggml_set_name(tensor=tensor, name=name.encode()) total_nbytes += ggml.ggml_nbytes(tensor) @@ -1339,7 +1639,26 @@ def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): tensor.contents.data = ctypes.cast( ctypes.addressof(buffer) + offset, ctypes.c_void_p ) - set_tensor_out(tensor, onnx.numpy_helper.to_array(initializer)) + + np_array = onnx.numpy_helper.to_array(initializer) + if ggml.ggml_is_quantized(tensor.contents.type): + np_c_float_data = ctypes.cast( + np_array.ctypes.data, ctypes.POINTER(ctypes.c_float) + ) + + ggml.utils.quantize_0( + np_c_float_data, + np_array.size, + np_array.shape[0], + ggml_qtype, + work=ctypes.cast( + ctypes.addressof(buffer) + offset, ctypes.c_void_p + ), + ) + + else: + set_tensor_out(tensor, np_array) + offset += nbytes ggml_backend_rep.ggml_buffer = buffer diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 549cfc65..fb26cadd 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -16,7 +16,7 @@ import contextlib import ggml import ggml.utils -from ggml.contrib.onnx import GgmlRuntimeBackend, ggml_operators +from ggml.contrib.onnx import GgmlRuntimeBackend, ggml_operators, GgmlBackendRep def test_ggml_onnx_runtime_shape_operator(): @@ -69,7 +69,9 @@ def test_ggml_onnx_runtime_shape_operator(): refs = [] for shape_node in nodes: - output_tensor = ggml_operators["Shape"](shape_node, tensors_dict, context, refs) + output_tensor = ggml_operators["Shape"]( + GgmlBackendRep(), shape_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) results.append(ggml.utils.to_numpy(output_tensor)) @@ -161,11 +163,13 @@ def forward(self, input): results = [] with pytest.raises(ValueError) as ex_input_error: - ggml_operators["Unsqueeze"](unsqueeze_node1, tensors_dict, context, refs) + ggml_operators["Unsqueeze"]( + GgmlBackendRep(), unsqueeze_node1, tensors_dict, context, refs + ) for shape_node in nodes: output_tensor = ggml_operators["Unsqueeze"]( - shape_node, tensors_dict, context, refs + GgmlBackendRep(), shape_node, tensors_dict, context, refs ) gf = ggml.ggml_build_forward(output_tensor) @@ -276,7 +280,9 @@ def onnx_gather(x, indices, axis): refs = [] - output_tensor = ggml_operators["Gather"](gather_node2, tensors_dict, context, refs) + output_tensor = ggml_operators["Gather"]( + GgmlBackendRep(), gather_node2, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) @@ -362,7 +368,7 @@ def onnx_constant(value, dtype, shape): for shape_node in nodes: output_tensor = ggml_operators["Constant"]( - shape_node, tensors_dict, context, refs + GgmlBackendRep(), shape_node, tensors_dict, context, refs ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -440,7 +446,7 @@ def onnx_constant_of_shape(value, other): for shape_node in nodes: output_tensor = ggml_operators["ConstantOfShape"]( - shape_node, tensors_dict, context, refs + GgmlBackendRep(), shape_node, tensors_dict, context, refs ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -451,7 +457,7 @@ def onnx_constant_of_shape(value, other): def test_ggml_onnx_concat_operator(): - return + # return def onnx_concat(inputs, axis): input_data_type = inputs[0].dtype @@ -551,7 +557,7 @@ def onnx_concat(inputs, axis): for concat_node in nodes: output_tensor = ggml_operators["Concat"]( - concat_node, tensors_dict, context, refs + GgmlBackendRep(), concat_node, tensors_dict, context, refs ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -626,7 +632,7 @@ def forward(self, x): for reshape_node in nodes: output_tensor = ggml_operators["Reshape"]( - reshape_node, tensors_dict, context, refs + GgmlBackendRep(), reshape_node, tensors_dict, context, refs ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -751,7 +757,7 @@ def forward(self, input): for reducemean_node in nodes: output_tensor = ggml_operators["ReduceMean"]( - reducemean_node, tensors_dict, context, refs + GgmlBackendRep(), reducemean_node, tensors_dict, context, refs ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -822,7 +828,9 @@ def forward(self, input1, input2): results = [] for less_node in nodes: - output_tensor = ggml_operators["Less"](less_node, tensors_dict, context, refs) + output_tensor = ggml_operators["Less"]( + GgmlBackendRep(), less_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) results.append(ggml.utils.to_numpy(output_tensor)) @@ -887,7 +895,9 @@ def forward(self, input1, input2): outputs=["greater_output"], ) - output_tensor = ggml_operators["Greater"](greater_node, tensors_dict, context, refs) + output_tensor = ggml_operators["Greater"]( + GgmlBackendRep(), greater_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) result = ggml.utils.to_numpy(output_tensor) @@ -948,7 +958,9 @@ def forward(self, input1): outputs=["min_output"], ) - output_tensor = ggml_operators["Min"](min_node, tensors_dict, context, refs) + output_tensor = ggml_operators["Min"]( + GgmlBackendRep(), min_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) result = ggml.utils.to_numpy(output_tensor) @@ -1007,7 +1019,9 @@ def forward(self, input1): outputs=["min_output"], ) - output_tensor = ggml_operators["Max"](min_node, tensors_dict, context, refs) + output_tensor = ggml_operators["Max"]( + GgmlBackendRep(), min_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) result = ggml.utils.to_numpy(output_tensor) @@ -1080,7 +1094,9 @@ def onnx_matmul(x, y): outputs=["matmul_output"], ) - output_tensor = ggml_operators["MatMul"](matmul_node, tensors_dict, context, refs) + output_tensor = ggml_operators["MatMul"]( + GgmlBackendRep(), matmul_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) result = ggml.utils.to_numpy(output_tensor) @@ -1149,7 +1165,9 @@ def forward(self, input1, input2): results = [] for pow_node in nodes: - output_tensor = ggml_operators["Pow"](pow_node, tensors_dict, context, refs) + output_tensor = ggml_operators["Pow"]( + GgmlBackendRep(), pow_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) results.append(ggml.utils.to_numpy(output_tensor)) @@ -1214,7 +1232,9 @@ def forward(self, input): results = [] for relu_node in nodes: - output_tensor = ggml_operators["Relu"](relu_node, tensors_dict, context, refs) + output_tensor = ggml_operators["Relu"]( + GgmlBackendRep(), relu_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) results.append(ggml.utils.to_numpy(output_tensor)) @@ -1237,12 +1257,12 @@ def onnx_transpose(x, perm=[1, 0]): "transpose_graph", inputs=[ onnx.helper.make_tensor_value_info( - "input", onnx.TensorProto.FLOAT, list(x.shape) + "input", onnx.TensorProto.INT32, list(x.shape) ) ], outputs=[ onnx.helper.make_tensor_value_info( - "output", onnx.TensorProto.FLOAT, list(x.shape) + "output", onnx.TensorProto.INT32, [list(x.shape)[i] for i in perm] ) ], ) @@ -1270,14 +1290,13 @@ def onnx_transpose(x, perm=[1, 0]): import itertools - input_array = np.random.rand(3, 3, 3).astype(np.float32) + shape = (2, 3, 4) + input_array = np.arange(np.prod(shape), dtype=np.int32).reshape(shape) permutations = list(itertools.permutations(np.arange(len(input_array.shape)))) tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) - nodes = [] - ggml_results = [] - onnx_results = [] - + print() + print() for i, permutation in enumerate(permutations): transpose_node = onnx.helper.make_node( "Transpose", @@ -1286,32 +1305,24 @@ def onnx_transpose(x, perm=[1, 0]): perm=permutation, ) - nodes.append(transpose_node) - onnx_results.append(onnx_transpose(input_array, permutation)) + onnx_result = onnx_transpose(input_array, permutation) - for node in nodes: - output_tensor = ggml_operators["Transpose"](node, tensors_dict, context, refs) + output_tensor = ggml_operators["Transpose"]( + GgmlBackendRep(), transpose_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - ggml_results.append(ggml.utils.to_numpy(output_tensor)) - - test_results = [] + ggml_result = ggml.utils.to_numpy(output_tensor) + test_result = np.array_equal(ggml_result, onnx_result) - for i, result in enumerate(ggml_results): - test_results.append(np.allclose(result, onnx_results[i])) - # if not np.allclose(result, onnx_results[i]): - # print() - # print() - # print() - # print(permutations[i]) - # print("ggml:") - # print(result) - # print("onnx:") - # print(onnx_results[i]) - # break - - print(test_results) + print("test_result:", test_result, " Perm:", *permutation) + if not test_result: + print("ggml:\n", ggml_result) + print("onnx:\n", onnx_result) + print() + print() + print() ggml.ggml_free(context) @@ -1385,7 +1396,9 @@ def onnx_range(start, limit, delta): outputs=["range_output"], ) - output_tensor = ggml_operators["Range"](range_node, tensors_dict, context, refs) + output_tensor = ggml_operators["Range"]( + GgmlBackendRep(), range_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) result = ggml.utils.to_numpy(output_tensor) @@ -1446,7 +1459,9 @@ def forward(self, input): to=onnx.TensorProto.INT32, ) - output_tensor = ggml_operators["Cast"](cast_node, tensors_dict, context, refs) + output_tensor = ggml_operators["Cast"]( + GgmlBackendRep(), cast_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) result = ggml.utils.to_numpy(output_tensor) @@ -1518,7 +1533,9 @@ def forward(self, condition, x, y): outputs=["where_output"], ) - output_tensor = ggml_operators["Where"](where_node, tensors_dict, context, refs) + output_tensor = ggml_operators["Where"]( + GgmlBackendRep(), where_node, tensors_dict, context, refs + ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) result = ggml.utils.to_numpy(output_tensor) From 866ef9657b1ed3411f9f4e90ad475e480f2aa454 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 18 Aug 2023 17:15:46 -0400 Subject: [PATCH 061/232] Add test_ggml_onnx_qweights --- tests/test_ggml_onnx.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 9eb06d30..bc7c0ddb 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -8,6 +8,7 @@ from InstructorEmbedding import INSTRUCTOR from ggml.contrib.onnx import GgmlRuntimeBackend +import torch def test_ggml_onnx_runtime_basic(): @@ -86,6 +87,41 @@ def test_ggml_onnx_runtime_basic(): assert ggml_result == runtime_result +def test_ggml_onnx_qweights(): + class MatMulModel(torch.nn.Module): + def __init__(self): + super(MatMulModel, self).__init__() + self.weight = torch.nn.Parameter( + torch.tensor( + [[2.001034010, 1.00103040134], [0.1341415, 3.0001341340]], + dtype=torch.float32, + ) + ) + + def forward(self, x): + return torch.matmul(x, self.weight) + + model = MatMulModel() + input_data = torch.tensor( + [[1.0187673849, 2.23652460], [3.42562560, -4.024562465]], dtype=torch.float32 + ) + + f = io.BytesIO() + torch.onnx.export(model, input_data, f, input_names=["x"], output_names=["output"]) + f.seek(0) + + onnx_model = onnx.load_model(f) + session = InferenceSession(f.getvalue()) + input_name = session.get_inputs()[0].name + input_feed = {input_name: input_data.numpy()} + + runtime_result = session.run(None, input_feed)[0] + + ggml_dummy_model = GgmlRuntimeBackend.prepare(onnx_model) + ggml_result = ggml_dummy_model.run(input_feed)[0] + assert np.allclose(ggml_result, runtime_result) + + def test_ggml_onnx_runtime_instructor(): # return instructor_model = INSTRUCTOR("hkunlp/instructor-base") From 74bbd700a50eec63c7157b302edf303039a28258 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 18 Aug 2023 17:18:11 -0400 Subject: [PATCH 062/232] Remove unwanted comments --- ggml/contrib/onnx.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 503201de..db27ca66 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1509,16 +1509,6 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Build layers for node in model_graph.node: - # print( - # "OP:", - # node.op_type, - # "| NODE:", - # node.name, - # "| IN:", - # node.input, - # "| OUT:", - # node.output[0], - # ) node_output = ggml_operators[node.op_type]( self, node, @@ -1527,10 +1517,6 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: refs, ) - node_value = ggml.utils.to_numpy(self.eval_tensor(node_output, context)) - # print("OUTPUT_SHAPE:", node_value.shape) - # print() - if node.output[-1] == self.graph.output[-1].name: exit_node = node_output From 94fffbdae0de76c2f92c51cde2ac108baf511e05 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sat, 19 Aug 2023 13:32:45 -0400 Subject: [PATCH 063/232] Remove unnecessary dependencies --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 10c4f9e2..cbd6ed32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,9 +49,6 @@ onnx-tests = [ "pytest-cov==4.1.0", "pytest-runner==6.0.0", "onnxruntime==1.15.1", - "InstructorEmbedding==1.0.1", - "sentence_transformers==2.2.2", - "sentencepiece==0.1.99" ] [project.urls] From 4036cbb14e31132e06754fef28fdcb9035926426 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sat, 19 Aug 2023 14:26:25 -0400 Subject: [PATCH 064/232] Simplify onnx tests and reduce number of backend methods --- ggml/contrib/onnx.py | 44 +- tests/test_ggml_onnx.py | 79 +- tests/test_ggml_onnx_ops.py | 1655 ----------------------------------- tests/test_onnx.py | 193 ---- 4 files changed, 26 insertions(+), 1945 deletions(-) delete mode 100644 tests/test_ggml_onnx_ops.py delete mode 100644 tests/test_onnx.py diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index db27ca66..1cc58a5e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1,11 +1,14 @@ +"""GGML ONNX backend. + +This module implements a GGML backend for ONNX models and operators. +""" import ctypes from typing import Any, List, Optional, Tuple import numpy as np import onnx -from onnx import defs from onnx.backend.base import Backend, BackendRep -from onnx.helper import make_opsetid, tensor_dtype_to_np_dtype +from onnx.helper import tensor_dtype_to_np_dtype from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto import ggml @@ -345,8 +348,6 @@ def ggml_operator_constant( data_type = tensor.data_type np_data_type = tensor_dtype_to_np_dtype(data_type) - # print(node_attributes) - np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) @@ -1450,6 +1451,8 @@ def eval_tensor(self, tensor: ggml.ggml_tensor_p, context: ggml.ggml_context_p): def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: """Abstract function.""" + print(inputs) + # check: data is should be on CPU model_graph = self.graph @@ -1552,32 +1555,7 @@ def prepare(cls, model: ModelProto, device="CPU", **kwargs): """ super(GgmlRuntimeBackend, cls).prepare(model, device, **kwargs) - ggml_rep = cls.onnx_model_to_ggml_rep(model, **kwargs) - - return ggml_rep - - @classmethod - def onnx_model_to_ggml_rep(cls, model: ModelProto, **kwargs): - """Convert ONNX model to GgmlRep. - - :param model: ONNX ModelProto object. - and the converted tensorflow model. - :return: GgmlRep object. - """ - - # Models with IR_VERSION less than 3 does not have opset_import set. - # We default to minimum opset, this behavior is consistent with - # onnx checker. - # c.f. https://github.com/onnx/onnx/blob/427ac0c1b792363d373e3d7e4eef97fa46458420/onnx/checker.cc#L478 - if model.ir_version < 3: - opset_import = [make_opsetid(defs.ONNX_DOMAIN, 1)] - else: - opset_import = model.opset_import - - return cls._onnx_graph_to_ggml_rep(model.graph, opset_import, **kwargs) - - @classmethod - def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): + graph_def = model.graph ggml_backend_rep = GgmlBackendRep() ggml_backend_rep.graph = graph_def @@ -1628,8 +1606,8 @@ def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): np_array = onnx.numpy_helper.to_array(initializer) if ggml.ggml_is_quantized(tensor.contents.type): - np_c_float_data = ctypes.cast( - np_array.ctypes.data, ctypes.POINTER(ctypes.c_float) + np_c_float_data = (ctypes.c_float * np_array.size).from_address( + ctypes.addressof(np_array.ctypes.data) ) ggml.utils.quantize_0( @@ -1669,6 +1647,8 @@ def run_model(cls, model, inputs, device=None, **kwargs): :return: predictions """ rep = cls.prepare(model, device, **kwargs) + if isinstance(inputs, list): + inputs = {k:v for k, v in zip(model.graph.input, inputs)} return rep.run(inputs, **kwargs) @classmethod diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index bc7c0ddb..7678f209 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -2,17 +2,17 @@ import numpy as np import onnx -from onnx import TensorProto, helper -from onnxruntime import InferenceSession -from transformers import AutoTokenizer -from InstructorEmbedding import INSTRUCTOR +from onnx import helper +from onnx.onnx_pb import TensorProto + +import onnx.backend.test + +from onnxruntime import InferenceSession # type: ignore from ggml.contrib.onnx import GgmlRuntimeBackend -import torch def test_ggml_onnx_runtime_basic(): - # return # The name of the input tensor input_name = "X" @@ -87,63 +87,12 @@ def test_ggml_onnx_runtime_basic(): assert ggml_result == runtime_result -def test_ggml_onnx_qweights(): - class MatMulModel(torch.nn.Module): - def __init__(self): - super(MatMulModel, self).__init__() - self.weight = torch.nn.Parameter( - torch.tensor( - [[2.001034010, 1.00103040134], [0.1341415, 3.0001341340]], - dtype=torch.float32, - ) - ) - - def forward(self, x): - return torch.matmul(x, self.weight) - - model = MatMulModel() - input_data = torch.tensor( - [[1.0187673849, 2.23652460], [3.42562560, -4.024562465]], dtype=torch.float32 - ) - - f = io.BytesIO() - torch.onnx.export(model, input_data, f, input_names=["x"], output_names=["output"]) - f.seek(0) - - onnx_model = onnx.load_model(f) - session = InferenceSession(f.getvalue()) - input_name = session.get_inputs()[0].name - input_feed = {input_name: input_data.numpy()} - - runtime_result = session.run(None, input_feed)[0] - - ggml_dummy_model = GgmlRuntimeBackend.prepare(onnx_model) - ggml_result = ggml_dummy_model.run(input_feed)[0] - assert np.allclose(ggml_result, runtime_result) - - -def test_ggml_onnx_runtime_instructor(): - # return - instructor_model = INSTRUCTOR("hkunlp/instructor-base") - - onnx_instructor_model = onnx.load("instructor_base_onnx/encoder_model.onnx") - ggml_onnx_instructor_model = GgmlRuntimeBackend.prepare(onnx_instructor_model) - - instructor_tokenizer = AutoTokenizer.from_pretrained("t5-large") - - sentence = "This is a sentence" - instruction = "Represent the follwing sentence:" - - sentence_tokens = instructor_tokenizer.encode( - [instruction, sentence], return_tensors="np" - ) - - input_data = { - "input_ids": sentence_tokens, - "attention_mask": [np.ones(sentence_tokens.shape[1])], - } - - instructor_output = instructor_model.encode([[instruction, sentence]]) - ggml_output = ggml_onnx_instructor_model.run(input_data) +# # This is a pytest magic variable to load extra plugins +# pytest_plugins = ("onnx.backend.test.report",) - assert instructor_output == ggml_output +# backend_test = onnx.backend.test.BackendTest(GgmlRuntimeBackend, __name__) +# # backend_test.exclude(".*") +# # backend_test.include("test_ggml_onnx_runtime_basic") +# backend_test.include('test_add_cpu') +# # import all test cases at global scope to make them visible to python.unittest +# globals().update(backend_test.enable_report().test_cases) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py deleted file mode 100644 index fb26cadd..00000000 --- a/tests/test_ggml_onnx_ops.py +++ /dev/null @@ -1,1655 +0,0 @@ -import ctypes -import io -import os -import sys -from io import BytesIO - -import numpy as np -import onnx -import onnxruntime as ort -import pytest -import torch -import torch.onnx -from onnx import TensorProto, helper, numpy_helper -from onnxruntime import InferenceSession - -import contextlib -import ggml -import ggml.utils -from ggml.contrib.onnx import GgmlRuntimeBackend, ggml_operators, GgmlBackendRep - - -def test_ggml_onnx_runtime_shape_operator(): - # return - - tensors_dict = {} - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - - test_list = [0, 1, 2, 3, 5, 6, 7, 8, 9, 10] - - input_data1 = np.array(test_list, dtype=np.int32) - - tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_data1, context) - - tensors_dict["start1"] = ggml.utils.from_numpy( - np.array([0], dtype=np.int32), context - ) - tensors_dict["end1"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) - - tensors_dict["start2"] = ggml.utils.from_numpy( - np.array([2], dtype=np.int32), context - ) - tensors_dict["end2"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) - - shape_node1 = onnx.helper.make_node( - "Shape", - name="Shape1", - inputs=["input_tensor"], - outputs=["output_tensor1"], - ) - - shape_node2 = onnx.helper.make_node( - "Shape", - name="Shape2", - inputs=["input_tensor", "start1", "end1"], - outputs=["output_tensor2"], - ) - - shape_node3 = onnx.helper.make_node( - "Shape", - name="Shape3", - inputs=["input_tensor", "start2", "end2"], - outputs=["output_tensor3"], - ) - - nodes = [shape_node1, shape_node2, shape_node3] - results = [] - refs = [] - - for shape_node in nodes: - output_tensor = ggml_operators["Shape"]( - GgmlBackendRep(), shape_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert results[0] == list(input_data1.shape) - assert results[1] == list(input_data1[:6].shape) - assert results[2] == list(input_data1[2:6].shape) - - ggml.ggml_free(context) - - -def test_ggml_onnx_runtime_unsqueeze_operator(): - # return - - def onnx_unsqueeze(x, axes): - class UnsqueezeModel(torch.nn.Module): - def forward(self, input): - for axis in axes: - input = torch.unsqueeze(input, dim=axis) - return input - - model = UnsqueezeModel() - - x_tensor = torch.tensor(x, dtype=torch.int32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - x_tensor, - f, - input_names=["data"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - input_feed = {"data": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - tensors_dict = {} - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - - test_x = [0, 1, 2, 3, 5, 6] - test_axes1 = np.array([1], dtype=np.int32) - test_axes2 = np.array([0], dtype=np.int32) - test_axes3 = np.array([1, 2], dtype=np.int32) - - input_data1 = np.array(test_x, dtype=np.int32) - - tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_data1, context) - - tensors_dict["axes1"] = ggml.utils.from_numpy(test_axes1, context) - tensors_dict["axes2"] = ggml.utils.from_numpy(test_axes2, context) - tensors_dict["axes3"] = ggml.utils.from_numpy(test_axes3, context) - - unsqueeze_node1 = onnx.NodeProto() - unsqueeze_node1.name = "Input error Test" - unsqueeze_node1.op_type = "Unsqueeze" - unsqueeze_node1.input.extend(["input_tensor"]) - unsqueeze_node1.output.extend(["output_tensor1"]) - - unsqueeze_node2 = onnx.NodeProto() - unsqueeze_node2.op_type = "Unsqueeze" - unsqueeze_node2.input.extend(["input_tensor", "axes1"]) - unsqueeze_node2.output.extend(["output_tensor2"]) - - unsqueeze_node3 = onnx.NodeProto() - unsqueeze_node3.op_type = "Unsqueeze" - unsqueeze_node3.input.extend(["input_tensor", "axes2"]) - unsqueeze_node3.output.extend(["output_tensor3"]) - - unsqueeze_node4 = onnx.NodeProto() - unsqueeze_node4.op_type = "Unsqueeze" - unsqueeze_node4.input.extend(["input_tensor", "axes3"]) - unsqueeze_node4.output.extend(["output_tensor4"]) - - refs = [] - nodes = [unsqueeze_node2, unsqueeze_node3, unsqueeze_node4] - results = [] - - with pytest.raises(ValueError) as ex_input_error: - ggml_operators["Unsqueeze"]( - GgmlBackendRep(), unsqueeze_node1, tensors_dict, context, refs - ) - - for shape_node in nodes: - output_tensor = ggml_operators["Unsqueeze"]( - GgmlBackendRep(), shape_node, tensors_dict, context, refs - ) - - gf = ggml.ggml_build_forward(output_tensor) - - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - - results.append(ggml.utils.to_numpy(output_tensor)) - - assert ( - str(ex_input_error.value) - == 'Error for node "Input error Test": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: 1' - ) - - assert np.array_equal(results[0], onnx_unsqueeze(input_data1, test_axes1)) - assert np.array_equal(results[1], onnx_unsqueeze(input_data1, test_axes2)) - assert np.array_equal(results[2], onnx_unsqueeze(input_data1, test_axes3)) - - ggml.ggml_free(context) - - -def test_ggml_onnx_runtime_gather_operator(): - # return - - def onnx_gather(x, indices, axis): - if axis < 0: - axis += len(x.shape) - - node_def = onnx.helper.make_node( - "Gather", inputs=["data", "indices"], outputs=["output"], axis=axis - ) - output_shape = list(x.shape) # Initial assumption, adjust if needed - output_shape[axis] = indices.shape[0] # Update the size along the gather axis - graph_def = onnx.helper.make_graph( - [node_def], - "gather_model", - inputs=[ - onnx.helper.make_tensor_value_info( - "data", onnx.TensorProto.INT32, list(x.shape) - ), - onnx.helper.make_tensor_value_info( - "indices", onnx.TensorProto.INT32, list(indices.shape) - ), - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "output", onnx.TensorProto.INT32, output_shape - ) - ], - ) - model_def = onnx.helper.make_model( - graph_def, producer_name="onnx_gather_example" - ) - - onnx_model_bytes = BytesIO() - onnx.save_model(model_def, onnx_model_bytes) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - indices_list = indices.tolist() - - input_feed = {"data": x_list, "indices": indices_list} - - output = sess.run(None, input_feed) - - return output[0] - - tensors_dict = {} - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - - test_x = [ - 1046676483, - -1102854076, - -1089318038, - 1023432841, - 1041114519, - -1099187814, - 1040889675, - -1088007423, - -1096868517, - -1131772615, - -1103856891, - -1097108246, - -1098364964, - 1024061975, - -1102637477, - ] - test_indices1 = np.array([1], dtype=np.int32) - - input_data1 = np.array(test_x, dtype=np.int32) - - input_tensor = ggml.utils.from_numpy(input_data1, context) - indices_tensor = ggml.utils.from_numpy(test_indices1, context) - - tensors_dict["input_tensor"] = input_tensor - tensors_dict["indices"] = indices_tensor - - gather_node2 = onnx.helper.make_node( - "Gather", - name="/Gather", - inputs=["input_tensor", "indices"], - outputs=["output_tensor2"], - axis=0, - ) - - refs = [] - - output_tensor = ggml_operators["Gather"]( - GgmlBackendRep(), gather_node2, tensors_dict, context, refs - ) - - gf = ggml.ggml_build_forward(output_tensor) - - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - output_tensor = ggml.ggml_get_tensor(context, ggml.ggml_get_name(output_tensor)) - - assert np.array_equal( - ggml.utils.to_numpy(output_tensor), onnx_gather(input_data1, test_indices1, 0) - ) - - ggml.ggml_free(context) - - -def test_ggml_onnx_constant_operator(): - # return - - def onnx_constant(value, dtype, shape): - tensor = numpy_helper.from_array(value) - constant_node = onnx.helper.make_node( - "Constant", inputs=[], outputs=["constant_output"], value=tensor - ) - graph = onnx.helper.make_graph( - [constant_node], - "constant_graph", - inputs=[], - outputs=[ - onnx.helper.make_tensor_value_info("constant_output", dtype, shape) - ], - ) - model = onnx.helper.make_model(graph) - - return numpy_helper.to_array(model.graph.node[0].attribute[0].t) - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - - constant1 = np.array([1], dtype=np.int32) - constant2 = np.array([[1]], dtype=np.int32) - constant3 = np.array([[1, 2], [3, 4], [6, 6]], dtype=np.int32) - constant4 = np.array(6, dtype=np.int64) - - dtype = onnx.TensorProto.INT32 - - constant_numpy1 = onnx_constant(constant1, dtype, constant1.shape) - constant_numpy2 = onnx_constant(constant2, dtype, constant2.shape) - constant_numpy3 = onnx_constant(constant3, dtype, constant3.shape) - constant_numpy4 = onnx_constant(constant4, dtype, constant4.shape) - - constant_node1 = onnx.helper.make_node( - "Constant", - inputs=[], - name="constant_node1", - outputs=["constant_output1"], - value=numpy_helper.from_array(constant1), - ) - constant_node2 = onnx.helper.make_node( - "Constant", - name="constant_node2", - inputs=[], - outputs=["constant_output2"], - value=numpy_helper.from_array(constant2), - ) - constant_node3 = onnx.helper.make_node( - "Constant", - name="constant_node3", - inputs=[], - outputs=["constant_output3"], - value=numpy_helper.from_array(constant3), - ) - - constant_node4 = onnx.helper.make_node( - "Constant", - name="constant_node3", - inputs=[], - outputs=["constant_output3"], - value=numpy_helper.from_array(constant4), - ) - - nodes = [constant_node1, constant_node2, constant_node3, constant_node4] - results = [] - refs = [] - - for shape_node in nodes: - output_tensor = ggml_operators["Constant"]( - GgmlBackendRep(), shape_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.array_equal(results[0], constant_numpy1) - assert np.array_equal(results[1], constant_numpy2) - assert np.array_equal(results[2], constant_numpy3) - assert results[3] == constant_numpy4 - - ggml.ggml_free(context) - - -def test_ggml_onnx_constant_of_shape_operator(): - # return - - def onnx_constant_of_shape(value, other): - value = numpy_helper.from_array(value) - constant_node = onnx.helper.make_node( - "ConstantOfShape", inputs=["data"], outputs=["constant_output"], value=value - ) - graph = onnx.helper.make_graph( - [constant_node], - "constant_graph", - inputs=[ - onnx.helper.make_tensor_value_info( - "data", onnx.TensorProto.INT64, list(other.shape) - ) - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "constant_output", - onnx.TensorProto.FLOAT, - other.astype(np.int32).tolist(), - ) - ], - ) - model = onnx.helper.make_model(graph) - - onnx_model_bytes = BytesIO() - onnx.save_model(model, onnx_model_bytes) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = other.tolist() - input_feed = {"data": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - - shape1 = np.array([2, 3, 4], dtype=np.int32) - value_tensor = np.array([15], dtype=np.float32) - - cof_node1 = onnx.helper.make_node( - "ConstantOfShape", - inputs=["shape1"], - name="cof_node1", - outputs=["cof_output"], - value=numpy_helper.from_array(value_tensor), - ) - - tensors_dict["shape1"] = ggml.utils.from_numpy(shape1, context) - - constant_onnx = onnx_constant_of_shape(value_tensor, shape1) - - nodes = [cof_node1] - results = [] - refs = [] - - for shape_node in nodes: - output_tensor = ggml_operators["ConstantOfShape"]( - GgmlBackendRep(), shape_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - assert np.array_equal(results[0], constant_onnx) - - ggml.ggml_free(context) - - -def test_ggml_onnx_concat_operator(): - # return - - def onnx_concat(inputs, axis): - input_data_type = inputs[0].dtype - - graph = onnx.GraphProto() - - input_names = [] - for i, input_array in enumerate(inputs): - input_name = f"input{i}" - input_names.append(input_name) - - input_value_info = onnx.helper.make_tensor_value_info( - input_name, - onnx.TensorProto.FLOAT - if input_data_type == np.float32 - else onnx.TensorProto.INT32, - input_array.shape, - ) - graph.input.extend([input_value_info]) - - concat_node = onnx.NodeProto() - concat_node.op_type = "Concat" - concat_node.name = "concat_node" - concat_node.output.extend(["output"]) - concat_node.attribute.extend([onnx.helper.make_attribute("axis", axis)]) - concat_node.input.extend(input_names) - - output_value_info = onnx.helper.make_tensor_value_info( - "output", - onnx.TensorProto.FLOAT - if input_data_type == np.float32 - else onnx.TensorProto.INT32, - None, - ) - graph.output.extend([output_value_info]) - - graph.node.extend([concat_node]) - model = onnx.helper.make_model(graph) - - onnx_model_bytes = BytesIO() - onnx.save_model(model, onnx_model_bytes) - - # Load the ONNX model from BytesIO - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = { - input_name: input_array - for input_name, input_array in zip(input_names, inputs) - } - - output = sess.run(["output"], input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - - array1 = np.array([1], dtype=np.int32) - array2 = np.array([2, 3, 4, 5], dtype=np.int32) - array3 = np.array([6], dtype=np.int32) - array4 = np.array([7, 8, 9, 10], dtype=np.int32) - - tensors_dict["array1"] = ggml.utils.from_numpy(array1, context) - tensors_dict["array2"] = ggml.utils.from_numpy(array2, context) - tensors_dict["array3"] = ggml.utils.from_numpy(array3, context) - tensors_dict["array4"] = ggml.utils.from_numpy(array4, context) - - test1 = ["array1", "array2"] - inputs1 = [array1, array2] - test2 = ["array1", "array2", "array3", "array4"] - inputs2 = [array1, array2, array3, array4] - axis = 0 - - concat_node1 = onnx.helper.make_node( - "Concat", - inputs=test1, - name="concat_node1", - outputs=["concat_output1"], - axis=axis, - ) - concat_node2 = onnx.helper.make_node( - "Concat", - inputs=test2, - name="concat_node2", - outputs=["concat_output2"], - axis=axis, - ) - - concat_onnx_result1 = onnx_concat(inputs1, axis) - concat_onnx_result2 = onnx_concat(inputs2, axis) - - nodes = [concat_node1, concat_node2] - results = [] - refs = [] - - for concat_node in nodes: - output_tensor = ggml_operators["Concat"]( - GgmlBackendRep(), concat_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.array_equal(results[0], concat_onnx_result1) - assert np.array_equal(results[1], concat_onnx_result2) - - -def test_ggml_onnx_reshape_operation(): - # return - - def onnx_reshape(input_tensor, shape): - class DynamicReshapeModel(torch.nn.Module): - def __init__(self, shape): - super(DynamicReshapeModel, self).__init__() - self.shape = tuple(shape) - - def forward(self, x): - reshaped = torch.reshape(x, self.shape) - return reshaped - - if not isinstance(input_tensor, np.ndarray): - raise ValueError("Input tensor must be a NumPy array") - - if not isinstance(shape, np.ndarray): - shape = np.array(shape) - - if len(shape) != len(input_tensor.shape): - raise ValueError( - "Input shape must have the same number of dimensions as the input tensor" - ) - - model = DynamicReshapeModel(shape) - - input_tensor = torch.tensor(input_tensor, dtype=torch.int32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, input_tensor, f, opset_version=12, do_constant_folding=True - ) - f.seek(0) - sess = ort.InferenceSession(f.getvalue()) - input_name = sess.get_inputs()[0].name - output_name = sess.get_outputs()[0].name - - result = sess.run([output_name], {input_name: input_tensor.numpy()}) - - return result[0] - - input_tensor = np.array([[1, 2, 3, 4, 5, 6]], dtype=np.int32) - new_shape = np.array([2, 3], dtype=np.int32) - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - - tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_tensor, context) - tensors_dict["new_shape"] = ggml.utils.from_numpy(new_shape, context) - - reshape_node1 = onnx.helper.make_node( - "Reshape", - inputs=["input_tensor", "new_shape"], - name="reshape_node1", - outputs=["reshape_output1"], - ) - - nodes = [reshape_node1] - results = [] - refs = [] - - for reshape_node in nodes: - output_tensor = ggml_operators["Reshape"]( - GgmlBackendRep(), reshape_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.array_equal(results[0], onnx_reshape(input_tensor, new_shape)) - - -def test_ggml_onnx_softmax_operator(): - # return - - input_name = "X" - - output_name = "Softmax_Output" - - input_data = { - input_name: np.array([[-1.5, 0.001, 3.73, 5.1, 6, 6.0001]], dtype=np.float32) - } - - node1 = helper.make_node( - "Softmax", [input_name], [output_name], name="softmax_node" - ) - - X_value_info = helper.make_tensor_value_info( - input_name, TensorProto.FLOAT, [None, 6] - ) - - softmax_value_info = helper.make_tensor_value_info( - output_name, TensorProto.FLOAT, [None, 6] - ) - - graph_def = helper.make_graph( - [node1], "softmax_model", [X_value_info], [softmax_value_info] - ) - - model_def = helper.make_model(graph_def, producer_name="onnx-softmax") - - f = io.BytesIO() - onnx.save(model_def, f) - - runtime_result = InferenceSession(f.getvalue()).run(None, input_data) - - ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) - - ggml_result = ggml_dummy_model.run(input_data) - - assert np.allclose(ggml_result, runtime_result, rtol=0.001) - - -def test_ggml_onnx_reducemean_operator(): - # return - - def onnx_reducemean(x, axes): - class ReduceMeanModel(torch.nn.Module): - def forward(self, input): - return torch.mean(input, dim=axes.tolist(), keepdim=False) - - model = ReduceMeanModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - x_tensor, - f, - input_names=["data"], - output_names=["output"], - verbose=False, - ) - - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - input_feed = {"data": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - axes1 = np.array([0, 1], dtype=np.int32) - - input_array2 = np.array([[1, 2, 3, 4]], dtype=np.float32) - axes2 = np.array([1], dtype=np.int32) - - reducemean_numpy1 = onnx_reducemean(input_array1, axes1) - reducemean_numpy2 = onnx_reducemean(input_array2, axes2) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - tensors_dict["axes1"] = ggml.utils.from_numpy(axes1, context) - tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) - tensors_dict["axes2"] = ggml.utils.from_numpy(axes2, context) - - reducemean_node1 = onnx.helper.make_node( - "ReduceMean", - inputs=["input_array1"], - outputs=["reducemean_output1"], - axes=axes1, - keepdims=0, - ) - - reducemean_node2 = onnx.helper.make_node( - "ReduceMean", - inputs=["input_array2"], - outputs=["reducemean_output2"], - axes=axes2, - keepdims=0, - ) - - nodes = [reducemean_node1, reducemean_node2] - results = [] - - for reducemean_node in nodes: - output_tensor = ggml_operators["ReduceMean"]( - GgmlBackendRep(), reducemean_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.allclose(results[0], reducemean_numpy1) - assert np.allclose(results[1], reducemean_numpy2) - - ggml.ggml_free(context) - - -def test_ggml_onnx_less_operator(): - # return - - def onnx_less(x, y): - class LessModel(torch.nn.Module): - def forward(self, input1, input2): - return torch.less(input1, input2) - - model = LessModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - y_tensor = torch.tensor(y, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor, y_tensor), - f, - input_names=["input1", "input2"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - y_list = y.tolist() - input_feed = {"input1": x_list, "input2": y_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - input_array2 = np.array([[2, 2, 2], [5, 5, 5], [8, 8, 8]], dtype=np.float32) - - less_numpy = onnx_less(input_array1, input_array2) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) - - less_node = onnx.helper.make_node( - "Less", - inputs=["input_array1", "input_array2"], - outputs=["less_output"], - ) - - nodes = [less_node] - results = [] - - for less_node in nodes: - output_tensor = ggml_operators["Less"]( - GgmlBackendRep(), less_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.allclose(results[0], less_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_greater_operator(): - # return - - def onnx_greater(x, y): - class GreaterModel(torch.nn.Module): - def forward(self, input1, input2): - return torch.gt(input1, input2) - - model = GreaterModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - y_tensor = torch.tensor(y, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor, y_tensor), - f, - input_names=["input1", "input2"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - y_list = y.tolist() - input_feed = {"input1": x_list, "input2": y_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - input_array2 = np.array([[2, 2, 2], [5, 5, 5], [8, 8, 8]], dtype=np.float32) - - greater_numpy = onnx_greater(input_array1, input_array2) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) - - greater_node = onnx.helper.make_node( - "Greater", - inputs=["input_array1", "input_array2"], - outputs=["greater_output"], - ) - - output_tensor = ggml_operators["Greater"]( - GgmlBackendRep(), greater_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, greater_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_min_operator(): - # return - - def onnx_min(x): - class MinModel(torch.nn.Module): - def forward(self, input1): - return torch.min(input1) - - model = MinModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor), - f, - input_names=["input1"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - input_feed = {"input1": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - - min_numpy = onnx_min(input_array1) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - - min_node = onnx.helper.make_node( - "Min", - inputs=["input_array1"], - outputs=["min_output"], - ) - - output_tensor = ggml_operators["Min"]( - GgmlBackendRep(), min_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, min_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_max_operator(): - # return - - def onnx_max(x): - class MaxModel(torch.nn.Module): - def forward(self, input1): - return torch.max(input1) - - model = MaxModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor), - f, - input_names=["input1"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - input_feed = {"input1": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - min_numpy = onnx_max(input_array1) - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - - min_node = onnx.helper.make_node( - "Min", - inputs=["input_array1"], - outputs=["min_output"], - ) - - output_tensor = ggml_operators["Max"]( - GgmlBackendRep(), min_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, min_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_matmul_operator(): - # return - - def onnx_matmul(x, y): - matmul_node = onnx.helper.make_node( - "MatMul", inputs=["input1", "input2"], outputs=["output"] - ) - - graph = onnx.helper.make_graph( - [matmul_node], - "matmul_graph", - inputs=[ - onnx.helper.make_tensor_value_info( - "input1", onnx.TensorProto.FLOAT, list(x.shape) - ), - onnx.helper.make_tensor_value_info( - "input2", onnx.TensorProto.FLOAT, list(y.shape) - ), - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "output", onnx.TensorProto.FLOAT, list((x.shape[0], y.shape[1])) - ) - ], - ) - - model = onnx.helper.make_model(graph) - - f = BytesIO() - onnx.save_model(model, f) - - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = {"input1": x, "input2": y} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - # Define input arrays - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - input_array2 = np.array([[9, 8, 7], [6, 5, 4], [3, 2, 1]], dtype=np.float32) - - # Compute ONNX MatMul using GGML - matmul_numpy = onnx_matmul(input_array1, input_array2) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) - - matmul_node = onnx.helper.make_node( - "MatMul", - inputs=["input_array1", "input_array2"], - outputs=["matmul_output"], - ) - - output_tensor = ggml_operators["MatMul"]( - GgmlBackendRep(), matmul_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, matmul_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_pow_operator(): - # return - - def onnx_pow(x, y): - class PowModel(torch.nn.Module): - def forward(self, input1, input2): - return torch.pow(input1, input2) - - model = PowModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - y_tensor = torch.tensor(y, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor, y_tensor), - f, - input_names=["input1", "input2"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - y_list = y.tolist() - input_feed = {"input1": x_list, "input2": y_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - input_array2 = np.array([[2, 2, 2], [3, 3, 3], [4, 4, 4]], dtype=np.float32) - - pow_numpy = onnx_pow(input_array1, input_array2) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) - - pow_node = onnx.helper.make_node( - "Pow", - inputs=["input_array1", "input_array2"], - outputs=["pow_output"], - ) - - nodes = [pow_node] - results = [] - - for pow_node in nodes: - output_tensor = ggml_operators["Pow"]( - GgmlBackendRep(), pow_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.array_equal(results[0], pow_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_relu_operator(): - # return - - def onnx_relu(x): - class ReluModel(torch.nn.Module): - def forward(self, input): - return torch.relu(input) - - model = ReluModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor,), - f, - input_names=["input"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - input_feed = {"input": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array = np.array([[1, -2, 3], [-4, 5, -6], [7, -8, 9]], dtype=np.float32) - - relu_numpy = onnx_relu(input_array) - - tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) - - relu_node = onnx.helper.make_node( - "Relu", - inputs=["input_array"], - outputs=["relu_output"], - ) - - nodes = [relu_node] - results = [] - - for relu_node in nodes: - output_tensor = ggml_operators["Relu"]( - GgmlBackendRep(), relu_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.allclose(results[0], relu_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_transpose_operator(): - # return - - def onnx_transpose(x, perm=[1, 0]): - transpose_node = onnx.helper.make_node( - "Transpose", inputs=["input"], outputs=["output"], perm=perm - ) - - graph = onnx.helper.make_graph( - [transpose_node], - "transpose_graph", - inputs=[ - onnx.helper.make_tensor_value_info( - "input", onnx.TensorProto.INT32, list(x.shape) - ) - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "output", onnx.TensorProto.INT32, [list(x.shape)[i] for i in perm] - ) - ], - ) - - model = onnx.helper.make_model(graph) - - f = BytesIO() - onnx.save_model(model, f) - - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = {"input": x} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - import itertools - - shape = (2, 3, 4) - input_array = np.arange(np.prod(shape), dtype=np.int32).reshape(shape) - permutations = list(itertools.permutations(np.arange(len(input_array.shape)))) - - tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) - print() - print() - for i, permutation in enumerate(permutations): - transpose_node = onnx.helper.make_node( - "Transpose", - inputs=["input_array"], - outputs=[f"transpose_output{i}"], - perm=permutation, - ) - - onnx_result = onnx_transpose(input_array, permutation) - - output_tensor = ggml_operators["Transpose"]( - GgmlBackendRep(), transpose_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - ggml_result = ggml.utils.to_numpy(output_tensor) - test_result = np.array_equal(ggml_result, onnx_result) - - print("test_result:", test_result, " Perm:", *permutation) - if not test_result: - print("ggml:\n", ggml_result) - print("onnx:\n", onnx_result) - print() - - print() - print() - ggml.ggml_free(context) - - -def test_ggml_onnx_range_operator(): - # return - - def onnx_range(start, limit, delta): - range_node = onnx.helper.make_node( - "Range", - inputs=["start", "limit", "delta"], - outputs=["output"], - ) - - graph = onnx.helper.make_graph( - [range_node], - "range_graph", - inputs=[ - onnx.helper.make_tensor_value_info( - "start", onnx.TensorProto.FLOAT, list(start.shape) - ), - onnx.helper.make_tensor_value_info( - "limit", onnx.TensorProto.FLOAT, list(limit.shape) - ), - onnx.helper.make_tensor_value_info( - "delta", onnx.TensorProto.FLOAT, list(delta.shape) - ), - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "output", - onnx.TensorProto.FLOAT, - (int(np.ceil((limit - start) / delta)),), - ), - ], - ) - - model = onnx.helper.make_model(graph) - - f = BytesIO() - onnx.save_model(model, f) - - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = {"start": start, "limit": limit, "delta": delta} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - start_array = np.array([-5], np.float32) - limit_array = np.array([10], np.float32) - delta_array = np.array([0.5], np.float32) - - range_numpy = onnx_range(start_array, limit_array, delta_array) - - tensors_dict["start_array"] = ggml.utils.from_numpy(start_array, context) - tensors_dict["limit_array"] = ggml.utils.from_numpy(limit_array, context) - tensors_dict["delta_array"] = ggml.utils.from_numpy(delta_array, context) - - range_node = onnx.helper.make_node( - "Range", - inputs=["start_array", "limit_array", "delta_array"], - outputs=["range_output"], - ) - - output_tensor = ggml_operators["Range"]( - GgmlBackendRep(), range_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, range_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_cast_operator(): - # return - - def onnx_cast(input_data, to_dtype): - class CastModel(torch.nn.Module): - def forward(self, input): - return input.to(dtype=to_dtype) - - model = CastModel() - - x_tensor = torch.tensor(input_data, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor,), - f, - input_names=["input"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = {"input": input_data} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_data_array = np.array([1.2, 2.5, 3.7], np.float32) - - cast_numpy = onnx_cast(input_data_array, torch.int32) - - tensors_dict["input_data_array"] = ggml.utils.from_numpy(input_data_array, context) - - cast_node = onnx.helper.make_node( - "Cast", - inputs=["input_data_array"], - outputs=["cast_output"], - to=onnx.TensorProto.INT32, - ) - - output_tensor = ggml_operators["Cast"]( - GgmlBackendRep(), cast_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, cast_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_where_operator(): - # return - - def onnx_where(condition_data, x_data, y_data): - class WhereModel(torch.nn.Module): - def forward(self, condition, x, y): - return torch.where(condition, x, y) - - model = WhereModel() - - condition_tensor = torch.tensor(condition_data, dtype=torch.bool) - x_tensor = torch.tensor(x_data, dtype=torch.float32) - y_tensor = torch.tensor(y_data, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (condition_tensor, x_tensor, y_tensor), - f, - input_names=["condition", "x", "y"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = { - "condition": condition_data, - "x": x_data, - "y": y_data, - } - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - condition_data_array = np.array([True, False, True], dtype=bool) - x_data_array = np.array([1.2, 2.5, 3.7], np.float32) - y_data_array = np.array([0.5, 1.0, 2.0], np.float32) - - where_numpy = onnx_where(condition_data_array, x_data_array, y_data_array) - - tensors_dict["condition_data_array"] = ggml.utils.from_numpy( - condition_data_array, context - ) - tensors_dict["x_data_array"] = ggml.utils.from_numpy(x_data_array, context) - tensors_dict["y_data_array"] = ggml.utils.from_numpy(y_data_array, context) - - where_node = onnx.helper.make_node( - "Where", - inputs=["condition_data_array", "x_data_array", "y_data_array"], - outputs=["where_output"], - ) - - output_tensor = ggml_operators["Where"]( - GgmlBackendRep(), where_node, tensors_dict, context, refs - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.array_equal(result, where_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_runtime_basic(): - # return - - input_name = "X" - - weight_name_a = "A" - weight_name_b = "B" - weight_name_c = "C" - weight_name_d = "D" - - intermediate_name1 = "intermediate1" - intermediate_name2 = "intermediate2" - intermediate_name3 = "intermediate3" - intermediate_name4 = "intermediate4" - intermediate_name5 = "intermediate5" - intermediate_name6 = "intermediate6" - - output_name = "Y" - - node1 = helper.make_node( - "Mul", [input_name, weight_name_a], [intermediate_name1], name="node1" - ) # X * A - node2 = helper.make_node( - "Div", [intermediate_name1, weight_name_b], [intermediate_name2], name="node2" - ) # (X * A) / B - node3 = helper.make_node( - "Add", [intermediate_name2, weight_name_c], [intermediate_name3], name="node3" - ) # (X * A / B) + C - node4 = helper.make_node( - "Sub", [intermediate_name3, weight_name_d], [intermediate_name4], name="node4" - ) # (X * A / B) + C - D - node5 = helper.make_node( - "Sqrt", [intermediate_name4], [intermediate_name5], name="node5" - ) # Sqrt((X * A / B) + C - D) - node6 = helper.make_node( - "Log", [intermediate_name5], [intermediate_name6], name="node6" - ) # Log(Sqrt((X * A / B) + C - D)) - node7 = helper.make_node( - "Abs", [intermediate_name6], [output_name], name="node7" - ) # Abs(Log(Sqrt((X * A / B) + C - D))) - - X_value_info = helper.make_tensor_value_info( - input_name, TensorProto.FLOAT, [None, 1] - ) - - output_value_info = helper.make_tensor_value_info( - output_name, TensorProto.FLOAT, [None, 1] - ) - - weights_a = np.array([50.6], dtype=float).astype(np.float32) - weights_b = np.array([0.0013], dtype=float).astype(np.float32) - weights_c = np.array([8.1], dtype=float).astype(np.float32) - weights_d = np.array([13.22], dtype=float).astype(np.float32) - - A_init = helper.make_tensor( - weight_name_a, - TensorProto.FLOAT, - [ - 1, - ], - weights_a, - ) - B_init = helper.make_tensor( - weight_name_b, - TensorProto.FLOAT, - [ - 1, - ], - weights_b, - ) - C_init = helper.make_tensor( - weight_name_c, - TensorProto.FLOAT, - [ - 1, - ], - weights_c, - ) - D_init = helper.make_tensor( - weight_name_d, - TensorProto.FLOAT, - [ - 1, - ], - weights_d, - ) - - graph_def = helper.make_graph( - [node1, node2, node3, node4, node5, node6, node7], - "complex_expression_model_with_log", - [X_value_info], - [output_value_info], - [A_init, B_init, C_init, D_init], - ) - - model_def = helper.make_model(graph_def, producer_name="onnx-complex-expression") - - input_data = {"X": np.array([[6.0]], dtype=np.float32)} - - f = io.BytesIO() - onnx.save(model_def, f) - - runtime_result = InferenceSession(f.getvalue()).run(None, input_data) - - ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) - ggml_result = ggml_dummy_model.run(input_data) - - assert np.allclose(ggml_result, runtime_result) diff --git a/tests/test_onnx.py b/tests/test_onnx.py deleted file mode 100644 index d7d2179f..00000000 --- a/tests/test_onnx.py +++ /dev/null @@ -1,193 +0,0 @@ -import os -import unittest - -import onnx.backend.test - -from ggml.contrib.onnx import GgmlRuntimeBackend as ggml_onnx - -# This is a pytest magic variable to load extra plugins -pytest_plugins = ("onnx.backend.test.report",) - -backend_test = onnx.backend.test.BackendTest(ggml_onnx, __name__) - -backend_test.exclude( - r"(test_hardsigmoid" # Does not support Hardsigmoid. - "|test_hardmax" # Does not support Hardmax. - "|test_.*FLOAT16.*" # Does not support Cast on Float16. - "|test_depthtospace.*" # Does not support DepthToSpace. - "|test_reduce_l1.*" # Does not support ReduceL1. - "|test_reduce_l2.*" # Does not support ReduceL2. - "|test_reduce_log_sum.*" # Does not support ReduceLogSum. - "|test_reduce_prod.*" # Does not support ReduceProd. - "|test_reduce_sum_square.*" # Does not support ReduceSumSquare - "|test_det.*" # Does not support Det - "|test_range.*" # Does not support Range - "|test_tile.*" # Tile's Caffe2 implementation needs some tweak - "|test_lstm.*" # Seems LSTM case has some problem - "|test_simple_rnn.*" # Seems simple RNN case has some problem - "|test_gru.*" # Seems GRU case has some problem - "|test_prelu.*" # PRelu is not compliant with ONNX yet - "|test_operator_repeat.*" # Tile is not compliant with ONNX yet - "|test_.*pool_.*same.*" # Does not support pool same. - "|test_.*pool_.*ceil.*" # Does not support pool same. - "|test_maxpool_with_argmax.*" # MaxPool outputs indices in different format. - "|test_maxpool.*dilation.*" # MaxPool doesn't support dilation yet. - "|test_maxpool.*uint8.*" # MaxPool doesn't support uint8 yet. - "|test_convtranspose.*" # ConvTranspose needs some more complicated translation - "|test_mvn.*" # MeanVarianceNormalization is experimental and not supported. - "|test_dynamic_slice.*" # MeanVarianceNormalization is experimental and not supported. - "|test_eyelike.*" # Needs implementation - "|test_maxunpool.*" # Needs implementation - "|test_acosh.*" # Needs implementation - "|test_asinh.*" # Needs implementation - "|test_atanh.*" # Needs implementation - "|test_onehot.*" # Needs implementation - "|test_scan.*" # Needs implementation - "|test_isnan.*" # Needs implementation - "|test_scatter.*" # Should be similar to ScatterAssign - "|test_constantofshape_int.*" # Needs implementation - "|test_shrink.*" # Needs implementation - "|test_strnorm.*" # Needs implementation - "|test_nonzero.*" # Needs implementation - "|test_tfidfvectorizer.*" # Needs implementation - "|test_top_k.*" # opset 10 is not supported yet - "|test_resize.*" # opset 10 is not supported yet - "|test_slice.*" # opset 10 is not supported yet - "|test_.*qlinear.*" # Skip quantized op test - "|test_.*quantize.*" # Skip quantized op test - "|test_.*matmulinteger.*" # Skip quantized op test - "|test_.*convinteger.*" # Skip quantized op test - "|test_isinf.*" # Needs implementation - "|test_mod.*" # Needs implementation - "|test_nonmaxsuppression.*" # Needs implementation - "|test_reversesequence.*" # Needs implementation - "|test_roialign.*" # Needs implementation - "|test_bitshift.*" # Needs implementation - "|test_round.*" # Needs implementation - "|test_cumsum.*" # Needs implementation - "|test_clip.*" # opset 11 is not supported yet - "|test_gather_elements.*" # opset 11 is not supported yet - "|test_scatter.*" # opset 11 is not supported yet - "|test_unique.*" # opset 11 is not supported yet - "|test_gathernd.*" # opset 11 is not supported yet - "|test_dropout_random.*" # opset 12 is not supported - "|test_dropout_default.*" # opset 12 is not supported - "|test_einsum.*" # opset 12 is not supported - "|test_.*training.*" # training is not supported - "|test_.*_loss.*" # training is not supported - "|test_split_zero_size.*" # unsupported case - "|test_constantofshape_int_shape_zero.*" # unsupported case - "|test_constant_pad.*" # 1d pad is not supported - "|test_edge_pad.*" # 1d pad is not supported - "|test_reflect_pad.*" # 1d pad is not supported - "|test_gemm_default_no_bias.*" # no bias is not supported - "|test_gemm_default_scalar_bias.*" # incorrect type - "|test_sequence_.*" # type sequence is not supported yet - "|test_.*negative_ax.*" # negative axis is not supported yet - "|test_.*negative_ind.*" # negative axis is not supported yet - "|test_argmax_.*select_last_index.*" # unsupported case - "|test_argmin_.*select_last_index_.*" # unsupported case - "|test_celu.*" # unsupported case - "|test_gathernd.*" # unsupported case - "|test_greater_equal.*" # unsupported case - "|test_less_equal.*" # unsupported case - "|test_max_.*" # unsupported case - "|test_min_.*" # unsupported case - "|test_.*momentum_.*" # unsupported case - "|test_sce.*" # unsupported case - "|test_nllloss.*" # unsupported case - "|test_unfoldtodepth.*" # unsupported case - "|test_.*gradient.*" # no support for gradient op in c2-onnx - "|test_.*adagrad.*" # no support for gradient op in c2-onnx - "|test_.*loss.*" # no support for loss op in c2-onnx - "|test_.*adam.*" # no support for adam op - "|test_.*identity.*" # no support for adam op - ")" -) - -# Quick patch to unbreak master CI, is working on the debugging. -backend_test.exclude( - "(test_cast_.*" - "|test_compress_.*" - "|test_Conv1d_.*cuda" - "|test_Conv3d_groups_cuda" - "|test_rnn_seq_length" - "|test_operator_add.*_cuda" - "|test_operator_lstm_cuda" - "|test_operator_rnn.*_cuda" - "|test_lrn_default_cuda)" -) - -# Temporarily skip some ONNX backend tests with broadcasting. -backend_test.exclude("(test_pow_bcast" "|test_pow_types.*" ")") - -# Temporarily skip some ONNX backend tests due to updates in opset 13. -backend_test.exclude( - "(test_if_.*" # added support for sequence type inputs - "|test_if_seq_.*" # added support for sequence type inputs - "|test_logsoftmax_.*" # axis attr default value changed from 1 to -1 - "|test_loop11_.*" # seg fault issue - "|test_loop16_.*" # seg fault issue - "|test_loop13_seq_.*" # no support for sequence inputs for scan input - "|test_reduce_sum_.*" # axes is now an input (not attr), added noop_with_empty_axes - "|test_softmax_.*" # axis attr default value changed from 1 to -1 - "|test_split_variable_parts_.*" # axes is now an input (not attr) - "|test_squeeze_.*" # axes is now an input (not attr) - "|test_unsqueeze_.*" # axes is now an input (not attr) - "|test_MaxPool1d_stride_padding_dilation_.*" - "|test_MaxPool2d_stride_padding_dilation_.*" - ")" -) - -# Temporarily skip some ONNX backend tests due to updates in opset 14. -backend_test.exclude( - "(test_add_uint8_.*" # uint8 dtype added - "|test_div_uint8_.*" # uint8 dtype added - "|test_hardswish_.*" # new operator added - "|test_mul_uint8_.*" # uint8 dtype added - "|test_sub_uint8_.*" # uint8 dtype added - "|test_tril_.*" # new operator added - "|test_triu_.*" # new operator added - "|test_identity_sequence_.*" # new operator added - "|test_reshape_allowzero_reordered_.*" - "|test_conv_with_autopad_same_.*" - ")" -) - -# Unsupported ops in opset 15 -backend_test.exclude( - "(test_bernoulli_.*" - "|test_castlike_.*" - "|test_optional_.*" - "|test_shape_end_.*" - "|test_shape_start_.*" - "|test_identity_opt_*" - "|test_loop16_seq_none_*" - "|test_if_opt_*" - ")" -) - -# Unsupported ops in opset 16 -backend_test.exclude("(test_gridsample_.*" "|test_spacetodepth_.*" ")") - -# Unsupported ops in opset 17 -backend_test.exclude( - "(test_layer_normalization_.*" - "|test_blackmanwindow_.*" - "|test_dft_.*" - "|test_hammingwindow_.*" - "|test_hannwindow_.*" - "|test_melweightmatrix_.*" - "|test_stft_.*" - "|test_sequencemap_.*" - ")" -) - -# Unsupported ops in opset 18 -backend_test.exclude("(test_center_crop_pad_.*" "|test_col2im*" "|test_bitwise*)") - -# import all test cases at global scope to make them visible to python.unittest -globals().update(backend_test.enable_report().test_cases) - -if __name__ == "__main__": - unittest.main() From 9838115eb8164dbb01c385c1d76beb6afccdf775 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sat, 19 Aug 2023 15:12:50 -0400 Subject: [PATCH 065/232] cleanup and enable passing tests --- ggml/contrib/onnx.py | 131 +++++++++++++++++----------------------- tests/test_ggml_onnx.py | 44 +++++++++++--- 2 files changed, 91 insertions(+), 84 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 1cc58a5e..0f15a5be 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3,7 +3,7 @@ This module implements a GGML backend for ONNX models and operators. """ import ctypes -from typing import Any, List, Optional, Tuple +from typing import Any, List, Optional, Tuple, Dict import numpy as np import onnx @@ -101,12 +101,6 @@ def broadcast_tensor( (ctypes.c_int64 * len(shape))(*shape), ) - # new_tensor = ggml.ggml_repeat( - # ctx, - # tensor, - # new_tensor, - # ) - if ggml.utils.get_shape(tensor) == (): ggml.utils.to_numpy(new_tensor)[()] = ggml.utils.to_numpy(tensor) else: @@ -123,7 +117,7 @@ def broadcast_shapes( output_shape = tuple( reversed(np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape) - ) + ) # TODO: Fix this a_shaped = a b_shaped = b @@ -136,23 +130,6 @@ def broadcast_shapes( return a_shaped, b_shaped -@ggml.ggml_custom2_op_t -def custom_broadcast( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - context = userdata - tensor_out = ggml.ggml_repeat( - context, - tensor_in_1, - tensor_in_2, - ) - - # ------ Operators ------ @@ -160,7 +137,7 @@ def custom_broadcast( def ggml_operator_abs( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -186,7 +163,7 @@ def ggml_operator_abs( def ggml_operator_add( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -199,8 +176,8 @@ def ggml_operator_add( output_name = node.output[0] - a = node_inputs[0] - b = node_inputs[1] + a, b = node_inputs + a, b = broadcast_shapes(context, a, b) add_result = ggml.ggml_add( context, @@ -231,7 +208,7 @@ def custom_cast( def ggml_operator_cast( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -262,7 +239,7 @@ def ggml_operator_cast( def ggml_operator_concat( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -337,7 +314,7 @@ def custom_constant( def ggml_operator_constant( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -407,7 +384,7 @@ def custom_constant_of_shape( def ggml_operator_constant_of_shape( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -455,7 +432,7 @@ def ggml_operator_constant_of_shape( def ggml_operator_div( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -504,7 +481,7 @@ def custom_gather( def ggml_operator_gather( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -567,7 +544,7 @@ def custom_greater( def ggml_operator_greater( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -622,7 +599,7 @@ def custom_less( def ggml_operator_less( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -659,7 +636,7 @@ def ggml_operator_less( def ggml_operator_log( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -685,7 +662,7 @@ def ggml_operator_log( def ggml_operator_mat_mul( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -743,7 +720,7 @@ def custom_max( def ggml_operator_max( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -796,7 +773,7 @@ def custom_min( def ggml_operator_min( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -835,7 +812,7 @@ def ggml_operator_min( def ggml_operator_mul( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -883,7 +860,7 @@ def custom_pow( def ggml_operator_pow( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -930,7 +907,7 @@ def custom_range( def ggml_operator_range( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1005,7 +982,7 @@ def custom_reduce_mean( def ggml_operator_reduce_mean( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1055,7 +1032,7 @@ def ggml_operator_reduce_mean( def ggml_operator_relu( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1081,7 +1058,7 @@ def ggml_operator_relu( def ggml_operator_reshape( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1159,7 +1136,7 @@ def custom_shape( def ggml_operator_shape( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1213,7 +1190,7 @@ def ggml_operator_shape( def ggml_operator_softmax( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1239,7 +1216,7 @@ def ggml_operator_softmax( def ggml_operator_sqrt( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1265,7 +1242,7 @@ def ggml_operator_sqrt( def ggml_operator_sub( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1295,7 +1272,7 @@ def ggml_operator_sub( def ggml_operator_transpose( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1353,7 +1330,7 @@ def custom_unsqueeze( def ggml_operator_unsqueeze( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1410,7 +1387,7 @@ def custom_where( def ggml_operator_where( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1435,8 +1412,15 @@ def ggml_operator_where( class GgmlBackendRep(BackendRep): - def __init__(self): + def __init__(self, graph, weights, weights_buffer, inputs, outputs, ggml_context, ggml_init_params): super(GgmlBackendRep, self).__init__() + self.graph = graph + self.weights = weights + self.weights_buffer = weights_buffer + self.inputs = inputs + self.outputs = outputs + self.ggml_context = ggml_context + self.ggml_init_params = ggml_init_params def __del__(self): if hasattr(self, "ggml_context"): @@ -1449,11 +1433,12 @@ def eval_tensor(self, tensor: ggml.ggml_tensor_p, context: ggml.ggml_context_p): return tensor def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: - """Abstract function.""" + """Run the model with the specified inputs.""" - print(inputs) + if isinstance(inputs, list): + inputs = {k.name:v for k,v in zip(self.inputs, inputs)} - # check: data is should be on CPU + assert isinstance(inputs, dict) model_graph = self.graph exit_node = None @@ -1555,29 +1540,24 @@ def prepare(cls, model: ModelProto, device="CPU", **kwargs): """ super(GgmlRuntimeBackend, cls).prepare(model, device, **kwargs) - graph_def = model.graph - ggml_backend_rep = GgmlBackendRep() - ggml_backend_rep.graph = graph_def - + graph = model.graph weights = {} - n_tensors = len(graph_def.initializer) + n_tensors = len(graph.initializer) init_params = ggml.ggml_init_params( mem_size=n_tensors * ggml.ggml_tensor_overhead(), no_alloc=True, ) context = ggml.ggml_init(init_params) - ggml_backend_rep.ggml_context = context - ggml_backend_rep.ggml_init_params = init_params total_nbytes = 0 pairs = [] - for initializer in graph_def.initializer: + for initializer in graph.initializer: name = initializer.name np_array = onnx.numpy_helper.to_array(initializer) - if can_quantize(np_array, name, graph_def): + if can_quantize(np_array, name, graph): ggml_qtype = ggml.utils.GGML_TYPE.Q8_0 shape = tuple(reversed(np_array.shape)) tensor = ggml.ggml_new_tensor( @@ -1625,12 +1605,15 @@ def prepare(cls, model: ModelProto, device="CPU", **kwargs): offset += nbytes - ggml_backend_rep.ggml_buffer = buffer - ggml_backend_rep.weights = weights - ggml_backend_rep.inputs = graph_def.input - ggml_backend_rep.outputs = graph_def.output - - return ggml_backend_rep + return GgmlBackendRep( + graph=graph, + weights=weights, + weights_buffer=buffer, + inputs=graph.input, + outputs=graph.output, + ggml_context=context, + ggml_init_params=init_params, + ) @classmethod def run_model(cls, model, inputs, device=None, **kwargs): @@ -1647,8 +1630,6 @@ def run_model(cls, model, inputs, device=None, **kwargs): :return: predictions """ rep = cls.prepare(model, device, **kwargs) - if isinstance(inputs, list): - inputs = {k:v for k, v in zip(model.graph.input, inputs)} return rep.run(inputs, **kwargs) @classmethod diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 7678f209..8a96f728 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -87,12 +87,38 @@ def test_ggml_onnx_runtime_basic(): assert ggml_result == runtime_result -# # This is a pytest magic variable to load extra plugins -# pytest_plugins = ("onnx.backend.test.report",) - -# backend_test = onnx.backend.test.BackendTest(GgmlRuntimeBackend, __name__) -# # backend_test.exclude(".*") -# # backend_test.include("test_ggml_onnx_runtime_basic") -# backend_test.include('test_add_cpu') -# # import all test cases at global scope to make them visible to python.unittest -# globals().update(backend_test.enable_report().test_cases) +# This is a pytest magic variable to load extra plugins +pytest_plugins = ("onnx.backend.test.report",) + +backend_test = onnx.backend.test.BackendTest(GgmlRuntimeBackend, __name__) +backend_test.include("test_abs_") +# backend_test.include("test_add_") +# backend_test.include("test_cast") +backend_test.include("test_concat_") +# backend_test.include("test_constant_") +# backend_test.include("test_div_") +# backend_test.include("test_gather_") +# backend_test.include("test_greater_") +# backend_test.include("test_less_") +# backend_test.include("test_log_") +# backend_test.include("test_matmul_") +# backend_test.include("test_max_") +# backend_test.include("test_min_") +# backend_test.include("test_mul_") +# backend_test.include("test_pow_") +# backend_test.include("test_range_") +# backend_test.include("test_reduce_mean_") +# backend_test.include("test_relu_") +# backend_test.include("test_reshape_") +# backend_test.include("test_shape") +# backend_test.include("test_softmax_") +backend_test.include("test_sqrt_") +# backend_test.include("test_sub_") +# backend_test.include("test_transpose_") +# backend_test.include("test_unsqueeze_") +# backend_test.include("test_where_") + +# backend_test.exclude(".*cuda.*") + +# import all test cases at global scope to make them visible to python.unittest +globals().update(backend_test.enable_report().test_cases) From a89fd6a39367e6a04f470114e83fa2b758c09982 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sat, 19 Aug 2023 16:17:22 -0400 Subject: [PATCH 066/232] Update return types --- ggml/contrib/onnx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 0f15a5be..a9b4a8d2 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1616,7 +1616,7 @@ def prepare(cls, model: ModelProto, device="CPU", **kwargs): ) @classmethod - def run_model(cls, model, inputs, device=None, **kwargs): + def run_model(cls, model: ModelProto, inputs: Any, device=None, **kwargs) -> Tuple[Any, ...]: """ Compute the prediction. @@ -1633,7 +1633,7 @@ def run_model(cls, model, inputs, device=None, **kwargs): return rep.run(inputs, **kwargs) @classmethod - def run_node(cls, node, inputs, device=None, outputs_info=None, **kwargs): + def run_node(cls, node: NodeProto, inputs: Any, device=None, outputs_info=None, **kwargs) -> Tuple[Any, ...]: """ This method is not implemented as it is much more efficient to run a whole model than every node independently. From 75fe261f102e2fb8bf8985cf9adf2fe1457b3cf7 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sat, 19 Aug 2023 17:06:40 -0400 Subject: [PATCH 067/232] broadcast subtract --- ggml/contrib/onnx.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index a9b4a8d2..d3b55ba2 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1254,9 +1254,7 @@ def ggml_operator_sub( ) output_name = node.output[0] - a = node_inputs[0] - b = node_inputs[1] - + a, b = node_inputs a, b = broadcast_shapes(context, a, b) sub_result = ggml.ggml_sub( From cba250237faf5b91ee5f4aad5693c07907a8b6d2 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sat, 19 Aug 2023 17:06:57 -0400 Subject: [PATCH 068/232] Enable some tests for implemented operators --- tests/test_ggml_onnx.py | 158 ++++++++++++++++++++++++++++++++++------ 1 file changed, 134 insertions(+), 24 deletions(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 8a96f728..c4130b6a 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -91,34 +91,144 @@ def test_ggml_onnx_runtime_basic(): pytest_plugins = ("onnx.backend.test.report",) backend_test = onnx.backend.test.BackendTest(GgmlRuntimeBackend, __name__) + backend_test.include("test_abs_") -# backend_test.include("test_add_") -# backend_test.include("test_cast") + +backend_test.include("test_add_") +backend_test.exclude("test_add_uint8_") # not supported + +backend_test.include("test_cast_") + backend_test.include("test_concat_") -# backend_test.include("test_constant_") -# backend_test.include("test_div_") -# backend_test.include("test_gather_") -# backend_test.include("test_greater_") -# backend_test.include("test_less_") -# backend_test.include("test_log_") -# backend_test.include("test_matmul_") -# backend_test.include("test_max_") -# backend_test.include("test_min_") -# backend_test.include("test_mul_") -# backend_test.include("test_pow_") -# backend_test.include("test_range_") -# backend_test.include("test_reduce_mean_") -# backend_test.include("test_relu_") -# backend_test.include("test_reshape_") -# backend_test.include("test_shape") -# backend_test.include("test_softmax_") + +backend_test.include("test_constant_") + +backend_test.include("test_div_") + +backend_test.exclude("test_div_uint8_") # not supported + +backend_test.include("test_gather_") +backend_test.exclude("test_gather_2d") +backend_test.exclude("test_gather_elements") +backend_test.exclude("test_gather_negative") + +backend_test.include("test_greater_") +backend_test.exclude("test_greater_bcast") +backend_test.exclude("test_greater_equal") + +backend_test.include("test_less_") +backend_test.exclude("test_less_") +backend_test.exclude("test_less_bcast") +backend_test.exclude("test_less_cuda") +backend_test.exclude("test_less_equal_") + +backend_test.include("test_log_") +backend_test.exclude("test_log_") + +backend_test.include("test_matmul_") +backend_test.exclude("test_matmul_") + +backend_test.include("test_max_") +backend_test.exclude("test_max_one") +backend_test.exclude("test_max_two") +backend_test.exclude("test_max_float16") +backend_test.exclude("test_max_float32") +backend_test.exclude("test_max_float64") +backend_test.exclude("test_max_int8") +backend_test.exclude("test_max_int16") +backend_test.exclude("test_max_int32") +backend_test.exclude("test_max_int64") +backend_test.exclude("test_max_uint") +backend_test.exclude("test_max_example") + +backend_test.include("test_min_") +backend_test.exclude("test_min_one") +backend_test.exclude("test_min_two") +backend_test.exclude("test_min_float16") +backend_test.exclude("test_min_float32") +backend_test.exclude("test_min_float64") +backend_test.exclude("test_min_int8") +backend_test.exclude("test_min_int16") +backend_test.exclude("test_min_int32") +backend_test.exclude("test_min_int64") +backend_test.exclude("test_min_uint") +backend_test.exclude("test_min_example") + +backend_test.include("test_mul_") +backend_test.exclude("test_mul_") +backend_test.exclude("test_mul_bcast") +backend_test.exclude("test_mul_example") +backend_test.exclude("test_mul_uint8") + +backend_test.include("test_pow_") +backend_test.exclude("test_pow_") +backend_test.exclude("test_pow_types") +backend_test.exclude("test_pow_types_int64") +backend_test.exclude("test_pow_types_int64") + +backend_test.include("test_range_") +backend_test.exclude("test_range_float") +backend_test.exclude("test_range_int32") + +backend_test.include("test_reduce_mean_") +backend_test.exclude("test_reduce_mean_default") +backend_test.exclude("test_reduce_mean_do_not_keepdims") +backend_test.exclude("test_reduce_mean_keepdims") +backend_test.exclude("test_reduce_mean_negative_axes") + +backend_test.include("test_relu_") +backend_test.exclude("test_relu_") +backend_test.exclude("test_relu_expanded") + +backend_test.include("test_reshape_") +backend_test.exclude("test_reshape_allowzero") +backend_test.exclude("test_reshape_negative") +backend_test.exclude("test_reshape_one_dim") +backend_test.exclude("test_reshape_reduced") +backend_test.exclude("test_reshape_reordered") +backend_test.exclude("test_reshape_zero") +backend_test.exclude("test_reshape_extended") + +backend_test.include("test_shape_") +backend_test.exclude("test_shape_cpu") +backend_test.exclude("test_shape_cuda") +backend_test.exclude("test_shape_clip") +backend_test.exclude("test_shape_start") +backend_test.exclude("test_shape_end") +backend_test.exclude("test_shape_example") + +backend_test.include("test_softmax_") +backend_test.exclude("test_softmax_axis") +backend_test.exclude("test_softmax_default_axis") +backend_test.exclude("test_softmax_example") +backend_test.exclude("test_softmax_large_number") +backend_test.exclude("test_softmax_negative_axis") +backend_test.exclude("test_softmax_functional") +backend_test.exclude("test_softmax_lastdim") + backend_test.include("test_sqrt_") -# backend_test.include("test_sub_") -# backend_test.include("test_transpose_") -# backend_test.include("test_unsqueeze_") -# backend_test.include("test_where_") +backend_test.exclude("test_sqrt_cpu") +backend_test.exclude("test_sqrt_cuda") +backend_test.exclude("test_sqrt_example") + +backend_test.include("test_sub_") +backend_test.exclude("test_sub_cpu") +backend_test.exclude("test_sub_example") # not supported +backend_test.exclude("test_sub_cuda") # not supported +backend_test.exclude("test_sub_bcast_") # not supported +backend_test.exclude("test_sub_uint8_") # not supported + +backend_test.include("test_transpose_") +backend_test.exclude("test_transpose_") + +backend_test.include("test_unsqueeze_") +backend_test.exclude("test_unsqueeze_") + +backend_test.include("test_where_") +backend_test.exclude("test_where_long") +backend_test.exclude("test_where_example") -# backend_test.exclude(".*cuda.*") +backend_test.exclude(".*cuda.*") # import all test cases at global scope to make them visible to python.unittest globals().update(backend_test.enable_report().test_cases) From fed802e4ed5135c582f6a40e30ed71cfb105433f Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 19 Aug 2023 16:02:14 -0700 Subject: [PATCH 069/232] Fix Reshape --- ggml/contrib/onnx.py | 33 +++++++++++++++++++++++++++------ tests/test_ggml_onnx.py | 2 +- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 0f15a5be..669fe45d 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -117,7 +117,7 @@ def broadcast_shapes( output_shape = tuple( reversed(np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape) - ) # TODO: Fix this + ) # TODO: Fix this a_shaped = a b_shaped = b @@ -176,7 +176,7 @@ def ggml_operator_add( output_name = node.output[0] - a, b = node_inputs + a, b = node_inputs a, b = broadcast_shapes(context, a, b) add_result = ggml.ggml_add( @@ -1063,19 +1063,31 @@ def ggml_operator_reshape( refs: List[Any], ): node_inputs = [tensors_dict[inp] for inp in node.input] - if len(node_inputs) != 2: raise ValueError( f'Error for node "{node.name}": Operation "Reshape" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) + + try: + allowzero_attr = next(attr for attr in node.attribute if attr.name == "allowzero") + allowzero = allowzero_attr.i == 1 + except StopIteration: + allowzero = False + + a = node_inputs[0] b = node_inputs[1] eval_b = backend.eval_tensor(b, context) new_shape = ggml.utils.to_numpy(eval_b).astype(dtype=np.int32) + old_shape = get_tensor_shape(a) + + if not allowzero: + keep_idxs = np.where(new_shape == 0)[0] + new_shape[keep_idxs] = np.array(old_shape)[keep_idxs] - temp_a = np.empty(get_tensor_shape(a), dtype=get_tensor_dtype(a)) + temp_a = np.empty(old_shape, dtype=get_tensor_dtype(a)) x = temp_a.reshape(new_shape) x_t = ggml.utils.from_numpy(x, context) @@ -1412,7 +1424,16 @@ def ggml_operator_where( class GgmlBackendRep(BackendRep): - def __init__(self, graph, weights, weights_buffer, inputs, outputs, ggml_context, ggml_init_params): + def __init__( + self, + graph, + weights, + weights_buffer, + inputs, + outputs, + ggml_context, + ggml_init_params, + ): super(GgmlBackendRep, self).__init__() self.graph = graph self.weights = weights @@ -1436,7 +1457,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: """Run the model with the specified inputs.""" if isinstance(inputs, list): - inputs = {k.name:v for k,v in zip(self.inputs, inputs)} + inputs = {k.name: v for k, v in zip(self.inputs, inputs)} assert isinstance(inputs, dict) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 8a96f728..c2bca990 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -109,7 +109,7 @@ def test_ggml_onnx_runtime_basic(): # backend_test.include("test_range_") # backend_test.include("test_reduce_mean_") # backend_test.include("test_relu_") -# backend_test.include("test_reshape_") +backend_test.include("test_reshape_") # backend_test.include("test_shape") # backend_test.include("test_softmax_") backend_test.include("test_sqrt_") From f299f6942edf8b3d3b0cbb678b41c3e6de0410c3 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 19 Aug 2023 16:14:30 -0700 Subject: [PATCH 070/232] Update GH Actions setup --- .github/workflows/test.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ae964d54..f18f42a0 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -10,7 +10,6 @@ on: jobs: build-linux: - runs-on: ubuntu-latest strategy: matrix: @@ -27,13 +26,12 @@ jobs: - name: Install dependencies run: | python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools - python3 -m pip install --verbose --editable . + python3 -m pip install --verbose --editable .[onnx,onnx-tests] - name: Test with pytest run: | python3 -m pytest build-windows: - runs-on: windows-latest strategy: matrix: @@ -56,7 +54,6 @@ jobs: python3 -m pytest build-macos: - runs-on: macos-latest strategy: matrix: @@ -76,4 +73,4 @@ jobs: python3 -m pip install --verbose --editable . - name: Test with pytest run: | - python3 -m pytest \ No newline at end of file + python3 -m pytest From 709174c5e4f694727bdc8c3d342e52120472f0f7 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 19 Aug 2023 16:17:50 -0700 Subject: [PATCH 071/232] resolve deps --- .github/workflows/test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f18f42a0..ef47f572 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -25,8 +25,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[onnx,onnx-tests] + python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools onnxruntime onnx + python3 -m pip install --verbose --editable . - name: Test with pytest run: | python3 -m pytest From 59c44e46d0cfae13e1ff6ee98ee07bc4fc9db01a Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 19 Aug 2023 16:19:28 -0700 Subject: [PATCH 072/232] add missing test deps --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ef47f572..951c9f27 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -25,7 +25,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools onnxruntime onnx + python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools onnxruntime onnx tabulate pytest-cov pytest-runner python3 -m pip install --verbose --editable . - name: Test with pytest run: | From 47c7c26bcb525442a11ecd5ef579f849024af30b Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 19 Aug 2023 16:55:53 -0700 Subject: [PATCH 073/232] ? --- ggml/contrib/onnx.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 669fe45d..ef0c27af 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1086,6 +1086,7 @@ def ggml_operator_reshape( if not allowzero: keep_idxs = np.where(new_shape == 0)[0] new_shape[keep_idxs] = np.array(old_shape)[keep_idxs] + new_shape = new_shape.copy() temp_a = np.empty(old_shape, dtype=get_tensor_dtype(a)) x = temp_a.reshape(new_shape) From 7d210dd9a5516add086e1d6f2288280adf7af978 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 19 Aug 2023 16:58:02 -0700 Subject: [PATCH 074/232] remove non-fix --- ggml/contrib/onnx.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index ef0c27af..669fe45d 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1086,7 +1086,6 @@ def ggml_operator_reshape( if not allowzero: keep_idxs = np.where(new_shape == 0)[0] new_shape[keep_idxs] = np.array(old_shape)[keep_idxs] - new_shape = new_shape.copy() temp_a = np.empty(old_shape, dtype=get_tensor_dtype(a)) x = temp_a.reshape(new_shape) From b6913c177ac7edcba45b2bba1198b67a61437fe7 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sun, 20 Aug 2023 01:19:46 -0700 Subject: [PATCH 075/232] . --- .github/workflows/test.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 951c9f27..32d4c198 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -25,8 +25,9 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools onnxruntime onnx tabulate pytest-cov pytest-runner - python3 -m pip install --verbose --editable . + python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools + + python3 -m pip install --verbose --editable .[onnx,onnx-runtime] - name: Test with pytest run: | python3 -m pytest @@ -47,8 +48,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools - python3 -m pip install --verbose --editable . + python3 -m pip install --upgrade pip cmake scikit-build setuptools + python3 -m pip install --verbose --editable .[test,onnx,onnx-runtime] - name: Test with pytest run: | python3 -m pytest @@ -57,7 +58,8 @@ jobs: runs-on: macos-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] + # python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 From 4f1e49e8cfd690dbdf6efb117a3d21c853d63dc5 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 21 Aug 2023 13:02:41 -0400 Subject: [PATCH 076/232] Eval node for required operators --- ggml/contrib/onnx.py | 73 ++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index db27ca66..5db21fb2 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -98,22 +98,24 @@ def broadcast_tensor( (ctypes.c_int64 * len(shape))(*shape), ) - # new_tensor = ggml.ggml_repeat( - # ctx, - # tensor, - # new_tensor, - # ) - - if ggml.utils.get_shape(tensor) == (): - ggml.utils.to_numpy(new_tensor)[()] = ggml.utils.to_numpy(tensor) - else: - ggml.utils.to_numpy(new_tensor)[:] = ggml.utils.to_numpy(tensor) + new_tensor = ggml.ggml_repeat( + ctx, + tensor, + new_tensor, + ) + + # if ggml.utils.get_shape(tensor) == (): + # ggml.utils.to_numpy(new_tensor)[()] = ggml.utils.to_numpy(tensor) + # else: + # ggml.utils.to_numpy(new_tensor)[:] = ggml.utils.to_numpy(tensor) return new_tensor def broadcast_shapes( - ctx: ggml.ggml_context_p, a: ggml.ggml_tensor_p, b: ggml.ggml_tensor_p + ctx: ggml.ggml_context_p, + a: ggml.ggml_tensor_p, + b: ggml.ggml_tensor_p, ): a_shape = get_tensor_shape(a) b_shape = get_tensor_shape(b) @@ -345,8 +347,6 @@ def ggml_operator_constant( data_type = tensor.data_type np_data_type = tensor_dtype_to_np_dtype(data_type) - # print(node_attributes) - np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) @@ -433,7 +433,8 @@ def ggml_operator_constant_of_shape( context, ) - shape = ggml.utils.to_numpy(node_inputs[0]) + shape_eval = backend.eval_tensor(node_inputs[0], context) + shape = ggml.utils.to_numpy(shape_eval) x = np.empty(shape, dtype=np_data_type_limit) x_t = ggml.utils.from_numpy(x, context) @@ -940,7 +941,10 @@ def ggml_operator_range( f'Error for node "{node.name}": Operation "Range" requires exactly three inputs. Actual number of inputs: {len(node_inputs)}' ) - tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + tensors_eval = [ + backend.eval_tensor(node_input, context) for node_input in node_inputs + ] + tensors = [ggml.utils.to_numpy(tensor_eval) for tensor_eval in tensors_eval] start, stop, step = tensors output_shape = (int(np.ceil((stop - start) / step)),) @@ -1171,16 +1175,17 @@ def ggml_operator_shape( tensor_shape = get_tensor_shape(node_inputs[0]) tensor_dtype = get_tensor_dtype(node_inputs[0]) - start = ( - ggml.utils.to_numpy(node_inputs[1]) - if len(node_inputs) > 1 - else [ctypes.c_int(0)] - ) - end = ( - ggml.utils.to_numpy(node_inputs[2]) - if len(node_inputs) > 2 - else [ctypes.c_int(tensor_shape[-1])] - ) + + start = [ctypes.c_int(0)] + end = [ctypes.c_int(tensor_shape[-1])] + + if len(node_inputs) > 1: + eval_start = backend.eval_tensor(node_inputs[1], context) + start = ggml.utils.to_numpy(eval_start) + + if len(node_inputs) > 2: + eval_end = backend.eval_tensor(node_inputs[2], context) + end = ggml.utils.to_numpy(eval_end) start = start[0] if len(start) else ctypes.c_int(0) end = end[0] if len(end) else ctypes.c_int(tensor_shape[-1]) @@ -1365,7 +1370,9 @@ def ggml_operator_unsqueeze( x_shape = get_tensor_shape(node_inputs[0]) x_dtype = get_tensor_dtype(node_inputs[0]) - axes = ggml.utils.to_numpy(node_inputs[1]) + + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) for axis in np.nditer(axes): x_shape = np.insert(x_shape, axis, 1) @@ -1509,6 +1516,16 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Build layers for node in model_graph.node: + # print( + # "OP:", + # node.op_type, + # "| NODE:", + # node.name, + # "| IN:", + # node.input, + # "| OUT:", + # node.output[0], + # ) node_output = ggml_operators[node.op_type]( self, node, @@ -1517,6 +1534,10 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: refs, ) + # node_value = ggml.utils.to_numpy(self.eval_tensor(node_output, context)) + # print("OUTPUT_SHAPE:", node_value.shape) + # print() + if node.output[-1] == self.graph.output[-1].name: exit_node = node_output From b0b94c763e8ed6ec01dca595582eaa9347212e76 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 21 Aug 2023 13:22:25 -0400 Subject: [PATCH 077/232] Merge changes from `mrezanvari/main` branch --- ggml/contrib/onnx.py | 235 ++++++++++++++++++---------------------- tests/test_ggml_onnx.py | 217 ++++++++++++++++++++++++++----------- 2 files changed, 254 insertions(+), 198 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 5db21fb2..7748f93e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1,11 +1,14 @@ +"""GGML ONNX backend. + +This module implements a GGML backend for ONNX models and operators. +""" import ctypes -from typing import Any, List, Optional, Tuple +from typing import Any, List, Optional, Tuple, Dict import numpy as np import onnx -from onnx import defs from onnx.backend.base import Backend, BackendRep -from onnx.helper import make_opsetid, tensor_dtype_to_np_dtype +from onnx.helper import tensor_dtype_to_np_dtype from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto import ggml @@ -98,31 +101,29 @@ def broadcast_tensor( (ctypes.c_int64 * len(shape))(*shape), ) - new_tensor = ggml.ggml_repeat( - ctx, - tensor, - new_tensor, - ) + # new_tensor = ggml.ggml_repeat( + # ctx, + # tensor, + # new_tensor, + # ) - # if ggml.utils.get_shape(tensor) == (): - # ggml.utils.to_numpy(new_tensor)[()] = ggml.utils.to_numpy(tensor) - # else: - # ggml.utils.to_numpy(new_tensor)[:] = ggml.utils.to_numpy(tensor) + if ggml.utils.get_shape(tensor) == (): + ggml.utils.to_numpy(new_tensor)[()] = ggml.utils.to_numpy(tensor) + else: + ggml.utils.to_numpy(new_tensor)[:] = ggml.utils.to_numpy(tensor) return new_tensor def broadcast_shapes( - ctx: ggml.ggml_context_p, - a: ggml.ggml_tensor_p, - b: ggml.ggml_tensor_p, + ctx: ggml.ggml_context_p, a: ggml.ggml_tensor_p, b: ggml.ggml_tensor_p ): a_shape = get_tensor_shape(a) b_shape = get_tensor_shape(b) output_shape = tuple( reversed(np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape) - ) + ) # TODO: Fix this a_shaped = a b_shaped = b @@ -135,23 +136,6 @@ def broadcast_shapes( return a_shaped, b_shaped -@ggml.ggml_custom2_op_t -def custom_broadcast( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - context = userdata - tensor_out = ggml.ggml_repeat( - context, - tensor_in_1, - tensor_in_2, - ) - - # ------ Operators ------ @@ -159,7 +143,7 @@ def custom_broadcast( def ggml_operator_abs( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -185,7 +169,7 @@ def ggml_operator_abs( def ggml_operator_add( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -198,8 +182,8 @@ def ggml_operator_add( output_name = node.output[0] - a = node_inputs[0] - b = node_inputs[1] + a, b = node_inputs + a, b = broadcast_shapes(context, a, b) add_result = ggml.ggml_add( context, @@ -230,7 +214,7 @@ def custom_cast( def ggml_operator_cast( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -261,7 +245,7 @@ def ggml_operator_cast( def ggml_operator_concat( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -336,7 +320,7 @@ def custom_constant( def ggml_operator_constant( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -406,7 +390,7 @@ def custom_constant_of_shape( def ggml_operator_constant_of_shape( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -433,8 +417,7 @@ def ggml_operator_constant_of_shape( context, ) - shape_eval = backend.eval_tensor(node_inputs[0], context) - shape = ggml.utils.to_numpy(shape_eval) + shape = ggml.utils.to_numpy(node_inputs[0]) x = np.empty(shape, dtype=np_data_type_limit) x_t = ggml.utils.from_numpy(x, context) @@ -455,7 +438,7 @@ def ggml_operator_constant_of_shape( def ggml_operator_div( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -504,7 +487,7 @@ def custom_gather( def ggml_operator_gather( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -567,7 +550,7 @@ def custom_greater( def ggml_operator_greater( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -622,7 +605,7 @@ def custom_less( def ggml_operator_less( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -659,7 +642,7 @@ def ggml_operator_less( def ggml_operator_log( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -685,7 +668,7 @@ def ggml_operator_log( def ggml_operator_mat_mul( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -743,7 +726,7 @@ def custom_max( def ggml_operator_max( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -796,7 +779,7 @@ def custom_min( def ggml_operator_min( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -835,7 +818,7 @@ def ggml_operator_min( def ggml_operator_mul( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -883,7 +866,7 @@ def custom_pow( def ggml_operator_pow( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -930,7 +913,7 @@ def custom_range( def ggml_operator_range( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -941,10 +924,7 @@ def ggml_operator_range( f'Error for node "{node.name}": Operation "Range" requires exactly three inputs. Actual number of inputs: {len(node_inputs)}' ) - tensors_eval = [ - backend.eval_tensor(node_input, context) for node_input in node_inputs - ] - tensors = [ggml.utils.to_numpy(tensor_eval) for tensor_eval in tensors_eval] + tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] start, stop, step = tensors output_shape = (int(np.ceil((stop - start) / step)),) @@ -1008,7 +988,7 @@ def custom_reduce_mean( def ggml_operator_reduce_mean( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1058,7 +1038,7 @@ def ggml_operator_reduce_mean( def ggml_operator_relu( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1084,7 +1064,7 @@ def ggml_operator_relu( def ggml_operator_reshape( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1162,7 +1142,7 @@ def custom_shape( def ggml_operator_shape( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1175,17 +1155,16 @@ def ggml_operator_shape( tensor_shape = get_tensor_shape(node_inputs[0]) tensor_dtype = get_tensor_dtype(node_inputs[0]) - - start = [ctypes.c_int(0)] - end = [ctypes.c_int(tensor_shape[-1])] - - if len(node_inputs) > 1: - eval_start = backend.eval_tensor(node_inputs[1], context) - start = ggml.utils.to_numpy(eval_start) - - if len(node_inputs) > 2: - eval_end = backend.eval_tensor(node_inputs[2], context) - end = ggml.utils.to_numpy(eval_end) + start = ( + ggml.utils.to_numpy(node_inputs[1]) + if len(node_inputs) > 1 + else [ctypes.c_int(0)] + ) + end = ( + ggml.utils.to_numpy(node_inputs[2]) + if len(node_inputs) > 2 + else [ctypes.c_int(tensor_shape[-1])] + ) start = start[0] if len(start) else ctypes.c_int(0) end = end[0] if len(end) else ctypes.c_int(tensor_shape[-1]) @@ -1217,7 +1196,7 @@ def ggml_operator_shape( def ggml_operator_softmax( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1243,7 +1222,7 @@ def ggml_operator_softmax( def ggml_operator_sqrt( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1269,7 +1248,7 @@ def ggml_operator_sqrt( def ggml_operator_sub( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1281,9 +1260,7 @@ def ggml_operator_sub( ) output_name = node.output[0] - a = node_inputs[0] - b = node_inputs[1] - + a, b = node_inputs a, b = broadcast_shapes(context, a, b) sub_result = ggml.ggml_sub( @@ -1299,7 +1276,7 @@ def ggml_operator_sub( def ggml_operator_transpose( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1357,7 +1334,7 @@ def custom_unsqueeze( def ggml_operator_unsqueeze( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1370,9 +1347,7 @@ def ggml_operator_unsqueeze( x_shape = get_tensor_shape(node_inputs[0]) x_dtype = get_tensor_dtype(node_inputs[0]) - - axes_eval = backend.eval_tensor(node_inputs[1], context) - axes = ggml.utils.to_numpy(axes_eval) + axes = ggml.utils.to_numpy(node_inputs[1]) for axis in np.nditer(axes): x_shape = np.insert(x_shape, axis, 1) @@ -1416,7 +1391,7 @@ def custom_where( def ggml_operator_where( backend: "GgmlBackendRep", node: NodeProto, - tensors_dict: dict, + tensors_dict: Dict[str, ggml.ggml_tensor_p], context: ggml.ggml_context_p, refs: List[Any], ): @@ -1441,8 +1416,24 @@ def ggml_operator_where( class GgmlBackendRep(BackendRep): - def __init__(self): + def __init__( + self, + graph, + weights, + weights_buffer, + inputs, + outputs, + ggml_context, + ggml_init_params, + ): super(GgmlBackendRep, self).__init__() + self.graph = graph + self.weights = weights + self.weights_buffer = weights_buffer + self.inputs = inputs + self.outputs = outputs + self.ggml_context = ggml_context + self.ggml_init_params = ggml_init_params def __del__(self): if hasattr(self, "ggml_context"): @@ -1455,9 +1446,12 @@ def eval_tensor(self, tensor: ggml.ggml_tensor_p, context: ggml.ggml_context_p): return tensor def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: - """Abstract function.""" + """Run the model with the specified inputs.""" + + if isinstance(inputs, list): + inputs = {k.name: v for k, v in zip(self.inputs, inputs)} - # check: data is should be on CPU + assert isinstance(inputs, dict) model_graph = self.graph exit_node = None @@ -1573,54 +1567,24 @@ def prepare(cls, model: ModelProto, device="CPU", **kwargs): """ super(GgmlRuntimeBackend, cls).prepare(model, device, **kwargs) - ggml_rep = cls.onnx_model_to_ggml_rep(model, **kwargs) - - return ggml_rep - - @classmethod - def onnx_model_to_ggml_rep(cls, model: ModelProto, **kwargs): - """Convert ONNX model to GgmlRep. - - :param model: ONNX ModelProto object. - and the converted tensorflow model. - :return: GgmlRep object. - """ - - # Models with IR_VERSION less than 3 does not have opset_import set. - # We default to minimum opset, this behavior is consistent with - # onnx checker. - # c.f. https://github.com/onnx/onnx/blob/427ac0c1b792363d373e3d7e4eef97fa46458420/onnx/checker.cc#L478 - if model.ir_version < 3: - opset_import = [make_opsetid(defs.ONNX_DOMAIN, 1)] - else: - opset_import = model.opset_import - - return cls._onnx_graph_to_ggml_rep(model.graph, opset_import, **kwargs) - - @classmethod - def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): - ggml_backend_rep = GgmlBackendRep() - ggml_backend_rep.graph = graph_def - + graph = model.graph weights = {} - n_tensors = len(graph_def.initializer) + n_tensors = len(graph.initializer) init_params = ggml.ggml_init_params( mem_size=n_tensors * ggml.ggml_tensor_overhead(), no_alloc=True, ) context = ggml.ggml_init(init_params) - ggml_backend_rep.ggml_context = context - ggml_backend_rep.ggml_init_params = init_params total_nbytes = 0 pairs = [] - for initializer in graph_def.initializer: + for initializer in graph.initializer: name = initializer.name np_array = onnx.numpy_helper.to_array(initializer) - if can_quantize(np_array, name, graph_def): + if can_quantize(np_array, name, graph): ggml_qtype = ggml.utils.GGML_TYPE.Q8_0 shape = tuple(reversed(np_array.shape)) tensor = ggml.ggml_new_tensor( @@ -1649,8 +1613,8 @@ def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): np_array = onnx.numpy_helper.to_array(initializer) if ggml.ggml_is_quantized(tensor.contents.type): - np_c_float_data = ctypes.cast( - np_array.ctypes.data, ctypes.POINTER(ctypes.c_float) + np_c_float_data = (ctypes.c_float * np_array.size).from_address( + ctypes.addressof(np_array.ctypes.data) ) ggml.utils.quantize_0( @@ -1668,15 +1632,20 @@ def _onnx_graph_to_ggml_rep(cls, graph_def: GraphProto, opset, **kwargs): offset += nbytes - ggml_backend_rep.ggml_buffer = buffer - ggml_backend_rep.weights = weights - ggml_backend_rep.inputs = graph_def.input - ggml_backend_rep.outputs = graph_def.output - - return ggml_backend_rep + return GgmlBackendRep( + graph=graph, + weights=weights, + weights_buffer=buffer, + inputs=graph.input, + outputs=graph.output, + ggml_context=context, + ggml_init_params=init_params, + ) @classmethod - def run_model(cls, model, inputs, device=None, **kwargs): + def run_model( + cls, model: ModelProto, inputs: Any, device=None, **kwargs + ) -> Tuple[Any, ...]: """ Compute the prediction. @@ -1693,7 +1662,9 @@ def run_model(cls, model, inputs, device=None, **kwargs): return rep.run(inputs, **kwargs) @classmethod - def run_node(cls, node, inputs, device=None, outputs_info=None, **kwargs): + def run_node( + cls, node: NodeProto, inputs: Any, device=None, outputs_info=None, **kwargs + ) -> Tuple[Any, ...]: """ This method is not implemented as it is much more efficient to run a whole model than every node independently. diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index bc7c0ddb..c4130b6a 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -2,17 +2,17 @@ import numpy as np import onnx -from onnx import TensorProto, helper -from onnxruntime import InferenceSession -from transformers import AutoTokenizer -from InstructorEmbedding import INSTRUCTOR +from onnx import helper +from onnx.onnx_pb import TensorProto + +import onnx.backend.test + +from onnxruntime import InferenceSession # type: ignore from ggml.contrib.onnx import GgmlRuntimeBackend -import torch def test_ggml_onnx_runtime_basic(): - # return # The name of the input tensor input_name = "X" @@ -87,63 +87,148 @@ def test_ggml_onnx_runtime_basic(): assert ggml_result == runtime_result -def test_ggml_onnx_qweights(): - class MatMulModel(torch.nn.Module): - def __init__(self): - super(MatMulModel, self).__init__() - self.weight = torch.nn.Parameter( - torch.tensor( - [[2.001034010, 1.00103040134], [0.1341415, 3.0001341340]], - dtype=torch.float32, - ) - ) - - def forward(self, x): - return torch.matmul(x, self.weight) - - model = MatMulModel() - input_data = torch.tensor( - [[1.0187673849, 2.23652460], [3.42562560, -4.024562465]], dtype=torch.float32 - ) - - f = io.BytesIO() - torch.onnx.export(model, input_data, f, input_names=["x"], output_names=["output"]) - f.seek(0) - - onnx_model = onnx.load_model(f) - session = InferenceSession(f.getvalue()) - input_name = session.get_inputs()[0].name - input_feed = {input_name: input_data.numpy()} - - runtime_result = session.run(None, input_feed)[0] - - ggml_dummy_model = GgmlRuntimeBackend.prepare(onnx_model) - ggml_result = ggml_dummy_model.run(input_feed)[0] - assert np.allclose(ggml_result, runtime_result) - - -def test_ggml_onnx_runtime_instructor(): - # return - instructor_model = INSTRUCTOR("hkunlp/instructor-base") - - onnx_instructor_model = onnx.load("instructor_base_onnx/encoder_model.onnx") - ggml_onnx_instructor_model = GgmlRuntimeBackend.prepare(onnx_instructor_model) - - instructor_tokenizer = AutoTokenizer.from_pretrained("t5-large") - - sentence = "This is a sentence" - instruction = "Represent the follwing sentence:" - - sentence_tokens = instructor_tokenizer.encode( - [instruction, sentence], return_tensors="np" - ) - - input_data = { - "input_ids": sentence_tokens, - "attention_mask": [np.ones(sentence_tokens.shape[1])], - } - - instructor_output = instructor_model.encode([[instruction, sentence]]) - ggml_output = ggml_onnx_instructor_model.run(input_data) - - assert instructor_output == ggml_output +# This is a pytest magic variable to load extra plugins +pytest_plugins = ("onnx.backend.test.report",) + +backend_test = onnx.backend.test.BackendTest(GgmlRuntimeBackend, __name__) + +backend_test.include("test_abs_") + +backend_test.include("test_add_") +backend_test.exclude("test_add_uint8_") # not supported + +backend_test.include("test_cast_") + +backend_test.include("test_concat_") + +backend_test.include("test_constant_") + +backend_test.include("test_div_") + +backend_test.exclude("test_div_uint8_") # not supported + +backend_test.include("test_gather_") +backend_test.exclude("test_gather_2d") +backend_test.exclude("test_gather_elements") +backend_test.exclude("test_gather_negative") + +backend_test.include("test_greater_") +backend_test.exclude("test_greater_bcast") +backend_test.exclude("test_greater_equal") + +backend_test.include("test_less_") +backend_test.exclude("test_less_") +backend_test.exclude("test_less_bcast") +backend_test.exclude("test_less_cuda") +backend_test.exclude("test_less_equal_") + +backend_test.include("test_log_") +backend_test.exclude("test_log_") + +backend_test.include("test_matmul_") +backend_test.exclude("test_matmul_") + +backend_test.include("test_max_") +backend_test.exclude("test_max_one") +backend_test.exclude("test_max_two") +backend_test.exclude("test_max_float16") +backend_test.exclude("test_max_float32") +backend_test.exclude("test_max_float64") +backend_test.exclude("test_max_int8") +backend_test.exclude("test_max_int16") +backend_test.exclude("test_max_int32") +backend_test.exclude("test_max_int64") +backend_test.exclude("test_max_uint") +backend_test.exclude("test_max_example") + +backend_test.include("test_min_") +backend_test.exclude("test_min_one") +backend_test.exclude("test_min_two") +backend_test.exclude("test_min_float16") +backend_test.exclude("test_min_float32") +backend_test.exclude("test_min_float64") +backend_test.exclude("test_min_int8") +backend_test.exclude("test_min_int16") +backend_test.exclude("test_min_int32") +backend_test.exclude("test_min_int64") +backend_test.exclude("test_min_uint") +backend_test.exclude("test_min_example") + +backend_test.include("test_mul_") +backend_test.exclude("test_mul_") +backend_test.exclude("test_mul_bcast") +backend_test.exclude("test_mul_example") +backend_test.exclude("test_mul_uint8") + +backend_test.include("test_pow_") +backend_test.exclude("test_pow_") +backend_test.exclude("test_pow_types") +backend_test.exclude("test_pow_types_int64") +backend_test.exclude("test_pow_types_int64") + +backend_test.include("test_range_") +backend_test.exclude("test_range_float") +backend_test.exclude("test_range_int32") + +backend_test.include("test_reduce_mean_") +backend_test.exclude("test_reduce_mean_default") +backend_test.exclude("test_reduce_mean_do_not_keepdims") +backend_test.exclude("test_reduce_mean_keepdims") +backend_test.exclude("test_reduce_mean_negative_axes") + +backend_test.include("test_relu_") +backend_test.exclude("test_relu_") +backend_test.exclude("test_relu_expanded") + +backend_test.include("test_reshape_") +backend_test.exclude("test_reshape_allowzero") +backend_test.exclude("test_reshape_negative") +backend_test.exclude("test_reshape_one_dim") +backend_test.exclude("test_reshape_reduced") +backend_test.exclude("test_reshape_reordered") +backend_test.exclude("test_reshape_zero") +backend_test.exclude("test_reshape_extended") + +backend_test.include("test_shape_") +backend_test.exclude("test_shape_cpu") +backend_test.exclude("test_shape_cuda") +backend_test.exclude("test_shape_clip") +backend_test.exclude("test_shape_start") +backend_test.exclude("test_shape_end") +backend_test.exclude("test_shape_example") + +backend_test.include("test_softmax_") +backend_test.exclude("test_softmax_axis") +backend_test.exclude("test_softmax_default_axis") +backend_test.exclude("test_softmax_example") +backend_test.exclude("test_softmax_large_number") +backend_test.exclude("test_softmax_negative_axis") +backend_test.exclude("test_softmax_functional") +backend_test.exclude("test_softmax_lastdim") + +backend_test.include("test_sqrt_") +backend_test.exclude("test_sqrt_cpu") +backend_test.exclude("test_sqrt_cuda") +backend_test.exclude("test_sqrt_example") + +backend_test.include("test_sub_") +backend_test.exclude("test_sub_cpu") +backend_test.exclude("test_sub_example") # not supported +backend_test.exclude("test_sub_cuda") # not supported +backend_test.exclude("test_sub_bcast_") # not supported +backend_test.exclude("test_sub_uint8_") # not supported + +backend_test.include("test_transpose_") +backend_test.exclude("test_transpose_") + +backend_test.include("test_unsqueeze_") +backend_test.exclude("test_unsqueeze_") + +backend_test.include("test_where_") +backend_test.exclude("test_where_long") +backend_test.exclude("test_where_example") + +backend_test.exclude(".*cuda.*") + +# import all test cases at global scope to make them visible to python.unittest +globals().update(backend_test.enable_report().test_cases) From 7b33a4a0c75d9c8f042c4ecd0238d45e43a9ad98 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 21 Aug 2023 14:43:34 -0400 Subject: [PATCH 078/232] Fix test cases --- tests/test_ggml_onnx_ops.py | 280 +++++++++++++++++++++++++++++++++--- 1 file changed, 260 insertions(+), 20 deletions(-) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index fb26cadd..5fe2c5ff 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -70,7 +70,19 @@ def test_ggml_onnx_runtime_shape_operator(): for shape_node in nodes: output_tensor = ggml_operators["Shape"]( - GgmlBackendRep(), shape_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + shape_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -164,12 +176,36 @@ def forward(self, input): with pytest.raises(ValueError) as ex_input_error: ggml_operators["Unsqueeze"]( - GgmlBackendRep(), unsqueeze_node1, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + unsqueeze_node1, + tensors_dict, + context, + refs, ) for shape_node in nodes: output_tensor = ggml_operators["Unsqueeze"]( - GgmlBackendRep(), shape_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + shape_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) @@ -281,7 +317,19 @@ def onnx_gather(x, indices, axis): refs = [] output_tensor = ggml_operators["Gather"]( - GgmlBackendRep(), gather_node2, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + gather_node2, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) @@ -368,7 +416,19 @@ def onnx_constant(value, dtype, shape): for shape_node in nodes: output_tensor = ggml_operators["Constant"]( - GgmlBackendRep(), shape_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + shape_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -446,7 +506,19 @@ def onnx_constant_of_shape(value, other): for shape_node in nodes: output_tensor = ggml_operators["ConstantOfShape"]( - GgmlBackendRep(), shape_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + shape_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -557,7 +629,19 @@ def onnx_concat(inputs, axis): for concat_node in nodes: output_tensor = ggml_operators["Concat"]( - GgmlBackendRep(), concat_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + concat_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -632,7 +716,19 @@ def forward(self, x): for reshape_node in nodes: output_tensor = ggml_operators["Reshape"]( - GgmlBackendRep(), reshape_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + reshape_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -757,7 +853,19 @@ def forward(self, input): for reducemean_node in nodes: output_tensor = ggml_operators["ReduceMean"]( - GgmlBackendRep(), reducemean_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + reducemean_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -829,7 +937,19 @@ def forward(self, input1, input2): for less_node in nodes: output_tensor = ggml_operators["Less"]( - GgmlBackendRep(), less_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + less_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -896,7 +1016,19 @@ def forward(self, input1, input2): ) output_tensor = ggml_operators["Greater"]( - GgmlBackendRep(), greater_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + greater_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -959,7 +1091,19 @@ def forward(self, input1): ) output_tensor = ggml_operators["Min"]( - GgmlBackendRep(), min_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + min_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -1020,7 +1164,19 @@ def forward(self, input1): ) output_tensor = ggml_operators["Max"]( - GgmlBackendRep(), min_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + min_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -1095,7 +1251,19 @@ def onnx_matmul(x, y): ) output_tensor = ggml_operators["MatMul"]( - GgmlBackendRep(), matmul_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + matmul_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -1166,7 +1334,19 @@ def forward(self, input1, input2): for pow_node in nodes: output_tensor = ggml_operators["Pow"]( - GgmlBackendRep(), pow_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + pow_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -1233,7 +1413,19 @@ def forward(self, input): for relu_node in nodes: output_tensor = ggml_operators["Relu"]( - GgmlBackendRep(), relu_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + relu_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -1308,7 +1500,19 @@ def onnx_transpose(x, perm=[1, 0]): onnx_result = onnx_transpose(input_array, permutation) output_tensor = ggml_operators["Transpose"]( - GgmlBackendRep(), transpose_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + transpose_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -1397,7 +1601,19 @@ def onnx_range(start, limit, delta): ) output_tensor = ggml_operators["Range"]( - GgmlBackendRep(), range_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + range_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -1460,7 +1676,19 @@ def forward(self, input): ) output_tensor = ggml_operators["Cast"]( - GgmlBackendRep(), cast_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + cast_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) @@ -1534,7 +1762,19 @@ def forward(self, condition, x, y): ) output_tensor = ggml_operators["Where"]( - GgmlBackendRep(), where_node, tensors_dict, context, refs + GgmlBackendRep( + graph=None, + weights=None, + weights_buffer=None, + inputs=None, + outputs=None, + ggml_context=None, + ggml_init_params=None, + ), + where_node, + tensors_dict, + context, + refs, ) gf = ggml.ggml_build_forward(output_tensor) ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) From ce7192a59520da54668b57dd080c6815ff4f72b1 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 21 Aug 2023 15:41:49 -0400 Subject: [PATCH 079/232] Exclude `Pad` operator tests --- tests/test_ggml_onnx.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index c4130b6a..4f14ef85 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -95,7 +95,7 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_abs_") backend_test.include("test_add_") -backend_test.exclude("test_add_uint8_") # not supported +backend_test.exclude("test_add_uint8_") # not supported backend_test.include("test_cast_") @@ -105,7 +105,7 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_div_") -backend_test.exclude("test_div_uint8_") # not supported +backend_test.exclude("test_div_uint8_") # not supported backend_test.include("test_gather_") backend_test.exclude("test_gather_2d") @@ -213,10 +213,10 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_sub_") backend_test.exclude("test_sub_cpu") -backend_test.exclude("test_sub_example") # not supported -backend_test.exclude("test_sub_cuda") # not supported -backend_test.exclude("test_sub_bcast_") # not supported -backend_test.exclude("test_sub_uint8_") # not supported +backend_test.exclude("test_sub_example") # not supported +backend_test.exclude("test_sub_cuda") # not supported +backend_test.exclude("test_sub_bcast_") # not supported +backend_test.exclude("test_sub_uint8_") # not supported backend_test.include("test_transpose_") backend_test.exclude("test_transpose_") @@ -229,6 +229,7 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_where_example") backend_test.exclude(".*cuda.*") +backend_test.exclude(".*pad.*") # import all test cases at global scope to make them visible to python.unittest globals().update(backend_test.enable_report().test_cases) From 5f4120cdf32ae83ac6d00874575bafefc723ef30 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 21 Aug 2023 16:21:29 -0400 Subject: [PATCH 080/232] Fix Cast --- ggml/contrib/onnx.py | 69 ++++++++++++++++++++++------------------- tests/test_ggml_onnx.py | 3 ++ 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 7748f93e..2148f226 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -30,9 +30,10 @@ def inner(func): def map_to_ggml_type(dtype: np.dtype): + np_data_type_limit = np.dtype(str(dtype).replace("64", "32")) ggml_type = ggml.utils.NUMPY_DTYPE_TO_GGML_TYPE.get( - dtype.type, - ggml.utils.GGML_TYPE.I32, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 + np_data_type_limit.type, + ggml.GGML_FTYPE_UNKNOWN, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 ) return ggml_type @@ -101,16 +102,16 @@ def broadcast_tensor( (ctypes.c_int64 * len(shape))(*shape), ) - # new_tensor = ggml.ggml_repeat( - # ctx, - # tensor, - # new_tensor, - # ) + new_tensor = ggml.ggml_repeat( + ctx, + tensor, + new_tensor, + ) - if ggml.utils.get_shape(tensor) == (): - ggml.utils.to_numpy(new_tensor)[()] = ggml.utils.to_numpy(tensor) - else: - ggml.utils.to_numpy(new_tensor)[:] = ggml.utils.to_numpy(tensor) + # if ggml.utils.get_shape(tensor) == (): + # ggml.utils.to_numpy(new_tensor)[()] = ggml.utils.to_numpy(tensor) + # else: + # ggml.utils.to_numpy(new_tensor)[:] = ggml.utils.to_numpy(tensor) return new_tensor @@ -194,16 +195,17 @@ def ggml_operator_add( return add_result -@ggml.ggml_custom1_op_t +@ggml.ggml_custom2_op_t def custom_cast( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, ith: int, nth: int, userdata: Optional[ctypes.c_void_p], ): dtype = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value - tensor = ggml.utils.to_numpy(tensor_in_1) + tensor = ggml.utils.to_numpy(tensor_in_2) np_data_type = tensor_dtype_to_np_dtype(dtype) np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) @@ -228,9 +230,17 @@ def ggml_operator_cast( onnx_type = next(attr.i for attr in node.attribute if attr.name == "to") onnx_type_c = ctypes.c_int(onnx_type) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + a = node_inputs[0] + np_data_type = tensor_dtype_to_np_dtype(onnx_type) + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + x = np.empty(get_tensor_shape(a), dtype=np_data_type_limit) + + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( context, - node_inputs[0], + x_t, + a, custom_cast, 1, ctypes.pointer(onnx_type_c), @@ -1493,8 +1503,9 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Create the input tensors with the correct type/shape ggml_type = map_to_ggml_type(input_data.dtype) - shape = tuple(reversed(input_data.shape)) + + context tensor = ggml.ggml_new_tensor( context, ggml_type.value, @@ -1510,17 +1521,11 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Build layers for node in model_graph.node: - # print( - # "OP:", - # node.op_type, - # "| NODE:", - # node.name, - # "| IN:", - # node.input, - # "| OUT:", - # node.output[0], - # ) - node_output = ggml_operators[node.op_type]( + operator_func = ggml_operators.get(node.op_type) + if operator_func is None: + raise NotImplementedError(f'Operator "{node.op_type}" not implemented') + + node_output = operator_func( self, node, ggml_tensors, @@ -1528,10 +1533,6 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: refs, ) - # node_value = ggml.utils.to_numpy(self.eval_tensor(node_output, context)) - # print("OUTPUT_SHAPE:", node_value.shape) - # print() - if node.output[-1] == self.graph.output[-1].name: exit_node = node_output @@ -1541,7 +1542,11 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Compute graph ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - graph_output = ggml.utils.to_numpy(exit_node) + graph_output = ggml.utils.to_numpy( + exit_node + ) # TODO: Add checks to convert values back to bool or etc types + + ggml.ggml_free(context) return [graph_output] diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 4f14ef85..e63d1228 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -230,6 +230,9 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude(".*cuda.*") backend_test.exclude(".*pad.*") +backend_test.exclude( + ".*greater.*" +) # FIXME: values are correct dtypes are not bool != int32 # import all test cases at global scope to make them visible to python.unittest globals().update(backend_test.enable_report().test_cases) From baf9edaf083a0f30888da9093871afa1349213e1 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 21 Aug 2023 17:06:00 -0400 Subject: [PATCH 081/232] Include new tests --- tests/test_ggml_onnx.py | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index e63d1228..b9234502 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -123,10 +123,9 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_less_equal_") backend_test.include("test_log_") -backend_test.exclude("test_log_") +backend_test.exclude("test_log_softmax_*") backend_test.include("test_matmul_") -backend_test.exclude("test_matmul_") backend_test.include("test_max_") backend_test.exclude("test_max_one") @@ -155,13 +154,10 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_min_example") backend_test.include("test_mul_") -backend_test.exclude("test_mul_") -backend_test.exclude("test_mul_bcast") -backend_test.exclude("test_mul_example") backend_test.exclude("test_mul_uint8") backend_test.include("test_pow_") -backend_test.exclude("test_pow_") +backend_test.exclude("test_pow_bcast") backend_test.exclude("test_pow_types") backend_test.exclude("test_pow_types_int64") backend_test.exclude("test_pow_types_int64") @@ -177,25 +173,19 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_reduce_mean_negative_axes") backend_test.include("test_relu_") -backend_test.exclude("test_relu_") backend_test.exclude("test_relu_expanded") backend_test.include("test_reshape_") backend_test.exclude("test_reshape_allowzero") -backend_test.exclude("test_reshape_negative") -backend_test.exclude("test_reshape_one_dim") -backend_test.exclude("test_reshape_reduced") -backend_test.exclude("test_reshape_reordered") backend_test.exclude("test_reshape_zero") -backend_test.exclude("test_reshape_extended") backend_test.include("test_shape_") backend_test.exclude("test_shape_cpu") backend_test.exclude("test_shape_cuda") -backend_test.exclude("test_shape_clip") -backend_test.exclude("test_shape_start") -backend_test.exclude("test_shape_end") -backend_test.exclude("test_shape_example") +# backend_test.exclude("test_shape_clip") +# backend_test.exclude("test_shape_start") +# backend_test.exclude("test_shape_end") +# backend_test.exclude("test_shape_example") backend_test.include("test_softmax_") backend_test.exclude("test_softmax_axis") @@ -207,13 +197,13 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_softmax_lastdim") backend_test.include("test_sqrt_") -backend_test.exclude("test_sqrt_cpu") +# backend_test.exclude("test_sqrt_cpu") backend_test.exclude("test_sqrt_cuda") -backend_test.exclude("test_sqrt_example") +# backend_test.exclude("test_sqrt_example") backend_test.include("test_sub_") -backend_test.exclude("test_sub_cpu") -backend_test.exclude("test_sub_example") # not supported +# backend_test.exclude("test_sub_cpu") +# backend_test.exclude("test_sub_example") # not supported backend_test.exclude("test_sub_cuda") # not supported backend_test.exclude("test_sub_bcast_") # not supported backend_test.exclude("test_sub_uint8_") # not supported @@ -233,6 +223,7 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude( ".*greater.*" ) # FIXME: values are correct dtypes are not bool != int32 +backend_test.exclude(".*FLOAT*E*M*.*") # import all test cases at global scope to make them visible to python.unittest globals().update(backend_test.enable_report().test_cases) From 8183f35a918069ac3d9e104064e0880d54ae2583 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 22 Aug 2023 13:51:26 -0400 Subject: [PATCH 082/232] Fix Constant, MatMul, Shape, Less and Greater ops --- ggml/contrib/onnx.py | 148 +++++++++++++++++++--------------------- tests/test_ggml_onnx.py | 18 +---- 2 files changed, 72 insertions(+), 94 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 2148f226..4adbb00a 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3,7 +3,8 @@ This module implements a GGML backend for ONNX models and operators. """ import ctypes -from typing import Any, List, Optional, Tuple, Dict +import re +from typing import Any, Dict, List, Optional, Tuple import numpy as np import onnx @@ -117,7 +118,9 @@ def broadcast_tensor( def broadcast_shapes( - ctx: ggml.ggml_context_p, a: ggml.ggml_tensor_p, b: ggml.ggml_tensor_p + ctx: ggml.ggml_context_p, + a: ggml.ggml_tensor_p, + b: ggml.ggml_tensor_p, ): a_shape = get_tensor_shape(a) b_shape = get_tensor_shape(b) @@ -137,6 +140,19 @@ def broadcast_shapes( return a_shaped, b_shaped +def get_final_dtype(tensor: ggml.ggml_tensor_p, pattern: str = r"<(.*?)>"): + tensor_name = tensor.contents.name.decode() + tensor_dtype = get_tensor_dtype(tensor) + + match = re.search(pattern, tensor_name) + + if match: + dtype_str = match.group(1) + tensor_dtype = np.dtype(dtype_str) + + return tensor_dtype + + # ------ Operators ------ @@ -335,15 +351,20 @@ def ggml_operator_constant( refs: List[Any], ): node_attributes = node.attribute + name = node.output[0] value_attr = next(attr for attr in node_attributes if attr.name == "value") tensor = value_attr.t data_type = tensor.data_type np_data_type = tensor_dtype_to_np_dtype(data_type) - np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) - data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) + if tensor.raw_data: + data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) + elif tensor.float_data: + data_value = np.array(tensor.float_data, dtype=np_data_type) + else: + raise ValueError("Data field not found.") data_tensor = ggml.utils.from_numpy( data_value.astype(np_data_type_limit), @@ -377,6 +398,7 @@ def ggml_operator_constant( None, ) + ggml.ggml_set_name(new_tensor, (name + f"<{np_data_type}>").encode()) return new_tensor @@ -574,13 +596,14 @@ def ggml_operator_greater( a_shape = get_tensor_shape(node_inputs[0]) a_dtype = get_tensor_dtype(node_inputs[0]) b_shape = get_tensor_shape(node_inputs[1]) + name = node.output[0] output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) x_t = ggml.utils.from_numpy(x, context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( context, x_t, node_inputs[0], @@ -590,6 +613,8 @@ def ggml_operator_greater( None, ) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) + return new_tensor @@ -629,13 +654,14 @@ def ggml_operator_less( a_shape = get_tensor_shape(node_inputs[0]) a_dtype = get_tensor_dtype(node_inputs[0]) b_shape = get_tensor_shape(node_inputs[1]) + name = node.output[0] output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) x_t = ggml.utils.from_numpy(x, context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( context, x_t, node_inputs[0], @@ -645,6 +671,8 @@ def ggml_operator_less( None, ) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) + return new_tensor @@ -690,16 +718,28 @@ def ggml_operator_mat_mul( ) output_name = node.output[0] - a = node_inputs[0] - b = node_inputs[1] + a, b = node_inputs + b_shape = get_tensor_shape(b) + a_shape = get_tensor_shape(a) - a, b = broadcast_shapes(context, a, b) + # TODO: is this check required? broadcast alone wont pass ONNX tests but is broadcasting itself even required or should it fail if a,b are not correct? + try: + np.matmul(np.empty(a_shape), np.empty(b_shape)) + except: + a, b = broadcast_shapes(context, a, b) - b_shape = get_tensor_shape(b) b_dtype = get_tensor_dtype(b) + + b_permute = ggml.ggml_transpose( + context, + b, + ) + + b_shape = ggml.utils.get_shape(b_permute) + b_transposed = ggml.ggml_cpy( context, - ggml.ggml_transpose(context, b), + b_permute, ggml.ggml_new_tensor( context, map_to_ggml_type(b_dtype).value, @@ -1122,32 +1162,6 @@ def custom_reshape( return new_tensor -class ShapeUserData(ctypes.Structure): - _fields_ = [("start", ctypes.c_int), ("end", ctypes.c_int)] - - -@ggml.ggml_custom2_op_t -def custom_shape( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ShapeUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - start = userdata_data.start - end = userdata_data.end - - shaped_tensor = tensor[start:end] - tensor_shape = np.array(shaped_tensor.shape, dtype=np.int32) - - set_tensor_out(tensor_out, tensor_shape) - - @ggml_operator("Shape") def ggml_operator_shape( backend: "GgmlBackendRep", @@ -1158,46 +1172,22 @@ def ggml_operator_shape( ): node_inputs = [tensors_dict[inp] for inp in node.input] - if len(node_inputs) == 0 or len(node_inputs) > 3: + if len(node_inputs) != 1: raise ValueError( - f'Error for node "{node.name}": Operation "Shape" requires at least 1 and maximum of 3 inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Shape" requires exactly one input. Actual number of inputs: {len(node_inputs)}' ) - tensor_shape = get_tensor_shape(node_inputs[0]) - tensor_dtype = get_tensor_dtype(node_inputs[0]) - start = ( - ggml.utils.to_numpy(node_inputs[1]) - if len(node_inputs) > 1 - else [ctypes.c_int(0)] - ) - end = ( - ggml.utils.to_numpy(node_inputs[2]) - if len(node_inputs) > 2 - else [ctypes.c_int(tensor_shape[-1])] - ) - - start = start[0] if len(start) else ctypes.c_int(0) - end = end[0] if len(end) else ctypes.c_int(tensor_shape[-1]) - - shape_userdata = ShapeUserData(start, end) - userdata_p = ctypes.cast(ctypes.pointer(shape_userdata), ctypes.c_void_p) - - output_shape = len(list(tensor_shape)) - - x = np.empty(output_shape, dtype=tensor_dtype) - - x_t = ggml.utils.from_numpy(x, context) - - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, - x_t, - node_inputs[0], - custom_shape, - 1, - userdata_p, + tensor_shape = np.array(get_tensor_shape(node_inputs[0]), dtype=np.int32) + name = node.output[0] + start = next((attr.i for attr in node.attribute if attr.name == "start"), None) + end = next( + (attr.i for attr in node.attribute if attr.name == "end"), + None, ) + shape_slice = tensor_shape[start:end] + new_tensor = tensors_dict[name] = ggml.utils.from_numpy(shape_slice, context) - refs.append(shape_userdata) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) return new_tensor @@ -1301,19 +1291,19 @@ def ggml_operator_transpose( x = node_inputs[0] input_shape = get_tensor_shape(x) - perm_map = {2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} + perm_map = {1: [0, 1, 2, 3], 2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} perm_attr = next((attr for attr in node.attribute if attr.name == "perm"), None) # add special case and -> fix me comments if perm_attr is None: - perm = perm_map.get(len(input_shape), [1, 0, 2, 3]) + perms = perm_map.get(len(input_shape), [1, 0, 2, 3]) else: - perm = list(perm_attr.ints) - perm += [0, 1, 2, 3][len(perm) :] + perms = list(perm_attr.ints) + perms += [0, 1, 2, 3][len(perms) :] - ax0, ax1, ax2, ax3 = perm + ax0, ax1, ax2, ax3 = perms transpose_result = ggml.ggml_permute(context, x, ax0, ax1, ax2, ax3) @@ -1541,10 +1531,12 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Compute graph ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - graph_output = ggml.utils.to_numpy( exit_node ) # TODO: Add checks to convert values back to bool or etc types + graph_output = graph_output.astype( + get_final_dtype(exit_node) + ) # TODO: add a second dict to keep track of types and use that instead ggml.ggml_free(context) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index b9234502..2edaa412 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -108,16 +108,14 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_div_uint8_") # not supported backend_test.include("test_gather_") -backend_test.exclude("test_gather_2d") backend_test.exclude("test_gather_elements") -backend_test.exclude("test_gather_negative") backend_test.include("test_greater_") backend_test.exclude("test_greater_bcast") +backend_test.exclude("test_greater_cuda") backend_test.exclude("test_greater_equal") backend_test.include("test_less_") -backend_test.exclude("test_less_") backend_test.exclude("test_less_bcast") backend_test.exclude("test_less_cuda") backend_test.exclude("test_less_equal_") @@ -180,12 +178,7 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_reshape_zero") backend_test.include("test_shape_") -backend_test.exclude("test_shape_cpu") backend_test.exclude("test_shape_cuda") -# backend_test.exclude("test_shape_clip") -# backend_test.exclude("test_shape_start") -# backend_test.exclude("test_shape_end") -# backend_test.exclude("test_shape_example") backend_test.include("test_softmax_") backend_test.exclude("test_softmax_axis") @@ -197,19 +190,15 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_softmax_lastdim") backend_test.include("test_sqrt_") -# backend_test.exclude("test_sqrt_cpu") backend_test.exclude("test_sqrt_cuda") -# backend_test.exclude("test_sqrt_example") backend_test.include("test_sub_") -# backend_test.exclude("test_sub_cpu") -# backend_test.exclude("test_sub_example") # not supported backend_test.exclude("test_sub_cuda") # not supported backend_test.exclude("test_sub_bcast_") # not supported backend_test.exclude("test_sub_uint8_") # not supported backend_test.include("test_transpose_") -backend_test.exclude("test_transpose_") +# backend_test.exclude("test_transpose_") backend_test.include("test_unsqueeze_") backend_test.exclude("test_unsqueeze_") @@ -220,9 +209,6 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude(".*cuda.*") backend_test.exclude(".*pad.*") -backend_test.exclude( - ".*greater.*" -) # FIXME: values are correct dtypes are not bool != int32 backend_test.exclude(".*FLOAT*E*M*.*") # import all test cases at global scope to make them visible to python.unittest From 2cdb2f32e0c3c0c13894812b961b3dae42ce8db0 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 22 Aug 2023 16:42:42 -0400 Subject: [PATCH 083/232] Fix Transpose, add new tests --- ggml/contrib/onnx.py | 17 ++++++++++++++--- tests/test_ggml_onnx.py | 4 +--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 4adbb00a..15da8d7e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -34,7 +34,7 @@ def map_to_ggml_type(dtype: np.dtype): np_data_type_limit = np.dtype(str(dtype).replace("64", "32")) ggml_type = ggml.utils.NUMPY_DTYPE_TO_GGML_TYPE.get( np_data_type_limit.type, - ggml.GGML_FTYPE_UNKNOWN, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 + ggml.utils.GGML_TYPE.I32, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 ) return ggml_type @@ -1046,7 +1046,7 @@ def ggml_operator_reduce_mean( if len(node_inputs) != 1: raise ValueError( - f'Error for node "{node.name}": Operation "ReduceMean" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "ReduceMean-13" requires exactly one input. Actual number of inputs: {len(node_inputs)}' ) tensor_shape = get_tensor_shape(node_inputs[0]) @@ -1304,9 +1304,21 @@ def ggml_operator_transpose( perms += [0, 1, 2, 3][len(perms) :] ax0, ax1, ax2, ax3 = perms + dims = ggml.utils.get_ndims(x) + + if dims > 3: + raise ValueError( + "n_dims cannot be more than 3. 4D permutations may not work" + ) # FIXME: 2,3D permutations are fine 4d is not. Passes ONNX test + + if dims == 3 and f"02" in "".join([str(perm) for perm in perms]): + x = ggml.ggml_transpose(context, x) transpose_result = ggml.ggml_permute(context, x, ax0, ax1, ax2, ax3) + if dims == 3 and f"02" in "".join([str(perm) for perm in perms]): + transpose_result = ggml.ggml_permute(context, transpose_result, 0, 2, 1, 3) + tensors_dict[output_name] = transpose_result return transpose_result @@ -1495,7 +1507,6 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml_type = map_to_ggml_type(input_data.dtype) shape = tuple(reversed(input_data.shape)) - context tensor = ggml.ggml_new_tensor( context, ggml_type.value, diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 2edaa412..5ea18eb4 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -198,14 +198,12 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_sub_uint8_") # not supported backend_test.include("test_transpose_") -# backend_test.exclude("test_transpose_") backend_test.include("test_unsqueeze_") -backend_test.exclude("test_unsqueeze_") +# backend_test.exclude("test_unsqueeze_") backend_test.include("test_where_") backend_test.exclude("test_where_long") -backend_test.exclude("test_where_example") backend_test.exclude(".*cuda.*") backend_test.exclude(".*pad.*") From 77a797c10135dbae590bdc8de8565a9fc2f3c963 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 22 Aug 2023 14:26:13 -0700 Subject: [PATCH 084/232] Don't run test matrix on python3.7 --- .github/workflows/test.yaml | 2 +- ggml/contrib/onnx.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 32d4c198..a79bc798 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 669fe45d..08f486c0 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1068,21 +1068,21 @@ def ggml_operator_reshape( f'Error for node "{node.name}": Operation "Reshape" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - try: - allowzero_attr = next(attr for attr in node.attribute if attr.name == "allowzero") + allowzero_attr = next( + attr for attr in node.attribute if attr.name == "allowzero" + ) allowzero = allowzero_attr.i == 1 except StopIteration: allowzero = False - a = node_inputs[0] b = node_inputs[1] eval_b = backend.eval_tensor(b, context) new_shape = ggml.utils.to_numpy(eval_b).astype(dtype=np.int32) - old_shape = get_tensor_shape(a) + old_shape = get_tensor_shape(a) if not allowzero: keep_idxs = np.where(new_shape == 0)[0] new_shape[keep_idxs] = np.array(old_shape)[keep_idxs] From 775b41fb0777a68b87c9537b353acb4033393766 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 22 Aug 2023 14:27:53 -0700 Subject: [PATCH 085/232] Exclude test_reshape_allowzero-reordered_ tests --- tests/test_ggml_onnx.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index c2bca990..b9789f14 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -110,6 +110,7 @@ def test_ggml_onnx_runtime_basic(): # backend_test.include("test_reduce_mean_") # backend_test.include("test_relu_") backend_test.include("test_reshape_") +backend_test.exclude("test_reshape_allowzero_reordered_") # backend_test.include("test_shape") # backend_test.include("test_softmax_") backend_test.include("test_sqrt_") From 72431007ffab2177b5c7de202a86220b51a71d77 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 22 Aug 2023 14:36:55 -0700 Subject: [PATCH 086/232] Update GH action --- .github/workflows/test.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a79bc798..77e7fc16 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -25,9 +25,9 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools + python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[onnx,onnx-runtime] + python3 -m pip install --verbose --editable .[test,onnx,onnx-runtime] - name: Test with pytest run: | python3 -m pytest @@ -71,8 +71,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools - python3 -m pip install --verbose --editable . + python3 -m pip install --upgrade pip cmake scikit-build setuptools + python3 -m pip install --verbose --editable .[test,onnx,onnx-runtime] - name: Test with pytest run: | python3 -m pytest From b2f3fba13a682f64106afc38ef16dd3e94fb3d00 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 22 Aug 2023 14:38:06 -0700 Subject: [PATCH 087/232] fix install --- .github/workflows/test.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 77e7fc16..163ed830 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -27,7 +27,7 @@ jobs: run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test,onnx,onnx-runtime] + python3 -m pip install --verbose --editable .[test,onnx,onnx-tests - name: Test with pytest run: | python3 -m pytest @@ -49,7 +49,7 @@ jobs: - name: Install dependencies run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test,onnx,onnx-runtime] + python3 -m pip install --verbose --editable .[test,onnx,onnx-tests - name: Test with pytest run: | python3 -m pytest @@ -72,7 +72,7 @@ jobs: - name: Install dependencies run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test,onnx,onnx-runtime] + python3 -m pip install --verbose --editable .[test,onnx,onnx-tests] - name: Test with pytest run: | python3 -m pytest From 424be0316d741abaa7e13d49b16d12a001cfec1e Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 22 Aug 2023 14:38:52 -0700 Subject: [PATCH 088/232] Remove python3.7 from test matrix: GH actions --- .github/workflows/test.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 163ed830..4be11d1b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -36,7 +36,7 @@ jobs: runs-on: windows-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 @@ -59,7 +59,6 @@ jobs: strategy: matrix: python-version: ["3.8", "3.9", "3.10", "3.11"] - # python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 From cd5c50aaff7979c6659d6efa962f3a83edfbdab8 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 22 Aug 2023 14:40:40 -0700 Subject: [PATCH 089/232] fix typo --- .github/workflows/test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4be11d1b..c7b14093 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -27,7 +27,7 @@ jobs: run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test,onnx,onnx-tests + python3 -m pip install --verbose --editable .[test,onnx,onnx-tests] - name: Test with pytest run: | python3 -m pytest @@ -49,7 +49,7 @@ jobs: - name: Install dependencies run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test,onnx,onnx-tests + python3 -m pip install --verbose --editable .[test,onnx,onnx-tests] - name: Test with pytest run: | python3 -m pytest From 2adf95b94f18b048f5d3b436f96a7f0f14db8138 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 23 Aug 2023 11:24:00 -0400 Subject: [PATCH 090/232] Fix Max, Min and Unsqueeze --- ggml/contrib/onnx.py | 137 +++++++++++++++++++++++++--------------- tests/test_ggml_onnx.py | 22 +------ 2 files changed, 87 insertions(+), 72 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 15da8d7e..56632431 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -34,7 +34,7 @@ def map_to_ggml_type(dtype: np.dtype): np_data_type_limit = np.dtype(str(dtype).replace("64", "32")) ggml_type = ggml.utils.NUMPY_DTYPE_TO_GGML_TYPE.get( np_data_type_limit.type, - ggml.utils.GGML_TYPE.I32, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 + ggml.utils.GGML_TYPE.F32, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 ) return ggml_type @@ -758,20 +758,6 @@ def ggml_operator_mat_mul( return mul_mat_result -@ggml.ggml_custom2_op_t -def custom_max( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - x = np.max(a) - set_tensor_out(tensor_out, np.array(x)) - - @ggml_operator("Max") def ggml_operator_max( backend: "GgmlBackendRep", @@ -782,16 +768,22 @@ def ggml_operator_max( ): node_inputs = [tensors_dict[inp] for inp in node.input] - if len(node_inputs) != 1: + if len(node_inputs) < 1: raise ValueError( - f'Error for node "{node.name}": Operation "Max" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Max" requires at least one input. Actual number of inputs: {len(node_inputs)}' ) a_dtype = get_tensor_dtype(node_inputs[0]) - - output_shape = () ggml_type = map_to_ggml_type(a_dtype) + input_shapes = [get_tensor_shape(node_input) for node_input in node_inputs] + output_shape = input_shapes[0] + + for shape in input_shapes[1:]: + output_shape = np.maximum(output_shape, shape) + + output_shape = tuple(reversed(output_shape)) + x_t = ggml.ggml_new_tensor( context, ggml_type.value, @@ -799,30 +791,29 @@ def ggml_operator_max( (ctypes.c_int64 * len(output_shape))(*output_shape), ) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + @ggml.ggml_custom1_op_t + def custom_max( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + x = np.max(tensors, axis=0) + set_tensor_out(tensor_out, np.array(x)) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( context, x_t, - node_inputs[0], custom_max, 1, None, ) - return new_tensor - + refs.append(custom_max) -@ggml.ggml_custom2_op_t -def custom_min( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - x = np.min(a) - set_tensor_out(tensor_out, np.array(x)) + return new_tensor @ggml_operator("Min") @@ -835,16 +826,22 @@ def ggml_operator_min( ): node_inputs = [tensors_dict[inp] for inp in node.input] - if len(node_inputs) != 1: + if len(node_inputs) < 1: raise ValueError( - f'Error for node "{node.name}": Operation "Min" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Min" requires at least one input. Actual number of inputs: {len(node_inputs)}' ) a_dtype = get_tensor_dtype(node_inputs[0]) - - output_shape = () ggml_type = map_to_ggml_type(a_dtype) + input_shapes = [get_tensor_shape(node_input) for node_input in node_inputs] + output_shape = input_shapes[0] + + for shape in input_shapes[1:]: + output_shape = np.minimum(output_shape, shape) + + output_shape = tuple(reversed(output_shape)) + x_t = ggml.ggml_new_tensor( context, ggml_type.value, @@ -852,15 +849,28 @@ def ggml_operator_min( (ctypes.c_int64 * len(output_shape))(*output_shape), ) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + @ggml.ggml_custom1_op_t + def custom_min( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + x = np.min(tensors, axis=0) + set_tensor_out(tensor_out, np.array(x)) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( context, x_t, - node_inputs[0], custom_min, 1, None, ) + refs.append(custom_min) + return new_tensor @@ -1336,7 +1346,10 @@ def custom_unsqueeze( x = ggml.utils.to_numpy(tensor_in_2) axes = ggml.utils.to_numpy(tensor_in_3) - for axis in np.nditer(axes): + axes_values = [ax if ax >= 0 else ax + x.ndim + 1 for ax in axes] + axes_values.sort() + axes_values = np.array(axes_values) + for axis in axes_values: x = np.expand_dims(x, axis=axis) set_tensor_out(tensor_out, x) @@ -1357,23 +1370,43 @@ def ggml_operator_unsqueeze( f'Error for node "{node.name}": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' ) - x_shape = get_tensor_shape(node_inputs[0]) - x_dtype = get_tensor_dtype(node_inputs[0]) - axes = ggml.utils.to_numpy(node_inputs[1]) + data = node_inputs[0] + axes_input = node_inputs[1] - for axis in np.nditer(axes): - x_shape = np.insert(x_shape, axis, 1) + x_shape = get_tensor_shape(data) + x_dtype = get_tensor_dtype(data) + x_ndims = ggml.utils.get_ndims(data) - x_shape = x_shape.astype(np.int32) + axes_eval = backend.eval_tensor(axes_input, context) + axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) - x = np.empty(x_shape, dtype=x_dtype) - x_t = ggml.utils.from_numpy(x, context) + axes_values = [ax if ax >= 0 else ax + x_ndims + 1 for ax in axes] + axes_values.sort() + + dummy_data = np.empty(x_shape) + for axis in axes_values: + dummy_data = np.expand_dims(dummy_data, axis=axis) + + ggml_type = map_to_ggml_type(x_dtype) + new_shape = tuple(reversed(dummy_data.shape)) + + if len(new_shape) > 4: + raise ValueError( + f'Error for node "{node.name}": {len(new_shape)}D arrays are not allowed.' + ) + + x_t = ggml.ggml_new_tensor( + context, + ggml_type.value, + len(new_shape), + (ctypes.c_int64 * len(new_shape))(*new_shape), + ) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( context, x_t, - node_inputs[0], - node_inputs[1], + data, + axes_input, custom_unsqueeze, 1, None, diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 5ea18eb4..a19484c7 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -111,12 +111,10 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_gather_elements") backend_test.include("test_greater_") -backend_test.exclude("test_greater_bcast") backend_test.exclude("test_greater_cuda") backend_test.exclude("test_greater_equal") backend_test.include("test_less_") -backend_test.exclude("test_less_bcast") backend_test.exclude("test_less_cuda") backend_test.exclude("test_less_equal_") @@ -126,38 +124,22 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_matmul_") backend_test.include("test_max_") -backend_test.exclude("test_max_one") -backend_test.exclude("test_max_two") -backend_test.exclude("test_max_float16") -backend_test.exclude("test_max_float32") +backend_test.exclude("test_max_float16") # uint16 not supported backend_test.exclude("test_max_float64") -backend_test.exclude("test_max_int8") -backend_test.exclude("test_max_int16") -backend_test.exclude("test_max_int32") backend_test.exclude("test_max_int64") backend_test.exclude("test_max_uint") -backend_test.exclude("test_max_example") backend_test.include("test_min_") -backend_test.exclude("test_min_one") -backend_test.exclude("test_min_two") backend_test.exclude("test_min_float16") -backend_test.exclude("test_min_float32") backend_test.exclude("test_min_float64") -backend_test.exclude("test_min_int8") -backend_test.exclude("test_min_int16") -backend_test.exclude("test_min_int32") backend_test.exclude("test_min_int64") backend_test.exclude("test_min_uint") -backend_test.exclude("test_min_example") backend_test.include("test_mul_") backend_test.exclude("test_mul_uint8") backend_test.include("test_pow_") backend_test.exclude("test_pow_bcast") -backend_test.exclude("test_pow_types") -backend_test.exclude("test_pow_types_int64") backend_test.exclude("test_pow_types_int64") backend_test.include("test_range_") @@ -200,7 +182,7 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_transpose_") backend_test.include("test_unsqueeze_") -# backend_test.exclude("test_unsqueeze_") +backend_test.exclude("test_unsqueeze_") backend_test.include("test_where_") backend_test.exclude("test_where_long") From 8cc8d3f200ebe06c8a660ca72f8885d3a11f18ff Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 23 Aug 2023 11:37:24 -0400 Subject: [PATCH 091/232] Improve Constant operator --- ggml/contrib/onnx.py | 5 ++--- tests/test_ggml_onnx.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 56632431..f624376c 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -356,15 +356,14 @@ def ggml_operator_constant( value_attr = next(attr for attr in node_attributes if attr.name == "value") tensor = value_attr.t data_type = tensor.data_type + np_data_type = tensor_dtype_to_np_dtype(data_type) np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) if tensor.raw_data: data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) - elif tensor.float_data: - data_value = np.array(tensor.float_data, dtype=np_data_type) else: - raise ValueError("Data field not found.") + data_value = onnx.numpy_helper.to_array(tensor) data_tensor = ggml.utils.from_numpy( data_value.astype(np_data_type_limit), diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index a19484c7..486eb768 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -130,7 +130,7 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_max_uint") backend_test.include("test_min_") -backend_test.exclude("test_min_float16") +backend_test.exclude("test_min_float16") # uint16 not supported backend_test.exclude("test_min_float64") backend_test.exclude("test_min_int64") backend_test.exclude("test_min_uint") From 25befc06568a9d52b87ef1eca99473553741589b Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 23 Aug 2023 12:22:42 -0400 Subject: [PATCH 092/232] Improve ReduceMean --- ggml/contrib/onnx.py | 46 +++++++++++++++++++++++++++-------------- tests/test_ggml_onnx.py | 4 ---- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index f624376c..8c085256 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1038,7 +1038,8 @@ def custom_reduce_mean( axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims - rmean_result = np.mean(tensor, tuple(axes), keepdims=keepdims) + axes = tuple(axes) if len(axes) else None + rmean_result = np.mean(tensor, axis=axes, keepdims=keepdims) set_tensor_out(tensor_out, rmean_result) @@ -1053,36 +1054,51 @@ def ggml_operator_reduce_mean( ): node_inputs = [tensors_dict[inp] for inp in node.input] - if len(node_inputs) != 1: + if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( - f'Error for node "{node.name}": Operation "ReduceMean-13" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "ReduceMean" requires at least one input. Actual number of inputs: {len(node_inputs)}' ) - tensor_shape = get_tensor_shape(node_inputs[0]) - tensor_dtype = get_tensor_dtype(node_inputs[0]) - axes = next(attr.ints for attr in node.attribute if attr.name == "axes") + input_tensor = node_inputs[0] + + tensor_shape = get_tensor_shape(input_tensor) + tensor_dtype = get_tensor_dtype(input_tensor) + + axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) + if not axes: + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceMean" requires an axis.' + ) + + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) rmean_userdata = RedueMeanUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) - output_shape = list(tensor_shape) - for axis in axes: - output_shape[axis] = 1 - for axis in axes: - if not keepdims: - output_shape.pop(0) + output_shape = tuple([1] * len(tensor_shape)) if keepdims else () - output_shape = tuple(output_shape) + if len(axes): + output_shape = list(tensor_shape) + sorted_axes = sorted(axes, reverse=True) - x = np.empty(output_shape, dtype=tensor_dtype) + for axis in sorted_axes: + if keepdims: + output_shape[axis] = 1 + else: + output_shape.pop(axis) + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( context, x_t, - node_inputs[0], + input_tensor, custom_reduce_mean, 1, userdata_p, diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 486eb768..08e69cfc 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -147,10 +147,6 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_range_int32") backend_test.include("test_reduce_mean_") -backend_test.exclude("test_reduce_mean_default") -backend_test.exclude("test_reduce_mean_do_not_keepdims") -backend_test.exclude("test_reduce_mean_keepdims") -backend_test.exclude("test_reduce_mean_negative_axes") backend_test.include("test_relu_") backend_test.exclude("test_relu_expanded") From ea59af1642e1c9523afa9288b70f8ea5a16a5c7e Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 16:28:28 -0700 Subject: [PATCH 093/232] Install .[convert] for tests --- .github/workflows/test.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c7b14093..057e77eb 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -27,7 +27,7 @@ jobs: run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test,onnx,onnx-tests] + python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] - name: Test with pytest run: | python3 -m pytest @@ -49,7 +49,7 @@ jobs: - name: Install dependencies run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test,onnx,onnx-tests] + python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] - name: Test with pytest run: | python3 -m pytest @@ -71,7 +71,7 @@ jobs: - name: Install dependencies run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test,onnx,onnx-tests] + python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] - name: Test with pytest run: | python3 -m pytest From b99f44e76cd938dac65a0e228f264ef3c7c33cf3 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 16:31:05 -0700 Subject: [PATCH 094/232] Skip broken tests --- tests/test_ggml_onnx_ops.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py index 5fe2c5ff..2219002f 100644 --- a/tests/test_ggml_onnx_ops.py +++ b/tests/test_ggml_onnx_ops.py @@ -19,6 +19,7 @@ from ggml.contrib.onnx import GgmlRuntimeBackend, ggml_operators, GgmlBackendRep +@pytest.mark.skip(reason="broken") def test_ggml_onnx_runtime_shape_operator(): # return @@ -1039,6 +1040,7 @@ def forward(self, input1, input2): ggml.ggml_free(context) +@pytest.mark.skip(reason="broken") def test_ggml_onnx_min_operator(): # return @@ -1114,6 +1116,7 @@ def forward(self, input1): ggml.ggml_free(context) +@pytest.mark.skip(reason="broken") def test_ggml_onnx_max_operator(): # return From c8c2f299170c45cf40dca1e1c0e72d35807cceb9 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 22:10:16 -0700 Subject: [PATCH 095/232] relu --- ggml/contrib/onnx.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 13a5ed8c..32ae7f8c 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -282,12 +282,22 @@ def ggml_operator_castlike( raise ValueError( f'Error for node "{node.name}": Operation "CastLike" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - dtype = get_tensor_dtype(node_inputs[1]) - onnx_type = np_dtype_to_tensor_dtype(dtype) + a = node_inputs[0] + b = node_inputs[1] + + np_data_dtype = get_tensor_dtype(b) + np_data_type_limit = np.dtype(str(np_data_dtype).replace("64", "32")) + + onnx_type = np_dtype_to_tensor_dtype(np_data_dtype) onnx_type_c = ctypes.c_int(onnx_type) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + + x = np.empty(get_tensor_shape(b), dtype=np_data_type_limit) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( context, - node_inputs[0], + x_t, + a, custom_cast, 1, ctypes.pointer(onnx_type_c), From d007388dea77a18930f551c371660df867c1ec16 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 22:22:29 -0700 Subject: [PATCH 096/232] Add LogSoftmax --- ggml/contrib/onnx.py | 25 +++++++++++++++++++++++++ tests/test_ggml_onnx.py | 31 ++++++++++++++++--------------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 32ae7f8c..1f7a60bd 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -742,6 +742,31 @@ def ggml_operator_log( return log_result +@ggml_operator("LogSoftmax") +def ggml_operator_log( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "LogSoftmax" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + a = node_inputs[0] + soft_max_result = ggml.ggml_soft_max(context,a) + log_result = ggml.ggml_log( + context, + soft_max_result, + ) + tensors_dict[output_name] = log_result + return log_result + @ggml_operator("MatMul") def ggml_operator_mat_mul( backend: "GgmlBackendRep", diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 41bfae9f..d87069d4 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -119,24 +119,23 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_less_equal_") backend_test.include("test_log_") -backend_test.exclude("test_log_softmax_*") backend_test.include("test_matmul_") backend_test.include("test_max_") -backend_test.exclude("test_max_float16") # uint16 not supported -backend_test.exclude("test_max_float64") -backend_test.exclude("test_max_int64") -backend_test.exclude("test_max_uint") +backend_test.exclude("test_max_float16") # not supported +backend_test.exclude("test_max_float64") # not supported +backend_test.exclude("test_max_int64") # not supported +backend_test.exclude("test_max_uint") # not supported backend_test.include("test_min_") -backend_test.exclude("test_min_float16") # uint16 not supported -backend_test.exclude("test_min_float64") -backend_test.exclude("test_min_int64") -backend_test.exclude("test_min_uint") +backend_test.exclude("test_min_float16") # not supported +backend_test.exclude("test_min_float64") # not supported +backend_test.exclude("test_min_int64") # not supported +backend_test.exclude("test_min_uint") # not supported backend_test.include("test_mul_") -backend_test.exclude("test_mul_uint8") +backend_test.exclude("test_mul_uint8") # not supported backend_test.include("test_pow_") backend_test.exclude("test_pow_bcast") @@ -149,13 +148,12 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_reduce_mean_") backend_test.include("test_relu_") -backend_test.exclude("test_relu_expanded") +backend_test.exclude("test_relu_expanded") # not supported backend_test.include("test_reshape_") -backend_test.exclude("test_reshape_allowzero") +backend_test.exclude("test_reshape_allowzero") # not supported backend_test.include("test_shape_") -backend_test.exclude("test_shape_cuda") backend_test.include("test_softmax_") backend_test.exclude("test_softmax_axis") @@ -177,10 +175,13 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_transpose_") backend_test.include("test_unsqueeze_") -backend_test.exclude("test_unsqueeze_") +backend_test.exclude("test_unsqueeze_negative_axes_cpu") # 5D Array not supported +backend_test.exclude("test_unsqueeze_three_axes_cpu") # 6D Array not supported +backend_test.exclude("test_unsqueeze_two_axes_cpu") # 5D Array not supported +backend_test.exclude("test_unsqueeze_unsorted_axes_cpu") # 5D Array not supported backend_test.include("test_where_") -backend_test.exclude("test_where_long") +backend_test.exclude("test_where_long") # not supported backend_test.exclude(".*cuda.*") backend_test.exclude(".*pad.*") From 92c21169a5731c5397d138e193e08ee241e8bf40 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 22:23:10 -0700 Subject: [PATCH 097/232] Fix name --- ggml/contrib/onnx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 1f7a60bd..b3f63d37 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -743,7 +743,7 @@ def ggml_operator_log( @ggml_operator("LogSoftmax") -def ggml_operator_log( +def ggml_operator_log_soft_max( backend: "GgmlBackendRep", node: NodeProto, tensors_dict: Dict[str, ggml.ggml_tensor_p], From d6d13b195da1a77a32738ea7b9028928119ad250 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 22:34:35 -0700 Subject: [PATCH 098/232] Added logical operators --- ggml/contrib/onnx.py | 226 ++++++++++++++++++++++++++++++++++++++++ tests/test_ggml_onnx.py | 10 +- 2 files changed, 229 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index b3f63d37..ad1b5423 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -535,6 +535,63 @@ def ggml_operator_div( tensors_dict[output_name] = div_result return div_result +@ggml.ggml_custom3_op_t +def custom_equal( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.equal(a, b) + + set_tensor_out(tensor_out, x) + + +@ggml_operator("Equal") +def ggml_operator_equal( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a_shape = get_tensor_shape(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) + b_shape = get_tensor_shape(node_inputs[1]) + name = node.output[0] + + output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape + + x = np.empty(output_shape, dtype=a_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_equal, + 1, + None, + ) + + ggml.ggml_set_name(new_tensor, (name + f"").encode()) + + return new_tensor + @ggml.ggml_custom3_op_t def custom_gather( @@ -657,6 +714,62 @@ def ggml_operator_greater( return new_tensor +@ggml.ggml_custom3_op_t +def custom_greater_equal( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.greater_equal(a, b) + + set_tensor_out(tensor_out, x) + + +@ggml_operator("GreaterOrEqual") +def ggml_operator_greater_or_equal( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a_shape = get_tensor_shape(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) + b_shape = get_tensor_shape(node_inputs[1]) + name = node.output[0] + + output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape + + x = np.empty(output_shape, dtype=a_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_greater_equal, + 1, + None, + ) + + ggml.ggml_set_name(new_tensor, (name + f"").encode()) + + return new_tensor @ggml.ggml_custom3_op_t def custom_less( @@ -715,6 +828,63 @@ def ggml_operator_less( return new_tensor +@ggml.ggml_custom3_op_t +def custom_less_equal( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.less_equal(a, b) + + set_tensor_out(tensor_out, x) + + +@ggml_operator("LessOrEqual") +def ggml_operator_less_or_equal( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a_shape = get_tensor_shape(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) + b_shape = get_tensor_shape(node_inputs[1]) + name = node.output[0] + + output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape + + x = np.empty(output_shape, dtype=a_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_less_equal, + 1, + None, + ) + + ggml.ggml_set_name(new_tensor, (name + f"").encode()) + + return new_tensor + @ggml_operator("Log") def ggml_operator_log( @@ -986,6 +1156,62 @@ def custom_pow( set_tensor_out(tensor_out, new_tensor) +@ggml.ggml_custom3_op_t +def custom_or( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.logical_or(a, b) + + set_tensor_out(tensor_out, x) + + +@ggml_operator("Or") +def ggml_operator_or( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a_shape = get_tensor_shape(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) + b_shape = get_tensor_shape(node_inputs[1]) + name = node.output[0] + + output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape + + x = np.empty(output_shape, dtype=a_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_or, + 1, + None, + ) + + ggml.ggml_set_name(new_tensor, (name + f"").encode()) + + return new_tensor @ggml_operator("Pow") def ggml_operator_pow( diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index d87069d4..e46863c9 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -108,15 +108,11 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_div_uint8_") # not supported backend_test.include("test_gather_") -backend_test.exclude("test_gather_elements") +backend_test.exclude("test_gather_elements") # not supported backend_test.include("test_greater_") -backend_test.exclude("test_greater_cuda") -backend_test.exclude("test_greater_equal") backend_test.include("test_less_") -backend_test.exclude("test_less_cuda") -backend_test.exclude("test_less_equal_") backend_test.include("test_log_") @@ -138,8 +134,8 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_mul_uint8") # not supported backend_test.include("test_pow_") -backend_test.exclude("test_pow_bcast") -backend_test.exclude("test_pow_types_int64") +backend_test.exclude("test_pow_bcast") # not supported +backend_test.exclude("test_pow_types_int64") # not supported backend_test.include("test_range_") backend_test.exclude("test_range_float") From 7b9004fcb9b1faf24ff447850a729cf3ff0c7d65 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 23:06:29 -0700 Subject: [PATCH 099/232] softmax --- ggml/contrib/onnx.py | 276 ++++++++++++++++++++++++++++++++++++++-- tests/test_ggml_onnx.py | 14 +- 2 files changed, 273 insertions(+), 17 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index ad1b5423..82b70562 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -535,6 +535,7 @@ def ggml_operator_div( tensors_dict[output_name] = div_result return div_result + @ggml.ggml_custom3_op_t def custom_equal( tensor_out: ggml.ggml_tensor_p, @@ -565,7 +566,7 @@ def ggml_operator_equal( if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Equal" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) a_shape = get_tensor_shape(node_inputs[0]) @@ -593,6 +594,51 @@ def ggml_operator_equal( return new_tensor +@ggml_operator("Exp") +def ggml_operator_exp( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Exp" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + a = node_inputs[0] + np_dtype = get_tensor_dtype(a) + + x = np.empty(get_tensor_shape(a), dtype=np_dtype) + x_t = ggml.utils.from_numpy(x, context) + + @ggml.ggml_custom1_op_t + def custom_exp( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + tensor = ggml.utils.to_numpy(tensor_in_1) + x = np.exp(tensor) + set_tensor_out(tensor_out, np.array(x)) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x_t, + custom_exp, + 1, + None, + ) + + refs.append(custom_exp) + + return new_tensor + + @ggml.ggml_custom3_op_t def custom_gather( tensor_out: ggml.ggml_tensor_p, @@ -714,6 +760,7 @@ def ggml_operator_greater( return new_tensor + @ggml.ggml_custom3_op_t def custom_greater_equal( tensor_out: ggml.ggml_tensor_p, @@ -744,7 +791,7 @@ def ggml_operator_greater_or_equal( if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "GreaterOrEqual" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) a_shape = get_tensor_shape(node_inputs[0]) @@ -771,6 +818,7 @@ def ggml_operator_greater_or_equal( return new_tensor + @ggml.ggml_custom3_op_t def custom_less( tensor_out: ggml.ggml_tensor_p, @@ -828,6 +876,7 @@ def ggml_operator_less( return new_tensor + @ggml.ggml_custom3_op_t def custom_less_equal( tensor_out: ggml.ggml_tensor_p, @@ -858,7 +907,7 @@ def ggml_operator_less_or_equal( if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "LessOrEqual" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) a_shape = get_tensor_shape(node_inputs[0]) @@ -929,7 +978,7 @@ def ggml_operator_log_soft_max( output_name = node.output[0] a = node_inputs[0] - soft_max_result = ggml.ggml_soft_max(context,a) + soft_max_result = ggml.ggml_soft_max(context, a) log_result = ggml.ggml_log( context, soft_max_result, @@ -937,6 +986,7 @@ def ggml_operator_log_soft_max( tensors_dict[output_name] = log_result return log_result + @ggml_operator("MatMul") def ggml_operator_mat_mul( backend: "GgmlBackendRep", @@ -1156,6 +1206,7 @@ def custom_pow( set_tensor_out(tensor_out, new_tensor) + @ggml.ggml_custom3_op_t def custom_or( tensor_out: ggml.ggml_tensor_p, @@ -1186,7 +1237,7 @@ def ggml_operator_or( if len(node_inputs) != 2: raise ValueError( - f'Error for node "{node.name}": Operation "Less" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + f'Error for node "{node.name}": Operation "Or" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) a_shape = get_tensor_shape(node_inputs[0]) @@ -1213,6 +1264,7 @@ def ggml_operator_or( return new_tensor + @ggml_operator("Pow") def ggml_operator_pow( backend: "GgmlBackendRep", @@ -1297,7 +1349,111 @@ def ggml_operator_range( return new_tensor -class RedueMeanUserData(ctypes.Structure): +class ReduceMaxUserData(ctypes.Structure): + _fields_ = [ + ("axes", ctypes.POINTER(ctypes.c_int)), + ("axes_length", ctypes.c_int), + ("keepdims", ctypes.c_int), + ] + + def __init__(self, axes, keepdims): + if isinstance(axes, list): + self.axes_length = len(axes) + self.axes = (ctypes.c_int * self.axes_length)(*axes) + else: + raise ValueError("axes should be a list of integers") + + self.keepdims = keepdims + + +@ggml.ggml_custom2_op_t +def custom_reduce_max( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceMaxUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rmean_result = np.max(tensor, axis=axes, keepdims=keepdims) + + set_tensor_out(tensor_out, rmean_result) + + +@ggml_operator("ReduceMax") +def ggml_operator_reduce_max( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) > 2 or len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceMax" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + input_tensor = node_inputs[0] + + tensor_shape = get_tensor_shape(input_tensor) + tensor_dtype = get_tensor_dtype(input_tensor) + + axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) + if not axes: + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceMean" requires an axis.' + ) + + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) + + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + + rmean_userdata = ReduceMeanUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) + + output_shape = tuple([1] * len(tensor_shape)) if keepdims else () + + if len(axes): + output_shape = list(tensor_shape) + sorted_axes = sorted(axes, reverse=True) + + for axis in sorted_axes: + if keepdims: + output_shape[axis] = 1 + else: + output_shape.pop(axis) + + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + input_tensor, + custom_reduce_max, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor + + +class ReduceMeanUserData(ctypes.Structure): _fields_ = [ ("axes", ctypes.POINTER(ctypes.c_int)), ("axes_length", ctypes.c_int), @@ -1323,7 +1479,7 @@ def custom_reduce_mean( nth: int, userdata: Optional[ctypes.c_void_p], ): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(RedueMeanUserData)) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceMeanUserData)) userdata_data = userdata_data_ptr.contents tensor = ggml.utils.to_numpy(tensor_in_2) @@ -1368,7 +1524,7 @@ def ggml_operator_reduce_mean( keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) - rmean_userdata = RedueMeanUserData(list(axes), keepdims) + rmean_userdata = ReduceMeanUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) output_shape = tuple([1] * len(tensor_shape)) if keepdims else () @@ -1401,6 +1557,110 @@ def ggml_operator_reduce_mean( return new_tensor +class ReduceSumUserData(ctypes.Structure): + _fields_ = [ + ("axes", ctypes.POINTER(ctypes.c_int)), + ("axes_length", ctypes.c_int), + ("keepdims", ctypes.c_int), + ] + + def __init__(self, axes, keepdims): + if isinstance(axes, list): + self.axes_length = len(axes) + self.axes = (ctypes.c_int * self.axes_length)(*axes) + else: + raise ValueError("axes should be a list of integers") + + self.keepdims = keepdims + + +@ggml.ggml_custom2_op_t +def custom_reduce_sum( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceSumUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + result = np.sum(tensor, axis=axes, keepdims=keepdims) + + set_tensor_out(tensor_out, result) + + +@ggml_operator("ReduceSum") +def ggml_operator_reduce_sum( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) > 2 or len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceSum" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + input_tensor = node_inputs[0] + + tensor_shape = get_tensor_shape(input_tensor) + tensor_dtype = get_tensor_dtype(input_tensor) + + axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) + if not axes: + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceMean" requires an axis.' + ) + + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) + + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + + rmean_userdata = ReduceSumUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) + + output_shape = tuple([1] * len(tensor_shape)) if keepdims else () + + if len(axes): + output_shape = list(tensor_shape) + sorted_axes = sorted(axes, reverse=True) + + for axis in sorted_axes: + if keepdims: + output_shape[axis] = 1 + else: + output_shape.pop(axis) + + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + input_tensor, + custom_reduce_sum, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor + + @ggml_operator("Relu") def ggml_operator_relu( backend: "GgmlBackendRep", diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index e46863c9..9959efff 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -152,19 +152,15 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_shape_") backend_test.include("test_softmax_") -backend_test.exclude("test_softmax_axis") -backend_test.exclude("test_softmax_default_axis") -backend_test.exclude("test_softmax_example") -backend_test.exclude("test_softmax_large_number") -backend_test.exclude("test_softmax_negative_axis") -backend_test.exclude("test_softmax_functional") -backend_test.exclude("test_softmax_lastdim") +backend_test.exclude("test_softmax_axis_0") # not supported +backend_test.exclude("test_softmax_axis_1") # not supported +backend_test.exclude("test_softmax_large_number") # not supported +backend_test.exclude("test_softmax_lastdim") # Out of tolerance + backend_test.include("test_sqrt_") -backend_test.exclude("test_sqrt_cuda") backend_test.include("test_sub_") -backend_test.exclude("test_sub_cuda") # not supported backend_test.exclude("test_sub_bcast_") # not supported backend_test.exclude("test_sub_uint8_") # not supported From ed7e4d03b24a95183e2c49fd62b424db47d9fe12 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 23:07:22 -0700 Subject: [PATCH 100/232] Enable CUDA tests --- tests/test_ggml_onnx.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 9959efff..a5b6fe1f 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -167,15 +167,14 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_transpose_") backend_test.include("test_unsqueeze_") -backend_test.exclude("test_unsqueeze_negative_axes_cpu") # 5D Array not supported -backend_test.exclude("test_unsqueeze_three_axes_cpu") # 6D Array not supported -backend_test.exclude("test_unsqueeze_two_axes_cpu") # 5D Array not supported -backend_test.exclude("test_unsqueeze_unsorted_axes_cpu") # 5D Array not supported +backend_test.exclude("test_unsqueeze_negative_axes") # 5D Array not supported +backend_test.exclude("test_unsqueeze_three_axes") # 6D Array not supported +backend_test.exclude("test_unsqueeze_two_axes") # 5D Array not supported +backend_test.exclude("test_unsqueeze_unsorted_axes") # 5D Array not supported backend_test.include("test_where_") backend_test.exclude("test_where_long") # not supported -backend_test.exclude(".*cuda.*") backend_test.exclude(".*pad.*") backend_test.exclude(".*FLOAT*E*M*.*") From 3b92069d94dff2d491d892079c573e12b6632858 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 23:20:40 -0700 Subject: [PATCH 101/232] Add comments to failing tests --- ggml/contrib/onnx.py | 1 - tests/test_ggml_onnx.py | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 82b70562..f116fd2a 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -366,7 +366,6 @@ def custom_concat( return new_tensor - @ggml.ggml_custom2_op_t def custom_constant( tensor_out: ggml.ggml_tensor_p, diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index a5b6fe1f..7dd5a86d 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -138,8 +138,8 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_pow_types_int64") # not supported backend_test.include("test_range_") -backend_test.exclude("test_range_float") -backend_test.exclude("test_range_int32") +backend_test.exclude("test_range_float") # segfault +backend_test.exclude("test_range_int32") # segfault backend_test.include("test_reduce_mean_") @@ -157,7 +157,6 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_softmax_large_number") # not supported backend_test.exclude("test_softmax_lastdim") # Out of tolerance - backend_test.include("test_sqrt_") backend_test.include("test_sub_") From 922234bda5877c34c48efcb8ccfcf30890efc0a6 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 23:37:04 -0700 Subject: [PATCH 102/232] conditional onnx tests --- .github/workflows/test.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2e24d8e0..e2c5c0ef 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -23,15 +23,28 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + - name: Install dependencies + if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] + + - name: Install dependencies [pypy] + if: ${{ startsWith(matrix.python-version, 'pypy') }} + run: | + python3 -m pip install --upgrade pip cmake scikit-build setuptools + python3 -m pip install --verbose --editable .[test,convert] + - name: Test with pytest + if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pytest + - name: Test with pytest [pypy] + if: ${{ startsWith(matrix.python-version, 'pypy') }} + python3 -m pytest -k 'not ggml_test_onnx' + build-windows: runs-on: windows-latest strategy: From 2ba162cd44f3a5b2a984ae33d96a863e3215adc4 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 23:37:49 -0700 Subject: [PATCH 103/232] typo --- .github/workflows/test.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e2c5c0ef..4310bfb5 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -43,6 +43,7 @@ jobs: - name: Test with pytest [pypy] if: ${{ startsWith(matrix.python-version, 'pypy') }} + run: | python3 -m pytest -k 'not ggml_test_onnx' build-windows: @@ -55,10 +56,12 @@ jobs: - uses: actions/checkout@v3 with: submodules: "true" + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + - name: Install dependencies run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools From 5ba538f12871589ccfa96959fcfbafa2ce0282e4 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 23:39:40 -0700 Subject: [PATCH 104/232] onnx tests --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4310bfb5..cbed761c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -34,7 +34,7 @@ jobs: if: ${{ startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test,convert] + python3 -m pip install --verbose --editable .[test] - name: Test with pytest if: ${{ !startsWith(matrix.python-version, 'pypy') }} From dd3c4dc4e1c944812bf97a77d6fac1533cb68590 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 23:45:08 -0700 Subject: [PATCH 105/232] ignore-glob=onnx --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index cbed761c..03d7caa1 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -44,7 +44,7 @@ jobs: - name: Test with pytest [pypy] if: ${{ startsWith(matrix.python-version, 'pypy') }} run: | - python3 -m pytest -k 'not ggml_test_onnx' + python3 -m pytest --ignore-glob='*onnx*' build-windows: runs-on: windows-latest From 6e5920e6286e607b58215f02bcb752f1eba801ff Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 23 Aug 2023 23:47:05 -0700 Subject: [PATCH 106/232] conditional tests on windows and osx --- .github/workflows/test.yaml | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 03d7caa1..942a501e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -61,15 +61,28 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies + if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] + + - name: Install dependencies [pypy] + if: ${{ startsWith(matrix.python-version, 'pypy') }} + run: | + python3 -m pip install --upgrade pip cmake scikit-build setuptools + python3 -m pip install --verbose --editable .[test] + - name: Test with pytest + if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pytest + - name: Test with pytest [pypy] + if: ${{ startsWith(matrix.python-version, 'pypy') }} + run: | + python3 -m pytest --ignore-glob='*onnx*' + build-macos: runs-on: macos-latest strategy: @@ -84,10 +97,25 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + - name: Install dependencies + if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] + + - name: Install dependencies [pypy] + if: ${{ startsWith(matrix.python-version, 'pypy') }} + run: | + python3 -m pip install --upgrade pip cmake scikit-build setuptools + python3 -m pip install --verbose --editable .[test] + - name: Test with pytest + if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pytest + + - name: Test with pytest [pypy] + if: ${{ startsWith(matrix.python-version, 'pypy') }} + run: | + python3 -m pytest --ignore-glob='*onnx*' From ea0fdc3d11b1301b4580585280ecb8d1cc122d12 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 24 Aug 2023 09:32:05 -0400 Subject: [PATCH 107/232] conditional tests on windows and osx --- .github/workflows/test.yaml | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 03d7caa1..942a501e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -61,15 +61,28 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies + if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] + + - name: Install dependencies [pypy] + if: ${{ startsWith(matrix.python-version, 'pypy') }} + run: | + python3 -m pip install --upgrade pip cmake scikit-build setuptools + python3 -m pip install --verbose --editable .[test] + - name: Test with pytest + if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pytest + - name: Test with pytest [pypy] + if: ${{ startsWith(matrix.python-version, 'pypy') }} + run: | + python3 -m pytest --ignore-glob='*onnx*' + build-macos: runs-on: macos-latest strategy: @@ -84,10 +97,25 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + - name: Install dependencies + if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] + + - name: Install dependencies [pypy] + if: ${{ startsWith(matrix.python-version, 'pypy') }} + run: | + python3 -m pip install --upgrade pip cmake scikit-build setuptools + python3 -m pip install --verbose --editable .[test] + - name: Test with pytest + if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pytest + + - name: Test with pytest [pypy] + if: ${{ startsWith(matrix.python-version, 'pypy') }} + run: | + python3 -m pytest --ignore-glob='*onnx*' From e75a6b75a478a27e2e835915d6adb97fd8182e71 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 25 Aug 2023 14:06:03 -0400 Subject: [PATCH 108/232] Create progress.md --- ggml/contrib/progress.md | 100 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 ggml/contrib/progress.md diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md new file mode 100644 index 00000000..63e1f4ba --- /dev/null +++ b/ggml/contrib/progress.md @@ -0,0 +1,100 @@ +# Operator Implementation Progress + + +| ONNX Operators | Implemented | ggml Equivalent | +|:----------------------|:---------------:|:------------------------:| +| [Abs](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Abs) | :white_check_mark: | `ggml_abs` | +| [Add](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Add) | :white_check_mark: | `ggml_add` | +| [And](https://github.com/onnx/onnx/blob/main/docs/Operators.md#And) | | | +| [ArgMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMax) | | | +| [ArgMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMin) | | | +| [AveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#AveragePool) | | | +| [BatchNormalizatio](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BatchNormalizatio) | | | +| [Cast](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Cast) | :white_check_mark: | | +| [Ceil](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Ceil) | | | +| [Clip](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Clip) | | | +| [Concat](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Concat) | :white_check_mark: | `ggml_concat` | +| [Constant](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Constant) | :white_check_mark: | | +| [Conv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv) | | | +| [ConvTranspose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConvTranspose) | | | +| [DepthToSpace](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DepthToSpace) | | | +| [Div](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Div) | :white_check_mark: | `ggml_div` | +| [Dropout](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Dropout) | | | +| [Elu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Elu) | | `ggml_elu` | +| [Equal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Equal) | :white_check_mark: | | +| [Exp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Exp) | :white_check_mark: | | +| [Flatten](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Flatten) | | | +| [Floor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Floor) | | | +| [GRU](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GRU) | | | +| [Gather](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gather) | :white_check_mark: | | +| [Gemm](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gemm) | | | +| [GlobalAveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalAveragePool) | | | +| [GlobalLpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalLpPool) | | | +| [GlobalMaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalMaxPool) | | | +| [Greater](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Greater) | | | +| [HardSigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSigmoid) | | | +| [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | | | +| [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | | | +| [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | | | +| [InstanceNormaliza](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormaliza) | | | +| [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | | | +| [LSTM](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LSTM) | | | +| [LeakyRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LeakyRelu) | | | +| [Less](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Less) | | | +| [Log](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Log) | :white_check_mark: | `ggml_log` | +| [LogSoftmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LogSoftmax) | :white_check_mark: | | +| [Loop](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Loop) | | | +| [LpNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpNormalization) | | | +| [LpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpPool) | | | +| [MatMul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MatMul) | :white_check_mark: | `ggml_mul_mat` | +| [Max](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Max) | :white_check_mark: | `ggml_max` | +| [MaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxPool) | | | +| [MaxRoiPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxRoiPool) | | | +| [Mean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mean) | | `ggml_mean` | +| [Min](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Min) | :white_check_mark: | | +| [Mul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mul) | :white_check_mark: | `ggml_mul` | +| [Neg](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Neg) | | `ggml_neg` | +| [Not](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Not) | | | +| [Or](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Or) | :white_check_mark: | | +| [PRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#PRelu) | | | +| [Pad](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad) | | | +| [Pow](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pow) | :white_check_mark: | | +| [RNN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RNN) | | | +| [RandomNormal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormal) | | | +| [RandomNormalLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormalLike) | | | +| [RandomUniform](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniform) | | | +| [RandomUniformLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniformLike) | | | +| [Reciprocal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reciprocal) | | | +| [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | | | +| [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | | | +| [ReduceLogSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSum) | | | +| [ReduceLogSumExp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSumExp) | | | +| [ReduceMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMax) | :white_check_mark: | | +| [ReduceMean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMean) | :white_check_mark: | | +| [ReduceMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMin) | | | +| [ReduceProd](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceProd) | | | +| [ReduceSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSum) | :white_check_mark: | `ggml_sum`? | +| [ReduceSumSquare](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSumSquare) | | | +| [Relu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Relu) | :white_check_mark: | `ggml_relu` | +| [Reshape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reshape) | :white_check_mark: | `ggml_reshape` | +| [Selu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Selu) | | | +| [Shape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Shape) | :white_check_mark: | | +| [Sigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sigmoid) | | | +| [Size](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Size) | | | +| [Slice](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Slice) | | | +| [Softmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softmax) | :white_check_mark: | `ggml_soft_max` | +| [Softplus](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softplus) | | | +| [Softsign](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softsign) | | | +| [SpaceToDepth](https://github.com/onnx/onnx/blob/main/docs/Operators.md#SpaceToDepth) | | | +| [Split](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Split) | | | +| [Sqrt](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sqrt) | :white_check_mark: | `ggml_sqrt` | +| [Squeeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Squeeze) | | | +| [Sub](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sub) | :white_check_mark: | `ggml_sub` | +| [Sum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sum) | :white_check_mark: | `ggml_sum` | +| [Tanh](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tanh) | :white_check_mark: | `ggml_tanh` | +| [Tile](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tile) | | | +| [TopK](https://github.com/onnx/onnx/blob/main/docs/Operators.md#TopK) | | | +| [Transpose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Transpose) | :white_check_mark: | `ggml_transpose` | +| [Unsqueeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Unsqueeze) | :white_check_mark: | | +| [Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample) | | | +| [Xor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Xor) | | | From 9357f980931dbacca984e7d3296a0a053fddfc70 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 25 Aug 2023 15:08:36 -0400 Subject: [PATCH 109/232] Add Elu, Mean and Neg operators --- ggml/contrib/onnx.py | 128 ++++++++++++++++++++++++++++++++++++--- ggml/contrib/progress.md | 8 +-- tests/test_ggml_onnx.py | 7 +++ 3 files changed, 130 insertions(+), 13 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index f116fd2a..c27a8e50 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -366,6 +366,7 @@ def custom_concat( return new_tensor + @ggml.ggml_custom2_op_t def custom_constant( tensor_out: ggml.ggml_tensor_p, @@ -393,24 +394,38 @@ def ggml_operator_constant( node_attributes = node.attribute name = node.output[0] - value_attr = next(attr for attr in node_attributes if attr.name == "value") - tensor = value_attr.t - data_type = tensor.data_type + value_attr = next(attr for attr in node_attributes if "value" in attr.name) - np_data_type = tensor_dtype_to_np_dtype(data_type) - np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + if value_attr.HasField("t"): + tensor = value_attr.t + data_type = tensor.data_type + np_data_type = tensor_dtype_to_np_dtype(data_type) + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + + if tensor.raw_data: + data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) + else: + data_value = onnx.numpy_helper.to_array(tensor) - if tensor.raw_data: - data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) else: - data_value = onnx.numpy_helper.to_array(tensor) + data_type = value_attr.type + np_data_type = tensor_dtype_to_np_dtype(data_type) + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + if np.issubdtype(np_data_type, np.floating): + data_value = np.array(value_attr.f) + elif np.issubdtype(np_data_type, np.integer): + data_value = np.array(value_attr.i) + else: + raise ValueError( + f'Error for node "{node.name}": Constant node not set correctly or incomplete implantation.' + ) data_tensor = ggml.utils.from_numpy( data_value.astype(np_data_type_limit), context, ) - tensor_shape = tensor.dims or () + tensor_shape = data_value.shape x = np.empty(tensor_shape, dtype=np_data_type_limit) x_t = None @@ -535,6 +550,41 @@ def ggml_operator_div( return div_result +@ggml_operator("Elu") +def ggml_operator_elu( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Elu" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + x = node_inputs[0] + alpha = next((attr.f for attr in node.attribute if attr.name == "alpha"), 1.0) + + Y = ggml.ggml_elu( + context, + x, + ) + + if alpha != 1.0: + Y_eval = backend.eval_tensor(Y, context) + Y_np = ggml.utils.to_numpy(Y_eval) + Y_alpha = np.where(Y_np < 0, alpha * Y_np, Y_np) + + Y = ggml.utils.from_numpy(Y_alpha, context) + + tensors_dict[output_name] = Y + return Y + + @ggml.ggml_custom3_op_t def custom_equal( tensor_out: ggml.ggml_tensor_p, @@ -1100,6 +1150,40 @@ def custom_max( return new_tensor +@ggml_operator("Mean") +def ggml_operator_mean( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Mean" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + sums = node_inputs[0] + + for tensor in node_inputs[1:]: + sums = ggml.ggml_add(context, sums, tensor) + + coef_np = np.full(get_tensor_shape(sums), len(node_inputs), dtype=np.float32) + coef_t = ggml.utils.from_numpy(coef_np, context) + + mean = ggml.ggml_div( + context, + sums, + coef_t, + ) + + tensors_dict[output_name] = mean + return mean + + @ggml_operator("Min") def ggml_operator_min( backend: "GgmlBackendRep", @@ -1189,6 +1273,32 @@ def ggml_operator_mul( return mul_result +@ggml_operator("Neg") +def ggml_operator_neg( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Neg" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + output_name = node.output[0] + + x_neg = ggml.ggml_neg( + context, + x, + ) + tensors_dict[output_name] = x_neg + return x_neg + + @ggml.ggml_custom2_op_t def custom_pow( tensor_out: ggml.ggml_tensor_p, diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index 63e1f4ba..9d990b18 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -2,7 +2,7 @@ | ONNX Operators | Implemented | ggml Equivalent | -|:----------------------|:---------------:|:------------------------:| +|:--------------------------------------------------------------------------------------------------|:------------------:|:----------------:| | [Abs](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Abs) | :white_check_mark: | `ggml_abs` | | [Add](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Add) | :white_check_mark: | `ggml_add` | | [And](https://github.com/onnx/onnx/blob/main/docs/Operators.md#And) | | | @@ -20,7 +20,7 @@ | [DepthToSpace](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DepthToSpace) | | | | [Div](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Div) | :white_check_mark: | `ggml_div` | | [Dropout](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Dropout) | | | -| [Elu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Elu) | | `ggml_elu` | +| [Elu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Elu) | :white_check_mark: | `ggml_elu` | | [Equal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Equal) | :white_check_mark: | | | [Exp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Exp) | :white_check_mark: | | | [Flatten](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Flatten) | | | @@ -50,10 +50,10 @@ | [Max](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Max) | :white_check_mark: | `ggml_max` | | [MaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxPool) | | | | [MaxRoiPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxRoiPool) | | | -| [Mean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mean) | | `ggml_mean` | +| [Mean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mean) | :white_check_mark: |~~`ggml_mean`~~
`ggml_add` + `ggml_div`| | [Min](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Min) | :white_check_mark: | | | [Mul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mul) | :white_check_mark: | `ggml_mul` | -| [Neg](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Neg) | | `ggml_neg` | +| [Neg](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Neg) | :white_check_mark: | `ggml_neg` | | [Not](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Not) | | | | [Or](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Or) | :white_check_mark: | | | [PRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#PRelu) | | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 7dd5a86d..4b7b0fdb 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -174,6 +174,13 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_where_") backend_test.exclude("test_where_long") # not supported +backend_test.include("test_elu_") +backend_test.exclude(".*elu.*.*ver18.*") + +backend_test.include("test_mean_") +backend_test.include("test_neg_") + + backend_test.exclude(".*pad.*") backend_test.exclude(".*FLOAT*E*M*.*") From b57150cb0dbda755a65a66ec97b4fec71f093d8c Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 25 Aug 2023 15:47:06 -0400 Subject: [PATCH 110/232] Add And, Not and Xor operators --- ggml/contrib/onnx.py | 174 +++++++++++++++++++++++++++++++++++++-- ggml/contrib/progress.md | 6 +- tests/test_ggml_onnx.py | 5 ++ 3 files changed, 174 insertions(+), 11 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index c27a8e50..7fe43cf7 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -212,6 +212,64 @@ def ggml_operator_add( return add_result +@ggml.ggml_custom3_op_t +def custom_and( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.logical_and(a, b) + + set_tensor_out(tensor_out, x) + + +@ggml_operator("And") +def ggml_operator_and( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "And" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a_shape = get_tensor_shape(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) + b_shape = get_tensor_shape(node_inputs[1]) + name = node.output[0] + + output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape + + x = np.empty(output_shape, dtype=a_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_and, + 1, + None, + ) + + ggml.ggml_set_name(new_tensor, (name + f"").encode()) + + return new_tensor + + @ggml.ggml_custom2_op_t def custom_cast( tensor_out: ggml.ggml_tensor_p, @@ -1299,21 +1357,47 @@ def ggml_operator_neg( return x_neg -@ggml.ggml_custom2_op_t -def custom_pow( +@ggml.ggml_custom1_op_t +def custom_not( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, ith: int, nth: int, userdata: Optional[ctypes.c_void_p], ): - x1 = ggml.utils.to_numpy(tensor_in_1) - x2 = ggml.utils.to_numpy(tensor_in_2) + a = ggml.utils.to_numpy(tensor_in_1) + x = np.logical_not(a) - new_tensor = np.power(x1, x2) + set_tensor_out(tensor_out, x) - set_tensor_out(tensor_out, new_tensor) + +@ggml_operator("Not") +def ggml_operator_not( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Not" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + name = node.output[0] + + new_tensor = tensors_dict[name] = ggml.ggml_map_custom1_inplace( + context, + node_inputs[0], + custom_not, + 1, + None, + ) + + ggml.ggml_set_name(new_tensor, (name + f"").encode()) + + return new_tensor @ggml.ggml_custom3_op_t @@ -1374,6 +1458,23 @@ def ggml_operator_or( return new_tensor +@ggml.ggml_custom2_op_t +def custom_pow( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x1 = ggml.utils.to_numpy(tensor_in_1) + x2 = ggml.utils.to_numpy(tensor_in_2) + + new_tensor = np.power(x1, x2) + + set_tensor_out(tensor_out, new_tensor) + + @ggml_operator("Pow") def ggml_operator_pow( backend: "GgmlBackendRep", @@ -1889,7 +1990,6 @@ def ggml_operator_shape( return new_tensor - @ggml_operator("Softmax") def ggml_operator_softmax( backend: "GgmlBackendRep", @@ -2148,6 +2248,64 @@ def ggml_operator_where( return new_tensor +@ggml.ggml_custom3_op_t +def custom_xor( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.logical_xor(a, b) + + set_tensor_out(tensor_out, x) + + +@ggml_operator("Xor") +def ggml_operator_xor( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Xor" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a_shape = get_tensor_shape(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) + b_shape = get_tensor_shape(node_inputs[1]) + name = node.output[0] + + output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape + + x = np.empty(output_shape, dtype=a_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( + context, + x_t, + node_inputs[0], + node_inputs[1], + custom_xor, + 1, + None, + ) + + ggml.ggml_set_name(new_tensor, (name + f"").encode()) + + return new_tensor + + class GgmlBackendRep(BackendRep): def __init__( self, diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index 9d990b18..9f99355d 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -5,7 +5,7 @@ |:--------------------------------------------------------------------------------------------------|:------------------:|:----------------:| | [Abs](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Abs) | :white_check_mark: | `ggml_abs` | | [Add](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Add) | :white_check_mark: | `ggml_add` | -| [And](https://github.com/onnx/onnx/blob/main/docs/Operators.md#And) | | | +| [And](https://github.com/onnx/onnx/blob/main/docs/Operators.md#And) | :white_check_mark: | | | [ArgMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMax) | | | | [ArgMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMin) | | | | [AveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#AveragePool) | | | @@ -54,7 +54,7 @@ | [Min](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Min) | :white_check_mark: | | | [Mul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mul) | :white_check_mark: | `ggml_mul` | | [Neg](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Neg) | :white_check_mark: | `ggml_neg` | -| [Not](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Not) | | | +| [Not](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Not) | :white_check_mark: | | | [Or](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Or) | :white_check_mark: | | | [PRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#PRelu) | | | | [Pad](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad) | | | @@ -97,4 +97,4 @@ | [Transpose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Transpose) | :white_check_mark: | `ggml_transpose` | | [Unsqueeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Unsqueeze) | :white_check_mark: | | | [Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample) | | | -| [Xor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Xor) | | | +| [Xor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Xor) | :white_check_mark: | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 4b7b0fdb..ec0ac407 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -180,6 +180,11 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_mean_") backend_test.include("test_neg_") +backend_test.include("test_or_") +backend_test.include("test_not_") +backend_test.include("test_and_") +backend_test.include("test_xor_") + backend_test.exclude(".*pad.*") backend_test.exclude(".*FLOAT*E*M*.*") From 62cce9820e53e4403a3fb2b459d324ebb44bbbc9 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 25 Aug 2023 16:25:59 -0400 Subject: [PATCH 111/232] Add Size, Sigmoid and HardSigmoid --- ggml/contrib/onnx.py | 157 +++++++++++++++++++++++++++++++++++++++ ggml/contrib/progress.md | 8 +- tests/test_ggml_onnx.py | 7 ++ 3 files changed, 168 insertions(+), 4 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 7fe43cf7..d3848da1 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -868,6 +868,67 @@ def ggml_operator_greater( return new_tensor +class HardSigmoidUserData(ctypes.Structure): + _fields_ = [ + ("alpha", ctypes.c_float), + ("beta", ctypes.c_float), + ] + + +@ggml.ggml_custom1_op_t +def custom_hard_sigmoid( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(HardSigmoidUserData)) + userdata_data = userdata_data_ptr.contents + x = ggml.utils.to_numpy(tensor_in_1) + alpha = userdata_data.alpha + beta = userdata_data.beta + + y = np.clip((x * alpha) + beta, 0, 1) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("HardSigmoid") +def ggml_operator_size( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Sigmoid" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + alpha = next((attr.f for attr in node.attribute if attr.name == "alpha"), 0.2) + beta = next((attr.f for attr in node.attribute if attr.name == "beta"), 0.5) + + hsig_userdata = HardSigmoidUserData(alpha, beta) + userdata_p = ctypes.cast(ctypes.pointer(hsig_userdata), ctypes.c_void_p) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x, + custom_hard_sigmoid, + 1, + userdata_p, + ) + + refs.append(userdata_p) + + return new_tensor + + @ggml.ggml_custom3_op_t def custom_greater_equal( tensor_out: ggml.ggml_tensor_p, @@ -1990,6 +2051,102 @@ def ggml_operator_shape( return new_tensor + +@ggml.ggml_custom1_op_t +def custom_sigmoid( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_1) + + y = 1.0 / (1.0 + np.exp(np.negative(x))) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("Sigmoid") +def ggml_operator_size( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Sigmoid" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x, + custom_sigmoid, + 1, + None, + ) + + return new_tensor + + +@ggml.ggml_custom2_op_t +def custom_size( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + tensor = ggml.utils.to_numpy(tensor_in_2) + set_tensor_out(tensor_out, tensor) + + +@ggml_operator("Size") +def ggml_operator_size( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Size" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + tensor_shape = np.array(get_tensor_shape(node_inputs[0]), dtype=np.int32) + name = node.output[0] + tensor_size_np = np.prod(tensor_shape).astype(np.int32) + tensor_size_np = np.array( + [tensor_size_np] + ) # Add a rank so ggml doesnt break the value, inside the custom reshape to scalar as expected + tensor_size_t = ggml.utils.from_numpy(np.array([tensor_size_np]), context) + + ggml_type = map_to_ggml_type(tensor_size_np.dtype).value + x_t = ggml.ggml_new_tensor(context, ggml_type, 0, (ctypes.c_int64 * 0)(*())) + + new_tensor = tensors_dict[name] = ggml.ggml_map_custom2_inplace( + context, + x_t, + tensor_size_t, + custom_size, + 1, + None, + ) + + ggml.ggml_set_name(new_tensor, (name + f"").encode()) + + return new_tensor + + @ggml_operator("Softmax") def ggml_operator_softmax( backend: "GgmlBackendRep", diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index 9f99355d..c0656da4 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -31,8 +31,8 @@ | [GlobalAveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalAveragePool) | | | | [GlobalLpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalLpPool) | | | | [GlobalMaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalMaxPool) | | | -| [Greater](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Greater) | | | -| [HardSigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSigmoid) | | | +| [Greater](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Greater) | :white_check_mark: | | +| [HardSigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSigmoid) | :white_check_mark: | | | [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | | | | [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | | | | [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | | | @@ -79,8 +79,8 @@ | [Reshape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reshape) | :white_check_mark: | `ggml_reshape` | | [Selu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Selu) | | | | [Shape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Shape) | :white_check_mark: | | -| [Sigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sigmoid) | | | -| [Size](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Size) | | | +| [Sigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sigmoid) | :white_check_mark: | | +| [Size](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Size) | :white_check_mark: | | | [Slice](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Slice) | | | | [Softmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softmax) | :white_check_mark: | `ggml_soft_max` | | [Softplus](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softplus) | | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index ec0ac407..a6c2d199 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -186,7 +186,14 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_xor_") +backend_test.include("test_size_") +backend_test.include("test_sigmoid_") +backend_test.include("test_hardsigmoid_") +backend_test.exclude(".*hardsigmoid.*.*ver18.*") + + backend_test.exclude(".*pad.*") +backend_test.exclude(".*ver18.*") backend_test.exclude(".*FLOAT*E*M*.*") # import all test cases at global scope to make them visible to python.unittest From 6461168912460dc1c8f04ac53acbce9eba47580e Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Fri, 25 Aug 2023 17:00:27 -0400 Subject: [PATCH 112/232] Add Hardmax --- ggml/contrib/onnx.py | 50 ++++++++++++++++++++++++++++++++++++++++ ggml/contrib/progress.md | 2 +- tests/test_ggml_onnx.py | 3 ++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index d3848da1..d12256a9 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -929,6 +929,56 @@ def ggml_operator_size( return new_tensor +@ggml.ggml_custom1_op_t +def custom_hardmax( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + x = ggml.utils.to_numpy(tensor_in_1) + + max_indices = np.argmax(x, axis=axis, keepdims=True) + y = np.zeros_like(x) + np.put_along_axis(y, max_indices, 1, axis=axis) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("Hardmax") +def ggml_operator_hardmax( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Hardmax" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + axis = next((attr.i for attr in node.attribute if attr.name == "axis"), -1) + axis_c = ctypes.c_int(axis) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x, + custom_hardmax, + 1, + ctypes.pointer(axis_c), + ) + + refs.append(axis_c) + + return new_tensor + + @ggml.ggml_custom3_op_t def custom_greater_equal( tensor_out: ggml.ggml_tensor_p, diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index c0656da4..acbbd752 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -33,7 +33,7 @@ | [GlobalMaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalMaxPool) | | | | [Greater](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Greater) | :white_check_mark: | | | [HardSigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSigmoid) | :white_check_mark: | | -| [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | | | +| [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | :white_check_mark: | | | [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | | | | [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | | | | [InstanceNormaliza](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormaliza) | | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index a6c2d199..ff2fa35e 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -191,9 +191,10 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_hardsigmoid_") backend_test.exclude(".*hardsigmoid.*.*ver18.*") +backend_test.include("test_hardmax_") + backend_test.exclude(".*pad.*") -backend_test.exclude(".*ver18.*") backend_test.exclude(".*FLOAT*E*M*.*") # import all test cases at global scope to make them visible to python.unittest From ef8e2471e8657863eba5059d31e6a1e913657d33 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 28 Aug 2023 12:30:02 -0400 Subject: [PATCH 113/232] Add ReduceMin, ReduceProd and ReduceSumSquare + bug fix Also updates UserData for Reduce operators --- ggml/contrib/onnx.py | 332 ++++++++++++++++++++++++++++++++------- ggml/contrib/progress.md | 8 +- tests/test_ggml_onnx.py | 22 ++- 3 files changed, 297 insertions(+), 65 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index d12256a9..32524871 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1670,7 +1670,7 @@ def ggml_operator_range( return new_tensor -class ReduceMaxUserData(ctypes.Structure): +class ReduceOpsUserData(ctypes.Structure): _fields_ = [ ("axes", ctypes.POINTER(ctypes.c_int)), ("axes_length", ctypes.c_int), @@ -1696,7 +1696,7 @@ def custom_reduce_max( nth: int, userdata: Optional[ctypes.c_void_p], ): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceMaxUserData)) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents tensor = ggml.utils.to_numpy(tensor_in_2) @@ -1732,16 +1732,14 @@ def ggml_operator_reduce_max( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) != 2: - raise ValueError( - f'Error for node "{node.name}": Operation "ReduceMean" requires an axis.' - ) - - axes_eval = backend.eval_tensor(node_inputs[1], context) - axes = ggml.utils.to_numpy(axes_eval) + axes = [] + else: + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) - rmean_userdata = ReduceMeanUserData(list(axes), keepdims) + rmean_userdata = ReduceOpsUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) output_shape = tuple([1] * len(tensor_shape)) if keepdims else () @@ -1774,23 +1772,6 @@ def ggml_operator_reduce_max( return new_tensor -class ReduceMeanUserData(ctypes.Structure): - _fields_ = [ - ("axes", ctypes.POINTER(ctypes.c_int)), - ("axes_length", ctypes.c_int), - ("keepdims", ctypes.c_int), - ] - - def __init__(self, axes, keepdims): - if isinstance(axes, list): - self.axes_length = len(axes) - self.axes = (ctypes.c_int * self.axes_length)(*axes) - else: - raise ValueError("axes should be a list of integers") - - self.keepdims = keepdims - - @ggml.ggml_custom2_op_t def custom_reduce_mean( tensor_out: ggml.ggml_tensor_p, @@ -1800,7 +1781,7 @@ def custom_reduce_mean( nth: int, userdata: Optional[ctypes.c_void_p], ): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceMeanUserData)) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents tensor = ggml.utils.to_numpy(tensor_in_2) @@ -1836,16 +1817,14 @@ def ggml_operator_reduce_mean( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) != 2: - raise ValueError( - f'Error for node "{node.name}": Operation "ReduceMean" requires an axis.' - ) - - axes_eval = backend.eval_tensor(node_inputs[1], context) - axes = ggml.utils.to_numpy(axes_eval) + axes = [] + else: + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) - rmean_userdata = ReduceMeanUserData(list(axes), keepdims) + rmean_userdata = ReduceOpsUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) output_shape = tuple([1] * len(tensor_shape)) if keepdims else () @@ -1878,21 +1857,174 @@ def ggml_operator_reduce_mean( return new_tensor -class ReduceSumUserData(ctypes.Structure): - _fields_ = [ - ("axes", ctypes.POINTER(ctypes.c_int)), - ("axes_length", ctypes.c_int), - ("keepdims", ctypes.c_int), - ] +@ggml.ggml_custom2_op_t +def custom_reduce_min( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents - def __init__(self, axes, keepdims): - if isinstance(axes, list): - self.axes_length = len(axes) - self.axes = (ctypes.c_int * self.axes_length)(*axes) + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rmean_result = np.minimum.reduce(tensor, axis=axes, keepdims=keepdims) + + set_tensor_out(tensor_out, rmean_result) + + +@ggml_operator("ReduceMin") +def ggml_operator_reduce_mean( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) > 2 or len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceMin" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + input_tensor = node_inputs[0] + + tensor_shape = get_tensor_shape(input_tensor) + tensor_dtype = get_tensor_dtype(input_tensor) + + axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) + if not axes: + if len(node_inputs) != 2: + axes = [] else: - raise ValueError("axes should be a list of integers") + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) - self.keepdims = keepdims + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + + rmean_userdata = ReduceOpsUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) + + output_shape = tuple([1] * len(tensor_shape)) if keepdims else () + + if len(axes): + output_shape = list(tensor_shape) + sorted_axes = sorted(axes, reverse=True) + + for axis in sorted_axes: + if keepdims: + output_shape[axis] = 1 + else: + output_shape.pop(axis) + + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + input_tensor, + custom_reduce_min, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor + + +@ggml.ggml_custom2_op_t +def custom_reduce_prod( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rmean_result = np.prod(tensor, axis=axes, keepdims=keepdims) + + set_tensor_out(tensor_out, rmean_result) + + +@ggml_operator("ReduceProd") +def ggml_operator_reduce_prod( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) > 2 or len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceProd" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + input_tensor = node_inputs[0] + + tensor_shape = get_tensor_shape(input_tensor) + tensor_dtype = get_tensor_dtype(input_tensor) + + axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) + if not axes: + if len(node_inputs) != 2: + axes = [] + else: + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) + + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + + rmean_userdata = ReduceOpsUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) + + output_shape = tuple([1] * len(tensor_shape)) if keepdims else () + + if len(axes): + output_shape = list(tensor_shape) + sorted_axes = sorted(axes, reverse=True) + + for axis in sorted_axes: + if keepdims: + output_shape[axis] = 1 + else: + output_shape.pop(axis) + + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + input_tensor, + custom_reduce_prod, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor @ggml.ggml_custom2_op_t @@ -1904,7 +2036,7 @@ def custom_reduce_sum( nth: int, userdata: Optional[ctypes.c_void_p], ): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceSumUserData)) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents tensor = ggml.utils.to_numpy(tensor_in_2) @@ -1913,7 +2045,6 @@ def custom_reduce_sum( axes = tuple(axes) if len(axes) else None result = np.sum(tensor, axis=axes, keepdims=keepdims) - set_tensor_out(tensor_out, result) @@ -1934,22 +2065,28 @@ def ggml_operator_reduce_sum( input_tensor = node_inputs[0] + noop_with_empty_axes = next( + (attr.i for attr in node.attribute if attr.name == "noop_with_empty_axes"), None + ) + + if noop_with_empty_axes == 1: + tensors_dict[node.output[0]] = input_tensor + return input_tensor + tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) != 2: - raise ValueError( - f'Error for node "{node.name}": Operation "ReduceMean" requires an axis.' - ) - - axes_eval = backend.eval_tensor(node_inputs[1], context) - axes = ggml.utils.to_numpy(axes_eval) + axes = [] + else: + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) - rmean_userdata = ReduceSumUserData(list(axes), keepdims) + rmean_userdata = ReduceOpsUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) output_shape = tuple([1] * len(tensor_shape)) if keepdims else () @@ -1982,6 +2119,91 @@ def ggml_operator_reduce_sum( return new_tensor +@ggml.ggml_custom2_op_t +def custom_reduce_sum_square( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + result = np.sum(np.square(tensor), axis=axes, keepdims=keepdims) + + set_tensor_out(tensor_out, result) + + +@ggml_operator("ReduceSumSquare") +def ggml_operator_reduce_sum_square( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) > 2 or len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceSumSquare" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + input_tensor = node_inputs[0] + + tensor_shape = get_tensor_shape(input_tensor) + tensor_dtype = get_tensor_dtype(input_tensor) + + axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) + if not axes: + if len(node_inputs) != 2: + axes = [] + else: + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) + + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + + rmean_userdata = ReduceOpsUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) + + output_shape = tuple([1] * len(tensor_shape)) if keepdims else () + + if len(axes): + output_shape = list(tensor_shape) + sorted_axes = sorted(axes, reverse=True) + + for axis in sorted_axes: + if keepdims: + output_shape[axis] = 1 + else: + output_shape.pop(axis) + + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + input_tensor, + custom_reduce_sum_square, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor + + @ggml_operator("Relu") def ggml_operator_relu( backend: "GgmlBackendRep", diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index acbbd752..2aaf6623 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -71,10 +71,10 @@ | [ReduceLogSumExp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSumExp) | | | | [ReduceMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMax) | :white_check_mark: | | | [ReduceMean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMean) | :white_check_mark: | | -| [ReduceMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMin) | | | -| [ReduceProd](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceProd) | | | -| [ReduceSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSum) | :white_check_mark: | `ggml_sum`? | -| [ReduceSumSquare](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSumSquare) | | | +| [ReduceMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMin) | :white_check_mark: | | +| [ReduceProd](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceProd) | :white_check_mark: | | +| [ReduceSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSum) | :white_check_mark: | | +| [ReduceSumSquare](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSumSquare) | :white_check_mark: | | | [Relu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Relu) | :white_check_mark: | `ggml_relu` | | [Reshape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reshape) | :white_check_mark: | `ggml_reshape` | | [Selu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Selu) | | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index ff2fa35e..2c4165aa 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -101,7 +101,9 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_concat_") + backend_test.include("test_constant_") +backend_test.exclude(".*constant.*.*pad.*") backend_test.include("test_div_") @@ -141,10 +143,22 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_range_float") # segfault backend_test.exclude("test_range_int32") # segfault +backend_test.include("test_reduce_max_") backend_test.include("test_reduce_mean_") +backend_test.include("test_reduce_min_") +backend_test.include("test_reduce_prod_") +backend_test.include("test_reduce_sum_") backend_test.include("test_relu_") -backend_test.exclude("test_relu_expanded") # not supported +backend_test.include("test_ReLU_") +backend_test.exclude(".*relu.*.*ver18.*") + +backend_test.include("test_elu_") +backend_test.include("test_ELU_") +backend_test.exclude(".*elu.*.*ver18.*") + +backend_test.include("test_selu_") +backend_test.exclude(".*selu.*.*ver18.*") backend_test.include("test_reshape_") backend_test.exclude("test_reshape_allowzero") # not supported @@ -174,9 +188,6 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_where_") backend_test.exclude("test_where_long") # not supported -backend_test.include("test_elu_") -backend_test.exclude(".*elu.*.*ver18.*") - backend_test.include("test_mean_") backend_test.include("test_neg_") @@ -191,10 +202,9 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_hardsigmoid_") backend_test.exclude(".*hardsigmoid.*.*ver18.*") -backend_test.include("test_hardmax_") +backend_test.include("test_hardmax_") -backend_test.exclude(".*pad.*") backend_test.exclude(".*FLOAT*E*M*.*") # import all test cases at global scope to make them visible to python.unittest From d998de55debce2255555170b7e45e30e943e1a94 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 28 Aug 2023 12:50:23 -0400 Subject: [PATCH 114/232] Add note to table --- ggml/contrib/progress.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index 2aaf6623..080a7c20 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -1,6 +1,6 @@ # Operator Implementation Progress - +This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/blob/main/onnx/defs/operator_sets.h) and may not include all ONNX operators. These are core operators available in all versions starting from ai.onnx version 1. | ONNX Operators | Implemented | ggml Equivalent | |:--------------------------------------------------------------------------------------------------|:------------------:|:----------------:| | [Abs](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Abs) | :white_check_mark: | `ggml_abs` | @@ -98,3 +98,4 @@ | [Unsqueeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Unsqueeze) | :white_check_mark: | | | [Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample) | | | | [Xor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Xor) | :white_check_mark: | | + From 974787fcfe38c176824bb54de6b2d0fbdba3bbe9 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 28 Aug 2023 15:26:31 -0400 Subject: [PATCH 115/232] Remove unnecessary tests --- tests/test_ggml_onnx_ops.py | 1898 ----------------------------------- 1 file changed, 1898 deletions(-) delete mode 100644 tests/test_ggml_onnx_ops.py diff --git a/tests/test_ggml_onnx_ops.py b/tests/test_ggml_onnx_ops.py deleted file mode 100644 index 2219002f..00000000 --- a/tests/test_ggml_onnx_ops.py +++ /dev/null @@ -1,1898 +0,0 @@ -import ctypes -import io -import os -import sys -from io import BytesIO - -import numpy as np -import onnx -import onnxruntime as ort -import pytest -import torch -import torch.onnx -from onnx import TensorProto, helper, numpy_helper -from onnxruntime import InferenceSession - -import contextlib -import ggml -import ggml.utils -from ggml.contrib.onnx import GgmlRuntimeBackend, ggml_operators, GgmlBackendRep - - -@pytest.mark.skip(reason="broken") -def test_ggml_onnx_runtime_shape_operator(): - # return - - tensors_dict = {} - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - - test_list = [0, 1, 2, 3, 5, 6, 7, 8, 9, 10] - - input_data1 = np.array(test_list, dtype=np.int32) - - tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_data1, context) - - tensors_dict["start1"] = ggml.utils.from_numpy( - np.array([0], dtype=np.int32), context - ) - tensors_dict["end1"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) - - tensors_dict["start2"] = ggml.utils.from_numpy( - np.array([2], dtype=np.int32), context - ) - tensors_dict["end2"] = ggml.utils.from_numpy(np.array([6], dtype=np.int32), context) - - shape_node1 = onnx.helper.make_node( - "Shape", - name="Shape1", - inputs=["input_tensor"], - outputs=["output_tensor1"], - ) - - shape_node2 = onnx.helper.make_node( - "Shape", - name="Shape2", - inputs=["input_tensor", "start1", "end1"], - outputs=["output_tensor2"], - ) - - shape_node3 = onnx.helper.make_node( - "Shape", - name="Shape3", - inputs=["input_tensor", "start2", "end2"], - outputs=["output_tensor3"], - ) - - nodes = [shape_node1, shape_node2, shape_node3] - results = [] - refs = [] - - for shape_node in nodes: - output_tensor = ggml_operators["Shape"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - shape_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert results[0] == list(input_data1.shape) - assert results[1] == list(input_data1[:6].shape) - assert results[2] == list(input_data1[2:6].shape) - - ggml.ggml_free(context) - - -def test_ggml_onnx_runtime_unsqueeze_operator(): - # return - - def onnx_unsqueeze(x, axes): - class UnsqueezeModel(torch.nn.Module): - def forward(self, input): - for axis in axes: - input = torch.unsqueeze(input, dim=axis) - return input - - model = UnsqueezeModel() - - x_tensor = torch.tensor(x, dtype=torch.int32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - x_tensor, - f, - input_names=["data"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - input_feed = {"data": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - tensors_dict = {} - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - - test_x = [0, 1, 2, 3, 5, 6] - test_axes1 = np.array([1], dtype=np.int32) - test_axes2 = np.array([0], dtype=np.int32) - test_axes3 = np.array([1, 2], dtype=np.int32) - - input_data1 = np.array(test_x, dtype=np.int32) - - tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_data1, context) - - tensors_dict["axes1"] = ggml.utils.from_numpy(test_axes1, context) - tensors_dict["axes2"] = ggml.utils.from_numpy(test_axes2, context) - tensors_dict["axes3"] = ggml.utils.from_numpy(test_axes3, context) - - unsqueeze_node1 = onnx.NodeProto() - unsqueeze_node1.name = "Input error Test" - unsqueeze_node1.op_type = "Unsqueeze" - unsqueeze_node1.input.extend(["input_tensor"]) - unsqueeze_node1.output.extend(["output_tensor1"]) - - unsqueeze_node2 = onnx.NodeProto() - unsqueeze_node2.op_type = "Unsqueeze" - unsqueeze_node2.input.extend(["input_tensor", "axes1"]) - unsqueeze_node2.output.extend(["output_tensor2"]) - - unsqueeze_node3 = onnx.NodeProto() - unsqueeze_node3.op_type = "Unsqueeze" - unsqueeze_node3.input.extend(["input_tensor", "axes2"]) - unsqueeze_node3.output.extend(["output_tensor3"]) - - unsqueeze_node4 = onnx.NodeProto() - unsqueeze_node4.op_type = "Unsqueeze" - unsqueeze_node4.input.extend(["input_tensor", "axes3"]) - unsqueeze_node4.output.extend(["output_tensor4"]) - - refs = [] - nodes = [unsqueeze_node2, unsqueeze_node3, unsqueeze_node4] - results = [] - - with pytest.raises(ValueError) as ex_input_error: - ggml_operators["Unsqueeze"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - unsqueeze_node1, - tensors_dict, - context, - refs, - ) - - for shape_node in nodes: - output_tensor = ggml_operators["Unsqueeze"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - shape_node, - tensors_dict, - context, - refs, - ) - - gf = ggml.ggml_build_forward(output_tensor) - - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - - results.append(ggml.utils.to_numpy(output_tensor)) - - assert ( - str(ex_input_error.value) - == 'Error for node "Input error Test": Operation "Unsqueeze" requires exactly two inputs, data and axes. Actual number of inputs: 1' - ) - - assert np.array_equal(results[0], onnx_unsqueeze(input_data1, test_axes1)) - assert np.array_equal(results[1], onnx_unsqueeze(input_data1, test_axes2)) - assert np.array_equal(results[2], onnx_unsqueeze(input_data1, test_axes3)) - - ggml.ggml_free(context) - - -def test_ggml_onnx_runtime_gather_operator(): - # return - - def onnx_gather(x, indices, axis): - if axis < 0: - axis += len(x.shape) - - node_def = onnx.helper.make_node( - "Gather", inputs=["data", "indices"], outputs=["output"], axis=axis - ) - output_shape = list(x.shape) # Initial assumption, adjust if needed - output_shape[axis] = indices.shape[0] # Update the size along the gather axis - graph_def = onnx.helper.make_graph( - [node_def], - "gather_model", - inputs=[ - onnx.helper.make_tensor_value_info( - "data", onnx.TensorProto.INT32, list(x.shape) - ), - onnx.helper.make_tensor_value_info( - "indices", onnx.TensorProto.INT32, list(indices.shape) - ), - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "output", onnx.TensorProto.INT32, output_shape - ) - ], - ) - model_def = onnx.helper.make_model( - graph_def, producer_name="onnx_gather_example" - ) - - onnx_model_bytes = BytesIO() - onnx.save_model(model_def, onnx_model_bytes) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - indices_list = indices.tolist() - - input_feed = {"data": x_list, "indices": indices_list} - - output = sess.run(None, input_feed) - - return output[0] - - tensors_dict = {} - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - - test_x = [ - 1046676483, - -1102854076, - -1089318038, - 1023432841, - 1041114519, - -1099187814, - 1040889675, - -1088007423, - -1096868517, - -1131772615, - -1103856891, - -1097108246, - -1098364964, - 1024061975, - -1102637477, - ] - test_indices1 = np.array([1], dtype=np.int32) - - input_data1 = np.array(test_x, dtype=np.int32) - - input_tensor = ggml.utils.from_numpy(input_data1, context) - indices_tensor = ggml.utils.from_numpy(test_indices1, context) - - tensors_dict["input_tensor"] = input_tensor - tensors_dict["indices"] = indices_tensor - - gather_node2 = onnx.helper.make_node( - "Gather", - name="/Gather", - inputs=["input_tensor", "indices"], - outputs=["output_tensor2"], - axis=0, - ) - - refs = [] - - output_tensor = ggml_operators["Gather"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - gather_node2, - tensors_dict, - context, - refs, - ) - - gf = ggml.ggml_build_forward(output_tensor) - - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - output_tensor = ggml.ggml_get_tensor(context, ggml.ggml_get_name(output_tensor)) - - assert np.array_equal( - ggml.utils.to_numpy(output_tensor), onnx_gather(input_data1, test_indices1, 0) - ) - - ggml.ggml_free(context) - - -def test_ggml_onnx_constant_operator(): - # return - - def onnx_constant(value, dtype, shape): - tensor = numpy_helper.from_array(value) - constant_node = onnx.helper.make_node( - "Constant", inputs=[], outputs=["constant_output"], value=tensor - ) - graph = onnx.helper.make_graph( - [constant_node], - "constant_graph", - inputs=[], - outputs=[ - onnx.helper.make_tensor_value_info("constant_output", dtype, shape) - ], - ) - model = onnx.helper.make_model(graph) - - return numpy_helper.to_array(model.graph.node[0].attribute[0].t) - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - - constant1 = np.array([1], dtype=np.int32) - constant2 = np.array([[1]], dtype=np.int32) - constant3 = np.array([[1, 2], [3, 4], [6, 6]], dtype=np.int32) - constant4 = np.array(6, dtype=np.int64) - - dtype = onnx.TensorProto.INT32 - - constant_numpy1 = onnx_constant(constant1, dtype, constant1.shape) - constant_numpy2 = onnx_constant(constant2, dtype, constant2.shape) - constant_numpy3 = onnx_constant(constant3, dtype, constant3.shape) - constant_numpy4 = onnx_constant(constant4, dtype, constant4.shape) - - constant_node1 = onnx.helper.make_node( - "Constant", - inputs=[], - name="constant_node1", - outputs=["constant_output1"], - value=numpy_helper.from_array(constant1), - ) - constant_node2 = onnx.helper.make_node( - "Constant", - name="constant_node2", - inputs=[], - outputs=["constant_output2"], - value=numpy_helper.from_array(constant2), - ) - constant_node3 = onnx.helper.make_node( - "Constant", - name="constant_node3", - inputs=[], - outputs=["constant_output3"], - value=numpy_helper.from_array(constant3), - ) - - constant_node4 = onnx.helper.make_node( - "Constant", - name="constant_node3", - inputs=[], - outputs=["constant_output3"], - value=numpy_helper.from_array(constant4), - ) - - nodes = [constant_node1, constant_node2, constant_node3, constant_node4] - results = [] - refs = [] - - for shape_node in nodes: - output_tensor = ggml_operators["Constant"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - shape_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.array_equal(results[0], constant_numpy1) - assert np.array_equal(results[1], constant_numpy2) - assert np.array_equal(results[2], constant_numpy3) - assert results[3] == constant_numpy4 - - ggml.ggml_free(context) - - -def test_ggml_onnx_constant_of_shape_operator(): - # return - - def onnx_constant_of_shape(value, other): - value = numpy_helper.from_array(value) - constant_node = onnx.helper.make_node( - "ConstantOfShape", inputs=["data"], outputs=["constant_output"], value=value - ) - graph = onnx.helper.make_graph( - [constant_node], - "constant_graph", - inputs=[ - onnx.helper.make_tensor_value_info( - "data", onnx.TensorProto.INT64, list(other.shape) - ) - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "constant_output", - onnx.TensorProto.FLOAT, - other.astype(np.int32).tolist(), - ) - ], - ) - model = onnx.helper.make_model(graph) - - onnx_model_bytes = BytesIO() - onnx.save_model(model, onnx_model_bytes) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = other.tolist() - input_feed = {"data": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - - shape1 = np.array([2, 3, 4], dtype=np.int32) - value_tensor = np.array([15], dtype=np.float32) - - cof_node1 = onnx.helper.make_node( - "ConstantOfShape", - inputs=["shape1"], - name="cof_node1", - outputs=["cof_output"], - value=numpy_helper.from_array(value_tensor), - ) - - tensors_dict["shape1"] = ggml.utils.from_numpy(shape1, context) - - constant_onnx = onnx_constant_of_shape(value_tensor, shape1) - - nodes = [cof_node1] - results = [] - refs = [] - - for shape_node in nodes: - output_tensor = ggml_operators["ConstantOfShape"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - shape_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - assert np.array_equal(results[0], constant_onnx) - - ggml.ggml_free(context) - - -def test_ggml_onnx_concat_operator(): - # return - - def onnx_concat(inputs, axis): - input_data_type = inputs[0].dtype - - graph = onnx.GraphProto() - - input_names = [] - for i, input_array in enumerate(inputs): - input_name = f"input{i}" - input_names.append(input_name) - - input_value_info = onnx.helper.make_tensor_value_info( - input_name, - onnx.TensorProto.FLOAT - if input_data_type == np.float32 - else onnx.TensorProto.INT32, - input_array.shape, - ) - graph.input.extend([input_value_info]) - - concat_node = onnx.NodeProto() - concat_node.op_type = "Concat" - concat_node.name = "concat_node" - concat_node.output.extend(["output"]) - concat_node.attribute.extend([onnx.helper.make_attribute("axis", axis)]) - concat_node.input.extend(input_names) - - output_value_info = onnx.helper.make_tensor_value_info( - "output", - onnx.TensorProto.FLOAT - if input_data_type == np.float32 - else onnx.TensorProto.INT32, - None, - ) - graph.output.extend([output_value_info]) - - graph.node.extend([concat_node]) - model = onnx.helper.make_model(graph) - - onnx_model_bytes = BytesIO() - onnx.save_model(model, onnx_model_bytes) - - # Load the ONNX model from BytesIO - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = { - input_name: input_array - for input_name, input_array in zip(input_names, inputs) - } - - output = sess.run(["output"], input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - - array1 = np.array([1], dtype=np.int32) - array2 = np.array([2, 3, 4, 5], dtype=np.int32) - array3 = np.array([6], dtype=np.int32) - array4 = np.array([7, 8, 9, 10], dtype=np.int32) - - tensors_dict["array1"] = ggml.utils.from_numpy(array1, context) - tensors_dict["array2"] = ggml.utils.from_numpy(array2, context) - tensors_dict["array3"] = ggml.utils.from_numpy(array3, context) - tensors_dict["array4"] = ggml.utils.from_numpy(array4, context) - - test1 = ["array1", "array2"] - inputs1 = [array1, array2] - test2 = ["array1", "array2", "array3", "array4"] - inputs2 = [array1, array2, array3, array4] - axis = 0 - - concat_node1 = onnx.helper.make_node( - "Concat", - inputs=test1, - name="concat_node1", - outputs=["concat_output1"], - axis=axis, - ) - concat_node2 = onnx.helper.make_node( - "Concat", - inputs=test2, - name="concat_node2", - outputs=["concat_output2"], - axis=axis, - ) - - concat_onnx_result1 = onnx_concat(inputs1, axis) - concat_onnx_result2 = onnx_concat(inputs2, axis) - - nodes = [concat_node1, concat_node2] - results = [] - refs = [] - - for concat_node in nodes: - output_tensor = ggml_operators["Concat"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - concat_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.array_equal(results[0], concat_onnx_result1) - assert np.array_equal(results[1], concat_onnx_result2) - - -def test_ggml_onnx_reshape_operation(): - # return - - def onnx_reshape(input_tensor, shape): - class DynamicReshapeModel(torch.nn.Module): - def __init__(self, shape): - super(DynamicReshapeModel, self).__init__() - self.shape = tuple(shape) - - def forward(self, x): - reshaped = torch.reshape(x, self.shape) - return reshaped - - if not isinstance(input_tensor, np.ndarray): - raise ValueError("Input tensor must be a NumPy array") - - if not isinstance(shape, np.ndarray): - shape = np.array(shape) - - if len(shape) != len(input_tensor.shape): - raise ValueError( - "Input shape must have the same number of dimensions as the input tensor" - ) - - model = DynamicReshapeModel(shape) - - input_tensor = torch.tensor(input_tensor, dtype=torch.int32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, input_tensor, f, opset_version=12, do_constant_folding=True - ) - f.seek(0) - sess = ort.InferenceSession(f.getvalue()) - input_name = sess.get_inputs()[0].name - output_name = sess.get_outputs()[0].name - - result = sess.run([output_name], {input_name: input_tensor.numpy()}) - - return result[0] - - input_tensor = np.array([[1, 2, 3, 4, 5, 6]], dtype=np.int32) - new_shape = np.array([2, 3], dtype=np.int32) - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - - tensors_dict["input_tensor"] = ggml.utils.from_numpy(input_tensor, context) - tensors_dict["new_shape"] = ggml.utils.from_numpy(new_shape, context) - - reshape_node1 = onnx.helper.make_node( - "Reshape", - inputs=["input_tensor", "new_shape"], - name="reshape_node1", - outputs=["reshape_output1"], - ) - - nodes = [reshape_node1] - results = [] - refs = [] - - for reshape_node in nodes: - output_tensor = ggml_operators["Reshape"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - reshape_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.array_equal(results[0], onnx_reshape(input_tensor, new_shape)) - - -def test_ggml_onnx_softmax_operator(): - # return - - input_name = "X" - - output_name = "Softmax_Output" - - input_data = { - input_name: np.array([[-1.5, 0.001, 3.73, 5.1, 6, 6.0001]], dtype=np.float32) - } - - node1 = helper.make_node( - "Softmax", [input_name], [output_name], name="softmax_node" - ) - - X_value_info = helper.make_tensor_value_info( - input_name, TensorProto.FLOAT, [None, 6] - ) - - softmax_value_info = helper.make_tensor_value_info( - output_name, TensorProto.FLOAT, [None, 6] - ) - - graph_def = helper.make_graph( - [node1], "softmax_model", [X_value_info], [softmax_value_info] - ) - - model_def = helper.make_model(graph_def, producer_name="onnx-softmax") - - f = io.BytesIO() - onnx.save(model_def, f) - - runtime_result = InferenceSession(f.getvalue()).run(None, input_data) - - ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) - - ggml_result = ggml_dummy_model.run(input_data) - - assert np.allclose(ggml_result, runtime_result, rtol=0.001) - - -def test_ggml_onnx_reducemean_operator(): - # return - - def onnx_reducemean(x, axes): - class ReduceMeanModel(torch.nn.Module): - def forward(self, input): - return torch.mean(input, dim=axes.tolist(), keepdim=False) - - model = ReduceMeanModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - x_tensor, - f, - input_names=["data"], - output_names=["output"], - verbose=False, - ) - - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - input_feed = {"data": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - axes1 = np.array([0, 1], dtype=np.int32) - - input_array2 = np.array([[1, 2, 3, 4]], dtype=np.float32) - axes2 = np.array([1], dtype=np.int32) - - reducemean_numpy1 = onnx_reducemean(input_array1, axes1) - reducemean_numpy2 = onnx_reducemean(input_array2, axes2) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - tensors_dict["axes1"] = ggml.utils.from_numpy(axes1, context) - tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) - tensors_dict["axes2"] = ggml.utils.from_numpy(axes2, context) - - reducemean_node1 = onnx.helper.make_node( - "ReduceMean", - inputs=["input_array1"], - outputs=["reducemean_output1"], - axes=axes1, - keepdims=0, - ) - - reducemean_node2 = onnx.helper.make_node( - "ReduceMean", - inputs=["input_array2"], - outputs=["reducemean_output2"], - axes=axes2, - keepdims=0, - ) - - nodes = [reducemean_node1, reducemean_node2] - results = [] - - for reducemean_node in nodes: - output_tensor = ggml_operators["ReduceMean"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - reducemean_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.allclose(results[0], reducemean_numpy1) - assert np.allclose(results[1], reducemean_numpy2) - - ggml.ggml_free(context) - - -def test_ggml_onnx_less_operator(): - # return - - def onnx_less(x, y): - class LessModel(torch.nn.Module): - def forward(self, input1, input2): - return torch.less(input1, input2) - - model = LessModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - y_tensor = torch.tensor(y, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor, y_tensor), - f, - input_names=["input1", "input2"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - y_list = y.tolist() - input_feed = {"input1": x_list, "input2": y_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - input_array2 = np.array([[2, 2, 2], [5, 5, 5], [8, 8, 8]], dtype=np.float32) - - less_numpy = onnx_less(input_array1, input_array2) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) - - less_node = onnx.helper.make_node( - "Less", - inputs=["input_array1", "input_array2"], - outputs=["less_output"], - ) - - nodes = [less_node] - results = [] - - for less_node in nodes: - output_tensor = ggml_operators["Less"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - less_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.allclose(results[0], less_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_greater_operator(): - # return - - def onnx_greater(x, y): - class GreaterModel(torch.nn.Module): - def forward(self, input1, input2): - return torch.gt(input1, input2) - - model = GreaterModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - y_tensor = torch.tensor(y, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor, y_tensor), - f, - input_names=["input1", "input2"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - y_list = y.tolist() - input_feed = {"input1": x_list, "input2": y_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - input_array2 = np.array([[2, 2, 2], [5, 5, 5], [8, 8, 8]], dtype=np.float32) - - greater_numpy = onnx_greater(input_array1, input_array2) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) - - greater_node = onnx.helper.make_node( - "Greater", - inputs=["input_array1", "input_array2"], - outputs=["greater_output"], - ) - - output_tensor = ggml_operators["Greater"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - greater_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, greater_numpy) - - ggml.ggml_free(context) - - -@pytest.mark.skip(reason="broken") -def test_ggml_onnx_min_operator(): - # return - - def onnx_min(x): - class MinModel(torch.nn.Module): - def forward(self, input1): - return torch.min(input1) - - model = MinModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor), - f, - input_names=["input1"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - input_feed = {"input1": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - - min_numpy = onnx_min(input_array1) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - - min_node = onnx.helper.make_node( - "Min", - inputs=["input_array1"], - outputs=["min_output"], - ) - - output_tensor = ggml_operators["Min"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - min_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, min_numpy) - - ggml.ggml_free(context) - - -@pytest.mark.skip(reason="broken") -def test_ggml_onnx_max_operator(): - # return - - def onnx_max(x): - class MaxModel(torch.nn.Module): - def forward(self, input1): - return torch.max(input1) - - model = MaxModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor), - f, - input_names=["input1"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - input_feed = {"input1": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - min_numpy = onnx_max(input_array1) - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - - min_node = onnx.helper.make_node( - "Min", - inputs=["input_array1"], - outputs=["min_output"], - ) - - output_tensor = ggml_operators["Max"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - min_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, min_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_matmul_operator(): - # return - - def onnx_matmul(x, y): - matmul_node = onnx.helper.make_node( - "MatMul", inputs=["input1", "input2"], outputs=["output"] - ) - - graph = onnx.helper.make_graph( - [matmul_node], - "matmul_graph", - inputs=[ - onnx.helper.make_tensor_value_info( - "input1", onnx.TensorProto.FLOAT, list(x.shape) - ), - onnx.helper.make_tensor_value_info( - "input2", onnx.TensorProto.FLOAT, list(y.shape) - ), - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "output", onnx.TensorProto.FLOAT, list((x.shape[0], y.shape[1])) - ) - ], - ) - - model = onnx.helper.make_model(graph) - - f = BytesIO() - onnx.save_model(model, f) - - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = {"input1": x, "input2": y} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - # Define input arrays - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - input_array2 = np.array([[9, 8, 7], [6, 5, 4], [3, 2, 1]], dtype=np.float32) - - # Compute ONNX MatMul using GGML - matmul_numpy = onnx_matmul(input_array1, input_array2) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) - - matmul_node = onnx.helper.make_node( - "MatMul", - inputs=["input_array1", "input_array2"], - outputs=["matmul_output"], - ) - - output_tensor = ggml_operators["MatMul"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - matmul_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, matmul_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_pow_operator(): - # return - - def onnx_pow(x, y): - class PowModel(torch.nn.Module): - def forward(self, input1, input2): - return torch.pow(input1, input2) - - model = PowModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - y_tensor = torch.tensor(y, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor, y_tensor), - f, - input_names=["input1", "input2"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - y_list = y.tolist() - input_feed = {"input1": x_list, "input2": y_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) - input_array2 = np.array([[2, 2, 2], [3, 3, 3], [4, 4, 4]], dtype=np.float32) - - pow_numpy = onnx_pow(input_array1, input_array2) - - tensors_dict["input_array1"] = ggml.utils.from_numpy(input_array1, context) - tensors_dict["input_array2"] = ggml.utils.from_numpy(input_array2, context) - - pow_node = onnx.helper.make_node( - "Pow", - inputs=["input_array1", "input_array2"], - outputs=["pow_output"], - ) - - nodes = [pow_node] - results = [] - - for pow_node in nodes: - output_tensor = ggml_operators["Pow"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - pow_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.array_equal(results[0], pow_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_relu_operator(): - # return - - def onnx_relu(x): - class ReluModel(torch.nn.Module): - def forward(self, input): - return torch.relu(input) - - model = ReluModel() - - x_tensor = torch.tensor(x, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor,), - f, - input_names=["input"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - x_list = x.tolist() - input_feed = {"input": x_list} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_array = np.array([[1, -2, 3], [-4, 5, -6], [7, -8, 9]], dtype=np.float32) - - relu_numpy = onnx_relu(input_array) - - tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) - - relu_node = onnx.helper.make_node( - "Relu", - inputs=["input_array"], - outputs=["relu_output"], - ) - - nodes = [relu_node] - results = [] - - for relu_node in nodes: - output_tensor = ggml_operators["Relu"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - relu_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - results.append(ggml.utils.to_numpy(output_tensor)) - - assert np.allclose(results[0], relu_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_transpose_operator(): - # return - - def onnx_transpose(x, perm=[1, 0]): - transpose_node = onnx.helper.make_node( - "Transpose", inputs=["input"], outputs=["output"], perm=perm - ) - - graph = onnx.helper.make_graph( - [transpose_node], - "transpose_graph", - inputs=[ - onnx.helper.make_tensor_value_info( - "input", onnx.TensorProto.INT32, list(x.shape) - ) - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "output", onnx.TensorProto.INT32, [list(x.shape)[i] for i in perm] - ) - ], - ) - - model = onnx.helper.make_model(graph) - - f = BytesIO() - onnx.save_model(model, f) - - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = {"input": x} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - import itertools - - shape = (2, 3, 4) - input_array = np.arange(np.prod(shape), dtype=np.int32).reshape(shape) - permutations = list(itertools.permutations(np.arange(len(input_array.shape)))) - - tensors_dict["input_array"] = ggml.utils.from_numpy(input_array, context) - print() - print() - for i, permutation in enumerate(permutations): - transpose_node = onnx.helper.make_node( - "Transpose", - inputs=["input_array"], - outputs=[f"transpose_output{i}"], - perm=permutation, - ) - - onnx_result = onnx_transpose(input_array, permutation) - - output_tensor = ggml_operators["Transpose"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - transpose_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - ggml_result = ggml.utils.to_numpy(output_tensor) - test_result = np.array_equal(ggml_result, onnx_result) - - print("test_result:", test_result, " Perm:", *permutation) - if not test_result: - print("ggml:\n", ggml_result) - print("onnx:\n", onnx_result) - print() - - print() - print() - ggml.ggml_free(context) - - -def test_ggml_onnx_range_operator(): - # return - - def onnx_range(start, limit, delta): - range_node = onnx.helper.make_node( - "Range", - inputs=["start", "limit", "delta"], - outputs=["output"], - ) - - graph = onnx.helper.make_graph( - [range_node], - "range_graph", - inputs=[ - onnx.helper.make_tensor_value_info( - "start", onnx.TensorProto.FLOAT, list(start.shape) - ), - onnx.helper.make_tensor_value_info( - "limit", onnx.TensorProto.FLOAT, list(limit.shape) - ), - onnx.helper.make_tensor_value_info( - "delta", onnx.TensorProto.FLOAT, list(delta.shape) - ), - ], - outputs=[ - onnx.helper.make_tensor_value_info( - "output", - onnx.TensorProto.FLOAT, - (int(np.ceil((limit - start) / delta)),), - ), - ], - ) - - model = onnx.helper.make_model(graph) - - f = BytesIO() - onnx.save_model(model, f) - - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = {"start": start, "limit": limit, "delta": delta} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - start_array = np.array([-5], np.float32) - limit_array = np.array([10], np.float32) - delta_array = np.array([0.5], np.float32) - - range_numpy = onnx_range(start_array, limit_array, delta_array) - - tensors_dict["start_array"] = ggml.utils.from_numpy(start_array, context) - tensors_dict["limit_array"] = ggml.utils.from_numpy(limit_array, context) - tensors_dict["delta_array"] = ggml.utils.from_numpy(delta_array, context) - - range_node = onnx.helper.make_node( - "Range", - inputs=["start_array", "limit_array", "delta_array"], - outputs=["range_output"], - ) - - output_tensor = ggml_operators["Range"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - range_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, range_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_cast_operator(): - # return - - def onnx_cast(input_data, to_dtype): - class CastModel(torch.nn.Module): - def forward(self, input): - return input.to(dtype=to_dtype) - - model = CastModel() - - x_tensor = torch.tensor(input_data, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (x_tensor,), - f, - input_names=["input"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = {"input": input_data} - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - input_data_array = np.array([1.2, 2.5, 3.7], np.float32) - - cast_numpy = onnx_cast(input_data_array, torch.int32) - - tensors_dict["input_data_array"] = ggml.utils.from_numpy(input_data_array, context) - - cast_node = onnx.helper.make_node( - "Cast", - inputs=["input_data_array"], - outputs=["cast_output"], - to=onnx.TensorProto.INT32, - ) - - output_tensor = ggml_operators["Cast"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - cast_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.allclose(result, cast_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_where_operator(): - # return - - def onnx_where(condition_data, x_data, y_data): - class WhereModel(torch.nn.Module): - def forward(self, condition, x, y): - return torch.where(condition, x, y) - - model = WhereModel() - - condition_tensor = torch.tensor(condition_data, dtype=torch.bool) - x_tensor = torch.tensor(x_data, dtype=torch.float32) - y_tensor = torch.tensor(y_data, dtype=torch.float32) - - f = BytesIO() - with contextlib.redirect_stdout(None): - torch.onnx.export( - model, - (condition_tensor, x_tensor, y_tensor), - f, - input_names=["condition", "x", "y"], - output_names=["output"], - verbose=False, - ) - onnx_model_bytes = BytesIO(f.getvalue()) - - onnx_model_bytes.seek(0) - sess = ort.InferenceSession(onnx_model_bytes.read()) - - input_feed = { - "condition": condition_data, - "x": x_data, - "y": y_data, - } - - output = sess.run(None, input_feed) - - return output[0] - - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - tensors_dict = {} - refs = [] - - condition_data_array = np.array([True, False, True], dtype=bool) - x_data_array = np.array([1.2, 2.5, 3.7], np.float32) - y_data_array = np.array([0.5, 1.0, 2.0], np.float32) - - where_numpy = onnx_where(condition_data_array, x_data_array, y_data_array) - - tensors_dict["condition_data_array"] = ggml.utils.from_numpy( - condition_data_array, context - ) - tensors_dict["x_data_array"] = ggml.utils.from_numpy(x_data_array, context) - tensors_dict["y_data_array"] = ggml.utils.from_numpy(y_data_array, context) - - where_node = onnx.helper.make_node( - "Where", - inputs=["condition_data_array", "x_data_array", "y_data_array"], - outputs=["where_output"], - ) - - output_tensor = ggml_operators["Where"]( - GgmlBackendRep( - graph=None, - weights=None, - weights_buffer=None, - inputs=None, - outputs=None, - ggml_context=None, - ggml_init_params=None, - ), - where_node, - tensors_dict, - context, - refs, - ) - gf = ggml.ggml_build_forward(output_tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - result = ggml.utils.to_numpy(output_tensor) - - assert np.array_equal(result, where_numpy) - - ggml.ggml_free(context) - - -def test_ggml_onnx_runtime_basic(): - # return - - input_name = "X" - - weight_name_a = "A" - weight_name_b = "B" - weight_name_c = "C" - weight_name_d = "D" - - intermediate_name1 = "intermediate1" - intermediate_name2 = "intermediate2" - intermediate_name3 = "intermediate3" - intermediate_name4 = "intermediate4" - intermediate_name5 = "intermediate5" - intermediate_name6 = "intermediate6" - - output_name = "Y" - - node1 = helper.make_node( - "Mul", [input_name, weight_name_a], [intermediate_name1], name="node1" - ) # X * A - node2 = helper.make_node( - "Div", [intermediate_name1, weight_name_b], [intermediate_name2], name="node2" - ) # (X * A) / B - node3 = helper.make_node( - "Add", [intermediate_name2, weight_name_c], [intermediate_name3], name="node3" - ) # (X * A / B) + C - node4 = helper.make_node( - "Sub", [intermediate_name3, weight_name_d], [intermediate_name4], name="node4" - ) # (X * A / B) + C - D - node5 = helper.make_node( - "Sqrt", [intermediate_name4], [intermediate_name5], name="node5" - ) # Sqrt((X * A / B) + C - D) - node6 = helper.make_node( - "Log", [intermediate_name5], [intermediate_name6], name="node6" - ) # Log(Sqrt((X * A / B) + C - D)) - node7 = helper.make_node( - "Abs", [intermediate_name6], [output_name], name="node7" - ) # Abs(Log(Sqrt((X * A / B) + C - D))) - - X_value_info = helper.make_tensor_value_info( - input_name, TensorProto.FLOAT, [None, 1] - ) - - output_value_info = helper.make_tensor_value_info( - output_name, TensorProto.FLOAT, [None, 1] - ) - - weights_a = np.array([50.6], dtype=float).astype(np.float32) - weights_b = np.array([0.0013], dtype=float).astype(np.float32) - weights_c = np.array([8.1], dtype=float).astype(np.float32) - weights_d = np.array([13.22], dtype=float).astype(np.float32) - - A_init = helper.make_tensor( - weight_name_a, - TensorProto.FLOAT, - [ - 1, - ], - weights_a, - ) - B_init = helper.make_tensor( - weight_name_b, - TensorProto.FLOAT, - [ - 1, - ], - weights_b, - ) - C_init = helper.make_tensor( - weight_name_c, - TensorProto.FLOAT, - [ - 1, - ], - weights_c, - ) - D_init = helper.make_tensor( - weight_name_d, - TensorProto.FLOAT, - [ - 1, - ], - weights_d, - ) - - graph_def = helper.make_graph( - [node1, node2, node3, node4, node5, node6, node7], - "complex_expression_model_with_log", - [X_value_info], - [output_value_info], - [A_init, B_init, C_init, D_init], - ) - - model_def = helper.make_model(graph_def, producer_name="onnx-complex-expression") - - input_data = {"X": np.array([[6.0]], dtype=np.float32)} - - f = io.BytesIO() - onnx.save(model_def, f) - - runtime_result = InferenceSession(f.getvalue()).run(None, input_data) - - ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) - ggml_result = ggml_dummy_model.run(input_data) - - assert np.allclose(ggml_result, runtime_result) From 258c0d3abd40a2c159bbd6a0df030420fdefb311 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 28 Aug 2023 15:39:16 -0400 Subject: [PATCH 116/232] Add Floor, Flatten, ArgMax, ArgMin and Ceil --- ggml/contrib/onnx.py | 709 +++++++++++++++++++++++++++++++++++++-- ggml/contrib/progress.md | 20 +- tests/test_ggml_onnx.py | 6 +- 3 files changed, 697 insertions(+), 38 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 32524871..e1700166 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -270,6 +270,206 @@ def ggml_operator_and( return new_tensor +class ArgOpsUserData(ctypes.Structure): + _fields_ = [ + ("axis", ctypes.c_int), + ("keepdims", ctypes.c_int), + ("select_last_index", ctypes.c_int), + ] + + +@ggml.ggml_custom2_op_t +def custom_arg_max( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_2) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ArgOpsUserData)) + userdata_data = userdata_data_ptr.contents + + axis = userdata_data.axis + keepdims = userdata_data.keepdims + select_last_index = userdata_data.select_last_index + + if select_last_index: + x = np.flip(x, axis) + + y = np.argmax(x, axis=axis) + + if select_last_index: + y = x.shape[axis] - y - 1 + + if keepdims: + y = np.expand_dims(y, axis) + + y = y.astype(np.int32) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("ArgMax") +def ggml_operator_arg_max( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ArgMax" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' + ) + + data = node_inputs[0] + name = node.output[0] + + axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 0) + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) + select_last_index = next( + (attr.i for attr in node.attribute if attr.name == "select_last_index"), 0 + ) + + x_shape = get_tensor_shape(data) + x_dtype = get_tensor_dtype(data) + x_ndims = ggml.utils.get_ndims(data) + + dummpy_data = np.empty(x_shape, dtype=np.int32) + + if select_last_index: + dummpy_data = np.flip(dummpy_data, axis) + + dummy_result = np.argmax(dummpy_data, axis=axis) + + if select_last_index: + dummy_result = dummpy_data.shape[axis] - dummy_result - 1 + + if keepdims: + dummy_result = np.expand_dims(dummy_result, axis) + + dummy_result = dummy_result.astype(np.int32) + + x_t = ggml.utils.from_numpy(dummy_result, context) + + argmax_userdata = ArgOpsUserData(axis, keepdims, select_last_index) + userdata_p = ctypes.cast(ctypes.pointer(argmax_userdata), ctypes.c_void_p) + + new_tensor = tensors_dict[name] = ggml.ggml_map_custom2_inplace( + context, + x_t, + data, + custom_arg_max, + 1, + userdata_p, + ) + + ggml.ggml_set_name(new_tensor, (name + "").encode()) + refs.append(argmax_userdata) + + return new_tensor + + +@ggml.ggml_custom2_op_t +def custom_arg_min( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_2) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ArgOpsUserData)) + userdata_data = userdata_data_ptr.contents + + axis = userdata_data.axis + keepdims = userdata_data.keepdims + select_last_index = userdata_data.select_last_index + + if select_last_index: + x = np.flip(x, axis) + + y = np.argmin(x, axis=axis) + + if select_last_index: + y = x.shape[axis] - y - 1 + + if keepdims: + y = np.expand_dims(y, axis) + + y = y.astype(np.int32) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("ArgMin") +def ggml_operator_arg_max( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ArgMin" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' + ) + + data = node_inputs[0] + name = node.output[0] + + axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 0) + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) + select_last_index = next( + (attr.i for attr in node.attribute if attr.name == "select_last_index"), 0 + ) + + x_shape = get_tensor_shape(data) + x_dtype = get_tensor_dtype(data) + x_ndims = ggml.utils.get_ndims(data) + + dummpy_data = np.empty(x_shape, dtype=np.int32) + + if select_last_index: + dummpy_data = np.flip(dummpy_data, axis) + + dummy_result = np.argmin(dummpy_data, axis=axis) + + if select_last_index: + dummy_result = dummpy_data.shape[axis] - dummy_result - 1 + + if keepdims: + dummy_result = np.expand_dims(dummy_result, axis) + + dummy_result = dummy_result.astype(np.int32) + + x_t = ggml.utils.from_numpy(dummy_result, context) + + argmax_userdata = ArgOpsUserData(axis, keepdims, select_last_index) + userdata_p = ctypes.cast(ctypes.pointer(argmax_userdata), ctypes.c_void_p) + + new_tensor = tensors_dict[name] = ggml.ggml_map_custom2_inplace( + context, + x_t, + data, + custom_arg_min, + 1, + userdata_p, + ) + + ggml.ggml_set_name(new_tensor, (name + "").encode()) + refs.append(argmax_userdata) + + return new_tensor + + @ggml.ggml_custom2_op_t def custom_cast( tensor_out: ggml.ggml_tensor_p, @@ -366,6 +566,51 @@ def ggml_operator_castlike( return new_tensor +@ggml_operator("Ceil") +def ggml_operator_exp( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Ceil" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + a = node_inputs[0] + np_dtype = get_tensor_dtype(a) + + x = np.empty(get_tensor_shape(a), dtype=np_dtype) + x_t = ggml.utils.from_numpy(x, context) + + @ggml.ggml_custom1_op_t + def custom_ceil( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + tensor = ggml.utils.to_numpy(tensor_in_1) + x = np.ceil(tensor) + set_tensor_out(tensor_out, np.array(x)) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x_t, + custom_ceil, + 1, + None, + ) + + refs.append(custom_ceil) + + return new_tensor + + @ggml_operator("Concat") def ggml_operator_concat( backend: "GgmlBackendRep", @@ -746,6 +991,115 @@ def custom_exp( return new_tensor +@ggml.ggml_custom2_op_t +def custom_flatten( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_2) + axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + + if axis < 0: + axis += len(x.shape) + new_shape = (np.prod(x.shape[:axis]).astype(np.int32), -1) + + y = x.reshape(new_shape) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("Flatten") +def ggml_operator_flatten( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Flatten" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + x_shape = get_tensor_shape(x) + x_dtype = get_tensor_dtype(x) + + axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 1) + + if axis < 0: + axis += len(x_shape) + + new_shape = (np.prod(x_shape[:axis]).astype(np.int32), -1) + + x_out = np.empty(x_shape, dtype=x_dtype) + x_out = x_out.reshape(new_shape) + x_t = ggml.utils.from_numpy(x_out, context) + + axis_c = ctypes.c_int(axis) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + x, + custom_flatten, + 1, + ctypes.pointer(axis_c), + ) + + refs.append(axis_c) + + return new_tensor + + +@ggml.ggml_custom1_op_t +def custom_floor( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_1) + y = np.floor(x) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("Floor") +def ggml_operator_floor( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Floor" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x, + custom_floor, + 1, + None, + ) + + return new_tensor + + @ggml.ggml_custom3_op_t def custom_gather( tensor_out: ggml.ggml_tensor_p, @@ -924,7 +1278,7 @@ def ggml_operator_size( userdata_p, ) - refs.append(userdata_p) + refs.append(hsig_userdata) return new_tensor @@ -1688,7 +2042,196 @@ def __init__(self, axes, keepdims): @ggml.ggml_custom2_op_t -def custom_reduce_max( +def custom_reduce_log_sum( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rlogsum_result = np.log(np.sum(tensor, axis=axes, keepdims=keepdims)) + + set_tensor_out(tensor_out, rlogsum_result) + + +@ggml_operator("ReduceLogSum") +def ggml_operator_reduce_log_sum( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) > 2 or len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceLogSum" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + input_tensor = node_inputs[0] + + noop_with_empty_axes = next( + (attr.i for attr in node.attribute if attr.name == "noop_with_empty_axes"), None + ) + + if noop_with_empty_axes == 1: + tensors_dict[node.output[0]] = input_tensor + return input_tensor + + tensor_shape = get_tensor_shape(input_tensor) + tensor_dtype = get_tensor_dtype(input_tensor) + + axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) + if not axes: + if len(node_inputs) > 1: + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) + else: + axes = [] + + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) + + rmean_userdata = ReduceOpsUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) + + output_shape = tuple([1] * len(tensor_shape)) if keepdims else () + + if len(axes): + output_shape = list(tensor_shape) + sorted_axes = sorted(axes, reverse=True) + + for axis in sorted_axes: + if keepdims: + output_shape[axis] = 1 + else: + output_shape.pop(axis) + + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + input_tensor, + custom_reduce_log_sum, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor + + +@ggml.ggml_custom2_op_t +def custom_reduce_log_sum_exp( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rlogsum_result = np.log(np.sum(np.exp(tensor), axis=axes, keepdims=keepdims)) + + set_tensor_out(tensor_out, rlogsum_result) + + +@ggml_operator("ReduceLogSumExp") +def ggml_operator_reduce_log_sum_exp( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + raise NotImplementedError( + f'Error for node "{node.name}": Operation "ReduceLogSumExp" is not implemented.' + ) + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) > 2 or len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceLogSumExp" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + input_tensor = node_inputs[0] + + noop_with_empty_axes = next( + (attr.i for attr in node.attribute if attr.name == "noop_with_empty_axes"), None + ) + + if noop_with_empty_axes == 1: + tensors_dict[node.output[0]] = input_tensor + return input_tensor + + tensor_shape = get_tensor_shape(input_tensor) + tensor_dtype = get_tensor_dtype(input_tensor) + + axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) + if not axes: + if len(node_inputs) > 1: + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) + else: + axes = [] + + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) + + rmean_userdata = ReduceOpsUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) + + output_shape = tuple([1] * len(tensor_shape)) if keepdims else () + + if len(axes): + output_shape = list(tensor_shape) + sorted_axes = sorted(axes, reverse=True) + + for axis in sorted_axes: + if keepdims: + output_shape[axis] = 1 + else: + output_shape.pop(axis) + + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + input_tensor, + custom_reduce_log_sum_exp, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor + + +@ggml.ggml_custom2_op_t +def custom_reduce_max( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, tensor_in_2: ggml.ggml_tensor_p, @@ -1726,18 +2269,26 @@ def ggml_operator_reduce_max( input_tensor = node_inputs[0] + noop_with_empty_axes = next( + (attr.i for attr in node.attribute if attr.name == "noop_with_empty_axes"), None + ) + + if noop_with_empty_axes == 1: + tensors_dict[node.output[0]] = input_tensor + return input_tensor + tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: - if len(node_inputs) != 2: - axes = [] - else: + if len(node_inputs) > 1: axes_eval = backend.eval_tensor(node_inputs[1], context) axes = ggml.utils.to_numpy(axes_eval) + else: + axes = [] - keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) rmean_userdata = ReduceOpsUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) @@ -1811,18 +2362,26 @@ def ggml_operator_reduce_mean( input_tensor = node_inputs[0] + noop_with_empty_axes = next( + (attr.i for attr in node.attribute if attr.name == "noop_with_empty_axes"), None + ) + + if noop_with_empty_axes == 1: + tensors_dict[node.output[0]] = input_tensor + return input_tensor + tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: - if len(node_inputs) != 2: - axes = [] - else: + if len(node_inputs) > 1: axes_eval = backend.eval_tensor(node_inputs[1], context) axes = ggml.utils.to_numpy(axes_eval) + else: + axes = [] - keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) rmean_userdata = ReduceOpsUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) @@ -1896,18 +2455,26 @@ def ggml_operator_reduce_mean( input_tensor = node_inputs[0] + noop_with_empty_axes = next( + (attr.i for attr in node.attribute if attr.name == "noop_with_empty_axes"), None + ) + + if noop_with_empty_axes == 1: + tensors_dict[node.output[0]] = input_tensor + return input_tensor + tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: - if len(node_inputs) != 2: - axes = [] - else: + if len(node_inputs) > 1: axes_eval = backend.eval_tensor(node_inputs[1], context) axes = ggml.utils.to_numpy(axes_eval) + else: + axes = [] - keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) rmean_userdata = ReduceOpsUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) @@ -1981,18 +2548,26 @@ def ggml_operator_reduce_prod( input_tensor = node_inputs[0] + noop_with_empty_axes = next( + (attr.i for attr in node.attribute if attr.name == "noop_with_empty_axes"), None + ) + + if noop_with_empty_axes == 1: + tensors_dict[node.output[0]] = input_tensor + return input_tensor + tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: - if len(node_inputs) != 2: - axes = [] - else: + if len(node_inputs) > 1: axes_eval = backend.eval_tensor(node_inputs[1], context) axes = ggml.utils.to_numpy(axes_eval) + else: + axes = [] - keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) rmean_userdata = ReduceOpsUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) @@ -2078,13 +2653,13 @@ def ggml_operator_reduce_sum( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: - if len(node_inputs) != 2: - axes = [] - else: + if len(node_inputs) > 1: axes_eval = backend.eval_tensor(node_inputs[1], context) axes = ggml.utils.to_numpy(axes_eval) + else: + axes = [] - keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) rmean_userdata = ReduceOpsUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) @@ -2158,18 +2733,26 @@ def ggml_operator_reduce_sum_square( input_tensor = node_inputs[0] + noop_with_empty_axes = next( + (attr.i for attr in node.attribute if attr.name == "noop_with_empty_axes"), None + ) + + if noop_with_empty_axes == 1: + tensors_dict[node.output[0]] = input_tensor + return input_tensor + tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: - if len(node_inputs) != 2: - axes = [] - else: + if len(node_inputs) > 1: axes_eval = backend.eval_tensor(node_inputs[1], context) axes = ggml.utils.to_numpy(axes_eval) + else: + axes = [] - keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 0) + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) rmean_userdata = ReduceOpsUserData(list(axes), keepdims) userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) @@ -2294,6 +2877,78 @@ def custom_reshape( return new_tensor +class SeluUserData(ctypes.Structure): + _fields_ = [ + ("alpha", ctypes.c_double), + ("gamma", ctypes.c_double), + ] + + +@ggml.ggml_custom1_op_t +def custom_selu( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(SeluUserData)) + userdata_data = userdata_data_ptr.contents + x = ggml.utils.to_numpy(tensor_in_1) + + alpha = userdata_data.alpha + gamma = userdata_data.gamma + + y = ( + np.clip(x, 0, np.inf) * gamma + + (np.exp(np.clip(x, -np.inf, 0)) - 1) * alpha * gamma + ) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("Selu") +def ggml_operator_selu( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Selu" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + + alpha = next( + (attr.f for attr in node.attribute if attr.name == "alpha"), + 1.67326319217681884765625, + ) + gamma = next( + (attr.f for attr in node.attribute if attr.name == "gamma"), + 1.05070102214813232421875, + ) + + selu_userdata = SeluUserData(alpha, gamma) + userdata_p = ctypes.cast(ctypes.pointer(selu_userdata), ctypes.c_void_p) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x, + custom_selu, + 1, + userdata_p, + ) + + refs.append(selu_userdata) + + return new_tensor + + @ggml_operator("Shape") def ggml_operator_shape( backend: "GgmlBackendRep", @@ -2340,7 +2995,7 @@ def custom_sigmoid( @ggml_operator("Sigmoid") -def ggml_operator_size( +def ggml_operator_sigmoid( backend: "GgmlBackendRep", node: NodeProto, tensors_dict: Dict[str, ggml.ggml_tensor_p], diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index 080a7c20..c66d6392 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -6,12 +6,12 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Abs](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Abs) | :white_check_mark: | `ggml_abs` | | [Add](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Add) | :white_check_mark: | `ggml_add` | | [And](https://github.com/onnx/onnx/blob/main/docs/Operators.md#And) | :white_check_mark: | | -| [ArgMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMax) | | | -| [ArgMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMin) | | | +| [ArgMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMax) | :white_check_mark: | | +| [ArgMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMin) | :white_check_mark: | | | [AveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#AveragePool) | | | | [BatchNormalizatio](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BatchNormalizatio) | | | | [Cast](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Cast) | :white_check_mark: | | -| [Ceil](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Ceil) | | | +| [Ceil](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Ceil) | :white_check_mark: | | | [Clip](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Clip) | | | | [Concat](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Concat) | :white_check_mark: | `ggml_concat` | | [Constant](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Constant) | :white_check_mark: | | @@ -23,9 +23,9 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Elu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Elu) | :white_check_mark: | `ggml_elu` | | [Equal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Equal) | :white_check_mark: | | | [Exp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Exp) | :white_check_mark: | | -| [Flatten](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Flatten) | | | -| [Floor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Floor) | | | -| [GRU](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GRU) | | | +| [Flatten](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Flatten) | :white_check_mark: | | +| [Floor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Floor) | :white_check_mark: | | +| [GRU](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GRU) | :white_check_mark: | | | [Gather](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gather) | :white_check_mark: | | | [Gemm](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gemm) | | | | [GlobalAveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalAveragePool) | | | @@ -48,7 +48,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [LpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpPool) | | | | [MatMul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MatMul) | :white_check_mark: | `ggml_mul_mat` | | [Max](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Max) | :white_check_mark: | `ggml_max` | -| [MaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxPool) | | | +| [MaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxPool) | |`ggml.ggml_pool_2d`| | [MaxRoiPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxRoiPool) | | | | [Mean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mean) | :white_check_mark: |~~`ggml_mean`~~
`ggml_add` + `ggml_div`| | [Min](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Min) | :white_check_mark: | | @@ -67,8 +67,8 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Reciprocal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reciprocal) | | | | [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | | | | [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | | | -| [ReduceLogSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSum) | | | -| [ReduceLogSumExp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSumExp) | | | +| [ReduceLogSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSum) | :white_check_mark: | | +| [ReduceLogSumExp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSumExp) | ⚙️ | | | [ReduceMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMax) | :white_check_mark: | | | [ReduceMean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMean) | :white_check_mark: | | | [ReduceMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMin) | :white_check_mark: | | @@ -77,7 +77,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [ReduceSumSquare](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSumSquare) | :white_check_mark: | | | [Relu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Relu) | :white_check_mark: | `ggml_relu` | | [Reshape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reshape) | :white_check_mark: | `ggml_reshape` | -| [Selu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Selu) | | | +| [Selu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Selu) | :white_check_mark: | | | [Shape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Shape) | :white_check_mark: | | | [Sigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sigmoid) | :white_check_mark: | | | [Size](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Size) | :white_check_mark: | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 2c4165aa..3fef3c2f 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -202,8 +202,12 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_hardsigmoid_") backend_test.exclude(".*hardsigmoid.*.*ver18.*") - backend_test.include("test_hardmax_") +backend_test.include("test_floor_") +backend_test.include("test_flatten_") +backend_test.include("test_argmax_") +backend_test.include("test_argmin_") +backend_test.include("test_ceil_") backend_test.exclude(".*FLOAT*E*M*.*") From b84c9d72f4c304890ffc074a242a65cb7c4efedb Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 28 Aug 2023 16:19:59 -0400 Subject: [PATCH 117/232] Typing and docstring improvements --- ggml/contrib/onnx.py | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index f116fd2a..669c86c7 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -2167,23 +2167,20 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: class GgmlRuntimeBackend(Backend): @classmethod - def is_opset_supported(cls, model): # pylint: disable=unused-argument + def is_opset_supported(cls, model: ModelProto): return True, "" @classmethod - def prepare(cls, model: ModelProto, device="CPU", **kwargs): - """ - Load the model and creates a :class:`onnxruntime.InferenceSession` - ready to be used as a backend. - - :param model: ModelProto (returned by `onnx.load`), - string for a filename or bytes for a serialized model - :param device: requested device for the computation, - None means the default one which depends on - the compilation settings - :param kwargs: see :class:`onnxruntime.SessionOptions` - :return: :class:`onnxruntime.InferenceSession` - """ + def prepare(cls, model: ModelProto, device: str="CPU", **kwargs): + """Load the model and creates the ggml runtime backend representation + for the onnx graph. + + Parameters: + model: ModelProto (returned by `onnx.load`), + device: requested device for the computation + + Returns: + GGML Backend Representation""" super(GgmlRuntimeBackend, cls).prepare(model, device, **kwargs) graph = model.graph @@ -2263,26 +2260,16 @@ def prepare(cls, model: ModelProto, device="CPU", **kwargs): @classmethod def run_model( - cls, model: ModelProto, inputs: Any, device=None, **kwargs + cls, model: ModelProto, inputs: Any, device: Optional[str]=None, **kwargs ) -> Tuple[Any, ...]: - """ - Compute the prediction. - - :param model: :class:`onnxruntime.InferenceSession` returned - by function *prepare* - :param inputs: inputs - :param device: requested device for the computation, - None means the default one which depends on - the compilation settings - :param kwargs: see :class:`onnxruntime.RunOptions` - :return: predictions + """Compute the prediction. """ rep = cls.prepare(model, device, **kwargs) return rep.run(inputs, **kwargs) @classmethod def run_node( - cls, node: NodeProto, inputs: Any, device=None, outputs_info=None, **kwargs + cls, node: NodeProto, inputs: Any, device: Optional[str]=None, outputs_info=None, **kwargs ) -> Tuple[Any, ...]: """ This method is not implemented as it is much more efficient From 6170f85722f1ebc95a9500f1f35507e0db350867 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Mon, 28 Aug 2023 16:29:01 -0400 Subject: [PATCH 118/232] Add PRelu operator LeakyRelu also added but do not pass because of differences between 32 and 64 floating points --- ggml/contrib/onnx.py | 93 ++++++++++++++++++++++++++++++++++++++++ ggml/contrib/progress.md | 12 +++--- tests/test_ggml_onnx.py | 13 ++++++ 3 files changed, 112 insertions(+), 6 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index e1700166..daba0d57 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1333,6 +1333,54 @@ def ggml_operator_hardmax( return new_tensor +@ggml.ggml_custom1_op_t +def custom_leaky_relu( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + alpha = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_double)).contents.value + x = ggml.utils.to_numpy(tensor_in_1) + y = np.clip(x, 0, np.inf) + np.clip(x, -np.inf, 0) * alpha + + set_tensor_out(tensor_out, y) + + +@ggml_operator("LeakyRelu") +def ggml_operator_leaky_relu( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "LeakyRelu" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + alpha = next((attr.f for attr in node.attribute if attr.name == "alpha"), 0.01) + + axis_c = ctypes.c_double(alpha) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x, + custom_leaky_relu, + 1, + ctypes.pointer(axis_c), + ) + + refs.append(axis_c) + + return new_tensor + + @ggml.ggml_custom3_op_t def custom_greater_equal( tensor_out: ggml.ggml_tensor_p, @@ -1923,6 +1971,51 @@ def ggml_operator_or( return new_tensor +@ggml.ggml_custom2_op_t +def custom_leaky_prelu( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_1) + slope = ggml.utils.to_numpy(tensor_in_2) + + y = np.clip(x, 0, np.inf) + np.clip(x, -np.inf, 0) * slope + + set_tensor_out(tensor_out, y) + + +@ggml_operator("PRelu") +def ggml_operator_leaky_relu( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "PRelu" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + x, slope = node_inputs + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x, + slope, + custom_leaky_prelu, + 1, + None, + ) + + return new_tensor + + @ggml.ggml_custom2_op_t def custom_pow( tensor_out: ggml.ggml_tensor_p, diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index c66d6392..14c9cca3 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -25,7 +25,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Exp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Exp) | :white_check_mark: | | | [Flatten](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Flatten) | :white_check_mark: | | | [Floor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Floor) | :white_check_mark: | | -| [GRU](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GRU) | :white_check_mark: | | +| [GRU](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GRU) | | | | [Gather](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gather) | :white_check_mark: | | | [Gemm](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gemm) | | | | [GlobalAveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalAveragePool) | | | @@ -36,11 +36,11 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | :white_check_mark: | | | [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | | | | [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | | | -| [InstanceNormaliza](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormaliza) | | | +| [InstanceNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormalization)| | | | [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | | | | [LSTM](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LSTM) | | | -| [LeakyRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LeakyRelu) | | | -| [Less](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Less) | | | +| [LeakyRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LeakyRelu) | ⚙️ | | +| [Less](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Less) | :white_check_mark: | | | [Log](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Log) | :white_check_mark: | `ggml_log` | | [LogSoftmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LogSoftmax) | :white_check_mark: | | | [Loop](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Loop) | | | @@ -56,7 +56,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Neg](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Neg) | :white_check_mark: | `ggml_neg` | | [Not](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Not) | :white_check_mark: | | | [Or](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Or) | :white_check_mark: | | -| [PRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#PRelu) | | | +| [PRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#PRelu) | :white_check_mark: | | | [Pad](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad) | | | | [Pow](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pow) | :white_check_mark: | | | [RNN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RNN) | | | @@ -68,7 +68,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | | | | [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | | | | [ReduceLogSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSum) | :white_check_mark: | | -| [ReduceLogSumExp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSumExp) | ⚙️ | | +| [ReduceLogSumExp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSumExp) | ⚙️ | | | [ReduceMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMax) | :white_check_mark: | | | [ReduceMean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMean) | :white_check_mark: | | | [ReduceMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMin) | :white_check_mark: | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 3fef3c2f..1551a608 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -148,18 +148,31 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_reduce_min_") backend_test.include("test_reduce_prod_") backend_test.include("test_reduce_sum_") +backend_test.include("test_reduce_log_sum_") +backend_test.exclude("test_reduce_log_sum_exp") backend_test.include("test_relu_") +backend_test.include("test_relu_example") backend_test.include("test_ReLU_") backend_test.exclude(".*relu.*.*ver18.*") +# backend_test.include("test_leakyrelu") +# backend_test.exclude(".*leakyrelu.*.*ver18.*") + backend_test.include("test_elu_") backend_test.include("test_ELU_") +backend_test.include("test_elu_example") backend_test.exclude(".*elu.*.*ver18.*") backend_test.include("test_selu_") +backend_test.include("test_selu_example") backend_test.exclude(".*selu.*.*ver18.*") +backend_test.include("test_prelu") +backend_test.include("test_PRelu_") +backend_test.include("test_prelu_example") +backend_test.exclude(".*prelu.*.*ver18.*") + backend_test.include("test_reshape_") backend_test.exclude("test_reshape_allowzero") # not supported From fd3ea92879784a455cc25e702b6dbbabbea6250a Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 10:17:19 -0400 Subject: [PATCH 119/232] Add Softsign, Softplus and Squeeze operators --- ggml/contrib/onnx.py | 136 ++++++++++++++++++++++++++++++++++++++- ggml/contrib/progress.md | 10 +-- tests/test_ggml_onnx.py | 12 ++-- 3 files changed, 145 insertions(+), 13 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index daba0d57..3a0dde49 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3147,7 +3147,7 @@ def ggml_operator_size( tensor_size_np = np.prod(tensor_shape).astype(np.int32) tensor_size_np = np.array( [tensor_size_np] - ) # Add a rank so ggml doesnt break the value, inside the custom reshape to scalar as expected + ) # Add a rank so ggml doesnt break the value, inside the custom reshape to scalar as expected TODO: Fix the ranking, ggml skalars or make sure broadcasting works fine tensor_size_t = ggml.utils.from_numpy(np.array([tensor_size_np]), context) ggml_type = map_to_ggml_type(tensor_size_np.dtype).value @@ -3167,6 +3167,76 @@ def ggml_operator_size( return new_tensor +@ggml.ggml_custom1_op_t +def custom_softplus( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_1) + y = np.log(np.exp(x) + 1) + set_tensor_out(tensor_out, y) + + +@ggml_operator("Softplus") +def ggml_operator_softplus( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Softplus" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x, + custom_softplus, + 1, + None, + ) + + return new_tensor + + +@ggml_operator("Softsign") +def ggml_operator_softsign( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Softsign" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + x_shape = get_tensor_shape(x) + x_dtype = get_tensor_dtype(x) + + # y = x / (1 + abs(x)) + one_np = np.full(x_shape, 1, dtype=x_dtype) + one_t = ggml.utils.from_numpy(one_np, context) + x_abs = ggml.ggml_abs(context, x) + one_plus_abs = ggml.ggml_add(context, one_t, x_abs) + y = ggml.ggml_div(context, x, one_plus_abs) + + return y + + @ggml_operator("Softmax") def ggml_operator_softmax( backend: "GgmlBackendRep", @@ -3219,6 +3289,70 @@ def ggml_operator_sqrt( return sqrt_result +@ggml.ggml_custom3_op_t +def custom_squeeze( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_2) + axes = ggml.utils.to_numpy(tensor_in_3) + + y = np.squeeze(x, axis=axes[0]) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("Squeeze") +def ggml_operator_squeeze( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Squeeze" requires exactly two inputs, data and axes. Actual number of inputs: {len(node_inputs)}' + ) + + data, axes_input = node_inputs + + x_shape = get_tensor_shape(data) + x_dtype = get_tensor_dtype(data) + + axes_eval = backend.eval_tensor(axes_input, context) + axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) + + dummy_data = np.empty(x_shape, dtype=x_dtype) + dummy_data = np.squeeze(dummy_data, axis=axes[0]) + + if len(dummy_data.shape) > 4: + raise ValueError( + f'Error for node "{node.name}": {len(dummy_data.shape)}D arrays are not allowed.' + ) + + x_t = ggml.utils.from_numpy(dummy_data, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + context, + x_t, + data, + axes_input, + custom_squeeze, + 1, + None, + ) + + return new_tensor + + @ggml_operator("Sub") def ggml_operator_sub( backend: "GgmlBackendRep", diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index 14c9cca3..e3c5ffab 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -9,7 +9,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [ArgMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMax) | :white_check_mark: | | | [ArgMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMin) | :white_check_mark: | | | [AveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#AveragePool) | | | -| [BatchNormalizatio](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BatchNormalizatio) | | | +| [BatchNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BatchNormalization) | | | | [Cast](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Cast) | :white_check_mark: | | | [Ceil](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Ceil) | :white_check_mark: | | | [Clip](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Clip) | | | @@ -83,12 +83,12 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Size](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Size) | :white_check_mark: | | | [Slice](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Slice) | | | | [Softmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softmax) | :white_check_mark: | `ggml_soft_max` | -| [Softplus](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softplus) | | | -| [Softsign](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softsign) | | | +| [Softplus](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softplus) | :white_check_mark: | | +| [Softsign](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softsign) | :white_check_mark: | | | [SpaceToDepth](https://github.com/onnx/onnx/blob/main/docs/Operators.md#SpaceToDepth) | | | | [Split](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Split) | | | | [Sqrt](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sqrt) | :white_check_mark: | `ggml_sqrt` | -| [Squeeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Squeeze) | | | +| [Squeeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Squeeze) | :white_check_mark: | | | [Sub](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sub) | :white_check_mark: | `ggml_sub` | | [Sum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sum) | :white_check_mark: | `ggml_sum` | | [Tanh](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tanh) | :white_check_mark: | `ggml_tanh` | @@ -96,6 +96,6 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [TopK](https://github.com/onnx/onnx/blob/main/docs/Operators.md#TopK) | | | | [Transpose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Transpose) | :white_check_mark: | `ggml_transpose` | | [Unsqueeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Unsqueeze) | :white_check_mark: | | -| [Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample) | | | +| ~~[Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample)~~ (Deprecated) | :x: | | | [Xor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Xor) | :white_check_mark: | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 1551a608..8b8c34c6 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -154,24 +154,19 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_relu_") backend_test.include("test_relu_example") backend_test.include("test_ReLU_") -backend_test.exclude(".*relu.*.*ver18.*") # backend_test.include("test_leakyrelu") -# backend_test.exclude(".*leakyrelu.*.*ver18.*") backend_test.include("test_elu_") backend_test.include("test_ELU_") backend_test.include("test_elu_example") -backend_test.exclude(".*elu.*.*ver18.*") backend_test.include("test_selu_") backend_test.include("test_selu_example") -backend_test.exclude(".*selu.*.*ver18.*") backend_test.include("test_prelu") backend_test.include("test_PRelu_") backend_test.include("test_prelu_example") -backend_test.exclude(".*prelu.*.*ver18.*") backend_test.include("test_reshape_") backend_test.exclude("test_reshape_allowzero") # not supported @@ -209,11 +204,9 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_and_") backend_test.include("test_xor_") - backend_test.include("test_size_") backend_test.include("test_sigmoid_") backend_test.include("test_hardsigmoid_") -backend_test.exclude(".*hardsigmoid.*.*ver18.*") backend_test.include("test_hardmax_") backend_test.include("test_floor_") @@ -222,7 +215,12 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_argmin_") backend_test.include("test_ceil_") +backend_test.include("test_softsign_") +backend_test.include("test_softplus_") +backend_test.include("test_squeeze_") + backend_test.exclude(".*FLOAT*E*M*.*") +backend_test.exclude(".*ver18.*") # import all test cases at global scope to make them visible to python.unittest globals().update(backend_test.enable_report().test_cases) From a6b92b81050c77770428aaa85c92a08a1f0c0897 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 10:52:06 -0400 Subject: [PATCH 120/232] Add Sum, Tanh and Tile --- ggml/contrib/onnx.py | 122 ++++++++++++++++++++++++++++++++++++++- ggml/contrib/progress.md | 3 +- tests/test_ggml_onnx.py | 3 + 3 files changed, 126 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 3a0dde49..194bb92d 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -822,7 +822,6 @@ def ggml_operator_constant_of_shape( return new_tensor - @ggml_operator("Div") def ggml_operator_div( backend: "GgmlBackendRep", @@ -3381,6 +3380,127 @@ def ggml_operator_sub( return sub_result +@ggml_operator("Sum") +def ggml_operator_sum( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Sum" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + shape = get_tensor_shape(node_inputs[0]) + dtype = get_tensor_dtype(node_inputs[0]) + + empty_np = np.full(shape, 0, dtype=dtype) + next_item = ggml.utils.from_numpy(empty_np, context) + + for tensor in node_inputs: + tensor, next_item = broadcast_shapes(context, tensor, next_item) + next_item = ggml.ggml_add( + context, + tensor, + next_item, + ) + + tensors_dict[output_name] = next_item + + return next_item + + +@ggml_operator("Tanh") +def ggml_operator_tanh( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Tanh" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + tanh_result = ggml.ggml_tanh( + context, + x, + ) + + tensors_dict[node.output[0]] = tanh_result + + return tanh_result + + +@ggml.ggml_custom3_op_t +def custom_tile( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_2) + repeats = ggml.utils.to_numpy(tensor_in_3) + + y = np.tile(x, repeats) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("Tile") +def ggml_operator_tile( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Tile" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + x, repeats = node_inputs + + repeats_eval = backend.eval_tensor(repeats, context) + repeats_vals = ggml.utils.to_numpy(repeats_eval).astype(dtype=np.int32) + + output_shape = list(get_tensor_shape(x)) + for i in range(len(output_shape)): + output_shape[i] = output_shape[i] * repeats_vals[i] + + x_t = ggml.utils.from_numpy( + np.empty(output_shape, dtype=get_tensor_dtype(x)), + context, + ) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + context, + x_t, + x, + repeats, + custom_tile, + 1, + None, + ) + + return new_tensor + + @ggml_operator("Transpose") def ggml_operator_transpose( backend: "GgmlBackendRep", diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index e3c5ffab..90a55b35 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -15,6 +15,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Clip](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Clip) | | | | [Concat](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Concat) | :white_check_mark: | `ggml_concat` | | [Constant](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Constant) | :white_check_mark: | | +| [ConstantOfShape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConstantOfShape) | :white_check_mark: | | | [Conv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv) | | | | [ConvTranspose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConvTranspose) | | | | [DepthToSpace](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DepthToSpace) | | | @@ -92,7 +93,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Sub](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sub) | :white_check_mark: | `ggml_sub` | | [Sum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sum) | :white_check_mark: | `ggml_sum` | | [Tanh](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tanh) | :white_check_mark: | `ggml_tanh` | -| [Tile](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tile) | | | +| [Tile](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tile) | :white_check_mark: | | | [TopK](https://github.com/onnx/onnx/blob/main/docs/Operators.md#TopK) | | | | [Transpose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Transpose) | :white_check_mark: | `ggml_transpose` | | [Unsqueeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Unsqueeze) | :white_check_mark: | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 8b8c34c6..bcffc081 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -218,6 +218,9 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_softsign_") backend_test.include("test_softplus_") backend_test.include("test_squeeze_") +backend_test.include("test_sum_") +backend_test.include("test_tanh_") +backend_test.include("test_tile_") backend_test.exclude(".*FLOAT*E*M*.*") backend_test.exclude(".*ver18.*") From 00209c7873bd40c662b08f1505cd42cc2dacb2ea Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 29 Aug 2023 11:11:45 -0400 Subject: [PATCH 121/232] Update mkdocs config to allow emoji shortcuts --- mkdocs.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mkdocs.yml b/mkdocs.yml index 9117a37a..e1597bd5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -29,6 +29,12 @@ plugins: - social markdown_extensions: + - tables + - attr_list + - pymdownx.emoji: + emoji_index: !!python/name:materialx.emoji.twemoji + emoji_generator: !!python/name:materialx.emoji.to_svg + - pymdownx.tilde - pymdownx.superfences - pymdownx.inlinehilite - pymdownx.snippets From 41758583926410dca32999f07a14918b9f83b738 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 29 Aug 2023 11:11:59 -0400 Subject: [PATCH 122/232] Add onnx documentation --- docs/contrib/onnx.md | 143 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 docs/contrib/onnx.md diff --git a/docs/contrib/onnx.md b/docs/contrib/onnx.md new file mode 100644 index 00000000..c0cd4cbd --- /dev/null +++ b/docs/contrib/onnx.md @@ -0,0 +1,143 @@ +# GGML ONNX Runtime + +## Getting Started + +### Installation + +```bash +pip install ggml-python[onnx] +``` + +### Usage + +```python +import onnx +from ggml.contrib.onnx import GgmlRuntimeBackend + +# Load an ONNX model +model = onnx.load("model.onnx") + +# Create a runtime session +ggml_backend_rep = GgmlRuntimeBackend.prepare(model) + +# Run inference +input = np.random.randn(1, 3, 224, 224).astype(np.float32) +output = ggml_backend_rep.run([input]) +``` + +## Technical Overview + +The GGML ONNX runtime is a backend for the [ONNX](https://onnx.ai/) model format. It is designed to be used as a drop-in replacement for the ONNX Runtime which leverages ggml for efficient model inference on a wide range of devices. + +To use the runtime: + +- Models are first converted from PyTorch, TensorFlow, and other frameworks to ONNX +- ONNX models are then optimized for ggml inference. This includes: + - Weight Quantization + - Dynamic Subgraph Detection + - GPU Offloading +- The optimized ONNX models are then executed in the GGML ONNX runtime + + +## Operator Support + +This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/blob/main/onnx/defs/operator_sets.h) and may not include all ONNX operators. These are core operators available in all versions starting from ai.onnx version 1. + +| ONNX Operator | Status | Implementation Method | +|:--------------------------------------------------------------------------------------------------|:------------------:|:----------------| +| [Abs](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Abs) | :white_check_mark: | `ggml_abs` | +| [Add](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Add) | :white_check_mark: | `ggml_add` | +| [And](https://github.com/onnx/onnx/blob/main/docs/Operators.md#And) | :white_check_mark: | | +| [ArgMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMax) | :white_check_mark: | | +| [ArgMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMin) | :white_check_mark: | | +| [AveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#AveragePool) | | | +| [BatchNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BatchNormalization) | | | +| [Cast](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Cast) | :white_check_mark: | | +| [Ceil](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Ceil) | :white_check_mark: | | +| [Clip](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Clip) | | | +| [Concat](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Concat) | :white_check_mark: | `ggml_concat` | +| [Constant](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Constant) | :white_check_mark: | | +| [ConstantOfShape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConstantOfShape) | :white_check_mark: | | +| [Conv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv) | | | +| [ConvTranspose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConvTranspose) | | | +| [DepthToSpace](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DepthToSpace) | | | +| [Div](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Div) | :white_check_mark: | `ggml_div` | +| [Dropout](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Dropout) -> [code ref](https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/dropout.py) | | | +| [Elu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Elu) | :white_check_mark: | `ggml_elu` | +| [Equal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Equal) | :white_check_mark: | | +| [Exp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Exp) | :white_check_mark: | | +| [Flatten](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Flatten) | :white_check_mark: | | +| [Floor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Floor) | :white_check_mark: | | +| [GRU](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GRU) | | | +| [Gather](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gather) | :white_check_mark: | | +| [Gemm](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gemm) | | | +| [GlobalAveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalAveragePool) | | | +| [GlobalLpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalLpPool) | | | +| [GlobalMaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalMaxPool) | | | +| [Greater](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Greater) | :white_check_mark: | | +| [HardSigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSigmoid) | :white_check_mark: | | +| [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | :white_check_mark: | | +| [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | | | +| [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | | | +| [InstanceNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormalization)| | | +| [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | | | +| [LSTM](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LSTM) | | | +| [LeakyRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LeakyRelu) | ⚙️ | | +| [Less](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Less) | :white_check_mark: | | +| [Log](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Log) | :white_check_mark: | `ggml_log` | +| [LogSoftmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LogSoftmax) | :white_check_mark: | | +| [Loop](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Loop) | | | +| [LpNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpNormalization) | | | +| [LpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpPool) | | | +| [MatMul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MatMul) | :white_check_mark: | `ggml_mul_mat` | +| [Max](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Max) | :white_check_mark: | `ggml_max` | +| [MaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxPool) | |`ggml.ggml_pool_2d`| +| [MaxRoiPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxRoiPool) | | | +| [Mean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mean) | :white_check_mark: |~~`ggml_mean`~~
`ggml_add` + `ggml_div`| +| [Min](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Min) | :white_check_mark: | | +| [Mul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mul) | :white_check_mark: | `ggml_mul` | +| [Neg](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Neg) | :white_check_mark: | `ggml_neg` | +| [Not](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Not) | :white_check_mark: | | +| [Or](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Or) | :white_check_mark: | | +| [PRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#PRelu) | :white_check_mark: | | +| [Pad](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad) | | | +| [Pow](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pow) | :white_check_mark: | | +| [RNN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RNN) | | | +| [RandomNormal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormal) | | | +| [RandomNormalLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormalLike) | | | +| [RandomUniform](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniform) | | | +| [RandomUniformLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniformLike) | | | +| [Reciprocal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reciprocal) | | | +| [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | | | +| [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | | | +| [ReduceLogSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSum) | :white_check_mark: | | +| [ReduceLogSumExp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSumExp) | ⚙️ | | +| [ReduceMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMax) | :white_check_mark: | | +| [ReduceMean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMean) | :white_check_mark: | | +| [ReduceMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMin) | :white_check_mark: | | +| [ReduceProd](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceProd) | :white_check_mark: | | +| [ReduceSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSum) | :white_check_mark: | | +| [ReduceSumSquare](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSumSquare) | :white_check_mark: | | +| [Relu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Relu) | :white_check_mark: | `ggml_relu` | +| [Reshape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reshape) | :white_check_mark: | `ggml_reshape` | +| [Selu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Selu) | :white_check_mark: | | +| [Shape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Shape) | :white_check_mark: | | +| [Sigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sigmoid) | :white_check_mark: | | +| [Size](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Size) | :white_check_mark: | | +| [Slice](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Slice) | | | +| [Softmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softmax) | :white_check_mark: | `ggml_soft_max` | +| [Softplus](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softplus) | :white_check_mark: | | +| [Softsign](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softsign) | :white_check_mark: | | +| [SpaceToDepth](https://github.com/onnx/onnx/blob/main/docs/Operators.md#SpaceToDepth) | | | +| [Split](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Split) | | | +| [Sqrt](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sqrt) | :white_check_mark: | `ggml_sqrt` | +| [Squeeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Squeeze) | :white_check_mark: | | +| [Sub](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sub) | :white_check_mark: | `ggml_sub` | +| [Sum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sum) | :white_check_mark: | `ggml_sum` | +| [Tanh](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tanh) | :white_check_mark: | `ggml_tanh` | +| [Tile](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tile) | :white_check_mark: | | +| [TopK](https://github.com/onnx/onnx/blob/main/docs/Operators.md#TopK) | | | +| [Transpose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Transpose) | :white_check_mark: | `ggml_transpose` | +| [Unsqueeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Unsqueeze) | :white_check_mark: | | +| ~~[Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample)~~ (Deprecated) | :x: | | +| [Xor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Xor) | :white_check_mark: | | From 45931e8f30016660e6b7c7152a358768eedbbd93 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 11:41:25 -0400 Subject: [PATCH 123/232] Add Identity, LRN and Reciprocal --- ggml/contrib/onnx.py | 157 ++++++++++++++++++++++++++++++++++++++- ggml/contrib/progress.md | 10 +-- tests/test_ggml_onnx.py | 5 ++ 3 files changed, 165 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 194bb92d..3b7cd897 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3,14 +3,14 @@ This module implements a GGML backend for ONNX models and operators. """ import ctypes +import math import re from typing import Any, Dict, List, Optional, Tuple import numpy as np import onnx from onnx.backend.base import Backend, BackendRep - -from onnx.helper import tensor_dtype_to_np_dtype, np_dtype_to_tensor_dtype +from onnx.helper import np_dtype_to_tensor_dtype, tensor_dtype_to_np_dtype from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto import ggml @@ -822,6 +822,7 @@ def ggml_operator_constant_of_shape( return new_tensor + @ggml_operator("Div") def ggml_operator_div( backend: "GgmlBackendRep", @@ -1332,6 +1333,119 @@ def ggml_operator_hardmax( return new_tensor +@ggml_operator("Identity") +def ggml_operator_floor( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Identity" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + output_name = node.output[0] + y = ggml.ggml_dup(context, x) + ggml.ggml_set_name(y, output_name.encode()) + + tensors_dict[output_name] = y + + return y + + +class LRNUserData(ctypes.Structure): + _fields_ = [ + ("alpha", ctypes.c_double), + ("beta", ctypes.c_double), + ("bias", ctypes.c_double), + ("size", ctypes.c_int), + ] + + +@ggml.ggml_custom1_op_t +def custom_leaky_lrn( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(LRNUserData)) + userdata_data = userdata_data_ptr.contents + + alpha = userdata_data.alpha + beta = userdata_data.beta + bias = userdata_data.bias + size = userdata_data.size + + x = ggml.utils.to_numpy(tensor_in_1) + + square_sum = np.zeros(x.shape).astype(x.dtype) + for n, c, h, w in np.ndindex(x.shape): + square_sum[n, c, h, w] = sum( + x[ + n, + max(0, c - int(math.floor((size - 1) / 2))) : min( + 5, c + int(math.ceil((size - 1) / 2)) + 1 + ), + h, + w, + ] + ** 2 + ) + y = x / ((bias + (alpha / size) * square_sum) ** beta) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("LRN") +def ggml_operator_leaky_relu( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "LRN" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + alpha = next((attr.f for attr in node.attribute if attr.name == "alpha"), 0.0001) + beta = next((attr.f for attr in node.attribute if attr.name == "beta"), 0.75) + bias = next((attr.f for attr in node.attribute if attr.name == "bias"), 1.0) + size = next((attr.i for attr in node.attribute if attr.name == "size"), None) + + if size is None: + raise ValueError( + f'Error for node "{node.name}": Operation "LRN" requires "size" attibute.' + ) + + lrn_userdata = LRNUserData(alpha, beta, bias, size) + userdata_p = ctypes.cast(ctypes.pointer(lrn_userdata), ctypes.c_void_p) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x, + custom_leaky_lrn, + 1, + userdata_p, + ) + + refs.append(lrn_userdata) + + return new_tensor + + @ggml.ggml_custom1_op_t def custom_leaky_relu( tensor_out: ggml.ggml_tensor_p, @@ -2061,6 +2175,45 @@ def ggml_operator_pow( return new_tensor +@ggml.ggml_custom1_op_t +def custom_reciprocal( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_1) + y = np.reciprocal(x) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("Reciprocal") +def ggml_operator_reciprocal( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Reciprocal" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x, + custom_reciprocal, + 1, + None, + ) + + return new_tensor @ggml.ggml_custom2_op_t def custom_range( diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index 90a55b35..d661474a 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -20,7 +20,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [ConvTranspose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConvTranspose) | | | | [DepthToSpace](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DepthToSpace) | | | | [Div](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Div) | :white_check_mark: | `ggml_div` | -| [Dropout](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Dropout) | | | +| [Dropout](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Dropout) -> [code ref](https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/dropout.py) | | | | [Elu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Elu) | :white_check_mark: | `ggml_elu` | | [Equal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Equal) | :white_check_mark: | | | [Exp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Exp) | :white_check_mark: | | @@ -35,17 +35,17 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Greater](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Greater) | :white_check_mark: | | | [HardSigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSigmoid) | :white_check_mark: | | | [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | :white_check_mark: | | -| [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | | | +| [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | :white_check_mark: | | | [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | | | | [InstanceNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormalization)| | | -| [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | | | +| [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | :white_check_mark: | | | [LSTM](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LSTM) | | | | [LeakyRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LeakyRelu) | ⚙️ | | | [Less](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Less) | :white_check_mark: | | | [Log](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Log) | :white_check_mark: | `ggml_log` | | [LogSoftmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LogSoftmax) | :white_check_mark: | | | [Loop](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Loop) | | | -| [LpNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpNormalization) | | | +| [LpNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpNormalization) |:x: (Test case not provided)| | | [LpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpPool) | | | | [MatMul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MatMul) | :white_check_mark: | `ggml_mul_mat` | | [Max](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Max) | :white_check_mark: | `ggml_max` | @@ -65,7 +65,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [RandomNormalLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormalLike) | | | | [RandomUniform](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniform) | | | | [RandomUniformLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniformLike) | | | -| [Reciprocal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reciprocal) | | | +| [Reciprocal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reciprocal) | :white_check_mark: | | | [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | | | | [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | | | | [ReduceLogSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSum) | :white_check_mark: | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index bcffc081..7f02a834 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -221,6 +221,11 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_sum_") backend_test.include("test_tanh_") backend_test.include("test_tile_") +backend_test.include("test_identity_") +backend_test.exclude("test_identity_opt") # test case not correct: ONNX issue +backend_test.exclude("test_identity_sequence") # test case not correct: ONNX issue +backend_test.include("test_lrn") +backend_test.include("test_reciprocal") backend_test.exclude(".*FLOAT*E*M*.*") backend_test.exclude(".*ver18.*") From b830e810fcf723459800412962ba9b30fa1351c3 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 29 Aug 2023 11:45:15 -0400 Subject: [PATCH 124/232] Add tests for graph optimizer and quantization --- tests/test_ggml_onnx.py | 170 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 2 deletions(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 7dd5a86d..d9c33b37 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -86,9 +86,172 @@ def test_ggml_onnx_runtime_basic(): ggml_result = ggml_dummy_model.run(input_data) assert ggml_result == runtime_result +def test_ggml_onnx_graph_optimization(): + # Construct an onnx graph and optimize it + # The graph is of the form y = (A^T)^T * x + b + # the optimization should remove the transpose operations + + # The name of the input tensor + input_name = "x" + + # The name of the weights tensor + weight_name_a = "A" + weight_name_b = "b" + + # The name of the output + output_name = "y" + + # Create the nodes (operations) in our graph + node1 = helper.make_node( + "Transpose", [weight_name_a], ["A_transposed"], name="node1" + ) # A^T + node2 = helper.make_node( + "Transpose", ["A_transposed"], ["A_transposed_transposed"], name="node2" + ) # (A^T)^T + node3 = helper.make_node( + "MatMul", [input_name, "A_transposed_transposed"], ["x_times_A"], name="node3" + ) # x * (A^T)^T + node4 = helper.make_node( + "Add", ["x_times_A", weight_name_b], [output_name], name="node4" + ) # x * (A^T)^T + b + + # Define the tensors (values) in our graph + X_value_info = helper.make_tensor_value_info( + input_name, TensorProto.FLOAT, [None, 32] + ) + + output_value_info = helper.make_tensor_value_info( + output_name, TensorProto.FLOAT, [None, 32] + ) + + # Set A and b as parameters/weights + weights_a = np.random.randn(32, 32).astype(np.float32) + + weights_b = np.random.randn(32).astype(np.float32) + + A_init = helper.make_tensor( + weight_name_a, + TensorProto.FLOAT, + [ + 32, + 32, + ], + weights_a, + ) + B_init = helper.make_tensor( + weight_name_b, + TensorProto.FLOAT, + [ + 32, + ], + weights_b, + ) + + # Create the graph (model). + graph_def = helper.make_graph( + [node1, node2, node3, node4], + "simple_expression_model", + [X_value_info], + [output_value_info], + [A_init, B_init], + ) + + model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") + + input_data = {"x": np.random.randn(1, 32).astype(np.float32)} + + f = io.BytesIO() + onnx.save(model_def, f) + + runtime_result = InferenceSession(f.getvalue()).run(None, input_data) + + ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) + ggml_result = ggml_dummy_model.run(input_data) + assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) + + +def test_ggml_onnx_runtime_quantized(): + # Construct an onnx graph of the form y = Ax + b + # where A and b are weights, x is the input, and y is the output + # A is a 32x32 matrix of normally distributed random numbers + # b is a vector of 32 normally distributed random numbers + # x is a vector of 32 normally distributed random numbers + # y is the output + + # The name of the input tensor + input_name = "x" + + # The name of the weights tensor + weight_name_a = "A" + weight_name_b = "b" + + # The name of the output + output_name = "y" + + # Create the nodes (operations) in our graph + node1 = helper.make_node( + "MatMul", [input_name, weight_name_a], ["x_times_A"], name="node1" + ) # x * A + node2 = helper.make_node( + "Add", ["x_times_A", weight_name_b], [output_name], name="node2" + ) # x * A + b + + # Define the tensors (values) in our graph + X_value_info = helper.make_tensor_value_info( + input_name, TensorProto.FLOAT, [None, 32] + ) + + output_value_info = helper.make_tensor_value_info( + output_name, TensorProto.FLOAT, [None, 32] + ) + + # Set A and b as parameters/weights + weights_a = np.random.randn(32, 32).astype(np.float32) + + weights_b = np.random.randn(32).astype(np.float32) + + A_init = helper.make_tensor( + weight_name_a, + TensorProto.FLOAT, + [ + 32, + 32, + ], + weights_a, + ) + B_init = helper.make_tensor( + weight_name_b, + TensorProto.FLOAT, + [ + 32, + ], + weights_b, + ) + + # Create the graph (model). + graph_def = helper.make_graph( + [node1, node2], + "simple_expression_model", + [X_value_info], + [output_value_info], + [A_init, B_init], + ) + + model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") + + input_data = {"x": np.random.randn(1, 32).astype(np.float32)} + + f = io.BytesIO() + onnx.save(model_def, f) + + runtime_result = InferenceSession(f.getvalue()).run(None, input_data) + + ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) + ggml_result = ggml_dummy_model.run(input_data) + + assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) + -# This is a pytest magic variable to load extra plugins -pytest_plugins = ("onnx.backend.test.report",) backend_test = onnx.backend.test.BackendTest(GgmlRuntimeBackend, __name__) @@ -177,5 +340,8 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude(".*pad.*") backend_test.exclude(".*FLOAT*E*M*.*") +# This is a pytest magic variable to load extra plugins +pytest_plugins = ("onnx.backend.test.report",) + # import all test cases at global scope to make them visible to python.unittest globals().update(backend_test.enable_report().test_cases) From 9489686dc6c7f22e68b7fb0fc5a03375a80bd107 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 12:50:30 -0400 Subject: [PATCH 125/232] Add ReduceL1 and ReduceL2 + fix Cast operator --- ggml/contrib/onnx.py | 202 ++++++++++++++++++++++++++++++++++++++- ggml/contrib/progress.md | 4 +- tests/test_ggml_onnx.py | 3 + 3 files changed, 202 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 3b7cd897..ff12c784 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -540,8 +540,7 @@ def ggml_operator_castlike( raise ValueError( f'Error for node "{node.name}": Operation "CastLike" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - a = node_inputs[0] - b = node_inputs[1] + a, b = node_inputs np_data_dtype = get_tensor_dtype(b) np_data_type_limit = np.dtype(str(np_data_dtype).replace("64", "32")) @@ -549,7 +548,7 @@ def ggml_operator_castlike( onnx_type = np_dtype_to_tensor_dtype(np_data_dtype) onnx_type_c = ctypes.c_int(onnx_type) - x = np.empty(get_tensor_shape(b), dtype=np_data_type_limit) + x = np.empty(get_tensor_shape(a), dtype=np_data_type_limit) x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( @@ -1350,7 +1349,9 @@ def ggml_operator_floor( x = node_inputs[0] output_name = node.output[0] - y = ggml.ggml_dup(context, x) + y = ggml.ggml_dup( + context, x + ) # NOTE: This will freeze the tensor in time, may not be expected. ggml.ggml_set_name(y, output_name.encode()) tensors_dict[output_name] = y @@ -1411,7 +1412,6 @@ def ggml_operator_leaky_relu( context: ggml.ggml_context_p, refs: List[Any], ): - node_inputs = [tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: @@ -2175,6 +2175,7 @@ def ggml_operator_pow( return new_tensor + @ggml.ggml_custom1_op_t def custom_reciprocal( tensor_out: ggml.ggml_tensor_p, @@ -2215,6 +2216,7 @@ def ggml_operator_reciprocal( return new_tensor + @ggml.ggml_custom2_op_t def custom_range( tensor_out: ggml.ggml_tensor_p, @@ -2286,6 +2288,196 @@ def __init__(self, axes, keepdims): self.keepdims = keepdims +@ggml.ggml_custom2_op_t +def custom_reduce_l1( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + + shape = tensor.shape + data = np.reshape(np.arange(1, np.prod(shape) + 1, dtype=np.float32), shape) + rl1_result = np.sum(a=np.abs(tensor), axis=axes, keepdims=keepdims) + + set_tensor_out(tensor_out, rl1_result) + + +@ggml_operator("ReduceL1") +def ggml_operator_reduce_l1( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) > 2 or len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceL1" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + input_tensor = node_inputs[0] + + noop_with_empty_axes = next( + (attr.i for attr in node.attribute if attr.name == "noop_with_empty_axes"), None + ) + + if noop_with_empty_axes == 1: + tensors_dict[node.output[0]] = input_tensor + return input_tensor + + tensor_shape = get_tensor_shape(input_tensor) + tensor_dtype = get_tensor_dtype(input_tensor) + + axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) + if not axes: + if len(node_inputs) > 1: + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) + else: + axes = [] + + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) + + rmean_userdata = ReduceOpsUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) + + output_shape = tuple([1] * len(tensor_shape)) if keepdims else () + + if len(axes): + output_shape = list(tensor_shape) + sorted_axes = sorted(axes, reverse=True) + + for axis in sorted_axes: + if keepdims: + output_shape[axis] = 1 + else: + output_shape.pop(axis) + + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + input_tensor, + custom_reduce_l1, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor + + +@ggml.ggml_custom2_op_t +def custom_reduce_l2( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + + rl2_result = np.sqrt(np.sum(a=np.square(tensor), axis=axes, keepdims=keepdims)) + + set_tensor_out(tensor_out, rl2_result) + + +@ggml_operator("ReduceL2") +def ggml_operator_reduce_l2( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) > 2 or len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "ReduceL2" requires at least one input. Actual number of inputs: {len(node_inputs)}' + ) + + input_tensor = node_inputs[0] + + noop_with_empty_axes = next( + (attr.i for attr in node.attribute if attr.name == "noop_with_empty_axes"), None + ) + + if noop_with_empty_axes == 1: + tensors_dict[node.output[0]] = input_tensor + return input_tensor + + tensor_shape = get_tensor_shape(input_tensor) + tensor_dtype = get_tensor_dtype(input_tensor) + + axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) + if not axes: + if len(node_inputs) > 1: + axes_eval = backend.eval_tensor(node_inputs[1], context) + axes = ggml.utils.to_numpy(axes_eval) + else: + axes = [] + + keepdims = next((attr.i for attr in node.attribute if attr.name == "keepdims"), 1) + + rmean_userdata = ReduceOpsUserData(list(axes), keepdims) + userdata_p = ctypes.cast(ctypes.pointer(rmean_userdata), ctypes.c_void_p) + + output_shape = tuple([1] * len(tensor_shape)) if keepdims else () + + if len(axes): + output_shape = list(tensor_shape) + sorted_axes = sorted(axes, reverse=True) + + for axis in sorted_axes: + if keepdims: + output_shape[axis] = 1 + else: + output_shape.pop(axis) + + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) + x_t = ggml.utils.from_numpy(x, context) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + input_tensor, + custom_reduce_l2, + 1, + userdata_p, + ) + + refs.append(rmean_userdata) + + return new_tensor + + @ggml.ggml_custom2_op_t def custom_reduce_log_sum( tensor_out: ggml.ggml_tensor_p, diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index d661474a..f0478302 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -66,8 +66,8 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [RandomUniform](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniform) | | | | [RandomUniformLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniformLike) | | | | [Reciprocal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reciprocal) | :white_check_mark: | | -| [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | | | -| [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | | | +| [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | :white_check_mark: | | +| [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | :white_check_mark: | | | [ReduceLogSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSum) | :white_check_mark: | | | [ReduceLogSumExp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSumExp) | ⚙️ | | | [ReduceMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMax) | :white_check_mark: | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 7f02a834..11768ffe 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -151,6 +151,9 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_reduce_log_sum_") backend_test.exclude("test_reduce_log_sum_exp") +backend_test.include("test_reduce_l1_") +backend_test.include("test_reduce_l2_") + backend_test.include("test_relu_") backend_test.include("test_relu_example") backend_test.include("test_ReLU_") From 20f27a7b63ad43a6d1fcf7a361b33563e5899132 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 13:05:43 -0400 Subject: [PATCH 126/232] Sort tests + add Equal tests --- tests/test_ggml_onnx.py | 105 ++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 42 deletions(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 11768ffe..6bcea354 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -97,27 +97,61 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_add_") backend_test.exclude("test_add_uint8_") # not supported +backend_test.include("test_and_") + +backend_test.include("test_argmax_") +backend_test.include("test_argmin_") + backend_test.include("test_cast_") -backend_test.include("test_concat_") +backend_test.include("test_ceil_") +backend_test.include("test_concat_") backend_test.include("test_constant_") backend_test.exclude(".*constant.*.*pad.*") backend_test.include("test_div_") - backend_test.exclude("test_div_uint8_") # not supported +backend_test.include("test_elu_") +backend_test.include("test_ELU_") +backend_test.include("test_elu_example") + +backend_test.include("test_eq_") + +backend_test.include("test_equal_") +backend_test.exclude(".*equal.*.*string.*") + +backend_test.include("test_exp_") + +backend_test.include("test_flatten_") + +backend_test.include("test_floor_") + +backend_test.include("test_greater_") + backend_test.include("test_gather_") backend_test.exclude("test_gather_elements") # not supported backend_test.include("test_greater_") +backend_test.include("test_hardsigmoid_") + +backend_test.include("test_hardmax_") + +backend_test.include("test_identity_") +backend_test.exclude("test_identity_opt") # test case not correct: ONNX issue +backend_test.exclude("test_identity_sequence") # test case not correct: ONNX issue + +# backend_test.include("test_leakyrelu") + backend_test.include("test_less_") backend_test.include("test_log_") +backend_test.include("test_lrn") + backend_test.include("test_matmul_") backend_test.include("test_max_") @@ -126,6 +160,8 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_max_int64") # not supported backend_test.exclude("test_max_uint") # not supported +backend_test.include("test_mean_") + backend_test.include("test_min_") backend_test.exclude("test_min_float16") # not supported backend_test.exclude("test_min_float64") # not supported @@ -135,6 +171,16 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_mul_") backend_test.exclude("test_mul_uint8") # not supported +backend_test.include("test_neg_") + +backend_test.include("test_not_") + +backend_test.include("test_or_") + +backend_test.include("test_prelu") +backend_test.include("test_PRelu_") +backend_test.include("test_prelu_example") + backend_test.include("test_pow_") backend_test.exclude("test_pow_bcast") # not supported backend_test.exclude("test_pow_types_int64") # not supported @@ -143,6 +189,8 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_range_float") # segfault backend_test.exclude("test_range_int32") # segfault +backend_test.include("test_reciprocal") + backend_test.include("test_reduce_max_") backend_test.include("test_reduce_mean_") backend_test.include("test_reduce_min_") @@ -158,23 +206,17 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_relu_example") backend_test.include("test_ReLU_") -# backend_test.include("test_leakyrelu") - -backend_test.include("test_elu_") -backend_test.include("test_ELU_") -backend_test.include("test_elu_example") +backend_test.include("test_reshape_") +backend_test.exclude("test_reshape_allowzero") # not supported backend_test.include("test_selu_") backend_test.include("test_selu_example") -backend_test.include("test_prelu") -backend_test.include("test_PRelu_") -backend_test.include("test_prelu_example") +backend_test.include("test_shape_") -backend_test.include("test_reshape_") -backend_test.exclude("test_reshape_allowzero") # not supported +backend_test.include("test_sigmoid_") -backend_test.include("test_shape_") +backend_test.include("test_size_") backend_test.include("test_softmax_") backend_test.exclude("test_softmax_axis_0") # not supported @@ -182,12 +224,20 @@ def test_ggml_onnx_runtime_basic(): backend_test.exclude("test_softmax_large_number") # not supported backend_test.exclude("test_softmax_lastdim") # Out of tolerance +backend_test.include("test_softplus_") +backend_test.include("test_softsign_") + backend_test.include("test_sqrt_") backend_test.include("test_sub_") backend_test.exclude("test_sub_bcast_") # not supported backend_test.exclude("test_sub_uint8_") # not supported +backend_test.include("test_sum_") + +backend_test.include("test_tanh_") +backend_test.include("test_tile_") + backend_test.include("test_transpose_") backend_test.include("test_unsqueeze_") @@ -199,37 +249,8 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_where_") backend_test.exclude("test_where_long") # not supported -backend_test.include("test_mean_") -backend_test.include("test_neg_") - -backend_test.include("test_or_") -backend_test.include("test_not_") -backend_test.include("test_and_") backend_test.include("test_xor_") -backend_test.include("test_size_") -backend_test.include("test_sigmoid_") -backend_test.include("test_hardsigmoid_") - -backend_test.include("test_hardmax_") -backend_test.include("test_floor_") -backend_test.include("test_flatten_") -backend_test.include("test_argmax_") -backend_test.include("test_argmin_") -backend_test.include("test_ceil_") - -backend_test.include("test_softsign_") -backend_test.include("test_softplus_") -backend_test.include("test_squeeze_") -backend_test.include("test_sum_") -backend_test.include("test_tanh_") -backend_test.include("test_tile_") -backend_test.include("test_identity_") -backend_test.exclude("test_identity_opt") # test case not correct: ONNX issue -backend_test.exclude("test_identity_sequence") # test case not correct: ONNX issue -backend_test.include("test_lrn") -backend_test.include("test_reciprocal") - backend_test.exclude(".*FLOAT*E*M*.*") backend_test.exclude(".*ver18.*") From 53b64d19e52d7e027649b9ae453ca6fdd5d4fd68 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 14:17:43 -0400 Subject: [PATCH 127/232] Update progress table --- ggml/contrib/progress.md | 12 ++++++------ tests/test_ggml_onnx.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md index f0478302..f1aafe17 100644 --- a/ggml/contrib/progress.md +++ b/ggml/contrib/progress.md @@ -36,7 +36,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [HardSigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSigmoid) | :white_check_mark: | | | [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | :white_check_mark: | | | [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | :white_check_mark: | | -| [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | | | +| [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | :x: | | | [InstanceNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormalization)| | | | [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | :white_check_mark: | | | [LSTM](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LSTM) | | | @@ -44,7 +44,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Less](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Less) | :white_check_mark: | | | [Log](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Log) | :white_check_mark: | `ggml_log` | | [LogSoftmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LogSoftmax) | :white_check_mark: | | -| [Loop](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Loop) | | | +| [Loop](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Loop) | :x: | | | [LpNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpNormalization) |:x: (Test case not provided)| | | [LpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpPool) | | | | [MatMul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MatMul) | :white_check_mark: | `ggml_mul_mat` | @@ -61,10 +61,10 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Pad](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad) | | | | [Pow](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pow) | :white_check_mark: | | | [RNN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RNN) | | | -| [RandomNormal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormal) | | | -| [RandomNormalLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormalLike) | | | -| [RandomUniform](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniform) | | | -| [RandomUniformLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniformLike) | | | +| [RandomNormal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormal) |:x: (Test case not provided)| | +| [RandomNormalLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormalLike) |:x: (Test case not provided)| | +| [RandomUniform](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniform) |:x: (Test case not provided)| | +| [RandomUniformLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniformLike) |:x: (Test case not provided)| | | [Reciprocal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reciprocal) | :white_check_mark: | | | [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | :white_check_mark: | | | [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | :white_check_mark: | | diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 6bcea354..3173ede6 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -109,7 +109,7 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_concat_") backend_test.include("test_constant_") -backend_test.exclude(".*constant.*.*pad.*") +# backend_test.exclude(".*constant.*.*pad.*") backend_test.include("test_div_") backend_test.exclude("test_div_uint8_") # not supported From b8ec875bd00fb1a3edef070483e4cb29c94c1627 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 29 Aug 2023 14:28:27 -0400 Subject: [PATCH 128/232] Add support for multiple outputs --- ggml/contrib/onnx.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 669c86c7..d9eb292e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -2131,13 +2131,17 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: for key, value in inputs.items(): set_tensor_out(ggml_tensors[key], value) + gf = ggml.ggml_cgraph() + gf_p = ctypes.pointer(gf) + output_names = [output.name for output in model_graph.output] + # Build layers for node in model_graph.node: operator_func = ggml_operators.get(node.op_type) if operator_func is None: raise NotImplementedError(f'Operator "{node.op_type}" not implemented') - node_output = operator_func( + operator_func( self, node, ggml_tensors, @@ -2145,24 +2149,27 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: refs, ) - if node.output[-1] == self.graph.output[-1].name: - exit_node = node_output - - # Build graph - gf = ggml.ggml_build_forward(exit_node) + for output in node.output: + if output in output_names: + ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) # Compute graph - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - graph_output = ggml.utils.to_numpy( - exit_node - ) # TODO: Add checks to convert values back to bool or etc types - graph_output = graph_output.astype( - get_final_dtype(exit_node) - ) # TODO: add a second dict to keep track of types and use that instead + ggml.ggml_graph_compute_with_ctx(context, gf_p, 1) + + graph_outputs = [] + for output in self.outputs: + exit_node = ggml_tensors[output.name] + graph_output = ggml.utils.to_numpy( + exit_node + ) # TODO: Add checks to convert values back to bool or etc types + graph_output = graph_output.astype( + get_final_dtype(exit_node) + ) # TODO: add a second dict to keep track of types and use that instead + graph_outputs.append(graph_output) ggml.ggml_free(context) - return [graph_output] + return graph_outputs class GgmlRuntimeBackend(Backend): From 030132479be5bf713e6a137e727cca3651a057ad Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 29 Aug 2023 15:00:49 -0400 Subject: [PATCH 129/232] Use nbytes_pad --- ggml/contrib/onnx.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index d9eb292e..5f36ff41 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -2221,7 +2221,7 @@ def prepare(cls, model: ModelProto, device: str="CPU", **kwargs): tensor = ggml.utils.from_numpy(x=np_array, ctx=context) ggml.ggml_set_name(tensor=tensor, name=name.encode()) - total_nbytes += ggml.ggml_nbytes(tensor) + total_nbytes += ggml.ggml_nbytes_pad(tensor) weights[name] = tensor pairs.append((tensor, initializer)) @@ -2229,7 +2229,7 @@ def prepare(cls, model: ModelProto, device: str="CPU", **kwargs): offset = 0 for tensor, initializer in pairs: - nbytes = ggml.ggml_nbytes(tensor) + nbytes = ggml.ggml_nbytes_pad(tensor) tensor.contents.data = ctypes.cast( ctypes.addressof(buffer) + offset, ctypes.c_void_p ) @@ -2285,3 +2285,36 @@ def run_node( raise NotImplementedError( "It is much more efficient to run a whole model than every node independently." ) + +class GgmlOnnxGraphOptimizerRule: + """Base class for a graph optimization rule.""" + + def __init__(self, name: str): + self.name = name + + def apply(self, model: ModelProto) -> Optional[ModelProto]: + """Apply the optimization rule to the given ONNX model.""" + raise NotImplementedError() + +class GgmlOnnxGraphOptimizer: + """Optimize an ONNX graph for the GGML runtime.""" + def __init__(self, model: ModelProto, rules: List[GgmlOnnxGraphOptimizerRule]): + self.model = model + self.rules = rules + + def optimize(self) -> ModelProto: + """Apply the optimization rules to the ONNX model until there are no + more optimizations left to perform. + + NOTE: This is a naive implementation that applies the rules in order until + no more rules can be applied.""" + model = self.model + while True: + for rule in self.rules: + new_model = rule.apply(model) + if new_model is not None: + model = new_model + break + else: + break + return model \ No newline at end of file From b8253d977020c000315deb75ab5104d41f5f8fba Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 15:05:06 -0400 Subject: [PATCH 130/232] Update test_ggml_onnx.py --- tests/test_ggml_onnx.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 3173ede6..b33b8404 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -111,6 +111,8 @@ def test_ggml_onnx_runtime_basic(): backend_test.include("test_constant_") # backend_test.exclude(".*constant.*.*pad.*") +# backend_test.include("test_clip_") + backend_test.include("test_div_") backend_test.exclude("test_div_uint8_") # not supported From 10c40a58bfc052e37d1a5b31169b951c56cf38d1 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 15:06:35 -0400 Subject: [PATCH 131/232] Merge changes from onnx-backend --- ggml/contrib/onnx.py | 124 +++++++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 45 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index ff12c784..77abe0b8 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4125,7 +4125,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml_tensors = self.weights # Define context - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + params = ggml.ggml_init_params(mem_size=16000 * 1024 * 1024, mem_buffer=None) context = ggml.ggml_init(params=params) refs: List[Any] = [] @@ -4175,13 +4175,17 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: for key, value in inputs.items(): set_tensor_out(ggml_tensors[key], value) + gf = ggml.ggml_cgraph() + gf_p = ctypes.pointer(gf) + output_names = [output.name for output in model_graph.output] + # Build layers for node in model_graph.node: operator_func = ggml_operators.get(node.op_type) if operator_func is None: raise NotImplementedError(f'Operator "{node.op_type}" not implemented') - node_output = operator_func( + operator_func( self, node, ggml_tensors, @@ -4189,45 +4193,45 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: refs, ) - if node.output[-1] == self.graph.output[-1].name: - exit_node = node_output - - # Build graph - gf = ggml.ggml_build_forward(exit_node) + for output in node.output: + if output in output_names: + ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) # Compute graph - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) - graph_output = ggml.utils.to_numpy( - exit_node - ) # TODO: Add checks to convert values back to bool or etc types - graph_output = graph_output.astype( - get_final_dtype(exit_node) - ) # TODO: add a second dict to keep track of types and use that instead + ggml.ggml_graph_compute_with_ctx(context, gf_p, 1) + + graph_outputs = [] + for output in self.outputs: + exit_node = ggml_tensors[output.name] + graph_output = ggml.utils.to_numpy( + exit_node + ) # TODO: Add checks to convert values back to bool or etc types + graph_output = graph_output.astype( + get_final_dtype(exit_node) + ) # TODO: add a second dict to keep track of types and use that instead + graph_outputs.append(graph_output) ggml.ggml_free(context) - return [graph_output] + return graph_outputs class GgmlRuntimeBackend(Backend): @classmethod - def is_opset_supported(cls, model): # pylint: disable=unused-argument + def is_opset_supported(cls, model: ModelProto): return True, "" @classmethod - def prepare(cls, model: ModelProto, device="CPU", **kwargs): - """ - Load the model and creates a :class:`onnxruntime.InferenceSession` - ready to be used as a backend. - - :param model: ModelProto (returned by `onnx.load`), - string for a filename or bytes for a serialized model - :param device: requested device for the computation, - None means the default one which depends on - the compilation settings - :param kwargs: see :class:`onnxruntime.SessionOptions` - :return: :class:`onnxruntime.InferenceSession` - """ + def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): + """Load the model and creates the ggml runtime backend representation + for the onnx graph. + + Parameters: + model: ModelProto (returned by `onnx.load`), + device: requested device for the computation + + Returns: + GGML Backend Representation""" super(GgmlRuntimeBackend, cls).prepare(model, device, **kwargs) graph = model.graph @@ -4261,7 +4265,7 @@ def prepare(cls, model: ModelProto, device="CPU", **kwargs): tensor = ggml.utils.from_numpy(x=np_array, ctx=context) ggml.ggml_set_name(tensor=tensor, name=name.encode()) - total_nbytes += ggml.ggml_nbytes(tensor) + total_nbytes += ggml.ggml_nbytes_pad(tensor) weights[name] = tensor pairs.append((tensor, initializer)) @@ -4269,7 +4273,7 @@ def prepare(cls, model: ModelProto, device="CPU", **kwargs): offset = 0 for tensor, initializer in pairs: - nbytes = ggml.ggml_nbytes(tensor) + nbytes = ggml.ggml_nbytes_pad(tensor) tensor.contents.data = ctypes.cast( ctypes.addressof(buffer) + offset, ctypes.c_void_p ) @@ -4307,26 +4311,20 @@ def prepare(cls, model: ModelProto, device="CPU", **kwargs): @classmethod def run_model( - cls, model: ModelProto, inputs: Any, device=None, **kwargs + cls, model: ModelProto, inputs: Any, device: Optional[str] = None, **kwargs ) -> Tuple[Any, ...]: - """ - Compute the prediction. - - :param model: :class:`onnxruntime.InferenceSession` returned - by function *prepare* - :param inputs: inputs - :param device: requested device for the computation, - None means the default one which depends on - the compilation settings - :param kwargs: see :class:`onnxruntime.RunOptions` - :return: predictions - """ + """Compute the prediction.""" rep = cls.prepare(model, device, **kwargs) return rep.run(inputs, **kwargs) @classmethod def run_node( - cls, node: NodeProto, inputs: Any, device=None, outputs_info=None, **kwargs + cls, + node: NodeProto, + inputs: Any, + device: Optional[str] = None, + outputs_info=None, + **kwargs, ) -> Tuple[Any, ...]: """ This method is not implemented as it is much more efficient @@ -4335,3 +4333,39 @@ def run_node( raise NotImplementedError( "It is much more efficient to run a whole model than every node independently." ) + + +class GgmlOnnxGraphOptimizerRule: + """Base class for a graph optimization rule.""" + + def __init__(self, name: str): + self.name = name + + def apply(self, model: ModelProto) -> Optional[ModelProto]: + """Apply the optimization rule to the given ONNX model.""" + raise NotImplementedError() + + +class GgmlOnnxGraphOptimizer: + """Optimize an ONNX graph for the GGML runtime.""" + + def __init__(self, model: ModelProto, rules: List[GgmlOnnxGraphOptimizerRule]): + self.model = model + self.rules = rules + + def optimize(self) -> ModelProto: + """Apply the optimization rules to the ONNX model until there are no + more optimizations left to perform. + + NOTE: This is a naive implementation that applies the rules in order until + no more rules can be applied.""" + model = self.model + while True: + for rule in self.rules: + new_model = rule.apply(model) + if new_model is not None: + model = new_model + break + else: + break + return model From 5932e2a04adaa3c0bfb318c7d12390de1f79b574 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 15:29:13 -0400 Subject: [PATCH 132/232] Update onnx.py --- ggml/contrib/onnx.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index e35bb36d..bd3ebb25 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4125,7 +4125,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml_tensors = self.weights # Define context - params = ggml.ggml_init_params(mem_size=16000 * 1024 * 1024, mem_buffer=None) + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) context = ggml.ggml_init(params=params) refs: List[Any] = [] @@ -4222,7 +4222,7 @@ def is_opset_supported(cls, model: ModelProto): return True, "" @classmethod - def prepare(cls, model: ModelProto, device: str="CPU", **kwargs): + def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): """Load the model and creates the ggml runtime backend representation for the onnx graph. @@ -4311,16 +4311,20 @@ def prepare(cls, model: ModelProto, device: str="CPU", **kwargs): @classmethod def run_model( - cls, model: ModelProto, inputs: Any, device: Optional[str]=None, **kwargs + cls, model: ModelProto, inputs: Any, device: Optional[str] = None, **kwargs ) -> Tuple[Any, ...]: - """Compute the prediction. - """ + """Compute the prediction.""" rep = cls.prepare(model, device, **kwargs) return rep.run(inputs, **kwargs) @classmethod def run_node( - cls, node: NodeProto, inputs: Any, device: Optional[str]=None, outputs_info=None, **kwargs + cls, + node: NodeProto, + inputs: Any, + device: Optional[str] = None, + outputs_info=None, + **kwargs, ) -> Tuple[Any, ...]: """ This method is not implemented as it is much more efficient @@ -4330,6 +4334,7 @@ def run_node( "It is much more efficient to run a whole model than every node independently." ) + class GgmlOnnxGraphOptimizerRule: """Base class for a graph optimization rule.""" @@ -4340,8 +4345,10 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: """Apply the optimization rule to the given ONNX model.""" raise NotImplementedError() + class GgmlOnnxGraphOptimizer: """Optimize an ONNX graph for the GGML runtime.""" + def __init__(self, model: ModelProto, rules: List[GgmlOnnxGraphOptimizerRule]): self.model = model self.rules = rules @@ -4349,7 +4356,7 @@ def __init__(self, model: ModelProto, rules: List[GgmlOnnxGraphOptimizerRule]): def optimize(self) -> ModelProto: """Apply the optimization rules to the ONNX model until there are no more optimizations left to perform. - + NOTE: This is a naive implementation that applies the rules in order until no more rules can be applied.""" model = self.model From b5502354eb743b58cfb2057be9be2d047fb57198 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 15:31:52 -0400 Subject: [PATCH 133/232] Progress doc cleanup --- docs/contrib/onnx.md | 24 ++++----- ggml/contrib/progress.md | 102 --------------------------------------- 2 files changed, 12 insertions(+), 114 deletions(-) delete mode 100644 ggml/contrib/progress.md diff --git a/docs/contrib/onnx.md b/docs/contrib/onnx.md index c0cd4cbd..5f479c46 100644 --- a/docs/contrib/onnx.md +++ b/docs/contrib/onnx.md @@ -77,17 +77,17 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Greater](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Greater) | :white_check_mark: | | | [HardSigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSigmoid) | :white_check_mark: | | | [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | :white_check_mark: | | -| [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | | | -| [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | | | +| [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | :white_check_mark: | | +| [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | :x: | | | [InstanceNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormalization)| | | -| [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | | | +| [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | :white_check_mark: | | | [LSTM](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LSTM) | | | | [LeakyRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LeakyRelu) | ⚙️ | | | [Less](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Less) | :white_check_mark: | | | [Log](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Log) | :white_check_mark: | `ggml_log` | | [LogSoftmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LogSoftmax) | :white_check_mark: | | -| [Loop](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Loop) | | | -| [LpNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpNormalization) | | | +| [Loop](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Loop) | :x: | | +| [LpNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpNormalization) |:x: (Test case not provided)| | | [LpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpPool) | | | | [MatMul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MatMul) | :white_check_mark: | `ggml_mul_mat` | | [Max](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Max) | :white_check_mark: | `ggml_max` | @@ -103,13 +103,13 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Pad](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad) | | | | [Pow](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pow) | :white_check_mark: | | | [RNN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RNN) | | | -| [RandomNormal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormal) | | | -| [RandomNormalLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormalLike) | | | -| [RandomUniform](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniform) | | | -| [RandomUniformLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniformLike) | | | -| [Reciprocal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reciprocal) | | | -| [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | | | -| [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | | | +| [RandomNormal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormal) |:x: (Test case not provided)| | +| [RandomNormalLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormalLike) |:x: (Test case not provided)| | +| [RandomUniform](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniform) |:x: (Test case not provided)| | +| [RandomUniformLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniformLike) |:x: (Test case not provided)| | +| [Reciprocal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reciprocal) | :white_check_mark: | | +| [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | :white_check_mark: | | +| [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | :white_check_mark: | | | [ReduceLogSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSum) | :white_check_mark: | | | [ReduceLogSumExp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSumExp) | ⚙️ | | | [ReduceMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMax) | :white_check_mark: | | diff --git a/ggml/contrib/progress.md b/ggml/contrib/progress.md deleted file mode 100644 index f1aafe17..00000000 --- a/ggml/contrib/progress.md +++ /dev/null @@ -1,102 +0,0 @@ -# Operator Implementation Progress - -This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/blob/main/onnx/defs/operator_sets.h) and may not include all ONNX operators. These are core operators available in all versions starting from ai.onnx version 1. -| ONNX Operators | Implemented | ggml Equivalent | -|:--------------------------------------------------------------------------------------------------|:------------------:|:----------------:| -| [Abs](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Abs) | :white_check_mark: | `ggml_abs` | -| [Add](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Add) | :white_check_mark: | `ggml_add` | -| [And](https://github.com/onnx/onnx/blob/main/docs/Operators.md#And) | :white_check_mark: | | -| [ArgMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMax) | :white_check_mark: | | -| [ArgMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ArgMin) | :white_check_mark: | | -| [AveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#AveragePool) | | | -| [BatchNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BatchNormalization) | | | -| [Cast](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Cast) | :white_check_mark: | | -| [Ceil](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Ceil) | :white_check_mark: | | -| [Clip](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Clip) | | | -| [Concat](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Concat) | :white_check_mark: | `ggml_concat` | -| [Constant](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Constant) | :white_check_mark: | | -| [ConstantOfShape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConstantOfShape) | :white_check_mark: | | -| [Conv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv) | | | -| [ConvTranspose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConvTranspose) | | | -| [DepthToSpace](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DepthToSpace) | | | -| [Div](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Div) | :white_check_mark: | `ggml_div` | -| [Dropout](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Dropout) -> [code ref](https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/dropout.py) | | | -| [Elu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Elu) | :white_check_mark: | `ggml_elu` | -| [Equal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Equal) | :white_check_mark: | | -| [Exp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Exp) | :white_check_mark: | | -| [Flatten](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Flatten) | :white_check_mark: | | -| [Floor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Floor) | :white_check_mark: | | -| [GRU](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GRU) | | | -| [Gather](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gather) | :white_check_mark: | | -| [Gemm](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gemm) | | | -| [GlobalAveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalAveragePool) | | | -| [GlobalLpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalLpPool) | | | -| [GlobalMaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalMaxPool) | | | -| [Greater](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Greater) | :white_check_mark: | | -| [HardSigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSigmoid) | :white_check_mark: | | -| [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | :white_check_mark: | | -| [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | :white_check_mark: | | -| [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | :x: | | -| [InstanceNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormalization)| | | -| [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | :white_check_mark: | | -| [LSTM](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LSTM) | | | -| [LeakyRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LeakyRelu) | ⚙️ | | -| [Less](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Less) | :white_check_mark: | | -| [Log](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Log) | :white_check_mark: | `ggml_log` | -| [LogSoftmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LogSoftmax) | :white_check_mark: | | -| [Loop](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Loop) | :x: | | -| [LpNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpNormalization) |:x: (Test case not provided)| | -| [LpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LpPool) | | | -| [MatMul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MatMul) | :white_check_mark: | `ggml_mul_mat` | -| [Max](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Max) | :white_check_mark: | `ggml_max` | -| [MaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxPool) | |`ggml.ggml_pool_2d`| -| [MaxRoiPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxRoiPool) | | | -| [Mean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mean) | :white_check_mark: |~~`ggml_mean`~~
`ggml_add` + `ggml_div`| -| [Min](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Min) | :white_check_mark: | | -| [Mul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Mul) | :white_check_mark: | `ggml_mul` | -| [Neg](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Neg) | :white_check_mark: | `ggml_neg` | -| [Not](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Not) | :white_check_mark: | | -| [Or](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Or) | :white_check_mark: | | -| [PRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#PRelu) | :white_check_mark: | | -| [Pad](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad) | | | -| [Pow](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pow) | :white_check_mark: | | -| [RNN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RNN) | | | -| [RandomNormal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormal) |:x: (Test case not provided)| | -| [RandomNormalLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormalLike) |:x: (Test case not provided)| | -| [RandomUniform](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniform) |:x: (Test case not provided)| | -| [RandomUniformLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniformLike) |:x: (Test case not provided)| | -| [Reciprocal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reciprocal) | :white_check_mark: | | -| [ReduceL1](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL1) | :white_check_mark: | | -| [ReduceL2](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceL2) | :white_check_mark: | | -| [ReduceLogSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSum) | :white_check_mark: | | -| [ReduceLogSumExp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceLogSumExp) | ⚙️ | | -| [ReduceMax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMax) | :white_check_mark: | | -| [ReduceMean](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMean) | :white_check_mark: | | -| [ReduceMin](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceMin) | :white_check_mark: | | -| [ReduceProd](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceProd) | :white_check_mark: | | -| [ReduceSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSum) | :white_check_mark: | | -| [ReduceSumSquare](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSumSquare) | :white_check_mark: | | -| [Relu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Relu) | :white_check_mark: | `ggml_relu` | -| [Reshape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reshape) | :white_check_mark: | `ggml_reshape` | -| [Selu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Selu) | :white_check_mark: | | -| [Shape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Shape) | :white_check_mark: | | -| [Sigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sigmoid) | :white_check_mark: | | -| [Size](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Size) | :white_check_mark: | | -| [Slice](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Slice) | | | -| [Softmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softmax) | :white_check_mark: | `ggml_soft_max` | -| [Softplus](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softplus) | :white_check_mark: | | -| [Softsign](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softsign) | :white_check_mark: | | -| [SpaceToDepth](https://github.com/onnx/onnx/blob/main/docs/Operators.md#SpaceToDepth) | | | -| [Split](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Split) | | | -| [Sqrt](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sqrt) | :white_check_mark: | `ggml_sqrt` | -| [Squeeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Squeeze) | :white_check_mark: | | -| [Sub](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sub) | :white_check_mark: | `ggml_sub` | -| [Sum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sum) | :white_check_mark: | `ggml_sum` | -| [Tanh](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tanh) | :white_check_mark: | `ggml_tanh` | -| [Tile](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tile) | :white_check_mark: | | -| [TopK](https://github.com/onnx/onnx/blob/main/docs/Operators.md#TopK) | | | -| [Transpose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Transpose) | :white_check_mark: | `ggml_transpose` | -| [Unsqueeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Unsqueeze) | :white_check_mark: | | -| ~~[Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample)~~ (Deprecated) | :x: | | -| [Xor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Xor) | :white_check_mark: | | - From 7fc5804e2d3df24915736c775e41a417ff8b8468 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 15:36:19 -0400 Subject: [PATCH 134/232] Fix Softsign --- ggml/contrib/onnx.py | 3 ++- tests/test_ggml_onnx.py | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index bd3ebb25..1714f82a 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3577,7 +3577,8 @@ def ggml_operator_softsign( x_abs = ggml.ggml_abs(context, x) one_plus_abs = ggml.ggml_add(context, one_t, x_abs) y = ggml.ggml_div(context, x, one_plus_abs) - + tensors_dict[node.output[0]] = y + return y diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 82bad257..c279cca5 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -86,6 +86,7 @@ def test_ggml_onnx_runtime_basic(): ggml_result = ggml_dummy_model.run(input_data) assert ggml_result == runtime_result + def test_ggml_onnx_graph_optimization(): # Construct an onnx graph and optimize it # The graph is of the form y = (A^T)^T * x + b @@ -93,7 +94,7 @@ def test_ggml_onnx_graph_optimization(): # The name of the input tensor input_name = "x" - + # The name of the weights tensor weight_name_a = "A" weight_name_b = "b" @@ -195,12 +196,12 @@ def test_ggml_onnx_runtime_quantized(): node2 = helper.make_node( "Add", ["x_times_A", weight_name_b], [output_name], name="node2" ) # x * A + b - + # Define the tensors (values) in our graph X_value_info = helper.make_tensor_value_info( input_name, TensorProto.FLOAT, [None, 32] ) - + output_value_info = helper.make_tensor_value_info( output_name, TensorProto.FLOAT, [None, 32] ) @@ -243,16 +244,15 @@ def test_ggml_onnx_runtime_quantized(): f = io.BytesIO() onnx.save(model_def, f) - + runtime_result = InferenceSession(f.getvalue()).run(None, input_data) - + ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) ggml_result = ggml_dummy_model.run(input_data) assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) - backend_test = onnx.backend.test.BackendTest(GgmlRuntimeBackend, __name__) backend_test.include("test_abs_") @@ -272,7 +272,7 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_concat_") backend_test.include("test_constant_") -# backend_test.exclude(".*constant.*.*pad.*") +backend_test.exclude(".*constant.*.*pad.*") # backend_test.include("test_clip_") From d5355c689aaaf40deaaaf8318d1b7d65e999f338 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 29 Aug 2023 16:36:49 -0400 Subject: [PATCH 135/232] Add transpose transpose rewrite rule --- tests/test_ggml_onnx.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index d9c33b37..46407df4 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -158,6 +158,43 @@ def test_ggml_onnx_graph_optimization(): model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") + from typing import Optional + from ggml.contrib.onnx import GgmlOnnxGraphOptimizer, GgmlOnnxGraphOptimizerRule + from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto + + class TransposeTransposeRule(GgmlOnnxGraphOptimizerRule): + def __init__(self): + super().__init__() + + def apply(self, model: onnx.ModelProto) -> Optional[ModelProto]: + # find first transpose node + transpose_node: Optional[NodeProto] = None + for node in model.graph.node: + if node.op_type == "Transpose": + transpose_node = node + break + else: + return None + + # find a transpose node that transposes the output of the first transpose node + transpose_transpose_node: Optional[NodeProto] = None + for node in model.graph.node: + if node.op_type == "Transpose" and node.input[0] == transpose_node.output[0]: + transpose_transpose_node = node + break + else: + return None + + # remove the transpose nodes + model.graph.node.remove(transpose_node) + model.graph.node.remove(transpose_transpose_node) + + # update the connections + transpose_transpose_node.output[0] = transpose_node.input[0] + + return model + + input_data = {"x": np.random.randn(1, 32).astype(np.float32)} f = io.BytesIO() From dd9efbc8026d21106e745e32949a17fead3f6a5c Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Tue, 29 Aug 2023 17:32:38 -0400 Subject: [PATCH 136/232] Add TopK operator --- ggml/contrib/onnx.py | 141 +++++++++++++++++++++++++++++++++++++++- tests/test_ggml_onnx.py | 4 +- 2 files changed, 142 insertions(+), 3 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 1714f82a..37248fbd 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3578,7 +3578,7 @@ def ggml_operator_softsign( one_plus_abs = ggml.ggml_add(context, one_t, x_abs) y = ggml.ggml_div(context, x, one_plus_abs) tensors_dict[node.output[0]] = y - + return y @@ -3847,6 +3847,145 @@ def ggml_operator_tile( return new_tensor +class TopKUserData(ctypes.Structure): + _fields_ = [ + ("axis", ctypes.c_int), + ("largest", ctypes.c_int), + ("sorted", ctypes.c_int), + ("k", ctypes.c_int), + ] + + +@ggml.ggml_custom2_op_t +def custom_top_k_indices( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_2) + + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(TopKUserData)) + userdata_data = userdata_data_ptr.contents + + axis = userdata_data.axis + largest = bool(userdata_data.largest) + sort = bool(userdata_data.sorted) + + k = userdata_data.k + + if largest: + sorted_indices = np.argsort(x, axis=axis)[:, ::-1] + else: + sorted_indices = np.argsort(x, axis=axis) + + topk_indices = sorted_indices[:, :k] + + set_tensor_out(tensor_out, topk_indices) + + +@ggml.ggml_custom3_op_t +def custom_top_k_values( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_2) + topk_indices = ggml.utils.to_numpy(tensor_in_3).astype(np.int32) + + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(TopKUserData)) + userdata_data = userdata_data_ptr.contents + + axis = userdata_data.axis + sorted_flag = bool(userdata_data.sorted) + + topk_values = np.take_along_axis(x, topk_indices, axis=axis) + if sorted_flag: + topk_values_sorted = np.sort(topk_values, axis=axis) + else: + topk_values_sorted = topk_values + + set_tensor_out(tensor_out, topk_values_sorted) + + +@ggml_operator("TopK") +def ggml_operator_top_k( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 2: + raise ValueError( + f'Error for node "{node.name}": Operation "TopK" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + x, k = node_inputs + + input_shape = get_tensor_shape(x) + + axis = next((attr.i for attr in node.attribute if attr.name == "axis"), -1) + largest = next((attr.i for attr in node.attribute if attr.name == "largest"), 1) + sorted_flag = next((attr.i for attr in node.attribute if attr.name == "sorted"), 0) + + k_eval = backend.eval_tensor(k, context) + k_np = ggml.utils.to_numpy(k_eval)[0] + + topk_userdata = TopKUserData(axis, largest, sorted_flag, k_np) + userdata_p = ctypes.cast(ctypes.pointer(topk_userdata), ctypes.c_void_p) + + output_shape = list(input_shape) + output_shape[axis] = k_np + output_shape = tuple(output_shape) + + indices_t = ggml.utils.from_numpy( + np.empty(output_shape, dtype=np.int32), + context, + ) + + values_t = ggml.utils.from_numpy( + np.empty(output_shape, dtype=get_tensor_dtype(x)), + context, + ) + + indices = ggml.ggml_map_custom2_inplace( + context, + indices_t, + x, + custom_top_k_indices, + 1, + userdata_p, + ) + + values = ggml.ggml_map_custom3_inplace( + context, + values_t, + x, + indices, + custom_top_k_values, + 1, + userdata_p, + ) + + tensors_dict[node.output[0]] = values + tensors_dict[node.output[1]] = indices + + refs.append(topk_userdata) + + ggml.ggml_set_name(indices, (node.output[1] + f"").encode()) + + return values, indices + + @ggml_operator("Transpose") def ggml_operator_transpose( backend: "GgmlBackendRep", diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index c279cca5..b7528068 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -274,8 +274,6 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_constant_") backend_test.exclude(".*constant.*.*pad.*") -# backend_test.include("test_clip_") - backend_test.include("test_div_") backend_test.exclude("test_div_uint8_") # not supported @@ -403,6 +401,8 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_tanh_") backend_test.include("test_tile_") +backend_test.include("test_top_k") + backend_test.include("test_transpose_") backend_test.include("test_unsqueeze_") From c535f07347077a1049e99442a12c4c165aa797a1 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 30 Aug 2023 11:52:41 -0400 Subject: [PATCH 137/232] Add Split operator --- docs/contrib/onnx.md | 4 +- ggml/contrib/onnx.py | 115 +++++++++++++++++++++++++++++++++++++++- tests/test_ggml_onnx.py | 3 ++ 3 files changed, 119 insertions(+), 3 deletions(-) diff --git a/docs/contrib/onnx.md b/docs/contrib/onnx.md index 5f479c46..c2f0cc39 100644 --- a/docs/contrib/onnx.md +++ b/docs/contrib/onnx.md @@ -129,14 +129,14 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Softplus](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softplus) | :white_check_mark: | | | [Softsign](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softsign) | :white_check_mark: | | | [SpaceToDepth](https://github.com/onnx/onnx/blob/main/docs/Operators.md#SpaceToDepth) | | | -| [Split](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Split) | | | +| [Split](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Split) | :white_check_mark: | | | [Sqrt](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sqrt) | :white_check_mark: | `ggml_sqrt` | | [Squeeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Squeeze) | :white_check_mark: | | | [Sub](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sub) | :white_check_mark: | `ggml_sub` | | [Sum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sum) | :white_check_mark: | `ggml_sum` | | [Tanh](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tanh) | :white_check_mark: | `ggml_tanh` | | [Tile](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Tile) | :white_check_mark: | | -| [TopK](https://github.com/onnx/onnx/blob/main/docs/Operators.md#TopK) | | | +| [TopK](https://github.com/onnx/onnx/blob/main/docs/Operators.md#TopK) | :white_check_mark: | | | [Transpose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Transpose) | :white_check_mark: | `ggml_transpose` | | [Unsqueeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Unsqueeze) | :white_check_mark: | | | ~~[Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample)~~ (Deprecated) | :x: | | diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 37248fbd..32f7b61a 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3511,6 +3511,120 @@ def ggml_operator_size( return new_tensor +class SplitUserData(ctypes.Structure): + _fields_ = [ + ("axis", ctypes.c_int), + ("split_index", ctypes.c_int), + ] + + +@ggml.ggml_custom3_op_t +def custom_split( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(SplitUserData)) + userdata_data = userdata_data_ptr.contents + + axis = userdata_data.axis + split_index = userdata_data.split_index + + tensor = ggml.utils.to_numpy(tensor_in_2) + + split_shapes = ggml.utils.to_numpy(tensor_in_3) + split_shape = list(ggml.utils.to_numpy(tensor_in_1).shape) + + split_size = split_shape[axis] + split_start = sum(split_shapes[i][axis] for i in range(split_index)) + split_end = split_start + split_size + + split_output = np.take(tensor, range(split_start, split_end), axis=axis) + + set_tensor_out(tensor_out, split_output) + + +@ggml_operator("Split") +def ggml_operator_split( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 1 or len(node_inputs) > 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Split" requires 1 - 2 inputs. Actual number of inputs: {len(node_inputs)}' + ) + + input_tensor = node_inputs.pop(0) + split_tensor = node_inputs.pop(0) if len(node_inputs) else None + + axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 0) + num_outputs = next( + (attr.i for attr in node.attribute if attr.name == "num_outputs"), + len(node.output), + ) + + input_shape = list(get_tensor_shape(input_tensor)) + dtype = get_tensor_dtype(input_tensor) + + if split_tensor is None: + split_size = input_shape[axis] // num_outputs + remainder = input_shape[axis] % num_outputs + split_shapes = [list(input_shape) for _ in range(num_outputs)] + + for i in range(num_outputs): + split_shapes[i][axis] = split_size + if i < remainder: + split_shapes[i][axis] += 1 + + split_shapes = [tuple(split_shape) for split_shape in split_shapes] + + else: + split_eval = backend.eval_tensor(split_tensor, context) + split_values = ggml.utils.to_numpy(split_eval) + split_shapes = [list(input_shape) for _ in range(num_outputs)] + + for i, split_value in enumerate(split_values): + split_shapes[i][axis] = split_value + + split_shapes = tuple(map(tuple, split_shapes)) + + split_shapes_np = np.array(split_shapes, dtype=np.int32) + split_shapes_t = ggml.utils.from_numpy(split_shapes_np, context) + + outputs = [] + + for split_index, split_shape in enumerate(split_shapes): + split_userdata = SplitUserData(axis, split_index) + userdata_p = ctypes.cast(ctypes.pointer(split_userdata), ctypes.c_void_p) + + x_t = ggml.utils.from_numpy(np.empty(split_shape, dtype=dtype), context) + new_tensor = tensors_dict[ + node.output[split_index] + ] = ggml.ggml_map_custom3_inplace( + context, + x_t, + input_tensor, + split_shapes_t, + custom_split, + 1, + userdata_p, + ) + + refs.append(split_userdata) + outputs.append(new_tensor) + + return outputs + + @ggml.ggml_custom1_op_t def custom_softplus( tensor_out: ggml.ggml_tensor_p, @@ -3872,7 +3986,6 @@ def custom_top_k_indices( axis = userdata_data.axis largest = bool(userdata_data.largest) - sort = bool(userdata_data.sorted) k = userdata_data.k diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index b7528068..10ac12d6 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -381,6 +381,9 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_size_") +backend_test.include("test_split_") +backend_test.exclude(".*split.*.*to.*.*sequence.*") + backend_test.include("test_softmax_") backend_test.exclude("test_softmax_axis_0") # not supported backend_test.exclude("test_softmax_axis_1") # not supported From c5ba003ad9388bc440042f969bd5c8b9c6337864 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 30 Aug 2023 13:12:39 -0400 Subject: [PATCH 138/232] Add SpaceToDepth + sort operators --- docs/contrib/onnx.md | 6 +- ggml/contrib/onnx.py | 267 +++++++++++++++++++++++++--------------- tests/test_ggml_onnx.py | 2 + 3 files changed, 174 insertions(+), 101 deletions(-) diff --git a/docs/contrib/onnx.md b/docs/contrib/onnx.md index c2f0cc39..2fe0ef28 100644 --- a/docs/contrib/onnx.md +++ b/docs/contrib/onnx.md @@ -102,7 +102,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [PRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#PRelu) | :white_check_mark: | | | [Pad](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad) | | | | [Pow](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pow) | :white_check_mark: | | -| [RNN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RNN) | | | +| [RNN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RNN) | :x: | | | [RandomNormal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormal) |:x: (Test case not provided)| | | [RandomNormalLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomNormalLike) |:x: (Test case not provided)| | | [RandomUniform](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RandomUniform) |:x: (Test case not provided)| | @@ -128,7 +128,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Softmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softmax) | :white_check_mark: | `ggml_soft_max` | | [Softplus](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softplus) | :white_check_mark: | | | [Softsign](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Softsign) | :white_check_mark: | | -| [SpaceToDepth](https://github.com/onnx/onnx/blob/main/docs/Operators.md#SpaceToDepth) | | | +| [SpaceToDepth](https://github.com/onnx/onnx/blob/main/docs/Operators.md#SpaceToDepth) | :white_check_mark: | | | [Split](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Split) | :white_check_mark: | | | [Sqrt](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sqrt) | :white_check_mark: | `ggml_sqrt` | | [Squeeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Squeeze) | :white_check_mark: | | @@ -139,5 +139,5 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [TopK](https://github.com/onnx/onnx/blob/main/docs/Operators.md#TopK) | :white_check_mark: | | | [Transpose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Transpose) | :white_check_mark: | `ggml_transpose` | | [Unsqueeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Unsqueeze) | :white_check_mark: | | -| ~~[Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample)~~ (Deprecated) | :x: | | +| ~~[Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample)~~ | :x: (Deprecated) | | | [Xor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Xor) | :white_check_mark: | | diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 32f7b61a..127f85ef 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3511,6 +3511,175 @@ def ggml_operator_size( return new_tensor +@ggml_operator("Softmax") +def ggml_operator_softmax( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Softmax" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + output_name = node.output[0] + a = node_inputs[0] + + soft_max_result = ggml.ggml_soft_max( + context, + a, + ) + tensors_dict[output_name] = soft_max_result + return soft_max_result + + +@ggml.ggml_custom1_op_t +def custom_softplus( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_1) + y = np.log(np.exp(x) + 1) + set_tensor_out(tensor_out, y) + + +@ggml_operator("Softplus") +def ggml_operator_softplus( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Softplus" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + context, + x, + custom_softplus, + 1, + None, + ) + + return new_tensor + + +@ggml_operator("Softsign") +def ggml_operator_softsign( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Softsign" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + x_shape = get_tensor_shape(x) + x_dtype = get_tensor_dtype(x) + + # y = x / (1 + abs(x)) + one_np = np.full(x_shape, 1, dtype=x_dtype) + one_t = ggml.utils.from_numpy(one_np, context) + x_abs = ggml.ggml_abs(context, x) + one_plus_abs = ggml.ggml_add(context, one_t, x_abs) + y = ggml.ggml_div(context, x, one_plus_abs) + tensors_dict[node.output[0]] = y + + return y + + +@ggml.ggml_custom2_op_t +def custom_space_to_depth( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_2) + blocksize = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + + N, C, H, W = x.shape + new_H = H // blocksize + new_W = W // blocksize + + reshaped = x.reshape(N, C, new_H, blocksize, new_W, blocksize) + transposed = reshaped.transpose(0, 3, 5, 1, 2, 4) # ONNX specification TODO: Test more examples + y = transposed.reshape(N, C * (blocksize ** 2), new_H, new_W) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("SpaceToDepth") +def ggml_operator_space_to_depth( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "SpaceToDepth" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + blocksize = next( + (attr.i for attr in node.attribute if attr.name == "blocksize"), None + ) + + if blocksize is None: + raise ValueError( + f'Error for node "{node.name}": Operation "SpaceToDepth" requires "blocksize"' + ) + + N, C, H, W = get_tensor_shape(x) + new_H = H // blocksize + new_W = W // blocksize + output_shape = (N, C * blocksize * blocksize, new_H, new_W) + + x_t = ggml.utils.from_numpy( + np.empty(output_shape, dtype=get_tensor_dtype(x)), context + ) + + blocksize_c = ctypes.c_int(blocksize) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + x, + custom_space_to_depth, + 1, + ctypes.pointer(blocksize_c), + ) + + refs.append(blocksize_c) + + return new_tensor + class SplitUserData(ctypes.Structure): _fields_ = [ ("axis", ctypes.c_int), @@ -3624,104 +3793,6 @@ def ggml_operator_split( return outputs - -@ggml.ggml_custom1_op_t -def custom_softplus( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_1) - y = np.log(np.exp(x) + 1) - set_tensor_out(tensor_out, y) - - -@ggml_operator("Softplus") -def ggml_operator_softplus( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] - - if len(node_inputs) != 1: - raise ValueError( - f'Error for node "{node.name}": Operation "Softplus" requires exactly one input. Actual number of inputs: {len(node_inputs)}' - ) - - x = node_inputs[0] - - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, - x, - custom_softplus, - 1, - None, - ) - - return new_tensor - - -@ggml_operator("Softsign") -def ggml_operator_softsign( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] - - if len(node_inputs) != 1: - raise ValueError( - f'Error for node "{node.name}": Operation "Softsign" requires exactly one input. Actual number of inputs: {len(node_inputs)}' - ) - - x = node_inputs[0] - x_shape = get_tensor_shape(x) - x_dtype = get_tensor_dtype(x) - - # y = x / (1 + abs(x)) - one_np = np.full(x_shape, 1, dtype=x_dtype) - one_t = ggml.utils.from_numpy(one_np, context) - x_abs = ggml.ggml_abs(context, x) - one_plus_abs = ggml.ggml_add(context, one_t, x_abs) - y = ggml.ggml_div(context, x, one_plus_abs) - tensors_dict[node.output[0]] = y - - return y - - -@ggml_operator("Softmax") -def ggml_operator_softmax( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] - - if len(node_inputs) != 1: - raise ValueError( - f'Error for node "{node.name}": Operation "Softmax" requires exactly one input. Actual number of inputs: {len(node_inputs)}' - ) - - output_name = node.output[0] - a = node_inputs[0] - - soft_max_result = ggml.ggml_soft_max( - context, - a, - ) - tensors_dict[output_name] = soft_max_result - return soft_max_result - - @ggml_operator("Sqrt") def ggml_operator_sqrt( backend: "GgmlBackendRep", diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 10ac12d6..beac74ab 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -393,6 +393,8 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_softplus_") backend_test.include("test_softsign_") +backend_test.include("test_spacetodepth") + backend_test.include("test_sqrt_") backend_test.include("test_sub_") From c07261f3df2a246da2cc4015643ceb8814c62734 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 30 Aug 2023 14:30:23 -0400 Subject: [PATCH 139/232] Remove quantization from prepare --- ggml/contrib/onnx.py | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 1714f82a..e6a9debb 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4252,19 +4252,7 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): for initializer in graph.initializer: name = initializer.name np_array = onnx.numpy_helper.to_array(initializer) - if can_quantize(np_array, name, graph): - ggml_qtype = ggml.utils.GGML_TYPE.Q8_0 - shape = tuple(reversed(np_array.shape)) - tensor = ggml.ggml_new_tensor( - context, - ggml_qtype.value, - len(shape), - (ctypes.c_int64 * len(shape))(*shape), - ) - - else: - tensor = ggml.utils.from_numpy(x=np_array, ctx=context) - + tensor = ggml.utils.from_numpy(x=np_array, ctx=context) ggml.ggml_set_name(tensor=tensor, name=name.encode()) total_nbytes += ggml.ggml_nbytes_pad(tensor) weights[name] = tensor @@ -4278,25 +4266,8 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): tensor.contents.data = ctypes.cast( ctypes.addressof(buffer) + offset, ctypes.c_void_p ) - np_array = onnx.numpy_helper.to_array(initializer) - if ggml.ggml_is_quantized(tensor.contents.type): - np_c_float_data = (ctypes.c_float * np_array.size).from_address( - ctypes.addressof(np_array.ctypes.data) - ) - - ggml.utils.quantize_0( - np_c_float_data, - np_array.size, - np_array.shape[0], - ggml_qtype, - work=ctypes.cast( - ctypes.addressof(buffer) + offset, ctypes.c_void_p - ), - ) - - else: - set_tensor_out(tensor, np_array) + set_tensor_out(tensor, np_array) offset += nbytes From 4ed259f4ee625f73505a33f40ce5b1b81b66e818 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 30 Aug 2023 14:32:55 -0400 Subject: [PATCH 140/232] Add Gemm operator --- docs/contrib/onnx.md | 4 +- ggml/contrib/onnx.py | 135 ++++++++++++++++++++++++++++++++++++++-- tests/test_ggml_onnx.py | 9 ++- 3 files changed, 138 insertions(+), 10 deletions(-) diff --git a/docs/contrib/onnx.md b/docs/contrib/onnx.md index 2fe0ef28..7f2c157e 100644 --- a/docs/contrib/onnx.md +++ b/docs/contrib/onnx.md @@ -68,9 +68,9 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Exp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Exp) | :white_check_mark: | | | [Flatten](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Flatten) | :white_check_mark: | | | [Floor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Floor) | :white_check_mark: | | -| [GRU](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GRU) | | | +| [GRU](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GRU) | :x: | | | [Gather](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gather) | :white_check_mark: | | -| [Gemm](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gemm) | | | +| [Gemm](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Gemm) | :white_check_mark: | | | [GlobalAveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalAveragePool) | | | | [GlobalLpPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalLpPool) | | | | [GlobalMaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#GlobalMaxPool) | | | diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 127f85ef..821881be 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1163,6 +1163,127 @@ def ggml_operator_gather( return new_tensor +@ggml_operator("Gemm") +def ggml_operator_gemm( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Gemm" requires at least two inputs. Actual number of inputs: {len(node_inputs)}' + ) + + node_inputs_iter = iter(node_inputs) + + a = next(node_inputs_iter) + b = next(node_inputs_iter) + c = next(node_inputs_iter, None) + + alpha = next((attr.f for attr in node.attribute if attr.name == "alpha"), 1.0) + beta = next((attr.f for attr in node.attribute if attr.name == "beta"), 1.0) + + transA = next((attr.i for attr in node.attribute if attr.name == "transA"), 0) + transB = next((attr.i for attr in node.attribute if attr.name == "transB"), 0) + + b_shape = get_tensor_shape(b) + a_shape = get_tensor_shape(a) + + # TODO: broadcast? Current broadcasting method fails during tests + + a_dtype = get_tensor_dtype(a) + b_dtype = get_tensor_dtype(b) + + a_transposed = a + b_transposed = b + + if transA: + a_permute = ggml.ggml_transpose( + context, + a, + ) + a_shape = ggml.utils.get_shape(a_permute) + a_transposed = ggml.ggml_cpy( + context, + a_permute, + ggml.ggml_new_tensor( + context, + map_to_ggml_type(a_dtype).value, + len(a_shape), + (ctypes.c_int64 * len(a_shape))(*a_shape), + ), + ) + + if not transB: + b_permute = ggml.ggml_transpose( + context, + b, + ) + b_shape = ggml.utils.get_shape(b_permute) + b_transposed = ggml.ggml_cpy( + context, + b_permute, + ggml.ggml_new_tensor( + context, + map_to_ggml_type(b_dtype).value, + len(b_shape), + (ctypes.c_int64 * len(b_shape))(*b_shape), + ), + ) + + # Y = alpha * np.dot(A, B) + beta * C + # ref: https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/gemm.py + + mul_mat_result = ggml.ggml_mul_mat( + context, + b_transposed, + a_transposed, + ) + + alpha_t = ggml.utils.from_numpy( + np.full( + get_tensor_shape(mul_mat_result), + alpha, + dtype=get_tensor_dtype(mul_mat_result), + ), + context, + ) + + mul_mat_result = ggml.ggml_mul_inplace(context, mul_mat_result, alpha_t) + + if c is None: + c = ggml.utils.from_numpy( + np.full( + get_tensor_shape(mul_mat_result), + 0, + dtype=get_tensor_dtype(mul_mat_result), + ), + context, + ) + + c, mul_mat_result = broadcast_shapes(context, c, mul_mat_result) + + beta_t = ggml.utils.from_numpy( + np.full( + get_tensor_shape(mul_mat_result), + beta, + dtype=get_tensor_dtype(mul_mat_result), + ), + context, + ) + + mul_mat_result = ggml.ggml_add_inplace( + context, mul_mat_result, ggml.ggml_mul_inplace(context, c, beta_t) + ) + + tensors_dict[node.output[0]] = mul_mat_result + return mul_mat_result + + @ggml.ggml_custom3_op_t def custom_greater( tensor_out: ggml.ggml_tensor_p, @@ -3623,11 +3744,13 @@ def custom_space_to_depth( N, C, H, W = x.shape new_H = H // blocksize new_W = W // blocksize - + reshaped = x.reshape(N, C, new_H, blocksize, new_W, blocksize) - transposed = reshaped.transpose(0, 3, 5, 1, 2, 4) # ONNX specification TODO: Test more examples - y = transposed.reshape(N, C * (blocksize ** 2), new_H, new_W) - + transposed = reshaped.transpose( + 0, 3, 5, 1, 2, 4 + ) # ONNX specification TODO: Test more examples + y = transposed.reshape(N, C * (blocksize**2), new_H, new_W) + set_tensor_out(tensor_out, y) @@ -3680,6 +3803,7 @@ def ggml_operator_space_to_depth( return new_tensor + class SplitUserData(ctypes.Structure): _fields_ = [ ("axis", ctypes.c_int), @@ -3793,6 +3917,7 @@ def ggml_operator_split( return outputs + @ggml_operator("Sqrt") def ggml_operator_sqrt( backend: "GgmlBackendRep", @@ -4497,7 +4622,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Set user inputs for key, value in inputs.items(): - set_tensor_out(ggml_tensors[key], value) + set_tensor_out(ggml_tensors[key], np.array(value)) gf = ggml.ggml_cgraph() gf_p = ctypes.pointer(gf) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index beac74ab..3ec6d49f 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -297,6 +297,9 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_gather_") backend_test.exclude("test_gather_elements") # not supported +backend_test.include("test_gemm") +backend_test.exclude("test_gemm_default_scalar_bias") + backend_test.include("test_greater_") backend_test.include("test_hardsigmoid_") @@ -381,9 +384,6 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_size_") -backend_test.include("test_split_") -backend_test.exclude(".*split.*.*to.*.*sequence.*") - backend_test.include("test_softmax_") backend_test.exclude("test_softmax_axis_0") # not supported backend_test.exclude("test_softmax_axis_1") # not supported @@ -395,6 +395,9 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_spacetodepth") +backend_test.include("test_split_") +backend_test.exclude(".*split.*.*to.*.*sequence.*") + backend_test.include("test_sqrt_") backend_test.include("test_sub_") From 4a1c638118bc3af17bb7748360ad4bb660648db2 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 30 Aug 2023 15:39:27 -0400 Subject: [PATCH 141/232] Add DepthToSpace, fix ConstantOfShape --- docs/contrib/onnx.md | 4 +- ggml/contrib/onnx.py | 128 ++++++++++++++++++++++++++++++++++++++-- tests/test_ggml_onnx.py | 4 ++ 3 files changed, 128 insertions(+), 8 deletions(-) diff --git a/docs/contrib/onnx.md b/docs/contrib/onnx.md index 7f2c157e..a680f533 100644 --- a/docs/contrib/onnx.md +++ b/docs/contrib/onnx.md @@ -60,7 +60,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [ConstantOfShape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConstantOfShape) | :white_check_mark: | | | [Conv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv) | | | | [ConvTranspose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConvTranspose) | | | -| [DepthToSpace](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DepthToSpace) | | | +| [DepthToSpace](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DepthToSpace) | :white_check_mark: | | | [Div](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Div) | :white_check_mark: | `ggml_div` | | [Dropout](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Dropout) -> [code ref](https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/dropout.py) | | | | [Elu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Elu) | :white_check_mark: | `ggml_elu` | @@ -81,7 +81,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | :x: | | | [InstanceNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormalization)| | | | [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | :white_check_mark: | | -| [LSTM](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LSTM) | | | +| [LSTM](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LSTM) | :x: | | | [LeakyRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LeakyRelu) | ⚙️ | | | [Less](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Less) | :white_check_mark: | | | [Log](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Log) | :white_check_mark: | `ggml_log` | diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 821881be..6566b8b2 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -790,15 +790,31 @@ def ggml_operator_constant_of_shape( ) node_attributes = node.attribute + value_attr = next(attr for attr in node_attributes if "value" in attr.name) - value_attr = next(attr for attr in node_attributes if attr.name == "value") - tensor = value_attr.t - data_type = tensor.data_type - np_data_type = tensor_dtype_to_np_dtype(data_type) + if value_attr.HasField("t"): + tensor = value_attr.t + data_type = tensor.data_type + np_data_type = tensor_dtype_to_np_dtype(data_type) + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) - np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + if tensor.raw_data: + data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) + else: + data_value = onnx.numpy_helper.to_array(tensor) - data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) + else: + data_type = value_attr.type + np_data_type = tensor_dtype_to_np_dtype(data_type) + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + if np.issubdtype(np_data_type, np.floating): + data_value = np.array(value_attr.f) + elif np.issubdtype(np_data_type, np.integer): + data_value = np.array(value_attr.i) + else: + raise ValueError( + f'Error for node "{node.name}": Constant node not set correctly or incomplete implantation.' + ) data_tensor = ggml.utils.from_numpy( data_value.astype(np_data_type_limit), @@ -822,6 +838,106 @@ def ggml_operator_constant_of_shape( return new_tensor +class DepthToSpaceUserData(ctypes.Structure): + _fields_ = [ + ("blocksize", ctypes.c_int), + ("mode", ctypes.c_char_p), + ] + + +@ggml.ggml_custom2_op_t +def custom_depth_to_space( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_2) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DepthToSpaceUserData)) + userdata_data = userdata_data_ptr.contents + + blocksize = userdata_data.blocksize + mode = userdata_data.mode + + N, C, H, W = x.shape + + new_C = C // (blocksize**2) + new_H = H * blocksize + new_W = W * blocksize + + if mode == b"DCR": + reshaped = x.reshape(N, blocksize, blocksize, C // (blocksize**2), H, W) + transposed_axes = (0, 3, 4, 1, 5, 2) + + elif mode == b"CRD": + reshaped = x.reshape(N, C // (blocksize**2), blocksize, blocksize, H, W) + transposed_axes = (0, 1, 4, 2, 5, 3) + else: + raise ValueError(f"Unknown mode: {mode}") + + transposed = np.transpose(reshaped, axes=transposed_axes) + y = transposed.reshape(N, new_C, new_H, new_W) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("DepthToSpace") +def ggml_operator_depth_to_space( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "DepthToSpace" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + blocksize = next( + (attr.i for attr in node.attribute if attr.name == "blocksize"), None + ) + + mode = next((attr.s for attr in node.attribute if attr.name == "mode"), b"DCR") + + if blocksize is None: + raise ValueError( + f'Error for node "{node.name}": Operation "SpaceToDepth" requires "blocksize"' + ) + + N, C, H, W = get_tensor_shape(x) + + new_C = C // (blocksize**2) + new_H = H * blocksize + new_W = W * blocksize + + output_shape = (N, new_C, new_H, new_W) + + x_t = ggml.utils.from_numpy( + np.empty(output_shape, dtype=get_tensor_dtype(x)), context + ) + depthtospace_userdata = DepthToSpaceUserData(blocksize, mode) + userdata_p = ctypes.cast(ctypes.pointer(depthtospace_userdata), ctypes.c_void_p) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + x, + custom_depth_to_space, + 1, + userdata_p, + ) + + refs.append(depthtospace_userdata) + + return new_tensor + + @ggml_operator("Div") def ggml_operator_div( backend: "GgmlBackendRep", diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 3ec6d49f..b6de5634 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -274,6 +274,10 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_constant_") backend_test.exclude(".*constant.*.*pad.*") +backend_test.include("test_constantofshape") + +backend_test.include("test_depthtospace") + backend_test.include("test_div_") backend_test.exclude("test_div_uint8_") # not supported From b7d731584d0054f8b491aa7e554489efa6b1e3da Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 30 Aug 2023 15:59:13 -0400 Subject: [PATCH 142/232] Add InstanceNormalization operator --- docs/contrib/onnx.md | 2 +- ggml/contrib/onnx.py | 54 +++++++++++++++++++++++++++++++++++++++++ tests/test_ggml_onnx.py | 2 ++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/docs/contrib/onnx.md b/docs/contrib/onnx.md index a680f533..b01845a8 100644 --- a/docs/contrib/onnx.md +++ b/docs/contrib/onnx.md @@ -79,7 +79,7 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | :white_check_mark: | | | [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | :white_check_mark: | | | [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | :x: | | -| [InstanceNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormalization)| | | +| [InstanceNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormalization)| :white_check_mark: | | | [LRN](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LRN) | :white_check_mark: | | | [LSTM](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LSTM) | :x: | | | [LeakyRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#LeakyRelu) | ⚙️ | | diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 6566b8b2..5f19cc0b 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1596,6 +1596,60 @@ def ggml_operator_floor( return y +@ggml.ggml_custom3_op_t +def custom_instancenorm( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_1) + scale = ggml.utils.to_numpy(tensor_in_2) + B = ggml.utils.to_numpy(tensor_in_3) + epsilon = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_double)).contents.value + + mean = np.mean(x, axis=(2, 3), keepdims=True) + variance = np.var(x, axis=(2, 3), keepdims=True) + normalized = (x - mean) / np.sqrt(variance + epsilon) + y = scale.reshape(1, -1, 1, 1) * normalized + B.reshape(1, -1, 1, 1) + + set_tensor_out(tensor_out, y) + + +@ggml_operator("InstanceNormalization") +def ggml_operator_instancenorm( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 3: + raise ValueError( + f'Error for node "{node.name}": Operation "InstanceNormalization" requires exactly three inputs. Actual number of inputs: {len(node_inputs)}' + ) + input_tensor, scale, B = node_inputs + epsilon = next((attr.f for attr in node.attribute if attr.name == "epsilon"), 1e-05) + epsilon_c = ctypes.c_double(epsilon) + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + context, + input_tensor, + scale, + B, + custom_instancenorm, + 1, + ctypes.pointer(epsilon_c), + ) + + refs.append(epsilon_c) + return new_tensor + + class LRNUserData(ctypes.Structure): _fields_ = [ ("alpha", ctypes.c_double), diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index b6de5634..a279e05a 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -314,6 +314,8 @@ def test_ggml_onnx_runtime_quantized(): backend_test.exclude("test_identity_opt") # test case not correct: ONNX issue backend_test.exclude("test_identity_sequence") # test case not correct: ONNX issue +backend_test.include("test_instancenorm") + # backend_test.include("test_leakyrelu") backend_test.include("test_less_") From 53d5bf2fc89175c2f780e0c0d3d5ef800e860eb6 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Wed, 30 Aug 2023 16:10:43 -0400 Subject: [PATCH 143/232] Update onnx.py --- ggml/contrib/onnx.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 5f19cc0b..0a401424 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -432,8 +432,6 @@ def ggml_operator_arg_max( ) x_shape = get_tensor_shape(data) - x_dtype = get_tensor_dtype(data) - x_ndims = ggml.utils.get_ndims(data) dummpy_data = np.empty(x_shape, dtype=np.int32) From e1f977ee86dd8d32dee02a6ec92386b7dc00bfc5 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 31 Aug 2023 10:00:52 -0400 Subject: [PATCH 144/232] Add PyTorch converted model operator tests --- tests/test_ggml_onnx.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index a279e05a..7fa2cc90 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -265,17 +265,22 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_argmax_") backend_test.include("test_argmin_") +backend_test.include("test_operator_basic_") + backend_test.include("test_cast_") backend_test.include("test_ceil_") backend_test.include("test_concat_") +backend_test.include("test_operator_concat") backend_test.include("test_constant_") backend_test.exclude(".*constant.*.*pad.*") backend_test.include("test_constantofshape") +backend_test.include("test_operator_chunk") + backend_test.include("test_depthtospace") backend_test.include("test_div_") @@ -291,8 +296,12 @@ def test_ggml_onnx_runtime_quantized(): backend_test.exclude(".*equal.*.*string.*") backend_test.include("test_exp_") +backend_test.include("test_operator_exp_") + backend_test.include("test_flatten_") +backend_test.include("test_operator_flatten_") + backend_test.include("test_floor_") @@ -322,15 +331,20 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_log_") +backend_test.include("test_LogSoftmax_") + backend_test.include("test_lrn") backend_test.include("test_matmul_") +backend_test.include("test_operator_mm") backend_test.include("test_max_") backend_test.exclude("test_max_float16") # not supported backend_test.exclude("test_max_float64") # not supported backend_test.exclude("test_max_int64") # not supported backend_test.exclude("test_max_uint") # not supported +backend_test.include("test_operator_max_") + backend_test.include("test_mean_") @@ -339,6 +353,8 @@ def test_ggml_onnx_runtime_quantized(): backend_test.exclude("test_min_float64") # not supported backend_test.exclude("test_min_int64") # not supported backend_test.exclude("test_min_uint") # not supported +backend_test.include("test_operator_min_") + backend_test.include("test_mul_") backend_test.exclude("test_mul_uint8") # not supported @@ -356,6 +372,7 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_pow_") backend_test.exclude("test_pow_bcast") # not supported backend_test.exclude("test_pow_types_int64") # not supported +backend_test.include("test_operator_pow_") backend_test.include("test_range_") backend_test.exclude("test_range_float") # segfault @@ -365,12 +382,15 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_reduce_max_") backend_test.include("test_reduce_mean_") +backend_test.include("test_operator_reduced_mean_") backend_test.include("test_reduce_min_") backend_test.include("test_reduce_prod_") backend_test.include("test_reduce_sum_") +backend_test.include("test_operator_reduced_sum_") backend_test.include("test_reduce_log_sum_") backend_test.exclude("test_reduce_log_sum_exp") + backend_test.include("test_reduce_l1_") backend_test.include("test_reduce_l2_") @@ -383,21 +403,28 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_selu_") backend_test.include("test_selu_example") +backend_test.include("test_SELU_") +backend_test.include("test_operator_selu_") backend_test.include("test_shape_") backend_test.include("test_sigmoid_") +backend_test.include("test_Sigmoid_") backend_test.include("test_size_") +# backend_test.include("test_slice_") + backend_test.include("test_softmax_") backend_test.exclude("test_softmax_axis_0") # not supported backend_test.exclude("test_softmax_axis_1") # not supported backend_test.exclude("test_softmax_large_number") # not supported backend_test.exclude("test_softmax_lastdim") # Out of tolerance +# backend_test.include("test_Softmax") backend_test.include("test_softplus_") backend_test.include("test_softsign_") +backend_test.include("test_Softplus") backend_test.include("test_spacetodepth") @@ -405,6 +432,7 @@ def test_ggml_onnx_runtime_quantized(): backend_test.exclude(".*split.*.*to.*.*sequence.*") backend_test.include("test_sqrt_") +backend_test.include("test_operator_sqrt_") backend_test.include("test_sub_") backend_test.exclude("test_sub_bcast_") # not supported @@ -413,6 +441,8 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_sum_") backend_test.include("test_tanh_") +backend_test.include("test_Tanh_") + backend_test.include("test_tile_") backend_test.include("test_top_k") From e479e1ffbdb9ac19a98c2a6d4e3c511f11e510b0 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 31 Aug 2023 13:44:41 -0400 Subject: [PATCH 145/232] Add partial implementation for Conv --- ggml/contrib/onnx.py | 86 +++++++++++++++++++++++++++++++++++++++++ tests/test_ggml_onnx.py | 4 ++ 2 files changed, 90 insertions(+) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 0a401424..b68cafab 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -836,6 +836,92 @@ def ggml_operator_constant_of_shape( return new_tensor +@ggml_operator("Conv") +def ggml_operator_conv( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Conv" requires 2 - 3 inputs. Actual number of inputs: {len(node_inputs)}' + ) + + node_inputs_iter = iter(node_inputs) + x = next(node_inputs_iter) + x_shape = get_tensor_shape(x) + w = next(node_inputs_iter) + w_shape = get_tensor_shape(w) + m = w_shape[0] + bias = next( + node_inputs_iter, + ggml.utils.from_numpy(np.full(m, 0, dtype=get_tensor_dtype(x)), context), + ) + + auto_pad = next( + (attr.s.decode() for attr in node.attribute if attr.name == "auto_pad"), + "NOTSET", + ) + dilations = next( + (attr.ints for attr in node.attribute if attr.name == "dilations"), + [1 for _ in x_shape[2:]], + ) + group = next((attr.i for attr in node.attribute if attr.name == "group"), 1) + kernel_shape = next( + (attr.ints for attr in node.attribute if attr.name == "kernel_shape"), + w_shape[2:], + ) + pads = next( + (attr.ints for attr in node.attribute if attr.name == "pads"), + [0 for _ in x_shape[2:]] * 2, + ) + strides = next( + (attr.ints for attr in node.attribute if attr.name == "strides"), + [1 for _ in x_shape[2:]], + ) + + # Source: https://github.com/onnx/onnx/blob/main/onnx/reference/ops/op_conv.py + + if auto_pad in {"SAME_LOWER", "SAME_UPPER", "VALID"}: + head = [] + tail = [] + for i in range(len(x_shape) - 2): + d = x_shape[i] + target_size = (d + strides[i] - 1) // strides[i] + pad_needed = (target_size - 1) * strides[i] + kernel_shape[i] - d + if auto_pad == "SAME_LOWER": + pad_head = (pad_needed + 1) // 2 + else: + pad_head = pad_needed // 2 + pad_tail = pad_needed - pad_head + head.append(pad_head) + tail.append(pad_tail) + pads = head + tail + + if len(strides) != 2: + raise NotImplementedError("Cannot handle other than 2 strides") + + raise NotImplementedError(f'Operator "Conv" not implemented') + # FIXME: ggml can only work with F16 + conv_result = ggml.ggml_conv_2d( + context, + x, + bias, + strides[0], + strides[1], + pads[0], + pads[1], + dilations[0], + dilations[1], + ) + + tensors_dict[node.output[0]] = conv_result + return conv_result + class DepthToSpaceUserData(ctypes.Structure): _fields_ = [ ("blocksize", ctypes.c_int), diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 7fa2cc90..8bce660c 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -279,6 +279,10 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_constantofshape") +# backend_test.include("_conv_") +# backend_test.exclude("_deform_conv") +# backend_test.exclude("test_operator_conv") + backend_test.include("test_operator_chunk") backend_test.include("test_depthtospace") From 34a9833eb3c7f3f64059868165539accb8727b1a Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 31 Aug 2023 13:47:03 -0400 Subject: [PATCH 146/232] Add partial implementation for ConvTranspose --- ggml/contrib/onnx.py | 113 ++++++++++++++++++++++++++++++++++++++++ tests/test_ggml_onnx.py | 5 ++ 2 files changed, 118 insertions(+) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index b68cafab..0f01c0b0 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -905,6 +905,7 @@ def ggml_operator_conv( if len(strides) != 2: raise NotImplementedError("Cannot handle other than 2 strides") + raise NotImplementedError(f'Operator "Conv" not implemented') # FIXME: ggml can only work with F16 conv_result = ggml.ggml_conv_2d( @@ -922,6 +923,118 @@ def ggml_operator_conv( tensors_dict[node.output[0]] = conv_result return conv_result + +@ggml_operator("ConvTranspose") +def ggml_operator_convtranspose( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 2: + raise ValueError( + f'Error for node "{node.name}": Operation "ConvTranspose" requires 2 - 3 inputs. Actual number of inputs: {len(node_inputs)}' + ) + + node_inputs_iter = iter(node_inputs) + x = next(node_inputs_iter) + x_shape = get_tensor_shape(x) + w = next(node_inputs_iter) + w_shape = get_tensor_shape(w) + m = w_shape[0] + bias = next( + node_inputs_iter, + ggml.utils.from_numpy(np.full(m, 0, dtype=get_tensor_dtype(x)), context), + ) + + auto_pad = next( + (attr.s.decode() for attr in node.attribute if attr.name == "auto_pad"), + "NOTSET", + ) + dilations = next( + (attr.ints for attr in node.attribute if attr.name == "dilations"), + [1 for _ in x_shape[2:]], + ) + group = next((attr.i for attr in node.attribute if attr.name == "group"), 1) + kernel_shape = next( + (attr.ints for attr in node.attribute if attr.name == "kernel_shape"), + w_shape[2:], + ) + output_padding = next( + (attr.ints for attr in node.attribute if attr.name == "output_padding"), + [0 for _ in x_shape[2:]] * 2, + ) + output_shape = next( + (attr.ints for attr in node.attribute if attr.name == "output_shape"), + None, + ) + pads = next( + (attr.ints for attr in node.attribute if attr.name == "pads"), + None, + ) + strides = next( + (attr.ints for attr in node.attribute if attr.name == "strides"), + [1 for _ in x_shape[2:]], + ) + + # https://github.com/onnx/onnx/blob/main/onnx/reference/ops/op_conv_transpose.py + + if pads is None and auto_pad not in {"SAME_UPPER", "SAME_LOWER"}: + pads = [0 for i in range(2 * len(strides))] + if pads is None: + if output_shape is None: + output_shape = [x_shape[i + 2] * strides[i] for i in range(len(strides))] + total_padding = [ + strides[i] * (x_shape[i + 2] - 1) + + output_padding[i] + + ((kernel_shape[i] - 1) * dilations[i] + 1) + - output_shape[i] + for i in range(len(output_shape)) + ] + pads_1 = [] + pads_2 = [] + for i in range(len(output_shape)): + if auto_pad == "SAME_UPPER": + pads_1.append(total_padding[i] // 2) + pads_2.append(total_padding[i] - (total_padding[i] // 2)) + else: + pads_1.append(total_padding[i] - (total_padding[i] // 2)) + pads_2.append(total_padding[i] // 2) + pads = pads_1 + pads_2 + n_dims = len(pads) // 2 + else: + n_dims = len(x_shape) - 2 + new_pads = np.array([(pads[i], pads[i + n_dims]) for i in range(n_dims)]) + if output_shape is None: + output_shape = [ + strides[i] * (x_shape[i + 2] - 1) + + output_padding[i] + + ((kernel_shape[i] - 1) * dilations[i] + 1) + - new_pads[i, :].sum() + for i in range(n_dims) + ] + + kernel_shape = w_shape[2:] + kernel_size = np.prod(kernel_shape) + num_output_channels = w_shape[1] * group + kernel_dim = num_output_channels // group * kernel_size + + C = x_shape[1] # num_inputs_channels + m = kernel_dim # kernel_dim + n = np.prod(x_shape[2:]) # input_image_size + k = C // group + + if group != 1: + raise NotImplementedError( + f'Error for node "{node.name}": Implementation for group={group} > 1 is not available yet.' + ) + + raise NotImplementedError(f'Operator "ConvTranspose" not implemented') + + class DepthToSpaceUserData(ctypes.Structure): _fields_ = [ ("blocksize", ctypes.c_int), diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 8bce660c..b570d8b3 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -283,6 +283,11 @@ def test_ggml_onnx_runtime_quantized(): # backend_test.exclude("_deform_conv") # backend_test.exclude("test_operator_conv") + +# backend_test.include("_convtranspose_") +# backend_test.exclude("_deform_convtranspose") +# backend_test.exclude("test_operator_convtranspose") + backend_test.include("test_operator_chunk") backend_test.include("test_depthtospace") From 65e431ddfda628eae395c149ea66958bdd514c24 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 31 Aug 2023 15:06:45 -0400 Subject: [PATCH 147/232] Update onnx.md --- docs/contrib/onnx.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/contrib/onnx.md b/docs/contrib/onnx.md index b01845a8..4cbc71a2 100644 --- a/docs/contrib/onnx.md +++ b/docs/contrib/onnx.md @@ -58,11 +58,11 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Concat](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Concat) | :white_check_mark: | `ggml_concat` | | [Constant](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Constant) | :white_check_mark: | | | [ConstantOfShape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConstantOfShape) | :white_check_mark: | | -| [Conv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv) | | | -| [ConvTranspose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConvTranspose) | | | +| [Conv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv) | ⚙️ (in progress) | | +| [ConvTranspose](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConvTranspose) | ⚙️ (in progress) | | | [DepthToSpace](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DepthToSpace) | :white_check_mark: | | | [Div](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Div) | :white_check_mark: | `ggml_div` | -| [Dropout](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Dropout) -> [code ref](https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/dropout.py) | | | +| [Dropout](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Dropout) | ⚙️ (in progress) | | | [Elu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Elu) | :white_check_mark: | `ggml_elu` | | [Equal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Equal) | :white_check_mark: | | | [Exp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Exp) | :white_check_mark: | | From 8914ac27b8b361bf3119fe1f529d5adc0b4bc533 Mon Sep 17 00:00:00 2001 From: Mohammadreza Anvari Date: Thu, 31 Aug 2023 16:07:15 -0400 Subject: [PATCH 148/232] Add partial implementation for Dropout operator --- ggml/contrib/onnx.py | 133 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 0f01c0b0..6b70626c 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1164,6 +1164,139 @@ def ggml_operator_div( tensors_dict[output_name] = div_result return div_result +class DropoutUserData(ctypes.Structure): + _fields_ = [ + ("seed", ctypes.c_int), + ("training_mode", ctypes.c_bool), + ] + + +@ggml.ggml_custom2_op_t +def custom_dropout_mask( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_1) + ratio = ggml.utils.to_numpy(tensor_in_2) + + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DropoutUserData)) + userdata_data = userdata_data_ptr.contents + + seed = userdata_data.seed + training_mode = userdata_data.training_mode + + if np.equal(0, np.array(ratio)) or training_mode is False: + mask = np.ones(x.shape, dtype=np.int32) + + else: + np.random.seed(seed) + mask = np.random.uniform(0, 1.0, x.shape) >= ratio + + set_tensor_out(tensor_out, mask) + + +@ggml.ggml_custom3_op_t +def custom_dropout_output( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], +): + x = ggml.utils.to_numpy(tensor_in_1) + ratio = ggml.utils.to_numpy(tensor_in_2) + mask = ggml.utils.to_numpy(tensor_in_3) + + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DropoutUserData)) + userdata_data = userdata_data_ptr.contents + + training_mode = userdata_data.training_mode + + if np.equal(0, np.array(ratio)) or training_mode is False: + y = x + + else: + scale = 1 / (1 - ratio) + y = mask * x * scale + + set_tensor_out(tensor_out, y) + + +@ggml_operator("Dropout") +def ggml_operator_dropout( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + node_inputs = [tensors_dict[inp] for inp in node.input] + + if len(node_inputs) < 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Dropout" requires 1 - 3 inputs. Actual number of inputs: {len(node_inputs)}' + ) + + + # Ref = https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/dropout.py + + node_inputs_iter = iter(node_inputs) + + data = next(node_inputs_iter) + ratio = next( + node_inputs_iter, + next((attr.f for attr in node.attribute if attr.name == "ratio"), 0.5), + ) + training_mode = next(node_inputs_iter, np.bool_(False)) + + if type(ratio) is float: + ratio = ggml.utils.from_numpy(np.array([ratio]).astype(np.float32), context) + + seed = next((attr.i for attr in node.attribute if attr.name == "seed"), 6) + + if type(training_mode) is ggml.ggml_tensor_p: + training_mode_eval = backend.eval_tensor(training_mode, context) + training_mode = ggml.utils.to_numpy(training_mode_eval) + + droput_userdata = DropoutUserData(seed, bool(training_mode)) + userdata_p = ctypes.cast(ctypes.pointer(droput_userdata), ctypes.c_void_p) + + mask = ggml.ggml_map_custom2_inplace( + context, + data, + ratio, + custom_dropout_mask, + 1, + userdata_p, + ) + + output = ggml.ggml_map_custom3_inplace( + context, + data, + ratio, + mask, + custom_dropout_output, + 1, + userdata_p, + ) + + refs.append(droput_userdata) + + if len(node.output) == 2: + ggml.ggml_set_name(mask, (node.output[1] + f"").encode()) + tensors_dict[node.output[0]] = output + tensors_dict[node.output[1]] = mask + + return output, mask + + tensors_dict[node.output[0]] = output + return output @ggml_operator("Elu") def ggml_operator_elu( From fe8818c685a867a4ea7d77385ae1d91efc12a541 Mon Sep 17 00:00:00 2001 From: David Miller Date: Fri, 1 Sep 2023 13:35:23 -0700 Subject: [PATCH 149/232] WIP --- examples/replit/main.py | 1 + ggml/__init__.py | 2 +- ggml/experimental.py | 7 ++++++- ggml/ggml.py | 14 ++++++++++++++ tests/test_experimental.py | 1 + tests/test_utils.py | 7 ++----- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/examples/replit/main.py b/examples/replit/main.py index 6e50af7e..da770363 100644 --- a/examples/replit/main.py +++ b/examples/replit/main.py @@ -38,6 +38,7 @@ class ReplitAbortException(Exception): pass + ## Generic Sampling Functions diff --git a/ggml/__init__.py b/ggml/__init__.py index 700a12fe..7a4f5cc2 100644 --- a/ggml/__init__.py +++ b/ggml/__init__.py @@ -1 +1 @@ -from .ggml import * \ No newline at end of file +from .ggml import * diff --git a/ggml/experimental.py b/ggml/experimental.py index b1f40a09..48697d89 100644 --- a/ggml/experimental.py +++ b/ggml/experimental.py @@ -130,7 +130,12 @@ def __len__(self): return self.nelements() @classmethod - def with_buffer(cls, tensor: ggml.ggml_tensor_p, ctx: Optional[Context] = None, src: Optional[List[Tensor]] = None): + def with_buffer( + cls, + tensor: ggml.ggml_tensor_p, + ctx: Optional[Context] = None, + src: Optional[List[Tensor]] = None, + ): src = src or [] if tensor.contents.data is not None: return cls(tensor=tensor, ctx=ctx, src=src) diff --git a/ggml/ggml.py b/ggml/ggml.py index 529f47ba..6c65bcaa 100644 --- a/ggml/ggml.py +++ b/ggml/ggml.py @@ -6490,6 +6490,7 @@ def gguf_get_val_f32( ] lib.gguf_get_val_f32.restype = ctypes.c_float + # GGML_API uint64_t gguf_get_val_u64 (struct gguf_context * ctx, int i); def gguf_get_val_u64( ctx: gguf_context_p, @@ -6504,6 +6505,7 @@ def gguf_get_val_u64( ] lib.gguf_get_val_u64.restype = ctypes.c_uint64 + # GGML_API int64_t gguf_get_val_i64 (struct gguf_context * ctx, int i); def gguf_get_val_i64( ctx: gguf_context_p, @@ -6518,6 +6520,7 @@ def gguf_get_val_i64( ] lib.gguf_get_val_i64.restype = ctypes.c_int64 + # GGML_API double gguf_get_val_f64 (struct gguf_context * ctx, int i); def gguf_get_val_f64( ctx: gguf_context_p, @@ -6532,6 +6535,7 @@ def gguf_get_val_f64( ] lib.gguf_get_val_f64.restype = ctypes.c_double + # GGML_API bool gguf_get_val_bool(struct gguf_context * ctx, int i); def gguf_get_val_bool( ctx: gguf_context_p, @@ -6786,6 +6790,7 @@ def gguf_set_val_f32( ] lib.gguf_set_val_f32.restype = None + # GGML_API void gguf_set_val_u64 (struct gguf_context * ctx, const char * key, uint64_t val); def gguf_set_val_u64( ctx: gguf_context_p, @@ -6802,6 +6807,7 @@ def gguf_set_val_u64( ] lib.gguf_set_val_u64.restype = None + # GGML_API void gguf_set_val_i64 (struct gguf_context * ctx, const char * key, int64_t val); def gguf_set_val_i64( ctx: gguf_context_p, @@ -6818,6 +6824,7 @@ def gguf_set_val_i64( ] lib.gguf_set_val_i64.restype = None + # GGML_API void gguf_set_val_f64 (struct gguf_context * ctx, const char * key, double val); def gguf_set_val_f64( ctx: gguf_context_p, @@ -6834,6 +6841,7 @@ def gguf_set_val_f64( ] lib.gguf_set_val_f64.restype = None + # GGML_API void gguf_set_val_bool(struct gguf_context * ctx, const char * key, bool val); def gguf_set_val_bool( ctx: gguf_context_p, @@ -7189,6 +7197,7 @@ def ggml_cpu_has_sse3() -> int: lib.ggml_cpu_has_sse3.argtypes = [] lib.ggml_cpu_has_sse3.restype = ctypes.c_int + # GGML_API int ggml_cpu_has_ssse3 (void); def ggml_cpu_has_ssse3() -> int: return lib.ggml_cpu_has_ssse3() @@ -7516,18 +7525,21 @@ def ggml_cuda_assign_buffers_force_inplace( ] lib.ggml_cuda_assign_buffers_force_inplace.restype = None + # GGML_API void ggml_cuda_assign_buffers_no_alloc(struct ggml_tensor * tensor); def ggml_cuda_assign_buffers_no_alloc( tensor: ggml_tensor_p, ): return lib.ggml_cuda_assign_buffers_no_alloc(tensor) + if GGML_USE_CUBLAS: lib.ggml_cuda_assign_buffers_no_alloc.argtypes = [ ctypes.POINTER(ggml_tensor), ] lib.ggml_cuda_assign_buffers_no_alloc.restype = None + # GGML_API void ggml_cuda_assign_scratch_offset(struct ggml_tensor * tensor, size_t offset); def ggml_cuda_assign_scratch_offset( tensor: ggml_tensor_p, @@ -7535,6 +7547,7 @@ def ggml_cuda_assign_scratch_offset( ): return lib.ggml_cuda_assign_scratch_offset(tensor, offset) + if GGML_USE_CUBLAS: lib.ggml_cuda_assign_scratch_offset.argtypes = [ ctypes.POINTER(ggml_tensor), @@ -7542,6 +7555,7 @@ def ggml_cuda_assign_scratch_offset( ] lib.ggml_cuda_assign_scratch_offset.restype = None + # void ggml_cuda_set_main_device(int main_device); def ggml_cuda_set_main_device( main_device: Union[ctypes.c_int, int], diff --git a/tests/test_experimental.py b/tests/test_experimental.py index e3f42e3d..1623df04 100644 --- a/tests/test_experimental.py +++ b/tests/test_experimental.py @@ -10,6 +10,7 @@ def test_tensor(): assert t.ggml_type == GGML_TYPE.F32 assert np.allclose(t.numpy(), x) + def test_tensor_compute(): x = Tensor.from_numpy(np.array([2.0], dtype=np.float32)) a = Tensor.from_numpy(np.array([3.0], dtype=np.float32)) diff --git a/tests/test_utils.py b/tests/test_utils.py index ff585f73..fd449190 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -59,9 +59,6 @@ def test_slice_tensor(): with ggml.utils.ggml_context_manager(params) as ctx: x = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32) t = ggml.utils.from_numpy(x, ctx) - t_slice = ggml.utils.slice_tensor(ctx, t, [ - slice(0, 2), - slice(0, 1) - ]) + t_slice = ggml.utils.slice_tensor(ctx, t, [slice(0, 2), slice(0, 1)]) x_slice = ggml.utils.to_numpy(t_slice) - assert np.array_equal(x_slice, x[:1, :2]) \ No newline at end of file + assert np.array_equal(x_slice, x[:1, :2]) From 1626fdf4d6fd222951d60b912cb11c87d81c4ea4 Mon Sep 17 00:00:00 2001 From: David Miller Date: Fri, 1 Sep 2023 13:35:35 -0700 Subject: [PATCH 150/232] pad operator --- ggml/contrib/onnx.py | 89 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 0a401424..4099c470 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -2373,6 +2373,95 @@ def ggml_operator_or( return new_tensor +@ggml_operator("Pad") +def ggml_operator_pad( + backend: "GgmlBackendRep", + node: NodeProto, + tensors_dict: Dict[str, ggml.ggml_tensor_p], + context: ggml.ggml_context_p, + refs: List[Any], +): + # x, pads, value, axes + if len(tensors_dict) < 2: + raise ValueError( + f'Error for node "{node.name}": Operation "Pad" requires at least two inputs. Actual number of inputs: {len(node_inputs)}' + ) + input_rank = tensors_dict["x"].contents.n_dims + mode = next( + (attr.s for attr in node.attribute if attr.name == "mode"), b"constant" + ).decode("utf-8") + + if "axes" not in tensors_dict: + axes = list(range(input_rank)) + else: + # axes_eval = backend.eval_tensor(tensors_dict["axes"], context) + # axes = ggml.utils.to_numpy(axes_eval) + axes = ggml.utils.to_numpy(tensors_dict["axes"]) + axes = [axis if axis >= 0 else axis + input_rank for axis in axes] + num_axes = len(axes) + pad_width = [] + for _ in range(input_rank): + pad_width += [[0, 0]] # init to zero + + # raw_pads = ggml.utils.to_numpy(backend.eval_tensor(tensors_dict["pads"], context)) + raw_pads = ggml.utils.to_numpy(tensors_dict["pads"]) + + # re-order to np.pad accepted order ((x1_begin, x1_end), (x2_begin, x2_end), ...) + for i in range(num_axes): + axis = axes[i] + if axis < 0: + axis = input_rank + axis + pad_width[axis] = [raw_pads[i], raw_pads[i + num_axes]] + + expand_by = [sum(pad) for pad in pad_width] + prev_shape = get_tensor_shape(tensors_dict["x"]) + output_shape = [sum(x) for x in zip(prev_shape, expand_by)] + a_dtype = get_tensor_dtype(tensors_dict["x"]) + x = np.empty(output_shape, dtype=a_dtype) + x_t = ggml.utils.from_numpy(x, context) + + constant_value = None + if "value" in tensors_dict: + # constant_value = ggml.utils.to_numpy(backend.eval_tensor(tensors_dict["value"], context)) + constant_values = ggml.utils.to_numpy(tensors_dict["value"]) + + @ggml.ggml_custom2_op_t + def custom_pad( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) + if mode == "constant": + x = np.pad( + a, + pad_width=pad_width, + mode=mode, + constant_values=constant_values, + ) + + else: + x = np.pad( + a, + pad_width=pad_width, + mode=mode, + ) + set_tensor_out(tensor_out, x) + + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + context, + x_t, + x, + custom_pad, + 1, + None, + ) + return new_tensor + + @ggml.ggml_custom2_op_t def custom_leaky_prelu( tensor_out: ggml.ggml_tensor_p, From c19a2207397ed601fa04361ee4b1ba9ffafe6cd1 Mon Sep 17 00:00:00 2001 From: David Miller Date: Fri, 1 Sep 2023 15:10:29 -0700 Subject: [PATCH 151/232] Fix pad operator --- ggml/contrib/onnx.py | 24 ++++++++++++++---------- tests/test_ggml_onnx.py | 1 - 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 12246624..4f7a0df5 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -905,7 +905,6 @@ def ggml_operator_conv( if len(strides) != 2: raise NotImplementedError("Cannot handle other than 2 strides") - raise NotImplementedError(f'Operator "Conv" not implemented') # FIXME: ggml can only work with F16 conv_result = ggml.ggml_conv_2d( @@ -1164,6 +1163,7 @@ def ggml_operator_div( tensors_dict[output_name] = div_result return div_result + class DropoutUserData(ctypes.Structure): _fields_ = [ ("seed", ctypes.c_int), @@ -1243,7 +1243,6 @@ def ggml_operator_dropout( f'Error for node "{node.name}": Operation "Dropout" requires 1 - 3 inputs. Actual number of inputs: {len(node_inputs)}' ) - # Ref = https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/dropout.py node_inputs_iter = iter(node_inputs) @@ -1298,6 +1297,7 @@ def ggml_operator_dropout( tensors_dict[node.output[0]] = output return output + @ggml_operator("Elu") def ggml_operator_elu( backend: "GgmlBackendRep", @@ -2726,17 +2726,15 @@ def ggml_operator_pad( if "axes" not in tensors_dict: axes = list(range(input_rank)) else: - # axes_eval = backend.eval_tensor(tensors_dict["axes"], context) - # axes = ggml.utils.to_numpy(axes_eval) - axes = ggml.utils.to_numpy(tensors_dict["axes"]) + axes_eval = backend.eval_tensor(tensors_dict["axes"], context) + axes = ggml.utils.to_numpy(axes_eval) axes = [axis if axis >= 0 else axis + input_rank for axis in axes] num_axes = len(axes) pad_width = [] for _ in range(input_rank): pad_width += [[0, 0]] # init to zero - # raw_pads = ggml.utils.to_numpy(backend.eval_tensor(tensors_dict["pads"], context)) - raw_pads = ggml.utils.to_numpy(tensors_dict["pads"]) + raw_pads = ggml.utils.to_numpy(backend.eval_tensor(tensors_dict["pads"], context)) # re-order to np.pad accepted order ((x1_begin, x1_end), (x2_begin, x2_end), ...) for i in range(num_axes): @@ -2754,8 +2752,9 @@ def ggml_operator_pad( constant_value = None if "value" in tensors_dict: - # constant_value = ggml.utils.to_numpy(backend.eval_tensor(tensors_dict["value"], context)) - constant_values = ggml.utils.to_numpy(tensors_dict["value"]) + constant_values = ggml.utils.to_numpy( + backend.eval_tensor(tensors_dict["value"], context) + ) @ggml.ggml_custom2_op_t def custom_pad( @@ -2786,11 +2785,12 @@ def custom_pad( new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( context, x_t, - x, + tensors_dict["x"], custom_pad, 1, None, ) + refs.append(custom_pad) return new_tensor @@ -5200,6 +5200,10 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml_type = map_to_ggml_type(input_data.dtype) shape = tuple(reversed(input_data.shape)) + # Handle scalars + if len(shape) == 0: + shape = (1,) + tensor = ggml.ggml_new_tensor( context, ggml_type.value, diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index b570d8b3..6e6b5e78 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -275,7 +275,6 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_operator_concat") backend_test.include("test_constant_") -backend_test.exclude(".*constant.*.*pad.*") backend_test.include("test_constantofshape") From 4145cb6e86f6f8c871513f5b7be671955ecad7b4 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sat, 2 Sep 2023 11:33:51 -0400 Subject: [PATCH 152/232] Add debug build and test --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index f1cfea40..272eaf31 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,9 @@ update-pip: build: ${submodules} update-pip python3 -m pip install --verbose --editable . +build.debug: ${submodules} update-pip + CMAKE_ARGS="-DCMAKE_BUILD_TYPE=Debug" python3 -m pip install --verbose --editable . + build.openblas: ${submodules} update-pip CMAKE_ARGS="-DGGML_OPENBLAS=On" python3 -m pip install --verbose --editable . @@ -29,6 +32,9 @@ deploy: test: python3 -m pytest +test.gdb: + gdb -ex r -ex "thread apply all bt" --args python -m pytest -s -vvvv + clean: - rm -rf _skbuild - rm -rf dist From 194cba693877bb98a31d7deff35bdbe2a6f64ca6 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sun, 3 Sep 2023 19:38:06 -0400 Subject: [PATCH 153/232] Avoid stripping debug info for debug builds --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 272eaf31..8a5feaba 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ build: ${submodules} update-pip python3 -m pip install --verbose --editable . build.debug: ${submodules} update-pip - CMAKE_ARGS="-DCMAKE_BUILD_TYPE=Debug" python3 -m pip install --verbose --editable . + CMAKE_ARGS="-DCMAKE_BUILD_TYPE=Debug" python3 -m pip install --verbose --config-settings=cmake.verbose=true --config-settings=logging.level=INFO --config-settings=install.strip=false --editable . build.openblas: ${submodules} update-pip CMAKE_ARGS="-DGGML_OPENBLAS=On" python3 -m pip install --verbose --editable . @@ -36,7 +36,7 @@ test.gdb: gdb -ex r -ex "thread apply all bt" --args python -m pytest -s -vvvv clean: - - rm -rf _skbuild + - rm -rf build - rm -rf dist - rm ggml/*.so - rm ggml/*.dll From aa31b5204e2f9eb4aed491cc8cfedcba32b88013 Mon Sep 17 00:00:00 2001 From: David Miller Date: Thu, 7 Sep 2023 16:19:07 -0700 Subject: [PATCH 154/232] Reshape scalar numpy values to shape = (1,) --- ggml/contrib/onnx.py | 24 +++++++----------------- ggml/utils.py | 3 +++ 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 1ffc9dd2..f382a60c 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -726,22 +726,9 @@ def ggml_operator_constant( ) tensor_shape = data_value.shape - x = np.empty(tensor_shape, dtype=np_data_type_limit) - x_t = None - - if tensor_shape == (): - ggml_type = map_to_ggml_type(np_data_type_limit) - - x_t = ggml.ggml_new_tensor( - context, - ggml_type.value, - len(tensor_shape), - (ctypes.c_int64 * len(tensor_shape))(*tensor_shape), - ) - - else: - x_t = ggml.utils.from_numpy(x, context) + + x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( context, @@ -2803,6 +2790,8 @@ def custom_leaky_prelu( nth: int, userdata: Optional[ctypes.c_void_p], ): + + x = ggml.utils.to_numpy(tensor_in_1) slope = ggml.utils.to_numpy(tensor_in_2) @@ -2825,8 +2814,8 @@ def ggml_operator_leaky_relu( raise ValueError( f'Error for node "{node.name}": Operation "PRelu" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - x, slope = node_inputs + new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( context, x, @@ -4205,7 +4194,8 @@ def ggml_operator_size( tensor_size_t = ggml.utils.from_numpy(np.array([tensor_size_np]), context) ggml_type = map_to_ggml_type(tensor_size_np.dtype).value - x_t = ggml.ggml_new_tensor(context, ggml_type, 0, (ctypes.c_int64 * 0)(*())) + x = np.empty(tensor_shape, dtype=tensor_size_np.dtype) + x_t = ggml.utils.from_numpy(x, context) new_tensor = tensors_dict[name] = ggml.ggml_map_custom2_inplace( context, diff --git a/ggml/utils.py b/ggml/utils.py index e28fa068..f4a2300f 100644 --- a/ggml/utils.py +++ b/ggml/utils.py @@ -77,6 +77,9 @@ def from_numpy(x: npt.NDArray[Any], ctx: ggml.ggml_context_p) -> ggml.ggml_tenso if x.dtype.type == np.bool_: x = x.astype(np.int32) + if x.shape == (): + x = x.reshape((1,)) + ggml_type = NUMPY_DTYPE_TO_GGML_TYPE[x.dtype.type] shape = tuple(reversed(x.shape)) tensor = ggml.ggml_new_tensor( From b0479d3e64fb478f3dd387bca767e28227f19f17 Mon Sep 17 00:00:00 2001 From: David Miller Date: Mon, 11 Sep 2023 17:14:06 -0700 Subject: [PATCH 155/232] Return empty numpy array if tensor data->NULL --- ggml/utils.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ggml/utils.py b/ggml/utils.py index f4a2300f..ca20a4e9 100644 --- a/ggml/utils.py +++ b/ggml/utils.py @@ -48,14 +48,19 @@ def to_numpy( Returns: Numpy array with a view of data from tensor """ + data = ggml.ggml_get_data(tensor) + if data is None: + return np.array([]) + ggml_type = GGML_TYPE(tensor.contents.type) if ggml_type == GGML_TYPE.F16: ctypes_type = ctypes.c_uint16 else: ctypes_type = np.ctypeslib.as_ctypes_type(GGML_TYPE_TO_NUMPY_DTYPE[ggml_type]) - array = ctypes.cast(ggml.ggml_get_data(tensor), ctypes.POINTER(ctypes_type)) + array = ctypes.cast(data, ctypes.POINTER(ctypes_type)) shape = tuple(reversed(tensor.contents.ne[: tensor.contents.n_dims])) + output = np.ctypeslib.as_array(array, shape=shape) if ggml_type == GGML_TYPE.F16: output.dtype = np.float16 From ebfbc9de2c6b11ebcb5987819ba9339504f27b7a Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 13 Sep 2023 03:45:49 -0400 Subject: [PATCH 156/232] Allocate input context seperately --- ggml/contrib/onnx.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index f382a60c..54fe6267 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5152,11 +5152,11 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: exit_node = None ggml_tensors = self.weights - # Define context - params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) - - refs: List[Any] = [] + input_context = ggml.ggml_init(params=ggml.ggml_init_params( + mem_size=2 * ggml.GGML_MAX_NODES * ggml.ggml_tensor_overhead(), # FIXME: Reduce to n inputs or combine with tensors context + no_alloc=True, + )) + input_buffer_size = 0 # Create entry inputs for model_input in model_graph.input: @@ -5195,17 +5195,31 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: shape = (1,) tensor = ggml.ggml_new_tensor( - context, + input_context, ggml_type.value, len(shape), (ctypes.c_int64 * len(shape))(*shape), ) + input_buffer_size += ggml.ggml_nbytes_pad(tensor) ggml_tensors[input_name] = tensor + + input_buffer = (ctypes.c_uint8 * input_buffer_size)() + input_buffer_offset = 0 # Set user inputs for key, value in inputs.items(): - set_tensor_out(ggml_tensors[key], np.array(value)) + tensor = ggml_tensors[key] + tensor.contents.data = ctypes.cast( + ctypes.addressof(input_buffer) + input_buffer_offset, ctypes.c_void_p + ) + input_buffer_offset += ggml.ggml_nbytes_pad(tensor) + set_tensor_out(tensor, np.array(value)) + + # Define context + context = ggml.ggml_init(params=ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None)) + + refs: List[Any] = [] gf = ggml.ggml_cgraph() gf_p = ctypes.pointer(gf) @@ -5244,6 +5258,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: graph_outputs.append(graph_output) ggml.ggml_free(context) + ggml.ggml_free(input_context) return graph_outputs From 15af1a292de5c11af63a166168fe7d3fa48350c1 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 13 Sep 2023 03:58:04 -0400 Subject: [PATCH 157/232] use graph plan to compute graph --- ggml/contrib/onnx.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 54fe6267..660cd959 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5136,7 +5136,11 @@ def __del__(self): def eval_tensor(self, tensor: ggml.ggml_tensor_p, context: ggml.ggml_context_p): gf = ggml.ggml_build_forward(tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + gp = ggml.ggml_graph_plan(ctypes.pointer(gf), 1) + work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size else None + if gp.work_size: + gp.work = ctypes.cast(ctypes.addressof(work_buffer), ctypes.c_void_p) + ggml.ggml_graph_compute(ctypes.byref(gf), ctypes.byref(gp)) return tensor @@ -5244,7 +5248,11 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) # Compute graph - ggml.ggml_graph_compute_with_ctx(context, gf_p, 1) + gp = ggml.ggml_graph_plan(ctypes.pointer(gf), 1) + work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size else None + if gp.work_size: + gp.work = ctypes.cast(ctypes.addressof(work_buffer), ctypes.c_void_p) + ggml.ggml_graph_compute(gf_p, ctypes.byref(gp)) graph_outputs = [] for output in self.outputs: From 06067bfb0fca7ce8671b5a2ffc1b3b5126794f9e Mon Sep 17 00:00:00 2001 From: David Miller Date: Fri, 15 Sep 2023 17:54:24 -0700 Subject: [PATCH 158/232] Refactor graph context into class --- ggml/contrib/onnx.py | 1491 +++++++++++++++--------------------------- 1 file changed, 520 insertions(+), 971 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index f382a60c..35d2ea46 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -158,14 +158,8 @@ def get_final_dtype(tensor: ggml.ggml_tensor_p, pattern: str = r"<(.*?)>"): @ggml_operator("Abs") -def ggml_operator_abs( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_abs(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -176,22 +170,16 @@ def ggml_operator_abs( a = node_inputs[0] abs_result = ggml.ggml_abs( - context, + ctx.ggml_context, a, ) - tensors_dict[output_name] = abs_result + ctx.tensors_dict[output_name] = abs_result return abs_result @ggml_operator("Add") -def ggml_operator_add( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -201,14 +189,14 @@ def ggml_operator_add( output_name = node.output[0] a, b = node_inputs - a, b = broadcast_shapes(context, a, b) + a, b = broadcast_shapes(ctx.ggml_context, a, b) add_result = ggml.ggml_add( - context, + ctx.ggml_context, a, b, ) - tensors_dict[output_name] = add_result + ctx.tensors_dict[output_name] = add_result return add_result @@ -231,14 +219,8 @@ def custom_and( @ggml_operator("And") -def ggml_operator_and( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_and(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -253,10 +235,10 @@ def ggml_operator_and( output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, node_inputs[0], node_inputs[1], @@ -312,14 +294,8 @@ def custom_arg_max( @ggml_operator("ArgMax") -def ggml_operator_arg_max( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -354,13 +330,13 @@ def ggml_operator_arg_max( dummy_result = dummy_result.astype(np.int32) - x_t = ggml.utils.from_numpy(dummy_result, context) + x_t = ggml.utils.from_numpy(dummy_result, ctx.ggml_context) argmax_userdata = ArgOpsUserData(axis, keepdims, select_last_index) userdata_p = ctypes.cast(ctypes.pointer(argmax_userdata), ctypes.c_void_p) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, data, custom_arg_max, @@ -369,7 +345,7 @@ def ggml_operator_arg_max( ) ggml.ggml_set_name(new_tensor, (name + "").encode()) - refs.append(argmax_userdata) + ctx.refs.append(argmax_userdata) return new_tensor @@ -408,14 +384,8 @@ def custom_arg_min( @ggml_operator("ArgMin") -def ggml_operator_arg_max( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -448,13 +418,13 @@ def ggml_operator_arg_max( dummy_result = dummy_result.astype(np.int32) - x_t = ggml.utils.from_numpy(dummy_result, context) + x_t = ggml.utils.from_numpy(dummy_result, ctx.ggml_context) argmax_userdata = ArgOpsUserData(axis, keepdims, select_last_index) userdata_p = ctypes.cast(ctypes.pointer(argmax_userdata), ctypes.c_void_p) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, data, custom_arg_min, @@ -463,7 +433,7 @@ def ggml_operator_arg_max( ) ggml.ggml_set_name(new_tensor, (name + "").encode()) - refs.append(argmax_userdata) + ctx.refs.append(argmax_userdata) return new_tensor @@ -486,14 +456,8 @@ def custom_cast( @ggml_operator("Cast") -def ggml_operator_cast( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_cast(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -508,10 +472,10 @@ def ggml_operator_cast( np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) x = np.empty(get_tensor_shape(a), dtype=np_data_type_limit) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, a, custom_cast, @@ -519,20 +483,14 @@ def ggml_operator_cast( ctypes.pointer(onnx_type_c), ) - refs.append(onnx_type_c) + ctx.refs.append(onnx_type_c) return new_tensor @ggml_operator("CastLike") -def ggml_operator_castlike( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_castlike(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -547,10 +505,10 @@ def ggml_operator_castlike( onnx_type_c = ctypes.c_int(onnx_type) x = np.empty(get_tensor_shape(a), dtype=np_data_type_limit) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, a, custom_cast, @@ -558,20 +516,14 @@ def ggml_operator_castlike( ctypes.pointer(onnx_type_c), ) - refs.append(onnx_type_c) + ctx.refs.append(onnx_type_c) return new_tensor @ggml_operator("Ceil") -def ggml_operator_exp( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -581,7 +533,7 @@ def ggml_operator_exp( np_dtype = get_tensor_dtype(a) x = np.empty(get_tensor_shape(a), dtype=np_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) @ggml.ggml_custom1_op_t def custom_ceil( @@ -595,28 +547,22 @@ def custom_ceil( x = np.ceil(tensor) set_tensor_out(tensor_out, np.array(x)) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x_t, custom_ceil, 1, None, ) - refs.append(custom_ceil) + ctx.refs.append(custom_ceil) return new_tensor @ggml_operator("Concat") -def ggml_operator_concat( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 2: raise ValueError( @@ -639,7 +585,7 @@ def ggml_operator_concat( output_shape[axis] = total_dim x = np.empty(output_shape, dtype=get_tensor_dtype(node_inputs[0])) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) @ggml.ggml_custom1_op_t def custom_concat( @@ -654,15 +600,15 @@ def custom_concat( set_tensor_out(tensor_out, x) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x_t, custom_concat, 1, None, ) - refs.append(custom_concat) + ctx.refs.append(custom_concat) return new_tensor @@ -684,13 +630,7 @@ def custom_constant( @ggml_operator("Constant") -def ggml_operator_constant( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): +def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_attributes = node.attribute name = node.output[0] @@ -722,16 +662,16 @@ def ggml_operator_constant( data_tensor = ggml.utils.from_numpy( data_value.astype(np_data_type_limit), - context, + ctx.ggml_context, ) tensor_shape = data_value.shape x = np.empty(tensor_shape, dtype=np_data_type_limit) - - x_t = ggml.utils.from_numpy(x, context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, data_tensor, custom_constant, @@ -760,14 +700,8 @@ def custom_constant_of_shape( @ggml_operator("ConstantOfShape") -def ggml_operator_constant_of_shape( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -803,16 +737,16 @@ def ggml_operator_constant_of_shape( data_tensor = ggml.utils.from_numpy( data_value.astype(np_data_type_limit), - context, + ctx.ggml_context, ) shape = ggml.utils.to_numpy(node_inputs[0]) x = np.empty(shape, dtype=np_data_type_limit) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, data_tensor, custom_constant_of_shape, @@ -824,14 +758,8 @@ def ggml_operator_constant_of_shape( @ggml_operator("Conv") -def ggml_operator_conv( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 2: raise ValueError( @@ -846,7 +774,9 @@ def ggml_operator_conv( m = w_shape[0] bias = next( node_inputs_iter, - ggml.utils.from_numpy(np.full(m, 0, dtype=get_tensor_dtype(x)), context), + ggml.utils.from_numpy( + np.full(m, 0, dtype=get_tensor_dtype(x)), ctx.ggml_context + ), ) auto_pad = next( @@ -895,7 +825,7 @@ def ggml_operator_conv( raise NotImplementedError(f'Operator "Conv" not implemented') # FIXME: ggml can only work with F16 conv_result = ggml.ggml_conv_2d( - context, + ctx.ggml_context, x, bias, strides[0], @@ -906,19 +836,13 @@ def ggml_operator_conv( dilations[1], ) - tensors_dict[node.output[0]] = conv_result + ctx.tensors_dict[node.output[0]] = conv_result return conv_result @ggml_operator("ConvTranspose") -def ggml_operator_convtranspose( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_convtranspose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 2: raise ValueError( @@ -933,7 +857,9 @@ def ggml_operator_convtranspose( m = w_shape[0] bias = next( node_inputs_iter, - ggml.utils.from_numpy(np.full(m, 0, dtype=get_tensor_dtype(x)), context), + ggml.utils.from_numpy( + np.full(m, 0, dtype=get_tensor_dtype(x)), ctx.ggml_context + ), ) auto_pad = next( @@ -1067,14 +993,8 @@ def custom_depth_to_space( @ggml_operator("DepthToSpace") -def ggml_operator_depth_to_space( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_depth_to_space(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1102,13 +1022,13 @@ def ggml_operator_depth_to_space( output_shape = (N, new_C, new_H, new_W) x_t = ggml.utils.from_numpy( - np.empty(output_shape, dtype=get_tensor_dtype(x)), context + np.empty(output_shape, dtype=get_tensor_dtype(x)), ctx.ggml_context ) depthtospace_userdata = DepthToSpaceUserData(blocksize, mode) userdata_p = ctypes.cast(ctypes.pointer(depthtospace_userdata), ctypes.c_void_p) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, x, custom_depth_to_space, @@ -1116,20 +1036,14 @@ def ggml_operator_depth_to_space( userdata_p, ) - refs.append(depthtospace_userdata) + ctx.refs.append(depthtospace_userdata) return new_tensor @ggml_operator("Div") -def ggml_operator_div( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_div(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -1140,14 +1054,14 @@ def ggml_operator_div( a = node_inputs[0] b = node_inputs[1] - a, b = broadcast_shapes(context, a, b) + a, b = broadcast_shapes(ctx.ggml_context, a, b) div_result = ggml.ggml_div( - context, + ctx.ggml_context, a, b, ) - tensors_dict[output_name] = div_result + ctx.tensors_dict[output_name] = div_result return div_result @@ -1216,14 +1130,8 @@ def custom_dropout_output( @ggml_operator("Dropout") -def ggml_operator_dropout( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -1242,19 +1150,21 @@ def ggml_operator_dropout( training_mode = next(node_inputs_iter, np.bool_(False)) if type(ratio) is float: - ratio = ggml.utils.from_numpy(np.array([ratio]).astype(np.float32), context) + ratio = ggml.utils.from_numpy( + np.array([ratio]).astype(np.float32), ctx.ggml_context + ) seed = next((attr.i for attr in node.attribute if attr.name == "seed"), 6) if type(training_mode) is ggml.ggml_tensor_p: - training_mode_eval = backend.eval_tensor(training_mode, context) + training_mode_eval = ctx.backend.eval_tensor(training_mode, ctx.ggml_context) training_mode = ggml.utils.to_numpy(training_mode_eval) droput_userdata = DropoutUserData(seed, bool(training_mode)) userdata_p = ctypes.cast(ctypes.pointer(droput_userdata), ctypes.c_void_p) mask = ggml.ggml_map_custom2_inplace( - context, + ctx.ggml_context, data, ratio, custom_dropout_mask, @@ -1263,7 +1173,7 @@ def ggml_operator_dropout( ) output = ggml.ggml_map_custom3_inplace( - context, + ctx.ggml_context, data, ratio, mask, @@ -1272,28 +1182,22 @@ def ggml_operator_dropout( userdata_p, ) - refs.append(droput_userdata) + ctx.refs.append(droput_userdata) if len(node.output) == 2: ggml.ggml_set_name(mask, (node.output[1] + f"").encode()) - tensors_dict[node.output[0]] = output - tensors_dict[node.output[1]] = mask + ctx.tensors_dict[node.output[0]] = output + ctx.tensors_dict[node.output[1]] = mask return output, mask - tensors_dict[node.output[0]] = output + ctx.tensors_dict[node.output[0]] = output return output @ggml_operator("Elu") -def ggml_operator_elu( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1305,18 +1209,18 @@ def ggml_operator_elu( alpha = next((attr.f for attr in node.attribute if attr.name == "alpha"), 1.0) Y = ggml.ggml_elu( - context, + ctx.ggml_context, x, ) if alpha != 1.0: - Y_eval = backend.eval_tensor(Y, context) + Y_eval = ctx.backend.eval_tensor(Y, ctx.ggml_context) Y_np = ggml.utils.to_numpy(Y_eval) Y_alpha = np.where(Y_np < 0, alpha * Y_np, Y_np) - Y = ggml.utils.from_numpy(Y_alpha, context) + Y = ggml.utils.from_numpy(Y_alpha, ctx.ggml_context) - tensors_dict[output_name] = Y + ctx.tensors_dict[output_name] = Y return Y @@ -1339,14 +1243,8 @@ def custom_equal( @ggml_operator("Equal") -def ggml_operator_equal( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -1361,10 +1259,10 @@ def ggml_operator_equal( output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, node_inputs[0], node_inputs[1], @@ -1379,14 +1277,8 @@ def ggml_operator_equal( @ggml_operator("Exp") -def ggml_operator_exp( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -1396,7 +1288,7 @@ def ggml_operator_exp( np_dtype = get_tensor_dtype(a) x = np.empty(get_tensor_shape(a), dtype=np_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) @ggml.ggml_custom1_op_t def custom_exp( @@ -1410,15 +1302,15 @@ def custom_exp( x = np.exp(tensor) set_tensor_out(tensor_out, np.array(x)) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x_t, custom_exp, 1, None, ) - refs.append(custom_exp) + ctx.refs.append(custom_exp) return new_tensor @@ -1445,14 +1337,8 @@ def custom_flatten( @ggml_operator("Flatten") -def ggml_operator_flatten( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_flatten(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1472,12 +1358,12 @@ def ggml_operator_flatten( x_out = np.empty(x_shape, dtype=x_dtype) x_out = x_out.reshape(new_shape) - x_t = ggml.utils.from_numpy(x_out, context) + x_t = ggml.utils.from_numpy(x_out, ctx.ggml_context) axis_c = ctypes.c_int(axis) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, x, custom_flatten, @@ -1485,7 +1371,7 @@ def ggml_operator_flatten( ctypes.pointer(axis_c), ) - refs.append(axis_c) + ctx.refs.append(axis_c) return new_tensor @@ -1505,14 +1391,8 @@ def custom_floor( @ggml_operator("Floor") -def ggml_operator_floor( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1521,8 +1401,8 @@ def ggml_operator_floor( x = node_inputs[0] - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x, custom_floor, 1, @@ -1552,14 +1432,8 @@ def custom_gather( @ggml_operator("Gather") -def ggml_operator_gather( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_gather(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -1579,10 +1453,10 @@ def ggml_operator_gather( output_shape = tuple(list(Ni) + list(Nj) + list(Nk)) x = np.empty(output_shape, dtype=input_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, node_inputs[0], node_inputs[1], @@ -1591,20 +1465,14 @@ def ggml_operator_gather( ctypes.pointer(axis_c), ) - refs.append(axis_c) + ctx.refs.append(axis_c) return new_tensor @ggml_operator("Gemm") -def ggml_operator_gemm( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 2: raise ValueError( @@ -1636,15 +1504,15 @@ def ggml_operator_gemm( if transA: a_permute = ggml.ggml_transpose( - context, + ctx.ggml_context, a, ) a_shape = ggml.utils.get_shape(a_permute) a_transposed = ggml.ggml_cpy( - context, + ctx.ggml_context, a_permute, ggml.ggml_new_tensor( - context, + ctx.ggml_context, map_to_ggml_type(a_dtype).value, len(a_shape), (ctypes.c_int64 * len(a_shape))(*a_shape), @@ -1653,15 +1521,15 @@ def ggml_operator_gemm( if not transB: b_permute = ggml.ggml_transpose( - context, + ctx.ggml_context, b, ) b_shape = ggml.utils.get_shape(b_permute) b_transposed = ggml.ggml_cpy( - context, + ctx.ggml_context, b_permute, ggml.ggml_new_tensor( - context, + ctx.ggml_context, map_to_ggml_type(b_dtype).value, len(b_shape), (ctypes.c_int64 * len(b_shape))(*b_shape), @@ -1672,7 +1540,7 @@ def ggml_operator_gemm( # ref: https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/gemm.py mul_mat_result = ggml.ggml_mul_mat( - context, + ctx.ggml_context, b_transposed, a_transposed, ) @@ -1683,10 +1551,10 @@ def ggml_operator_gemm( alpha, dtype=get_tensor_dtype(mul_mat_result), ), - context, + ctx.ggml_context, ) - mul_mat_result = ggml.ggml_mul_inplace(context, mul_mat_result, alpha_t) + mul_mat_result = ggml.ggml_mul_inplace(ctx.ggml_context, mul_mat_result, alpha_t) if c is None: c = ggml.utils.from_numpy( @@ -1695,10 +1563,10 @@ def ggml_operator_gemm( 0, dtype=get_tensor_dtype(mul_mat_result), ), - context, + ctx.ggml_context, ) - c, mul_mat_result = broadcast_shapes(context, c, mul_mat_result) + c, mul_mat_result = broadcast_shapes(ctx.ggml_context, c, mul_mat_result) beta_t = ggml.utils.from_numpy( np.full( @@ -1706,14 +1574,16 @@ def ggml_operator_gemm( beta, dtype=get_tensor_dtype(mul_mat_result), ), - context, + ctx.ggml_context, ) mul_mat_result = ggml.ggml_add_inplace( - context, mul_mat_result, ggml.ggml_mul_inplace(context, c, beta_t) + ctx.ggml_context, + mul_mat_result, + ggml.ggml_mul_inplace(ctx.ggml_context, c, beta_t), ) - tensors_dict[node.output[0]] = mul_mat_result + ctx.tensors_dict[node.output[0]] = mul_mat_result return mul_mat_result @@ -1736,14 +1606,8 @@ def custom_greater( @ggml_operator("Greater") -def ggml_operator_greater( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_greater(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -1758,10 +1622,10 @@ def ggml_operator_greater( output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, node_inputs[0], node_inputs[1], @@ -1802,14 +1666,8 @@ def custom_hard_sigmoid( @ggml_operator("HardSigmoid") -def ggml_operator_size( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1823,15 +1681,15 @@ def ggml_operator_size( hsig_userdata = HardSigmoidUserData(alpha, beta) userdata_p = ctypes.cast(ctypes.pointer(hsig_userdata), ctypes.c_void_p) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x, custom_hard_sigmoid, 1, userdata_p, ) - refs.append(hsig_userdata) + ctx.refs.append(hsig_userdata) return new_tensor @@ -1855,14 +1713,8 @@ def custom_hardmax( @ggml_operator("Hardmax") -def ggml_operator_hardmax( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_hardmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1873,28 +1725,22 @@ def ggml_operator_hardmax( axis = next((attr.i for attr in node.attribute if attr.name == "axis"), -1) axis_c = ctypes.c_int(axis) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x, custom_hardmax, 1, ctypes.pointer(axis_c), ) - refs.append(axis_c) + ctx.refs.append(axis_c) return new_tensor @ggml_operator("Identity") -def ggml_operator_floor( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1904,11 +1750,11 @@ def ggml_operator_floor( x = node_inputs[0] output_name = node.output[0] y = ggml.ggml_dup( - context, x + ctx.ggml_context, x ) # NOTE: This will freeze the tensor in time, may not be expected. ggml.ggml_set_name(y, output_name.encode()) - tensors_dict[output_name] = y + ctx.tensors_dict[output_name] = y return y @@ -1937,14 +1783,8 @@ def custom_instancenorm( @ggml_operator("InstanceNormalization") -def ggml_operator_instancenorm( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_instancenorm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 3: raise ValueError( @@ -1953,8 +1793,8 @@ def ggml_operator_instancenorm( input_tensor, scale, B = node_inputs epsilon = next((attr.f for attr in node.attribute if attr.name == "epsilon"), 1e-05) epsilon_c = ctypes.c_double(epsilon) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, input_tensor, scale, B, @@ -1963,7 +1803,7 @@ def ggml_operator_instancenorm( ctypes.pointer(epsilon_c), ) - refs.append(epsilon_c) + ctx.refs.append(epsilon_c) return new_tensor @@ -2013,14 +1853,8 @@ def custom_leaky_lrn( @ggml_operator("LRN") -def ggml_operator_leaky_relu( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2041,15 +1875,15 @@ def ggml_operator_leaky_relu( lrn_userdata = LRNUserData(alpha, beta, bias, size) userdata_p = ctypes.cast(ctypes.pointer(lrn_userdata), ctypes.c_void_p) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x, custom_leaky_lrn, 1, userdata_p, ) - refs.append(lrn_userdata) + ctx.refs.append(lrn_userdata) return new_tensor @@ -2070,14 +1904,8 @@ def custom_leaky_relu( @ggml_operator("LeakyRelu") -def ggml_operator_leaky_relu( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2089,15 +1917,15 @@ def ggml_operator_leaky_relu( axis_c = ctypes.c_double(alpha) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x, custom_leaky_relu, 1, ctypes.pointer(axis_c), ) - refs.append(axis_c) + ctx.refs.append(axis_c) return new_tensor @@ -2121,14 +1949,8 @@ def custom_greater_equal( @ggml_operator("GreaterOrEqual") -def ggml_operator_greater_or_equal( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_greater_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2143,10 +1965,10 @@ def ggml_operator_greater_or_equal( output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, node_inputs[0], node_inputs[1], @@ -2179,14 +2001,8 @@ def custom_less( @ggml_operator("Less") -def ggml_operator_less( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_less(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2201,10 +2017,10 @@ def ggml_operator_less( output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, node_inputs[0], node_inputs[1], @@ -2237,14 +2053,8 @@ def custom_less_equal( @ggml_operator("LessOrEqual") -def ggml_operator_less_or_equal( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_less_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2259,10 +2069,10 @@ def ggml_operator_less_or_equal( output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, node_inputs[0], node_inputs[1], @@ -2277,14 +2087,8 @@ def ggml_operator_less_or_equal( @ggml_operator("Log") -def ggml_operator_log( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_log(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2295,22 +2099,16 @@ def ggml_operator_log( a = node_inputs[0] log_result = ggml.ggml_log( - context, + ctx.ggml_context, a, ) - tensors_dict[output_name] = log_result + ctx.tensors_dict[output_name] = log_result return log_result @ggml_operator("LogSoftmax") -def ggml_operator_log_soft_max( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_log_soft_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2319,24 +2117,18 @@ def ggml_operator_log_soft_max( output_name = node.output[0] a = node_inputs[0] - soft_max_result = ggml.ggml_soft_max(context, a) + soft_max_result = ggml.ggml_soft_max(ctx.ggml_context, a) log_result = ggml.ggml_log( - context, + ctx.ggml_context, soft_max_result, ) - tensors_dict[output_name] = log_result + ctx.tensors_dict[output_name] = log_result return log_result @ggml_operator("MatMul") -def ggml_operator_mat_mul( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2352,22 +2144,22 @@ def ggml_operator_mat_mul( try: np.matmul(np.empty(a_shape), np.empty(b_shape)) except: - a, b = broadcast_shapes(context, a, b) + a, b = broadcast_shapes(ctx.ggml_context, a, b) b_dtype = get_tensor_dtype(b) b_permute = ggml.ggml_transpose( - context, + ctx.ggml_context, b, ) b_shape = ggml.utils.get_shape(b_permute) b_transposed = ggml.ggml_cpy( - context, + ctx.ggml_context, b_permute, ggml.ggml_new_tensor( - context, + ctx.ggml_context, map_to_ggml_type(b_dtype).value, len(b_shape), (ctypes.c_int64 * len(b_shape))(*b_shape), @@ -2375,24 +2167,18 @@ def ggml_operator_mat_mul( ) mul_mat_result = ggml.ggml_mul_mat( - context, + ctx.ggml_context, b_transposed, a, ) - tensors_dict[output_name] = mul_mat_result + ctx.tensors_dict[output_name] = mul_mat_result return mul_mat_result @ggml_operator("Max") -def ggml_operator_max( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -2411,7 +2197,7 @@ def ggml_operator_max( output_shape = tuple(reversed(output_shape)) x_t = ggml.ggml_new_tensor( - context, + ctx.ggml_context, ggml_type.value, len(output_shape), (ctypes.c_int64 * len(output_shape))(*output_shape), @@ -2429,28 +2215,22 @@ def custom_max( x = np.max(tensors, axis=0) set_tensor_out(tensor_out, np.array(x)) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x_t, custom_max, 1, None, ) - refs.append(custom_max) + ctx.refs.append(custom_max) return new_tensor @ggml_operator("Mean") -def ggml_operator_mean( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -2461,30 +2241,24 @@ def ggml_operator_mean( sums = node_inputs[0] for tensor in node_inputs[1:]: - sums = ggml.ggml_add(context, sums, tensor) + sums = ggml.ggml_add(ctx.ggml_context, sums, tensor) coef_np = np.full(get_tensor_shape(sums), len(node_inputs), dtype=np.float32) - coef_t = ggml.utils.from_numpy(coef_np, context) + coef_t = ggml.utils.from_numpy(coef_np, ctx.ggml_context) mean = ggml.ggml_div( - context, + ctx.ggml_context, sums, coef_t, ) - tensors_dict[output_name] = mean + ctx.tensors_dict[output_name] = mean return mean @ggml_operator("Min") -def ggml_operator_min( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_min(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -2503,7 +2277,7 @@ def ggml_operator_min( output_shape = tuple(reversed(output_shape)) x_t = ggml.ggml_new_tensor( - context, + ctx.ggml_context, ggml_type.value, len(output_shape), (ctypes.c_int64 * len(output_shape))(*output_shape), @@ -2521,28 +2295,22 @@ def custom_min( x = np.min(tensors, axis=0) set_tensor_out(tensor_out, np.array(x)) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x_t, custom_min, 1, None, ) - refs.append(custom_min) + ctx.refs.append(custom_min) return new_tensor @ggml_operator("Mul") -def ggml_operator_mul( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2553,27 +2321,21 @@ def ggml_operator_mul( a = node_inputs[0] b = node_inputs[1] - a, b = broadcast_shapes(context, a, b) + a, b = broadcast_shapes(ctx.ggml_context, a, b) mul_result = ggml.ggml_mul( - context, + ctx.ggml_context, a, b, ) - tensors_dict[output_name] = mul_result + ctx.tensors_dict[output_name] = mul_result return mul_result @ggml_operator("Neg") -def ggml_operator_neg( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_neg(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2584,10 +2346,10 @@ def ggml_operator_neg( output_name = node.output[0] x_neg = ggml.ggml_neg( - context, + ctx.ggml_context, x, ) - tensors_dict[output_name] = x_neg + ctx.tensors_dict[output_name] = x_neg return x_neg @@ -2606,14 +2368,8 @@ def custom_not( @ggml_operator("Not") -def ggml_operator_not( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_not(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2621,8 +2377,8 @@ def ggml_operator_not( ) name = node.output[0] - new_tensor = tensors_dict[name] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, node_inputs[0], custom_not, 1, @@ -2653,14 +2409,8 @@ def custom_or( @ggml_operator("Or") -def ggml_operator_or( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_or(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2675,10 +2425,10 @@ def ggml_operator_or( output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, node_inputs[0], node_inputs[1], @@ -2693,27 +2443,21 @@ def ggml_operator_or( @ggml_operator("Pad") -def ggml_operator_pad( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): +def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): # x, pads, value, axes - if len(tensors_dict) < 2: + if len(ctx.tensors_dict) < 2: raise ValueError( f'Error for node "{node.name}": Operation "Pad" requires at least two inputs. Actual number of inputs: {len(node_inputs)}' ) - input_rank = tensors_dict["x"].contents.n_dims + input_rank = ctx.tensors_dict["x"].contents.n_dims mode = next( (attr.s for attr in node.attribute if attr.name == "mode"), b"constant" ).decode("utf-8") - if "axes" not in tensors_dict: + if "axes" not in ctx.tensors_dict: axes = list(range(input_rank)) else: - axes_eval = backend.eval_tensor(tensors_dict["axes"], context) + axes_eval = ctx.backend.eval_tensor(ctx.tensors_dict["axes"], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) axes = [axis if axis >= 0 else axis + input_rank for axis in axes] num_axes = len(axes) @@ -2721,7 +2465,9 @@ def ggml_operator_pad( for _ in range(input_rank): pad_width += [[0, 0]] # init to zero - raw_pads = ggml.utils.to_numpy(backend.eval_tensor(tensors_dict["pads"], context)) + raw_pads = ggml.utils.to_numpy( + ctx.backend.eval_tensor(ctx.tensors_dict["pads"], ctx.ggml_context) + ) # re-order to np.pad accepted order ((x1_begin, x1_end), (x2_begin, x2_end), ...) for i in range(num_axes): @@ -2731,16 +2477,16 @@ def ggml_operator_pad( pad_width[axis] = [raw_pads[i], raw_pads[i + num_axes]] expand_by = [sum(pad) for pad in pad_width] - prev_shape = get_tensor_shape(tensors_dict["x"]) + prev_shape = get_tensor_shape(ctx.tensors_dict["x"]) output_shape = [sum(x) for x in zip(prev_shape, expand_by)] - a_dtype = get_tensor_dtype(tensors_dict["x"]) + a_dtype = get_tensor_dtype(ctx.tensors_dict["x"]) x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) constant_value = None - if "value" in tensors_dict: + if "value" in ctx.tensors_dict: constant_values = ggml.utils.to_numpy( - backend.eval_tensor(tensors_dict["value"], context) + ctx.backend.eval_tensor(ctx.tensors_dict["value"], ctx.ggml_context) ) @ggml.ggml_custom2_op_t @@ -2769,15 +2515,15 @@ def custom_pad( ) set_tensor_out(tensor_out, x) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, - tensors_dict["x"], + ctx.tensors_dict["x"], custom_pad, 1, None, ) - refs.append(custom_pad) + ctx.refs.append(custom_pad) return new_tensor @@ -2790,8 +2536,6 @@ def custom_leaky_prelu( nth: int, userdata: Optional[ctypes.c_void_p], ): - - x = ggml.utils.to_numpy(tensor_in_1) slope = ggml.utils.to_numpy(tensor_in_2) @@ -2801,14 +2545,8 @@ def custom_leaky_prelu( @ggml_operator("PRelu") -def ggml_operator_leaky_relu( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2816,8 +2554,8 @@ def ggml_operator_leaky_relu( ) x, slope = node_inputs - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x, slope, custom_leaky_prelu, @@ -2846,14 +2584,8 @@ def custom_pow( @ggml_operator("Pow") -def ggml_operator_pow( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_pow(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2863,8 +2595,8 @@ def ggml_operator_pow( x1 = node_inputs[0] x2 = node_inputs[1] - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x1, x2, custom_pow, @@ -2890,14 +2622,8 @@ def custom_reciprocal( @ggml_operator("Reciprocal") -def ggml_operator_reciprocal( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reciprocal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2905,8 +2631,8 @@ def ggml_operator_reciprocal( ) x = node_inputs[0] - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x, custom_reciprocal, 1, @@ -2934,14 +2660,8 @@ def custom_range( @ggml_operator("Range") -def ggml_operator_range( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 3: raise ValueError( @@ -2954,12 +2674,12 @@ def ggml_operator_range( output_shape = (int(np.ceil((stop - start) / step)),) x = np.empty(output_shape, dtype=step.dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - input_tensors = ggml.utils.from_numpy(np.array(tensors), context) + input_tensors = ggml.utils.from_numpy(np.array(tensors), ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensors, custom_range, @@ -3013,14 +2733,8 @@ def custom_reduce_l1( @ggml_operator("ReduceL1") -def ggml_operator_reduce_l1( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3034,7 +2748,7 @@ def ggml_operator_reduce_l1( ) if noop_with_empty_axes == 1: - tensors_dict[node.output[0]] = input_tensor + ctx.tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3043,7 +2757,7 @@ def ggml_operator_reduce_l1( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = backend.eval_tensor(node_inputs[1], context) + axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3067,10 +2781,10 @@ def ggml_operator_reduce_l1( output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensor, custom_reduce_l1, @@ -3078,7 +2792,7 @@ def ggml_operator_reduce_l1( userdata_p, ) - refs.append(rmean_userdata) + ctx.refs.append(rmean_userdata) return new_tensor @@ -3107,14 +2821,8 @@ def custom_reduce_l2( @ggml_operator("ReduceL2") -def ggml_operator_reduce_l2( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3128,7 +2836,7 @@ def ggml_operator_reduce_l2( ) if noop_with_empty_axes == 1: - tensors_dict[node.output[0]] = input_tensor + ctx.tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3137,7 +2845,7 @@ def ggml_operator_reduce_l2( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = backend.eval_tensor(node_inputs[1], context) + axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3161,10 +2869,10 @@ def ggml_operator_reduce_l2( output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensor, custom_reduce_l2, @@ -3172,7 +2880,7 @@ def ggml_operator_reduce_l2( userdata_p, ) - refs.append(rmean_userdata) + ctx.refs.append(rmean_userdata) return new_tensor @@ -3200,14 +2908,8 @@ def custom_reduce_log_sum( @ggml_operator("ReduceLogSum") -def ggml_operator_reduce_log_sum( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3221,7 +2923,7 @@ def ggml_operator_reduce_log_sum( ) if noop_with_empty_axes == 1: - tensors_dict[node.output[0]] = input_tensor + ctx.tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3230,7 +2932,7 @@ def ggml_operator_reduce_log_sum( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = backend.eval_tensor(node_inputs[1], context) + axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3254,10 +2956,10 @@ def ggml_operator_reduce_log_sum( output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensor, custom_reduce_log_sum, @@ -3265,7 +2967,7 @@ def ggml_operator_reduce_log_sum( userdata_p, ) - refs.append(rmean_userdata) + ctx.refs.append(rmean_userdata) return new_tensor @@ -3293,17 +2995,11 @@ def custom_reduce_log_sum_exp( @ggml_operator("ReduceLogSumExp") -def ggml_operator_reduce_log_sum_exp( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): +def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): raise NotImplementedError( f'Error for node "{node.name}": Operation "ReduceLogSumExp" is not implemented.' ) - node_inputs = [tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3317,7 +3013,7 @@ def ggml_operator_reduce_log_sum_exp( ) if noop_with_empty_axes == 1: - tensors_dict[node.output[0]] = input_tensor + ctx.tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3326,7 +3022,7 @@ def ggml_operator_reduce_log_sum_exp( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = backend.eval_tensor(node_inputs[1], context) + axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3350,10 +3046,10 @@ def ggml_operator_reduce_log_sum_exp( output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensor, custom_reduce_log_sum_exp, @@ -3361,7 +3057,7 @@ def ggml_operator_reduce_log_sum_exp( userdata_p, ) - refs.append(rmean_userdata) + ctx.refs.append(rmean_userdata) return new_tensor @@ -3389,14 +3085,8 @@ def custom_reduce_max( @ggml_operator("ReduceMax") -def ggml_operator_reduce_max( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3410,7 +3100,7 @@ def ggml_operator_reduce_max( ) if noop_with_empty_axes == 1: - tensors_dict[node.output[0]] = input_tensor + ctx.tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3419,7 +3109,7 @@ def ggml_operator_reduce_max( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = backend.eval_tensor(node_inputs[1], context) + axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3443,10 +3133,10 @@ def ggml_operator_reduce_max( output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensor, custom_reduce_max, @@ -3454,7 +3144,7 @@ def ggml_operator_reduce_max( userdata_p, ) - refs.append(rmean_userdata) + ctx.refs.append(rmean_userdata) return new_tensor @@ -3482,14 +3172,8 @@ def custom_reduce_mean( @ggml_operator("ReduceMean") -def ggml_operator_reduce_mean( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3503,7 +3187,7 @@ def ggml_operator_reduce_mean( ) if noop_with_empty_axes == 1: - tensors_dict[node.output[0]] = input_tensor + ctx.tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3512,7 +3196,7 @@ def ggml_operator_reduce_mean( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = backend.eval_tensor(node_inputs[1], context) + axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3536,10 +3220,10 @@ def ggml_operator_reduce_mean( output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensor, custom_reduce_mean, @@ -3547,7 +3231,7 @@ def ggml_operator_reduce_mean( userdata_p, ) - refs.append(rmean_userdata) + ctx.refs.append(rmean_userdata) return new_tensor @@ -3575,14 +3259,8 @@ def custom_reduce_min( @ggml_operator("ReduceMin") -def ggml_operator_reduce_mean( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3596,7 +3274,7 @@ def ggml_operator_reduce_mean( ) if noop_with_empty_axes == 1: - tensors_dict[node.output[0]] = input_tensor + ctx.tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3605,7 +3283,7 @@ def ggml_operator_reduce_mean( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = backend.eval_tensor(node_inputs[1], context) + axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3629,10 +3307,10 @@ def ggml_operator_reduce_mean( output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensor, custom_reduce_min, @@ -3640,7 +3318,7 @@ def ggml_operator_reduce_mean( userdata_p, ) - refs.append(rmean_userdata) + ctx.refs.append(rmean_userdata) return new_tensor @@ -3668,14 +3346,8 @@ def custom_reduce_prod( @ggml_operator("ReduceProd") -def ggml_operator_reduce_prod( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3689,7 +3361,7 @@ def ggml_operator_reduce_prod( ) if noop_with_empty_axes == 1: - tensors_dict[node.output[0]] = input_tensor + ctx.tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3698,7 +3370,7 @@ def ggml_operator_reduce_prod( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = backend.eval_tensor(node_inputs[1], context) + axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3722,10 +3394,10 @@ def ggml_operator_reduce_prod( output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensor, custom_reduce_prod, @@ -3733,7 +3405,7 @@ def ggml_operator_reduce_prod( userdata_p, ) - refs.append(rmean_userdata) + ctx.refs.append(rmean_userdata) return new_tensor @@ -3760,14 +3432,8 @@ def custom_reduce_sum( @ggml_operator("ReduceSum") -def ggml_operator_reduce_sum( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3781,7 +3447,7 @@ def ggml_operator_reduce_sum( ) if noop_with_empty_axes == 1: - tensors_dict[node.output[0]] = input_tensor + ctx.tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3790,7 +3456,7 @@ def ggml_operator_reduce_sum( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = backend.eval_tensor(node_inputs[1], context) + axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3814,10 +3480,10 @@ def ggml_operator_reduce_sum( output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensor, custom_reduce_sum, @@ -3825,7 +3491,7 @@ def ggml_operator_reduce_sum( userdata_p, ) - refs.append(rmean_userdata) + ctx.refs.append(rmean_userdata) return new_tensor @@ -3853,14 +3519,8 @@ def custom_reduce_sum_square( @ggml_operator("ReduceSumSquare") -def ggml_operator_reduce_sum_square( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3874,7 +3534,7 @@ def ggml_operator_reduce_sum_square( ) if noop_with_empty_axes == 1: - tensors_dict[node.output[0]] = input_tensor + ctx.tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3883,7 +3543,7 @@ def ggml_operator_reduce_sum_square( axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = backend.eval_tensor(node_inputs[1], context) + axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3907,10 +3567,10 @@ def ggml_operator_reduce_sum_square( output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, input_tensor, custom_reduce_sum_square, @@ -3918,20 +3578,14 @@ def ggml_operator_reduce_sum_square( userdata_p, ) - refs.append(rmean_userdata) + ctx.refs.append(rmean_userdata) return new_tensor @ggml_operator("Relu") -def ggml_operator_relu( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -3942,22 +3596,16 @@ def ggml_operator_relu( a = node_inputs[0] relu_result = ggml.ggml_relu( - context, + ctx.ggml_context, a, ) - tensors_dict[output_name] = relu_result + ctx.tensors_dict[output_name] = relu_result return relu_result @ggml_operator("Reshape") -def ggml_operator_reshape( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_reshape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( f'Error for node "{node.name}": Operation "Reshape" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' @@ -3973,7 +3621,7 @@ def ggml_operator_reshape( a = node_inputs[0] b = node_inputs[1] - eval_b = backend.eval_tensor(b, context) + eval_b = ctx.backend.eval_tensor(b, ctx.ggml_context) new_shape = ggml.utils.to_numpy(eval_b).astype(dtype=np.int32) @@ -3984,7 +3632,7 @@ def ggml_operator_reshape( temp_a = np.empty(old_shape, dtype=get_tensor_dtype(a)) x = temp_a.reshape(new_shape) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) @ggml.ggml_custom2_op_t def custom_reshape( @@ -3999,8 +3647,8 @@ def custom_reshape( x_reshape = np.reshape(x, new_shape) set_tensor_out(tensor_out, x_reshape) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, a, custom_reshape, @@ -4008,7 +3656,7 @@ def custom_reshape( None, ) - refs.append(custom_reshape) + ctx.refs.append(custom_reshape) return new_tensor @@ -4044,14 +3692,8 @@ def custom_selu( @ggml_operator("Selu") -def ggml_operator_selu( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_selu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4072,28 +3714,22 @@ def ggml_operator_selu( selu_userdata = SeluUserData(alpha, gamma) userdata_p = ctypes.cast(ctypes.pointer(selu_userdata), ctypes.c_void_p) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x, custom_selu, 1, userdata_p, ) - refs.append(selu_userdata) + ctx.refs.append(selu_userdata) return new_tensor @ggml_operator("Shape") -def ggml_operator_shape( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4108,7 +3744,9 @@ def ggml_operator_shape( None, ) shape_slice = tensor_shape[start:end] - new_tensor = tensors_dict[name] = ggml.utils.from_numpy(shape_slice, context) + new_tensor = ctx.tensors_dict[name] = ggml.utils.from_numpy( + shape_slice, ctx.ggml_context + ) ggml.ggml_set_name(new_tensor, (name + f"").encode()) @@ -4131,14 +3769,8 @@ def custom_sigmoid( @ggml_operator("Sigmoid") -def ggml_operator_sigmoid( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_sigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4146,8 +3778,8 @@ def ggml_operator_sigmoid( ) x = node_inputs[0] - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x, custom_sigmoid, 1, @@ -4171,14 +3803,8 @@ def custom_size( @ggml_operator("Size") -def ggml_operator_size( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4191,14 +3817,14 @@ def ggml_operator_size( tensor_size_np = np.array( [tensor_size_np] ) # Add a rank so ggml doesnt break the value, inside the custom reshape to scalar as expected TODO: Fix the ranking, ggml skalars or make sure broadcasting works fine - tensor_size_t = ggml.utils.from_numpy(np.array([tensor_size_np]), context) + tensor_size_t = ggml.utils.from_numpy(np.array([tensor_size_np]), ctx.ggml_context) ggml_type = map_to_ggml_type(tensor_size_np.dtype).value x = np.empty(tensor_shape, dtype=tensor_size_np.dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, tensor_size_t, custom_size, @@ -4212,14 +3838,8 @@ def ggml_operator_size( @ggml_operator("Softmax") -def ggml_operator_softmax( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4230,10 +3850,10 @@ def ggml_operator_softmax( a = node_inputs[0] soft_max_result = ggml.ggml_soft_max( - context, + ctx.ggml_context, a, ) - tensors_dict[output_name] = soft_max_result + ctx.tensors_dict[output_name] = soft_max_result return soft_max_result @@ -4251,14 +3871,8 @@ def custom_softplus( @ggml_operator("Softplus") -def ggml_operator_softplus( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_softplus(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4267,8 +3881,8 @@ def ggml_operator_softplus( x = node_inputs[0] - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, x, custom_softplus, 1, @@ -4279,14 +3893,8 @@ def ggml_operator_softplus( @ggml_operator("Softsign") -def ggml_operator_softsign( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_softsign(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4299,11 +3907,11 @@ def ggml_operator_softsign( # y = x / (1 + abs(x)) one_np = np.full(x_shape, 1, dtype=x_dtype) - one_t = ggml.utils.from_numpy(one_np, context) - x_abs = ggml.ggml_abs(context, x) - one_plus_abs = ggml.ggml_add(context, one_t, x_abs) - y = ggml.ggml_div(context, x, one_plus_abs) - tensors_dict[node.output[0]] = y + one_t = ggml.utils.from_numpy(one_np, ctx.ggml_context) + x_abs = ggml.ggml_abs(ctx.ggml_context, x) + one_plus_abs = ggml.ggml_add(ctx.ggml_context, one_t, x_abs) + y = ggml.ggml_div(ctx.ggml_context, x, one_plus_abs) + ctx.tensors_dict[node.output[0]] = y return y @@ -4334,14 +3942,8 @@ def custom_space_to_depth( @ggml_operator("SpaceToDepth") -def ggml_operator_space_to_depth( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_space_to_depth(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4364,13 +3966,13 @@ def ggml_operator_space_to_depth( output_shape = (N, C * blocksize * blocksize, new_H, new_W) x_t = ggml.utils.from_numpy( - np.empty(output_shape, dtype=get_tensor_dtype(x)), context + np.empty(output_shape, dtype=get_tensor_dtype(x)), ctx.ggml_context ) blocksize_c = ctypes.c_int(blocksize) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, x_t, x, custom_space_to_depth, @@ -4378,7 +3980,7 @@ def ggml_operator_space_to_depth( ctypes.pointer(blocksize_c), ) - refs.append(blocksize_c) + ctx.refs.append(blocksize_c) return new_tensor @@ -4421,14 +4023,8 @@ def custom_split( @ggml_operator("Split") -def ggml_operator_split( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1 or len(node_inputs) > 2: raise ValueError( @@ -4460,7 +4056,7 @@ def ggml_operator_split( split_shapes = [tuple(split_shape) for split_shape in split_shapes] else: - split_eval = backend.eval_tensor(split_tensor, context) + split_eval = ctx.backend.eval_tensor(split_tensor, ctx.ggml_context) split_values = ggml.utils.to_numpy(split_eval) split_shapes = [list(input_shape) for _ in range(num_outputs)] @@ -4470,7 +4066,7 @@ def ggml_operator_split( split_shapes = tuple(map(tuple, split_shapes)) split_shapes_np = np.array(split_shapes, dtype=np.int32) - split_shapes_t = ggml.utils.from_numpy(split_shapes_np, context) + split_shapes_t = ggml.utils.from_numpy(split_shapes_np, ctx.ggml_context) outputs = [] @@ -4478,11 +4074,13 @@ def ggml_operator_split( split_userdata = SplitUserData(axis, split_index) userdata_p = ctypes.cast(ctypes.pointer(split_userdata), ctypes.c_void_p) - x_t = ggml.utils.from_numpy(np.empty(split_shape, dtype=dtype), context) - new_tensor = tensors_dict[ + x_t = ggml.utils.from_numpy( + np.empty(split_shape, dtype=dtype), ctx.ggml_context + ) + new_tensor = ctx.tensors_dict[ node.output[split_index] ] = ggml.ggml_map_custom3_inplace( - context, + ctx.ggml_context, x_t, input_tensor, split_shapes_t, @@ -4491,21 +4089,15 @@ def ggml_operator_split( userdata_p, ) - refs.append(split_userdata) + ctx.refs.append(split_userdata) outputs.append(new_tensor) return outputs @ggml_operator("Sqrt") -def ggml_operator_sqrt( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_sqrt(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4516,10 +4108,10 @@ def ggml_operator_sqrt( a = node_inputs[0] sqrt_result = ggml.ggml_sqrt( - context, + ctx.ggml_context, a, ) - tensors_dict[output_name] = sqrt_result + ctx.tensors_dict[output_name] = sqrt_result return sqrt_result @@ -4542,14 +4134,8 @@ def custom_squeeze( @ggml_operator("Squeeze") -def ggml_operator_squeeze( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -4561,7 +4147,7 @@ def ggml_operator_squeeze( x_shape = get_tensor_shape(data) x_dtype = get_tensor_dtype(data) - axes_eval = backend.eval_tensor(axes_input, context) + axes_eval = ctx.backend.eval_tensor(axes_input, ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) dummy_data = np.empty(x_shape, dtype=x_dtype) @@ -4572,10 +4158,10 @@ def ggml_operator_squeeze( f'Error for node "{node.name}": {len(dummy_data.shape)}D arrays are not allowed.' ) - x_t = ggml.utils.from_numpy(dummy_data, context) + x_t = ggml.utils.from_numpy(dummy_data, ctx.ggml_context) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, data, axes_input, @@ -4588,14 +4174,8 @@ def ggml_operator_squeeze( @ggml_operator("Sub") -def ggml_operator_sub( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_sub(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -4604,26 +4184,20 @@ def ggml_operator_sub( output_name = node.output[0] a, b = node_inputs - a, b = broadcast_shapes(context, a, b) + a, b = broadcast_shapes(ctx.ggml_context, a, b) sub_result = ggml.ggml_sub( - context, + ctx.ggml_context, a, b, ) - tensors_dict[output_name] = sub_result + ctx.tensors_dict[output_name] = sub_result return sub_result @ggml_operator("Sum") -def ggml_operator_sum( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -4635,30 +4209,24 @@ def ggml_operator_sum( dtype = get_tensor_dtype(node_inputs[0]) empty_np = np.full(shape, 0, dtype=dtype) - next_item = ggml.utils.from_numpy(empty_np, context) + next_item = ggml.utils.from_numpy(empty_np, ctx.ggml_context) for tensor in node_inputs: - tensor, next_item = broadcast_shapes(context, tensor, next_item) + tensor, next_item = broadcast_shapes(ctx.ggml_context, tensor, next_item) next_item = ggml.ggml_add( - context, + ctx.ggml_context, tensor, next_item, ) - tensors_dict[output_name] = next_item + ctx.tensors_dict[output_name] = next_item return next_item @ggml_operator("Tanh") -def ggml_operator_tanh( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_tanh(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4667,11 +4235,11 @@ def ggml_operator_tanh( x = node_inputs[0] tanh_result = ggml.ggml_tanh( - context, + ctx.ggml_context, x, ) - tensors_dict[node.output[0]] = tanh_result + ctx.tensors_dict[node.output[0]] = tanh_result return tanh_result @@ -4695,14 +4263,8 @@ def custom_tile( @ggml_operator("Tile") -def ggml_operator_tile( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -4711,7 +4273,7 @@ def ggml_operator_tile( x, repeats = node_inputs - repeats_eval = backend.eval_tensor(repeats, context) + repeats_eval = ctx.backend.eval_tensor(repeats, ctx.ggml_context) repeats_vals = ggml.utils.to_numpy(repeats_eval).astype(dtype=np.int32) output_shape = list(get_tensor_shape(x)) @@ -4720,11 +4282,11 @@ def ggml_operator_tile( x_t = ggml.utils.from_numpy( np.empty(output_shape, dtype=get_tensor_dtype(x)), - context, + ctx.ggml_context, ) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, x, repeats, @@ -4803,14 +4365,8 @@ def custom_top_k_values( @ggml_operator("TopK") -def ggml_operator_top_k( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -4825,7 +4381,7 @@ def ggml_operator_top_k( largest = next((attr.i for attr in node.attribute if attr.name == "largest"), 1) sorted_flag = next((attr.i for attr in node.attribute if attr.name == "sorted"), 0) - k_eval = backend.eval_tensor(k, context) + k_eval = ctx.backend.eval_tensor(k, ctx.ggml_context) k_np = ggml.utils.to_numpy(k_eval)[0] topk_userdata = TopKUserData(axis, largest, sorted_flag, k_np) @@ -4837,16 +4393,16 @@ def ggml_operator_top_k( indices_t = ggml.utils.from_numpy( np.empty(output_shape, dtype=np.int32), - context, + ctx.ggml_context, ) values_t = ggml.utils.from_numpy( np.empty(output_shape, dtype=get_tensor_dtype(x)), - context, + ctx.ggml_context, ) indices = ggml.ggml_map_custom2_inplace( - context, + ctx.ggml_context, indices_t, x, custom_top_k_indices, @@ -4855,7 +4411,7 @@ def ggml_operator_top_k( ) values = ggml.ggml_map_custom3_inplace( - context, + ctx.ggml_context, values_t, x, indices, @@ -4864,10 +4420,10 @@ def ggml_operator_top_k( userdata_p, ) - tensors_dict[node.output[0]] = values - tensors_dict[node.output[1]] = indices + ctx.tensors_dict[node.output[0]] = values + ctx.tensors_dict[node.output[1]] = indices - refs.append(topk_userdata) + ctx.refs.append(topk_userdata) ggml.ggml_set_name(indices, (node.output[1] + f"").encode()) @@ -4875,14 +4431,8 @@ def ggml_operator_top_k( @ggml_operator("Transpose") -def ggml_operator_transpose( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4914,14 +4464,16 @@ def ggml_operator_transpose( ) # FIXME: 2,3D permutations are fine 4d is not. Passes ONNX test if dims == 3 and f"02" in "".join([str(perm) for perm in perms]): - x = ggml.ggml_transpose(context, x) + x = ggml.ggml_transpose(ctx.ggml_context, x) - transpose_result = ggml.ggml_permute(context, x, ax0, ax1, ax2, ax3) + transpose_result = ggml.ggml_permute(ctx.ggml_context, x, ax0, ax1, ax2, ax3) if dims == 3 and f"02" in "".join([str(perm) for perm in perms]): - transpose_result = ggml.ggml_permute(context, transpose_result, 0, 2, 1, 3) + transpose_result = ggml.ggml_permute( + ctx.ggml_context, transpose_result, 0, 2, 1, 3 + ) - tensors_dict[output_name] = transpose_result + ctx.tensors_dict[output_name] = transpose_result return transpose_result @@ -4948,14 +4500,8 @@ def custom_unsqueeze( @ggml_operator("Unsqueeze") -def ggml_operator_unsqueeze( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -4969,7 +4515,7 @@ def ggml_operator_unsqueeze( x_dtype = get_tensor_dtype(data) x_ndims = ggml.utils.get_ndims(data) - axes_eval = backend.eval_tensor(axes_input, context) + axes_eval = ctx.backend.eval_tensor(axes_input, ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) axes_values = [ax if ax >= 0 else ax + x_ndims + 1 for ax in axes] @@ -4988,14 +4534,14 @@ def ggml_operator_unsqueeze( ) x_t = ggml.ggml_new_tensor( - context, + ctx.ggml_context, ggml_type.value, len(new_shape), (ctypes.c_int64 * len(new_shape))(*new_shape), ) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, data, axes_input, @@ -5025,22 +4571,16 @@ def custom_where( @ggml_operator("Where") -def ggml_operator_where( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_where(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 3: raise ValueError( f'Error for node "{node.name}": Operation "Where" requires exactly three inputs. Actual number of inputs: {len(node_inputs)}' ) - new_tensor = tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, node_inputs[1], node_inputs[2], node_inputs[0], @@ -5071,14 +4611,8 @@ def custom_xor( @ggml_operator("Xor") -def ggml_operator_xor( - backend: "GgmlBackendRep", - node: NodeProto, - tensors_dict: Dict[str, ggml.ggml_tensor_p], - context: ggml.ggml_context_p, - refs: List[Any], -): - node_inputs = [tensors_dict[inp] for inp in node.input] +def ggml_operator_xor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -5093,10 +4627,10 @@ def ggml_operator_xor( output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, context) + x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - new_tensor = tensors_dict[name] = ggml.ggml_map_custom3_inplace( - context, + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, node_inputs[0], node_inputs[1], @@ -5110,6 +4644,20 @@ def ggml_operator_xor( return new_tensor +class GgmlOnnxExecutionContext: + def __init__( + self, + backend: "GgmlBackendRep", + tensors_dict: Dict[str, ggml.ggml_tensor_p], + ggml_context: ggml.ggml_context_p, + refs: List[Any], + ): + self.backend = backend + self.tensors_dict = tensors_dict + self.ggml_context = ggml_context + self.refs = refs + + class GgmlBackendRep(BackendRep): def __init__( self, @@ -5134,9 +4682,11 @@ def __del__(self): if hasattr(self, "ggml_context"): ggml.ggml_free(self.ggml_context) - def eval_tensor(self, tensor: ggml.ggml_tensor_p, context: ggml.ggml_context_p): + def eval_tensor( + self, tensor: ggml.ggml_tensor_p, ggml_context: ggml.ggml_context_p + ): gf = ggml.ggml_build_forward(tensor) - ggml.ggml_graph_compute_with_ctx(context, ctypes.pointer(gf), 1) + ggml.ggml_graph_compute_with_ctx(ggml_context, ctypes.pointer(gf), 1) return tensor @@ -5152,9 +4702,9 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: exit_node = None ggml_tensors = self.weights - # Define context + # Define ggml_context params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) - context = ggml.ggml_init(params=params) + ggml_context = ggml.ggml_init(params=params) refs: List[Any] = [] @@ -5195,7 +4745,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: shape = (1,) tensor = ggml.ggml_new_tensor( - context, + ggml_context, ggml_type.value, len(shape), (ctypes.c_int64 * len(shape))(*shape), @@ -5211,6 +4761,8 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: gf_p = ctypes.pointer(gf) output_names = [output.name for output in model_graph.output] + ctx = GgmlOnnxExecutionContext(self, ggml_tensors, ggml_context, refs) + # Build layers for node in model_graph.node: operator_func = ggml_operators.get(node.op_type) @@ -5218,11 +4770,8 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: raise NotImplementedError(f'Operator "{node.op_type}" not implemented') operator_func( - self, + ctx, node, - ggml_tensors, - context, - refs, ) for output in node.output: @@ -5230,7 +4779,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) # Compute graph - ggml.ggml_graph_compute_with_ctx(context, gf_p, 1) + ggml.ggml_graph_compute_with_ctx(ggml_context, gf_p, 1) graph_outputs = [] for output in self.outputs: @@ -5243,7 +4792,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ) # TODO: add a second dict to keep track of types and use that instead graph_outputs.append(graph_output) - ggml.ggml_free(context) + ggml.ggml_free(ggml_context) return graph_outputs @@ -5275,7 +4824,7 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): no_alloc=True, ) - context = ggml.ggml_init(init_params) + ggml_context = ggml.ggml_init(init_params) total_nbytes = 0 pairs = [] @@ -5283,7 +4832,7 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): for initializer in graph.initializer: name = initializer.name np_array = onnx.numpy_helper.to_array(initializer) - tensor = ggml.utils.from_numpy(x=np_array, ctx=context) + tensor = ggml.utils.from_numpy(x=np_array, ctx=ggml_context) ggml.ggml_set_name(tensor=tensor, name=name.encode()) total_nbytes += ggml.ggml_nbytes_pad(tensor) weights[name] = tensor @@ -5308,7 +4857,7 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): weights_buffer=buffer, inputs=graph.input, outputs=graph.output, - ggml_context=context, + ggml_context=ggml_context, ggml_init_params=init_params, ) From 5dfebead5599c69deefd5c927c37857bfa4856ed Mon Sep 17 00:00:00 2001 From: David Miller Date: Mon, 18 Sep 2023 14:34:07 -0700 Subject: [PATCH 159/232] Remove pypy tests from GH actions tests --- .github/workflows/test.yaml | 46 ++++--------------------------------- 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 942a501e..5390bf32 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "pypy3.9", "pypy3.10"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 @@ -25,32 +25,19 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies - if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] - - name: Install dependencies [pypy] - if: ${{ startsWith(matrix.python-version, 'pypy') }} - run: | - python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test] - - name: Test with pytest - if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pytest - - name: Test with pytest [pypy] - if: ${{ startsWith(matrix.python-version, 'pypy') }} - run: | - python3 -m pytest --ignore-glob='*onnx*' - build-windows: runs-on: windows-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "pypy3.9", "pypy3.10"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 @@ -61,33 +48,21 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + - name: Install dependencies - if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] - - name: Install dependencies [pypy] - if: ${{ startsWith(matrix.python-version, 'pypy') }} - run: | - python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test] - - name: Test with pytest - if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pytest - - name: Test with pytest [pypy] - if: ${{ startsWith(matrix.python-version, 'pypy') }} - run: | - python3 -m pytest --ignore-glob='*onnx*' - build-macos: runs-on: macos-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "pypy3.9", "pypy3.10"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 @@ -99,23 +74,10 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies - if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pip install --upgrade pip cmake scikit-build setuptools python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] - - name: Install dependencies [pypy] - if: ${{ startsWith(matrix.python-version, 'pypy') }} - run: | - python3 -m pip install --upgrade pip cmake scikit-build setuptools - python3 -m pip install --verbose --editable .[test] - - name: Test with pytest - if: ${{ !startsWith(matrix.python-version, 'pypy') }} run: | python3 -m pytest - - - name: Test with pytest [pypy] - if: ${{ startsWith(matrix.python-version, 'pypy') }} - run: | - python3 -m pytest --ignore-glob='*onnx*' From e8b5419b3f1ca50a5ec487fbe747665a52871979 Mon Sep 17 00:00:00 2001 From: David Miller Date: Mon, 18 Sep 2023 14:39:12 -0700 Subject: [PATCH 160/232] fix --- ggml/contrib/onnx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index b41c6409..5edfa6c9 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4771,7 +4771,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: set_tensor_out(tensor, np.array(value)) # Define context - context = ggml.ggml_init(params=ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None)) + ggml_context = ggml.ggml_init(params=ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None)) refs: List[Any] = [] @@ -4814,7 +4814,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ) # TODO: add a second dict to keep track of types and use that instead graph_outputs.append(graph_output) - ggml.ggml_free(context) + ggml.ggml_free(ggml_context) ggml.ggml_free(input_context) return graph_outputs From 715112bf2975c19d26b632e115316e8036802f64 Mon Sep 17 00:00:00 2001 From: David Miller Date: Mon, 18 Sep 2023 18:55:26 -0700 Subject: [PATCH 161/232] Wrap to_numpy/from_numpy with Context method --- ggml/contrib/onnx.py | 140 +++++++++++++++++++++++++++---------------- 1 file changed, 88 insertions(+), 52 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 5edfa6c9..3713f11e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -235,7 +235,7 @@ def ggml_operator_and(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -472,7 +472,7 @@ def ggml_operator_cast(ctx: "GgmlOnnxExecutionContext", node: NodeProto): np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) x = np.empty(get_tensor_shape(a), dtype=np_data_type_limit) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -505,7 +505,7 @@ def ggml_operator_castlike(ctx: "GgmlOnnxExecutionContext", node: NodeProto): onnx_type_c = ctypes.c_int(onnx_type) x = np.empty(get_tensor_shape(a), dtype=np_data_type_limit) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -533,7 +533,7 @@ def ggml_operator_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): np_dtype = get_tensor_dtype(a) x = np.empty(get_tensor_shape(a), dtype=np_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) @ggml.ggml_custom1_op_t def custom_ceil( @@ -543,7 +543,7 @@ def custom_ceil( nth: int, userdata: Optional[ctypes.c_void_p], ): - tensor = ggml.utils.to_numpy(tensor_in_1) + tensor = ctx.to_numpy(tensor_in_1) x = np.ceil(tensor) set_tensor_out(tensor_out, np.array(x)) @@ -570,7 +570,7 @@ def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 0) - shapes = [get_tensor_shape(tensor) for tensor in node_inputs] + shapes = [ctx.get_tensor_shape(tensor) for tensor in node_inputs] if not all( shape[:axis] == shapes[0][:axis] and shape[axis + 1 :] == shapes[0][axis + 1 :] @@ -585,24 +585,30 @@ def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape[axis] = total_dim x = np.empty(output_shape, dtype=get_tensor_dtype(node_inputs[0])) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) - @ggml.ggml_custom1_op_t + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom3_op_t def custom_concat( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, ith: int, nth: int, userdata: Optional[ctypes.c_void_p], ): - tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] - x = np.concatenate(tensors, axis=axis) - + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) + x = np.concatenate([a, b], axis=axis) set_tensor_out(tensor_out, x) - - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + tensor_a = node_inputs[0] + tensor_b = node_inputs[1] + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, + tensor_a, + tensor_b, custom_concat, 1, None, @@ -639,6 +645,8 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if value_attr.HasField("t"): tensor = value_attr.t data_type = tensor.data_type + dims = tensor.dims[0] if tensor.dims else 0 + np_data_type = tensor_dtype_to_np_dtype(data_type) np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) @@ -668,7 +676,7 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): tensor_shape = data_value.shape x = np.empty(tensor_shape, dtype=np_data_type_limit) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -678,6 +686,8 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, None, ) + if dims == 0: + ctx.set_tensor_shape(new_tensor, ()) ggml.ggml_set_name(new_tensor, (name + f"<{np_data_type}>").encode()) return new_tensor @@ -735,15 +745,14 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP f'Error for node "{node.name}": Constant node not set correctly or incomplete implantation.' ) - data_tensor = ggml.utils.from_numpy( - data_value.astype(np_data_type_limit), - ctx.ggml_context, + data_tensor = ctx.from_numpy( + data_value.astype(np_data_type_limit) ) - shape = ggml.utils.to_numpy(node_inputs[0]) + shape = ctx.to_numpy(node_inputs[0]) x = np.empty(shape, dtype=np_data_type_limit) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -1158,7 +1167,7 @@ def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if type(training_mode) is ggml.ggml_tensor_p: training_mode_eval = ctx.backend.eval_tensor(training_mode, ctx.ggml_context) - training_mode = ggml.utils.to_numpy(training_mode_eval) + training_mode = ctx.to_numpy(training_mode_eval) droput_userdata = DropoutUserData(seed, bool(training_mode)) userdata_p = ctypes.cast(ctypes.pointer(droput_userdata), ctypes.c_void_p) @@ -1215,10 +1224,10 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if alpha != 1.0: Y_eval = ctx.backend.eval_tensor(Y, ctx.ggml_context) - Y_np = ggml.utils.to_numpy(Y_eval) + Y_np = ctx.to_numpy(Y_eval) Y_alpha = np.where(Y_np < 0, alpha * Y_np, Y_np) - Y = ggml.utils.from_numpy(Y_alpha, ctx.ggml_context) + Y = ctx.from_numpy(Y_alpha) ctx.tensors_dict[output_name] = Y return Y @@ -1259,7 +1268,7 @@ def ggml_operator_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -1288,7 +1297,7 @@ def ggml_operator_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): np_dtype = get_tensor_dtype(a) x = np.empty(get_tensor_shape(a), dtype=np_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) @ggml.ggml_custom1_op_t def custom_exp( @@ -1443,9 +1452,9 @@ def ggml_operator_gather(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 0) axis_c = ctypes.c_int(axis) - input_shape = get_tensor_shape(node_inputs[0]) + input_shape = ctx.get_tensor_shape(node_inputs[0]) input_dtype = get_tensor_dtype(node_inputs[0]) - index_shape = get_tensor_shape(node_inputs[1]) + index_shape = ctx.get_tensor_shape(node_inputs[1]) Ni = input_shape[:axis] Nk = input_shape[axis + 1 :] @@ -1453,7 +1462,7 @@ def ggml_operator_gather(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = tuple(list(Ni) + list(Nj) + list(Nk)) x = np.empty(output_shape, dtype=input_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -1467,6 +1476,9 @@ def ggml_operator_gather(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.refs.append(axis_c) + if output_shape == (): + ctx.set_tensor_shape(new_tensor, ()) + return new_tensor @@ -1622,7 +1634,7 @@ def ggml_operator_greater(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -1965,7 +1977,7 @@ def ggml_operator_greater_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodePr output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -2017,7 +2029,7 @@ def ggml_operator_less(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -2069,7 +2081,7 @@ def ggml_operator_less_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -2425,7 +2437,7 @@ def ggml_operator_or(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -2458,14 +2470,14 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = list(range(input_rank)) else: axes_eval = ctx.backend.eval_tensor(ctx.tensors_dict["axes"], ctx.ggml_context) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) axes = [axis if axis >= 0 else axis + input_rank for axis in axes] num_axes = len(axes) pad_width = [] for _ in range(input_rank): pad_width += [[0, 0]] # init to zero - raw_pads = ggml.utils.to_numpy( + raw_pads = ctx.to_numpy( ctx.backend.eval_tensor(ctx.tensors_dict["pads"], ctx.ggml_context) ) @@ -2481,11 +2493,11 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = [sum(x) for x in zip(prev_shape, expand_by)] a_dtype = get_tensor_dtype(ctx.tensors_dict["x"]) x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) constant_value = None if "value" in ctx.tensors_dict: - constant_values = ggml.utils.to_numpy( + constant_values = ctx.to_numpy( ctx.backend.eval_tensor(ctx.tensors_dict["value"], ctx.ggml_context) ) @@ -2674,7 +2686,7 @@ def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = (int(np.ceil((stop - start) / step)),) x = np.empty(output_shape, dtype=step.dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) input_tensors = ggml.utils.from_numpy(np.array(tensors), ctx.ggml_context) @@ -2781,7 +2793,7 @@ def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -2869,7 +2881,7 @@ def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -2956,7 +2968,7 @@ def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProt output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -3046,7 +3058,7 @@ def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: Node output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -3133,7 +3145,7 @@ def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -3220,7 +3232,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -3307,7 +3319,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -3394,7 +3406,7 @@ def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -3480,7 +3492,7 @@ def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -3567,7 +3579,7 @@ def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeP output_shape = tuple(output_shape) x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -3632,7 +3644,7 @@ def ggml_operator_reshape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): temp_a = np.empty(old_shape, dtype=get_tensor_dtype(a)) x = temp_a.reshape(new_shape) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) @ggml.ggml_custom2_op_t def custom_reshape( @@ -3821,7 +3833,7 @@ def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ggml_type = map_to_ggml_type(tensor_size_np.dtype).value x = np.empty(tensor_shape, dtype=tensor_size_np.dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -4511,7 +4523,7 @@ def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): data = node_inputs[0] axes_input = node_inputs[1] - x_shape = get_tensor_shape(data) + x_shape = ctx.get_tensor_shape(data) x_dtype = get_tensor_dtype(data) x_ndims = ggml.utils.get_ndims(data) @@ -4549,7 +4561,6 @@ def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, None, ) - return new_tensor @@ -4627,7 +4638,7 @@ def ggml_operator_xor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape x = np.empty(output_shape, dtype=a_dtype) - x_t = ggml.utils.from_numpy(x, ctx.ggml_context) + x_t = ctx.from_numpy(x) new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -4656,7 +4667,28 @@ def __init__( self.tensors_dict = tensors_dict self.ggml_context = ggml_context self.refs = refs + self.shapes = {} + def set_tensor_shape(self, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...]): + data = tensor.contents.data + self.shapes[data] = shape + + def get_tensor_shape(self, tensor: ggml.ggml_tensor_p) -> Tuple[int, ...]: + data = tensor.contents.data + if data not in self.shapes: + self.shapes[data] = get_tensor_shape(tensor) + return self.shapes[data] + + def to_numpy(self, tensor: ggml.ggml_tensor_p) -> np.ndarray: + shape = self.get_tensor_shape(tensor) + array = ggml.utils.to_numpy(tensor) + return array.reshape(shape) + + def from_numpy(self, array: np.ndarray) -> ggml.ggml_tensor_p: + shape = array.shape + tensor = ggml.utils.from_numpy(array, self.ggml_context) + self.set_tensor_shape(tensor, shape) + return tensor class GgmlBackendRep(BackendRep): def __init__( @@ -4812,6 +4844,10 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: graph_output = graph_output.astype( get_final_dtype(exit_node) ) # TODO: add a second dict to keep track of types and use that instead + + shape = ctx.get_tensor_shape(exit_node) + graph_output = graph_output.reshape(shape) + graph_outputs.append(graph_output) ggml.ggml_free(ggml_context) From 7933fe66d03add7926d70247adbc1fd5f902236e Mon Sep 17 00:00:00 2001 From: David Miller Date: Mon, 18 Sep 2023 20:54:20 -0700 Subject: [PATCH 162/232] Implement Slice op --- ggml/contrib/onnx.py | 59 ++++++++++++++++++++++++++++++++++++++++- tests/test_ggml_onnx.py | 10 ++++--- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 3713f11e..d34abde4 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3848,7 +3848,64 @@ def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return new_tensor +@ggml_operator("Slice") +def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + a_shape = ctx.get_tensor_shape(node_inputs[0]) + a_dtype = get_tensor_dtype(node_inputs[0]) + + starts = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context)) + ends = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[2], ctx.ggml_context)) + + dims = len(a_shape) + if len(node_inputs) >= 4: + axes = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[3], ctx.ggml_context)) + else: + axes = list(range(len(starts))) + + axes = [a + dims if a < 0 else a for a in axes] + + if len(node_inputs) == 5: + steps = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[4], ctx.ggml_context)) + else: + steps = np.ones_like(starts) + + + slices = [slice(start,end, step) for start, end, step in zip(starts, ends, steps)] + all_slices = [] + for axis in range(dims): + if axis not in axes: + all_slices.append(slice(None)) + else: + all_slices.append(slices.pop(0)) + + x = np.empty(a_shape, dtype=a_dtype)[tuple(all_slices)].copy() + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom2_op_t + def custom_slice(tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p]): + x = ggml.utils.to_numpy(tensor_in_2) + y = x[tuple(all_slices)].copy() + + set_tensor_out(tensor_out, y) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, + x_t, + node_inputs[0], + custom_slice, + 1, + None + ) + ctx.refs.append(custom_slice) + return new_tensor + @ggml_operator("Softmax") def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4161,7 +4218,7 @@ def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes_eval = ctx.backend.eval_tensor(axes_input, ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) - + # breakpoint() dummy_data = np.empty(x_shape, dtype=x_dtype) dummy_data = np.squeeze(dummy_data, axis=axes[0]) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 547a3b5d..e97122a4 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -176,11 +176,14 @@ def apply(self, model: onnx.ModelProto) -> Optional[ModelProto]: break else: return None - + # find a transpose node that transposes the output of the first transpose node transpose_transpose_node: Optional[NodeProto] = None for node in model.graph.node: - if node.op_type == "Transpose" and node.input[0] == transpose_node.output[0]: + if ( + node.op_type == "Transpose" + and node.input[0] == transpose_node.output[0] + ): transpose_transpose_node = node break else: @@ -195,7 +198,6 @@ def apply(self, model: onnx.ModelProto) -> Optional[ModelProto]: return model - input_data = {"x": np.random.randn(1, 32).astype(np.float32)} f = io.BytesIO() @@ -458,7 +460,7 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_size_") -# backend_test.include("test_slice_") +backend_test.include("test_slice_") backend_test.include("test_softmax_") backend_test.exclude("test_softmax_axis_0") # not supported From c24e7d5b4976216495f687bb104273af85a53a4b Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 19 Sep 2023 12:12:51 -0400 Subject: [PATCH 163/232] Format --- ggml/contrib/onnx.py | 63 +++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index d34abde4..997a6961 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -587,7 +587,7 @@ def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=get_tensor_dtype(node_inputs[0])) x_t = ctx.from_numpy(x) - + @ggml.ggml_custom3_op_t def custom_concat( tensor_out: ggml.ggml_tensor_p, @@ -602,13 +602,14 @@ def custom_concat( b = ctx.to_numpy(tensor_in_3) x = np.concatenate([a, b], axis=axis) set_tensor_out(tensor_out, x) + tensor_a = node_inputs[0] tensor_b = node_inputs[1] new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, tensor_a, - tensor_b, + tensor_b, custom_concat, 1, None, @@ -745,9 +746,7 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP f'Error for node "{node.name}": Constant node not set correctly or incomplete implantation.' ) - data_tensor = ctx.from_numpy( - data_value.astype(np_data_type_limit) - ) + data_tensor = ctx.from_numpy(data_value.astype(np_data_type_limit)) shape = ctx.to_numpy(node_inputs[0]) @@ -3848,9 +3847,9 @@ def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return new_tensor + @ggml_operator("Slice") def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] a_shape = ctx.get_tensor_shape(node_inputs[0]) a_dtype = get_tensor_dtype(node_inputs[0]) @@ -3865,14 +3864,13 @@ def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = list(range(len(starts))) axes = [a + dims if a < 0 else a for a in axes] - + if len(node_inputs) == 5: steps = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[4], ctx.ggml_context)) else: steps = np.ones_like(starts) - - slices = [slice(start,end, step) for start, end, step in zip(starts, ends, steps)] + slices = [slice(start, end, step) for start, end, step in zip(starts, ends, steps)] all_slices = [] for axis in range(dims): if axis not in axes: @@ -3882,30 +3880,28 @@ def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(a_shape, dtype=a_dtype)[tuple(all_slices)].copy() x_t = ctx.from_numpy(x) - + @ggml.ggml_custom2_op_t - def custom_slice(tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p]): + def custom_slice( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): x = ggml.utils.to_numpy(tensor_in_2) y = x[tuple(all_slices)].copy() set_tensor_out(tensor_out, y) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, - x_t, - node_inputs[0], - custom_slice, - 1, - None + ctx.ggml_context, x_t, node_inputs[0], custom_slice, 1, None ) ctx.refs.append(custom_slice) return new_tensor - + + @ggml_operator("Softmax") def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4729,7 +4725,7 @@ def __init__( def set_tensor_shape(self, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...]): data = tensor.contents.data self.shapes[data] = shape - + def get_tensor_shape(self, tensor: ggml.ggml_tensor_p) -> Tuple[int, ...]: data = tensor.contents.data if data not in self.shapes: @@ -4747,6 +4743,7 @@ def from_numpy(self, array: np.ndarray) -> ggml.ggml_tensor_p: self.set_tensor_shape(tensor, shape) return tensor + class GgmlBackendRep(BackendRep): def __init__( self, @@ -4795,10 +4792,14 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: exit_node = None ggml_tensors = self.weights - input_context = ggml.ggml_init(params=ggml.ggml_init_params( - mem_size=2 * ggml.GGML_MAX_NODES * ggml.ggml_tensor_overhead(), # FIXME: Reduce to n inputs or combine with tensors context - no_alloc=True, - )) + input_context = ggml.ggml_init( + params=ggml.ggml_init_params( + mem_size=2 + * ggml.GGML_MAX_NODES + * ggml.ggml_tensor_overhead(), # FIXME: Reduce to n inputs or combine with tensors context + no_alloc=True, + ) + ) input_buffer_size = 0 # Create entry inputs @@ -4846,7 +4847,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: input_buffer_size += ggml.ggml_nbytes_pad(tensor) ggml_tensors[input_name] = tensor - + input_buffer = (ctypes.c_uint8 * input_buffer_size)() input_buffer_offset = 0 @@ -4860,7 +4861,9 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: set_tensor_out(tensor, np.array(value)) # Define context - ggml_context = ggml.ggml_init(params=ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None)) + ggml_context = ggml.ggml_init( + params=ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + ) refs: List[Any] = [] From a9648604b7b285e8b2584f4babbc7f3bb480653b Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 19 Sep 2023 12:35:28 -0400 Subject: [PATCH 164/232] Fix typing --- ggml/contrib/onnx.py | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 997a6961..b6a9635d 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5,13 +5,15 @@ import ctypes import math import re -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple, Sequence +from typing_extensions import TypeGuard import numpy as np +import numpy.typing as npt import onnx from onnx.backend.base import Backend, BackendRep from onnx.helper import np_dtype_to_tensor_dtype, tensor_dtype_to_np_dtype -from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto +from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto, ValueInfoProto import ggml import ggml.utils @@ -4747,13 +4749,13 @@ def from_numpy(self, array: np.ndarray) -> ggml.ggml_tensor_p: class GgmlBackendRep(BackendRep): def __init__( self, - graph, - weights, - weights_buffer, - inputs, - outputs, - ggml_context, - ggml_init_params, + graph: GraphProto, + weights: Dict[str, ggml.ggml_tensor_p], + weights_buffer: Any, + inputs: Sequence[ValueInfoProto], + outputs: Sequence[ValueInfoProto], + ggml_context: ggml.ggml_context_p, + ggml_init_params: ggml.ggml_init_params, ): super(GgmlBackendRep, self).__init__() self.graph = graph @@ -4780,13 +4782,25 @@ def eval_tensor( return tensor + @staticmethod + def _is_list_of_arraylike(x: Any) -> TypeGuard[List[npt.ArrayLike]]: + return isinstance(x, list) and all( + isinstance(y, (np.ndarray, list)) for y in x + ) + + @staticmethod + def _is_dict_of_arraylike(x: Any) -> TypeGuard[Dict[str,npt.ArrayLike]]: + return isinstance(x, dict) and all( + isinstance(y, (np.ndarray, list)) for y in x.values() + ) and all(isinstance(k, str) for k in x.keys()) + def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: """Run the model with the specified inputs.""" - if isinstance(inputs, list): + if self._is_list_of_arraylike(inputs): inputs = {k.name: v for k, v in zip(self.inputs, inputs)} - assert isinstance(inputs, dict) + assert self._is_dict_of_arraylike(inputs) model_graph = self.graph exit_node = None @@ -4935,7 +4949,7 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): super(GgmlRuntimeBackend, cls).prepare(model, device, **kwargs) graph = model.graph - weights = {} + weights: Dict[str, ggml.ggml_tensor_p] = {} n_tensors = len(graph.initializer) init_params = ggml.ggml_init_params( From a49553a3b385a178a4311192d7fc4c928c6a3f0b Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 19 Sep 2023 12:50:22 -0400 Subject: [PATCH 165/232] Add single _compute_graph --- ggml/contrib/onnx.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index b6a9635d..c9a8ed37 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4769,17 +4769,19 @@ def __init__( def __del__(self): if hasattr(self, "ggml_context"): ggml.ggml_free(self.ggml_context) - - def eval_tensor( - self, tensor: ggml.ggml_tensor_p, ggml_context: ggml.ggml_context_p - ): - gf = ggml.ggml_build_forward(tensor) + + def _compute_graph(self, gf: ggml.ggml_cgraph): gp = ggml.ggml_graph_plan(ctypes.pointer(gf), 1) work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size else None if gp.work_size: gp.work = ctypes.cast(ctypes.addressof(work_buffer), ctypes.c_void_p) ggml.ggml_graph_compute(ctypes.byref(gf), ctypes.byref(gp)) + def eval_tensor( + self, tensor: ggml.ggml_tensor_p, ggml_context: ggml.ggml_context_p + ): + gf = ggml.ggml_build_forward(tensor) + self._compute_graph(gf) return tensor @staticmethod @@ -4903,11 +4905,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) # Compute graph - gp = ggml.ggml_graph_plan(ctypes.pointer(gf), 1) - work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size else None - if gp.work_size: - gp.work = ctypes.cast(ctypes.addressof(work_buffer), ctypes.c_void_p) - ggml.ggml_graph_compute(gf_p, ctypes.byref(gp)) + self._compute_graph(gf) graph_outputs = [] for output in self.outputs: From c54f2c1ed8e4f49fa4526deab6db1b8edde2c283 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 19 Sep 2023 13:13:49 -0400 Subject: [PATCH 166/232] Move eval_tensor and compute_graph to execution context --- ggml/contrib/onnx.py | 80 ++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index c9a8ed37..9bbd779f 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1167,7 +1167,7 @@ def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): seed = next((attr.i for attr in node.attribute if attr.name == "seed"), 6) if type(training_mode) is ggml.ggml_tensor_p: - training_mode_eval = ctx.backend.eval_tensor(training_mode, ctx.ggml_context) + training_mode_eval = ctx.eval_tensor(training_mode, ctx.ggml_context) training_mode = ctx.to_numpy(training_mode_eval) droput_userdata = DropoutUserData(seed, bool(training_mode)) @@ -1224,7 +1224,7 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) if alpha != 1.0: - Y_eval = ctx.backend.eval_tensor(Y, ctx.ggml_context) + Y_eval = ctx.eval_tensor(Y, ctx.ggml_context) Y_np = ctx.to_numpy(Y_eval) Y_alpha = np.where(Y_np < 0, alpha * Y_np, Y_np) @@ -2470,7 +2470,7 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if "axes" not in ctx.tensors_dict: axes = list(range(input_rank)) else: - axes_eval = ctx.backend.eval_tensor(ctx.tensors_dict["axes"], ctx.ggml_context) + axes_eval = ctx.eval_tensor(ctx.tensors_dict["axes"], ctx.ggml_context) axes = ctx.to_numpy(axes_eval) axes = [axis if axis >= 0 else axis + input_rank for axis in axes] num_axes = len(axes) @@ -2479,7 +2479,7 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): pad_width += [[0, 0]] # init to zero raw_pads = ctx.to_numpy( - ctx.backend.eval_tensor(ctx.tensors_dict["pads"], ctx.ggml_context) + ctx.eval_tensor(ctx.tensors_dict["pads"], ctx.ggml_context) ) # re-order to np.pad accepted order ((x1_begin, x1_end), (x2_begin, x2_end), ...) @@ -2499,7 +2499,7 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): constant_value = None if "value" in ctx.tensors_dict: constant_values = ctx.to_numpy( - ctx.backend.eval_tensor(ctx.tensors_dict["value"], ctx.ggml_context) + ctx.eval_tensor(ctx.tensors_dict["value"], ctx.ggml_context) ) @ggml.ggml_custom2_op_t @@ -2770,7 +2770,7 @@ def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -2858,7 +2858,7 @@ def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -2945,7 +2945,7 @@ def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProt axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3035,7 +3035,7 @@ def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: Node axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3122,7 +3122,7 @@ def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3209,7 +3209,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3296,7 +3296,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3383,7 +3383,7 @@ def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3469,7 +3469,7 @@ def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3556,7 +3556,7 @@ def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeP axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3634,7 +3634,7 @@ def ggml_operator_reshape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] b = node_inputs[1] - eval_b = ctx.backend.eval_tensor(b, ctx.ggml_context) + eval_b = ctx.eval_tensor(b, ctx.ggml_context) new_shape = ggml.utils.to_numpy(eval_b).astype(dtype=np.int32) @@ -3856,19 +3856,19 @@ def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a_shape = ctx.get_tensor_shape(node_inputs[0]) a_dtype = get_tensor_dtype(node_inputs[0]) - starts = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context)) - ends = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[2], ctx.ggml_context)) + starts = ctx.to_numpy(ctx.eval_tensor(node_inputs[1], ctx.ggml_context)) + ends = ctx.to_numpy(ctx.eval_tensor(node_inputs[2], ctx.ggml_context)) dims = len(a_shape) if len(node_inputs) >= 4: - axes = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[3], ctx.ggml_context)) + axes = ctx.to_numpy(ctx.eval_tensor(node_inputs[3], ctx.ggml_context)) else: axes = list(range(len(starts))) axes = [a + dims if a < 0 else a for a in axes] if len(node_inputs) == 5: - steps = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[4], ctx.ggml_context)) + steps = ctx.to_numpy(ctx.eval_tensor(node_inputs[4], ctx.ggml_context)) else: steps = np.ones_like(starts) @@ -4123,7 +4123,7 @@ def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): split_shapes = [tuple(split_shape) for split_shape in split_shapes] else: - split_eval = ctx.backend.eval_tensor(split_tensor, ctx.ggml_context) + split_eval = ctx.eval_tensor(split_tensor, ctx.ggml_context) split_values = ggml.utils.to_numpy(split_eval) split_shapes = [list(input_shape) for _ in range(num_outputs)] @@ -4214,7 +4214,7 @@ def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_shape = get_tensor_shape(data) x_dtype = get_tensor_dtype(data) - axes_eval = ctx.backend.eval_tensor(axes_input, ctx.ggml_context) + axes_eval = ctx.eval_tensor(axes_input, ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) # breakpoint() dummy_data = np.empty(x_shape, dtype=x_dtype) @@ -4340,7 +4340,7 @@ def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x, repeats = node_inputs - repeats_eval = ctx.backend.eval_tensor(repeats, ctx.ggml_context) + repeats_eval = ctx.eval_tensor(repeats, ctx.ggml_context) repeats_vals = ggml.utils.to_numpy(repeats_eval).astype(dtype=np.int32) output_shape = list(get_tensor_shape(x)) @@ -4448,7 +4448,7 @@ def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): largest = next((attr.i for attr in node.attribute if attr.name == "largest"), 1) sorted_flag = next((attr.i for attr in node.attribute if attr.name == "sorted"), 0) - k_eval = ctx.backend.eval_tensor(k, ctx.ggml_context) + k_eval = ctx.eval_tensor(k, ctx.ggml_context) k_np = ggml.utils.to_numpy(k_eval)[0] topk_userdata = TopKUserData(axis, largest, sorted_flag, k_np) @@ -4582,7 +4582,7 @@ def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_dtype = get_tensor_dtype(data) x_ndims = ggml.utils.get_ndims(data) - axes_eval = ctx.backend.eval_tensor(axes_input, ctx.ggml_context) + axes_eval = ctx.eval_tensor(axes_input, ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) axes_values = [ax if ax >= 0 else ax + x_ndims + 1 for ax in axes] @@ -4745,6 +4745,20 @@ def from_numpy(self, array: np.ndarray) -> ggml.ggml_tensor_p: self.set_tensor_shape(tensor, shape) return tensor + def compute_graph(self, gf: ggml.ggml_cgraph): + gp = ggml.ggml_graph_plan(ctypes.pointer(gf), 1) + work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size else None + if gp.work_size: + gp.work = ctypes.cast(ctypes.addressof(work_buffer), ctypes.c_void_p) + ggml.ggml_graph_compute(ctypes.byref(gf), ctypes.byref(gp)) + + def eval_tensor( + self, tensor: ggml.ggml_tensor_p, ggml_context: ggml.ggml_context_p + ): + gf = ggml.ggml_build_forward(tensor) + self.compute_graph(gf) + return tensor + class GgmlBackendRep(BackendRep): def __init__( @@ -4770,20 +4784,6 @@ def __del__(self): if hasattr(self, "ggml_context"): ggml.ggml_free(self.ggml_context) - def _compute_graph(self, gf: ggml.ggml_cgraph): - gp = ggml.ggml_graph_plan(ctypes.pointer(gf), 1) - work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size else None - if gp.work_size: - gp.work = ctypes.cast(ctypes.addressof(work_buffer), ctypes.c_void_p) - ggml.ggml_graph_compute(ctypes.byref(gf), ctypes.byref(gp)) - - def eval_tensor( - self, tensor: ggml.ggml_tensor_p, ggml_context: ggml.ggml_context_p - ): - gf = ggml.ggml_build_forward(tensor) - self._compute_graph(gf) - return tensor - @staticmethod def _is_list_of_arraylike(x: Any) -> TypeGuard[List[npt.ArrayLike]]: return isinstance(x, list) and all( @@ -4905,7 +4905,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) # Compute graph - self._compute_graph(gf) + ctx.compute_graph(gf) graph_outputs = [] for output in self.outputs: From a0a04be17c0538655b0fc574648a5e7ea02ed20a Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 19 Sep 2023 11:58:29 -0700 Subject: [PATCH 167/232] Fix slice --- ggml/contrib/onnx.py | 181 ++++++++++++++++++++++++++-------------- ggml/ggml.py | 12 +++ tests/test_ggml_onnx.py | 1 + 3 files changed, 130 insertions(+), 64 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index d34abde4..40b6acb6 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -522,7 +522,7 @@ def ggml_operator_castlike(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @ggml_operator("Ceil") -def ggml_operator_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): +def ggml_operator_ceil(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: @@ -587,7 +587,7 @@ def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=get_tensor_dtype(node_inputs[0])) x_t = ctx.from_numpy(x) - + @ggml.ggml_custom3_op_t def custom_concat( tensor_out: ggml.ggml_tensor_p, @@ -602,13 +602,14 @@ def custom_concat( b = ctx.to_numpy(tensor_in_3) x = np.concatenate([a, b], axis=axis) set_tensor_out(tensor_out, x) + tensor_a = node_inputs[0] tensor_b = node_inputs[1] new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, tensor_a, - tensor_b, + tensor_b, custom_concat, 1, None, @@ -641,7 +642,6 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): name = node.output[0] value_attr = next(attr for attr in node_attributes if "value" in attr.name) - if value_attr.HasField("t"): tensor = value_attr.t data_type = tensor.data_type @@ -649,7 +649,6 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): np_data_type = tensor_dtype_to_np_dtype(data_type) np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) - if tensor.raw_data: data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) else: @@ -668,10 +667,13 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": Constant node not set correctly or incomplete implantation.' ) - data_tensor = ggml.utils.from_numpy( - data_value.astype(np_data_type_limit), - ctx.ggml_context, - ) + # clamp to 32 bit max/mins + if np_data_type == np.int64: + data_value = np.clip(data_value, np.iinfo(np.int32).min, np.iinfo(np.int32).max) + + data_value = data_value.astype(np_data_type_limit) + + data_tensor = ctx.from_numpy(data_value) tensor_shape = data_value.shape x = np.empty(tensor_shape, dtype=np_data_type_limit) @@ -745,10 +747,8 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP f'Error for node "{node.name}": Constant node not set correctly or incomplete implantation.' ) - data_tensor = ctx.from_numpy( - data_value.astype(np_data_type_limit) - ) - + data_tensor = ctx.from_numpy(data_value.astype(np_data_type_limit)) + ctx.backend.eval_tensor(node_inputs[0], ctx.ggml_context) shape = ctx.to_numpy(node_inputs[0]) x = np.empty(shape, dtype=np_data_type_limit) @@ -1324,6 +1324,45 @@ def custom_exp( return new_tensor +@ggml_operator("Expand") +def ggml_operator_expand(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + + a_shape = get_tensor_shape(node_inputs[0]) + target_shape = ctx.to_numpy( + ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context) + ) + new_shape = np.broadcast(np.empty(a_shape), np.empty(target_shape)).shape + + x = np.empty(new_shape, dtype=get_tensor_dtype(node_inputs[0])) + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom2_op_t + def custom_expand( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ctx.to_numpy(tensor_in_2) + expanded = a * np.ones(new_shape, dtype=get_tensor_dtype(tensor_in_2)) + + set_tensor_out(tensor_out, expanded) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, + x_t, + node_inputs[0], + custom_expand, + 1, + None, + ) + ctx.refs.append(custom_expand) + return new_tensor + + @ggml.ggml_custom2_op_t def custom_flatten( tensor_out: ggml.ggml_tensor_p, @@ -1678,7 +1717,7 @@ def custom_hard_sigmoid( @ggml_operator("HardSigmoid") -def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): +def ggml_operator_hardsigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: @@ -2680,8 +2719,10 @@ def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": Operation "Range" requires exactly three inputs. Actual number of inputs: {len(node_inputs)}' ) - tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + for node_input in node_inputs: + ctx.backend.eval_tensor(node_input, ctx.ggml_context) + tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] start, stop, step = tensors output_shape = (int(np.ceil((stop - start) / step)),) @@ -3848,32 +3889,36 @@ def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return new_tensor + @ggml_operator("Slice") def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] a_shape = ctx.get_tensor_shape(node_inputs[0]) a_dtype = get_tensor_dtype(node_inputs[0]) + dims = len(a_shape) + starts = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context)) ends = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[2], ctx.ggml_context)) - dims = len(a_shape) if len(node_inputs) >= 4: axes = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[3], ctx.ggml_context)) else: axes = list(range(len(starts))) - axes = [a + dims if a < 0 else a for a in axes] - if len(node_inputs) == 5: steps = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[4], ctx.ggml_context)) else: steps = np.ones_like(starts) - - slices = [slice(start,end, step) for start, end, step in zip(starts, ends, steps)] + axes_sizes = [a_shape[i] for i in axes] + starts = [a + size if a < 0 else a for a, size in zip(starts, axes_sizes)] + ends = [a + size if a < 0 else a for a, size in zip(ends, axes_sizes)] + axes = [a + dims if a < 0 else a for a in axes] + + slices = [slice(start, end, step) for start, end, step in zip(starts, ends, steps)] all_slices = [] + for axis in range(dims): if axis not in axes: all_slices.append(slice(None)) @@ -3882,30 +3927,28 @@ def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(a_shape, dtype=a_dtype)[tuple(all_slices)].copy() x_t = ctx.from_numpy(x) - + @ggml.ggml_custom2_op_t - def custom_slice(tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p]): + def custom_slice( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): x = ggml.utils.to_numpy(tensor_in_2) y = x[tuple(all_slices)].copy() set_tensor_out(tensor_out, y) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, - x_t, - node_inputs[0], - custom_slice, - 1, - None + ctx.ggml_context, x_t, node_inputs[0], custom_slice, 1, None ) ctx.refs.append(custom_slice) return new_tensor - + + @ggml_operator("Softmax") def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4184,24 +4227,6 @@ def ggml_operator_sqrt(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return sqrt_result -@ggml.ggml_custom3_op_t -def custom_squeeze( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - axes = ggml.utils.to_numpy(tensor_in_3) - - y = np.squeeze(x, axis=axes[0]) - - set_tensor_out(tensor_out, y) - - @ggml_operator("Squeeze") def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4212,13 +4237,11 @@ def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) data, axes_input = node_inputs - x_shape = get_tensor_shape(data) x_dtype = get_tensor_dtype(data) axes_eval = ctx.backend.eval_tensor(axes_input, ctx.ggml_context) axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) - # breakpoint() dummy_data = np.empty(x_shape, dtype=x_dtype) dummy_data = np.squeeze(dummy_data, axis=axes[0]) @@ -4227,7 +4250,22 @@ def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": {len(dummy_data.shape)}D arrays are not allowed.' ) - x_t = ggml.utils.from_numpy(dummy_data, ctx.ggml_context) + x_t = ctx.from_numpy(dummy_data) + + @ggml.ggml_custom3_op_t + def custom_squeeze( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ctx.to_numpy(tensor_in_2) + axes = ctx.to_numpy(tensor_in_3) + y = np.squeeze(x, axis=axes[0]) + set_tensor_out(tensor_out, y) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -4238,7 +4276,7 @@ def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, None, ) - + ctx.refs.append(custom_squeeze) return new_tensor @@ -4729,7 +4767,7 @@ def __init__( def set_tensor_shape(self, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...]): data = tensor.contents.data self.shapes[data] = shape - + def get_tensor_shape(self, tensor: ggml.ggml_tensor_p) -> Tuple[int, ...]: data = tensor.contents.data if data not in self.shapes: @@ -4747,6 +4785,15 @@ def from_numpy(self, array: np.ndarray) -> ggml.ggml_tensor_p: self.set_tensor_shape(tensor, shape) return tensor + def set_tensor_out(self, tensor: ggml.ggml_tensor_p, array: np.ndarray): + output_shape = get_tensor_shape(tensor) + + if output_shape == (): + self.to_numpy(tensor)[()] = array + else: + self.to_numpy(tensor)[:] = array + + class GgmlBackendRep(BackendRep): def __init__( self, @@ -4795,10 +4842,14 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: exit_node = None ggml_tensors = self.weights - input_context = ggml.ggml_init(params=ggml.ggml_init_params( - mem_size=2 * ggml.GGML_MAX_NODES * ggml.ggml_tensor_overhead(), # FIXME: Reduce to n inputs or combine with tensors context - no_alloc=True, - )) + input_context = ggml.ggml_init( + params=ggml.ggml_init_params( + mem_size=2 + * ggml.GGML_MAX_NODES + * ggml.ggml_tensor_overhead(), # FIXME: Reduce to n inputs or combine with tensors context + no_alloc=True, + ) + ) input_buffer_size = 0 # Create entry inputs @@ -4846,7 +4897,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: input_buffer_size += ggml.ggml_nbytes_pad(tensor) ggml_tensors[input_name] = tensor - + input_buffer = (ctypes.c_uint8 * input_buffer_size)() input_buffer_offset = 0 @@ -4860,7 +4911,9 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: set_tensor_out(tensor, np.array(value)) # Define context - ggml_context = ggml.ggml_init(params=ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None)) + ggml_context = ggml.ggml_init( + params=ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + ) refs: List[Any] = [] diff --git a/ggml/ggml.py b/ggml/ggml.py index 6077134d..66687570 100644 --- a/ggml/ggml.py +++ b/ggml/ggml.py @@ -570,6 +570,7 @@ class ggml_object(ctypes.Structure): # void * extra; // extra things e.g. for ggml-cuda.cu + # char padding[4]; # }; class ggml_tensor(ctypes.Structure): @@ -5434,6 +5435,7 @@ def ggml_build_forward_expand( ] lib.ggml_build_forward_expand.restype = None + # GGML_API void ggml_build_backward_expand(struct ggml_context * ctx, struct ggml_cgraph * gf, struct ggml_cgraph * gb, bool keep); def ggml_build_backward_expand( ctx: ggml_context_p, @@ -5451,6 +5453,7 @@ def ggml_build_backward_expand( keep: Whether to keep the tensor.""" return lib.ggml_build_backward_expand(ctx, gf, gb, keep) + lib.ggml_build_backward_expand.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_cgraph), @@ -5459,6 +5462,7 @@ def ggml_build_backward_expand( ] lib.ggml_build_backward_expand.restype = None + # GGML_API struct ggml_cgraph ggml_build_forward (struct ggml_tensor * tensor); def ggml_build_forward( tensor: ggml_tensor_p, @@ -6006,6 +6010,7 @@ def ggml_opt_init( ): return lib.ggml_opt_init(ctx, opt, params, nx) + lib.ggml_opt_init.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_opt_context), @@ -6014,6 +6019,7 @@ def ggml_opt_init( ] lib.ggml_opt_init.restype = None + # // continue optimizing the function defined by the tensor f # GGML_API enum ggml_opt_result ggml_opt_resume( # struct ggml_context * ctx, @@ -6044,6 +6050,7 @@ def ggml_opt_resume( # ggml_opt_callback callback, # void * callback_data); + # // continue optimizing the function defined by the tensor f # GGML_API enum ggml_opt_result ggml_opt_resume_g( # struct ggml_context * ctx, @@ -6062,6 +6069,7 @@ def ggml_opt_resume_g( ) -> int: return lib.ggml_opt_resume_g(ctx, opt, f, gf, gb, callback, callback_data) + lib.ggml_opt_resume_g.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_opt_context), @@ -6536,6 +6544,7 @@ def gguf_get_val_f32( ] lib.gguf_get_val_f32.restype = ctypes.c_float + # GGML_API uint64_t gguf_get_val_u64 (const struct gguf_context * ctx, int i); def gguf_get_val_u64( ctx: gguf_context_p, @@ -6550,6 +6559,7 @@ def gguf_get_val_u64( ] lib.gguf_get_val_u64.restype = ctypes.c_uint64 + # GGML_API int64_t gguf_get_val_i64 (const struct gguf_context * ctx, int i); def gguf_get_val_i64( ctx: gguf_context_p, @@ -6564,6 +6574,7 @@ def gguf_get_val_i64( ] lib.gguf_get_val_i64.restype = ctypes.c_int64 + # GGML_API double gguf_get_val_f64 (const struct gguf_context * ctx, int i); def gguf_get_val_f64( ctx: gguf_context_p, @@ -6578,6 +6589,7 @@ def gguf_get_val_f64( ] lib.gguf_get_val_f64.restype = ctypes.c_double + # GGML_API bool gguf_get_val_bool(const struct gguf_context * ctx, int i); def gguf_get_val_bool( ctx: gguf_context_p, diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index e97122a4..8cf84adb 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -345,6 +345,7 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_exp_") backend_test.include("test_operator_exp_") +backend_test.include("test_expand_") backend_test.include("test_flatten_") backend_test.include("test_operator_flatten_") From 732e65c854aa02ede0354db23817b08ee7078326 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 19 Sep 2023 12:14:06 -0700 Subject: [PATCH 168/232] Fix Constant operator --- ggml/contrib/onnx.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 40b6acb6..c4612741 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -645,7 +645,7 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if value_attr.HasField("t"): tensor = value_attr.t data_type = tensor.data_type - dims = tensor.dims[0] if tensor.dims else 0 + dims = tensor.dims np_data_type = tensor_dtype_to_np_dtype(data_type) np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) @@ -654,6 +654,8 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): else: data_value = onnx.numpy_helper.to_array(tensor) + data_value = data_value.reshape(dims) + else: data_type = value_attr.type np_data_type = tensor_dtype_to_np_dtype(data_type) @@ -688,8 +690,6 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, None, ) - if dims == 0: - ctx.set_tensor_shape(new_tensor, ()) ggml.ggml_set_name(new_tensor, (name + f"<{np_data_type}>").encode()) return new_tensor @@ -3900,7 +3900,6 @@ def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): starts = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[1], ctx.ggml_context)) ends = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[2], ctx.ggml_context)) - if len(node_inputs) >= 4: axes = ctx.to_numpy(ctx.backend.eval_tensor(node_inputs[3], ctx.ggml_context)) else: @@ -3911,10 +3910,11 @@ def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): else: steps = np.ones_like(starts) + axes = [a + dims if a < 0 else a for a in axes] axes_sizes = [a_shape[i] for i in axes] starts = [a + size if a < 0 else a for a, size in zip(starts, axes_sizes)] ends = [a + size if a < 0 else a for a, size in zip(ends, axes_sizes)] - axes = [a + dims if a < 0 else a for a in axes] + slices = [slice(start, end, step) for start, end, step in zip(starts, ends, steps)] all_slices = [] From 1aaa1f3ed7c7c870ff0c4af0c16c6fa1bb2b636d Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 19 Sep 2023 16:47:12 -0400 Subject: [PATCH 169/232] Merge branch 'onnx-backend' of github.com:abetlen/ggml-python into onnx-backend --- ggml/contrib/onnx.py | 178 +++++++++++++++++++++++++--------------- ggml/ggml.py | 12 +++ tests/test_ggml_onnx.py | 1 + 3 files changed, 127 insertions(+), 64 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 9bbd779f..2955a265 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -524,7 +524,7 @@ def ggml_operator_castlike(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @ggml_operator("Ceil") -def ggml_operator_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): +def ggml_operator_ceil(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: @@ -644,20 +644,20 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): name = node.output[0] value_attr = next(attr for attr in node_attributes if "value" in attr.name) - if value_attr.HasField("t"): tensor = value_attr.t data_type = tensor.data_type - dims = tensor.dims[0] if tensor.dims else 0 + dims = tensor.dims np_data_type = tensor_dtype_to_np_dtype(data_type) np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) - if tensor.raw_data: data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) else: data_value = onnx.numpy_helper.to_array(tensor) + data_value = data_value.reshape(dims) + else: data_type = value_attr.type np_data_type = tensor_dtype_to_np_dtype(data_type) @@ -671,10 +671,13 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": Constant node not set correctly or incomplete implantation.' ) - data_tensor = ggml.utils.from_numpy( - data_value.astype(np_data_type_limit), - ctx.ggml_context, - ) + # clamp to 32 bit max/mins + if np_data_type == np.int64: + data_value = np.clip(data_value, np.iinfo(np.int32).min, np.iinfo(np.int32).max) + + data_value = data_value.astype(np_data_type_limit) + + data_tensor = ctx.from_numpy(data_value) tensor_shape = data_value.shape x = np.empty(tensor_shape, dtype=np_data_type_limit) @@ -689,8 +692,6 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, None, ) - if dims == 0: - ctx.set_tensor_shape(new_tensor, ()) ggml.ggml_set_name(new_tensor, (name + f"<{np_data_type}>").encode()) return new_tensor @@ -749,7 +750,7 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP ) data_tensor = ctx.from_numpy(data_value.astype(np_data_type_limit)) - + ctx.eval_tensor(node_inputs[0]) shape = ctx.to_numpy(node_inputs[0]) x = np.empty(shape, dtype=np_data_type_limit) @@ -1167,7 +1168,7 @@ def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): seed = next((attr.i for attr in node.attribute if attr.name == "seed"), 6) if type(training_mode) is ggml.ggml_tensor_p: - training_mode_eval = ctx.eval_tensor(training_mode, ctx.ggml_context) + training_mode_eval = ctx.eval_tensor(training_mode,) training_mode = ctx.to_numpy(training_mode_eval) droput_userdata = DropoutUserData(seed, bool(training_mode)) @@ -1224,7 +1225,7 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) if alpha != 1.0: - Y_eval = ctx.eval_tensor(Y, ctx.ggml_context) + Y_eval = ctx.eval_tensor(Y,) Y_np = ctx.to_numpy(Y_eval) Y_alpha = np.where(Y_np < 0, alpha * Y_np, Y_np) @@ -1325,6 +1326,45 @@ def custom_exp( return new_tensor +@ggml_operator("Expand") +def ggml_operator_expand(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + + a_shape = get_tensor_shape(node_inputs[0]) + target_shape = ctx.to_numpy( + ctx.eval_tensor(node_inputs[1]) + ) + new_shape = np.broadcast(np.empty(a_shape), np.empty(target_shape)).shape + + x = np.empty(new_shape, dtype=get_tensor_dtype(node_inputs[0])) + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom2_op_t + def custom_expand( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ctx.to_numpy(tensor_in_2) + expanded = a * np.ones(new_shape, dtype=get_tensor_dtype(tensor_in_2)) + + set_tensor_out(tensor_out, expanded) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, + x_t, + node_inputs[0], + custom_expand, + 1, + None, + ) + ctx.refs.append(custom_expand) + return new_tensor + + @ggml.ggml_custom2_op_t def custom_flatten( tensor_out: ggml.ggml_tensor_p, @@ -1679,7 +1719,7 @@ def custom_hard_sigmoid( @ggml_operator("HardSigmoid") -def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): +def ggml_operator_hardsigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: @@ -2470,7 +2510,7 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if "axes" not in ctx.tensors_dict: axes = list(range(input_rank)) else: - axes_eval = ctx.eval_tensor(ctx.tensors_dict["axes"], ctx.ggml_context) + axes_eval = ctx.eval_tensor(ctx.tensors_dict["axes"]) axes = ctx.to_numpy(axes_eval) axes = [axis if axis >= 0 else axis + input_rank for axis in axes] num_axes = len(axes) @@ -2479,7 +2519,7 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): pad_width += [[0, 0]] # init to zero raw_pads = ctx.to_numpy( - ctx.eval_tensor(ctx.tensors_dict["pads"], ctx.ggml_context) + ctx.eval_tensor(ctx.tensors_dict["pads"]) ) # re-order to np.pad accepted order ((x1_begin, x1_end), (x2_begin, x2_end), ...) @@ -2499,7 +2539,7 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): constant_value = None if "value" in ctx.tensors_dict: constant_values = ctx.to_numpy( - ctx.eval_tensor(ctx.tensors_dict["value"], ctx.ggml_context) + ctx.eval_tensor(ctx.tensors_dict["value"]) ) @ggml.ggml_custom2_op_t @@ -2681,8 +2721,10 @@ def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": Operation "Range" requires exactly three inputs. Actual number of inputs: {len(node_inputs)}' ) - tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + for node_input in node_inputs: + ctx.backend.eval_tensor(node_input,) + tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] start, stop, step = tensors output_shape = (int(np.ceil((stop - start) / step)),) @@ -2770,7 +2812,7 @@ def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1]) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -2858,7 +2900,7 @@ def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1]) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -2945,7 +2987,7 @@ def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProt axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1]) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3035,7 +3077,7 @@ def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: Node axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1]) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3122,7 +3164,7 @@ def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1]) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3209,7 +3251,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1]) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3296,7 +3338,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1]) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3383,7 +3425,7 @@ def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1]) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3469,7 +3511,7 @@ def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1]) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3556,7 +3598,7 @@ def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeP axes = next((attr.ints for attr in node.attribute if attr.name == "axes"), None) if not axes: if len(node_inputs) > 1: - axes_eval = ctx.eval_tensor(node_inputs[1], ctx.ggml_context) + axes_eval = ctx.eval_tensor(node_inputs[1]) axes = ggml.utils.to_numpy(axes_eval) else: axes = [] @@ -3634,7 +3676,7 @@ def ggml_operator_reshape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] b = node_inputs[1] - eval_b = ctx.eval_tensor(b, ctx.ggml_context) + eval_b = ctx.eval_tensor(b,) new_shape = ggml.utils.to_numpy(eval_b).astype(dtype=np.int32) @@ -3856,24 +3898,29 @@ def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a_shape = ctx.get_tensor_shape(node_inputs[0]) a_dtype = get_tensor_dtype(node_inputs[0]) - starts = ctx.to_numpy(ctx.eval_tensor(node_inputs[1], ctx.ggml_context)) - ends = ctx.to_numpy(ctx.eval_tensor(node_inputs[2], ctx.ggml_context)) - dims = len(a_shape) + + starts = ctx.to_numpy(ctx.eval_tensor(node_inputs[1])) + ends = ctx.to_numpy(ctx.eval_tensor(node_inputs[2])) if len(node_inputs) >= 4: - axes = ctx.to_numpy(ctx.eval_tensor(node_inputs[3], ctx.ggml_context)) + axes = ctx.to_numpy(ctx.eval_tensor(node_inputs[3])) else: axes = list(range(len(starts))) - axes = [a + dims if a < 0 else a for a in axes] - if len(node_inputs) == 5: - steps = ctx.to_numpy(ctx.eval_tensor(node_inputs[4], ctx.ggml_context)) + steps = ctx.to_numpy(ctx.eval_tensor(node_inputs[4])) else: steps = np.ones_like(starts) + axes = [a + dims if a < 0 else a for a in axes] + axes_sizes = [a_shape[i] for i in axes] + starts = [a + size if a < 0 else a for a, size in zip(starts, axes_sizes)] + ends = [a + size if a < 0 else a for a, size in zip(ends, axes_sizes)] + + slices = [slice(start, end, step) for start, end, step in zip(starts, ends, steps)] all_slices = [] + for axis in range(dims): if axis not in axes: all_slices.append(slice(None)) @@ -4123,7 +4170,7 @@ def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): split_shapes = [tuple(split_shape) for split_shape in split_shapes] else: - split_eval = ctx.eval_tensor(split_tensor, ctx.ggml_context) + split_eval = ctx.eval_tensor(split_tensor,) split_values = ggml.utils.to_numpy(split_eval) split_shapes = [list(input_shape) for _ in range(num_outputs)] @@ -4182,24 +4229,6 @@ def ggml_operator_sqrt(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return sqrt_result -@ggml.ggml_custom3_op_t -def custom_squeeze( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - axes = ggml.utils.to_numpy(tensor_in_3) - - y = np.squeeze(x, axis=axes[0]) - - set_tensor_out(tensor_out, y) - - @ggml_operator("Squeeze") def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4210,13 +4239,11 @@ def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) data, axes_input = node_inputs - x_shape = get_tensor_shape(data) x_dtype = get_tensor_dtype(data) - axes_eval = ctx.eval_tensor(axes_input, ctx.ggml_context) + axes_eval = ctx.eval_tensor(axes_input,) axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) - # breakpoint() dummy_data = np.empty(x_shape, dtype=x_dtype) dummy_data = np.squeeze(dummy_data, axis=axes[0]) @@ -4225,7 +4252,22 @@ def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": {len(dummy_data.shape)}D arrays are not allowed.' ) - x_t = ggml.utils.from_numpy(dummy_data, ctx.ggml_context) + x_t = ctx.from_numpy(dummy_data) + + @ggml.ggml_custom3_op_t + def custom_squeeze( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ctx.to_numpy(tensor_in_2) + axes = ctx.to_numpy(tensor_in_3) + y = np.squeeze(x, axis=axes[0]) + set_tensor_out(tensor_out, y) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -4236,7 +4278,7 @@ def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, None, ) - + ctx.refs.append(custom_squeeze) return new_tensor @@ -4340,7 +4382,7 @@ def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x, repeats = node_inputs - repeats_eval = ctx.eval_tensor(repeats, ctx.ggml_context) + repeats_eval = ctx.eval_tensor(repeats,) repeats_vals = ggml.utils.to_numpy(repeats_eval).astype(dtype=np.int32) output_shape = list(get_tensor_shape(x)) @@ -4448,7 +4490,7 @@ def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): largest = next((attr.i for attr in node.attribute if attr.name == "largest"), 1) sorted_flag = next((attr.i for attr in node.attribute if attr.name == "sorted"), 0) - k_eval = ctx.eval_tensor(k, ctx.ggml_context) + k_eval = ctx.eval_tensor(k,) k_np = ggml.utils.to_numpy(k_eval)[0] topk_userdata = TopKUserData(axis, largest, sorted_flag, k_np) @@ -4582,7 +4624,7 @@ def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_dtype = get_tensor_dtype(data) x_ndims = ggml.utils.get_ndims(data) - axes_eval = ctx.eval_tensor(axes_input, ctx.ggml_context) + axes_eval = ctx.eval_tensor(axes_input,) axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) axes_values = [ax if ax >= 0 else ax + x_ndims + 1 for ax in axes] @@ -4753,12 +4795,20 @@ def compute_graph(self, gf: ggml.ggml_cgraph): ggml.ggml_graph_compute(ctypes.byref(gf), ctypes.byref(gp)) def eval_tensor( - self, tensor: ggml.ggml_tensor_p, ggml_context: ggml.ggml_context_p + self, tensor: ggml.ggml_tensor_p ): gf = ggml.ggml_build_forward(tensor) self.compute_graph(gf) return tensor + def set_tensor_out(self, tensor: ggml.ggml_tensor_p, array: np.ndarray): + output_shape = get_tensor_shape(tensor) + + if output_shape == (): + self.to_numpy(tensor)[()] = array + else: + self.to_numpy(tensor)[:] = array + class GgmlBackendRep(BackendRep): def __init__( diff --git a/ggml/ggml.py b/ggml/ggml.py index 6077134d..66687570 100644 --- a/ggml/ggml.py +++ b/ggml/ggml.py @@ -570,6 +570,7 @@ class ggml_object(ctypes.Structure): # void * extra; // extra things e.g. for ggml-cuda.cu + # char padding[4]; # }; class ggml_tensor(ctypes.Structure): @@ -5434,6 +5435,7 @@ def ggml_build_forward_expand( ] lib.ggml_build_forward_expand.restype = None + # GGML_API void ggml_build_backward_expand(struct ggml_context * ctx, struct ggml_cgraph * gf, struct ggml_cgraph * gb, bool keep); def ggml_build_backward_expand( ctx: ggml_context_p, @@ -5451,6 +5453,7 @@ def ggml_build_backward_expand( keep: Whether to keep the tensor.""" return lib.ggml_build_backward_expand(ctx, gf, gb, keep) + lib.ggml_build_backward_expand.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_cgraph), @@ -5459,6 +5462,7 @@ def ggml_build_backward_expand( ] lib.ggml_build_backward_expand.restype = None + # GGML_API struct ggml_cgraph ggml_build_forward (struct ggml_tensor * tensor); def ggml_build_forward( tensor: ggml_tensor_p, @@ -6006,6 +6010,7 @@ def ggml_opt_init( ): return lib.ggml_opt_init(ctx, opt, params, nx) + lib.ggml_opt_init.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_opt_context), @@ -6014,6 +6019,7 @@ def ggml_opt_init( ] lib.ggml_opt_init.restype = None + # // continue optimizing the function defined by the tensor f # GGML_API enum ggml_opt_result ggml_opt_resume( # struct ggml_context * ctx, @@ -6044,6 +6050,7 @@ def ggml_opt_resume( # ggml_opt_callback callback, # void * callback_data); + # // continue optimizing the function defined by the tensor f # GGML_API enum ggml_opt_result ggml_opt_resume_g( # struct ggml_context * ctx, @@ -6062,6 +6069,7 @@ def ggml_opt_resume_g( ) -> int: return lib.ggml_opt_resume_g(ctx, opt, f, gf, gb, callback, callback_data) + lib.ggml_opt_resume_g.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_opt_context), @@ -6536,6 +6544,7 @@ def gguf_get_val_f32( ] lib.gguf_get_val_f32.restype = ctypes.c_float + # GGML_API uint64_t gguf_get_val_u64 (const struct gguf_context * ctx, int i); def gguf_get_val_u64( ctx: gguf_context_p, @@ -6550,6 +6559,7 @@ def gguf_get_val_u64( ] lib.gguf_get_val_u64.restype = ctypes.c_uint64 + # GGML_API int64_t gguf_get_val_i64 (const struct gguf_context * ctx, int i); def gguf_get_val_i64( ctx: gguf_context_p, @@ -6564,6 +6574,7 @@ def gguf_get_val_i64( ] lib.gguf_get_val_i64.restype = ctypes.c_int64 + # GGML_API double gguf_get_val_f64 (const struct gguf_context * ctx, int i); def gguf_get_val_f64( ctx: gguf_context_p, @@ -6578,6 +6589,7 @@ def gguf_get_val_f64( ] lib.gguf_get_val_f64.restype = ctypes.c_double + # GGML_API bool gguf_get_val_bool(const struct gguf_context * ctx, int i); def gguf_get_val_bool( ctx: gguf_context_p, diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index e97122a4..8cf84adb 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -345,6 +345,7 @@ def test_ggml_onnx_runtime_quantized(): backend_test.include("test_exp_") backend_test.include("test_operator_exp_") +backend_test.include("test_expand_") backend_test.include("test_flatten_") backend_test.include("test_operator_flatten_") From 1c2972e49a550770f08d8c55056a1c1b0387138c Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 19 Sep 2023 17:58:48 -0400 Subject: [PATCH 170/232] Use closures for custom operators --- ggml/contrib/onnx.py | 2109 +++++++++++++++++++++++------------------- 1 file changed, 1138 insertions(+), 971 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index e3ccd31c..810b3829 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -202,22 +202,6 @@ def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return add_result -@ggml.ggml_custom3_op_t -def custom_and( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) - - x = np.logical_and(a, b) - - set_tensor_out(tensor_out, x) @ggml_operator("And") @@ -239,6 +223,23 @@ def ggml_operator_and(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=a_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom3_op_t + def custom_and( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.logical_and(a, b) + + ctx.set_tensor_out(tensor_out, x) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, @@ -248,6 +249,7 @@ def ggml_operator_and(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, None, ) + ctx.refs.append(custom_and) ggml.ggml_set_name(new_tensor, (name + f"").encode()) @@ -262,37 +264,6 @@ class ArgOpsUserData(ctypes.Structure): ] -@ggml.ggml_custom2_op_t -def custom_arg_max( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ArgOpsUserData)) - userdata_data = userdata_data_ptr.contents - - axis = userdata_data.axis - keepdims = userdata_data.keepdims - select_last_index = userdata_data.select_last_index - - if select_last_index: - x = np.flip(x, axis) - - y = np.argmax(x, axis=axis) - - if select_last_index: - y = x.shape[axis] - y - 1 - - if keepdims: - y = np.expand_dims(y, axis) - - y = y.astype(np.int32) - - set_tensor_out(tensor_out, y) @ggml_operator("ArgMax") @@ -337,6 +308,38 @@ def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): argmax_userdata = ArgOpsUserData(axis, keepdims, select_last_index) userdata_p = ctypes.cast(ctypes.pointer(argmax_userdata), ctypes.c_void_p) + @ggml.ggml_custom2_op_t + def custom_arg_max( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_2) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ArgOpsUserData)) + userdata_data = userdata_data_ptr.contents + + axis = userdata_data.axis + keepdims = userdata_data.keepdims + select_last_index = userdata_data.select_last_index + + if select_last_index: + x = np.flip(x, axis) + + y = np.argmax(x, axis=axis) + + if select_last_index: + y = x.shape[axis] - y - 1 + + if keepdims: + y = np.expand_dims(y, axis) + + y = y.astype(np.int32) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -345,6 +348,7 @@ def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, userdata_p, ) + ctx.refs.append(custom_arg_max) ggml.ggml_set_name(new_tensor, (name + "").encode()) ctx.refs.append(argmax_userdata) @@ -352,37 +356,6 @@ def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return new_tensor -@ggml.ggml_custom2_op_t -def custom_arg_min( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ArgOpsUserData)) - userdata_data = userdata_data_ptr.contents - - axis = userdata_data.axis - keepdims = userdata_data.keepdims - select_last_index = userdata_data.select_last_index - - if select_last_index: - x = np.flip(x, axis) - - y = np.argmin(x, axis=axis) - - if select_last_index: - y = x.shape[axis] - y - 1 - - if keepdims: - y = np.expand_dims(y, axis) - - y = y.astype(np.int32) - - set_tensor_out(tensor_out, y) @ggml_operator("ArgMin") @@ -425,6 +398,38 @@ def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): argmax_userdata = ArgOpsUserData(axis, keepdims, select_last_index) userdata_p = ctypes.cast(ctypes.pointer(argmax_userdata), ctypes.c_void_p) + @ggml.ggml_custom2_op_t + def custom_arg_min( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_2) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ArgOpsUserData)) + userdata_data = userdata_data_ptr.contents + + axis = userdata_data.axis + keepdims = userdata_data.keepdims + select_last_index = userdata_data.select_last_index + + if select_last_index: + x = np.flip(x, axis) + + y = np.argmin(x, axis=axis) + + if select_last_index: + y = x.shape[axis] - y - 1 + + if keepdims: + y = np.expand_dims(y, axis) + + y = y.astype(np.int32) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -433,6 +438,7 @@ def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, userdata_p, ) + ctx.refs.append(custom_arg_min) ggml.ggml_set_name(new_tensor, (name + "").encode()) ctx.refs.append(argmax_userdata) @@ -440,21 +446,6 @@ def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return new_tensor -@ggml.ggml_custom2_op_t -def custom_cast( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - dtype = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value - tensor = ggml.utils.to_numpy(tensor_in_2) - np_data_type = tensor_dtype_to_np_dtype(dtype) - np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) - - set_tensor_out(tensor_out, tensor.astype(np_data_type_limit)) @ggml_operator("Cast") @@ -476,6 +467,22 @@ def ggml_operator_cast(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_cast( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + dtype = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + tensor = ggml.utils.to_numpy(tensor_in_2) + np_data_type = tensor_dtype_to_np_dtype(dtype) + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + + ctx.set_tensor_out(tensor_out, tensor.astype(np_data_type_limit)) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -485,6 +492,8 @@ def ggml_operator_cast(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctypes.pointer(onnx_type_c), ) + ctx.refs.append(custom_cast) + ctx.refs.append(onnx_type_c) return new_tensor @@ -509,6 +518,23 @@ def ggml_operator_castlike(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(get_tensor_shape(a), dtype=np_data_type_limit) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_cast( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + dtype = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + tensor = ggml.utils.to_numpy(tensor_in_2) + np_data_type = tensor_dtype_to_np_dtype(dtype) + np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) + + ctx.set_tensor_out(tensor_out, tensor.astype(np_data_type_limit)) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -518,6 +544,8 @@ def ggml_operator_castlike(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctypes.pointer(onnx_type_c), ) + ctx.refs.append(custom_cast) + ctx.refs.append(onnx_type_c) return new_tensor @@ -547,7 +575,7 @@ def custom_ceil( ): tensor = ctx.to_numpy(tensor_in_1) x = np.ceil(tensor) - set_tensor_out(tensor_out, np.array(x)) + ctx.set_tensor_out(tensor_out, np.array(x)) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, @@ -603,7 +631,7 @@ def custom_concat( a = ctx.to_numpy(tensor_in_2) b = ctx.to_numpy(tensor_in_3) x = np.concatenate([a, b], axis=axis) - set_tensor_out(tensor_out, x) + ctx.set_tensor_out(tensor_out, x) tensor_a = node_inputs[0] tensor_b = node_inputs[1] @@ -622,20 +650,6 @@ def custom_concat( return new_tensor -@ggml.ggml_custom2_op_t -def custom_constant( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - shape = get_tensor_shape(tensor_in_1) - constant_data = ggml.utils.to_numpy(tensor_in_2) - new_tenor = constant_data.reshape(shape) - - set_tensor_out(tensor_out, new_tenor) @ggml_operator("Constant") @@ -684,6 +698,21 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_constant( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + shape = get_tensor_shape(tensor_in_1) + constant_data = ggml.utils.to_numpy(tensor_in_2) + new_tenor = constant_data.reshape(shape) + + ctx.set_tensor_out(tensor_out, new_tenor) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -692,25 +721,12 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, None, ) + ctx.refs.append(custom_constant) ggml.ggml_set_name(new_tensor, (name + f"<{np_data_type}>").encode()) return new_tensor -@ggml.ggml_custom2_op_t -def custom_constant_of_shape( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - shape = get_tensor_shape(tensor_out) - value = ggml.utils.to_numpy(tensor_in_2) - new_tenor = np.full(tuple(shape), value) - - set_tensor_out(tensor_out, new_tenor) @ggml_operator("ConstantOfShape") @@ -756,6 +772,21 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP x = np.empty(shape, dtype=np_data_type_limit) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_constant_of_shape( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + shape = get_tensor_shape(tensor_out) + value = ggml.utils.to_numpy(tensor_in_2) + new_tenor = np.full(tuple(shape), value) + + ctx.set_tensor_out(tensor_out, new_tenor) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -765,6 +796,8 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP None, ) + ctx.refs.append(custom_constant_of_shape) + return new_tensor @@ -965,42 +998,6 @@ class DepthToSpaceUserData(ctypes.Structure): ] -@ggml.ggml_custom2_op_t -def custom_depth_to_space( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DepthToSpaceUserData)) - userdata_data = userdata_data_ptr.contents - - blocksize = userdata_data.blocksize - mode = userdata_data.mode - - N, C, H, W = x.shape - - new_C = C // (blocksize**2) - new_H = H * blocksize - new_W = W * blocksize - - if mode == b"DCR": - reshaped = x.reshape(N, blocksize, blocksize, C // (blocksize**2), H, W) - transposed_axes = (0, 3, 4, 1, 5, 2) - - elif mode == b"CRD": - reshaped = x.reshape(N, C // (blocksize**2), blocksize, blocksize, H, W) - transposed_axes = (0, 1, 4, 2, 5, 3) - else: - raise ValueError(f"Unknown mode: {mode}") - - transposed = np.transpose(reshaped, axes=transposed_axes) - y = transposed.reshape(N, new_C, new_H, new_W) - - set_tensor_out(tensor_out, y) @ggml_operator("DepthToSpace") @@ -1038,6 +1035,43 @@ def ggml_operator_depth_to_space(ctx: "GgmlOnnxExecutionContext", node: NodeProt depthtospace_userdata = DepthToSpaceUserData(blocksize, mode) userdata_p = ctypes.cast(ctypes.pointer(depthtospace_userdata), ctypes.c_void_p) + @ggml.ggml_custom2_op_t + def custom_depth_to_space( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_2) + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DepthToSpaceUserData)) + userdata_data = userdata_data_ptr.contents + + blocksize = userdata_data.blocksize + mode = userdata_data.mode + + N, C, H, W = x.shape + + new_C = C // (blocksize**2) + new_H = H * blocksize + new_W = W * blocksize + + if mode == b"DCR": + reshaped = x.reshape(N, blocksize, blocksize, C // (blocksize**2), H, W) + transposed_axes = (0, 3, 4, 1, 5, 2) + + elif mode == b"CRD": + reshaped = x.reshape(N, C // (blocksize**2), blocksize, blocksize, H, W) + transposed_axes = (0, 1, 4, 2, 5, 3) + else: + raise ValueError(f"Unknown mode: {mode}") + + transposed = np.transpose(reshaped, axes=transposed_axes) + y = transposed.reshape(N, new_C, new_H, new_W) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -1047,6 +1081,8 @@ def ggml_operator_depth_to_space(ctx: "GgmlOnnxExecutionContext", node: NodeProt userdata_p, ) + ctx.refs.append(custom_depth_to_space) + ctx.refs.append(depthtospace_userdata) return new_tensor @@ -1083,61 +1119,8 @@ class DropoutUserData(ctypes.Structure): ] -@ggml.ggml_custom2_op_t -def custom_dropout_mask( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_1) - ratio = ggml.utils.to_numpy(tensor_in_2) - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DropoutUserData)) - userdata_data = userdata_data_ptr.contents - seed = userdata_data.seed - training_mode = userdata_data.training_mode - - if np.equal(0, np.array(ratio)) or training_mode is False: - mask = np.ones(x.shape, dtype=np.int32) - - else: - np.random.seed(seed) - mask = np.random.uniform(0, 1.0, x.shape) >= ratio - - set_tensor_out(tensor_out, mask) - - -@ggml.ggml_custom3_op_t -def custom_dropout_output( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_1) - ratio = ggml.utils.to_numpy(tensor_in_2) - mask = ggml.utils.to_numpy(tensor_in_3) - - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DropoutUserData)) - userdata_data = userdata_data_ptr.contents - - training_mode = userdata_data.training_mode - - if np.equal(0, np.array(ratio)) or training_mode is False: - y = x - - else: - scale = 1 / (1 - ratio) - y = mask * x * scale - - set_tensor_out(tensor_out, y) @ggml_operator("Dropout") @@ -1174,6 +1157,32 @@ def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): droput_userdata = DropoutUserData(seed, bool(training_mode)) userdata_p = ctypes.cast(ctypes.pointer(droput_userdata), ctypes.c_void_p) + @ggml.ggml_custom2_op_t + def custom_dropout_mask( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_1) + ratio = ggml.utils.to_numpy(tensor_in_2) + + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DropoutUserData)) + userdata_data = userdata_data_ptr.contents + + seed = userdata_data.seed + training_mode = userdata_data.training_mode + + if np.equal(0, np.array(ratio)) or training_mode is False: + mask = np.ones(x.shape, dtype=np.int32) + + else: + np.random.seed(seed) + mask = np.random.uniform(0, 1.0, x.shape) >= ratio + + ctx.set_tensor_out(tensor_out, mask) mask = ggml.ggml_map_custom2_inplace( ctx.ggml_context, data, @@ -1183,6 +1192,35 @@ def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_dropout_mask) + + @ggml.ggml_custom3_op_t + def custom_dropout_output( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_1) + ratio = ggml.utils.to_numpy(tensor_in_2) + mask = ggml.utils.to_numpy(tensor_in_3) + + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DropoutUserData)) + userdata_data = userdata_data_ptr.contents + + training_mode = userdata_data.training_mode + + if np.equal(0, np.array(ratio)) or training_mode is False: + y = x + + else: + scale = 1 / (1 - ratio) + y = mask * x * scale + + ctx.set_tensor_out(tensor_out, y) output = ggml.ggml_map_custom3_inplace( ctx.ggml_context, data, @@ -1193,6 +1231,8 @@ def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_dropout_output) + ctx.refs.append(droput_userdata) if len(node.output) == 2: @@ -1235,22 +1275,6 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return Y -@ggml.ggml_custom3_op_t -def custom_equal( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) - - x = np.equal(a, b) - - set_tensor_out(tensor_out, x) @ggml_operator("Equal") @@ -1272,6 +1296,23 @@ def ggml_operator_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=a_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom3_op_t + def custom_equal( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.equal(a, b) + + ctx.set_tensor_out(tensor_out, x) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, @@ -1282,6 +1323,8 @@ def ggml_operator_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_equal) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) return new_tensor @@ -1311,7 +1354,7 @@ def custom_exp( ): tensor = ggml.utils.to_numpy(tensor_in_1) x = np.exp(tensor) - set_tensor_out(tensor_out, np.array(x)) + ctx.set_tensor_out(tensor_out, np.array(x)) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, @@ -1351,7 +1394,7 @@ def custom_expand( a = ctx.to_numpy(tensor_in_2) expanded = a * np.ones(new_shape, dtype=get_tensor_dtype(tensor_in_2)) - set_tensor_out(tensor_out, expanded) + ctx.set_tensor_out(tensor_out, expanded) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -1365,25 +1408,6 @@ def custom_expand( return new_tensor -@ggml.ggml_custom2_op_t -def custom_flatten( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value - - if axis < 0: - axis += len(x.shape) - new_shape = (np.prod(x.shape[:axis]).astype(np.int32), -1) - - y = x.reshape(new_shape) - - set_tensor_out(tensor_out, y) @ggml_operator("Flatten") @@ -1412,6 +1436,26 @@ def ggml_operator_flatten(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axis_c = ctypes.c_int(axis) + @ggml.ggml_custom2_op_t + def custom_flatten( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_2) + axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + + if axis < 0: + axis += len(x.shape) + new_shape = (np.prod(x.shape[:axis]).astype(np.int32), -1) + + y = x.reshape(new_shape) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -1421,23 +1465,12 @@ def ggml_operator_flatten(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctypes.pointer(axis_c), ) + ctx.refs.append(custom_flatten) ctx.refs.append(axis_c) return new_tensor -@ggml.ggml_custom1_op_t -def custom_floor( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_1) - y = np.floor(x) - - set_tensor_out(tensor_out, y) @ggml_operator("Floor") @@ -1451,6 +1484,19 @@ def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = node_inputs[0] + @ggml.ggml_custom1_op_t + def custom_floor( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_1) + y = np.floor(x) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, x, @@ -1459,26 +1505,11 @@ def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) - return new_tensor - + ctx.refs.append(custom_floor) -@ggml.ggml_custom3_op_t -def custom_gather( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - input_array = ggml.utils.to_numpy(tensor_in_2) - index_array = ggml.utils.to_numpy(tensor_in_3) - axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + return new_tensor - new_array = np.take(input_array, index_array, axis=axis) - set_tensor_out(tensor_out, new_array) @ggml_operator("Gather") @@ -1505,6 +1536,24 @@ def ggml_operator_gather(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=input_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom3_op_t + def custom_gather( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + input_array = ggml.utils.to_numpy(tensor_in_2) + index_array = ggml.utils.to_numpy(tensor_in_3) + axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + + new_array = np.take(input_array, index_array, axis=axis) + + ctx.set_tensor_out(tensor_out, new_array) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, @@ -1515,6 +1564,8 @@ def ggml_operator_gather(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctypes.pointer(axis_c), ) + ctx.refs.append(custom_gather) + ctx.refs.append(axis_c) if output_shape == (): @@ -1640,22 +1691,6 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return mul_mat_result -@ggml.ggml_custom3_op_t -def custom_greater( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) - - x = np.greater(a, b) - - set_tensor_out(tensor_out, x) @ggml_operator("Greater") @@ -1677,6 +1712,23 @@ def ggml_operator_greater(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=a_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom3_op_t + def custom_greater( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.greater(a, b) + + ctx.set_tensor_out(tensor_out, x) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, @@ -1687,6 +1739,8 @@ def ggml_operator_greater(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_greater) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) return new_tensor @@ -1699,23 +1753,6 @@ class HardSigmoidUserData(ctypes.Structure): ] -@ggml.ggml_custom1_op_t -def custom_hard_sigmoid( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(HardSigmoidUserData)) - userdata_data = userdata_data_ptr.contents - x = ggml.utils.to_numpy(tensor_in_1) - alpha = userdata_data.alpha - beta = userdata_data.beta - - y = np.clip((x * alpha) + beta, 0, 1) - - set_tensor_out(tensor_out, y) @ggml_operator("HardSigmoid") @@ -1734,6 +1771,24 @@ def ggml_operator_hardsigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): hsig_userdata = HardSigmoidUserData(alpha, beta) userdata_p = ctypes.cast(ctypes.pointer(hsig_userdata), ctypes.c_void_p) + @ggml.ggml_custom1_op_t + def custom_hard_sigmoid( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(HardSigmoidUserData)) + userdata_data = userdata_data_ptr.contents + x = ggml.utils.to_numpy(tensor_in_1) + alpha = userdata_data.alpha + beta = userdata_data.beta + + y = np.clip((x * alpha) + beta, 0, 1) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, x, @@ -1742,27 +1797,13 @@ def ggml_operator_hardsigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_hard_sigmoid) + ctx.refs.append(hsig_userdata) return new_tensor -@ggml.ggml_custom1_op_t -def custom_hardmax( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value - x = ggml.utils.to_numpy(tensor_in_1) - - max_indices = np.argmax(x, axis=axis, keepdims=True) - y = np.zeros_like(x) - np.put_along_axis(y, max_indices, 1, axis=axis) - - set_tensor_out(tensor_out, y) @ggml_operator("Hardmax") @@ -1778,6 +1819,23 @@ def ggml_operator_hardmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axis = next((attr.i for attr in node.attribute if attr.name == "axis"), -1) axis_c = ctypes.c_int(axis) + @ggml.ggml_custom1_op_t + def custom_hardmax( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + x = ggml.utils.to_numpy(tensor_in_1) + + max_indices = np.argmax(x, axis=axis, keepdims=True) + y = np.zeros_like(x) + np.put_along_axis(y, max_indices, 1, axis=axis) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, x, @@ -1786,6 +1844,8 @@ def ggml_operator_hardmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctypes.pointer(axis_c), ) + ctx.refs.append(custom_hardmax) + ctx.refs.append(axis_c) return new_tensor @@ -1812,27 +1872,6 @@ def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return y -@ggml.ggml_custom3_op_t -def custom_instancenorm( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_1) - scale = ggml.utils.to_numpy(tensor_in_2) - B = ggml.utils.to_numpy(tensor_in_3) - epsilon = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_double)).contents.value - - mean = np.mean(x, axis=(2, 3), keepdims=True) - variance = np.var(x, axis=(2, 3), keepdims=True) - normalized = (x - mean) / np.sqrt(variance + epsilon) - y = scale.reshape(1, -1, 1, 1) * normalized + B.reshape(1, -1, 1, 1) - - set_tensor_out(tensor_out, y) @ggml_operator("InstanceNormalization") @@ -1846,6 +1885,28 @@ def ggml_operator_instancenorm(ctx: "GgmlOnnxExecutionContext", node: NodeProto) input_tensor, scale, B = node_inputs epsilon = next((attr.f for attr in node.attribute if attr.name == "epsilon"), 1e-05) epsilon_c = ctypes.c_double(epsilon) + + @ggml.ggml_custom3_op_t + def custom_instancenorm( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_1) + scale = ggml.utils.to_numpy(tensor_in_2) + B = ggml.utils.to_numpy(tensor_in_3) + epsilon = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_double)).contents.value + + mean = np.mean(x, axis=(2, 3), keepdims=True) + variance = np.var(x, axis=(2, 3), keepdims=True) + normalized = (x - mean) / np.sqrt(variance + epsilon) + y = scale.reshape(1, -1, 1, 1) * normalized + B.reshape(1, -1, 1, 1) + + ctx.set_tensor_out(tensor_out, y) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, input_tensor, @@ -1855,7 +1916,7 @@ def ggml_operator_instancenorm(ctx: "GgmlOnnxExecutionContext", node: NodeProto) 1, ctypes.pointer(epsilon_c), ) - + ctx.refs.append(custom_instancenorm) ctx.refs.append(epsilon_c) return new_tensor @@ -1869,40 +1930,6 @@ class LRNUserData(ctypes.Structure): ] -@ggml.ggml_custom1_op_t -def custom_leaky_lrn( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(LRNUserData)) - userdata_data = userdata_data_ptr.contents - - alpha = userdata_data.alpha - beta = userdata_data.beta - bias = userdata_data.bias - size = userdata_data.size - - x = ggml.utils.to_numpy(tensor_in_1) - - square_sum = np.zeros(x.shape).astype(x.dtype) - for n, c, h, w in np.ndindex(x.shape): - square_sum[n, c, h, w] = sum( - x[ - n, - max(0, c - int(math.floor((size - 1) / 2))) : min( - 5, c + int(math.ceil((size - 1) / 2)) + 1 - ), - h, - w, - ] - ** 2 - ) - y = x / ((bias + (alpha / size) * square_sum) ** beta) - - set_tensor_out(tensor_out, y) @ggml_operator("LRN") @@ -1928,6 +1955,40 @@ def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): lrn_userdata = LRNUserData(alpha, beta, bias, size) userdata_p = ctypes.cast(ctypes.pointer(lrn_userdata), ctypes.c_void_p) + @ggml.ggml_custom1_op_t + def custom_leaky_lrn( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(LRNUserData)) + userdata_data = userdata_data_ptr.contents + + alpha = userdata_data.alpha + beta = userdata_data.beta + bias = userdata_data.bias + size = userdata_data.size + + x = ggml.utils.to_numpy(tensor_in_1) + + square_sum = np.zeros(x.shape).astype(x.dtype) + for n, c, h, w in np.ndindex(x.shape): + square_sum[n, c, h, w] = sum( + x[ + n, + max(0, c - int(math.floor((size - 1) / 2))) : min( + 5, c + int(math.ceil((size - 1) / 2)) + 1 + ), + h, + w, + ] + ** 2 + ) + y = x / ((bias + (alpha / size) * square_sum) ** beta) + + ctx.set_tensor_out(tensor_out, y) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, x, @@ -1936,24 +1997,12 @@ def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_leaky_lrn) ctx.refs.append(lrn_userdata) return new_tensor -@ggml.ggml_custom1_op_t -def custom_leaky_relu( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - alpha = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_double)).contents.value - x = ggml.utils.to_numpy(tensor_in_1) - y = np.clip(x, 0, np.inf) + np.clip(x, -np.inf, 0) * alpha - - set_tensor_out(tensor_out, y) @ggml_operator("LeakyRelu") @@ -1970,6 +2019,20 @@ def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axis_c = ctypes.c_double(alpha) + @ggml.ggml_custom1_op_t + def custom_leaky_relu( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + alpha = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_double)).contents.value + x = ggml.utils.to_numpy(tensor_in_1) + y = np.clip(x, 0, np.inf) + np.clip(x, -np.inf, 0) * alpha + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, x, @@ -1978,27 +2041,12 @@ def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctypes.pointer(axis_c), ) + ctx.refs.append(custom_leaky_relu) ctx.refs.append(axis_c) return new_tensor -@ggml.ggml_custom3_op_t -def custom_greater_equal( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) - - x = np.greater_equal(a, b) - - set_tensor_out(tensor_out, x) @ggml_operator("GreaterOrEqual") @@ -2015,10 +2063,27 @@ def ggml_operator_greater_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodePr b_shape = get_tensor_shape(node_inputs[1]) name = node.output[0] - output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape + output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape + + x = np.empty(output_shape, dtype=a_dtype) + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom3_op_t + def custom_greater_equal( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.greater_equal(a, b) - x = np.empty(output_shape, dtype=a_dtype) - x_t = ctx.from_numpy(x) + ctx.set_tensor_out(tensor_out, x) new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -2030,27 +2095,13 @@ def ggml_operator_greater_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodePr None, ) + ctx.refs.append(custom_greater_equal) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) return new_tensor -@ggml.ggml_custom3_op_t -def custom_less( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) - - x = np.less(a, b) - - set_tensor_out(tensor_out, x) @ggml_operator("Less") @@ -2072,6 +2123,23 @@ def ggml_operator_less(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=a_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom3_op_t + def custom_less( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.less(a, b) + + ctx.set_tensor_out(tensor_out, x) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, @@ -2082,27 +2150,13 @@ def ggml_operator_less(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_less) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) return new_tensor -@ggml.ggml_custom3_op_t -def custom_less_equal( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) - - x = np.less_equal(a, b) - - set_tensor_out(tensor_out, x) @ggml_operator("LessOrEqual") @@ -2124,6 +2178,23 @@ def ggml_operator_less_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto x = np.empty(output_shape, dtype=a_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom3_op_t + def custom_less_equal( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.less_equal(a, b) + + ctx.set_tensor_out(tensor_out, x) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, @@ -2134,6 +2205,8 @@ def ggml_operator_less_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto None, ) + ctx.refs.append(custom_less_equal) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) return new_tensor @@ -2266,7 +2339,7 @@ def custom_max( ): tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] x = np.max(tensors, axis=0) - set_tensor_out(tensor_out, np.array(x)) + ctx.set_tensor_out(tensor_out, np.array(x)) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, @@ -2346,7 +2419,7 @@ def custom_min( ): tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] x = np.min(tensors, axis=0) - set_tensor_out(tensor_out, np.array(x)) + ctx.set_tensor_out(tensor_out, np.array(x)) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, @@ -2406,18 +2479,6 @@ def ggml_operator_neg(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return x_neg -@ggml.ggml_custom1_op_t -def custom_not( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_1) - x = np.logical_not(a) - - set_tensor_out(tensor_out, x) @ggml_operator("Not") @@ -2430,6 +2491,19 @@ def ggml_operator_not(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) name = node.output[0] + @ggml.ggml_custom1_op_t + def custom_not( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_1) + x = np.logical_not(a) + + ctx.set_tensor_out(tensor_out, x) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, node_inputs[0], @@ -2438,27 +2512,13 @@ def ggml_operator_not(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_not) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) return new_tensor -@ggml.ggml_custom3_op_t -def custom_or( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) - - x = np.logical_or(a, b) - - set_tensor_out(tensor_out, x) @ggml_operator("Or") @@ -2480,6 +2540,23 @@ def ggml_operator_or(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=a_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom3_op_t + def custom_or( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.logical_or(a, b) + + ctx.set_tensor_out(tensor_out, x) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, @@ -2490,6 +2567,8 @@ def ggml_operator_or(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_or) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) return new_tensor @@ -2566,7 +2645,7 @@ def custom_pad( pad_width=pad_width, mode=mode, ) - set_tensor_out(tensor_out, x) + ctx.set_tensor_out(tensor_out, x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -2580,21 +2659,6 @@ def custom_pad( return new_tensor -@ggml.ggml_custom2_op_t -def custom_leaky_prelu( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_1) - slope = ggml.utils.to_numpy(tensor_in_2) - - y = np.clip(x, 0, np.inf) + np.clip(x, -np.inf, 0) * slope - - set_tensor_out(tensor_out, y) @ggml_operator("PRelu") @@ -2607,6 +2671,22 @@ def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) x, slope = node_inputs + @ggml.ggml_custom2_op_t + def custom_leaky_prelu( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_1) + slope = ggml.utils.to_numpy(tensor_in_2) + + y = np.clip(x, 0, np.inf) + np.clip(x, -np.inf, 0) * slope + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x, @@ -2616,24 +2696,11 @@ def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) - return new_tensor - + ctx.refs.append(custom_leaky_prelu) -@ggml.ggml_custom2_op_t -def custom_pow( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x1 = ggml.utils.to_numpy(tensor_in_1) - x2 = ggml.utils.to_numpy(tensor_in_2) + return new_tensor - new_tensor = np.power(x1, x2) - set_tensor_out(tensor_out, new_tensor) @ggml_operator("Pow") @@ -2648,6 +2715,22 @@ def ggml_operator_pow(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x1 = node_inputs[0] x2 = node_inputs[1] + @ggml.ggml_custom2_op_t + def custom_pow( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x1 = ggml.utils.to_numpy(tensor_in_1) + x2 = ggml.utils.to_numpy(tensor_in_2) + + new_tensor = np.power(x1, x2) + + ctx.set_tensor_out(tensor_out, new_tensor) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x1, @@ -2657,21 +2740,11 @@ def ggml_operator_pow(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) - return new_tensor + ctx.refs.append(custom_pow) + return new_tensor -@ggml.ggml_custom1_op_t -def custom_reciprocal( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_1) - y = np.reciprocal(x) - set_tensor_out(tensor_out, y) @ggml_operator("Reciprocal") @@ -2684,6 +2757,20 @@ def ggml_operator_reciprocal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) x = node_inputs[0] + + @ggml.ggml_custom1_op_t + def custom_reciprocal( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_1) + y = np.reciprocal(x) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, x, @@ -2692,24 +2779,11 @@ def ggml_operator_reciprocal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) - return new_tensor - + ctx.refs.append(custom_reciprocal) -@ggml.ggml_custom2_op_t -def custom_range( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - tensors = ggml.utils.to_numpy(tensor_in_2) - start_array, limit_array, delta_array = tensors + return new_tensor - new_tensor = np.arange(start_array, limit_array, delta_array) - set_tensor_out(tensor_out, new_tensor) @ggml_operator("Range") @@ -2733,6 +2807,22 @@ def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): input_tensors = ggml.utils.from_numpy(np.array(tensors), ctx.ggml_context) + @ggml.ggml_custom2_op_t + def custom_range( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + tensors = ggml.utils.to_numpy(tensor_in_2) + start_array, limit_array, delta_array = tensors + + new_tensor = np.arange(start_array, limit_array, delta_array) + + ctx.set_tensor_out(tensor_out, new_tensor) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -2742,6 +2832,8 @@ def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_range) + return new_tensor @@ -2762,29 +2854,6 @@ def __init__(self, axes, keepdims): self.keepdims = keepdims -@ggml.ggml_custom2_op_t -def custom_reduce_l1( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - axes = tuple(axes) if len(axes) else None - - shape = tensor.shape - data = np.reshape(np.arange(1, np.prod(shape) + 1, dtype=np.float32), shape) - rl1_result = np.sum(a=np.abs(tensor), axis=axes, keepdims=keepdims) - - set_tensor_out(tensor_out, rl1_result) @ggml_operator("ReduceL1") @@ -2838,6 +2907,30 @@ def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=tensor_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_reduce_l1( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + + shape = tensor.shape + data = np.reshape(np.arange(1, np.prod(shape) + 1, dtype=np.float32), shape) + rl1_result = np.sum(a=np.abs(tensor), axis=axes, keepdims=keepdims) + + ctx.set_tensor_out(tensor_out, rl1_result) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -2847,32 +2940,13 @@ def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_reduce_l1) + ctx.refs.append(rmean_userdata) return new_tensor -@ggml.ggml_custom2_op_t -def custom_reduce_l2( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - axes = tuple(axes) if len(axes) else None - - rl2_result = np.sqrt(np.sum(a=np.square(tensor), axis=axes, keepdims=keepdims)) - - set_tensor_out(tensor_out, rl2_result) @ggml_operator("ReduceL2") @@ -2926,6 +3000,28 @@ def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=tensor_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_reduce_l2( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + + rl2_result = np.sqrt(np.sum(a=np.square(tensor), axis=axes, keepdims=keepdims)) + + ctx.set_tensor_out(tensor_out, rl2_result) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -2935,31 +3031,13 @@ def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_reduce_l2) + ctx.refs.append(rmean_userdata) return new_tensor -@ggml.ggml_custom2_op_t -def custom_reduce_log_sum( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - axes = tuple(axes) if len(axes) else None - rlogsum_result = np.log(np.sum(tensor, axis=axes, keepdims=keepdims)) - - set_tensor_out(tensor_out, rlogsum_result) @ggml_operator("ReduceLogSum") @@ -3013,6 +3091,27 @@ def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProt x = np.empty(output_shape, dtype=tensor_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_reduce_log_sum( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rlogsum_result = np.log(np.sum(tensor, axis=axes, keepdims=keepdims)) + + ctx.set_tensor_out(tensor_out, rlogsum_result) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -3022,31 +3121,13 @@ def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProt userdata_p, ) + ctx.refs.append(custom_reduce_log_sum) + ctx.refs.append(rmean_userdata) return new_tensor -@ggml.ggml_custom2_op_t -def custom_reduce_log_sum_exp( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - axes = tuple(axes) if len(axes) else None - rlogsum_result = np.log(np.sum(np.exp(tensor), axis=axes, keepdims=keepdims)) - - set_tensor_out(tensor_out, rlogsum_result) @ggml_operator("ReduceLogSumExp") @@ -3103,6 +3184,27 @@ def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: Node x = np.empty(output_shape, dtype=tensor_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_reduce_log_sum_exp( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rlogsum_result = np.log(np.sum(np.exp(tensor), axis=axes, keepdims=keepdims)) + + ctx.set_tensor_out(tensor_out, rlogsum_result) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -3112,31 +3214,13 @@ def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: Node userdata_p, ) + ctx.refs.append(custom_reduce_log_sum_exp) + ctx.refs.append(rmean_userdata) return new_tensor -@ggml.ggml_custom2_op_t -def custom_reduce_max( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - axes = tuple(axes) if len(axes) else None - rmean_result = np.max(tensor, axis=axes, keepdims=keepdims) - - set_tensor_out(tensor_out, rmean_result) @ggml_operator("ReduceMax") @@ -3190,6 +3274,27 @@ def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=tensor_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_reduce_max( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rmean_result = np.max(tensor, axis=axes, keepdims=keepdims) + + ctx.set_tensor_out(tensor_out, rmean_result) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -3199,31 +3304,13 @@ def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_reduce_max) + ctx.refs.append(rmean_userdata) return new_tensor -@ggml.ggml_custom2_op_t -def custom_reduce_mean( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - axes = tuple(axes) if len(axes) else None - rmean_result = np.mean(tensor, axis=axes, keepdims=keepdims) - - set_tensor_out(tensor_out, rmean_result) @ggml_operator("ReduceMean") @@ -3277,6 +3364,27 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=tensor_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_reduce_mean( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rmean_result = np.mean(tensor, axis=axes, keepdims=keepdims) + + ctx.set_tensor_out(tensor_out, rmean_result) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -3286,31 +3394,13 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_reduce_mean) + ctx.refs.append(rmean_userdata) return new_tensor -@ggml.ggml_custom2_op_t -def custom_reduce_min( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - axes = tuple(axes) if len(axes) else None - rmean_result = np.minimum.reduce(tensor, axis=axes, keepdims=keepdims) - - set_tensor_out(tensor_out, rmean_result) @ggml_operator("ReduceMin") @@ -3360,9 +3450,30 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): else: output_shape.pop(axis) - output_shape = tuple(output_shape) - x = np.empty(output_shape, dtype=tensor_dtype) - x_t = ctx.from_numpy(x) + output_shape = tuple(output_shape) + x = np.empty(output_shape, dtype=tensor_dtype) + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom2_op_t + def custom_reduce_min( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rmean_result = np.minimum.reduce(tensor, axis=axes, keepdims=keepdims) + + ctx.set_tensor_out(tensor_out, rmean_result) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -3373,31 +3484,13 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_reduce_min) + ctx.refs.append(rmean_userdata) return new_tensor -@ggml.ggml_custom2_op_t -def custom_reduce_prod( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - axes = tuple(axes) if len(axes) else None - rmean_result = np.prod(tensor, axis=axes, keepdims=keepdims) - - set_tensor_out(tensor_out, rmean_result) @ggml_operator("ReduceProd") @@ -3451,6 +3544,27 @@ def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=tensor_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_reduce_prod( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + rmean_result = np.prod(tensor, axis=axes, keepdims=keepdims) + + ctx.set_tensor_out(tensor_out, rmean_result) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -3460,30 +3574,13 @@ def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_reduce_prod) + ctx.refs.append(rmean_userdata) return new_tensor -@ggml.ggml_custom2_op_t -def custom_reduce_sum( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - axes = tuple(axes) if len(axes) else None - result = np.sum(tensor, axis=axes, keepdims=keepdims) - set_tensor_out(tensor_out, result) @ggml_operator("ReduceSum") @@ -3537,6 +3634,26 @@ def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=tensor_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_reduce_sum( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + result = np.sum(tensor, axis=axes, keepdims=keepdims) + ctx.set_tensor_out(tensor_out, result) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -3546,31 +3663,13 @@ def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_reduce_sum) + ctx.refs.append(rmean_userdata) return new_tensor -@ggml.ggml_custom2_op_t -def custom_reduce_sum_square( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) - userdata_data = userdata_data_ptr.contents - - tensor = ggml.utils.to_numpy(tensor_in_2) - axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] - keepdims = userdata_data.keepdims - - axes = tuple(axes) if len(axes) else None - result = np.sum(np.square(tensor), axis=axes, keepdims=keepdims) - - set_tensor_out(tensor_out, result) @ggml_operator("ReduceSumSquare") @@ -3624,6 +3723,27 @@ def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeP x = np.empty(output_shape, dtype=tensor_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom2_op_t + def custom_reduce_sum_square( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) + userdata_data = userdata_data_ptr.contents + + tensor = ggml.utils.to_numpy(tensor_in_2) + axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] + keepdims = userdata_data.keepdims + + axes = tuple(axes) if len(axes) else None + result = np.sum(np.square(tensor), axis=axes, keepdims=keepdims) + + ctx.set_tensor_out(tensor_out, result) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -3633,6 +3753,8 @@ def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeP userdata_p, ) + ctx.refs.append(custom_reduce_sum_square) + ctx.refs.append(rmean_userdata) return new_tensor @@ -3700,7 +3822,7 @@ def custom_reshape( ): x = ggml.utils.to_numpy(tensor_in_2) x_reshape = np.reshape(x, new_shape) - set_tensor_out(tensor_out, x_reshape) + ctx.set_tensor_out(tensor_out, x_reshape) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -3723,27 +3845,6 @@ class SeluUserData(ctypes.Structure): ] -@ggml.ggml_custom1_op_t -def custom_selu( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(SeluUserData)) - userdata_data = userdata_data_ptr.contents - x = ggml.utils.to_numpy(tensor_in_1) - - alpha = userdata_data.alpha - gamma = userdata_data.gamma - - y = ( - np.clip(x, 0, np.inf) * gamma - + (np.exp(np.clip(x, -np.inf, 0)) - 1) * alpha * gamma - ) - - set_tensor_out(tensor_out, y) @ggml_operator("Selu") @@ -3769,6 +3870,28 @@ def ggml_operator_selu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): selu_userdata = SeluUserData(alpha, gamma) userdata_p = ctypes.cast(ctypes.pointer(selu_userdata), ctypes.c_void_p) + @ggml.ggml_custom1_op_t + def custom_selu( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(SeluUserData)) + userdata_data = userdata_data_ptr.contents + x = ggml.utils.to_numpy(tensor_in_1) + + alpha = userdata_data.alpha + gamma = userdata_data.gamma + + y = ( + np.clip(x, 0, np.inf) * gamma + + (np.exp(np.clip(x, -np.inf, 0)) - 1) * alpha * gamma + ) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, x, @@ -3777,6 +3900,8 @@ def ggml_operator_selu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_selu) + ctx.refs.append(selu_userdata) return new_tensor @@ -3808,19 +3933,6 @@ def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return new_tensor -@ggml.ggml_custom1_op_t -def custom_sigmoid( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_1) - - y = 1.0 / (1.0 + np.exp(np.negative(x))) - - set_tensor_out(tensor_out, y) @ggml_operator("Sigmoid") @@ -3833,6 +3945,21 @@ def ggml_operator_sigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) x = node_inputs[0] + + @ggml.ggml_custom1_op_t + def custom_sigmoid( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_1) + + y = 1.0 / (1.0 + np.exp(np.negative(x))) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, x, @@ -3841,20 +3968,11 @@ def ggml_operator_sigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_sigmoid) + return new_tensor -@ggml.ggml_custom2_op_t -def custom_size( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - tensor = ggml.utils.to_numpy(tensor_in_2) - set_tensor_out(tensor_out, tensor) @ggml_operator("Size") @@ -3878,6 +3996,19 @@ def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(tensor_shape, dtype=tensor_size_np.dtype) x_t = ctx.from_numpy(x) + + @ggml.ggml_custom2_op_t + def custom_size( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + tensor = ggml.utils.to_numpy(tensor_in_2) + ctx.set_tensor_out(tensor_out, tensor) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -3887,6 +4018,8 @@ def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_size) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) return new_tensor @@ -3942,7 +4075,7 @@ def custom_slice( x = ggml.utils.to_numpy(tensor_in_2) y = x[tuple(all_slices)].copy() - set_tensor_out(tensor_out, y) + ctx.set_tensor_out(tensor_out, y) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, node_inputs[0], custom_slice, 1, None @@ -3971,17 +4104,6 @@ def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return soft_max_result -@ggml.ggml_custom1_op_t -def custom_softplus( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_1) - y = np.log(np.exp(x) + 1) - set_tensor_out(tensor_out, y) @ggml_operator("Softplus") @@ -3995,6 +4117,18 @@ def ggml_operator_softplus(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = node_inputs[0] + @ggml.ggml_custom1_op_t + def custom_softplus( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_1) + y = np.log(np.exp(x) + 1) + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, x, @@ -4003,6 +4137,8 @@ def ggml_operator_softplus(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_softplus) + return new_tensor @@ -4030,29 +4166,6 @@ def ggml_operator_softsign(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return y -@ggml.ggml_custom2_op_t -def custom_space_to_depth( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - blocksize = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value - - N, C, H, W = x.shape - new_H = H // blocksize - new_W = W // blocksize - - reshaped = x.reshape(N, C, new_H, blocksize, new_W, blocksize) - transposed = reshaped.transpose( - 0, 3, 5, 1, 2, 4 - ) # ONNX specification TODO: Test more examples - y = transposed.reshape(N, C * (blocksize**2), new_H, new_W) - - set_tensor_out(tensor_out, y) @ggml_operator("SpaceToDepth") @@ -4085,6 +4198,30 @@ def ggml_operator_space_to_depth(ctx: "GgmlOnnxExecutionContext", node: NodeProt blocksize_c = ctypes.c_int(blocksize) + @ggml.ggml_custom2_op_t + def custom_space_to_depth( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_2) + blocksize = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value + + N, C, H, W = x.shape + new_H = H // blocksize + new_W = W // blocksize + + reshaped = x.reshape(N, C, new_H, blocksize, new_W, blocksize) + transposed = reshaped.transpose( + 0, 3, 5, 1, 2, 4 + ) # ONNX specification TODO: Test more examples + y = transposed.reshape(N, C * (blocksize**2), new_H, new_W) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -4094,6 +4231,8 @@ def ggml_operator_space_to_depth(ctx: "GgmlOnnxExecutionContext", node: NodeProt ctypes.pointer(blocksize_c), ) + ctx.refs.append(custom_space_to_depth) + ctx.refs.append(blocksize_c) return new_tensor @@ -4106,34 +4245,6 @@ class SplitUserData(ctypes.Structure): ] -@ggml.ggml_custom3_op_t -def custom_split( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(SplitUserData)) - userdata_data = userdata_data_ptr.contents - - axis = userdata_data.axis - split_index = userdata_data.split_index - - tensor = ggml.utils.to_numpy(tensor_in_2) - - split_shapes = ggml.utils.to_numpy(tensor_in_3) - split_shape = list(ggml.utils.to_numpy(tensor_in_1).shape) - - split_size = split_shape[axis] - split_start = sum(split_shapes[i][axis] for i in range(split_index)) - split_end = split_start + split_size - - split_output = np.take(tensor, range(split_start, split_end), axis=axis) - - set_tensor_out(tensor_out, split_output) @ggml_operator("Split") @@ -4191,6 +4302,36 @@ def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_t = ggml.utils.from_numpy( np.empty(split_shape, dtype=dtype), ctx.ggml_context ) + + @ggml.ggml_custom3_op_t + def custom_split( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(SplitUserData)) + userdata_data = userdata_data_ptr.contents + + axis = userdata_data.axis + split_index = userdata_data.split_index + + tensor = ggml.utils.to_numpy(tensor_in_2) + + split_shapes = ggml.utils.to_numpy(tensor_in_3) + split_shape = list(ggml.utils.to_numpy(tensor_in_1).shape) + + split_size = split_shape[axis] + split_start = sum(split_shapes[i][axis] for i in range(split_index)) + split_end = split_start + split_size + + split_output = np.take(tensor, range(split_start, split_end), axis=axis) + + ctx.set_tensor_out(tensor_out, split_output) + new_tensor = ctx.tensors_dict[ node.output[split_index] ] = ggml.ggml_map_custom3_inplace( @@ -4202,6 +4343,7 @@ def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, userdata_p, ) + ctx.refs.append(custom_split) ctx.refs.append(split_userdata) outputs.append(new_tensor) @@ -4267,7 +4409,7 @@ def custom_squeeze( x = ctx.to_numpy(tensor_in_2) axes = ctx.to_numpy(tensor_in_3) y = np.squeeze(x, axis=axes[0]) - set_tensor_out(tensor_out, y) + ctx.set_tensor_out(tensor_out, y) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -4353,22 +4495,6 @@ def ggml_operator_tanh(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return tanh_result -@ggml.ggml_custom3_op_t -def custom_tile( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - repeats = ggml.utils.to_numpy(tensor_in_3) - - y = np.tile(x, repeats) - - set_tensor_out(tensor_out, y) @ggml_operator("Tile") @@ -4394,6 +4520,23 @@ def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.ggml_context, ) + @ggml.ggml_custom3_op_t + def custom_tile( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_2) + repeats = ggml.utils.to_numpy(tensor_in_3) + + y = np.tile(x, repeats) + + ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, @@ -4404,6 +4547,8 @@ def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_tile) + return new_tensor @@ -4416,61 +4561,8 @@ class TopKUserData(ctypes.Structure): ] -@ggml.ggml_custom2_op_t -def custom_top_k_indices( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(TopKUserData)) - userdata_data = userdata_data_ptr.contents - - axis = userdata_data.axis - largest = bool(userdata_data.largest) - - k = userdata_data.k - - if largest: - sorted_indices = np.argsort(x, axis=axis)[:, ::-1] - else: - sorted_indices = np.argsort(x, axis=axis) - - topk_indices = sorted_indices[:, :k] - - set_tensor_out(tensor_out, topk_indices) - - -@ggml.ggml_custom3_op_t -def custom_top_k_values( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - topk_indices = ggml.utils.to_numpy(tensor_in_3).astype(np.int32) - - userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(TopKUserData)) - userdata_data = userdata_data_ptr.contents - - axis = userdata_data.axis - sorted_flag = bool(userdata_data.sorted) - topk_values = np.take_along_axis(x, topk_indices, axis=axis) - if sorted_flag: - topk_values_sorted = np.sort(topk_values, axis=axis) - else: - topk_values_sorted = topk_values - set_tensor_out(tensor_out, topk_values_sorted) @ggml_operator("TopK") @@ -4510,6 +4602,34 @@ def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.ggml_context, ) + @ggml.ggml_custom2_op_t + def custom_top_k_indices( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_2) + + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(TopKUserData)) + userdata_data = userdata_data_ptr.contents + + axis = userdata_data.axis + largest = bool(userdata_data.largest) + + k = userdata_data.k + + if largest: + sorted_indices = np.argsort(x, axis=axis)[:, ::-1] + else: + sorted_indices = np.argsort(x, axis=axis) + + topk_indices = sorted_indices[:, :k] + + ctx.set_tensor_out(tensor_out, topk_indices) + indices = ggml.ggml_map_custom2_inplace( ctx.ggml_context, indices_t, @@ -4519,6 +4639,35 @@ def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_top_k_indices) + + @ggml.ggml_custom3_op_t + def custom_top_k_values( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_2) + topk_indices = ggml.utils.to_numpy(tensor_in_3).astype(np.int32) + + userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(TopKUserData)) + userdata_data = userdata_data_ptr.contents + + axis = userdata_data.axis + sorted_flag = bool(userdata_data.sorted) + + topk_values = np.take_along_axis(x, topk_indices, axis=axis) + if sorted_flag: + topk_values_sorted = np.sort(topk_values, axis=axis) + else: + topk_values_sorted = topk_values + + ctx.set_tensor_out(tensor_out, topk_values_sorted) + values = ggml.ggml_map_custom3_inplace( ctx.ggml_context, values_t, @@ -4529,6 +4678,8 @@ def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): userdata_p, ) + ctx.refs.append(custom_top_k_values) + ctx.tensors_dict[node.output[0]] = values ctx.tensors_dict[node.output[1]] = indices @@ -4586,26 +4737,6 @@ def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): return transpose_result -@ggml.ggml_custom3_op_t -def custom_unsqueeze( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_2) - axes = ggml.utils.to_numpy(tensor_in_3) - - axes_values = [ax if ax >= 0 else ax + x.ndim + 1 for ax in axes] - axes_values.sort() - axes_values = np.array(axes_values) - for axis in axes_values: - x = np.expand_dims(x, axis=axis) - - set_tensor_out(tensor_out, x) @ggml_operator("Unsqueeze") @@ -4649,6 +4780,27 @@ def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): (ctypes.c_int64 * len(new_shape))(*new_shape), ) + @ggml.ggml_custom3_op_t + def custom_unsqueeze( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_2) + axes = ggml.utils.to_numpy(tensor_in_3) + + axes_values = [ax if ax >= 0 else ax + x.ndim + 1 for ax in axes] + axes_values.sort() + axes_values = np.array(axes_values) + for axis in axes_values: + x = np.expand_dims(x, axis=axis) + + ctx.set_tensor_out(tensor_out, x) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, @@ -4658,24 +4810,10 @@ def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, None, ) + ctx.refs.append(custom_unsqueeze) return new_tensor -@ggml.ggml_custom3_op_t -def custom_where( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - x = ggml.utils.to_numpy(tensor_in_1) - y = ggml.utils.to_numpy(tensor_in_2) - condition_array = ggml.utils.to_numpy(tensor_in_3) - new_tensor = np.where(condition_array, x, y) - set_tensor_out(tensor_out, new_tensor) @ggml_operator("Where") @@ -4687,6 +4825,22 @@ def ggml_operator_where(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": Operation "Where" requires exactly three inputs. Actual number of inputs: {len(node_inputs)}' ) + @ggml.ggml_custom3_op_t + def custom_where( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_1) + y = ggml.utils.to_numpy(tensor_in_2) + condition_array = ggml.utils.to_numpy(tensor_in_3) + new_tensor = np.where(condition_array, x, y) + ctx.set_tensor_out(tensor_out, new_tensor) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, node_inputs[1], @@ -4696,26 +4850,11 @@ def ggml_operator_where(ctx: "GgmlOnnxExecutionContext", node: NodeProto): 1, None, ) + ctx.refs.append(custom_where) return new_tensor -@ggml.ggml_custom3_op_t -def custom_xor( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], -): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) - - x = np.logical_xor(a, b) - - set_tensor_out(tensor_out, x) @ggml_operator("Xor") @@ -4737,6 +4876,23 @@ def ggml_operator_xor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=a_dtype) x_t = ctx.from_numpy(x) + @ggml.ggml_custom3_op_t + def custom_xor( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) + b = ggml.utils.to_numpy(tensor_in_3) + + x = np.logical_xor(a, b) + + ctx.set_tensor_out(tensor_out, x) + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, @@ -4747,6 +4903,8 @@ def ggml_operator_xor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) + ctx.refs.append(custom_xor) + ggml.ggml_set_name(new_tensor, (name + f"").encode()) return new_tensor @@ -4784,6 +4942,11 @@ def to_numpy(self, tensor: ggml.ggml_tensor_p) -> np.ndarray: def from_numpy(self, array: np.ndarray) -> ggml.ggml_tensor_p: shape = array.shape tensor = ggml.utils.from_numpy(array, self.ggml_context) + if array.size > 0: + buffer = (ctypes.c_uint8 * ggml.ggml_nbytes_pad(tensor))() + self.refs.append(buffer) + tensor.contents.data = ctypes.cast(ctypes.addressof(buffer), ctypes.c_void_p) + self.set_tensor_out(tensor, array) self.set_tensor_shape(tensor, shape) return tensor @@ -4927,6 +5090,10 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: set_tensor_out(tensor, np.array(value)) # Define context + # max_overhead = 2 * ggml.GGML_MAX_NODES * ggml.ggml_tensor_overhead() + # ggml_context = ggml.ggml_init( + # params=ggml.ggml_init_params(mem_size=max_overhead, mem_buffer=None, no_alloc=True) + # ) ggml_context = ggml.ggml_init( params=ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) ) From 7f8b0246d51147fa4510ee058ce65e7ce7281d85 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 19 Sep 2023 18:14:45 -0700 Subject: [PATCH 171/232] Support concat of >2 tensors --- ggml/contrib/onnx.py | 53 +++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 810b3829..f0aebe43 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -609,15 +609,6 @@ def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): raise ValueError( "All tensors must have the same shape along the specified axis." ) - - total_dim = sum(shape[axis] for shape in shapes) - output_shape = list(shapes[0]) - output_shape[axis] = total_dim - - x = np.empty(output_shape, dtype=get_tensor_dtype(node_inputs[0])) - - x_t = ctx.from_numpy(x) - @ggml.ggml_custom3_op_t def custom_concat( tensor_out: ggml.ggml_tensor_p, @@ -633,20 +624,33 @@ def custom_concat( x = np.concatenate([a, b], axis=axis) ctx.set_tensor_out(tensor_out, x) - tensor_a = node_inputs[0] - tensor_b = node_inputs[1] - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, - x_t, - tensor_a, - tensor_b, - custom_concat, - 1, - None, - ) + def concat_2(tensor_a, tensor_b): + shape_a = ctx.get_tensor_shape(tensor_a) + shape_b = ctx.get_tensor_shape(tensor_b) + total_dim = shape_a[axis] + shape_b[axis] + output_shape = list(shape_a) + output_shape[axis] = total_dim - ctx.refs.append(custom_concat) + x = np.empty(output_shape, dtype=get_tensor_dtype(tensor_a)) + x_t = ctx.from_numpy(x) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, + x_t, + tensor_a, + tensor_b, + custom_concat, + 1, + None, + ) + + ctx.refs.append(custom_concat) + return new_tensor + + new_tensor = node_inputs[0] + for tensor in node_inputs[1:]: + new_tensor = concat_2(new_tensor, tensor) return new_tensor @@ -709,9 +713,8 @@ def custom_constant( ): shape = get_tensor_shape(tensor_in_1) constant_data = ggml.utils.to_numpy(tensor_in_2) - new_tenor = constant_data.reshape(shape) - - ctx.set_tensor_out(tensor_out, new_tenor) + new_tensor = constant_data.reshape(shape) + ctx.set_tensor_out(tensor_out, new_tensor) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, @@ -4965,7 +4968,7 @@ def eval_tensor( return tensor def set_tensor_out(self, tensor: ggml.ggml_tensor_p, array: np.ndarray): - output_shape = get_tensor_shape(tensor) + output_shape = self.get_tensor_shape(tensor) if output_shape == (): self.to_numpy(tensor)[()] = array From df92756b5bcab0b2297e963d1181d2c7d382794d Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 19 Sep 2023 21:18:22 -0400 Subject: [PATCH 172/232] Use ctx.from_numpy in all operators --- ggml/contrib/onnx.py | 64 ++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 810b3829..32112114 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -303,7 +303,7 @@ def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): dummy_result = dummy_result.astype(np.int32) - x_t = ggml.utils.from_numpy(dummy_result, ctx.ggml_context) + x_t = ctx.from_numpy(dummy_result) argmax_userdata = ArgOpsUserData(axis, keepdims, select_last_index) userdata_p = ctypes.cast(ctypes.pointer(argmax_userdata), ctypes.c_void_p) @@ -393,7 +393,7 @@ def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): dummy_result = dummy_result.astype(np.int32) - x_t = ggml.utils.from_numpy(dummy_result, ctx.ggml_context) + x_t = ctx.from_numpy(dummy_result) argmax_userdata = ArgOpsUserData(axis, keepdims, select_last_index) userdata_p = ctypes.cast(ctypes.pointer(argmax_userdata), ctypes.c_void_p) @@ -818,8 +818,8 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): m = w_shape[0] bias = next( node_inputs_iter, - ggml.utils.from_numpy( - np.full(m, 0, dtype=get_tensor_dtype(x)), ctx.ggml_context + ctx.from_numpy( + np.full(m, 0, dtype=get_tensor_dtype(x)) ), ) @@ -901,8 +901,8 @@ def ggml_operator_convtranspose(ctx: "GgmlOnnxExecutionContext", node: NodeProto m = w_shape[0] bias = next( node_inputs_iter, - ggml.utils.from_numpy( - np.full(m, 0, dtype=get_tensor_dtype(x)), ctx.ggml_context + ctx.from_numpy( + np.full(m, 0, dtype=get_tensor_dtype(x)) ), ) @@ -1029,8 +1029,8 @@ def ggml_operator_depth_to_space(ctx: "GgmlOnnxExecutionContext", node: NodeProt output_shape = (N, new_C, new_H, new_W) - x_t = ggml.utils.from_numpy( - np.empty(output_shape, dtype=get_tensor_dtype(x)), ctx.ggml_context + x_t = ctx.from_numpy( + np.empty(output_shape, dtype=get_tensor_dtype(x)) ) depthtospace_userdata = DepthToSpaceUserData(blocksize, mode) userdata_p = ctypes.cast(ctypes.pointer(depthtospace_userdata), ctypes.c_void_p) @@ -1144,8 +1144,8 @@ def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): training_mode = next(node_inputs_iter, np.bool_(False)) if type(ratio) is float: - ratio = ggml.utils.from_numpy( - np.array([ratio]).astype(np.float32), ctx.ggml_context + ratio = ctx.from_numpy( + np.array([ratio]).astype(np.float32) ) seed = next((attr.i for attr in node.attribute if attr.name == "seed"), 6) @@ -1432,7 +1432,7 @@ def ggml_operator_flatten(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_out = np.empty(x_shape, dtype=x_dtype) x_out = x_out.reshape(new_shape) - x_t = ggml.utils.from_numpy(x_out, ctx.ggml_context) + x_t = ctx.from_numpy(x_out) axis_c = ctypes.c_int(axis) @@ -1649,36 +1649,33 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a_transposed, ) - alpha_t = ggml.utils.from_numpy( + alpha_t = ctx.from_numpy( np.full( get_tensor_shape(mul_mat_result), alpha, dtype=get_tensor_dtype(mul_mat_result), ), - ctx.ggml_context, ) mul_mat_result = ggml.ggml_mul_inplace(ctx.ggml_context, mul_mat_result, alpha_t) if c is None: - c = ggml.utils.from_numpy( + c = ctx.from_numpy( np.full( get_tensor_shape(mul_mat_result), 0, dtype=get_tensor_dtype(mul_mat_result), ), - ctx.ggml_context, ) c, mul_mat_result = broadcast_shapes(ctx.ggml_context, c, mul_mat_result) - beta_t = ggml.utils.from_numpy( + beta_t = ctx.from_numpy( np.full( get_tensor_shape(mul_mat_result), beta, dtype=get_tensor_dtype(mul_mat_result), ), - ctx.ggml_context, ) mul_mat_result = ggml.ggml_add_inplace( @@ -2370,7 +2367,7 @@ def ggml_operator_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): sums = ggml.ggml_add(ctx.ggml_context, sums, tensor) coef_np = np.full(get_tensor_shape(sums), len(node_inputs), dtype=np.float32) - coef_t = ggml.utils.from_numpy(coef_np, ctx.ggml_context) + coef_t = ctx.from_numpy(coef_np) mean = ggml.ggml_div( ctx.ggml_context, @@ -2805,7 +2802,7 @@ def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(output_shape, dtype=step.dtype) x_t = ctx.from_numpy(x) - input_tensors = ggml.utils.from_numpy(np.array(tensors), ctx.ggml_context) + input_tensors = ctx.from_numpy(np.array(tensors)) @ggml.ggml_custom2_op_t def custom_range( @@ -3924,8 +3921,8 @@ def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) shape_slice = tensor_shape[start:end] - new_tensor = ctx.tensors_dict[name] = ggml.utils.from_numpy( - shape_slice, ctx.ggml_context + new_tensor = ctx.tensors_dict[name] = ctx.from_numpy( + shape_slice ) ggml.ggml_set_name(new_tensor, (name + f"").encode()) @@ -3990,7 +3987,7 @@ def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): tensor_size_np = np.array( [tensor_size_np] ) # Add a rank so ggml doesnt break the value, inside the custom reshape to scalar as expected TODO: Fix the ranking, ggml skalars or make sure broadcasting works fine - tensor_size_t = ggml.utils.from_numpy(np.array([tensor_size_np]), ctx.ggml_context) + tensor_size_t = ctx.from_numpy(np.array([tensor_size_np])) ggml_type = map_to_ggml_type(tensor_size_np.dtype).value x = np.empty(tensor_shape, dtype=tensor_size_np.dtype) @@ -4157,7 +4154,7 @@ def ggml_operator_softsign(ctx: "GgmlOnnxExecutionContext", node: NodeProto): # y = x / (1 + abs(x)) one_np = np.full(x_shape, 1, dtype=x_dtype) - one_t = ggml.utils.from_numpy(one_np, ctx.ggml_context) + one_t = ctx.from_numpy(one_np) x_abs = ggml.ggml_abs(ctx.ggml_context, x) one_plus_abs = ggml.ggml_add(ctx.ggml_context, one_t, x_abs) y = ggml.ggml_div(ctx.ggml_context, x, one_plus_abs) @@ -4192,8 +4189,8 @@ def ggml_operator_space_to_depth(ctx: "GgmlOnnxExecutionContext", node: NodeProt new_W = W // blocksize output_shape = (N, C * blocksize * blocksize, new_H, new_W) - x_t = ggml.utils.from_numpy( - np.empty(output_shape, dtype=get_tensor_dtype(x)), ctx.ggml_context + x_t = ctx.from_numpy( + np.empty(output_shape, dtype=get_tensor_dtype(x)) ) blocksize_c = ctypes.c_int(blocksize) @@ -4291,7 +4288,7 @@ def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): split_shapes = tuple(map(tuple, split_shapes)) split_shapes_np = np.array(split_shapes, dtype=np.int32) - split_shapes_t = ggml.utils.from_numpy(split_shapes_np, ctx.ggml_context) + split_shapes_t = ctx.from_numpy(split_shapes_np) outputs = [] @@ -4299,8 +4296,8 @@ def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): split_userdata = SplitUserData(axis, split_index) userdata_p = ctypes.cast(ctypes.pointer(split_userdata), ctypes.c_void_p) - x_t = ggml.utils.from_numpy( - np.empty(split_shape, dtype=dtype), ctx.ggml_context + x_t = ctx.from_numpy( + np.empty(split_shape, dtype=dtype) ) @ggml.ggml_custom3_op_t @@ -4460,7 +4457,7 @@ def ggml_operator_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): dtype = get_tensor_dtype(node_inputs[0]) empty_np = np.full(shape, 0, dtype=dtype) - next_item = ggml.utils.from_numpy(empty_np, ctx.ggml_context) + next_item = ctx.from_numpy(empty_np) for tensor in node_inputs: tensor, next_item = broadcast_shapes(ctx.ggml_context, tensor, next_item) @@ -4515,9 +4512,8 @@ def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): for i in range(len(output_shape)): output_shape[i] = output_shape[i] * repeats_vals[i] - x_t = ggml.utils.from_numpy( + x_t = ctx.from_numpy( np.empty(output_shape, dtype=get_tensor_dtype(x)), - ctx.ggml_context, ) @ggml.ggml_custom3_op_t @@ -4592,14 +4588,12 @@ def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape[axis] = k_np output_shape = tuple(output_shape) - indices_t = ggml.utils.from_numpy( + indices_t = ctx.from_numpy( np.empty(output_shape, dtype=np.int32), - ctx.ggml_context, ) - values_t = ggml.utils.from_numpy( + values_t = ctx.from_numpy( np.empty(output_shape, dtype=get_tensor_dtype(x)), - ctx.ggml_context, ) @ggml.ggml_custom2_op_t From b12d692f700e794ad03e69a1b60ae96d3569e6f2 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 19 Sep 2023 21:31:27 -0400 Subject: [PATCH 173/232] Dynamic memory allocation --- ggml/contrib/onnx.py | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 32112114..5f703a2a 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4933,13 +4933,18 @@ def to_numpy(self, tensor: ggml.ggml_tensor_p) -> np.ndarray: array = ggml.utils.to_numpy(tensor) return array.reshape(shape) + def alloc_tensor_cpu(self, tensor: ggml.ggml_tensor_p): + if tensor.contents.data: + return + buffer = (ctypes.c_uint8 * ggml.ggml_nbytes_pad(tensor))() + self.refs.append(buffer) + tensor.contents.data = ctypes.cast(ctypes.addressof(buffer), ctypes.c_void_p) + def from_numpy(self, array: np.ndarray) -> ggml.ggml_tensor_p: shape = array.shape tensor = ggml.utils.from_numpy(array, self.ggml_context) if array.size > 0: - buffer = (ctypes.c_uint8 * ggml.ggml_nbytes_pad(tensor))() - self.refs.append(buffer) - tensor.contents.data = ctypes.cast(ctypes.addressof(buffer), ctypes.c_void_p) + self.alloc_tensor_cpu(tensor) self.set_tensor_out(tensor, array) self.set_tensor_shape(tensor, shape) return tensor @@ -4954,13 +4959,30 @@ def compute_graph(self, gf: ggml.ggml_cgraph): def eval_tensor( self, tensor: ggml.ggml_tensor_p ): + self.alloc_tensor_cpu(tensor) gf = ggml.ggml_build_forward(tensor) + # NOTE: Should probably save / restore data pointers here for intermediate tensors + alignment = 32 + alloc_size = ggml.utils.alloc_graph_measure(gf, alignment=32) + alloc_buffer = (ctypes.c_uint8 * alloc_size)() + leaf_data = [ggml.ggml_get_data(gf.leafs[i]) for i in range(gf.n_leafs)] + node_data = [ggml.ggml_get_data(gf.nodes[i]) for i in range(gf.n_nodes)] + allocr = ggml.ggml_allocr_new(alloc_buffer, alloc_size, alignment) + ggml.ggml_allocr_alloc_graph(allocr, ctypes.byref(gf)) self.compute_graph(gf) + ggml.ggml_allocr_free(allocr) + for i in range(gf.n_leafs): + gf.leafs[i].contents.data = leaf_data[i] + for i in range(gf.n_nodes): + gf.nodes[i].contents.data = node_data[i] return tensor def set_tensor_out(self, tensor: ggml.ggml_tensor_p, array: np.ndarray): output_shape = get_tensor_shape(tensor) + if array.size == 0: + return + if output_shape == (): self.to_numpy(tensor)[()] = array else: @@ -5084,12 +5106,9 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: set_tensor_out(tensor, np.array(value)) # Define context - # max_overhead = 2 * ggml.GGML_MAX_NODES * ggml.ggml_tensor_overhead() - # ggml_context = ggml.ggml_init( - # params=ggml.ggml_init_params(mem_size=max_overhead, mem_buffer=None, no_alloc=True) - # ) + max_overhead = 2 * ggml.GGML_MAX_NODES * ggml.ggml_tensor_overhead() ggml_context = ggml.ggml_init( - params=ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None) + params=ggml.ggml_init_params(mem_size=max_overhead, mem_buffer=None, no_alloc=True) ) refs: List[Any] = [] @@ -5114,16 +5133,17 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: for output in node.output: if output in output_names: ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) + ctx.eval_tensor(ggml_tensors[output]) - # Compute graph - ctx.compute_graph(gf) graph_outputs = [] for output in self.outputs: exit_node = ggml_tensors[output.name] + # NOTE: 0 dimension in ggml may cause bugs + size = np.prod(ctx.get_tensor_shape(exit_node)) graph_output = ggml.utils.to_numpy( exit_node - ) # TODO: Add checks to convert values back to bool or etc types + ) if size > 0 else np.empty((0)) # TODO: Add checks to convert values back to bool or etc types graph_output = graph_output.astype( get_final_dtype(exit_node) ) # TODO: add a second dict to keep track of types and use that instead From 5fff3470841d96152976e51014b5cf37e6695f7b Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 19 Sep 2023 18:33:30 -0700 Subject: [PATCH 174/232] fix eval_tensor call --- ggml/contrib/onnx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index e247aeb7..afd54d3d 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -2796,7 +2796,7 @@ def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) for node_input in node_inputs: - ctx.backend.eval_tensor(node_input) + ctx.eval_tensor(node_input) tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] start, stop, step = tensors From 4de126b0bda54e093cb69e39b81bbba526fd4047 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 19 Sep 2023 22:06:30 -0400 Subject: [PATCH 175/232] Save overloaded dtypes in execution context dict --- ggml/contrib/onnx.py | 55 +++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index e247aeb7..90c522d7 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -251,7 +251,7 @@ def custom_and( ) ctx.refs.append(custom_and) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.bool_)) return new_tensor @@ -350,7 +350,7 @@ def custom_arg_max( ) ctx.refs.append(custom_arg_max) - ggml.ggml_set_name(new_tensor, (name + "").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.int64)) ctx.refs.append(argmax_userdata) return new_tensor @@ -440,7 +440,7 @@ def custom_arg_min( ) ctx.refs.append(custom_arg_min) - ggml.ggml_set_name(new_tensor, (name + "").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.int64)) ctx.refs.append(argmax_userdata) return new_tensor @@ -726,7 +726,7 @@ def custom_constant( ) ctx.refs.append(custom_constant) - ggml.ggml_set_name(new_tensor, (name + f"<{np_data_type}>").encode()) + ctx.set_tensor_dtype(name, np_data_type) return new_tensor @@ -1239,7 +1239,7 @@ def custom_dropout_output( ctx.refs.append(droput_userdata) if len(node.output) == 2: - ggml.ggml_set_name(mask, (node.output[1] + f"").encode()) + ctx.set_tensor_dtype(node.output[1], np.dtype(np.bool_)) ctx.tensors_dict[node.output[0]] = output ctx.tensors_dict[node.output[1]] = mask @@ -1328,7 +1328,7 @@ def custom_equal( ctx.refs.append(custom_equal) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.bool_)) return new_tensor @@ -1741,7 +1741,7 @@ def custom_greater( ctx.refs.append(custom_greater) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.bool_)) return new_tensor @@ -1865,7 +1865,6 @@ def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): y = ggml.ggml_dup( ctx.ggml_context, x ) # NOTE: This will freeze the tensor in time, may not be expected. - ggml.ggml_set_name(y, output_name.encode()) ctx.tensors_dict[output_name] = y @@ -2097,7 +2096,7 @@ def custom_greater_equal( ctx.refs.append(custom_greater_equal) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.bool_)) return new_tensor @@ -2152,7 +2151,7 @@ def custom_less( ctx.refs.append(custom_less) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.bool_)) return new_tensor @@ -2207,7 +2206,7 @@ def custom_less_equal( ctx.refs.append(custom_less_equal) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.bool_)) return new_tensor @@ -2514,7 +2513,7 @@ def custom_not( ctx.refs.append(custom_not) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.bool_)) return new_tensor @@ -2569,7 +2568,7 @@ def custom_or( ctx.refs.append(custom_or) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.bool_)) return new_tensor @@ -3928,7 +3927,7 @@ def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): shape_slice ) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.int64)) return new_tensor @@ -4020,7 +4019,7 @@ def custom_size( ctx.refs.append(custom_size) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.int64)) return new_tensor @@ -4682,7 +4681,7 @@ def custom_top_k_values( ctx.refs.append(topk_userdata) - ggml.ggml_set_name(indices, (node.output[1] + f"").encode()) + ctx.set_tensor_dtype(node.output[1], np.dtype(np.int64)) return values, indices @@ -4902,7 +4901,7 @@ def custom_xor( ctx.refs.append(custom_xor) - ggml.ggml_set_name(new_tensor, (name + f"").encode()) + ctx.set_tensor_dtype(name, np.dtype(np.bool_)) return new_tensor @@ -4920,6 +4919,7 @@ def __init__( self.ggml_context = ggml_context self.refs = refs self.shapes = {} + self.dtypes = {} def set_tensor_shape(self, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...]): data = tensor.contents.data @@ -4931,6 +4931,25 @@ def get_tensor_shape(self, tensor: ggml.ggml_tensor_p) -> Tuple[int, ...]: self.shapes[data] = get_tensor_shape(tensor) return self.shapes[data] + def set_tensor_dtype(self, name: str, dtype: np.dtype): + self.dtypes[name] = dtype + + def get_tensor_dtype(self, name: str) -> np.dtype: + tensor_dtype = get_tensor_dtype(self.tensors_dict[name]) + return self.dtypes.get(name, tensor_dtype) + + def get_final_dtype(self, tensor: ggml.ggml_tensor_p, pattern: str = r"<(.*?)>"): + tensor_name = tensor.contents.name.decode() + tensor_dtype = get_tensor_dtype(tensor) + + match = re.search(pattern, tensor_name) + + if match: + dtype_str = match.group(1) + tensor_dtype = np.dtype(dtype_str) + + return tensor_dtype + def to_numpy(self, tensor: ggml.ggml_tensor_p) -> np.ndarray: shape = self.get_tensor_shape(tensor) array = ggml.utils.to_numpy(tensor) @@ -5148,7 +5167,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: exit_node ) if size > 0 else np.empty((0)) # TODO: Add checks to convert values back to bool or etc types graph_output = graph_output.astype( - get_final_dtype(exit_node) + ctx.get_tensor_dtype(output.name) ) # TODO: add a second dict to keep track of types and use that instead shape = ctx.get_tensor_shape(exit_node) From 1abf44d9af3b4108a5f0baeacc40dccf6ef6d4bd Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 20 Sep 2023 02:53:14 -0400 Subject: [PATCH 176/232] Fix several type issues --- ggml/contrib/onnx.py | 92 +++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 60 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index cdef36a2..e612811b 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5,7 +5,7 @@ import ctypes import math import re -from typing import Any, Dict, List, Optional, Tuple, Sequence +from typing import Any, Callable, Dict, List, Optional, Tuple, Sequence from typing_extensions import TypeGuard import numpy as np @@ -13,27 +13,29 @@ import onnx from onnx.backend.base import Backend, BackendRep from onnx.helper import np_dtype_to_tensor_dtype, tensor_dtype_to_np_dtype -from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto, ValueInfoProto +from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto, ValueInfoProto, TensorProto import ggml import ggml.utils -ggml_operators = {} -onnx_dtype_map = { +GgmlOperator = Callable[["GgmlOnnxExecutionContext", NodeProto], ggml.ggml_tensor_p] + +ggml_operators: Dict[str, GgmlOperator] = {} +onnx_dtype_map: Dict[int, npt.DTypeLike] = { elem_type: np_dtype - for elem_type, np_dtype in onnx.mapping.TENSOR_TYPE_TO_NP_TYPE.items() + for elem_type, np_dtype in onnx.mapping.TENSOR_TYPE_TO_NP_TYPE.items() # type: ignore } -def ggml_operator(operator): - def inner(func): +def ggml_operator(operator: str): + def inner(func: GgmlOperator): ggml_operators[operator] = func return func return inner -def map_to_ggml_type(dtype: np.dtype): +def map_to_ggml_type(dtype: npt.DTypeLike): np_data_type_limit = np.dtype(str(dtype).replace("64", "32")) ggml_type = ggml.utils.NUMPY_DTYPE_TO_GGML_TYPE.get( np_data_type_limit.type, @@ -43,11 +45,11 @@ def map_to_ggml_type(dtype: np.dtype): return ggml_type -def get_tensor_shape(tensor): +def get_tensor_shape(tensor: ggml.ggml_tensor_p) -> Tuple[int, ...]: return tuple(reversed(ggml.utils.get_shape(tensor))) -def set_tensor_out(tensor, ndarray): +def set_tensor_out(tensor: ggml.ggml_tensor_p, ndarray: npt.NDArray[Any]): output_shape = get_tensor_shape(tensor) if output_shape == (): @@ -56,7 +58,7 @@ def set_tensor_out(tensor, ndarray): ggml.utils.to_numpy(tensor)[:] = ndarray -def get_tensor_dtype(tensor): +def get_tensor_dtype(tensor: ggml.ggml_tensor_p) -> npt.DTypeLike: ggml_type = ggml.utils.GGML_TYPE(tensor.contents.type) if ggml_type == ggml.utils.GGML_TYPE.F16: ctypes_type = ctypes.c_uint16 @@ -68,7 +70,7 @@ def get_tensor_dtype(tensor): def can_quantize( - np_array: np.ndarray, + np_array: npt.NDArray[Any], name: str, graph_def: GraphProto, ): @@ -95,7 +97,7 @@ def can_quantize( def broadcast_tensor( - ctx: ggml.ggml_context_p, tensor: ggml.ggml_tensor_p, shape: Tuple + ctx: ggml.ggml_context_p, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...] ): ggml_type = ggml.utils.GGML_TYPE(tensor.contents.type) @@ -112,11 +114,6 @@ def broadcast_tensor( new_tensor, ) - # if ggml.utils.get_shape(tensor) == (): - # ggml.utils.to_numpy(new_tensor)[()] = ggml.utils.to_numpy(tensor) - # else: - # ggml.utils.to_numpy(new_tensor)[:] = ggml.utils.to_numpy(tensor) - return new_tensor @@ -143,19 +140,6 @@ def broadcast_shapes( return a_shaped, b_shaped -def get_final_dtype(tensor: ggml.ggml_tensor_p, pattern: str = r"<(.*?)>"): - tensor_name = tensor.contents.name.decode() - tensor_dtype = get_tensor_dtype(tensor) - - match = re.search(pattern, tensor_name) - - if match: - dtype_str = match.group(1) - tensor_dtype = np.dtype(dtype_str) - - return tensor_dtype - - # ------ Operators ------ @@ -359,7 +343,7 @@ def custom_arg_max( @ggml_operator("ArgMin") -def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): +def ggml_operator_arg_min(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: @@ -4918,8 +4902,8 @@ def __init__( self.tensors_dict = tensors_dict self.ggml_context = ggml_context self.refs = refs - self.shapes = {} - self.dtypes = {} + self.shapes: Dict[str, Tuple[int, ...]] = {} + self.dtypes: Dict[str, npt.DTypeLike] = {} def set_tensor_shape(self, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...]): data = tensor.contents.data @@ -4931,26 +4915,14 @@ def get_tensor_shape(self, tensor: ggml.ggml_tensor_p) -> Tuple[int, ...]: self.shapes[data] = get_tensor_shape(tensor) return self.shapes[data] - def set_tensor_dtype(self, name: str, dtype: np.dtype): + def set_tensor_dtype(self, name: str, dtype: npt.DTypeLike): self.dtypes[name] = dtype - def get_tensor_dtype(self, name: str) -> np.dtype: + def get_tensor_dtype(self, name: str) -> npt.DTypeLike: tensor_dtype = get_tensor_dtype(self.tensors_dict[name]) return self.dtypes.get(name, tensor_dtype) - def get_final_dtype(self, tensor: ggml.ggml_tensor_p, pattern: str = r"<(.*?)>"): - tensor_name = tensor.contents.name.decode() - tensor_dtype = get_tensor_dtype(tensor) - - match = re.search(pattern, tensor_name) - - if match: - dtype_str = match.group(1) - tensor_dtype = np.dtype(dtype_str) - - return tensor_dtype - - def to_numpy(self, tensor: ggml.ggml_tensor_p) -> np.ndarray: + def to_numpy(self, tensor: ggml.ggml_tensor_p) -> npt.NDArray[Any]: shape = self.get_tensor_shape(tensor) array = ggml.utils.to_numpy(tensor) return array.reshape(shape) @@ -4962,7 +4934,7 @@ def alloc_tensor_cpu(self, tensor: ggml.ggml_tensor_p): self.refs.append(buffer) tensor.contents.data = ctypes.cast(ctypes.addressof(buffer), ctypes.c_void_p) - def from_numpy(self, array: np.ndarray) -> ggml.ggml_tensor_p: + def from_numpy(self, array: npt.NDArray[Any]) -> ggml.ggml_tensor_p: shape = array.shape tensor = ggml.utils.from_numpy(array, self.ggml_context) if array.size > 0: @@ -4973,9 +4945,9 @@ def from_numpy(self, array: np.ndarray) -> ggml.ggml_tensor_p: def compute_graph(self, gf: ggml.ggml_cgraph): gp = ggml.ggml_graph_plan(ctypes.pointer(gf), 1) - work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size else None - if gp.work_size: - gp.work = ctypes.cast(ctypes.addressof(work_buffer), ctypes.c_void_p) + work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size > 0 else None + if gp.work_size > 0: + gp.work = ctypes.cast(work_buffer, ctypes.c_void_p) ggml.ggml_graph_compute(ctypes.byref(gf), ctypes.byref(gp)) def eval_tensor( @@ -4989,7 +4961,7 @@ def eval_tensor( alloc_buffer = (ctypes.c_uint8 * alloc_size)() leaf_data = [ggml.ggml_get_data(gf.leafs[i]) for i in range(gf.n_leafs)] node_data = [ggml.ggml_get_data(gf.nodes[i]) for i in range(gf.n_nodes)] - allocr = ggml.ggml_allocr_new(alloc_buffer, alloc_size, alignment) + allocr = ggml.ggml_allocr_new(ctypes.cast(alloc_buffer, ctypes.c_void_p), alloc_size, alignment) ggml.ggml_allocr_alloc_graph(allocr, ctypes.byref(gf)) self.compute_graph(gf) ggml.ggml_allocr_free(allocr) @@ -4999,7 +4971,7 @@ def eval_tensor( gf.nodes[i].contents.data = node_data[i] return tensor - def set_tensor_out(self, tensor: ggml.ggml_tensor_p, array: np.ndarray): + def set_tensor_out(self, tensor: ggml.ggml_tensor_p, array: npt.NDArray[Any]): output_shape = self.get_tensor_shape(tensor) if array.size == 0: @@ -5143,7 +5115,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Build layers for node in model_graph.node: - operator_func = ggml_operators.get(node.op_type) + operator_func: Optional[GgmlOperator] = ggml_operators.get(node.op_type) if operator_func is None: raise NotImplementedError(f'Operator "{node.op_type}" not implemented') @@ -5158,12 +5130,12 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ctx.eval_tensor(ggml_tensors[output]) - graph_outputs = [] + graph_outputs: List[npt.NDArray[Any]] = [] for output in self.outputs: exit_node = ggml_tensors[output.name] # NOTE: 0 dimension in ggml may cause bugs size = np.prod(ctx.get_tensor_shape(exit_node)) - graph_output = ggml.utils.to_numpy( + graph_output: npt.NDArray[Any] = ggml.utils.to_numpy( exit_node ) if size > 0 else np.empty((0)) # TODO: Add checks to convert values back to bool or etc types graph_output = graph_output.astype( @@ -5211,11 +5183,11 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): ggml_context = ggml.ggml_init(init_params) total_nbytes = 0 - pairs = [] + pairs: List[Tuple[ggml.ggml_tensor_p, TensorProto]] = [] for initializer in graph.initializer: name = initializer.name - np_array = onnx.numpy_helper.to_array(initializer) + np_array: npt.NDArray[Any] = onnx.numpy_helper.to_array(initializer) # type: ignore tensor = ggml.utils.from_numpy(x=np_array, ctx=ggml_context) ggml.ggml_set_name(tensor=tensor, name=name.encode()) total_nbytes += ggml.ggml_nbytes_pad(tensor) From 15d21240d8e86e6504cc2320994c5995650a0cfd Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 20 Sep 2023 21:06:35 -0400 Subject: [PATCH 177/232] Remove unnused import --- ggml/contrib/onnx.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index e612811b..cdfa7c1c 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4,7 +4,6 @@ """ import ctypes import math -import re from typing import Any, Callable, Dict, List, Optional, Tuple, Sequence from typing_extensions import TypeGuard From ce5d9d2bca7aa1d0901bf6b0d9b12911cba23a0b Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Thu, 21 Sep 2023 00:56:04 -0400 Subject: [PATCH 178/232] Remove unnused operator returns --- ggml/contrib/onnx.py | 192 ++----------------------------------------- 1 file changed, 6 insertions(+), 186 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index cdfa7c1c..bbaaae2f 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -17,7 +17,7 @@ import ggml import ggml.utils -GgmlOperator = Callable[["GgmlOnnxExecutionContext", NodeProto], ggml.ggml_tensor_p] +GgmlOperator = Callable[["GgmlOnnxExecutionContext", NodeProto], None] ggml_operators: Dict[str, GgmlOperator] = {} onnx_dtype_map: Dict[int, npt.DTypeLike] = { @@ -159,7 +159,6 @@ def ggml_operator_abs(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, ) ctx.tensors_dict[output_name] = abs_result - return abs_result @ggml_operator("Add") @@ -182,7 +181,6 @@ def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): b, ) ctx.tensors_dict[output_name] = add_result - return add_result @@ -236,8 +234,6 @@ def custom_and( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - return new_tensor - class ArgOpsUserData(ctypes.Structure): _fields_ = [ @@ -336,8 +332,6 @@ def custom_arg_max( ctx.set_tensor_dtype(name, np.dtype(np.int64)) ctx.refs.append(argmax_userdata) - return new_tensor - @@ -426,8 +420,6 @@ def custom_arg_min( ctx.set_tensor_dtype(name, np.dtype(np.int64)) ctx.refs.append(argmax_userdata) - return new_tensor - @@ -479,8 +471,6 @@ def custom_cast( ctx.refs.append(onnx_type_c) - return new_tensor - @ggml_operator("CastLike") def ggml_operator_castlike(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -531,8 +521,6 @@ def custom_cast( ctx.refs.append(onnx_type_c) - return new_tensor - @ggml_operator("Ceil") def ggml_operator_ceil(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -570,8 +558,6 @@ def custom_ceil( ctx.refs.append(custom_ceil) - return new_tensor - @ggml_operator("Concat") def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -629,12 +615,10 @@ def concat_2(tensor_a, tensor_b): ) ctx.refs.append(custom_concat) - return new_tensor new_tensor = node_inputs[0] for tensor in node_inputs[1:]: new_tensor = concat_2(new_tensor, tensor) - return new_tensor @@ -710,7 +694,6 @@ def custom_constant( ctx.refs.append(custom_constant) ctx.set_tensor_dtype(name, np_data_type) - return new_tensor @@ -784,8 +767,6 @@ def custom_constant_of_shape( ctx.refs.append(custom_constant_of_shape) - return new_tensor - @ggml_operator("Conv") def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -867,7 +848,6 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) ctx.tensors_dict[node.output[0]] = conv_result - return conv_result @ggml_operator("ConvTranspose") @@ -1071,8 +1051,6 @@ def custom_depth_to_space( ctx.refs.append(depthtospace_userdata) - return new_tensor - @ggml_operator("Div") def ggml_operator_div(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -1229,7 +1207,6 @@ def custom_dropout_output( return output, mask ctx.tensors_dict[node.output[0]] = output - return output @ggml_operator("Elu") @@ -1258,7 +1235,6 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): Y = ctx.from_numpy(Y_alpha) ctx.tensors_dict[output_name] = Y - return Y @@ -1313,8 +1289,6 @@ def custom_equal( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - return new_tensor - @ggml_operator("Exp") def ggml_operator_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -1352,8 +1326,6 @@ def custom_exp( ctx.refs.append(custom_exp) - return new_tensor - @ggml_operator("Expand") def ggml_operator_expand(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -1391,7 +1363,6 @@ def custom_expand( None, ) ctx.refs.append(custom_expand) - return new_tensor @@ -1454,8 +1425,6 @@ def custom_flatten( ctx.refs.append(custom_flatten) ctx.refs.append(axis_c) - return new_tensor - @@ -1493,8 +1462,6 @@ def custom_floor( ctx.refs.append(custom_floor) - return new_tensor - @@ -1557,8 +1524,6 @@ def custom_gather( if output_shape == (): ctx.set_tensor_shape(new_tensor, ()) - return new_tensor - @ggml_operator("Gemm") def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -1671,8 +1636,6 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) ctx.tensors_dict[node.output[0]] = mul_mat_result - return mul_mat_result - @@ -1726,8 +1689,6 @@ def custom_greater( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - return new_tensor - class HardSigmoidUserData(ctypes.Structure): _fields_ = [ @@ -1784,8 +1745,6 @@ def custom_hard_sigmoid( ctx.refs.append(hsig_userdata) - return new_tensor - @@ -1831,8 +1790,6 @@ def custom_hardmax( ctx.refs.append(axis_c) - return new_tensor - @ggml_operator("Identity") def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -1851,8 +1808,6 @@ def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = y - return y - @@ -1900,7 +1855,6 @@ def custom_instancenorm( ) ctx.refs.append(custom_instancenorm) ctx.refs.append(epsilon_c) - return new_tensor class LRNUserData(ctypes.Structure): @@ -1982,8 +1936,6 @@ def custom_leaky_lrn( ctx.refs.append(custom_leaky_lrn) ctx.refs.append(lrn_userdata) - return new_tensor - @@ -2026,8 +1978,6 @@ def custom_leaky_relu( ctx.refs.append(custom_leaky_relu) ctx.refs.append(axis_c) - return new_tensor - @@ -2081,8 +2031,6 @@ def custom_greater_equal( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - return new_tensor - @@ -2136,8 +2084,6 @@ def custom_less( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - return new_tensor - @@ -2191,8 +2137,6 @@ def custom_less_equal( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - return new_tensor - @ggml_operator("Log") def ggml_operator_log(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -2211,7 +2155,6 @@ def ggml_operator_log(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, ) ctx.tensors_dict[output_name] = log_result - return log_result @ggml_operator("LogSoftmax") @@ -2231,7 +2174,6 @@ def ggml_operator_log_soft_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto) soft_max_result, ) ctx.tensors_dict[output_name] = log_result - return log_result @ggml_operator("MatMul") @@ -2281,7 +2223,6 @@ def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) ctx.tensors_dict[output_name] = mul_mat_result - return mul_mat_result @ggml_operator("Max") @@ -2333,8 +2274,6 @@ def custom_max( ctx.refs.append(custom_max) - return new_tensor - @ggml_operator("Mean") def ggml_operator_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -2361,7 +2300,6 @@ def ggml_operator_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) ctx.tensors_dict[output_name] = mean - return mean @ggml_operator("Min") @@ -2413,8 +2351,6 @@ def custom_min( ctx.refs.append(custom_min) - return new_tensor - @ggml_operator("Mul") def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -2438,7 +2374,6 @@ def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) ctx.tensors_dict[output_name] = mul_result - return mul_result @ggml_operator("Neg") @@ -2458,9 +2393,6 @@ def ggml_operator_neg(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x, ) ctx.tensors_dict[output_name] = x_neg - return x_neg - - @ggml_operator("Not") @@ -2498,10 +2430,6 @@ def custom_not( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - return new_tensor - - - @ggml_operator("Or") def ggml_operator_or(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -2553,8 +2481,6 @@ def custom_or( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - return new_tensor - @ggml_operator("Pad") def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -2638,9 +2564,6 @@ def custom_pad( None, ) ctx.refs.append(custom_pad) - return new_tensor - - @ggml_operator("PRelu") @@ -2680,9 +2603,6 @@ def custom_leaky_prelu( ctx.refs.append(custom_leaky_prelu) - return new_tensor - - @ggml_operator("Pow") @@ -2724,9 +2644,6 @@ def custom_pow( ctx.refs.append(custom_pow) - return new_tensor - - @ggml_operator("Reciprocal") @@ -2763,9 +2680,6 @@ def custom_reciprocal( ctx.refs.append(custom_reciprocal) - return new_tensor - - @ggml_operator("Range") @@ -2816,8 +2730,6 @@ def custom_range( ctx.refs.append(custom_range) - return new_tensor - class ReduceOpsUserData(ctypes.Structure): _fields_ = [ @@ -2926,9 +2838,6 @@ def custom_reduce_l1( ctx.refs.append(rmean_userdata) - return new_tensor - - @ggml_operator("ReduceL2") @@ -3017,9 +2926,6 @@ def custom_reduce_l2( ctx.refs.append(rmean_userdata) - return new_tensor - - @ggml_operator("ReduceLogSum") @@ -3107,9 +3013,6 @@ def custom_reduce_log_sum( ctx.refs.append(rmean_userdata) - return new_tensor - - @ggml_operator("ReduceLogSumExp") @@ -3200,10 +3103,6 @@ def custom_reduce_log_sum_exp( ctx.refs.append(rmean_userdata) - return new_tensor - - - @ggml_operator("ReduceMax") def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -3290,8 +3189,6 @@ def custom_reduce_max( ctx.refs.append(rmean_userdata) - return new_tensor - @@ -3312,7 +3209,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if noop_with_empty_axes == 1: ctx.tensors_dict[node.output[0]] = input_tensor - return input_tensor + return tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) @@ -3380,9 +3277,6 @@ def custom_reduce_mean( ctx.refs.append(rmean_userdata) - return new_tensor - - @ggml_operator("ReduceMin") @@ -3402,7 +3296,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if noop_with_empty_axes == 1: ctx.tensors_dict[node.output[0]] = input_tensor - return input_tensor + return tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) @@ -3470,10 +3364,6 @@ def custom_reduce_min( ctx.refs.append(rmean_userdata) - return new_tensor - - - @ggml_operator("ReduceProd") def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -3492,7 +3382,7 @@ def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if noop_with_empty_axes == 1: ctx.tensors_dict[node.output[0]] = input_tensor - return input_tensor + return tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) @@ -3560,10 +3450,6 @@ def custom_reduce_prod( ctx.refs.append(rmean_userdata) - return new_tensor - - - @ggml_operator("ReduceSum") def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -3582,7 +3468,7 @@ def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if noop_with_empty_axes == 1: ctx.tensors_dict[node.output[0]] = input_tensor - return input_tensor + return tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) @@ -3649,10 +3535,6 @@ def custom_reduce_sum( ctx.refs.append(rmean_userdata) - return new_tensor - - - @ggml_operator("ReduceSumSquare") def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -3671,7 +3553,7 @@ def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeP if noop_with_empty_axes == 1: ctx.tensors_dict[node.output[0]] = input_tensor - return input_tensor + return tensor_shape = get_tensor_shape(input_tensor) tensor_dtype = get_tensor_dtype(input_tensor) @@ -3739,8 +3621,6 @@ def custom_reduce_sum_square( ctx.refs.append(rmean_userdata) - return new_tensor - @ggml_operator("Relu") def ggml_operator_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -3759,7 +3639,6 @@ def ggml_operator_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, ) ctx.tensors_dict[output_name] = relu_result - return relu_result @ggml_operator("Reshape") @@ -3817,8 +3696,6 @@ def custom_reshape( ctx.refs.append(custom_reshape) - return new_tensor - class SeluUserData(ctypes.Structure): _fields_ = [ @@ -3886,8 +3763,6 @@ def custom_selu( ctx.refs.append(selu_userdata) - return new_tensor - @ggml_operator("Shape") def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -3912,10 +3787,6 @@ def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.set_tensor_dtype(name, np.dtype(np.int64)) - return new_tensor - - - @ggml_operator("Sigmoid") def ggml_operator_sigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -3952,10 +3823,6 @@ def custom_sigmoid( ctx.refs.append(custom_sigmoid) - return new_tensor - - - @ggml_operator("Size") def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -4004,8 +3871,6 @@ def custom_size( ctx.set_tensor_dtype(name, np.dtype(np.int64)) - return new_tensor - @ggml_operator("Slice") def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -4063,7 +3928,6 @@ def custom_slice( ctx.ggml_context, x_t, node_inputs[0], custom_slice, 1, None ) ctx.refs.append(custom_slice) - return new_tensor @ggml_operator("Softmax") @@ -4083,9 +3947,6 @@ def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, ) ctx.tensors_dict[output_name] = soft_max_result - return soft_max_result - - @ggml_operator("Softplus") @@ -4121,8 +3982,6 @@ def custom_softplus( ctx.refs.append(custom_softplus) - return new_tensor - @ggml_operator("Softsign") def ggml_operator_softsign(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -4145,10 +4004,6 @@ def ggml_operator_softsign(ctx: "GgmlOnnxExecutionContext", node: NodeProto): y = ggml.ggml_div(ctx.ggml_context, x, one_plus_abs) ctx.tensors_dict[node.output[0]] = y - return y - - - @ggml_operator("SpaceToDepth") def ggml_operator_space_to_depth(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -4217,8 +4072,6 @@ def custom_space_to_depth( ctx.refs.append(blocksize_c) - return new_tensor - class SplitUserData(ctypes.Structure): _fields_ = [ @@ -4227,8 +4080,6 @@ class SplitUserData(ctypes.Structure): ] - - @ggml_operator("Split") def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4330,8 +4181,6 @@ def custom_split( ctx.refs.append(split_userdata) outputs.append(new_tensor) - return outputs - @ggml_operator("Sqrt") def ggml_operator_sqrt(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -4350,7 +4199,6 @@ def ggml_operator_sqrt(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, ) ctx.tensors_dict[output_name] = sqrt_result - return sqrt_result @ggml_operator("Squeeze") @@ -4403,7 +4251,6 @@ def custom_squeeze( None, ) ctx.refs.append(custom_squeeze) - return new_tensor @ggml_operator("Sub") @@ -4425,7 +4272,6 @@ def ggml_operator_sub(ctx: "GgmlOnnxExecutionContext", node: NodeProto): b, ) ctx.tensors_dict[output_name] = sub_result - return sub_result @ggml_operator("Sum") @@ -4454,8 +4300,6 @@ def ggml_operator_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = next_item - return next_item - @ggml_operator("Tanh") def ggml_operator_tanh(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -4474,10 +4318,6 @@ def ggml_operator_tanh(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[node.output[0]] = tanh_result - return tanh_result - - - @ggml_operator("Tile") def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -4530,8 +4370,6 @@ def custom_tile( ctx.refs.append(custom_tile) - return new_tensor - class TopKUserData(ctypes.Structure): _fields_ = [ @@ -4542,10 +4380,6 @@ class TopKUserData(ctypes.Structure): ] - - - - @ggml_operator("TopK") def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4666,8 +4500,6 @@ def custom_top_k_values( ctx.set_tensor_dtype(node.output[1], np.dtype(np.int64)) - return values, indices - @ggml_operator("Transpose") def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -4713,9 +4545,6 @@ def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) ctx.tensors_dict[output_name] = transpose_result - return transpose_result - - @ggml_operator("Unsqueeze") @@ -4790,9 +4619,6 @@ def custom_unsqueeze( None, ) ctx.refs.append(custom_unsqueeze) - return new_tensor - - @ggml_operator("Where") @@ -4831,10 +4657,6 @@ def custom_where( ) ctx.refs.append(custom_where) - return new_tensor - - - @ggml_operator("Xor") def ggml_operator_xor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -4886,8 +4708,6 @@ def custom_xor( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - return new_tensor - class GgmlOnnxExecutionContext: def __init__( From 1bad529ebce0d060dff1d32cfdef61e77c3b94f4 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 25 Sep 2023 16:20:44 -0400 Subject: [PATCH 179/232] rename ggml_operator to register_ggml_operator --- ggml/contrib/onnx.py | 166 +++++++++++++++++++++---------------------- 1 file changed, 83 insertions(+), 83 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index bbaaae2f..97fe1cc8 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -26,7 +26,7 @@ } -def ggml_operator(operator: str): +def register_ggml_operator(operator: str): def inner(func: GgmlOperator): ggml_operators[operator] = func return func @@ -142,7 +142,7 @@ def broadcast_shapes( # ------ Operators ------ -@ggml_operator("Abs") +@register_ggml_operator("Abs") def ggml_operator_abs(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -161,7 +161,7 @@ def ggml_operator_abs(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = abs_result -@ggml_operator("Add") +@register_ggml_operator("Add") def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -185,7 +185,7 @@ def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): -@ggml_operator("And") +@register_ggml_operator("And") def ggml_operator_and(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -245,7 +245,7 @@ class ArgOpsUserData(ctypes.Structure): -@ggml_operator("ArgMax") +@register_ggml_operator("ArgMax") def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -335,7 +335,7 @@ def custom_arg_max( -@ggml_operator("ArgMin") +@register_ggml_operator("ArgMin") def ggml_operator_arg_min(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -423,7 +423,7 @@ def custom_arg_min( -@ggml_operator("Cast") +@register_ggml_operator("Cast") def ggml_operator_cast(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -472,7 +472,7 @@ def custom_cast( ctx.refs.append(onnx_type_c) -@ggml_operator("CastLike") +@register_ggml_operator("CastLike") def ggml_operator_castlike(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -522,7 +522,7 @@ def custom_cast( ctx.refs.append(onnx_type_c) -@ggml_operator("Ceil") +@register_ggml_operator("Ceil") def ggml_operator_ceil(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -559,7 +559,7 @@ def custom_ceil( ctx.refs.append(custom_ceil) -@ggml_operator("Concat") +@register_ggml_operator("Concat") def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -623,7 +623,7 @@ def concat_2(tensor_a, tensor_b): -@ggml_operator("Constant") +@register_ggml_operator("Constant") def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_attributes = node.attribute name = node.output[0] @@ -698,7 +698,7 @@ def custom_constant( -@ggml_operator("ConstantOfShape") +@register_ggml_operator("ConstantOfShape") def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -768,7 +768,7 @@ def custom_constant_of_shape( ctx.refs.append(custom_constant_of_shape) -@ggml_operator("Conv") +@register_ggml_operator("Conv") def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -850,7 +850,7 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[node.output[0]] = conv_result -@ggml_operator("ConvTranspose") +@register_ggml_operator("ConvTranspose") def ggml_operator_convtranspose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -966,7 +966,7 @@ class DepthToSpaceUserData(ctypes.Structure): -@ggml_operator("DepthToSpace") +@register_ggml_operator("DepthToSpace") def ggml_operator_depth_to_space(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1052,7 +1052,7 @@ def custom_depth_to_space( ctx.refs.append(depthtospace_userdata) -@ggml_operator("Div") +@register_ggml_operator("Div") def ggml_operator_div(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1087,7 +1087,7 @@ class DropoutUserData(ctypes.Structure): -@ggml_operator("Dropout") +@register_ggml_operator("Dropout") def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1209,7 +1209,7 @@ def custom_dropout_output( ctx.tensors_dict[node.output[0]] = output -@ggml_operator("Elu") +@register_ggml_operator("Elu") def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1239,7 +1239,7 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): -@ggml_operator("Equal") +@register_ggml_operator("Equal") def ggml_operator_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1290,7 +1290,7 @@ def custom_equal( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) -@ggml_operator("Exp") +@register_ggml_operator("Exp") def ggml_operator_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1327,7 +1327,7 @@ def custom_exp( ctx.refs.append(custom_exp) -@ggml_operator("Expand") +@register_ggml_operator("Expand") def ggml_operator_expand(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1367,7 +1367,7 @@ def custom_expand( -@ggml_operator("Flatten") +@register_ggml_operator("Flatten") def ggml_operator_flatten(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1428,7 +1428,7 @@ def custom_flatten( -@ggml_operator("Floor") +@register_ggml_operator("Floor") def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1465,7 +1465,7 @@ def custom_floor( -@ggml_operator("Gather") +@register_ggml_operator("Gather") def ggml_operator_gather(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1525,7 +1525,7 @@ def custom_gather( ctx.set_tensor_shape(new_tensor, ()) -@ggml_operator("Gemm") +@register_ggml_operator("Gemm") def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1639,7 +1639,7 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): -@ggml_operator("Greater") +@register_ggml_operator("Greater") def ggml_operator_greater(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1699,7 +1699,7 @@ class HardSigmoidUserData(ctypes.Structure): -@ggml_operator("HardSigmoid") +@register_ggml_operator("HardSigmoid") def ggml_operator_hardsigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1748,7 +1748,7 @@ def custom_hard_sigmoid( -@ggml_operator("Hardmax") +@register_ggml_operator("Hardmax") def ggml_operator_hardmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1791,7 +1791,7 @@ def custom_hardmax( ctx.refs.append(axis_c) -@ggml_operator("Identity") +@register_ggml_operator("Identity") def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1811,7 +1811,7 @@ def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): -@ggml_operator("InstanceNormalization") +@register_ggml_operator("InstanceNormalization") def ggml_operator_instancenorm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1868,7 +1868,7 @@ class LRNUserData(ctypes.Structure): -@ggml_operator("LRN") +@register_ggml_operator("LRN") def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1939,7 +1939,7 @@ def custom_leaky_lrn( -@ggml_operator("LeakyRelu") +@register_ggml_operator("LeakyRelu") def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1981,7 +1981,7 @@ def custom_leaky_relu( -@ggml_operator("GreaterOrEqual") +@register_ggml_operator("GreaterOrEqual") def ggml_operator_greater_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2034,7 +2034,7 @@ def custom_greater_equal( -@ggml_operator("Less") +@register_ggml_operator("Less") def ggml_operator_less(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2087,7 +2087,7 @@ def custom_less( -@ggml_operator("LessOrEqual") +@register_ggml_operator("LessOrEqual") def ggml_operator_less_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2138,7 +2138,7 @@ def custom_less_equal( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) -@ggml_operator("Log") +@register_ggml_operator("Log") def ggml_operator_log(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2157,7 +2157,7 @@ def ggml_operator_log(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = log_result -@ggml_operator("LogSoftmax") +@register_ggml_operator("LogSoftmax") def ggml_operator_log_soft_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2176,7 +2176,7 @@ def ggml_operator_log_soft_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto) ctx.tensors_dict[output_name] = log_result -@ggml_operator("MatMul") +@register_ggml_operator("MatMul") def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2225,7 +2225,7 @@ def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = mul_mat_result -@ggml_operator("Max") +@register_ggml_operator("Max") def ggml_operator_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2275,7 +2275,7 @@ def custom_max( ctx.refs.append(custom_max) -@ggml_operator("Mean") +@register_ggml_operator("Mean") def ggml_operator_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2302,7 +2302,7 @@ def ggml_operator_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = mean -@ggml_operator("Min") +@register_ggml_operator("Min") def ggml_operator_min(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2352,7 +2352,7 @@ def custom_min( ctx.refs.append(custom_min) -@ggml_operator("Mul") +@register_ggml_operator("Mul") def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2376,7 +2376,7 @@ def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = mul_result -@ggml_operator("Neg") +@register_ggml_operator("Neg") def ggml_operator_neg(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2395,7 +2395,7 @@ def ggml_operator_neg(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = x_neg -@ggml_operator("Not") +@register_ggml_operator("Not") def ggml_operator_not(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2431,7 +2431,7 @@ def custom_not( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) -@ggml_operator("Or") +@register_ggml_operator("Or") def ggml_operator_or(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2482,7 +2482,7 @@ def custom_or( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) -@ggml_operator("Pad") +@register_ggml_operator("Pad") def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): # x, pads, value, axes if len(ctx.tensors_dict) < 2: @@ -2566,7 +2566,7 @@ def custom_pad( ctx.refs.append(custom_pad) -@ggml_operator("PRelu") +@register_ggml_operator("PRelu") def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2605,7 +2605,7 @@ def custom_leaky_prelu( -@ggml_operator("Pow") +@register_ggml_operator("Pow") def ggml_operator_pow(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2646,7 +2646,7 @@ def custom_pow( -@ggml_operator("Reciprocal") +@register_ggml_operator("Reciprocal") def ggml_operator_reciprocal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2682,7 +2682,7 @@ def custom_reciprocal( -@ggml_operator("Range") +@register_ggml_operator("Range") def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2750,7 +2750,7 @@ def __init__(self, axes, keepdims): -@ggml_operator("ReduceL1") +@register_ggml_operator("ReduceL1") def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2840,7 +2840,7 @@ def custom_reduce_l1( -@ggml_operator("ReduceL2") +@register_ggml_operator("ReduceL2") def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2928,7 +2928,7 @@ def custom_reduce_l2( -@ggml_operator("ReduceLogSum") +@register_ggml_operator("ReduceLogSum") def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3015,7 +3015,7 @@ def custom_reduce_log_sum( -@ggml_operator("ReduceLogSumExp") +@register_ggml_operator("ReduceLogSumExp") def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): raise NotImplementedError( f'Error for node "{node.name}": Operation "ReduceLogSumExp" is not implemented.' @@ -3104,7 +3104,7 @@ def custom_reduce_log_sum_exp( ctx.refs.append(rmean_userdata) -@ggml_operator("ReduceMax") +@register_ggml_operator("ReduceMax") def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3192,7 +3192,7 @@ def custom_reduce_max( -@ggml_operator("ReduceMean") +@register_ggml_operator("ReduceMean") def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3279,7 +3279,7 @@ def custom_reduce_mean( -@ggml_operator("ReduceMin") +@register_ggml_operator("ReduceMin") def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3365,7 +3365,7 @@ def custom_reduce_min( ctx.refs.append(rmean_userdata) -@ggml_operator("ReduceProd") +@register_ggml_operator("ReduceProd") def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3451,7 +3451,7 @@ def custom_reduce_prod( ctx.refs.append(rmean_userdata) -@ggml_operator("ReduceSum") +@register_ggml_operator("ReduceSum") def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3536,7 +3536,7 @@ def custom_reduce_sum( ctx.refs.append(rmean_userdata) -@ggml_operator("ReduceSumSquare") +@register_ggml_operator("ReduceSumSquare") def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3622,7 +3622,7 @@ def custom_reduce_sum_square( ctx.refs.append(rmean_userdata) -@ggml_operator("Relu") +@register_ggml_operator("Relu") def ggml_operator_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3641,7 +3641,7 @@ def ggml_operator_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = relu_result -@ggml_operator("Reshape") +@register_ggml_operator("Reshape") def ggml_operator_reshape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: @@ -3706,7 +3706,7 @@ class SeluUserData(ctypes.Structure): -@ggml_operator("Selu") +@register_ggml_operator("Selu") def ggml_operator_selu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3764,7 +3764,7 @@ def custom_selu( ctx.refs.append(selu_userdata) -@ggml_operator("Shape") +@register_ggml_operator("Shape") def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3788,7 +3788,7 @@ def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.set_tensor_dtype(name, np.dtype(np.int64)) -@ggml_operator("Sigmoid") +@register_ggml_operator("Sigmoid") def ggml_operator_sigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3824,7 +3824,7 @@ def custom_sigmoid( ctx.refs.append(custom_sigmoid) -@ggml_operator("Size") +@register_ggml_operator("Size") def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3872,7 +3872,7 @@ def custom_size( ctx.set_tensor_dtype(name, np.dtype(np.int64)) -@ggml_operator("Slice") +@register_ggml_operator("Slice") def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] a_shape = ctx.get_tensor_shape(node_inputs[0]) @@ -3930,7 +3930,7 @@ def custom_slice( ctx.refs.append(custom_slice) -@ggml_operator("Softmax") +@register_ggml_operator("Softmax") def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3949,7 +3949,7 @@ def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = soft_max_result -@ggml_operator("Softplus") +@register_ggml_operator("Softplus") def ggml_operator_softplus(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3983,7 +3983,7 @@ def custom_softplus( ctx.refs.append(custom_softplus) -@ggml_operator("Softsign") +@register_ggml_operator("Softsign") def ggml_operator_softsign(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4005,7 +4005,7 @@ def ggml_operator_softsign(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[node.output[0]] = y -@ggml_operator("SpaceToDepth") +@register_ggml_operator("SpaceToDepth") def ggml_operator_space_to_depth(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4080,7 +4080,7 @@ class SplitUserData(ctypes.Structure): ] -@ggml_operator("Split") +@register_ggml_operator("Split") def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4182,7 +4182,7 @@ def custom_split( outputs.append(new_tensor) -@ggml_operator("Sqrt") +@register_ggml_operator("Sqrt") def ggml_operator_sqrt(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4201,7 +4201,7 @@ def ggml_operator_sqrt(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = sqrt_result -@ggml_operator("Squeeze") +@register_ggml_operator("Squeeze") def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4253,7 +4253,7 @@ def custom_squeeze( ctx.refs.append(custom_squeeze) -@ggml_operator("Sub") +@register_ggml_operator("Sub") def ggml_operator_sub(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4274,7 +4274,7 @@ def ggml_operator_sub(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = sub_result -@ggml_operator("Sum") +@register_ggml_operator("Sum") def ggml_operator_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4301,7 +4301,7 @@ def ggml_operator_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = next_item -@ggml_operator("Tanh") +@register_ggml_operator("Tanh") def ggml_operator_tanh(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4319,7 +4319,7 @@ def ggml_operator_tanh(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[node.output[0]] = tanh_result -@ggml_operator("Tile") +@register_ggml_operator("Tile") def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4380,7 +4380,7 @@ class TopKUserData(ctypes.Structure): ] -@ggml_operator("TopK") +@register_ggml_operator("TopK") def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4501,7 +4501,7 @@ def custom_top_k_values( ctx.set_tensor_dtype(node.output[1], np.dtype(np.int64)) -@ggml_operator("Transpose") +@register_ggml_operator("Transpose") def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4547,7 +4547,7 @@ def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = transpose_result -@ggml_operator("Unsqueeze") +@register_ggml_operator("Unsqueeze") def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4621,7 +4621,7 @@ def custom_unsqueeze( ctx.refs.append(custom_unsqueeze) -@ggml_operator("Where") +@register_ggml_operator("Where") def ggml_operator_where(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4658,7 +4658,7 @@ def custom_where( ctx.refs.append(custom_where) -@ggml_operator("Xor") +@register_ggml_operator("Xor") def ggml_operator_xor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] From 879bb2ea2a8f26a2880b31acd568c0f57ad3061b Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 25 Sep 2023 16:28:12 -0400 Subject: [PATCH 180/232] Replace set_tensor_out with np.copyto --- ggml/contrib/onnx.py | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 97fe1cc8..757f59d5 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -48,15 +48,6 @@ def get_tensor_shape(tensor: ggml.ggml_tensor_p) -> Tuple[int, ...]: return tuple(reversed(ggml.utils.get_shape(tensor))) -def set_tensor_out(tensor: ggml.ggml_tensor_p, ndarray: npt.NDArray[Any]): - output_shape = get_tensor_shape(tensor) - - if output_shape == (): - ggml.utils.to_numpy(tensor)[()] = ndarray - else: - ggml.utils.to_numpy(tensor)[:] = ndarray - - def get_tensor_dtype(tensor: ggml.ggml_tensor_p) -> npt.DTypeLike: ggml_type = ggml.utils.GGML_TYPE(tensor.contents.type) if ggml_type == ggml.utils.GGML_TYPE.F16: @@ -4791,15 +4782,7 @@ def eval_tensor( return tensor def set_tensor_out(self, tensor: ggml.ggml_tensor_p, array: npt.NDArray[Any]): - output_shape = self.get_tensor_shape(tensor) - - if array.size == 0: - return - - if output_shape == (): - self.to_numpy(tensor)[()] = array - else: - self.to_numpy(tensor)[:] = array + np.copyto(self.to_numpy(tensor), array, casting="unsafe") class GgmlBackendRep(BackendRep): @@ -4916,7 +4899,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ctypes.addressof(input_buffer) + input_buffer_offset, ctypes.c_void_p ) input_buffer_offset += ggml.ggml_nbytes_pad(tensor) - set_tensor_out(tensor, np.array(value)) + np.copyto(ggml.utils.to_numpy(tensor), np.array(value)) # Define context max_overhead = 2 * ggml.GGML_MAX_NODES * ggml.ggml_tensor_overhead() @@ -5022,7 +5005,7 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): ctypes.addressof(buffer) + offset, ctypes.c_void_p ) np_array = onnx.numpy_helper.to_array(initializer) - set_tensor_out(tensor, np_array) + np.copyto(ggml.utils.to_numpy(tensor), np_array) offset += nbytes From f92ebfb6f284440c40196bdb5c6eaf546854c52c Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 26 Sep 2023 18:23:29 -0400 Subject: [PATCH 181/232] Fix transpose identity test --- ggml/contrib/onnx.py | 4 ++-- tests/test_ggml_onnx.py | 47 ++++++++++++++++++++++++++++++++--------- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 757f59d5..14f7ba7b 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5048,8 +5048,8 @@ def run_node( class GgmlOnnxGraphOptimizerRule: """Base class for a graph optimization rule.""" - def __init__(self, name: str): - self.name = name + def __init__(self): + pass def apply(self, model: ModelProto) -> Optional[ModelProto]: """Apply the optimization rule to the given ONNX model.""" diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 8cf84adb..c3dda0f3 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -159,15 +159,15 @@ def test_ggml_onnx_graph_optimization(): model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") - from typing import Optional + from typing import Optional, List from ggml.contrib.onnx import GgmlOnnxGraphOptimizer, GgmlOnnxGraphOptimizerRule - from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto + from onnx.onnx_ml_pb2 import ModelProto, NodeProto class TransposeTransposeRule(GgmlOnnxGraphOptimizerRule): def __init__(self): super().__init__() - def apply(self, model: onnx.ModelProto) -> Optional[ModelProto]: + def apply(self, model: ModelProto) -> Optional[ModelProto]: # find first transpose node transpose_node: Optional[NodeProto] = None for node in model.graph.node: @@ -189,14 +189,31 @@ def apply(self, model: onnx.ModelProto) -> Optional[ModelProto]: else: return None - # remove the transpose nodes - model.graph.node.remove(transpose_node) - model.graph.node.remove(transpose_transpose_node) - - # update the connections - transpose_transpose_node.output[0] = transpose_node.input[0] + # Create a new node list without the two transpose nodes + new_nodes: List[NodeProto] = [] + for node in model.graph.node: + if node not in [transpose_node, transpose_transpose_node]: + new_node = NodeProto() + new_node.CopyFrom(node) + new_node.input[:] = [transpose_node.input[0] if inp == transpose_transpose_node.output[0] else inp for inp in node.input] + new_nodes.append(new_node) + + # Create the new graph + new_graph = helper.make_graph( + new_nodes, + model.graph.name, + model.graph.input, + model.graph.output, + model.graph.initializer, + ) + + # create a new model + new_model = helper.make_model( + new_graph, producer_name=model.producer_name + ) + + return new_model - return model input_data = {"x": np.random.randn(1, 32).astype(np.float32)} @@ -209,6 +226,16 @@ def apply(self, model: onnx.ModelProto) -> Optional[ModelProto]: ggml_result = ggml_dummy_model.run(input_data) assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) + optimizer = GgmlOnnxGraphOptimizer( + model=model_def, rules=[TransposeTransposeRule()] + ) + new_model = optimizer.optimize() + assert new_model is not None + ggml_dummy_model_new = GgmlRuntimeBackend.prepare(new_model) + assert ggml_dummy_model_new is not None + ggml_result_new = ggml_dummy_model_new.run(input_data) + assert np.allclose(ggml_result_new[0], runtime_result[0], rtol=1e-03, atol=1e-05) + def test_ggml_onnx_runtime_quantized(): # Construct an onnx graph of the form y = Ax + b From 05e3090224a2ae55df618818a20caba5bbc25c3e Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 26 Sep 2023 18:49:50 -0400 Subject: [PATCH 182/232] Ensure new graph has zero Transpose nodes --- tests/test_ggml_onnx.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index c3dda0f3..e4acbc13 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -163,7 +163,7 @@ def test_ggml_onnx_graph_optimization(): from ggml.contrib.onnx import GgmlOnnxGraphOptimizer, GgmlOnnxGraphOptimizerRule from onnx.onnx_ml_pb2 import ModelProto, NodeProto - class TransposeTransposeRule(GgmlOnnxGraphOptimizerRule): + class TransposeIdentityRule(GgmlOnnxGraphOptimizerRule): def __init__(self): super().__init__() @@ -227,7 +227,7 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) optimizer = GgmlOnnxGraphOptimizer( - model=model_def, rules=[TransposeTransposeRule()] + model=model_def, rules=[TransposeIdentityRule()] ) new_model = optimizer.optimize() assert new_model is not None @@ -235,6 +235,7 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: assert ggml_dummy_model_new is not None ggml_result_new = ggml_dummy_model_new.run(input_data) assert np.allclose(ggml_result_new[0], runtime_result[0], rtol=1e-03, atol=1e-05) + assert sum([node.op_type == "Transpose" for node in new_model.graph.node]) == 0 def test_ggml_onnx_runtime_quantized(): From 001e88afd5f5a4ea6f4472af870ddaef3aa49a04 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 26 Sep 2023 19:57:01 -0400 Subject: [PATCH 183/232] Add doctstring to transpose identity rule --- tests/test_ggml_onnx.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index e4acbc13..46288cdf 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -164,6 +164,12 @@ def test_ggml_onnx_graph_optimization(): from onnx.onnx_ml_pb2 import ModelProto, NodeProto class TransposeIdentityRule(GgmlOnnxGraphOptimizerRule): + """Transpose Identity Rewrite Rule + + This rules removes two consecutive transpose nodes that transpose the same tensor. + + ie Transpose(Transpose(x)) -> x""" + def __init__(self): super().__init__() From 6a943a76146adf75f61c271a1d0bc54380c1e419 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 26 Sep 2023 21:09:56 -0400 Subject: [PATCH 184/232] Rename OnnxGraphRule and OnnxGraphRuleEngine --- ggml/contrib/onnx.py | 19 +++++++++---------- tests/test_ggml_onnx.py | 10 +++++----- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 14f7ba7b..c26efe58 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5045,8 +5045,8 @@ def run_node( ) -class GgmlOnnxGraphOptimizerRule: - """Base class for a graph optimization rule.""" +class OnnxGraphRule: + """Base class for a graph rule which is applied to an onnx model.""" def __init__(self): pass @@ -5056,20 +5056,19 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: raise NotImplementedError() -class GgmlOnnxGraphOptimizer: - """Optimize an ONNX graph for the GGML runtime.""" +class OnnxGraphRuleEngine: + """Applies a series of OnnxGraphRule's to an ONNX model until + no more rules can be applied.""" - def __init__(self, model: ModelProto, rules: List[GgmlOnnxGraphOptimizerRule]): - self.model = model + def __init__(self, rules: List[OnnxGraphRule]): self.rules = rules - def optimize(self) -> ModelProto: - """Apply the optimization rules to the ONNX model until there are no - more optimizations left to perform. + def optimize(self, model: ModelProto) -> ModelProto: + """Apply the rules to the ONNX model until there no more rules + can be applied. NOTE: This is a naive implementation that applies the rules in order until no more rules can be applied.""" - model = self.model while True: for rule in self.rules: new_model = rule.apply(model) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 46288cdf..effe203e 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -160,10 +160,10 @@ def test_ggml_onnx_graph_optimization(): model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") from typing import Optional, List - from ggml.contrib.onnx import GgmlOnnxGraphOptimizer, GgmlOnnxGraphOptimizerRule + from ggml.contrib.onnx import OnnxGraphRuleEngine, OnnxGraphRule from onnx.onnx_ml_pb2 import ModelProto, NodeProto - class TransposeIdentityRule(GgmlOnnxGraphOptimizerRule): + class TransposeIdentityRule(OnnxGraphRule): """Transpose Identity Rewrite Rule This rules removes two consecutive transpose nodes that transpose the same tensor. @@ -232,10 +232,10 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: ggml_result = ggml_dummy_model.run(input_data) assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) - optimizer = GgmlOnnxGraphOptimizer( - model=model_def, rules=[TransposeIdentityRule()] + optimizer = OnnxGraphRuleEngine( + rules=[TransposeIdentityRule()] ) - new_model = optimizer.optimize() + new_model = optimizer.optimize(model=model_def) assert new_model is not None ggml_dummy_model_new = GgmlRuntimeBackend.prepare(new_model) assert ggml_dummy_model_new is not None From f9705b237858d2761c36b2880a1423618991379d Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 27 Sep 2023 02:41:01 -0400 Subject: [PATCH 185/232] Update quantization test --- tests/test_ggml_onnx.py | 186 +++++++++++++++++++++++++--------------- 1 file changed, 116 insertions(+), 70 deletions(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index effe203e..e7f378b3 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -245,85 +245,131 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: def test_ggml_onnx_runtime_quantized(): - # Construct an onnx graph of the form y = Ax + b - # where A and b are weights, x is the input, and y is the output - # A is a 32x32 matrix of normally distributed random numbers - # b is a vector of 32 normally distributed random numbers - # x is a vector of 32 normally distributed random numbers - # y is the output - - # The name of the input tensor - input_name = "x" - - # The name of the weights tensor - weight_name_a = "A" - weight_name_b = "b" - - # The name of the output - output_name = "y" - - # Create the nodes (operations) in our graph - node1 = helper.make_node( - "MatMul", [input_name, weight_name_a], ["x_times_A"], name="node1" - ) # x * A - node2 = helper.make_node( - "Add", ["x_times_A", weight_name_b], [output_name], name="node2" - ) # x * A + b - - # Define the tensors (values) in our graph - X_value_info = helper.make_tensor_value_info( - input_name, TensorProto.FLOAT, [None, 32] - ) - - output_value_info = helper.make_tensor_value_info( - output_name, TensorProto.FLOAT, [None, 32] - ) - - # Set A and b as parameters/weights - weights_a = np.random.randn(32, 32).astype(np.float32) + # Construct an onnx graph of the form Y = X * A + B + # and compute the result of the graph with quantized weights + # A and B and compare the result with the result of the + # unquantized graph + + # Sizes: X = (32, 32), A = (32, 32), B = (32, 32) + + # The expressions Y = X * A + B cannot be computed directly with quantized + # weights, because ggml expects the quantized weights to appear as the first + # input of the MatMul and Add nodes. Therefore, we rewrite the expression + # using the following identities: + # (AB)^T = B^T A^T + # A = (A^T)^T + # A + B = B + A + # The final expression is Y = B + (A^T X^T)^T + + from typing import Optional, List, Set + from ggml.contrib.onnx import OnnxGraphRuleEngine, OnnxGraphRule + from onnx.onnx_ml_pb2 import ModelProto, NodeProto - weights_b = np.random.randn(32).astype(np.float32) + def __ancestors_of(node: NodeProto, model: ModelProto) -> List[NodeProto]: + nodes = { node.name: node for node in model.graph.node } + visited: Set[str] = set() + queue = [node.name] + while len(queue) > 0: + curr = queue.pop(0) + if curr in visited: + continue + visited.add(curr) + queue.extend([inp for inp in nodes[curr].input if inp not in visited]) + return [nodes[v] for v in visited] + + def __is_weight_or_constant(node: NodeProto, model: ModelProto) -> bool: + inputs = { node.name for node in model.graph.input } + if node.name in inputs: + return True + ancestors = __ancestors_of(node, model) + return any([ancestor.name in inputs for ancestor in ancestors]) + + class MatMulTransposeRule(OnnxGraphRule): + def __init__(self): + super().__init__() - A_init = helper.make_tensor( - weight_name_a, - TensorProto.FLOAT, - [ - 32, - 32, - ], - weights_a, - ) - B_init = helper.make_tensor( - weight_name_b, - TensorProto.FLOAT, - [ - 32, - ], - weights_b, - ) + def apply(self, model: ModelProto) -> Optional[ModelProto]: + # find a matmul node + matmul_node: Optional[NodeProto] = None + for node in model.graph.node: + if node.op_type == "MatMul": + matmul_node = node + break + else: + return None + + # get first and second input of matmul node + matmul_input_0 = matmul_node.input[0] + matmul_input_1 = matmul_node.input[1] - # Create the graph (model). - graph_def = helper.make_graph( - [node1, node2], - "simple_expression_model", - [X_value_info], - [output_value_info], - [A_init, B_init], - ) + nodes = { node.name: node for node in model.graph.node } - model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") + # check that first input is _not_ a weight or constant tensor + if __is_weight_or_constant(nodes[matmul_input_0], model): + return None + + # check that second input is a weight or constant tensor + if not __is_weight_or_constant(nodes[matmul_input_1], model): + return None - input_data = {"x": np.random.randn(1, 32).astype(np.float32)} + # replace Matmul(matmul_input_0, matmul_input_1) with Transpose(MatMul(Transpose(matmul_input_1), Transpose(matmul_input_0))) - f = io.BytesIO() - onnx.save(model_def, f) + # create new transpose nodes for the inputs + transpose_node_0 = NodeProto() + transpose_node_0.CopyFrom(matmul_node) + transpose_node_0.op_type = "Transpose" + transpose_node_0.name = matmul_input_0 + "_transposed" + transpose_node_0.input[:] = [matmul_input_0] + transpose_node_0.output[:] = [matmul_input_0 + "_transposed"] + + transpose_node_1 = NodeProto() + transpose_node_1.CopyFrom(matmul_node) + transpose_node_1.op_type = "Transpose" + transpose_node_1.name = matmul_input_1 + "_transposed" + transpose_node_1.input[:] = [matmul_input_1] + transpose_node_1.output[:] = [matmul_input_1 + "_transposed"] + + # create new matmul node + new_matmul_node = NodeProto() + new_matmul_node.CopyFrom(matmul_node) + new_matmul_node.op_type = "MatMul" + new_matmul_node.name = matmul_node.name + "_inner" + new_matmul_node.input[:] = [transpose_node_1.output[0], transpose_node_0.output[0]] + new_matmul_node.output[:] = [matmul_node.output[0]] + + # create final transpose node + final_transpose_node = NodeProto() + final_transpose_node.CopyFrom(matmul_node) + final_transpose_node.op_type = "Transpose" + final_transpose_node.name = matmul_node.name # this is the name of the original matmul node + final_transpose_node.input[:] = [new_matmul_node.output[0]] + final_transpose_node.output[:] = [matmul_node.output[0]] + + # Create the new node list + new_nodes: List[NodeProto] = [] + for node in model.graph.node: + if node not in [matmul_node]: + new_node = NodeProto() + new_node.CopyFrom(node) + new_nodes.append(new_node) + else: + new_nodes.extend([transpose_node_0, transpose_node_1, new_matmul_node, final_transpose_node]) - runtime_result = InferenceSession(f.getvalue()).run(None, input_data) + # Create the new graph + new_graph = helper.make_graph( + new_nodes, + model.graph.name, + model.graph.input, + model.graph.output, + model.graph.initializer, + ) - ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) - ggml_result = ggml_dummy_model.run(input_data) + # create a new model + new_model = helper.make_model( + new_graph, producer_name=model.producer_name + ) - assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) + return new_model backend_test = onnx.backend.test.BackendTest(GgmlRuntimeBackend, __name__) From 77516bbe144109efd4723445cf17389d02dca8d5 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 27 Sep 2023 22:24:59 -0700 Subject: [PATCH 186/232] Fix concat return --- ggml/contrib/onnx.py | 185 ++++++++++++++++--------------------------- 1 file changed, 67 insertions(+), 118 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index c26efe58..5137e9b9 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -12,7 +12,13 @@ import onnx from onnx.backend.base import Backend, BackendRep from onnx.helper import np_dtype_to_tensor_dtype, tensor_dtype_to_np_dtype -from onnx.onnx_ml_pb2 import GraphProto, ModelProto, NodeProto, ValueInfoProto, TensorProto +from onnx.onnx_ml_pb2 import ( + GraphProto, + ModelProto, + NodeProto, + ValueInfoProto, + TensorProto, +) import ggml import ggml.utils @@ -22,7 +28,7 @@ ggml_operators: Dict[str, GgmlOperator] = {} onnx_dtype_map: Dict[int, npt.DTypeLike] = { elem_type: np_dtype - for elem_type, np_dtype in onnx.mapping.TENSOR_TYPE_TO_NP_TYPE.items() # type: ignore + for elem_type, np_dtype in onnx.mapping.TENSOR_TYPE_TO_NP_TYPE.items() # type: ignore } @@ -174,8 +180,6 @@ def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = add_result - - @register_ggml_operator("And") def ggml_operator_and(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -234,8 +238,6 @@ class ArgOpsUserData(ctypes.Structure): ] - - @register_ggml_operator("ArgMax") def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -324,8 +326,6 @@ def custom_arg_max( ctx.refs.append(argmax_userdata) - - @register_ggml_operator("ArgMin") def ggml_operator_arg_min(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -412,8 +412,6 @@ def custom_arg_min( ctx.refs.append(argmax_userdata) - - @register_ggml_operator("Cast") def ggml_operator_cast(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -498,7 +496,6 @@ def custom_cast( ctx.set_tensor_out(tensor_out, tensor.astype(np_data_type_limit)) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, @@ -569,6 +566,7 @@ def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): raise ValueError( "All tensors must have the same shape along the specified axis." ) + @ggml.ggml_custom3_op_t def custom_concat( tensor_out: ggml.ggml_tensor_p, @@ -593,7 +591,6 @@ def concat_2(tensor_a, tensor_b): x = np.empty(output_shape, dtype=get_tensor_dtype(tensor_a)) x_t = ctx.from_numpy(x) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, @@ -606,14 +603,13 @@ def concat_2(tensor_a, tensor_b): ) ctx.refs.append(custom_concat) + return new_tensor new_tensor = node_inputs[0] for tensor in node_inputs[1:]: new_tensor = concat_2(new_tensor, tensor) - - @register_ggml_operator("Constant") def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_attributes = node.attribute @@ -687,8 +683,6 @@ def custom_constant( ctx.set_tensor_dtype(name, np_data_type) - - @register_ggml_operator("ConstantOfShape") def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -776,9 +770,7 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): m = w_shape[0] bias = next( node_inputs_iter, - ctx.from_numpy( - np.full(m, 0, dtype=get_tensor_dtype(x)) - ), + ctx.from_numpy(np.full(m, 0, dtype=get_tensor_dtype(x))), ) auto_pad = next( @@ -858,9 +850,7 @@ def ggml_operator_convtranspose(ctx: "GgmlOnnxExecutionContext", node: NodeProto m = w_shape[0] bias = next( node_inputs_iter, - ctx.from_numpy( - np.full(m, 0, dtype=get_tensor_dtype(x)) - ), + ctx.from_numpy(np.full(m, 0, dtype=get_tensor_dtype(x))), ) auto_pad = next( @@ -955,8 +945,6 @@ class DepthToSpaceUserData(ctypes.Structure): ] - - @register_ggml_operator("DepthToSpace") def ggml_operator_depth_to_space(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -986,9 +974,7 @@ def ggml_operator_depth_to_space(ctx: "GgmlOnnxExecutionContext", node: NodeProt output_shape = (N, new_C, new_H, new_W) - x_t = ctx.from_numpy( - np.empty(output_shape, dtype=get_tensor_dtype(x)) - ) + x_t = ctx.from_numpy(np.empty(output_shape, dtype=get_tensor_dtype(x))) depthtospace_userdata = DepthToSpaceUserData(blocksize, mode) userdata_p = ctypes.cast(ctypes.pointer(depthtospace_userdata), ctypes.c_void_p) @@ -1074,10 +1060,6 @@ class DropoutUserData(ctypes.Structure): ] - - - - @register_ggml_operator("Dropout") def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1099,14 +1081,14 @@ def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): training_mode = next(node_inputs_iter, np.bool_(False)) if type(ratio) is float: - ratio = ctx.from_numpy( - np.array([ratio]).astype(np.float32) - ) + ratio = ctx.from_numpy(np.array([ratio]).astype(np.float32)) seed = next((attr.i for attr in node.attribute if attr.name == "seed"), 6) if type(training_mode) is ggml.ggml_tensor_p: - training_mode_eval = ctx.eval_tensor(training_mode,) + training_mode_eval = ctx.eval_tensor( + training_mode, + ) training_mode = ctx.to_numpy(training_mode_eval) droput_userdata = DropoutUserData(seed, bool(training_mode)) @@ -1138,6 +1120,7 @@ def custom_dropout_mask( mask = np.random.uniform(0, 1.0, x.shape) >= ratio ctx.set_tensor_out(tensor_out, mask) + mask = ggml.ggml_map_custom2_inplace( ctx.ggml_context, data, @@ -1176,6 +1159,7 @@ def custom_dropout_output( y = mask * x * scale ctx.set_tensor_out(tensor_out, y) + output = ggml.ggml_map_custom3_inplace( ctx.ggml_context, data, @@ -1219,7 +1203,9 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) if alpha != 1.0: - Y_eval = ctx.eval_tensor(Y,) + Y_eval = ctx.eval_tensor( + Y, + ) Y_np = ctx.to_numpy(Y_eval) Y_alpha = np.where(Y_np < 0, alpha * Y_np, Y_np) @@ -1228,8 +1214,6 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = Y - - @register_ggml_operator("Equal") def ggml_operator_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1323,9 +1307,7 @@ def ggml_operator_expand(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] a_shape = get_tensor_shape(node_inputs[0]) - target_shape = ctx.to_numpy( - ctx.eval_tensor(node_inputs[1]) - ) + target_shape = ctx.to_numpy(ctx.eval_tensor(node_inputs[1])) new_shape = np.broadcast(np.empty(a_shape), np.empty(target_shape)).shape x = np.empty(new_shape, dtype=get_tensor_dtype(node_inputs[0])) @@ -1356,8 +1338,6 @@ def custom_expand( ctx.refs.append(custom_expand) - - @register_ggml_operator("Flatten") def ggml_operator_flatten(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1417,8 +1397,6 @@ def custom_flatten( ctx.refs.append(axis_c) - - @register_ggml_operator("Floor") def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1454,8 +1432,6 @@ def custom_floor( ctx.refs.append(custom_floor) - - @register_ggml_operator("Gather") def ggml_operator_gather(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1629,7 +1605,6 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[node.output[0]] = mul_mat_result - @register_ggml_operator("Greater") def ggml_operator_greater(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1688,8 +1663,6 @@ class HardSigmoidUserData(ctypes.Structure): ] - - @register_ggml_operator("HardSigmoid") def ggml_operator_hardsigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1737,8 +1710,6 @@ def custom_hard_sigmoid( ctx.refs.append(hsig_userdata) - - @register_ggml_operator("Hardmax") def ggml_operator_hardmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1800,8 +1771,6 @@ def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = y - - @register_ggml_operator("InstanceNormalization") def ggml_operator_instancenorm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1835,6 +1804,7 @@ def custom_instancenorm( y = scale.reshape(1, -1, 1, 1) * normalized + B.reshape(1, -1, 1, 1) ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, input_tensor, @@ -1857,8 +1827,6 @@ class LRNUserData(ctypes.Structure): ] - - @register_ggml_operator("LRN") def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1916,6 +1884,7 @@ def custom_leaky_lrn( y = x / ((bias + (alpha / size) * square_sum) ** beta) ctx.set_tensor_out(tensor_out, y) + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, x, @@ -1928,8 +1897,6 @@ def custom_leaky_lrn( ctx.refs.append(lrn_userdata) - - @register_ggml_operator("LeakyRelu") def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1970,8 +1937,6 @@ def custom_leaky_relu( ctx.refs.append(axis_c) - - @register_ggml_operator("GreaterOrEqual") def ggml_operator_greater_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2023,8 +1988,6 @@ def custom_greater_equal( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - - @register_ggml_operator("Less") def ggml_operator_less(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2076,8 +2039,6 @@ def custom_less( ctx.set_tensor_dtype(name, np.dtype(np.bool_)) - - @register_ggml_operator("LessOrEqual") def ggml_operator_less_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2496,9 +2457,7 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): for _ in range(input_rank): pad_width += [[0, 0]] # init to zero - raw_pads = ctx.to_numpy( - ctx.eval_tensor(ctx.tensors_dict["pads"]) - ) + raw_pads = ctx.to_numpy(ctx.eval_tensor(ctx.tensors_dict["pads"])) # re-order to np.pad accepted order ((x1_begin, x1_end), (x2_begin, x2_end), ...) for i in range(num_axes): @@ -2516,9 +2475,7 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): constant_value = None if "value" in ctx.tensors_dict: - constant_values = ctx.to_numpy( - ctx.eval_tensor(ctx.tensors_dict["value"]) - ) + constant_values = ctx.to_numpy(ctx.eval_tensor(ctx.tensors_dict["value"])) @ggml.ggml_custom2_op_t def custom_pad( @@ -2595,7 +2552,6 @@ def custom_leaky_prelu( ctx.refs.append(custom_leaky_prelu) - @register_ggml_operator("Pow") def ggml_operator_pow(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2636,7 +2592,6 @@ def custom_pow( ctx.refs.append(custom_pow) - @register_ggml_operator("Reciprocal") def ggml_operator_reciprocal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2672,7 +2627,6 @@ def custom_reciprocal( ctx.refs.append(custom_reciprocal) - @register_ggml_operator("Range") def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2739,8 +2693,6 @@ def __init__(self, axes, keepdims): self.keepdims = keepdims - - @register_ggml_operator("ReduceL1") def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2830,7 +2782,6 @@ def custom_reduce_l1( ctx.refs.append(rmean_userdata) - @register_ggml_operator("ReduceL2") def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -2918,7 +2869,6 @@ def custom_reduce_l2( ctx.refs.append(rmean_userdata) - @register_ggml_operator("ReduceLogSum") def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3005,7 +2955,6 @@ def custom_reduce_log_sum( ctx.refs.append(rmean_userdata) - @register_ggml_operator("ReduceLogSumExp") def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): raise NotImplementedError( @@ -3181,8 +3130,6 @@ def custom_reduce_max( ctx.refs.append(rmean_userdata) - - @register_ggml_operator("ReduceMean") def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3269,7 +3216,6 @@ def custom_reduce_mean( ctx.refs.append(rmean_userdata) - @register_ggml_operator("ReduceMin") def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3650,7 +3596,9 @@ def ggml_operator_reshape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] b = node_inputs[1] - eval_b = ctx.eval_tensor(b,) + eval_b = ctx.eval_tensor( + b, + ) new_shape = ggml.utils.to_numpy(eval_b).astype(dtype=np.int32) @@ -3695,8 +3643,6 @@ class SeluUserData(ctypes.Structure): ] - - @register_ggml_operator("Selu") def ggml_operator_selu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -3772,9 +3718,7 @@ def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) shape_slice = tensor_shape[start:end] - new_tensor = ctx.tensors_dict[name] = ctx.from_numpy( - shape_slice - ) + new_tensor = ctx.tensors_dict[name] = ctx.from_numpy(shape_slice) ctx.set_tensor_dtype(name, np.dtype(np.int64)) @@ -3836,7 +3780,6 @@ def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = np.empty(tensor_shape, dtype=tensor_size_np.dtype) x_t = ctx.from_numpy(x) - @ggml.ggml_custom2_op_t def custom_size( tensor_out: ggml.ggml_tensor_p, @@ -3888,7 +3831,6 @@ def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): starts = [a + size if a < 0 else a for a, size in zip(starts, axes_sizes)] ends = [a + size if a < 0 else a for a, size in zip(ends, axes_sizes)] - slices = [slice(start, end, step) for start, end, step in zip(starts, ends, steps)] all_slices = [] @@ -4020,9 +3962,7 @@ def ggml_operator_space_to_depth(ctx: "GgmlOnnxExecutionContext", node: NodeProt new_W = W // blocksize output_shape = (N, C * blocksize * blocksize, new_H, new_W) - x_t = ctx.from_numpy( - np.empty(output_shape, dtype=get_tensor_dtype(x)) - ) + x_t = ctx.from_numpy(np.empty(output_shape, dtype=get_tensor_dtype(x))) blocksize_c = ctypes.c_int(blocksize) @@ -4105,7 +4045,9 @@ def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): split_shapes = [tuple(split_shape) for split_shape in split_shapes] else: - split_eval = ctx.eval_tensor(split_tensor,) + split_eval = ctx.eval_tensor( + split_tensor, + ) split_values = ggml.utils.to_numpy(split_eval) split_shapes = [list(input_shape) for _ in range(num_outputs)] @@ -4123,9 +4065,7 @@ def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): split_userdata = SplitUserData(axis, split_index) userdata_p = ctypes.cast(ctypes.pointer(split_userdata), ctypes.c_void_p) - x_t = ctx.from_numpy( - np.empty(split_shape, dtype=dtype) - ) + x_t = ctx.from_numpy(np.empty(split_shape, dtype=dtype)) @ggml.ggml_custom3_op_t def custom_split( @@ -4205,7 +4145,9 @@ def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_shape = get_tensor_shape(data) x_dtype = get_tensor_dtype(data) - axes_eval = ctx.eval_tensor(axes_input,) + axes_eval = ctx.eval_tensor( + axes_input, + ) axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) dummy_data = np.empty(x_shape, dtype=x_dtype) dummy_data = np.squeeze(dummy_data, axis=axes[0]) @@ -4321,7 +4263,9 @@ def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x, repeats = node_inputs - repeats_eval = ctx.eval_tensor(repeats,) + repeats_eval = ctx.eval_tensor( + repeats, + ) repeats_vals = ggml.utils.to_numpy(repeats_eval).astype(dtype=np.int32) output_shape = list(get_tensor_shape(x)) @@ -4388,7 +4332,9 @@ def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): largest = next((attr.i for attr in node.attribute if attr.name == "largest"), 1) sorted_flag = next((attr.i for attr in node.attribute if attr.name == "sorted"), 0) - k_eval = ctx.eval_tensor(k,) + k_eval = ctx.eval_tensor( + k, + ) k_np = ggml.utils.to_numpy(k_eval)[0] topk_userdata = TopKUserData(axis, largest, sorted_flag, k_np) @@ -4554,7 +4500,9 @@ def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_dtype = get_tensor_dtype(data) x_ndims = ggml.utils.get_ndims(data) - axes_eval = ctx.eval_tensor(axes_input,) + axes_eval = ctx.eval_tensor( + axes_input, + ) axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) axes_values = [ax if ax >= 0 else ax + x_ndims + 1 for ax in axes] @@ -4760,9 +4708,7 @@ def compute_graph(self, gf: ggml.ggml_cgraph): gp.work = ctypes.cast(work_buffer, ctypes.c_void_p) ggml.ggml_graph_compute(ctypes.byref(gf), ctypes.byref(gp)) - def eval_tensor( - self, tensor: ggml.ggml_tensor_p - ): + def eval_tensor(self, tensor: ggml.ggml_tensor_p): self.alloc_tensor_cpu(tensor) gf = ggml.ggml_build_forward(tensor) # NOTE: Should probably save / restore data pointers here for intermediate tensors @@ -4771,7 +4717,9 @@ def eval_tensor( alloc_buffer = (ctypes.c_uint8 * alloc_size)() leaf_data = [ggml.ggml_get_data(gf.leafs[i]) for i in range(gf.n_leafs)] node_data = [ggml.ggml_get_data(gf.nodes[i]) for i in range(gf.n_nodes)] - allocr = ggml.ggml_allocr_new(ctypes.cast(alloc_buffer, ctypes.c_void_p), alloc_size, alignment) + allocr = ggml.ggml_allocr_new( + ctypes.cast(alloc_buffer, ctypes.c_void_p), alloc_size, alignment + ) ggml.ggml_allocr_alloc_graph(allocr, ctypes.byref(gf)) self.compute_graph(gf) ggml.ggml_allocr_free(allocr) @@ -4808,18 +4756,18 @@ def __init__( def __del__(self): if hasattr(self, "ggml_context"): ggml.ggml_free(self.ggml_context) - + @staticmethod def _is_list_of_arraylike(x: Any) -> TypeGuard[List[npt.ArrayLike]]: - return isinstance(x, list) and all( - isinstance(y, (np.ndarray, list)) for y in x - ) + return isinstance(x, list) and all(isinstance(y, (np.ndarray, list)) for y in x) @staticmethod - def _is_dict_of_arraylike(x: Any) -> TypeGuard[Dict[str,npt.ArrayLike]]: - return isinstance(x, dict) and all( - isinstance(y, (np.ndarray, list)) for y in x.values() - ) and all(isinstance(k, str) for k in x.keys()) + def _is_dict_of_arraylike(x: Any) -> TypeGuard[Dict[str, npt.ArrayLike]]: + return ( + isinstance(x, dict) + and all(isinstance(y, (np.ndarray, list)) for y in x.values()) + and all(isinstance(k, str) for k in x.keys()) + ) def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: """Run the model with the specified inputs.""" @@ -4904,7 +4852,9 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: # Define context max_overhead = 2 * ggml.GGML_MAX_NODES * ggml.ggml_tensor_overhead() ggml_context = ggml.ggml_init( - params=ggml.ggml_init_params(mem_size=max_overhead, mem_buffer=None, no_alloc=True) + params=ggml.ggml_init_params( + mem_size=max_overhead, mem_buffer=None, no_alloc=True + ) ) refs: List[Any] = [] @@ -4931,15 +4881,14 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) ctx.eval_tensor(ggml_tensors[output]) - graph_outputs: List[npt.NDArray[Any]] = [] for output in self.outputs: exit_node = ggml_tensors[output.name] # NOTE: 0 dimension in ggml may cause bugs size = np.prod(ctx.get_tensor_shape(exit_node)) - graph_output: npt.NDArray[Any] = ggml.utils.to_numpy( - exit_node - ) if size > 0 else np.empty((0)) # TODO: Add checks to convert values back to bool or etc types + graph_output: npt.NDArray[Any] = ( + ggml.utils.to_numpy(exit_node) if size > 0 else np.empty((0)) + ) # TODO: Add checks to convert values back to bool or etc types graph_output = graph_output.astype( ctx.get_tensor_dtype(output.name) ) # TODO: add a second dict to keep track of types and use that instead @@ -4989,7 +4938,7 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): for initializer in graph.initializer: name = initializer.name - np_array: npt.NDArray[Any] = onnx.numpy_helper.to_array(initializer) # type: ignore + np_array: npt.NDArray[Any] = onnx.numpy_helper.to_array(initializer) # type: ignore tensor = ggml.utils.from_numpy(x=np_array, ctx=ggml_context) ggml.ggml_set_name(tensor=tensor, name=name.encode()) total_nbytes += ggml.ggml_nbytes_pad(tensor) From 570a4a710c5b08713217591a29a7002674c37c00 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 27 Sep 2023 22:46:38 -0700 Subject: [PATCH 187/232] Add fallbacks --- ggml/contrib/onnx.py | 67 +++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 5137e9b9..56340a85 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -93,28 +93,55 @@ def can_quantize( def broadcast_tensor( - ctx: ggml.ggml_context_p, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...] + ctx: "GgmlOnnxExecutionContext", tensor: ggml.ggml_tensor_p, shape: Tuple ): ggml_type = ggml.utils.GGML_TYPE(tensor.contents.type) - new_tensor = ggml.ggml_new_tensor( - ctx, - ggml_type.value, - len(shape), - (ctypes.c_int64 * len(shape))(*shape), - ) + if ggml_type == ggml.utils.GGML_TYPE.F32: + new_tensor = ggml.ggml_new_tensor( + ctx.ggml_context, + ggml_type.value, + len(shape), + (ctypes.c_int64 * len(shape))(*shape), + ) - new_tensor = ggml.ggml_repeat( - ctx, - tensor, - new_tensor, - ) + new_tensor = ggml.ggml_repeat( + ctx.ggml_context, + tensor, + new_tensor, + ) + else: + @ggml.ggml_custom2_op_t + def custom_broadcast_to( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ctx.to_numpy(tensor_in_2) + + x = np.broadcast_to(a, shape) + ctx.set_tensor_out(tensor_out, x) + + x = np.empty(shape, dtype=get_tensor_dtype(tensor)) + x_t = ctx.from_numpy(x) + new_tensor = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, + x_t, + tensor, + custom_broadcast_to, + 1, + None, + ) + ctx.refs.append(custom_broadcast_to) return new_tensor def broadcast_shapes( - ctx: ggml.ggml_context_p, + ctx: "GgmlOnnxExecutionContext", a: ggml.ggml_tensor_p, b: ggml.ggml_tensor_p, ): @@ -170,7 +197,7 @@ def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_name = node.output[0] a, b = node_inputs - a, b = broadcast_shapes(ctx.ggml_context, a, b) + a, b = broadcast_shapes(ctx, a, b) add_result = ggml.ggml_add( ctx.ggml_context, @@ -1042,7 +1069,7 @@ def ggml_operator_div(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] b = node_inputs[1] - a, b = broadcast_shapes(ctx.ggml_context, a, b) + a, b = broadcast_shapes(ctx, a, b) div_result = ggml.ggml_div( ctx.ggml_context, @@ -1586,7 +1613,7 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ), ) - c, mul_mat_result = broadcast_shapes(ctx.ggml_context, c, mul_mat_result) + c, mul_mat_result = broadcast_shapes(ctx, c, mul_mat_result) beta_t = ctx.from_numpy( np.full( @@ -2146,7 +2173,7 @@ def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): try: np.matmul(np.empty(a_shape), np.empty(b_shape)) except: - a, b = broadcast_shapes(ctx.ggml_context, a, b) + a, b = broadcast_shapes(ctx, a, b) b_dtype = get_tensor_dtype(b) @@ -2317,7 +2344,7 @@ def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] b = node_inputs[1] - a, b = broadcast_shapes(ctx.ggml_context, a, b) + a, b = broadcast_shapes(ctx, a, b) mul_result = ggml.ggml_mul( ctx.ggml_context, @@ -4197,7 +4224,7 @@ def ggml_operator_sub(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_name = node.output[0] a, b = node_inputs - a, b = broadcast_shapes(ctx.ggml_context, a, b) + a, b = broadcast_shapes(ctx, a, b) sub_result = ggml.ggml_sub( ctx.ggml_context, @@ -4224,7 +4251,7 @@ def ggml_operator_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): next_item = ctx.from_numpy(empty_np) for tensor in node_inputs: - tensor, next_item = broadcast_shapes(ctx.ggml_context, tensor, next_item) + tensor, next_item = broadcast_shapes(ctx, tensor, next_item) next_item = ggml.ggml_add( ctx.ggml_context, tensor, From ba01d2352300f4a7270c7bcff11344bcc1f42585 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 27 Sep 2023 23:06:55 -0700 Subject: [PATCH 188/232] Mul np fallback --- ggml/contrib/onnx.py | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 56340a85..b113dd15 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -2346,12 +2346,39 @@ def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, b = broadcast_shapes(ctx, a, b) - mul_result = ggml.ggml_mul( - ctx.ggml_context, - a, - b, - ) + ggml_type_src1 = ggml.utils.GGML_TYPE(b.contents.type) + if ggml_type_src1 == ggml.utils.GGML_TYPE.F32: + mul_result = ggml.ggml_mul( + ctx.ggml_context, + a, + b, + ) + else: + np_dtype = get_tensor_dtype(a) + x = np.empty(get_tensor_shape(a), dtype=np_dtype) + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom3_op_t + def custom_mul( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) + + x = np.multiply(a, b) + ctx.set_tensor_out(tensor_out, x) + + mul_result = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, a, b, custom_mul, 1, None + ) + ctx.refs.append(custom_mul) ctx.tensors_dict[output_name] = mul_result From 1cb96bdad61103989e982538a2b1195959b5ac59 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Thu, 28 Sep 2023 22:53:10 -0400 Subject: [PATCH 189/232] Fix quantized onnx graph test --- tests/test_ggml_onnx.py | 198 +++++++++++++++++++++++++++++++++++----- 1 file changed, 176 insertions(+), 22 deletions(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index e7f378b3..ae1a011f 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -265,24 +265,31 @@ def test_ggml_onnx_runtime_quantized(): from ggml.contrib.onnx import OnnxGraphRuleEngine, OnnxGraphRule from onnx.onnx_ml_pb2 import ModelProto, NodeProto - def __ancestors_of(node: NodeProto, model: ModelProto) -> List[NodeProto]: + def _depends_on_input(name: str, model: ModelProto) -> bool: + # Depth first search to find any node ancestor in model.graph.inputs + # that is an ancestor of node + initializers = { node.name: node for node in model.graph.initializer } + inputs = { node.name: node for node in model.graph.input } + outputs = { node.name: node for node in model.graph.output } nodes = { node.name: node for node in model.graph.node } - visited: Set[str] = set() - queue = [node.name] - while len(queue) > 0: - curr = queue.pop(0) - if curr in visited: - continue - visited.add(curr) - queue.extend([inp for inp in nodes[curr].input if inp not in visited]) - return [nodes[v] for v in visited] - - def __is_weight_or_constant(node: NodeProto, model: ModelProto) -> bool: - inputs = { node.name for node in model.graph.input } - if node.name in inputs: - return True - ancestors = __ancestors_of(node, model) - return any([ancestor.name in inputs for ancestor in ancestors]) + + def _dfs(name: str, visited: Set[str]) -> bool: + if name in visited: + return False + if name in inputs: + return True + if name not in nodes: + return False + visited.add(name) + for inp in nodes[name].input: + if inp in initializers: + continue + if inp in outputs: + continue + if _dfs(nodes[inp].name, visited): + return True + return False + return _dfs(name, set()) class MatMulTransposeRule(OnnxGraphRule): def __init__(self): @@ -297,19 +304,17 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: break else: return None - + # get first and second input of matmul node matmul_input_0 = matmul_node.input[0] matmul_input_1 = matmul_node.input[1] - nodes = { node.name: node for node in model.graph.node } - # check that first input is _not_ a weight or constant tensor - if __is_weight_or_constant(nodes[matmul_input_0], model): + if _depends_on_input(matmul_input_0, model): return None # check that second input is a weight or constant tensor - if not __is_weight_or_constant(nodes[matmul_input_1], model): + if not _depends_on_input(matmul_input_1, model): return None # replace Matmul(matmul_input_0, matmul_input_1) with Transpose(MatMul(Transpose(matmul_input_1), Transpose(matmul_input_0))) @@ -371,6 +376,155 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: return new_model + class AddAssociativityRule(OnnxGraphRule): + def __init__(self): + super().__init__() + + def apply(self, model: ModelProto) -> Optional[ModelProto]: + # find an add node + add_node: Optional[NodeProto] = None + for node in model.graph.node: + if node.op_type == "Add": + add_node = node + break + else: + return None + + # get first and second input of add node + add_input_0 = add_node.input[0] + add_input_1 = add_node.input[1] + + # check that first input is _not_ a weight or constant tensor + if _depends_on_input(add_input_0, model): + return None + + # check that second input is a weight or constant tensor + if not _depends_on_input(add_input_1, model): + return None + + # replace Add(add_input_0, add_input_1) with Add(add_input_1, add_input_0) + + # create new add node + new_add_node = NodeProto() + new_add_node.CopyFrom(add_node) + new_add_node.op_type = "Add" + new_add_node.name = add_node.name + new_add_node.input[:] = [add_input_1, add_input_0] + new_add_node.output[:] = [add_node.output[0]] + + # Create the new node list + new_nodes: List[NodeProto] = [] + for node in model.graph.node: + if node not in [add_node]: + new_node = NodeProto() + new_node.CopyFrom(node) + new_nodes.append(new_node) + else: + new_nodes.extend([new_add_node]) + + # Create the new graph + new_graph = helper.make_graph( + new_nodes, + model.graph.name, + model.graph.input, + model.graph.output, + model.graph.initializer, + ) + + # create a new model + new_model = helper.make_model( + new_graph, producer_name=model.producer_name + ) + + return new_model + + engine = OnnxGraphRuleEngine( + rules=[MatMulTransposeRule(), AddAssociativityRule()] + ) + + # The name of the input tensor + input_name = "X" + + # The name of the weights tensor + weight_name_a = "A" + weight_name_b = "B" + + # The name of the output + output_name = "Y" + + # Create the nodes (operations) in our graph Y = X * A + B + + # X * A + + node1 = helper.make_node( + "MatMul", [input_name, weight_name_a], ["X_times_A"], name="node1" + ) # X * A + + # X * A + B + + node2 = helper.make_node( + "Add", ["X_times_A", weight_name_b], [output_name], name="node2" + ) # X * A + B + + # Define the tensors (values) in our graph + X_value_info = helper.make_tensor_value_info( + input_name, TensorProto.FLOAT, [None, 32] + ) + + output_value_info = helper.make_tensor_value_info( + output_name, TensorProto.FLOAT, [None, 32] + ) + + # Set A and B as parameters/weights + weights_a = np.random.randn(32, 32).astype(np.float32) + + weights_b = np.random.randn(32, 32).astype(np.float32) + + A_init = helper.make_tensor( + weight_name_a, + TensorProto.FLOAT, + [ + 32, + 32, + ], + weights_a, + ) + B_init = helper.make_tensor( + weight_name_b, + TensorProto.FLOAT, + [ + 32, + 32, + ], + weights_b, + ) + + # Create the graph (model). + graph_def = helper.make_graph( + [node1, node2], + "simple_expression_model", + [X_value_info], + [output_value_info], + [A_init, B_init], + ) + + model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") + + input_data = {"X": np.random.randn(1, 32).astype(np.float32)} + + f = io.BytesIO() + onnx.save(model_def, f) + + runtime_result = InferenceSession(f.getvalue()).run(None, input_data) + + # rewrite the graph + new_model = engine.optimize(model=model_def) + assert new_model is not None + + ggml_dummy_model = GgmlRuntimeBackend.prepare(new_model) + ggml_result = ggml_dummy_model.run(input_data) + assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) + backend_test = onnx.backend.test.BackendTest(GgmlRuntimeBackend, __name__) From 5e4e691be24f8fe449dad86f043657b1f18d70c7 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 30 Sep 2023 01:28:32 -0700 Subject: [PATCH 190/232] Fix transpose so it handles any n_dims --- ggml/contrib/onnx.py | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index b113dd15..a5a2869e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4505,36 +4505,22 @@ def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = node_inputs[0] input_shape = get_tensor_shape(x) - perm_map = {1: [0, 1, 2, 3], 2: [1, 0, 2, 3], 3: [2, 1, 0, 3], 4: [3, 2, 1, 0]} - perm_attr = next((attr for attr in node.attribute if attr.name == "perm"), None) - # add special case and -> fix me comments - if perm_attr is None: - perms = perm_map.get(len(input_shape), [1, 0, 2, 3]) + perms = list(reversed(range(len(input_shape)))) else: perms = list(perm_attr.ints) - perms += [0, 1, 2, 3][len(perms) :] - - ax0, ax1, ax2, ax3 = perms - dims = ggml.utils.get_ndims(x) - - if dims > 3: - raise ValueError( - "n_dims cannot be more than 3. 4D permutations may not work" - ) # FIXME: 2,3D permutations are fine 4d is not. Passes ONNX test - if dims == 3 and f"02" in "".join([str(perm) for perm in perms]): - x = ggml.ggml_transpose(ctx.ggml_context, x) + # TODO: This can probably be simplified + idxs = list(reversed(range(len(perms)))) + new_idxs = [-1] * len(perms) + for idx, ax in enumerate(perms): + new_idxs[ax] = idxs[idx] + axes = list(reversed(new_idxs)) + list(range(4)[len(perms) :]) + ax0, ax1, ax2, ax3 = axes transpose_result = ggml.ggml_permute(ctx.ggml_context, x, ax0, ax1, ax2, ax3) - - if dims == 3 and f"02" in "".join([str(perm) for perm in perms]): - transpose_result = ggml.ggml_permute( - ctx.ggml_context, transpose_result, 0, 2, 1, 3 - ) - ctx.tensors_dict[output_name] = transpose_result From bbe99bceecc2d0a0265c8399fb5ce589e109a634 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 7 Oct 2023 09:38:42 -0700 Subject: [PATCH 191/232] Fix Mul shape --- ggml/contrib/onnx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index a5a2869e..cabfdffd 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -2356,7 +2356,7 @@ def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) else: np_dtype = get_tensor_dtype(a) - x = np.empty(get_tensor_shape(a), dtype=np_dtype) + x = np.empty(ctx.get_tensor_shape(a), dtype=np_dtype) x_t = ctx.from_numpy(x) @ggml.ggml_custom3_op_t From dce167fbcc5242ea592f21c6a3ba6863911206d8 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 7 Oct 2023 10:20:28 -0700 Subject: [PATCH 192/232] Add numpy fallback Add op --- ggml/contrib/onnx.py | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index cabfdffd..70b5294f 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -195,15 +195,41 @@ def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) output_name = node.output[0] - a, b = node_inputs a, b = broadcast_shapes(ctx, a, b) - add_result = ggml.ggml_add( - ctx.ggml_context, - a, - b, - ) + if ggml.utils.GGML_TYPE(a.contents.type) == ggml.utils.GGML_TYPE.I32: + np_dtype = get_tensor_dtype(a) + x = np.empty(ctx.get_tensor_shape(a), dtype=np_dtype) + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom3_op_t + def custom_add( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) + + x = np.add(a, b) + ctx.set_tensor_out(tensor_out, x) + + add_result = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, a, b, custom_add, 1, None + ) + ctx.refs.append(custom_add) + + else: + add_result = ggml.ggml_add( + ctx.ggml_context, + a, + b, + ) ctx.tensors_dict[output_name] = add_result From 62b7e2d9fd350073a0c942062ed90f1ed5770024 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 7 Oct 2023 10:40:38 -0700 Subject: [PATCH 193/232] Fix Where op --- ggml/contrib/onnx.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 70b5294f..97f560b0 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4645,16 +4645,17 @@ def custom_where( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_1) - y = ggml.utils.to_numpy(tensor_in_2) - condition_array = ggml.utils.to_numpy(tensor_in_3) + y = ggml.utils.to_numpy(tensor_in_1) + x = ggml.utils.to_numpy(tensor_in_2) + + condition_array = ctx.to_numpy(tensor_in_3) new_tensor = np.where(condition_array, x, y) ctx.set_tensor_out(tensor_out, new_tensor) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( ctx.ggml_context, - node_inputs[1], node_inputs[2], + node_inputs[1], node_inputs[0], custom_where, 1, From 6951246d46773b4049a2a334340092182ec637b0 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sun, 8 Oct 2023 12:57:11 -0700 Subject: [PATCH 194/232] Fix unsqueeze --- ggml/contrib/onnx.py | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 97f560b0..da17064e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -775,7 +775,6 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP data_tensor = ctx.from_numpy(data_value.astype(np_data_type_limit)) ctx.eval_tensor(node_inputs[0]) shape = ctx.to_numpy(node_inputs[0]) - x = np.empty(shape, dtype=np_data_type_limit) x_t = ctx.from_numpy(x) @@ -4569,29 +4568,21 @@ def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes_eval = ctx.eval_tensor( axes_input, ) - axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) + axes = ctx.to_numpy(axes_eval).astype(dtype=np.int32) axes_values = [ax if ax >= 0 else ax + x_ndims + 1 for ax in axes] axes_values.sort() - dummy_data = np.empty(x_shape) + x = np.empty(x_shape, dtype=x_dtype) for axis in axes_values: - dummy_data = np.expand_dims(dummy_data, axis=axis) - - ggml_type = map_to_ggml_type(x_dtype) - new_shape = tuple(reversed(dummy_data.shape)) + x = np.expand_dims(x, axis=axis) + new_shape = x.shape if len(new_shape) > 4: raise ValueError( f'Error for node "{node.name}": {len(new_shape)}D arrays are not allowed.' ) - - x_t = ggml.ggml_new_tensor( - ctx.ggml_context, - ggml_type.value, - len(new_shape), - (ctypes.c_int64 * len(new_shape))(*new_shape), - ) + x_t = ctx.from_numpy(x) @ggml.ggml_custom3_op_t def custom_unsqueeze( @@ -4603,15 +4594,15 @@ def custom_unsqueeze( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) - axes = ggml.utils.to_numpy(tensor_in_3) + x = ctx.to_numpy(tensor_in_2) + axes = ctx.to_numpy(tensor_in_3) axes_values = [ax if ax >= 0 else ax + x.ndim + 1 for ax in axes] axes_values.sort() axes_values = np.array(axes_values) for axis in axes_values: x = np.expand_dims(x, axis=axis) - + # print(node) ctx.set_tensor_out(tensor_out, x) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( From 9275099099fcb7e67a030606d9f1eaae32861b2a Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Thu, 12 Oct 2023 02:20:28 -0400 Subject: [PATCH 195/232] Fix allocate tensor for view tensors --- ggml/contrib/onnx.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index da17064e..6f2b6281 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4744,8 +4744,14 @@ def to_numpy(self, tensor: ggml.ggml_tensor_p) -> npt.NDArray[Any]: return array.reshape(shape) def alloc_tensor_cpu(self, tensor: ggml.ggml_tensor_p): + # Check if tensor is a view and if so allocate the view source + if tensor.contents.view_src: + self.alloc_tensor_cpu(tensor.contents.view_src) + tensor.contents.data = tensor.contents.view_src.contents.data + # Check if tensor is already allocated if tensor.contents.data: return + # Allocate tensor buffer = (ctypes.c_uint8 * ggml.ggml_nbytes_pad(tensor))() self.refs.append(buffer) tensor.contents.data = ctypes.cast(ctypes.addressof(buffer), ctypes.c_void_p) @@ -4773,8 +4779,16 @@ def eval_tensor(self, tensor: ggml.ggml_tensor_p): alignment = 32 alloc_size = ggml.utils.alloc_graph_measure(gf, alignment=32) alloc_buffer = (ctypes.c_uint8 * alloc_size)() - leaf_data = [ggml.ggml_get_data(gf.leafs[i]) for i in range(gf.n_leafs)] - node_data = [ggml.ggml_get_data(gf.nodes[i]) for i in range(gf.n_nodes)] + def copy_tensor(src: ggml.ggml_tensor_p, dst: Optional[ggml.ggml_tensor_p] = None) -> ggml.ggml_tensor: + # copy tensor data byte-by-byte using ctypes + src_tensor = src.contents + dst_tensor = ggml.ggml_tensor() if dst is None else dst.contents + ctypes.memmove(ctypes.byref(dst_tensor), ctypes.byref(src_tensor), ctypes.sizeof(src_tensor)) + return dst_tensor + leafs = [copy_tensor(gf.leafs[i]) for i in range(gf.n_leafs)] + nodes = [copy_tensor(gf.nodes[i]) for i in range(gf.n_nodes)] + # leaf_data = [ggml.ggml_get_data(gf.leafs[i]) for i in range(gf.n_leafs)] + # node_data = [ggml.ggml_get_data(gf.nodes[i]) for i in range(gf.n_nodes)] allocr = ggml.ggml_allocr_new( ctypes.cast(alloc_buffer, ctypes.c_void_p), alloc_size, alignment ) @@ -4782,9 +4796,11 @@ def eval_tensor(self, tensor: ggml.ggml_tensor_p): self.compute_graph(gf) ggml.ggml_allocr_free(allocr) for i in range(gf.n_leafs): - gf.leafs[i].contents.data = leaf_data[i] + copy_tensor(ctypes.pointer(leafs[i]), gf.leafs[i]) + # gf.leafs[i].contents.data = leaf_data[i] for i in range(gf.n_nodes): - gf.nodes[i].contents.data = node_data[i] + copy_tensor(ctypes.pointer(nodes[i]), gf.nodes[i]) + # gf.nodes[i].contents.data = node_data[i] return tensor def set_tensor_out(self, tensor: ggml.ggml_tensor_p, array: npt.NDArray[Any]): @@ -4917,8 +4933,8 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: refs: List[Any] = [] - gf = ggml.ggml_cgraph() - gf_p = ctypes.pointer(gf) + # gf = ggml.ggml_cgraph() + # gf_p = ctypes.pointer(gf) output_names = [output.name for output in model_graph.output] ctx = GgmlOnnxExecutionContext(self, ggml_tensors, ggml_context, refs) @@ -4936,7 +4952,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: for output in node.output: if output in output_names: - ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) + # ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) ctx.eval_tensor(ggml_tensors[output]) graph_outputs: List[npt.NDArray[Any]] = [] From 265b55cf7cc66706be509abd5f9df97fa6d28651 Mon Sep 17 00:00:00 2001 From: David Miller Date: Fri, 13 Oct 2023 12:51:47 -0700 Subject: [PATCH 196/232] Fixes: Conv, Add, Div, Pad, Or, Concat, Cast --- ggml/contrib/onnx.py | 92 ++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index da17064e..a8b15273 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -480,7 +480,7 @@ def ggml_operator_cast(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] np_data_type = tensor_dtype_to_np_dtype(onnx_type) np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) - x = np.empty(get_tensor_shape(a), dtype=np_data_type_limit) + x = np.empty(ctx.get_tensor_shape(a), dtype=np_data_type_limit) x_t = ctx.from_numpy(x) @@ -654,10 +654,9 @@ def concat_2(tensor_a, tensor_b): 1, None, ) - - ctx.refs.append(custom_concat) return new_tensor + ctx.refs.append(custom_concat) new_tensor = node_inputs[0] for tensor in node_inputs[1:]: new_tensor = concat_2(new_tensor, tensor) @@ -816,9 +815,14 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs_iter = iter(node_inputs) x = next(node_inputs_iter) - x_shape = get_tensor_shape(x) + x_shape = ctx.get_tensor_shape(x) w = next(node_inputs_iter) - w_shape = get_tensor_shape(w) + w_shape = ctx.get_tensor_shape(w) + w_dtype = get_tensor_dtype(w) + + if w_dtype == np.float32: + w = ctx.from_numpy(ctx.to_numpy(w).astype(np.float16)) + m = w_shape[0] bias = next( node_inputs_iter, @@ -868,12 +872,10 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if len(strides) != 2: raise NotImplementedError("Cannot handle other than 2 strides") - raise NotImplementedError(f'Operator "Conv" not implemented') - # FIXME: ggml can only work with F16 - conv_result = ggml.ggml_conv_2d( + cur = ggml.ggml_conv_2d( ctx.ggml_context, + w, x, - bias, strides[0], strides[1], pads[0], @@ -881,8 +883,17 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): dilations[0], dilations[1], ) + result = ggml.ggml_add( + ctx.ggml_context, + cur, + ggml.ggml_repeat( + ctx.ggml_context, + ggml.ggml_reshape_3d(ctx.ggml_context, bias, 1, 1, bias.contents.ne[0]), + cur, + ), + ) - ctx.tensors_dict[node.output[0]] = conv_result + ctx.tensors_dict[node.output[0]] = result @register_ggml_operator("ConvTranspose") @@ -1095,12 +1106,37 @@ def ggml_operator_div(ctx: "GgmlOnnxExecutionContext", node: NodeProto): b = node_inputs[1] a, b = broadcast_shapes(ctx, a, b) + a_dtype = get_tensor_dtype(a) + if a_dtype == np.float32: + div_result = ggml.ggml_div( + ctx.ggml_context, + a, + b, + ) + else: + x = np.empty(ctx.get_tensor_shape(a), dtype=a_dtype) + x_t = ctx.from_numpy(x) - div_result = ggml.ggml_div( - ctx.ggml_context, - a, - b, - ) + @ggml.ggml_custom3_op_t + def custom_div( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) + + x = np.divide(a, b) + ctx.set_tensor_out(tensor_out, x) + + div_result = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, a, b, custom_div, 1, None + ) + ctx.refs.append(custom_div) ctx.tensors_dict[output_name] = div_result return div_result @@ -2515,20 +2551,26 @@ def custom_or( @register_ggml_operator("Pad") def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + # x, pads, value, axes - if len(ctx.tensors_dict) < 2: + if len(node_inputs) < 2: raise ValueError( f'Error for node "{node.name}": Operation "Pad" requires at least two inputs. Actual number of inputs: {len(node_inputs)}' ) - input_rank = ctx.tensors_dict["x"].contents.n_dims + + node_inputs += [None] * (4 - len(node_inputs)) + x_in, pads, value, axes = node_inputs + + input_rank = x_in.contents.n_dims mode = next( (attr.s for attr in node.attribute if attr.name == "mode"), b"constant" ).decode("utf-8") - if "axes" not in ctx.tensors_dict: + if axes is None: axes = list(range(input_rank)) else: - axes_eval = ctx.eval_tensor(ctx.tensors_dict["axes"]) + axes_eval = ctx.eval_tensor(axes) axes = ctx.to_numpy(axes_eval) axes = [axis if axis >= 0 else axis + input_rank for axis in axes] num_axes = len(axes) @@ -2536,7 +2578,7 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): for _ in range(input_rank): pad_width += [[0, 0]] # init to zero - raw_pads = ctx.to_numpy(ctx.eval_tensor(ctx.tensors_dict["pads"])) + raw_pads = ctx.to_numpy(ctx.eval_tensor(pads)) # re-order to np.pad accepted order ((x1_begin, x1_end), (x2_begin, x2_end), ...) for i in range(num_axes): @@ -2546,15 +2588,15 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): pad_width[axis] = [raw_pads[i], raw_pads[i + num_axes]] expand_by = [sum(pad) for pad in pad_width] - prev_shape = get_tensor_shape(ctx.tensors_dict["x"]) + prev_shape = get_tensor_shape(x_in) output_shape = [sum(x) for x in zip(prev_shape, expand_by)] - a_dtype = get_tensor_dtype(ctx.tensors_dict["x"]) + a_dtype = get_tensor_dtype(x_in) x = np.empty(output_shape, dtype=a_dtype) x_t = ctx.from_numpy(x) constant_value = None - if "value" in ctx.tensors_dict: - constant_values = ctx.to_numpy(ctx.eval_tensor(ctx.tensors_dict["value"])) + if value is not None: + constant_values = ctx.to_numpy(ctx.eval_tensor(value)) @ggml.ggml_custom2_op_t def custom_pad( @@ -2585,7 +2627,7 @@ def custom_pad( new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, x_t, - ctx.tensors_dict["x"], + x_in, custom_pad, 1, None, From 9350741c70c38f78aad41b613226eb9231bd988d Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 21 Oct 2023 00:29:52 -0700 Subject: [PATCH 197/232] Save --- ggml/__init__.py | 2 + ggml/contrib/onnx.py | 100 +++++++++++++++++++++++++++++++++++-------- ggml/ggml.py | 70 ++++++++++++++++++++++++------ 3 files changed, 142 insertions(+), 30 deletions(-) diff --git a/ggml/__init__.py b/ggml/__init__.py index 0f114d0b..3c60471e 100644 --- a/ggml/__init__.py +++ b/ggml/__init__.py @@ -1,3 +1,5 @@ from .ggml import * +from signal import SIGABRT +import traceback __version__ = "0.0.20" diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index a8b15273..19f885ff 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -23,6 +23,8 @@ import ggml import ggml.utils +import IPython + GgmlOperator = Callable[["GgmlOnnxExecutionContext", NodeProto], None] ggml_operators: Dict[str, GgmlOperator] = {} @@ -600,6 +602,35 @@ def custom_ceil( ctx.refs.append(custom_ceil) +@register_ggml_operator("Clip") +def ggml_operator_clip(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + x_t, a_min, a_max = node_inputs + shape = ctx.get_tensor_shape(x_t) + name = node.output[0] + + @ggml.ggml_custom3_op_t + def custom_clip( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + tensor_in_3: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a_min = ctx.to_numpy(tensor_in_2) + a_max = ctx.to_numpy(tensor_in_3) + a = ctx.to_numpy(tensor_in_1) + x = np.clip(a, a_min, a_max) + ctx.set_tensor_out(tensor_out, x) + + new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_context, x_t, a_min, a_max, custom_clip, 1, None + ) + ctx.refs.append(custom_clip) + + @register_ggml_operator("Concat") def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -746,7 +777,6 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP node_attributes = node.attribute value_attr = next(attr for attr in node_attributes if "value" in attr.name) - if value_attr.HasField("t"): tensor = value_attr.t data_type = tensor.data_type @@ -757,6 +787,8 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) else: data_value = onnx.numpy_helper.to_array(tensor) + if node.output[0] == "/ConstantOfShape_output_0": + IPython.embed() else: data_type = value_attr.type @@ -2713,40 +2745,37 @@ def custom_pow( ctx.refs.append(custom_pow) -@register_ggml_operator("Reciprocal") -def ggml_operator_reciprocal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): +@register_ggml_operator("RandomNormalLike") +def ggml_operator_random_normal_like(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + shape = ctx.get_tensor_shape(node_inputs[0]) + dtype = get_tensor_dtype(node_inputs[0]) - if len(node_inputs) != 1: - raise ValueError( - f'Error for node "{node.name}": Operation "Reciprocal" requires exactly one input. Actual number of inputs: {len(node_inputs)}' - ) - - x = node_inputs[0] + x = np.empty(shape, dtype=dtype) + x_t = ctx.from_numpy(x) @ggml.ggml_custom1_op_t - def custom_reciprocal( + def custom_random_normal( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, ith: int, nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_1) - y = np.reciprocal(x) - - ctx.set_tensor_out(tensor_out, y) + # TODO: use loc and scale from inputs + x = np.random.normal(size=shape, loc=0.0, scale=1.0).astype(dtype) + ctx.set_tensor_out(tensor_out, x) + ctx.refs.append(custom_random_normal) + # breakpoint() new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( ctx.ggml_context, - x, - custom_reciprocal, + x_t, + custom_random_normal, 1, None, ) - ctx.refs.append(custom_reciprocal) - @register_ggml_operator("Range") def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -2797,6 +2826,41 @@ def custom_range( ctx.refs.append(custom_range) +@register_ggml_operator("Reciprocal") +def ggml_operator_reciprocal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Reciprocal" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + x = node_inputs[0] + + @ggml.ggml_custom1_op_t + def custom_reciprocal( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + x = ggml.utils.to_numpy(tensor_in_1) + y = np.reciprocal(x) + + ctx.set_tensor_out(tensor_out, y) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_context, + x, + custom_reciprocal, + 1, + None, + ) + + ctx.refs.append(custom_reciprocal) + + class ReduceOpsUserData(ctypes.Structure): _fields_ = [ ("axes", ctypes.POINTER(ctypes.c_int)), diff --git a/ggml/ggml.py b/ggml/ggml.py index 680bad69..130ef26f 100644 --- a/ggml/ggml.py +++ b/ggml/ggml.py @@ -730,6 +730,7 @@ class ggml_cplan(ctypes.Structure): # enum ggml_cgraph_eval_order order; + # // performance # int perf_runs; # int64_t perf_cycles; @@ -1616,15 +1617,16 @@ def ggml_set_f32( lib.ggml_set_f32.argtypes = [ctypes.POINTER(ggml_tensor), ctypes.c_float] lib.ggml_set_f32.restype = ctypes.POINTER(ggml_tensor) + # // Converts a flat index into coordinates # GGML_API void ggml_unravel_index(const struct ggml_tensor * tensor, int64_t i, int64_t * i0, int64_t * i1, int64_t * i2, int64_t * i3); def ggml_unravel_index( tensor: ggml_tensor_p, i: Union[ctypes.c_int64, int], - i0, # type: "ctypes._Pointer(ctypes.c_int64)" # type: ignore - i1, # type: "ctypes._Pointer(ctypes.c_int64)" # type: ignore - i2, # type: "ctypes._Pointer(ctypes.c_int64)" # type: ignore - i3, # type: "ctypes._Pointer(ctypes.c_int64)" # type: ignore + i0, # type: "ctypes._Pointer(ctypes.c_int64)" # type: ignore + i1, # type: "ctypes._Pointer(ctypes.c_int64)" # type: ignore + i2, # type: "ctypes._Pointer(ctypes.c_int64)" # type: ignore + i3, # type: "ctypes._Pointer(ctypes.c_int64)" # type: ignore ): """Convert a flat index into coordinates. @@ -1637,6 +1639,7 @@ def ggml_unravel_index( i3: pointer to index 3""" return lib.ggml_unravel_index(tensor, i, i0, i1, i2, i3) + lib.ggml_unravel_index.argtypes = [ ctypes.POINTER(ggml_tensor), ctypes.c_int64, @@ -1647,6 +1650,7 @@ def ggml_unravel_index( ] lib.ggml_unravel_index.restype = None + # GGML_API int32_t ggml_get_i32_1d(const struct ggml_tensor * tensor, int i); def ggml_get_i32_1d( tensor: ggml_tensor_p, @@ -1689,6 +1693,7 @@ def ggml_set_i32_1d( ] lib.ggml_set_i32_1d.restype = None + # GGML_API int32_t ggml_get_i32_nd(const struct ggml_tensor * tensor, int i0, int i1, int i2, int i3); def ggml_get_i32_nd( tensor: ggml_tensor_p, @@ -1710,6 +1715,7 @@ def ggml_get_i32_nd( integer value of element at coordinates""" return lib.ggml_get_i32_nd(tensor, i0, i1, i2, i3) + lib.ggml_get_i32_nd.argtypes = [ ctypes.POINTER(ggml_tensor), ctypes.c_int, @@ -1719,6 +1725,7 @@ def ggml_get_i32_nd( ] lib.ggml_get_i32_nd.restype = ctypes.c_int32 + # GGML_API void ggml_set_i32_nd(const struct ggml_tensor * tensor, int i0, int i1, int i2, int i3, int32_t value); def ggml_set_i32_nd( tensor: ggml_tensor_p, @@ -1739,6 +1746,7 @@ def ggml_set_i32_nd( value: integer value to set element to""" return lib.ggml_set_i32_nd(tensor, i0, i1, i2, i3, value) + lib.ggml_set_i32_nd.argtypes = [ ctypes.POINTER(ggml_tensor), ctypes.c_int, @@ -1749,6 +1757,7 @@ def ggml_set_i32_nd( ] lib.ggml_set_i32_nd.restype = None + # GGML_API float ggml_get_f32_1d(const struct ggml_tensor * tensor, int i); def ggml_get_f32_1d( tensor: ggml_tensor_p, @@ -1790,6 +1799,7 @@ def ggml_set_f32_1d( ] lib.ggml_set_f32_1d.restype = None + # GGML_API float ggml_get_f32_nd(const struct ggml_tensor * tensor, int i0, int i1, int i2, int i3); def ggml_get_f32_nd( tensor: ggml_tensor_p, @@ -1811,6 +1821,7 @@ def ggml_get_f32_nd( float value of element at coordinates""" return lib.ggml_get_f32_nd(tensor, i0, i1, i2, i3) + lib.ggml_get_f32_nd.argtypes = [ ctypes.POINTER(ggml_tensor), ctypes.c_int, @@ -1841,6 +1852,7 @@ def ggml_set_f32_nd( value: float value to set element to""" return lib.ggml_set_f32_nd(tensor, i0, i1, i2, i3, value) + lib.ggml_set_f32_nd.argtypes = [ ctypes.POINTER(ggml_tensor), ctypes.c_int, @@ -2051,6 +2063,7 @@ def ggml_add_inplace( ] lib.ggml_add_inplace.restype = ctypes.POINTER(ggml_tensor) + # GGML_API struct ggml_tensor * ggml_add_cast( # struct ggml_context * ctx, # struct ggml_tensor * a, @@ -3640,6 +3653,7 @@ def ggml_cont_inplace( lib.ggml_cont_inplace.argtypes = [ggml_context_p, ctypes.POINTER(ggml_tensor)] lib.ggml_cont_inplace.restype = ctypes.POINTER(ggml_tensor) + # // make contiguous, with new shape # GGML_API struct ggml_tensor * ggml_cont_1d( # struct ggml_context * ctx, @@ -3652,6 +3666,7 @@ def ggml_cont_1d( ) -> ggml_tensor_p: return lib.ggml_cont_1d(ctx, a, ne0) + lib.ggml_cont_1d.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_tensor), @@ -3660,7 +3675,6 @@ def ggml_cont_1d( lib.ggml_cont_1d.restype = ctypes.POINTER(ggml_tensor) - # GGML_API struct ggml_tensor * ggml_cont_2d( # struct ggml_context * ctx, # struct ggml_tensor * a, @@ -3674,6 +3688,7 @@ def ggml_cont_2d( ) -> ggml_tensor_p: return lib.ggml_cont_2d(ctx, a, ne0, ne1) + lib.ggml_cont_2d.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_tensor), @@ -3682,6 +3697,7 @@ def ggml_cont_2d( ] lib.ggml_cont_2d.restype = ctypes.POINTER(ggml_tensor) + # GGML_API struct ggml_tensor * ggml_cont_3d( # struct ggml_context * ctx, # struct ggml_tensor * a, @@ -3697,6 +3713,7 @@ def ggml_cont_3d( ) -> ggml_tensor_p: return lib.ggml_cont_3d(ctx, a, ne0, ne1, ne2) + lib.ggml_cont_3d.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_tensor), @@ -3706,6 +3723,7 @@ def ggml_cont_3d( ] lib.ggml_cont_3d.restype = ctypes.POINTER(ggml_tensor) + # GGML_API struct ggml_tensor * ggml_cont_4d( # struct ggml_context * ctx, # struct ggml_tensor * a, @@ -3723,6 +3741,7 @@ def ggml_cont_4d( ) -> ggml_tensor_p: return lib.ggml_cont_4d(ctx, a, ne0, ne1, ne2, ne3) + lib.ggml_cont_4d.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_tensor), @@ -3733,6 +3752,7 @@ def ggml_cont_4d( ] lib.ggml_cont_4d.restype = ctypes.POINTER(ggml_tensor) + # // return view(a), b specifies the new shape # // TODO: when we start computing gradient, make a copy instead of view # GGML_API struct ggml_tensor * ggml_reshape( @@ -4261,7 +4281,7 @@ def ggml_rope( n_ctx: Union[ctypes.c_int, int], ) -> ggml_tensor_p: """Rotary position embedding - + Parameters: ctx: ggml context a: tensor @@ -4276,6 +4296,7 @@ def ggml_rope( Pointer to ggml_tensor""" return lib.ggml_rope(ctx, a, b, n_dims, mode, n_ctx) + lib.ggml_rope.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_tensor), @@ -4286,6 +4307,7 @@ def ggml_rope( ] lib.ggml_rope.restype = ctypes.POINTER(ggml_tensor) + # // in-place, returns view(a) # GGML_API struct ggml_tensor * ggml_rope_inplace( # struct ggml_context * ctx, @@ -4318,6 +4340,7 @@ def ggml_rope_inplace( Pointer to ggml_tensor""" return lib.ggml_rope_inplace(ctx, a, b, n_dims, mode, n_ctx) + lib.ggml_rope_inplace.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_tensor), @@ -4328,6 +4351,7 @@ def ggml_rope_inplace( ] lib.ggml_rope_inplace.restype = ctypes.POINTER(ggml_tensor) + # // custom RoPE # GGML_API struct ggml_tensor * ggml_rope_custom( # struct ggml_context * ctx, @@ -4349,9 +4373,8 @@ def ggml_rope_custom( freq_scale: Union[ctypes.c_float, float], ) -> ggml_tensor_p: """Custom rotary position embedding""" - return lib.ggml_rope_custom( - ctx, a, b, n_dims, mode, n_ctx, freq_base, freq_scale - ) + return lib.ggml_rope_custom(ctx, a, b, n_dims, mode, n_ctx, freq_base, freq_scale) + lib.ggml_rope_custom.argtypes = [ ggml_context_p, @@ -4392,6 +4415,7 @@ def ggml_rope_custom_inplace( ctx, a, b, n_dims, mode, n_ctx, freq_base, freq_scale ) + lib.ggml_rope_custom_inplace.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_tensor), @@ -4424,6 +4448,7 @@ def ggml_rope_xpos_inplace( """xPos RoPE, in-place, returns view(a)""" return lib.ggml_rope_xpos_inplace(ctx, a, b, n_dims, base, down) + lib.ggml_rope_xpos_inplace.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_tensor), @@ -4466,6 +4491,7 @@ def ggml_rope_back( ctx, a, b, n_dims, mode, n_ctx, freq_base, freq_scale, xpos_base, xpos_down ) + lib.ggml_rope_back.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_tensor), @@ -4621,6 +4647,7 @@ def ggml_conv_1d_ph( ] lib.ggml_conv_1d_ph.restype = ctypes.POINTER(ggml_tensor) + # GGML_API struct ggml_tensor * ggml_conv_transpose_1d( # struct ggml_context * ctx, # struct ggml_tensor * a, @@ -4644,11 +4671,12 @@ def ggml_conv_transpose_1d( s0: stride p0: padding d0: dilation - + Returns: output tensor""" return lib.ggml_conv_transpose_1d(ctx, a, b, s0, p0, d0) + lib.ggml_conv_transpose_1d.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_tensor), @@ -4659,6 +4687,7 @@ def ggml_conv_transpose_1d( ] lib.ggml_conv_transpose_1d.restype = ctypes.POINTER(ggml_tensor) + # GGML_API struct ggml_tensor * ggml_conv_2d( # struct ggml_context * ctx, # struct ggml_tensor * a, @@ -6094,6 +6123,7 @@ def ggml_graph_dump_dot( ] lib.ggml_graph_dump_dot.restype = None + # // build gradient checkpointing backward graph gb for gf using provided checkpoints # // gb_tmp will contain original backward graph with rewritten backward process nodes, # // but without the second forward pass nodes. @@ -6116,6 +6146,7 @@ def ggml_build_backward_gradient_checkpointing( ctx, gf, gb, gb_tmp, checkpoints, n_checkpoints ) + lib.ggml_build_backward_gradient_checkpointing.argtypes = [ ggml_context_p, ctypes.POINTER(ggml_cgraph), @@ -6181,7 +6212,11 @@ def ggml_build_backward_gradient_checkpointing( # typedef void (*ggml_opt_callback)(void * data, int accum_step, float * sched, bool * cancel); ggml_opt_callback = ctypes.CFUNCTYPE( - None, ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_bool) + None, + ctypes.c_void_p, + ctypes.c_int, + ctypes.POINTER(ctypes.c_float), + ctypes.POINTER(ctypes.c_bool), ) # typedef void (*ggml_log_callback)(enum ggml_log_level level, const char * text, void * user_data); @@ -6965,6 +7000,7 @@ def gguf_get_val_f32( ] lib.gguf_get_val_f32.restype = ctypes.c_float + # GGML_API uint64_t gguf_get_val_u64 (const struct gguf_context * ctx, int key_id); def gguf_get_val_u64( ctx: gguf_context_p, @@ -6979,6 +7015,7 @@ def gguf_get_val_u64( ] lib.gguf_get_val_u64.restype = ctypes.c_uint64 + # GGML_API int64_t gguf_get_val_i64 (const struct gguf_context * ctx, int key_id); def gguf_get_val_i64( ctx: gguf_context_p, @@ -6993,6 +7030,7 @@ def gguf_get_val_i64( ] lib.gguf_get_val_i64.restype = ctypes.c_int64 + # GGML_API double gguf_get_val_f64 (const struct gguf_context * ctx, int key_id); def gguf_get_val_f64( ctx: gguf_context_p, @@ -7007,6 +7045,7 @@ def gguf_get_val_f64( ] lib.gguf_get_val_f64.restype = ctypes.c_double + # GGML_API bool gguf_get_val_bool(const struct gguf_context * ctx, int key_id); def gguf_get_val_bool( ctx: gguf_context_p, @@ -7857,12 +7896,14 @@ def ggml_allocr_alloc_graph( lib.ggml_allocr_alloc_graph.argtypes = [ggml_allocr_p, ctypes.POINTER(ggml_cgraph)] lib.ggml_allocr_alloc_graph.restype = ctypes.c_size_t + # GGML_API size_t ggml_allocr_max_size(struct ggml_allocr * alloc); def ggml_allocr_max_size( alloc: ggml_allocr_p, ) -> int: return lib.ggml_allocr_max_size(alloc) + lib.ggml_allocr_max_size.argtypes = [ggml_allocr_p] lib.ggml_allocr_max_size.restype = ctypes.c_size_t @@ -8044,18 +8085,21 @@ def ggml_cuda_assign_scratch_offset( ] lib.ggml_cuda_assign_scratch_offset.restype = None + # GGML_API void ggml_cuda_copy_to_device(struct ggml_tensor * tensor); def ggml_cuda_copy_to_device( tensor: ggml_tensor_p, ): return lib.ggml_cuda_copy_to_device(tensor) + if GGML_USE_CUBLAS: lib.ggml_cuda_copy_to_device.argtypes = [ ctypes.POINTER(ggml_tensor), ] lib.ggml_cuda_copy_to_device.restype = None + # void ggml_cuda_set_main_device(int main_device); def ggml_cuda_set_main_device( main_device: Union[ctypes.c_int, int], @@ -8166,13 +8210,15 @@ def ggml_cuda_get_device_description( # #define GGML_METAL_MAX_COMMAND_BUFFERS 32 GGML_METAL_MAX_COMMAND_BUFFERS = 32 + # void ggml_metal_log_set_callback(ggml_log_callback log_callback, void * user_data); def ggml_metal_log_set_callback( - log_callback, # type: "ctypes._CFuncPtr" # type: ignore + log_callback, # type: "ctypes._CFuncPtr" # type: ignore user_data: ctypes.c_void_p, ): return lib.ggml_metal_log_set_callback(log_callback, user_data) + if GGML_USE_METAL: lib.ggml_metal_log_set_callback.argtypes = [ ggml_log_callback, From dfa64c4585e1c09bea971fc366756d4b192edab6 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sat, 21 Oct 2023 12:53:15 -0700 Subject: [PATCH 198/232] Handle SIGABRT from GGML --- ggml/ggml.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ggml/ggml.py b/ggml/ggml.py index 130ef26f..30ec47d0 100644 --- a/ggml/ggml.py +++ b/ggml/ggml.py @@ -52,11 +52,24 @@ import os import sys import ctypes +import signal import pathlib +import traceback import importlib.resources from typing import List, Optional, Sequence, Union from typing_extensions import TypeAlias +c_globals = ctypes.CDLL(None) # POSIX + + +@ctypes.CFUNCTYPE(None, ctypes.c_int) +def sigabrt_handler(sig): + traceback.print_stack() + raise Exception("GGML SIGABRT") + + +c_globals.signal(signal.SIGABRT, sigabrt_handler) + # Load the library def load_shared_library(module_name: str, lib_base_name: str): From 0f4ddd6888d587cbcce9611c5647c0134d325918 Mon Sep 17 00:00:00 2001 From: David Miller Date: Mon, 23 Oct 2023 17:19:17 -0700 Subject: [PATCH 199/232] Fix instance norm --- ggml/contrib/onnx.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index c608fca4..a44c5468 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -1914,15 +1914,20 @@ def custom_instancenorm( userdata: Optional[ctypes.c_void_p], ): x = ggml.utils.to_numpy(tensor_in_1) - scale = ggml.utils.to_numpy(tensor_in_2) - B = ggml.utils.to_numpy(tensor_in_3) + s = ggml.utils.to_numpy(tensor_in_2) + bias = ggml.utils.to_numpy(tensor_in_3) epsilon = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_double)).contents.value - mean = np.mean(x, axis=(2, 3), keepdims=True) - variance = np.var(x, axis=(2, 3), keepdims=True) - normalized = (x - mean) / np.sqrt(variance + epsilon) - y = scale.reshape(1, -1, 1, 1) * normalized + B.reshape(1, -1, 1, 1) + dims_x = len(x.shape) + axis = tuple(range(2, dims_x)) + mean = np.mean(x, axis=axis, keepdims=True) + var = np.var(x, axis=axis, keepdims=True) + dim_ones = (1,) * (dims_x - 2) + s = s.reshape(-1, *dim_ones) + bias = bias.reshape(-1, *dim_ones) + + y = s * (x - mean) / np.sqrt(var + epsilon) + bias ctx.set_tensor_out(tensor_out, y) new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( From 7140aa9b9d2c14566b8ed9cfb1df1f91e29362fa Mon Sep 17 00:00:00 2001 From: David Miller Date: Mon, 23 Oct 2023 18:59:59 -0700 Subject: [PATCH 200/232] Fix sigmoid --- ggml/contrib/onnx.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index a44c5468..7065a52c 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3922,25 +3922,32 @@ def ggml_operator_sigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": Operation "Sigmoid" requires exactly one input. Actual number of inputs: {len(node_inputs)}' ) - x = node_inputs[0] + a = node_inputs[0] - @ggml.ggml_custom1_op_t + a_shape = ctx.get_tensor_shape(a) + a_dtype = get_tensor_dtype(a) + + x = np.empty(a_shape, dtype=a_dtype) + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom2_op_t def custom_sigmoid( tensor_out: ggml.ggml_tensor_p, tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, ith: int, nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_1) - - y = 1.0 / (1.0 + np.exp(np.negative(x))) + a = ctx.to_numpy(tensor_in_2) + y = 1.0 / (1.0 + np.exp(np.negative(a))) ctx.set_tensor_out(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_context, - x, + x_t, + a, custom_sigmoid, 1, None, From eb4845718455381409522ebe8e54364561eccf36 Mon Sep 17 00:00:00 2001 From: David Miller Date: Thu, 9 Nov 2023 16:56:22 -0800 Subject: [PATCH 201/232] Use tensor.contents address for shape dict key --- ggml/contrib/onnx.py | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 7065a52c..d0e081bb 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -22,7 +22,6 @@ import ggml import ggml.utils - import IPython GgmlOperator = Callable[["GgmlOnnxExecutionContext", NodeProto], None] @@ -48,7 +47,6 @@ def map_to_ggml_type(dtype: npt.DTypeLike): np_data_type_limit.type, ggml.utils.GGML_TYPE.F32, # TODO: Add i64 but for now, use i32 if looking for i64 or f64 ) - return ggml_type @@ -199,7 +197,6 @@ def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_name = node.output[0] a, b = node_inputs a, b = broadcast_shapes(ctx, a, b) - if ggml.utils.GGML_TYPE(a.contents.type) == ggml.utils.GGML_TYPE.I32: np_dtype = get_tensor_dtype(a) x = np.empty(ctx.get_tensor_shape(a), dtype=np_dtype) @@ -510,9 +507,9 @@ def custom_cast( 1, ctypes.pointer(onnx_type_c), ) + ctx.set_tensor_shape(new_tensor, ctx.get_tensor_shape(a)) ctx.refs.append(custom_cast) - ctx.refs.append(onnx_type_c) @@ -735,6 +732,7 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): data_tensor = ctx.from_numpy(data_value) tensor_shape = data_value.shape + x = np.empty(tensor_shape, dtype=np_data_type_limit) x_t = ctx.from_numpy(x) @@ -762,7 +760,7 @@ def custom_constant( None, ) ctx.refs.append(custom_constant) - + ctx.set_tensor_shape(new_tensor, tensor_shape) ctx.set_tensor_dtype(name, np_data_type) @@ -1169,6 +1167,7 @@ def custom_div( ctx.ggml_context, x_t, a, b, custom_div, 1, None ) ctx.refs.append(custom_div) + ctx.set_tensor_shape(div_result, ctx.get_tensor_shape(a)) ctx.tensors_dict[output_name] = div_result return div_result @@ -2452,6 +2451,7 @@ def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, b, ) + else: np_dtype = get_tensor_dtype(a) x = np.empty(ctx.get_tensor_shape(a), dtype=np_dtype) @@ -2476,7 +2476,9 @@ def custom_mul( mul_result = ggml.ggml_map_custom3_inplace( ctx.ggml_context, x_t, a, b, custom_mul, 1, None ) + ctx.set_tensor_shape(mul_result, ctx.get_tensor_shape(a)) ctx.refs.append(custom_mul) + ctx.tensors_dict[output_name] = mul_result @@ -3923,7 +3925,6 @@ def ggml_operator_sigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) a = node_inputs[0] - a_shape = ctx.get_tensor_shape(a) a_dtype = get_tensor_dtype(a) @@ -4380,6 +4381,7 @@ def custom_squeeze( 1, None, ) + ctx.set_tensor_shape(new_tensor, dummy_data.shape) ctx.refs.append(custom_squeeze) @@ -4836,18 +4838,18 @@ def __init__( self.tensors_dict = tensors_dict self.ggml_context = ggml_context self.refs = refs - self.shapes: Dict[str, Tuple[int, ...]] = {} + self.shapes: Dict[int, Tuple[int, ...]] = {} self.dtypes: Dict[str, npt.DTypeLike] = {} def set_tensor_shape(self, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...]): - data = tensor.contents.data - self.shapes[data] = shape + key = ctypes.addressof(tensor.contents) + self.shapes[key] = shape def get_tensor_shape(self, tensor: ggml.ggml_tensor_p) -> Tuple[int, ...]: - data = tensor.contents.data - if data not in self.shapes: - self.shapes[data] = get_tensor_shape(tensor) - return self.shapes[data] + key = ctypes.addressof(tensor.contents) + if key not in self.shapes: + self.shapes[key] = get_tensor_shape(tensor) + return self.shapes[key] def set_tensor_dtype(self, name: str, dtype: npt.DTypeLike): self.dtypes[name] = dtype @@ -4897,12 +4899,20 @@ def eval_tensor(self, tensor: ggml.ggml_tensor_p): alignment = 32 alloc_size = ggml.utils.alloc_graph_measure(gf, alignment=32) alloc_buffer = (ctypes.c_uint8 * alloc_size)() - def copy_tensor(src: ggml.ggml_tensor_p, dst: Optional[ggml.ggml_tensor_p] = None) -> ggml.ggml_tensor: + + def copy_tensor( + src: ggml.ggml_tensor_p, dst: Optional[ggml.ggml_tensor_p] = None + ) -> ggml.ggml_tensor: # copy tensor data byte-by-byte using ctypes src_tensor = src.contents dst_tensor = ggml.ggml_tensor() if dst is None else dst.contents - ctypes.memmove(ctypes.byref(dst_tensor), ctypes.byref(src_tensor), ctypes.sizeof(src_tensor)) + ctypes.memmove( + ctypes.byref(dst_tensor), + ctypes.byref(src_tensor), + ctypes.sizeof(src_tensor), + ) return dst_tensor + leafs = [copy_tensor(gf.leafs[i]) for i in range(gf.n_leafs)] nodes = [copy_tensor(gf.nodes[i]) for i in range(gf.n_nodes)] # leaf_data = [ggml.ggml_get_data(gf.leafs[i]) for i in range(gf.n_leafs)] From 67d1e669d0497843fc7bb82f757be935cc5e7130 Mon Sep 17 00:00:00 2001 From: David Miller Date: Thu, 9 Nov 2023 17:46:31 -0800 Subject: [PATCH 202/232] Handle permuted MatMul tensor input src1 --- ggml/contrib/onnx.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index d0e081bb..e1aec972 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -785,8 +785,6 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) else: data_value = onnx.numpy_helper.to_array(tensor) - if node.output[0] == "/ConstantOfShape_output_0": - IPython.embed() else: data_type = value_attr.type @@ -2272,6 +2270,20 @@ def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): except: a, b = broadcast_shapes(ctx, a, b) + if ggml.ggml_is_permuted(a): + a_dtype = get_tensor_dtype(a) + a_shape = ggml.utils.get_shape(a) + a = ggml.ggml_cpy( + ctx.ggml_context, + a, + ggml.ggml_new_tensor( + ctx.ggml_context, + map_to_ggml_type(a_dtype).value, + len(a_shape), + (ctypes.c_int64 * len(a_shape))(*a_shape), + ), + ) + b_dtype = get_tensor_dtype(b) b_permute = ggml.ggml_transpose( @@ -2291,7 +2303,6 @@ def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): (ctypes.c_int64 * len(b_shape))(*b_shape), ), ) - mul_mat_result = ggml.ggml_mul_mat( ctx.ggml_context, b_transposed, From 839fa9673694b8ff94b9df4b69374037358621ae Mon Sep 17 00:00:00 2001 From: David Miller Date: Fri, 10 Nov 2023 15:23:00 -0800 Subject: [PATCH 203/232] Resize with restricted parameters implemented. Only nearest-neighbor interpolation --- ggml/contrib/onnx.py | 119 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index e1aec972..c2bfe198 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3839,6 +3839,125 @@ def custom_reshape( ctx.refs.append(custom_reshape) +@register_ggml_operator("Resize") +def ggml_operator_resize(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] if inp != "" else None for inp in node.input] + node_inputs.extend([None] * (4 - len(node_inputs))) + + if len(node_inputs) > 4: + raise ValueError( + f'Error for node "{node.name}": Operation "Resize" requires 1-4 inputs. Actual number of inputs: {len(node_inputs)}' + ) + + a, roi_T, scales_T, sizes_T = node_inputs + + if roi_T is not None: + raise NotImplementedError( + f'Error for node "{node.name}": "roi" parameter not supported' + ) + if sizes_T is not None: + raise NotImplementedError( + f'Error for node "{node.name}": "sizes" parameter not supported' + ) + assert a is not None + assert scales_T is not None + + """ + scales_T (optional, non-differentiable) : tensor(float) +The scale array along each dimension. It takes value greater than 0. If it's less than 1, it's sampling down, otherwise, it's upsampling. The number of elements of 'scales' should be the same as the rank of input 'X' or the length of 'axes', if provided. + Based on that definition, write a code that uses ggml to take tensor a and scale accordingly based on scales_T + """ + + scales_t = ctx.eval_tensor(scales_T) + scales = ctx.to_numpy(scales_t) + + scales_shape = ctx.get_tensor_shape(scales_T) + + a_shape = ctx.get_tensor_shape(a) + a_dtype = get_tensor_dtype(a) + + if scales_shape[0] != len(a_shape): + raise ValueError( + f'Error for node "{node.name}": "scales" parameter must have the same length as the rank of input "X"' + ) + + output_shape = (a_shape * scales).astype(dtype=np.int32) + + x = np.empty(output_shape, dtype=a_dtype) + x_t = ctx.from_numpy(x) + + coordinate_transformation_mode = next( + ( + attr.s.decode("utf-8") + for attr in node.attribute + if attr.name == "coordinate_transformation_mode" + ), + "half_pixel", + ) + cubic_coeff_a = next( + (attr.f for attr in node.attribute if attr.name == "cubic_coeff_a"), -0.75 + ) + mode = next( + (attr.s.decode("utf-8") for attr in node.attribute if attr.name == "mode"), + "nearest", + ) + nearest_mode = next( + ( + attr.s.decode("utf-8") + for attr in node.attribute + if attr.name == "nearest_mode" + ), + "round_prefer_floor", + ) + attribute_names = [attr.name for attr in node.attribute] + expected_attributes = [ + "coordinate_transformation_mode", + "mode", + "nearest_mode", + ] + + assert all([attribute in attribute_names for attribute in expected_attributes]) + + if mode not in ["nearest"]: + raise NotImplementedError("Only mode=nearest is supported") + if nearest_mode not in ["floor"]: + raise NotImplementedError("Only nearest_mode=floor is supported") + if coordinate_transformation_mode not in ["asymmetric"]: + raise NotImplementedError( + "Only coordinate_transformation_mode=asymmetric is supported" + ) + + @ggml.ggml_custom2_op_t + def custom_resize( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) + + output_size = (scales * np.array(a.shape)).astype(int) + y = np.zeros(output_size) + + for idx in np.ndindex(*output_size): + x = (np.array(idx) // scales).astype(int) + y[idx] = a[tuple(x)] + ctx.set_tensor_out(tensor_out, y) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, + x_t, + a, + custom_resize, + 1, + None, + ) + ctx.refs.append(custom_resize) + ctx.tensors_dict[node.output[0]] = new_tensor + + class SeluUserData(ctypes.Structure): _fields_ = [ ("alpha", ctypes.c_double), From 6065ce40b6da46d4f47894982bb6050c9c4dfa36 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 21 Nov 2023 12:35:58 -0800 Subject: [PATCH 204/232] upscale using ggml_upscale --- ggml/contrib/onnx.py | 57 +++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index c2bfe198..9f0a6a0a 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -3927,34 +3927,41 @@ def ggml_operator_resize(ctx: "GgmlOnnxExecutionContext", node: NodeProto): "Only coordinate_transformation_mode=asymmetric is supported" ) - @ggml.ggml_custom2_op_t - def custom_resize( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], - ): - a = ggml.utils.to_numpy(tensor_in_2) + is_integer = all(scales.astype(np.int32) - scales == 0) + if scales[0] == 1 and scales[1] == 1 and scales[2] == scales[3] and is_integer: + # Special case for 2D scaling handled by ggml_upscale + scale_factor = int(scales[2]) + new_tensor = ggml.ggml_upscale(ctx.ggml_context, a, scale_factor) + else: - output_size = (scales * np.array(a.shape)).astype(int) - y = np.zeros(output_size) + @ggml.ggml_custom2_op_t + def custom_resize( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ggml.utils.to_numpy(tensor_in_2) - for idx in np.ndindex(*output_size): - x = (np.array(idx) // scales).astype(int) - y[idx] = a[tuple(x)] - ctx.set_tensor_out(tensor_out, y) + output_size = (scales * np.array(a.shape)).astype(int) + y = np.zeros(output_size) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, - x_t, - a, - custom_resize, - 1, - None, - ) - ctx.refs.append(custom_resize) + for idx in np.ndindex(*output_size): + x = (np.array(idx) // scales).astype(int) + y[idx] = a[tuple(x)] + ctx.set_tensor_out(tensor_out, y) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, + x_t, + a, + custom_resize, + 1, + None, + ) + ctx.refs.append(custom_resize) ctx.tensors_dict[node.output[0]] = new_tensor From e5010ad1ad7006c7734966fe4bfe3adb7c7232bd Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 21 Nov 2023 16:05:21 -0500 Subject: [PATCH 205/232] Update onnx runtime to latest ggml api --- ggml/contrib/onnx.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 6f2b6281..2d845f44 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -4765,19 +4765,20 @@ def from_numpy(self, array: npt.NDArray[Any]) -> ggml.ggml_tensor_p: self.set_tensor_shape(tensor, shape) return tensor - def compute_graph(self, gf: ggml.ggml_cgraph): - gp = ggml.ggml_graph_plan(ctypes.pointer(gf), 1) + def compute_graph(self, gf: ggml.ggml_cgraph_p): + gp = ggml.ggml_graph_plan(gf, 1) work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size > 0 else None if gp.work_size > 0: gp.work = ctypes.cast(work_buffer, ctypes.c_void_p) - ggml.ggml_graph_compute(ctypes.byref(gf), ctypes.byref(gp)) + ggml.ggml_graph_compute(gf, ctypes.byref(gp)) def eval_tensor(self, tensor: ggml.ggml_tensor_p): self.alloc_tensor_cpu(tensor) - gf = ggml.ggml_build_forward(tensor) + gf = ggml.ggml_new_graph(self.ggml_context) + ggml.ggml_build_forward_expand(gf, tensor) # NOTE: Should probably save / restore data pointers here for intermediate tensors alignment = 32 - alloc_size = ggml.utils.alloc_graph_measure(gf, alignment=32) + alloc_size = ggml.utils.alloc_graph_measure(gf.contents, alignment=32) alloc_buffer = (ctypes.c_uint8 * alloc_size)() def copy_tensor(src: ggml.ggml_tensor_p, dst: Optional[ggml.ggml_tensor_p] = None) -> ggml.ggml_tensor: # copy tensor data byte-by-byte using ctypes @@ -4785,21 +4786,21 @@ def copy_tensor(src: ggml.ggml_tensor_p, dst: Optional[ggml.ggml_tensor_p] = Non dst_tensor = ggml.ggml_tensor() if dst is None else dst.contents ctypes.memmove(ctypes.byref(dst_tensor), ctypes.byref(src_tensor), ctypes.sizeof(src_tensor)) return dst_tensor - leafs = [copy_tensor(gf.leafs[i]) for i in range(gf.n_leafs)] - nodes = [copy_tensor(gf.nodes[i]) for i in range(gf.n_nodes)] + leafs = [copy_tensor(gf.contents.leafs[i]) for i in range(gf.contents.n_leafs)] + nodes = [copy_tensor(gf.contents.nodes[i]) for i in range(gf.contents.n_nodes)] # leaf_data = [ggml.ggml_get_data(gf.leafs[i]) for i in range(gf.n_leafs)] # node_data = [ggml.ggml_get_data(gf.nodes[i]) for i in range(gf.n_nodes)] allocr = ggml.ggml_allocr_new( ctypes.cast(alloc_buffer, ctypes.c_void_p), alloc_size, alignment ) - ggml.ggml_allocr_alloc_graph(allocr, ctypes.byref(gf)) + ggml.ggml_allocr_alloc_graph(allocr, gf) self.compute_graph(gf) ggml.ggml_allocr_free(allocr) - for i in range(gf.n_leafs): - copy_tensor(ctypes.pointer(leafs[i]), gf.leafs[i]) + for i in range(gf.contents.n_leafs): + copy_tensor(ctypes.pointer(leafs[i]), gf.contents.leafs[i]) # gf.leafs[i].contents.data = leaf_data[i] - for i in range(gf.n_nodes): - copy_tensor(ctypes.pointer(nodes[i]), gf.nodes[i]) + for i in range(gf.contents.n_nodes): + copy_tensor(ctypes.pointer(nodes[i]), gf.contents.nodes[i]) # gf.nodes[i].contents.data = node_data[i] return tensor @@ -4858,7 +4859,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: input_context = ggml.ggml_init( params=ggml.ggml_init_params( mem_size=2 - * ggml.GGML_MAX_NODES + * ggml.GGML_DEFAULT_GRAPH_SIZE * ggml.ggml_tensor_overhead(), # FIXME: Reduce to n inputs or combine with tensors context no_alloc=True, ) @@ -4924,7 +4925,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: np.copyto(ggml.utils.to_numpy(tensor), np.array(value)) # Define context - max_overhead = 2 * ggml.GGML_MAX_NODES * ggml.ggml_tensor_overhead() + max_overhead = 2 * ggml.GGML_DEFAULT_GRAPH_SIZE * ggml.ggml_tensor_overhead() ggml_context = ggml.ggml_init( params=ggml.ggml_init_params( mem_size=max_overhead, mem_buffer=None, no_alloc=True From bb4c2fa5e7678f523e2f95d9d17b433d0590f06c Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 21 Nov 2023 16:12:24 -0500 Subject: [PATCH 206/232] Remove IPython import --- ggml/contrib/onnx.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 0e9b1034..36702480 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -22,7 +22,6 @@ import ggml import ggml.utils -import IPython GgmlOperator = Callable[["GgmlOnnxExecutionContext", NodeProto], None] From 9224e038ddc8961c15bcc9da03b9735472316af3 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 21 Nov 2023 16:21:16 -0500 Subject: [PATCH 207/232] Attempt fix python3.12 setuptools bug --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 64e2425c..2cd3165c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -26,7 +26,7 @@ jobs: - name: Install dependencies run: | - python3 -m pip install --upgrade pip cmake scikit-build setuptools + python3 -m pip install --upgrade pip python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] - name: Test with pytest From 0c4a0af255c4d56f9b9511131093066ab2a4293c Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 21 Nov 2023 16:23:51 -0500 Subject: [PATCH 208/232] Temporarily disable python3.12 tests --- .github/workflows/test.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2cd3165c..35eadb5a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 @@ -26,7 +26,7 @@ jobs: - name: Install dependencies run: | - python3 -m pip install --upgrade pip + python3 -m pip install --upgrade pip cmake scikit-build setuptools python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] - name: Test with pytest @@ -37,7 +37,7 @@ jobs: runs-on: windows-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 @@ -62,7 +62,7 @@ jobs: runs-on: macos-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 From 5bbf656132e3bf99919f652483097698f76d3da0 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 21 Nov 2023 16:24:46 -0500 Subject: [PATCH 209/232] Install onnx dependencies for metal test --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 35eadb5a..07571cdf 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -122,7 +122,7 @@ jobs: - name: Install dependencies run: | python3 -m pip install --upgrade pip pytest cmake scikit-build setuptools - CMAKE_ARGS="-DGGML_METAL=On" python3 -m pip install --verbose --editable . + CMAKE_ARGS="-DGGML_METAL=On" python3 -m pip install --verbose --editable .[test,onnx,onnx-tests,convert] - name: Test with pytest run: | python3 -m pytest \ No newline at end of file From 89b5a4e236b39bec4817e4894101486849337b93 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 21 Nov 2023 16:32:44 -0500 Subject: [PATCH 210/232] Fix windows tests --- ggml/ggml.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ggml/ggml.py b/ggml/ggml.py index 7f0723ec..f0c98866 100644 --- a/ggml/ggml.py +++ b/ggml/ggml.py @@ -60,16 +60,18 @@ from typing import List, Optional, Sequence, Union from typing_extensions import TypeAlias -c_globals = ctypes.CDLL(None) # POSIX +if sys.platform != "win32": + c_globals = ctypes.CDLL(None) # POSIX -@ctypes.CFUNCTYPE(None, ctypes.c_int) -def sigabrt_handler(sig): - traceback.print_stack() - raise Exception("GGML SIGABRT") + @ctypes.CFUNCTYPE(None, ctypes.c_int) + def sigabrt_handler(sig): + traceback.print_stack() + raise Exception("GGML SIGABRT") -c_globals.signal(signal.SIGABRT, sigabrt_handler) + + c_globals.signal(signal.SIGABRT, sigabrt_handler) # Load the library From c881ba26daf1ed1f14d2bf748f33eff7cef637b9 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 21 Nov 2023 16:34:32 -0800 Subject: [PATCH 211/232] Fix concat, add cos and si --- ggml/contrib/onnx.py | 138 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 8 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 9f0a6a0a..c1a7942e 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -632,11 +632,6 @@ def custom_clip( def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] - if len(node_inputs) < 2: - raise ValueError( - f'Error for node "{node.name}": Operation "Concat" requires at least two inputs. Actual number of inputs: {len(node_inputs)}' - ) - axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 0) shapes = [ctx.get_tensor_shape(tensor) for tensor in node_inputs] @@ -685,7 +680,7 @@ def concat_2(tensor_a, tensor_b): return new_tensor ctx.refs.append(custom_concat) - new_tensor = node_inputs[0] + new_tensor = ctx.tensors_dict[node.output[0]] = node_inputs[0] for tensor in node_inputs[1:]: new_tensor = concat_2(new_tensor, tensor) @@ -832,6 +827,48 @@ def custom_constant_of_shape( ctx.refs.append(custom_constant_of_shape) +@register_ggml_operator("Cos") +def ggml_operator_cos(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Cos" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + a = node_inputs[0] + a_shape = ctx.get_tensor_shape(a) + a_dtype = get_tensor_dtype(a) + + x = np.empty(a_shape, dtype=a_dtype) + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom2_op_t + def custom_cos( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ctx.to_numpy(tensor_in_2) + y = np.cos(a) + + ctx.set_tensor_out(tensor_out, y) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, + x_t, + a, + custom_cos, + 1, + None, + ) + + ctx.refs.append(custom_cos) + + @register_ggml_operator("Conv") def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -1331,6 +1368,48 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ctx.tensors_dict[output_name] = Y +@register_ggml_operator("Erf") +def ggml_operator_erf(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Erf" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + a = node_inputs[0] + a_shape = ctx.get_tensor_shape(a) + a_dtype = get_tensor_dtype(a) + + x = np.empty(a_shape, dtype=a_dtype) + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom2_op_t + def custom_erf( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ctx.to_numpy(tensor_in_2) + y = np.vectorize(math.erf)(a) + + ctx.set_tensor_out(tensor_out, y) + + new_tensor = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, + x_t, + a, + custom_erf, + 1, + None, + ) + + ctx.tensors_dict[node.output[0]] = new_tensor + + @register_ggml_operator("Equal") def ggml_operator_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -4094,6 +4173,48 @@ def custom_sigmoid( ctx.refs.append(custom_sigmoid) +@register_ggml_operator("Sin") +def ggml_operator_sin(ctx: "GgmlOnnxExecutionContext", node: NodeProto): + node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + + if len(node_inputs) != 1: + raise ValueError( + f'Error for node "{node.name}": Operation "Sin" requires exactly one input. Actual number of inputs: {len(node_inputs)}' + ) + + a = node_inputs[0] + a_shape = ctx.get_tensor_shape(a) + a_dtype = get_tensor_dtype(a) + + x = np.empty(a_shape, dtype=a_dtype) + x_t = ctx.from_numpy(x) + + @ggml.ggml_custom2_op_t + def custom_sin( + tensor_out: ggml.ggml_tensor_p, + tensor_in_1: ggml.ggml_tensor_p, + tensor_in_2: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + a = ctx.to_numpy(tensor_in_2) + y = np.sin(a) + + ctx.set_tensor_out(tensor_out, y) + + new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_context, + x_t, + a, + custom_sin, + 1, + None, + ) + + ctx.refs.append(custom_sin) + + @register_ggml_operator("Size") def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.tensors_dict[inp] for inp in node.input] @@ -5259,8 +5380,9 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): Returns: GGML Backend Representation""" - - super(GgmlRuntimeBackend, cls).prepare(model, device, **kwargs) + # This fails with large models. + # https://github.com/onnx/onnx/blob/b60f69412abb5393ab819b936b473f83867f6c87/onnx/backend/base.py#L85 + # super(GgmlRuntimeBackend, cls).prepare(model, device, **kwargs) graph = model.graph weights: Dict[str, ggml.ggml_tensor_p] = {} From 9f4eb57f2bdc137907b92b3e4baeb2f7e94777e4 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 21 Nov 2023 17:21:52 -0800 Subject: [PATCH 212/232] Copy tensor if permuted in Conv operator --- ggml/contrib/onnx.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index c1a7942e..25173420 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -936,7 +936,21 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if len(strides) != 2: raise NotImplementedError("Cannot handle other than 2 strides") + if ggml.ggml_is_permuted(x): + x_dtype = get_tensor_dtype(x) + x_shape = ggml.utils.get_shape(x)Now + x = ggml.ggml_cpy( + ctx.ggml_context, + x, + ggml.ggml_new_tensor( + ctx.ggml_context, + map_to_ggml_type(x_dtype).value, + len(x_shape), + (ctypes.c_int64 * len(x_shape))(*x_shape), + ), + ) + cur = ggml.ggml_conv_2d( ctx.ggml_context, w, From 33e643bb791cfb00fb0b24b39b4efe8402d9110f Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 22 Nov 2023 05:44:46 -0500 Subject: [PATCH 213/232] Fix --- ggml/contrib/onnx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 957eb8fe..289df303 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -937,7 +937,7 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): raise NotImplementedError("Cannot handle other than 2 strides") if ggml.ggml_is_permuted(x): x_dtype = get_tensor_dtype(x) - x_shape = ggml.utils.get_shape(x)Now + x_shape = ggml.utils.get_shape(x) x = ggml.ggml_cpy( ctx.ggml_context, From e22d53997cb4d99d9dd4a4debd2fd3c93877af97 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Thu, 23 Nov 2023 23:44:34 -0500 Subject: [PATCH 214/232] Remove unnused imports --- ggml/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ggml/__init__.py b/ggml/__init__.py index eaac3977..50a035bd 100644 --- a/ggml/__init__.py +++ b/ggml/__init__.py @@ -1,5 +1,3 @@ from .ggml import * -from signal import SIGABRT -import traceback __version__ = "0.0.23" From bd997f065ea21eebff25a65fc0ade68a862d3443 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 29 Nov 2023 04:52:35 -0500 Subject: [PATCH 215/232] Fix re-evaluate bug, allow for max tensors in graph to be set dynamically. --- ggml/contrib/onnx.py | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 289df303..eccb20d6 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5104,6 +5104,7 @@ def __init__( tensors_dict: Dict[str, ggml.ggml_tensor_p], ggml_context: ggml.ggml_context_p, refs: List[Any], + max_tensors: int, ): self.backend = backend self.tensors_dict = tensors_dict @@ -5111,6 +5112,8 @@ def __init__( self.refs = refs self.shapes: Dict[int, Tuple[int, ...]] = {} self.dtypes: Dict[str, npt.DTypeLike] = {} + self.gf = ggml.ggml_new_graph_custom(self.ggml_context, max_tensors, False) + self.n_threads = 8 def set_tensor_shape(self, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...]): key = ctypes.addressof(tensor.contents) @@ -5157,15 +5160,19 @@ def from_numpy(self, array: npt.NDArray[Any]) -> ggml.ggml_tensor_p: return tensor def compute_graph(self, gf: ggml.ggml_cgraph_p): - gp = ggml.ggml_graph_plan(gf, 1) + gp = ggml.ggml_graph_plan(gf, self.n_threads) + gp.n_threads = self.n_threads work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size > 0 else None if gp.work_size > 0: gp.work = ctypes.cast(work_buffer, ctypes.c_void_p) ggml.ggml_graph_compute(gf, ctypes.byref(gp)) + work_buffer = None + gp.work = None def eval_tensor(self, tensor: ggml.ggml_tensor_p): self.alloc_tensor_cpu(tensor) - gf = ggml.ggml_new_graph(self.ggml_context) + gf = self.gf + ggml.ggml_graph_clear(gf) ggml.ggml_build_forward_expand(gf, tensor) # NOTE: Should probably save / restore data pointers here for intermediate tensors alignment = 32 @@ -5186,8 +5193,6 @@ def copy_tensor( return dst_tensor leafs = [copy_tensor(gf.contents.leafs[i]) for i in range(gf.contents.n_leafs)] nodes = [copy_tensor(gf.contents.nodes[i]) for i in range(gf.contents.n_nodes)] - # leaf_data = [ggml.ggml_get_data(gf.leafs[i]) for i in range(gf.n_leafs)] - # node_data = [ggml.ggml_get_data(gf.nodes[i]) for i in range(gf.n_nodes)] allocr = ggml.ggml_allocr_new( ctypes.cast(alloc_buffer, ctypes.c_void_p), alloc_size, alignment ) @@ -5196,11 +5201,12 @@ def copy_tensor( ggml.ggml_allocr_free(allocr) for i in range(gf.contents.n_leafs): copy_tensor(ctypes.pointer(leafs[i]), gf.contents.leafs[i]) - # gf.leafs[i].contents.data = leaf_data[i] for i in range(gf.contents.n_nodes): copy_tensor(ctypes.pointer(nodes[i]), gf.contents.nodes[i]) - # gf.nodes[i].contents.data = node_data[i] - return tensor + tensor_copy = ggml.ggml_dup_tensor(self.ggml_context, tensor) + tensor_copy.contents.data = tensor.contents.data + # copy_tensor(tensor_copy, tensor) + return tensor_copy def set_tensor_out(self, tensor: ggml.ggml_tensor_p, array: npt.NDArray[Any]): np.copyto(self.to_numpy(tensor), array, casting="unsafe") @@ -5252,7 +5258,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: model_graph = self.graph exit_node = None - ggml_tensors = self.weights + ggml_tensors = self.weights.copy() input_context = ggml.ggml_init( params=ggml.ggml_init_params( @@ -5323,20 +5329,21 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: np.copyto(ggml.utils.to_numpy(tensor), np.array(value)) # Define context - max_overhead = 2 * ggml.GGML_DEFAULT_GRAPH_SIZE * ggml.ggml_tensor_overhead() + max_tensors = 8192 + max_overhead = ggml.ggml_tensor_overhead() * max_tensors + ggml.ggml_graph_overhead_custom(max_tensors, False) + mem_buffer = (ctypes.c_uint8 * max_overhead)() ggml_context = ggml.ggml_init( params=ggml.ggml_init_params( - mem_size=max_overhead, mem_buffer=None, no_alloc=True + mem_size=max_overhead, mem_buffer=ctypes.cast(mem_buffer, ctypes.c_void_p), no_alloc=True ) ) refs: List[Any] = [] + refs.append(mem_buffer) - # gf = ggml.ggml_cgraph() - # gf_p = ctypes.pointer(gf) output_names = [output.name for output in model_graph.output] - ctx = GgmlOnnxExecutionContext(self, ggml_tensors, ggml_context, refs) + ctx = GgmlOnnxExecutionContext(self, ggml_tensors, ggml_context, refs, max_tensors) # Build layers for node in model_graph.node: @@ -5351,16 +5358,15 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: for output in node.output: if output in output_names: - # ggml.ggml_build_forward_expand(gf_p, ggml_tensors[output]) ctx.eval_tensor(ggml_tensors[output]) graph_outputs: List[npt.NDArray[Any]] = [] for output in self.outputs: exit_node = ggml_tensors[output.name] # NOTE: 0 dimension in ggml may cause bugs - size = np.prod(ctx.get_tensor_shape(exit_node)) + max_tensors = np.prod(ctx.get_tensor_shape(exit_node)) graph_output: npt.NDArray[Any] = ( - ggml.utils.to_numpy(exit_node) if size > 0 else np.empty((0)) + ggml.utils.to_numpy(exit_node) if max_tensors > 0 else np.empty((0)) ) # TODO: Add checks to convert values back to bool or etc types graph_output = graph_output.astype( ctx.get_tensor_dtype(output.name) From 18a67cf5092a9a3293c272d97aecbdb2bedb219d Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 19 Feb 2024 21:56:38 -0500 Subject: [PATCH 216/232] docs: Add achknowledgements --- docs/contrib/onnx.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/contrib/onnx.md b/docs/contrib/onnx.md index 4cbc71a2..673b2cfe 100644 --- a/docs/contrib/onnx.md +++ b/docs/contrib/onnx.md @@ -141,3 +141,12 @@ This table is generated from [`operator_sets.h`](https://github.com/onnx/onnx/bl | [Unsqueeze](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Unsqueeze) | :white_check_mark: | | | ~~[Upsample](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Upsample)~~ | :x: (Deprecated) | | | [Xor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Xor) | :white_check_mark: | | + +## Acknowledgements + +The GGML ONNX runtime is built on top of the [ONNX](https://onnx.ai/) and [GGML](ggml.ai) + +The core of the runtime was written by Andrei Betlen (@abetlen), David Miller (@dmille), and +Mohammadreza Anvari (@mrezanvari) + +This work would also not be possible without the ggml community, in particular @slaren for their work on the ggml backends and memory allocation api. From 18f53eb5e1acd69ba017d1bc5704bf4a87050a80 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 19 Feb 2024 21:57:51 -0500 Subject: [PATCH 217/232] Temporarily disable setting data in from_numpy --- ggml/utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ggml/utils.py b/ggml/utils.py index 7317c6e3..48aa4364 100644 --- a/ggml/utils.py +++ b/ggml/utils.py @@ -102,11 +102,11 @@ def from_numpy(x: npt.NDArray[Any], ctx: ggml.ggml_context_p) -> ggml.ggml_tenso tensor.contents.nb[: len(shape)] = (ctypes.c_int64 * len(shape))( *tuple(reversed(x.strides)) ) - if ggml.ggml_get_data(tensor) is not None: - if shape == (): - to_numpy(tensor)[()] = x - else: - to_numpy(tensor)[:] = x + # if ggml.ggml_get_data(tensor) is not None: + # if shape == (): + # to_numpy(tensor)[()] = x + # else: + # to_numpy(tensor)[:] = x return tensor From 66aa960a14581c12694e5716bddf21c6021245fa Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 19 Feb 2024 21:58:11 -0500 Subject: [PATCH 218/232] Test multiple ggml graph chaining --- tests/test_ggml.py | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tests/test_ggml.py b/tests/test_ggml.py index 0ae5a693..0cce5752 100644 --- a/tests/test_ggml.py +++ b/tests/test_ggml.py @@ -264,3 +264,99 @@ def build_graph( ggml.ggml_backend_buffer_free(buffer) ggml.ggml_backend_free(backend) ggml.ggml_free(ctx) + + +def test_graph_chaining(): + """Test for chaining together mulitple ggml graphs + """ + backend = ggml.ggml_backend_cpu_init() + assert backend is not None + + no_op_n_calls = 0 + + @ggml.ggml_custom1_op_t + def no_op( + tensor_out: ggml.ggml_tensor_p, + tensor_in: ggml.ggml_tensor_p, + ith: int, + nth: int, + userdata: Optional[ctypes.c_void_p], + ): + data = (ctypes.c_uint8 * ggml.ggml_nbytes(tensor_in))() + ggml.ggml_backend_tensor_get( + tensor_in, + ctypes.cast(data, ctypes.c_void_p), + 0, + ggml.ggml_nbytes(tensor_in), + ) + tensor_out_size = ggml.ggml_nbytes(tensor_out) + ggml.ggml_backend_tensor_set( + tensor_out, + ctypes.cast(data, ctypes.c_void_p), + 0, + tensor_out_size, + ) + nonlocal no_op_n_calls + no_op_n_calls += 1 + + params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None, no_alloc=True) + ctx = ggml.ggml_init(params=params) + assert ctx is not None + assert ggml.ggml_used_mem(ctx) == 0 + x = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F32, 1) + a = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F32, 1) + b = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F32, 1) + x2 = ggml.ggml_mul(ctx, x, x) + x2 = ggml.ggml_map_custom1(ctx, x2, no_op, 1, None) + f = ggml.ggml_add(ctx, ggml.ggml_mul(ctx, a, x2), b) + + buffer = ggml.ggml_backend_alloc_ctx_tensors(ctx, backend) + + gf = ggml.ggml_new_graph(ctx) + ggml.ggml_build_forward_expand(gf, f) + + ggml.ggml_set_f32(x, 2.0) + ggml.ggml_set_f32(a, 3.0) + ggml.ggml_set_f32(b, 4.0) + + ggml.ggml_graph_compute_with_ctx(ctx, gf, 1) + output = ggml.ggml_get_f32_1d(f, 0) + assert output == 16.0 + assert no_op_n_calls == 1 + + params_eval = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None, no_alloc=True) + ctx_eval = ggml.ggml_init(params=params_eval) + assert ctx_eval is not None + + f_copy = ggml.ggml_dup_tensor(ctx_eval, f) + f_buffer = ggml.ggml_backend_alloc_buffer(backend, ggml.ggml_nbytes(f_copy)) + tallocr = ggml.ggml_tallocr_new(f_buffer) + ggml.ggml_tallocr_alloc(tallocr, f_copy) + ggml.ggml_tallocr_free(tallocr) + + ggml.ggml_backend_tensor_copy(f, f_copy) + + params2 = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None, no_alloc=True) + + ctx2 = ggml.ggml_init(params=params2) + assert ctx2 is not None + + g = ggml.ggml_add(ctx2, f_copy, a) + + buffer2 = ggml.ggml_backend_alloc_ctx_tensors(ctx2, backend) + + gf2 = ggml.ggml_new_graph(ctx2) + ggml.ggml_build_forward_expand(gf2, g) + + ggml.ggml_graph_compute_with_ctx(ctx2, gf2, 1) + + output = ggml.ggml_get_f32_1d(g, 0) + + assert output == 19.0 + assert no_op_n_calls == 1 + + ggml.ggml_free(ctx) + ggml.ggml_free(ctx2) + ggml.ggml_backend_buffer_free(buffer) + ggml.ggml_backend_buffer_free(buffer2) + ggml.ggml_backend_free(backend) From 13686c41ebc4ebdbd3d779e570a13014831b4399 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 19 Feb 2024 21:58:30 -0500 Subject: [PATCH 219/232] Update ggml_gallocr_new signature --- ggml/ggml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ggml/ggml.py b/ggml/ggml.py index 6d5b75e6..32ca106f 100644 --- a/ggml/ggml.py +++ b/ggml/ggml.py @@ -8790,7 +8790,7 @@ def ggml_tallocr_alloc(talloc: ggml_tallocr, tensor: ggml_tensor_p) -> None: # GGML_API ggml_gallocr_t ggml_gallocr_new(ggml_backend_buffer_type_t buft); -def ggml_gallocr_new(buft: ggml_backend_buffer_type_t) -> ggml_gallocr: +def ggml_gallocr_new(buft: ggml_backend_buffer_type_t) -> Optional[ggml_gallocr]: return lib.ggml_gallocr_new(buft) From c27fd6ed274e0be2777dcb729d3064ca54761e83 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 19 Feb 2024 21:58:44 -0500 Subject: [PATCH 220/232] Add debugging docs --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index dd977ed1..ff049fac 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,30 @@ If you are having trouble installing `ggml-python` or activating specific featur [options] pip install ggml-python --verbose --no-cache-dir --force-reinstall --upgrade ``` +# Debugging + +## Error: `SIGSEGV` or `Aborted (core dumped)` + +Godspeed! You are about to enter the world of debugging native code. +If you are seeing a `SIGSEGV` or `Aborted (core dumped)` error something has gone horribly wrong. +A good first step is to try to reproduce the error with a debug build of `ggml-python` and `ggml` and then use a debugger like `gdb` to step through the code and find the issue. + + +```bash +$ git clone https://github.com/abetlen/ggml-python.git +$ cd ggml-python +$ make build.debug # this preserves debug symbols +$ gdb --args python3 your_script.py +``` + +From there you can use `run` to start the script and `bt` to get a backtrace of native code and `py-bt` to get a backtrace of python code. + +Additionally, you should use python's built in `breakpoint()` function to set breakpoints in your python code and step through the code. + +# API Stability + +This project is currently in alpha and the API is subject to change. + # License This project is licensed under the terms of the MIT license. From 9cf3fc7d64e3172d043536486968ff1bf539ada6 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 19 Feb 2024 21:59:09 -0500 Subject: [PATCH 221/232] Update onnx to new ggml alloc apis --- ggml/contrib/onnx.py | 1232 +++++++++++++++++++++--------------------- 1 file changed, 602 insertions(+), 630 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index eccb20d6..d4d2bc02 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -2,8 +2,9 @@ This module implements a GGML backend for ONNX models and operators. """ -import ctypes import math +import ctypes +import weakref from typing import Any, Callable, Dict, List, Optional, Tuple, Sequence from typing_extensions import TypeGuard @@ -23,22 +24,29 @@ import ggml import ggml.utils -GgmlOperator = Callable[["GgmlOnnxExecutionContext", NodeProto], None] - -ggml_operators: Dict[str, GgmlOperator] = {} onnx_dtype_map: Dict[int, npt.DTypeLike] = { elem_type: np_dtype for elem_type, np_dtype in onnx.mapping.TENSOR_TYPE_TO_NP_TYPE.items() # type: ignore } - -def register_ggml_operator(operator: str): - def inner(func: GgmlOperator): - ggml_operators[operator] = func - return func - - return inner - +def set_ggml_tensor_data_from_numpy( + tensor: ggml.ggml_tensor_p, array: npt.NDArray[Any] +): + ggml.ggml_backend_tensor_set( + tensor, + array.ctypes.data_as(ctypes.c_void_p), + 0, + ggml.ggml_nbytes(tensor), + ) + +def get_ggml_tensor_data_as_numpy( + tensor: ggml.ggml_tensor_p +) -> npt.NDArray[Any]: + np_dtype = get_tensor_dtype(tensor) + shape = ggml.utils.get_shape(tensor) + array = np.empty(shape, dtype=np_dtype) + ggml.ggml_backend_tensor_get(tensor, array.ctypes.data_as(ctypes.c_void_p), 0, ggml.ggml_nbytes(tensor)) + return array def map_to_ggml_type(dtype: npt.DTypeLike): np_data_type_limit = np.dtype(str(dtype).replace("64", "32")) @@ -64,48 +72,21 @@ def get_tensor_dtype(tensor: ggml.ggml_tensor_p) -> npt.DTypeLike: return np.dtype(ctypes_type) -def can_quantize( - np_array: npt.NDArray[Any], - name: str, - graph_def: GraphProto, -): - return False - - allowed_op_types = set(["MatMul"]) - - is_weight = is_2d = is_f32 = is_op_supported = False - - is_weight = name in [initializer.name for initializer in graph_def.initializer] - is_2d = np_array.ndim == 2 - is_f32 = np_array.dtype == np.float32 - is_op_supported = any( - [ - node - for node in graph_def.node - if node.op_type in allowed_op_types - and name in node.input - and node.input[0] == name - ] - ) - - return all([is_weight, is_2d, is_f32, is_op_supported]) - - def broadcast_tensor( - ctx: "GgmlOnnxExecutionContext", tensor: ggml.ggml_tensor_p, shape: Tuple + ctx: "GgmlOnnxExecutionContext", tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...] ): ggml_type = ggml.utils.GGML_TYPE(tensor.contents.type) if ggml_type == ggml.utils.GGML_TYPE.F32: new_tensor = ggml.ggml_new_tensor( - ctx.ggml_context, + ctx.ggml_eval_context, ggml_type.value, len(shape), (ctypes.c_int64 * len(shape))(*shape), ) new_tensor = ggml.ggml_repeat( - ctx.ggml_context, + ctx.ggml_eval_context, tensor, new_tensor, ) @@ -123,12 +104,12 @@ def custom_broadcast_to( a = ctx.to_numpy(tensor_in_2) x = np.broadcast_to(a, shape) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) x = np.empty(shape, dtype=get_tensor_dtype(tensor)) x_t = ctx.from_numpy(x) new_tensor = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + ctx.ggml_eval_context, x_t, tensor, custom_broadcast_to, @@ -165,9 +146,23 @@ def broadcast_shapes( # ------ Operators ------ +GgmlOperator = Callable[["GgmlOnnxExecutionContext", NodeProto], None] + + +ggml_operators: Dict[str, GgmlOperator] = {} + + +def register_ggml_operator(operator: str): + def inner(func: GgmlOperator): + ggml_operators[operator] = func + return func + + return inner + + @register_ggml_operator("Abs") def ggml_operator_abs(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -178,15 +173,15 @@ def ggml_operator_abs(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] abs_result = ggml.ggml_abs( - ctx.ggml_context, + ctx.ggml_eval_context, a, ) - ctx.tensors_dict[output_name] = abs_result + ctx.ggml_tensors_dict[output_name] = abs_result @register_ggml_operator("Add") def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -215,25 +210,25 @@ def custom_add( b = ctx.to_numpy(tensor_in_3) x = np.add(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) add_result = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, x_t, a, b, custom_add, 1, None + ctx.ggml_eval_context, x_t, a, b, custom_add, 1, None ) ctx.refs.append(custom_add) else: add_result = ggml.ggml_add( - ctx.ggml_context, + ctx.ggml_eval_context, a, b, ) - ctx.tensors_dict[output_name] = add_result + ctx.ggml_tensors_dict[output_name] = add_result @register_ggml_operator("And") def ggml_operator_and(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -260,15 +255,15 @@ def custom_and( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) x = np.logical_and(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], node_inputs[1], @@ -291,7 +286,7 @@ class ArgOpsUserData(ctypes.Structure): @register_ggml_operator("ArgMax") def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -340,7 +335,7 @@ def custom_arg_max( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) + x = ctx.to_numpy(tensor_in_2) userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ArgOpsUserData)) userdata_data = userdata_data_ptr.contents @@ -361,10 +356,10 @@ def custom_arg_max( y = y.astype(np.int32) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, data, custom_arg_max, @@ -379,7 +374,7 @@ def custom_arg_max( @register_ggml_operator("ArgMin") def ggml_operator_arg_min(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -426,7 +421,7 @@ def custom_arg_min( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) + x = ctx.to_numpy(tensor_in_2) userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ArgOpsUserData)) userdata_data = userdata_data_ptr.contents @@ -447,10 +442,10 @@ def custom_arg_min( y = y.astype(np.int32) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, data, custom_arg_min, @@ -465,7 +460,7 @@ def custom_arg_min( @register_ggml_operator("Cast") def ggml_operator_cast(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -492,14 +487,14 @@ def custom_cast( userdata: Optional[ctypes.c_void_p], ): dtype = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) np_data_type = tensor_dtype_to_np_dtype(dtype) np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) - ctx.set_tensor_out(tensor_out, tensor.astype(np_data_type_limit)) + ctx.set_tensor_data(tensor_out, tensor.astype(np_data_type_limit)) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, a, custom_cast, @@ -514,7 +509,7 @@ def custom_cast( @register_ggml_operator("CastLike") def ggml_operator_castlike(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -541,14 +536,14 @@ def custom_cast( userdata: Optional[ctypes.c_void_p], ): dtype = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) np_data_type = tensor_dtype_to_np_dtype(dtype) np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) - ctx.set_tensor_out(tensor_out, tensor.astype(np_data_type_limit)) + ctx.set_tensor_data(tensor_out, tensor.astype(np_data_type_limit)) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, a, custom_cast, @@ -563,7 +558,7 @@ def custom_cast( @register_ggml_operator("Ceil") def ggml_operator_ceil(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -585,10 +580,10 @@ def custom_ceil( ): tensor = ctx.to_numpy(tensor_in_1) x = np.ceil(tensor) - ctx.set_tensor_out(tensor_out, np.array(x)) + ctx.set_tensor_data(tensor_out, np.array(x)) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x_t, custom_ceil, 1, @@ -600,7 +595,7 @@ def custom_ceil( @register_ggml_operator("Clip") def ggml_operator_clip(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] x_t, a_min, a_max = node_inputs shape = ctx.get_tensor_shape(x_t) name = node.output[0] @@ -619,17 +614,17 @@ def custom_clip( a_max = ctx.to_numpy(tensor_in_3) a = ctx.to_numpy(tensor_in_1) x = np.clip(a, a_min, a_max) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, x_t, a_min, a_max, custom_clip, 1, None + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, a_min, a_max, custom_clip, 1, None ) ctx.refs.append(custom_clip) @register_ggml_operator("Concat") def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 0) shapes = [ctx.get_tensor_shape(tensor) for tensor in node_inputs] @@ -655,7 +650,7 @@ def custom_concat( a = ctx.to_numpy(tensor_in_2) b = ctx.to_numpy(tensor_in_3) x = np.concatenate([a, b], axis=axis) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) def concat_2(tensor_a, tensor_b): shape_a = ctx.get_tensor_shape(tensor_a) @@ -667,8 +662,8 @@ def concat_2(tensor_a, tensor_b): x = np.empty(output_shape, dtype=get_tensor_dtype(tensor_a)) x_t = ctx.from_numpy(x) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, tensor_a, tensor_b, @@ -679,7 +674,7 @@ def concat_2(tensor_a, tensor_b): return new_tensor ctx.refs.append(custom_concat) - new_tensor = ctx.tensors_dict[node.output[0]] = node_inputs[0] + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = node_inputs[0] for tensor in node_inputs[1:]: new_tensor = concat_2(new_tensor, tensor) @@ -741,12 +736,12 @@ def custom_constant( userdata: Optional[ctypes.c_void_p], ): shape = get_tensor_shape(tensor_in_1) - constant_data = ggml.utils.to_numpy(tensor_in_2) + constant_data = ctx.to_numpy(tensor_in_2) new_tensor = constant_data.reshape(shape) - ctx.set_tensor_out(tensor_out, new_tensor) + ctx.set_tensor_data(tensor_out, new_tensor) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, data_tensor, custom_constant, @@ -760,7 +755,7 @@ def custom_constant( @register_ggml_operator("ConstantOfShape") def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -794,8 +789,8 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP ) data_tensor = ctx.from_numpy(data_value.astype(np_data_type_limit)) - ctx.eval_tensor(node_inputs[0]) - shape = ctx.to_numpy(node_inputs[0]) + node_inputs_0 = ctx.eval_tensor(node_inputs[0]) + shape = ctx.to_numpy(node_inputs_0) x = np.empty(shape, dtype=np_data_type_limit) x_t = ctx.from_numpy(x) @@ -809,13 +804,13 @@ def custom_constant_of_shape( userdata: Optional[ctypes.c_void_p], ): shape = get_tensor_shape(tensor_out) - value = ggml.utils.to_numpy(tensor_in_2) + value = ctx.to_numpy(tensor_in_2) new_tenor = np.full(tuple(shape), value) - ctx.set_tensor_out(tensor_out, new_tenor) + ctx.set_tensor_data(tensor_out, new_tenor) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, data_tensor, custom_constant_of_shape, @@ -828,7 +823,7 @@ def custom_constant_of_shape( @register_ggml_operator("Cos") def ggml_operator_cos(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -854,10 +849,10 @@ def custom_cos( a = ctx.to_numpy(tensor_in_2) y = np.cos(a) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, a, custom_cos, @@ -870,7 +865,7 @@ def custom_cos( @register_ggml_operator("Conv") def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) < 2: raise ValueError( @@ -940,10 +935,10 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_shape = ggml.utils.get_shape(x) x = ggml.ggml_cpy( - ctx.ggml_context, + ctx.ggml_eval_context, x, ggml.ggml_new_tensor( - ctx.ggml_context, + ctx.ggml_eval_context, map_to_ggml_type(x_dtype).value, len(x_shape), (ctypes.c_int64 * len(x_shape))(*x_shape), @@ -951,7 +946,7 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) cur = ggml.ggml_conv_2d( - ctx.ggml_context, + ctx.ggml_eval_context, w, x, strides[0], @@ -962,21 +957,21 @@ def ggml_operator_conv(ctx: "GgmlOnnxExecutionContext", node: NodeProto): dilations[1], ) result = ggml.ggml_add( - ctx.ggml_context, + ctx.ggml_eval_context, cur, ggml.ggml_repeat( - ctx.ggml_context, - ggml.ggml_reshape_3d(ctx.ggml_context, bias, 1, 1, bias.contents.ne[0]), + ctx.ggml_eval_context, + ggml.ggml_reshape_3d(ctx.ggml_eval_context, bias, 1, 1, bias.contents.ne[0]), cur, ), ) - ctx.tensors_dict[node.output[0]] = result + ctx.ggml_tensors_dict[node.output[0]] = result @register_ggml_operator("ConvTranspose") def ggml_operator_convtranspose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) < 2: raise ValueError( @@ -1088,7 +1083,7 @@ class DepthToSpaceUserData(ctypes.Structure): @register_ggml_operator("DepthToSpace") def ggml_operator_depth_to_space(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1128,7 +1123,7 @@ def custom_depth_to_space( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) + x = ctx.to_numpy(tensor_in_2) userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DepthToSpaceUserData)) userdata_data = userdata_data_ptr.contents @@ -1154,10 +1149,10 @@ def custom_depth_to_space( transposed = np.transpose(reshaped, axes=transposed_axes) y = transposed.reshape(N, new_C, new_H, new_W) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, x, custom_depth_to_space, @@ -1172,7 +1167,7 @@ def custom_depth_to_space( @register_ggml_operator("Div") def ggml_operator_div(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -1187,7 +1182,7 @@ def ggml_operator_div(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a_dtype = get_tensor_dtype(a) if a_dtype == np.float32: div_result = ggml.ggml_div( - ctx.ggml_context, + ctx.ggml_eval_context, a, b, ) @@ -1209,14 +1204,14 @@ def custom_div( b = ctx.to_numpy(tensor_in_3) x = np.divide(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) div_result = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, x_t, a, b, custom_div, 1, None + ctx.ggml_eval_context, x_t, a, b, custom_div, 1, None ) ctx.refs.append(custom_div) ctx.set_tensor_shape(div_result, ctx.get_tensor_shape(a)) - ctx.tensors_dict[output_name] = div_result + ctx.ggml_tensors_dict[output_name] = div_result return div_result @@ -1229,7 +1224,7 @@ class DropoutUserData(ctypes.Structure): @register_ggml_operator("Dropout") def ggml_operator_dropout(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -1270,8 +1265,8 @@ def custom_dropout_mask( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_1) - ratio = ggml.utils.to_numpy(tensor_in_2) + x = ctx.to_numpy(tensor_in_1) + ratio = ctx.to_numpy(tensor_in_2) userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DropoutUserData)) userdata_data = userdata_data_ptr.contents @@ -1286,10 +1281,10 @@ def custom_dropout_mask( np.random.seed(seed) mask = np.random.uniform(0, 1.0, x.shape) >= ratio - ctx.set_tensor_out(tensor_out, mask) + ctx.set_tensor_data(tensor_out, mask) mask = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + ctx.ggml_eval_context, data, ratio, custom_dropout_mask, @@ -1309,9 +1304,9 @@ def custom_dropout_output( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_1) - ratio = ggml.utils.to_numpy(tensor_in_2) - mask = ggml.utils.to_numpy(tensor_in_3) + x = ctx.to_numpy(tensor_in_1) + ratio = ctx.to_numpy(tensor_in_2) + mask = ctx.to_numpy(tensor_in_3) userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(DropoutUserData)) userdata_data = userdata_data_ptr.contents @@ -1325,10 +1320,10 @@ def custom_dropout_output( scale = 1 / (1 - ratio) y = mask * x * scale - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) output = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + ctx.ggml_eval_context, data, ratio, mask, @@ -1343,17 +1338,17 @@ def custom_dropout_output( if len(node.output) == 2: ctx.set_tensor_dtype(node.output[1], np.dtype(np.bool_)) - ctx.tensors_dict[node.output[0]] = output - ctx.tensors_dict[node.output[1]] = mask + ctx.ggml_tensors_dict[node.output[0]] = output + ctx.ggml_tensors_dict[node.output[1]] = mask return output, mask - ctx.tensors_dict[node.output[0]] = output + ctx.ggml_tensors_dict[node.output[0]] = output @register_ggml_operator("Elu") def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1365,7 +1360,7 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): alpha = next((attr.f for attr in node.attribute if attr.name == "alpha"), 1.0) Y = ggml.ggml_elu( - ctx.ggml_context, + ctx.ggml_eval_context, x, ) @@ -1378,12 +1373,12 @@ def ggml_operator_elu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): Y = ctx.from_numpy(Y_alpha) - ctx.tensors_dict[output_name] = Y + ctx.ggml_tensors_dict[output_name] = Y @register_ggml_operator("Erf") def ggml_operator_erf(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1409,10 +1404,10 @@ def custom_erf( a = ctx.to_numpy(tensor_in_2) y = np.vectorize(math.erf)(a) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) new_tensor = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + ctx.ggml_eval_context, x_t, a, custom_erf, @@ -1420,12 +1415,12 @@ def custom_erf( None, ) - ctx.tensors_dict[node.output[0]] = new_tensor + ctx.ggml_tensors_dict[node.output[0]] = new_tensor @register_ggml_operator("Equal") def ggml_operator_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -1452,15 +1447,15 @@ def custom_equal( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) x = np.equal(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], node_inputs[1], @@ -1476,7 +1471,7 @@ def custom_equal( @register_ggml_operator("Exp") def ggml_operator_exp(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -1496,12 +1491,12 @@ def custom_exp( nth: int, userdata: Optional[ctypes.c_void_p], ): - tensor = ggml.utils.to_numpy(tensor_in_1) + tensor = ctx.to_numpy(tensor_in_1) x = np.exp(tensor) - ctx.set_tensor_out(tensor_out, np.array(x)) + ctx.set_tensor_data(tensor_out, np.array(x)) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x_t, custom_exp, 1, @@ -1513,7 +1508,7 @@ def custom_exp( @register_ggml_operator("Expand") def ggml_operator_expand(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] a_shape = get_tensor_shape(node_inputs[0]) target_shape = ctx.to_numpy(ctx.eval_tensor(node_inputs[1])) @@ -1534,10 +1529,10 @@ def custom_expand( a = ctx.to_numpy(tensor_in_2) expanded = a * np.ones(new_shape, dtype=get_tensor_dtype(tensor_in_2)) - ctx.set_tensor_out(tensor_out, expanded) + ctx.set_tensor_data(tensor_out, expanded) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], custom_expand, @@ -1549,7 +1544,7 @@ def custom_expand( @register_ggml_operator("Flatten") def ggml_operator_flatten(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1582,7 +1577,7 @@ def custom_flatten( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) + x = ctx.to_numpy(tensor_in_2) axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value if axis < 0: @@ -1591,10 +1586,10 @@ def custom_flatten( y = x.reshape(new_shape) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, x, custom_flatten, @@ -1608,7 +1603,7 @@ def custom_flatten( @register_ggml_operator("Floor") def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1625,13 +1620,13 @@ def custom_floor( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_1) + x = ctx.to_numpy(tensor_in_1) y = np.floor(x) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x, custom_floor, 1, @@ -1643,7 +1638,7 @@ def custom_floor( @register_ggml_operator("Gather") def ggml_operator_gather(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -1675,16 +1670,16 @@ def custom_gather( nth: int, userdata: Optional[ctypes.c_void_p], ): - input_array = ggml.utils.to_numpy(tensor_in_2) - index_array = ggml.utils.to_numpy(tensor_in_3) + input_array = ctx.to_numpy(tensor_in_2) + index_array = ctx.to_numpy(tensor_in_3) axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value new_array = np.take(input_array, index_array, axis=axis) - ctx.set_tensor_out(tensor_out, new_array) + ctx.set_tensor_data(tensor_out, new_array) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], node_inputs[1], @@ -1703,7 +1698,7 @@ def custom_gather( @register_ggml_operator("Gemm") def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) < 2: raise ValueError( @@ -1735,15 +1730,15 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if transA: a_permute = ggml.ggml_transpose( - ctx.ggml_context, + ctx.ggml_eval_context, a, ) a_shape = ggml.utils.get_shape(a_permute) a_transposed = ggml.ggml_cpy( - ctx.ggml_context, + ctx.ggml_eval_context, a_permute, ggml.ggml_new_tensor( - ctx.ggml_context, + ctx.ggml_eval_context, map_to_ggml_type(a_dtype).value, len(a_shape), (ctypes.c_int64 * len(a_shape))(*a_shape), @@ -1752,15 +1747,15 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if not transB: b_permute = ggml.ggml_transpose( - ctx.ggml_context, + ctx.ggml_eval_context, b, ) b_shape = ggml.utils.get_shape(b_permute) b_transposed = ggml.ggml_cpy( - ctx.ggml_context, + ctx.ggml_eval_context, b_permute, ggml.ggml_new_tensor( - ctx.ggml_context, + ctx.ggml_eval_context, map_to_ggml_type(b_dtype).value, len(b_shape), (ctypes.c_int64 * len(b_shape))(*b_shape), @@ -1771,7 +1766,7 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): # ref: https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/gemm.py mul_mat_result = ggml.ggml_mul_mat( - ctx.ggml_context, + ctx.ggml_eval_context, b_transposed, a_transposed, ) @@ -1784,7 +1779,7 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ), ) - mul_mat_result = ggml.ggml_mul_inplace(ctx.ggml_context, mul_mat_result, alpha_t) + mul_mat_result = ggml.ggml_mul_inplace(ctx.ggml_eval_context, mul_mat_result, alpha_t) if c is None: c = ctx.from_numpy( @@ -1806,17 +1801,17 @@ def ggml_operator_gemm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) mul_mat_result = ggml.ggml_add_inplace( - ctx.ggml_context, + ctx.ggml_eval_context, mul_mat_result, - ggml.ggml_mul_inplace(ctx.ggml_context, c, beta_t), + ggml.ggml_mul_inplace(ctx.ggml_eval_context, c, beta_t), ) - ctx.tensors_dict[node.output[0]] = mul_mat_result + ctx.ggml_tensors_dict[node.output[0]] = mul_mat_result @register_ggml_operator("Greater") def ggml_operator_greater(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -1843,15 +1838,15 @@ def custom_greater( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) x = np.greater(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], node_inputs[1], @@ -1874,7 +1869,7 @@ class HardSigmoidUserData(ctypes.Structure): @register_ggml_operator("HardSigmoid") def ggml_operator_hardsigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1898,16 +1893,16 @@ def custom_hard_sigmoid( ): userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(HardSigmoidUserData)) userdata_data = userdata_data_ptr.contents - x = ggml.utils.to_numpy(tensor_in_1) + x = ctx.to_numpy(tensor_in_1) alpha = userdata_data.alpha beta = userdata_data.beta y = np.clip((x * alpha) + beta, 0, 1) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x, custom_hard_sigmoid, 1, @@ -1921,7 +1916,7 @@ def custom_hard_sigmoid( @register_ggml_operator("Hardmax") def ggml_operator_hardmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1941,16 +1936,16 @@ def custom_hardmax( userdata: Optional[ctypes.c_void_p], ): axis = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value - x = ggml.utils.to_numpy(tensor_in_1) + x = ctx.to_numpy(tensor_in_1) max_indices = np.argmax(x, axis=axis, keepdims=True) y = np.zeros_like(x) np.put_along_axis(y, max_indices, 1, axis=axis) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x, custom_hardmax, 1, @@ -1964,7 +1959,7 @@ def custom_hardmax( @register_ggml_operator("Identity") def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -1974,15 +1969,15 @@ def ggml_operator_floor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = node_inputs[0] output_name = node.output[0] y = ggml.ggml_dup( - ctx.ggml_context, x + ctx.ggml_eval_context, x ) # NOTE: This will freeze the tensor in time, may not be expected. - ctx.tensors_dict[output_name] = y + ctx.ggml_tensors_dict[output_name] = y @register_ggml_operator("InstanceNormalization") def ggml_operator_instancenorm(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 3: raise ValueError( @@ -2002,9 +1997,9 @@ def custom_instancenorm( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_1) - s = ggml.utils.to_numpy(tensor_in_2) - bias = ggml.utils.to_numpy(tensor_in_3) + x = ctx.to_numpy(tensor_in_1) + s = ctx.to_numpy(tensor_in_2) + bias = ctx.to_numpy(tensor_in_3) epsilon = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_double)).contents.value dims_x = len(x.shape) @@ -2017,10 +2012,10 @@ def custom_instancenorm( bias = bias.reshape(-1, *dim_ones) y = s * (x - mean) / np.sqrt(var + epsilon) + bias - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, input_tensor, scale, B, @@ -2043,7 +2038,7 @@ class LRNUserData(ctypes.Structure): @register_ggml_operator("LRN") def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2080,7 +2075,7 @@ def custom_leaky_lrn( bias = userdata_data.bias size = userdata_data.size - x = ggml.utils.to_numpy(tensor_in_1) + x = ctx.to_numpy(tensor_in_1) square_sum = np.zeros(x.shape).astype(x.dtype) for n, c, h, w in np.ndindex(x.shape): @@ -2097,10 +2092,10 @@ def custom_leaky_lrn( ) y = x / ((bias + (alpha / size) * square_sum) ** beta) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x, custom_leaky_lrn, 1, @@ -2113,7 +2108,7 @@ def custom_leaky_lrn( @register_ggml_operator("LeakyRelu") def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2134,13 +2129,13 @@ def custom_leaky_relu( userdata: Optional[ctypes.c_void_p], ): alpha = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_double)).contents.value - x = ggml.utils.to_numpy(tensor_in_1) + x = ctx.to_numpy(tensor_in_1) y = np.clip(x, 0, np.inf) + np.clip(x, -np.inf, 0) * alpha - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x, custom_leaky_relu, 1, @@ -2153,7 +2148,7 @@ def custom_leaky_relu( @register_ggml_operator("GreaterOrEqual") def ggml_operator_greater_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2180,15 +2175,15 @@ def custom_greater_equal( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) x = np.greater_equal(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], node_inputs[1], @@ -2204,7 +2199,7 @@ def custom_greater_equal( @register_ggml_operator("Less") def ggml_operator_less(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2231,15 +2226,15 @@ def custom_less( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) x = np.less(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], node_inputs[1], @@ -2255,7 +2250,7 @@ def custom_less( @register_ggml_operator("LessOrEqual") def ggml_operator_less_or_equal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2282,15 +2277,15 @@ def custom_less_equal( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) x = np.less_equal(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], node_inputs[1], @@ -2306,7 +2301,7 @@ def custom_less_equal( @register_ggml_operator("Log") def ggml_operator_log(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2317,15 +2312,15 @@ def ggml_operator_log(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] log_result = ggml.ggml_log( - ctx.ggml_context, + ctx.ggml_eval_context, a, ) - ctx.tensors_dict[output_name] = log_result + ctx.ggml_tensors_dict[output_name] = log_result @register_ggml_operator("LogSoftmax") def ggml_operator_log_soft_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2334,17 +2329,17 @@ def ggml_operator_log_soft_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto) output_name = node.output[0] a = node_inputs[0] - soft_max_result = ggml.ggml_soft_max(ctx.ggml_context, a) + soft_max_result = ggml.ggml_soft_max(ctx.ggml_eval_context, a) log_result = ggml.ggml_log( - ctx.ggml_context, + ctx.ggml_eval_context, soft_max_result, ) - ctx.tensors_dict[output_name] = log_result + ctx.ggml_tensors_dict[output_name] = log_result @register_ggml_operator("MatMul") def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2366,10 +2361,10 @@ def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a_dtype = get_tensor_dtype(a) a_shape = ggml.utils.get_shape(a) a = ggml.ggml_cpy( - ctx.ggml_context, + ctx.ggml_eval_context, a, ggml.ggml_new_tensor( - ctx.ggml_context, + ctx.ggml_eval_context, map_to_ggml_type(a_dtype).value, len(a_shape), (ctypes.c_int64 * len(a_shape))(*a_shape), @@ -2379,34 +2374,34 @@ def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): b_dtype = get_tensor_dtype(b) b_permute = ggml.ggml_transpose( - ctx.ggml_context, + ctx.ggml_eval_context, b, ) b_shape = ggml.utils.get_shape(b_permute) b_transposed = ggml.ggml_cpy( - ctx.ggml_context, + ctx.ggml_eval_context, b_permute, ggml.ggml_new_tensor( - ctx.ggml_context, + ctx.ggml_eval_context, map_to_ggml_type(b_dtype).value, len(b_shape), (ctypes.c_int64 * len(b_shape))(*b_shape), ), ) mul_mat_result = ggml.ggml_mul_mat( - ctx.ggml_context, + ctx.ggml_eval_context, b_transposed, a, ) - ctx.tensors_dict[output_name] = mul_mat_result + ctx.ggml_tensors_dict[output_name] = mul_mat_result @register_ggml_operator("Max") def ggml_operator_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -2425,7 +2420,7 @@ def ggml_operator_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = tuple(reversed(output_shape)) x_t = ggml.ggml_new_tensor( - ctx.ggml_context, + ctx.ggml_eval_context, ggml_type.value, len(output_shape), (ctypes.c_int64 * len(output_shape))(*output_shape), @@ -2439,12 +2434,12 @@ def custom_max( nth: int, userdata: Optional[ctypes.c_void_p], ): - tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + tensors = [ctx.to_numpy(node_input) for node_input in node_inputs] x = np.max(tensors, axis=0) - ctx.set_tensor_out(tensor_out, np.array(x)) + ctx.set_tensor_data(tensor_out, np.array(x)) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x_t, custom_max, 1, @@ -2456,7 +2451,7 @@ def custom_max( @register_ggml_operator("Mean") def ggml_operator_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -2467,23 +2462,23 @@ def ggml_operator_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): sums = node_inputs[0] for tensor in node_inputs[1:]: - sums = ggml.ggml_add(ctx.ggml_context, sums, tensor) + sums = ggml.ggml_add(ctx.ggml_eval_context, sums, tensor) coef_np = np.full(get_tensor_shape(sums), len(node_inputs), dtype=np.float32) coef_t = ctx.from_numpy(coef_np) mean = ggml.ggml_div( - ctx.ggml_context, + ctx.ggml_eval_context, sums, coef_t, ) - ctx.tensors_dict[output_name] = mean + ctx.ggml_tensors_dict[output_name] = mean @register_ggml_operator("Min") def ggml_operator_min(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -2502,7 +2497,7 @@ def ggml_operator_min(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_shape = tuple(reversed(output_shape)) x_t = ggml.ggml_new_tensor( - ctx.ggml_context, + ctx.ggml_eval_context, ggml_type.value, len(output_shape), (ctypes.c_int64 * len(output_shape))(*output_shape), @@ -2516,12 +2511,12 @@ def custom_min( nth: int, userdata: Optional[ctypes.c_void_p], ): - tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + tensors = [ctx.to_numpy(node_input) for node_input in node_inputs] x = np.min(tensors, axis=0) - ctx.set_tensor_out(tensor_out, np.array(x)) + ctx.set_tensor_data(tensor_out, np.array(x)) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x_t, custom_min, 1, @@ -2533,7 +2528,7 @@ def custom_min( @register_ggml_operator("Mul") def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2550,7 +2545,7 @@ def ggml_operator_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if ggml_type_src1 == ggml.utils.GGML_TYPE.F32: mul_result = ggml.ggml_mul( - ctx.ggml_context, + ctx.ggml_eval_context, a, b, ) @@ -2574,20 +2569,20 @@ def custom_mul( b = ctx.to_numpy(tensor_in_3) x = np.multiply(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) mul_result = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, x_t, a, b, custom_mul, 1, None + ctx.ggml_eval_context, x_t, a, b, custom_mul, 1, None ) ctx.set_tensor_shape(mul_result, ctx.get_tensor_shape(a)) ctx.refs.append(custom_mul) - ctx.tensors_dict[output_name] = mul_result + ctx.ggml_tensors_dict[output_name] = mul_result @register_ggml_operator("Neg") def ggml_operator_neg(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2598,15 +2593,15 @@ def ggml_operator_neg(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_name = node.output[0] x_neg = ggml.ggml_neg( - ctx.ggml_context, + ctx.ggml_eval_context, x, ) - ctx.tensors_dict[output_name] = x_neg + ctx.ggml_tensors_dict[output_name] = x_neg @register_ggml_operator("Not") def ggml_operator_not(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2622,13 +2617,13 @@ def custom_not( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_1) + a = ctx.to_numpy(tensor_in_1) x = np.logical_not(a) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, node_inputs[0], custom_not, 1, @@ -2642,7 +2637,7 @@ def custom_not( @register_ggml_operator("Or") def ggml_operator_or(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2669,15 +2664,15 @@ def custom_or( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) x = np.logical_or(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], node_inputs[1], @@ -2693,7 +2688,7 @@ def custom_or( @register_ggml_operator("Pad") def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] # x, pads, value, axes if len(node_inputs) < 2: @@ -2749,7 +2744,7 @@ def custom_pad( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) + a = ctx.to_numpy(tensor_in_2) if mode == "constant": x = np.pad( a, @@ -2764,10 +2759,10 @@ def custom_pad( pad_width=pad_width, mode=mode, ) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, x_in, custom_pad, @@ -2779,7 +2774,7 @@ def custom_pad( @register_ggml_operator("PRelu") def ggml_operator_leaky_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2796,15 +2791,15 @@ def custom_leaky_prelu( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_1) - slope = ggml.utils.to_numpy(tensor_in_2) + x = ctx.to_numpy(tensor_in_1) + slope = ctx.to_numpy(tensor_in_2) y = np.clip(x, 0, np.inf) + np.clip(x, -np.inf, 0) * slope - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x, slope, custom_leaky_prelu, @@ -2817,7 +2812,7 @@ def custom_leaky_prelu( @register_ggml_operator("Pow") def ggml_operator_pow(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -2836,15 +2831,15 @@ def custom_pow( nth: int, userdata: Optional[ctypes.c_void_p], ): - x1 = ggml.utils.to_numpy(tensor_in_1) - x2 = ggml.utils.to_numpy(tensor_in_2) + x1 = ctx.to_numpy(tensor_in_1) + x2 = ctx.to_numpy(tensor_in_2) new_tensor = np.power(x1, x2) - ctx.set_tensor_out(tensor_out, new_tensor) + ctx.set_tensor_data(tensor_out, new_tensor) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x1, x2, custom_pow, @@ -2857,7 +2852,7 @@ def custom_pow( @register_ggml_operator("RandomNormalLike") def ggml_operator_random_normal_like(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] shape = ctx.get_tensor_shape(node_inputs[0]) dtype = get_tensor_dtype(node_inputs[0]) @@ -2874,12 +2869,11 @@ def custom_random_normal( ): # TODO: use loc and scale from inputs x = np.random.normal(size=shape, loc=0.0, scale=1.0).astype(dtype) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) ctx.refs.append(custom_random_normal) - # breakpoint() - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x_t, custom_random_normal, 1, @@ -2889,7 +2883,7 @@ def custom_random_normal( @register_ggml_operator("Range") def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 3: raise ValueError( @@ -2899,7 +2893,7 @@ def ggml_operator_range(ctx: "GgmlOnnxExecutionContext", node: NodeProto): for node_input in node_inputs: ctx.eval_tensor(node_input) - tensors = [ggml.utils.to_numpy(node_input) for node_input in node_inputs] + tensors = [ctx.to_numpy(node_input) for node_input in node_inputs] start, stop, step = tensors output_shape = (int(np.ceil((stop - start) / step)),) @@ -2917,15 +2911,15 @@ def custom_range( nth: int, userdata: Optional[ctypes.c_void_p], ): - tensors = ggml.utils.to_numpy(tensor_in_2) + tensors = ctx.to_numpy(tensor_in_2) start_array, limit_array, delta_array = tensors new_tensor = np.arange(start_array, limit_array, delta_array) - ctx.set_tensor_out(tensor_out, new_tensor) + ctx.set_tensor_data(tensor_out, new_tensor) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensors, custom_range, @@ -2938,7 +2932,7 @@ def custom_range( @register_ggml_operator("Reciprocal") def ggml_operator_reciprocal(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -2955,13 +2949,13 @@ def custom_reciprocal( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_1) + x = ctx.to_numpy(tensor_in_1) y = np.reciprocal(x) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x, custom_reciprocal, 1, @@ -2990,7 +2984,7 @@ def __init__(self, axes, keepdims): @register_ggml_operator("ReduceL1") def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3004,7 +2998,7 @@ def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) if noop_with_empty_axes == 1: - ctx.tensors_dict[node.output[0]] = input_tensor + ctx.ggml_tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3014,7 +3008,7 @@ def ggml_operator_reduce_l1(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if not axes: if len(node_inputs) > 1: axes_eval = ctx.eval_tensor(node_inputs[1]) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) else: axes = [] @@ -3051,7 +3045,7 @@ def custom_reduce_l1( userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims @@ -3061,10 +3055,10 @@ def custom_reduce_l1( data = np.reshape(np.arange(1, np.prod(shape) + 1, dtype=np.float32), shape) rl1_result = np.sum(a=np.abs(tensor), axis=axes, keepdims=keepdims) - ctx.set_tensor_out(tensor_out, rl1_result) + ctx.set_tensor_data(tensor_out, rl1_result) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensor, custom_reduce_l1, @@ -3079,7 +3073,7 @@ def custom_reduce_l1( @register_ggml_operator("ReduceL2") def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3093,7 +3087,7 @@ def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) if noop_with_empty_axes == 1: - ctx.tensors_dict[node.output[0]] = input_tensor + ctx.ggml_tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3103,7 +3097,7 @@ def ggml_operator_reduce_l2(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if not axes: if len(node_inputs) > 1: axes_eval = ctx.eval_tensor(node_inputs[1]) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) else: axes = [] @@ -3140,7 +3134,7 @@ def custom_reduce_l2( userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims @@ -3148,10 +3142,10 @@ def custom_reduce_l2( rl2_result = np.sqrt(np.sum(a=np.square(tensor), axis=axes, keepdims=keepdims)) - ctx.set_tensor_out(tensor_out, rl2_result) + ctx.set_tensor_data(tensor_out, rl2_result) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensor, custom_reduce_l2, @@ -3166,7 +3160,7 @@ def custom_reduce_l2( @register_ggml_operator("ReduceLogSum") def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3180,7 +3174,7 @@ def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProt ) if noop_with_empty_axes == 1: - ctx.tensors_dict[node.output[0]] = input_tensor + ctx.ggml_tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3190,7 +3184,7 @@ def ggml_operator_reduce_log_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProt if not axes: if len(node_inputs) > 1: axes_eval = ctx.eval_tensor(node_inputs[1]) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) else: axes = [] @@ -3227,17 +3221,17 @@ def custom_reduce_log_sum( userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims axes = tuple(axes) if len(axes) else None rlogsum_result = np.log(np.sum(tensor, axis=axes, keepdims=keepdims)) - ctx.set_tensor_out(tensor_out, rlogsum_result) + ctx.set_tensor_data(tensor_out, rlogsum_result) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensor, custom_reduce_log_sum, @@ -3255,7 +3249,7 @@ def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: Node raise NotImplementedError( f'Error for node "{node.name}": Operation "ReduceLogSumExp" is not implemented.' ) - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3269,7 +3263,7 @@ def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: Node ) if noop_with_empty_axes == 1: - ctx.tensors_dict[node.output[0]] = input_tensor + ctx.ggml_tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3279,7 +3273,7 @@ def ggml_operator_reduce_log_sum_exp(ctx: "GgmlOnnxExecutionContext", node: Node if not axes: if len(node_inputs) > 1: axes_eval = ctx.eval_tensor(node_inputs[1]) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) else: axes = [] @@ -3316,7 +3310,7 @@ def custom_reduce_log_sum_exp( userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims @@ -3325,8 +3319,8 @@ def custom_reduce_log_sum_exp( ctx.set_tensor_out(tensor_out, rlogsum_result) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensor, custom_reduce_log_sum_exp, @@ -3341,7 +3335,7 @@ def custom_reduce_log_sum_exp( @register_ggml_operator("ReduceMax") def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3355,7 +3349,7 @@ def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) if noop_with_empty_axes == 1: - ctx.tensors_dict[node.output[0]] = input_tensor + ctx.ggml_tensors_dict[node.output[0]] = input_tensor return input_tensor tensor_shape = get_tensor_shape(input_tensor) @@ -3365,7 +3359,7 @@ def ggml_operator_reduce_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if not axes: if len(node_inputs) > 1: axes_eval = ctx.eval_tensor(node_inputs[1]) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) else: axes = [] @@ -3402,17 +3396,17 @@ def custom_reduce_max( userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims axes = tuple(axes) if len(axes) else None rmean_result = np.max(tensor, axis=axes, keepdims=keepdims) - ctx.set_tensor_out(tensor_out, rmean_result) + ctx.set_tensor_data(tensor_out, rmean_result) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensor, custom_reduce_max, @@ -3427,7 +3421,7 @@ def custom_reduce_max( @register_ggml_operator("ReduceMean") def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3441,7 +3435,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) if noop_with_empty_axes == 1: - ctx.tensors_dict[node.output[0]] = input_tensor + ctx.ggml_tensors_dict[node.output[0]] = input_tensor return tensor_shape = get_tensor_shape(input_tensor) @@ -3451,7 +3445,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if not axes: if len(node_inputs) > 1: axes_eval = ctx.eval_tensor(node_inputs[1]) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) else: axes = [] @@ -3488,17 +3482,17 @@ def custom_reduce_mean( userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims axes = tuple(axes) if len(axes) else None rmean_result = np.mean(tensor, axis=axes, keepdims=keepdims) - ctx.set_tensor_out(tensor_out, rmean_result) + ctx.set_tensor_data(tensor_out, rmean_result) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensor, custom_reduce_mean, @@ -3513,7 +3507,7 @@ def custom_reduce_mean( @register_ggml_operator("ReduceMin") def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3527,7 +3521,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) if noop_with_empty_axes == 1: - ctx.tensors_dict[node.output[0]] = input_tensor + ctx.ggml_tensors_dict[node.output[0]] = input_tensor return tensor_shape = get_tensor_shape(input_tensor) @@ -3537,7 +3531,7 @@ def ggml_operator_reduce_mean(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if not axes: if len(node_inputs) > 1: axes_eval = ctx.eval_tensor(node_inputs[1]) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) else: axes = [] @@ -3574,17 +3568,17 @@ def custom_reduce_min( userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims axes = tuple(axes) if len(axes) else None rmean_result = np.minimum.reduce(tensor, axis=axes, keepdims=keepdims) - ctx.set_tensor_out(tensor_out, rmean_result) + ctx.set_tensor_data(tensor_out, rmean_result) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensor, custom_reduce_min, @@ -3599,7 +3593,7 @@ def custom_reduce_min( @register_ggml_operator("ReduceProd") def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3613,7 +3607,7 @@ def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) if noop_with_empty_axes == 1: - ctx.tensors_dict[node.output[0]] = input_tensor + ctx.ggml_tensors_dict[node.output[0]] = input_tensor return tensor_shape = get_tensor_shape(input_tensor) @@ -3623,7 +3617,7 @@ def ggml_operator_reduce_prod(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if not axes: if len(node_inputs) > 1: axes_eval = ctx.eval_tensor(node_inputs[1]) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) else: axes = [] @@ -3660,17 +3654,17 @@ def custom_reduce_prod( userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims axes = tuple(axes) if len(axes) else None rmean_result = np.prod(tensor, axis=axes, keepdims=keepdims) - ctx.set_tensor_out(tensor_out, rmean_result) + ctx.set_tensor_data(tensor_out, rmean_result) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensor, custom_reduce_prod, @@ -3685,7 +3679,7 @@ def custom_reduce_prod( @register_ggml_operator("ReduceSum") def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3699,7 +3693,7 @@ def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) if noop_with_empty_axes == 1: - ctx.tensors_dict[node.output[0]] = input_tensor + ctx.ggml_tensors_dict[node.output[0]] = input_tensor return tensor_shape = get_tensor_shape(input_tensor) @@ -3709,7 +3703,7 @@ def ggml_operator_reduce_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if not axes: if len(node_inputs) > 1: axes_eval = ctx.eval_tensor(node_inputs[1]) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) else: axes = [] @@ -3746,16 +3740,16 @@ def custom_reduce_sum( userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims axes = tuple(axes) if len(axes) else None result = np.sum(tensor, axis=axes, keepdims=keepdims) - ctx.set_tensor_out(tensor_out, result) + ctx.set_tensor_data(tensor_out, result) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensor, custom_reduce_sum, @@ -3770,7 +3764,7 @@ def custom_reduce_sum( @register_ggml_operator("ReduceSumSquare") def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) > 2 or len(node_inputs) < 1: raise ValueError( @@ -3784,7 +3778,7 @@ def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeP ) if noop_with_empty_axes == 1: - ctx.tensors_dict[node.output[0]] = input_tensor + ctx.ggml_tensors_dict[node.output[0]] = input_tensor return tensor_shape = get_tensor_shape(input_tensor) @@ -3794,7 +3788,7 @@ def ggml_operator_reduce_sum_square(ctx: "GgmlOnnxExecutionContext", node: NodeP if not axes: if len(node_inputs) > 1: axes_eval = ctx.eval_tensor(node_inputs[1]) - axes = ggml.utils.to_numpy(axes_eval) + axes = ctx.to_numpy(axes_eval) else: axes = [] @@ -3831,17 +3825,17 @@ def custom_reduce_sum_square( userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(ReduceOpsUserData)) userdata_data = userdata_data_ptr.contents - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) axes = [userdata_data.axes[i] for i in range(userdata_data.axes_length)] keepdims = userdata_data.keepdims axes = tuple(axes) if len(axes) else None result = np.sum(np.square(tensor), axis=axes, keepdims=keepdims) - ctx.set_tensor_out(tensor_out, result) + ctx.set_tensor_data(tensor_out, result) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, input_tensor, custom_reduce_sum_square, @@ -3856,7 +3850,7 @@ def custom_reduce_sum_square( @register_ggml_operator("Relu") def ggml_operator_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -3867,15 +3861,15 @@ def ggml_operator_relu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] relu_result = ggml.ggml_relu( - ctx.ggml_context, + ctx.ggml_eval_context, a, ) - ctx.tensors_dict[output_name] = relu_result + ctx.ggml_tensors_dict[output_name] = relu_result @register_ggml_operator("Reshape") def ggml_operator_reshape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( f'Error for node "{node.name}": Operation "Reshape" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' @@ -3895,7 +3889,7 @@ def ggml_operator_reshape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): b, ) - new_shape = ggml.utils.to_numpy(eval_b).astype(dtype=np.int32) + new_shape = ctx.to_numpy(eval_b).astype(dtype=np.int32) old_shape = get_tensor_shape(a) if not allowzero: @@ -3915,12 +3909,12 @@ def custom_reshape( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) + x = ctx.to_numpy(tensor_in_2) x_reshape = np.reshape(x, new_shape) - ctx.set_tensor_out(tensor_out, x_reshape) + ctx.set_tensor_data(tensor_out, x_reshape) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, a, custom_reshape, @@ -3933,7 +3927,7 @@ def custom_reshape( @register_ggml_operator("Resize") def ggml_operator_resize(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] if inp != "" else None for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] if inp != "" else None for inp in node.input] node_inputs.extend([None] * (4 - len(node_inputs))) if len(node_inputs) > 4: @@ -4023,7 +4017,7 @@ def ggml_operator_resize(ctx: "GgmlOnnxExecutionContext", node: NodeProto): if scales[0] == 1 and scales[1] == 1 and scales[2] == scales[3] and is_integer: # Special case for 2D scaling handled by ggml_upscale scale_factor = int(scales[2]) - new_tensor = ggml.ggml_upscale(ctx.ggml_context, a, scale_factor) + new_tensor = ggml.ggml_upscale(ctx.ggml_eval_context, a, scale_factor) else: @ggml.ggml_custom2_op_t @@ -4035,7 +4029,7 @@ def custom_resize( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) + a = ctx.to_numpy(tensor_in_2) output_size = (scales * np.array(a.shape)).astype(int) y = np.zeros(output_size) @@ -4043,10 +4037,10 @@ def custom_resize( for idx in np.ndindex(*output_size): x = (np.array(idx) // scales).astype(int) y[idx] = a[tuple(x)] - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, a, custom_resize, @@ -4054,7 +4048,7 @@ def custom_resize( None, ) ctx.refs.append(custom_resize) - ctx.tensors_dict[node.output[0]] = new_tensor + ctx.ggml_tensors_dict[node.output[0]] = new_tensor class SeluUserData(ctypes.Structure): @@ -4066,7 +4060,7 @@ class SeluUserData(ctypes.Structure): @register_ggml_operator("Selu") def ggml_operator_selu(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4097,7 +4091,7 @@ def custom_selu( ): userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(SeluUserData)) userdata_data = userdata_data_ptr.contents - x = ggml.utils.to_numpy(tensor_in_1) + x = ctx.to_numpy(tensor_in_1) alpha = userdata_data.alpha gamma = userdata_data.gamma @@ -4107,10 +4101,10 @@ def custom_selu( + (np.exp(np.clip(x, -np.inf, 0)) - 1) * alpha * gamma ) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x, custom_selu, 1, @@ -4124,7 +4118,7 @@ def custom_selu( @register_ggml_operator("Shape") def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4139,14 +4133,14 @@ def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) shape_slice = tensor_shape[start:end] - new_tensor = ctx.tensors_dict[name] = ctx.from_numpy(shape_slice) + new_tensor = ctx.ggml_tensors_dict[name] = ctx.from_numpy(shape_slice) ctx.set_tensor_dtype(name, np.dtype(np.int64)) @register_ggml_operator("Sigmoid") def ggml_operator_sigmoid(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4172,10 +4166,10 @@ def custom_sigmoid( a = ctx.to_numpy(tensor_in_2) y = 1.0 / (1.0 + np.exp(np.negative(a))) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, a, custom_sigmoid, @@ -4188,7 +4182,7 @@ def custom_sigmoid( @register_ggml_operator("Sin") def ggml_operator_sin(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4214,10 +4208,10 @@ def custom_sin( a = ctx.to_numpy(tensor_in_2) y = np.sin(a) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, a, custom_sin, @@ -4230,7 +4224,7 @@ def custom_sin( @register_ggml_operator("Size") def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4258,11 +4252,11 @@ def custom_size( nth: int, userdata: Optional[ctypes.c_void_p], ): - tensor = ggml.utils.to_numpy(tensor_in_2) - ctx.set_tensor_out(tensor_out, tensor) + tensor = ctx.to_numpy(tensor_in_2) + ctx.set_tensor_data(tensor_out, tensor) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, tensor_size_t, custom_size, @@ -4277,7 +4271,7 @@ def custom_size( @register_ggml_operator("Slice") def ggml_operator_slice(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] a_shape = ctx.get_tensor_shape(node_inputs[0]) a_dtype = get_tensor_dtype(node_inputs[0]) @@ -4321,20 +4315,20 @@ def custom_slice( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) + x = ctx.to_numpy(tensor_in_2) y = x[tuple(all_slices)].copy() - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, x_t, node_inputs[0], custom_slice, 1, None + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], custom_slice, 1, None ) ctx.refs.append(custom_slice) @register_ggml_operator("Softmax") def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4345,15 +4339,15 @@ def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] soft_max_result = ggml.ggml_soft_max( - ctx.ggml_context, + ctx.ggml_eval_context, a, ) - ctx.tensors_dict[output_name] = soft_max_result + ctx.ggml_tensors_dict[output_name] = soft_max_result @register_ggml_operator("Softplus") def ggml_operator_softplus(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4370,12 +4364,12 @@ def custom_softplus( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_1) + x = ctx.to_numpy(tensor_in_1) y = np.log(np.exp(x) + 1) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom1_inplace( + ctx.ggml_eval_context, x, custom_softplus, 1, @@ -4387,7 +4381,7 @@ def custom_softplus( @register_ggml_operator("Softsign") def ggml_operator_softsign(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4401,15 +4395,15 @@ def ggml_operator_softsign(ctx: "GgmlOnnxExecutionContext", node: NodeProto): # y = x / (1 + abs(x)) one_np = np.full(x_shape, 1, dtype=x_dtype) one_t = ctx.from_numpy(one_np) - x_abs = ggml.ggml_abs(ctx.ggml_context, x) - one_plus_abs = ggml.ggml_add(ctx.ggml_context, one_t, x_abs) - y = ggml.ggml_div(ctx.ggml_context, x, one_plus_abs) - ctx.tensors_dict[node.output[0]] = y + x_abs = ggml.ggml_abs(ctx.ggml_eval_context, x) + one_plus_abs = ggml.ggml_add(ctx.ggml_eval_context, one_t, x_abs) + y = ggml.ggml_div(ctx.ggml_eval_context, x, one_plus_abs) + ctx.ggml_tensors_dict[node.output[0]] = y @register_ggml_operator("SpaceToDepth") def ggml_operator_space_to_depth(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4444,7 +4438,7 @@ def custom_space_to_depth( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) + x = ctx.to_numpy(tensor_in_2) blocksize = ctypes.cast(userdata, ctypes.POINTER(ctypes.c_int)).contents.value N, C, H, W = x.shape @@ -4457,10 +4451,10 @@ def custom_space_to_depth( ) # ONNX specification TODO: Test more examples y = transposed.reshape(N, C * (blocksize**2), new_H, new_W) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + ctx.ggml_eval_context, x_t, x, custom_space_to_depth, @@ -4482,7 +4476,7 @@ class SplitUserData(ctypes.Structure): @register_ggml_operator("Split") def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1 or len(node_inputs) > 2: raise ValueError( @@ -4517,7 +4511,7 @@ def ggml_operator_split(ctx: "GgmlOnnxExecutionContext", node: NodeProto): split_eval = ctx.eval_tensor( split_tensor, ) - split_values = ggml.utils.to_numpy(split_eval) + split_values = ctx.to_numpy(split_eval) split_shapes = [list(input_shape) for _ in range(num_outputs)] for i, split_value in enumerate(split_values): @@ -4552,10 +4546,10 @@ def custom_split( axis = userdata_data.axis split_index = userdata_data.split_index - tensor = ggml.utils.to_numpy(tensor_in_2) + tensor = ctx.to_numpy(tensor_in_2) - split_shapes = ggml.utils.to_numpy(tensor_in_3) - split_shape = list(ggml.utils.to_numpy(tensor_in_1).shape) + split_shapes = ctx.to_numpy(tensor_in_3) + split_shape = list(ctx.to_numpy(tensor_in_1).shape) split_size = split_shape[axis] split_start = sum(split_shapes[i][axis] for i in range(split_index)) @@ -4563,12 +4557,12 @@ def custom_split( split_output = np.take(tensor, range(split_start, split_end), axis=axis) - ctx.set_tensor_out(tensor_out, split_output) + ctx.set_tensor_data(tensor_out, split_output) - new_tensor = ctx.tensors_dict[ + new_tensor = ctx.ggml_tensors_dict[ node.output[split_index] ] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + ctx.ggml_eval_context, x_t, input_tensor, split_shapes_t, @@ -4584,7 +4578,7 @@ def custom_split( @register_ggml_operator("Sqrt") def ggml_operator_sqrt(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4595,15 +4589,15 @@ def ggml_operator_sqrt(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] sqrt_result = ggml.ggml_sqrt( - ctx.ggml_context, + ctx.ggml_eval_context, a, ) - ctx.tensors_dict[output_name] = sqrt_result + ctx.ggml_tensors_dict[output_name] = sqrt_result @register_ggml_operator("Squeeze") def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -4617,7 +4611,7 @@ def ggml_operator_squeeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes_eval = ctx.eval_tensor( axes_input, ) - axes = ggml.utils.to_numpy(axes_eval).astype(dtype=np.int32) + axes = ctx.to_numpy(axes_eval).astype(dtype=np.int32) dummy_data = np.empty(x_shape, dtype=x_dtype) dummy_data = np.squeeze(dummy_data, axis=axes[0]) @@ -4641,10 +4635,10 @@ def custom_squeeze( x = ctx.to_numpy(tensor_in_2) axes = ctx.to_numpy(tensor_in_3) y = np.squeeze(x, axis=axes[0]) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, data, axes_input, @@ -4658,7 +4652,7 @@ def custom_squeeze( @register_ggml_operator("Sub") def ggml_operator_sub(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -4670,16 +4664,16 @@ def ggml_operator_sub(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, b = broadcast_shapes(ctx, a, b) sub_result = ggml.ggml_sub( - ctx.ggml_context, + ctx.ggml_eval_context, a, b, ) - ctx.tensors_dict[output_name] = sub_result + ctx.ggml_tensors_dict[output_name] = sub_result @register_ggml_operator("Sum") def ggml_operator_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) < 1: raise ValueError( @@ -4696,17 +4690,17 @@ def ggml_operator_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): for tensor in node_inputs: tensor, next_item = broadcast_shapes(ctx, tensor, next_item) next_item = ggml.ggml_add( - ctx.ggml_context, + ctx.ggml_eval_context, tensor, next_item, ) - ctx.tensors_dict[output_name] = next_item + ctx.ggml_tensors_dict[output_name] = next_item @register_ggml_operator("Tanh") def ggml_operator_tanh(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4715,16 +4709,16 @@ def ggml_operator_tanh(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x = node_inputs[0] tanh_result = ggml.ggml_tanh( - ctx.ggml_context, + ctx.ggml_eval_context, x, ) - ctx.tensors_dict[node.output[0]] = tanh_result + ctx.ggml_tensors_dict[node.output[0]] = tanh_result @register_ggml_operator("Tile") def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -4736,7 +4730,7 @@ def ggml_operator_tile(ctx: "GgmlOnnxExecutionContext", node: NodeProto): repeats_eval = ctx.eval_tensor( repeats, ) - repeats_vals = ggml.utils.to_numpy(repeats_eval).astype(dtype=np.int32) + repeats_vals = ctx.to_numpy(repeats_eval).astype(dtype=np.int32) output_shape = list(get_tensor_shape(x)) for i in range(len(output_shape)): @@ -4756,15 +4750,15 @@ def custom_tile( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) - repeats = ggml.utils.to_numpy(tensor_in_3) + x = ctx.to_numpy(tensor_in_2) + repeats = ctx.to_numpy(tensor_in_3) y = np.tile(x, repeats) - ctx.set_tensor_out(tensor_out, y) + ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, x, repeats, @@ -4787,7 +4781,7 @@ class TopKUserData(ctypes.Structure): @register_ggml_operator("TopK") def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -4805,7 +4799,7 @@ def ggml_operator_top_k(ctx: "GgmlOnnxExecutionContext", node: NodeProto): k_eval = ctx.eval_tensor( k, ) - k_np = ggml.utils.to_numpy(k_eval)[0] + k_np = ctx.to_numpy(k_eval)[0] topk_userdata = TopKUserData(axis, largest, sorted_flag, k_np) userdata_p = ctypes.cast(ctypes.pointer(topk_userdata), ctypes.c_void_p) @@ -4831,7 +4825,7 @@ def custom_top_k_indices( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) + x = ctx.to_numpy(tensor_in_2) userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(TopKUserData)) userdata_data = userdata_data_ptr.contents @@ -4848,10 +4842,10 @@ def custom_top_k_indices( topk_indices = sorted_indices[:, :k] - ctx.set_tensor_out(tensor_out, topk_indices) + ctx.set_tensor_data(tensor_out, topk_indices) indices = ggml.ggml_map_custom2_inplace( - ctx.ggml_context, + ctx.ggml_eval_context, indices_t, x, custom_top_k_indices, @@ -4871,8 +4865,8 @@ def custom_top_k_values( nth: int, userdata: Optional[ctypes.c_void_p], ): - x = ggml.utils.to_numpy(tensor_in_2) - topk_indices = ggml.utils.to_numpy(tensor_in_3).astype(np.int32) + x = ctx.to_numpy(tensor_in_2) + topk_indices = ctx.to_numpy(tensor_in_3).astype(np.int32) userdata_data_ptr = ctypes.cast(userdata, ctypes.POINTER(TopKUserData)) userdata_data = userdata_data_ptr.contents @@ -4886,10 +4880,10 @@ def custom_top_k_values( else: topk_values_sorted = topk_values - ctx.set_tensor_out(tensor_out, topk_values_sorted) + ctx.set_tensor_data(tensor_out, topk_values_sorted) values = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + ctx.ggml_eval_context, values_t, x, indices, @@ -4900,8 +4894,8 @@ def custom_top_k_values( ctx.refs.append(custom_top_k_values) - ctx.tensors_dict[node.output[0]] = values - ctx.tensors_dict[node.output[1]] = indices + ctx.ggml_tensors_dict[node.output[0]] = values + ctx.ggml_tensors_dict[node.output[1]] = indices ctx.refs.append(topk_userdata) @@ -4910,7 +4904,7 @@ def custom_top_k_values( @register_ggml_operator("Transpose") def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 1: raise ValueError( @@ -4936,13 +4930,13 @@ def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes = list(reversed(new_idxs)) + list(range(4)[len(perms) :]) ax0, ax1, ax2, ax3 = axes - transpose_result = ggml.ggml_permute(ctx.ggml_context, x, ax0, ax1, ax2, ax3) - ctx.tensors_dict[output_name] = transpose_result + transpose_result = ggml.ggml_permute(ctx.ggml_eval_context, x, ax0, ax1, ax2, ax3) + ctx.ggml_tensors_dict[output_name] = transpose_result @register_ggml_operator("Unsqueeze") def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -4993,11 +4987,10 @@ def custom_unsqueeze( axes_values = np.array(axes_values) for axis in axes_values: x = np.expand_dims(x, axis=axis) - # print(node) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, data, axes_input, @@ -5010,7 +5003,7 @@ def custom_unsqueeze( @register_ggml_operator("Where") def ggml_operator_where(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 3: raise ValueError( @@ -5027,15 +5020,15 @@ def custom_where( nth: int, userdata: Optional[ctypes.c_void_p], ): - y = ggml.utils.to_numpy(tensor_in_1) - x = ggml.utils.to_numpy(tensor_in_2) + y = ctx.to_numpy(tensor_in_1) + x = ctx.to_numpy(tensor_in_2) condition_array = ctx.to_numpy(tensor_in_3) new_tensor = np.where(condition_array, x, y) - ctx.set_tensor_out(tensor_out, new_tensor) + ctx.set_tensor_data(tensor_out, new_tensor) - new_tensor = ctx.tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, node_inputs[2], node_inputs[1], node_inputs[0], @@ -5048,7 +5041,7 @@ def custom_where( @register_ggml_operator("Xor") def ggml_operator_xor(ctx: "GgmlOnnxExecutionContext", node: NodeProto): - node_inputs = [ctx.tensors_dict[inp] for inp in node.input] + node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] if len(node_inputs) != 2: raise ValueError( @@ -5075,15 +5068,15 @@ def custom_xor( nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ggml.utils.to_numpy(tensor_in_2) - b = ggml.utils.to_numpy(tensor_in_3) + a = ctx.to_numpy(tensor_in_2) + b = ctx.to_numpy(tensor_in_3) x = np.logical_xor(a, b) - ctx.set_tensor_out(tensor_out, x) + ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.tensors_dict[name] = ggml.ggml_map_custom3_inplace( - ctx.ggml_context, + new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom3_inplace( + ctx.ggml_eval_context, x_t, node_inputs[0], node_inputs[1], @@ -5101,18 +5094,20 @@ class GgmlOnnxExecutionContext: def __init__( self, backend: "GgmlBackendRep", - tensors_dict: Dict[str, ggml.ggml_tensor_p], - ggml_context: ggml.ggml_context_p, + ggml_tensors_dict: Dict[str, ggml.ggml_tensor_p], + ggml_eval_context: ggml.ggml_context_p, refs: List[Any], max_tensors: int, ): self.backend = backend - self.tensors_dict = tensors_dict - self.ggml_context = ggml_context + self.ggml_tensors_dict = ggml_tensors_dict + self.ggml_eval_context = ggml_eval_context self.refs = refs self.shapes: Dict[int, Tuple[int, ...]] = {} self.dtypes: Dict[str, npt.DTypeLike] = {} - self.gf = ggml.ggml_new_graph_custom(self.ggml_context, max_tensors, False) + self.max_tensors = max_tensors + self.ggml_graph = ggml.ggml_new_graph_custom(self.ggml_eval_context, max_tensors, False) + self.ggml_graph = None self.n_threads = 8 def set_tensor_shape(self, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...]): @@ -5129,87 +5124,64 @@ def set_tensor_dtype(self, name: str, dtype: npt.DTypeLike): self.dtypes[name] = dtype def get_tensor_dtype(self, name: str) -> npt.DTypeLike: - tensor_dtype = get_tensor_dtype(self.tensors_dict[name]) + tensor_dtype = get_tensor_dtype(self.ggml_tensors_dict[name]) return self.dtypes.get(name, tensor_dtype) def to_numpy(self, tensor: ggml.ggml_tensor_p) -> npt.NDArray[Any]: shape = self.get_tensor_shape(tensor) - array = ggml.utils.to_numpy(tensor) + array = get_ggml_tensor_data_as_numpy(tensor) return array.reshape(shape) - def alloc_tensor_cpu(self, tensor: ggml.ggml_tensor_p): - # Check if tensor is a view and if so allocate the view source - if tensor.contents.view_src: - self.alloc_tensor_cpu(tensor.contents.view_src) - tensor.contents.data = tensor.contents.view_src.contents.data - # Check if tensor is already allocated - if tensor.contents.data: - return - # Allocate tensor - buffer = (ctypes.c_uint8 * ggml.ggml_nbytes_pad(tensor))() - self.refs.append(buffer) - tensor.contents.data = ctypes.cast(ctypes.addressof(buffer), ctypes.c_void_p) - def from_numpy(self, array: npt.NDArray[Any]) -> ggml.ggml_tensor_p: shape = array.shape - tensor = ggml.utils.from_numpy(array, self.ggml_context) + tensor = ggml.utils.from_numpy(array, self.ggml_eval_context) + + tensor_buffer = ggml.ggml_backend_alloc_buffer(self.backend.ggml_backend, ggml.ggml_nbytes(tensor)) + weakref.finalize(tensor, ggml.ggml_backend_buffer_free, tensor_buffer) + tallocr = ggml.ggml_tallocr_new(tensor_buffer) + ggml.ggml_tallocr_alloc(tallocr, tensor) + ggml.ggml_tallocr_free(tallocr) + if array.size > 0: - self.alloc_tensor_cpu(tensor) - self.set_tensor_out(tensor, array) + set_ggml_tensor_data_from_numpy(tensor, array) + self.set_tensor_shape(tensor, shape) return tensor - def compute_graph(self, gf: ggml.ggml_cgraph_p): - gp = ggml.ggml_graph_plan(gf, self.n_threads) - gp.n_threads = self.n_threads - work_buffer = (ctypes.c_uint8 * gp.work_size)() if gp.work_size > 0 else None - if gp.work_size > 0: - gp.work = ctypes.cast(work_buffer, ctypes.c_void_p) - ggml.ggml_graph_compute(gf, ctypes.byref(gp)) - work_buffer = None - gp.work = None - def eval_tensor(self, tensor: ggml.ggml_tensor_p): - self.alloc_tensor_cpu(tensor) - gf = self.gf - ggml.ggml_graph_clear(gf) - ggml.ggml_build_forward_expand(gf, tensor) - # NOTE: Should probably save / restore data pointers here for intermediate tensors - alignment = 32 - alloc_size = ggml.utils.alloc_graph_measure(gf.contents, alignment=32) - alloc_buffer = (ctypes.c_uint8 * alloc_size)() - - def copy_tensor( - src: ggml.ggml_tensor_p, dst: Optional[ggml.ggml_tensor_p] = None - ) -> ggml.ggml_tensor: - # copy tensor data byte-by-byte using ctypes - src_tensor = src.contents - dst_tensor = ggml.ggml_tensor() if dst is None else dst.contents - ctypes.memmove( - ctypes.byref(dst_tensor), - ctypes.byref(src_tensor), - ctypes.sizeof(src_tensor), - ) - return dst_tensor - leafs = [copy_tensor(gf.contents.leafs[i]) for i in range(gf.contents.n_leafs)] - nodes = [copy_tensor(gf.contents.nodes[i]) for i in range(gf.contents.n_nodes)] - allocr = ggml.ggml_allocr_new( - ctypes.cast(alloc_buffer, ctypes.c_void_p), alloc_size, alignment - ) - ggml.ggml_allocr_alloc_graph(allocr, gf) - self.compute_graph(gf) - ggml.ggml_allocr_free(allocr) - for i in range(gf.contents.n_leafs): - copy_tensor(ctypes.pointer(leafs[i]), gf.contents.leafs[i]) - for i in range(gf.contents.n_nodes): - copy_tensor(ctypes.pointer(nodes[i]), gf.contents.nodes[i]) - tensor_copy = ggml.ggml_dup_tensor(self.ggml_context, tensor) - tensor_copy.contents.data = tensor.contents.data - # copy_tensor(tensor_copy, tensor) + self.ggml_graph = ggml.ggml_new_graph_custom(self.ggml_eval_context, self.max_tensors, False) + ggml.ggml_set_output(tensor) + ggml.ggml_build_forward_expand(self.ggml_graph, tensor) + + gallocr = ggml.ggml_gallocr_new(ggml.ggml_backend_get_default_buffer_type(self.backend.ggml_backend)) + + if gallocr is None: + raise RuntimeError("Failed to create GGML graph allocator") + + if not ggml.ggml_gallocr_alloc_graph(gallocr, self.ggml_graph): + raise RuntimeError("Failed to allocate GGML graph") + + if not ggml.ggml_backend_graph_compute(self.backend.ggml_backend, self.ggml_graph): + raise RuntimeError("Failed to compute GGML graph") + + tensor_copy = ggml.ggml_dup_tensor(self.ggml_eval_context, tensor) + tensor_copy_buffer = ggml.ggml_backend_alloc_buffer(self.backend.ggml_backend, ggml.ggml_nbytes(tensor_copy)) + weakref.finalize(tensor_copy, ggml.ggml_backend_buffer_free, tensor_copy_buffer) + tallocr = ggml.ggml_tallocr_new(tensor_copy_buffer) + ggml.ggml_tallocr_alloc(tallocr, tensor_copy) + + ggml.ggml_backend_tensor_copy(tensor, tensor_copy) + self.refs.append(tensor_copy_buffer) + + ggml.ggml_tallocr_free(tallocr) + ggml.ggml_gallocr_free(gallocr) + + self.set_tensor_shape(tensor_copy, self.get_tensor_shape(tensor)) + return tensor_copy - def set_tensor_out(self, tensor: ggml.ggml_tensor_p, array: npt.NDArray[Any]): - np.copyto(self.to_numpy(tensor), array, casting="unsafe") + def set_tensor_data(self, tensor: ggml.ggml_tensor_p, array: npt.NDArray[Any]): + set_ggml_tensor_data_from_numpy(tensor, array) class GgmlBackendRep(BackendRep): @@ -5217,24 +5189,26 @@ def __init__( self, graph: GraphProto, weights: Dict[str, ggml.ggml_tensor_p], - weights_buffer: Any, inputs: Sequence[ValueInfoProto], outputs: Sequence[ValueInfoProto], ggml_context: ggml.ggml_context_p, ggml_init_params: ggml.ggml_init_params, + ggml_backend: ggml.ggml_backend_t, + ggml_weights_buffer: Any, ): super(GgmlBackendRep, self).__init__() self.graph = graph self.weights = weights - self.weights_buffer = weights_buffer self.inputs = inputs self.outputs = outputs self.ggml_context = ggml_context self.ggml_init_params = ggml_init_params + self.ggml_backend = ggml_backend + self.ggml_weights_buffer = ggml_weights_buffer def __del__(self): - if hasattr(self, "ggml_context"): - ggml.ggml_free(self.ggml_context) + ggml.ggml_backend_buffer_free(self.ggml_weights_buffer) + ggml.ggml_free(self.ggml_context) @staticmethod def _is_list_of_arraylike(x: Any) -> TypeGuard[List[npt.ArrayLike]]: @@ -5260,7 +5234,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: exit_node = None ggml_tensors = self.weights.copy() - input_context = ggml.ggml_init( + ggml_input_context = ggml.ggml_init( params=ggml.ggml_init_params( mem_size=2 * ggml.GGML_DEFAULT_GRAPH_SIZE @@ -5268,7 +5242,8 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: no_alloc=True, ) ) - input_buffer_size = 0 + if ggml_input_context is None: + raise RuntimeError("Failed to initialize GGML input context") # Create entry inputs for model_input in model_graph.input: @@ -5307,45 +5282,43 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: shape = (1,) tensor = ggml.ggml_new_tensor( - input_context, + ggml_input_context, ggml_type.value, len(shape), (ctypes.c_int64 * len(shape))(*shape), ) - input_buffer_size += ggml.ggml_nbytes_pad(tensor) ggml_tensors[input_name] = tensor - input_buffer = (ctypes.c_uint8 * input_buffer_size)() - input_buffer_offset = 0 + ggml_input_buffer = ggml.ggml_backend_alloc_ctx_tensors(ggml_input_context, self.ggml_backend) # Set user inputs for key, value in inputs.items(): tensor = ggml_tensors[key] - tensor.contents.data = ctypes.cast( - ctypes.addressof(input_buffer) + input_buffer_offset, ctypes.c_void_p - ) - input_buffer_offset += ggml.ggml_nbytes_pad(tensor) - np.copyto(ggml.utils.to_numpy(tensor), np.array(value)) + set_ggml_tensor_data_from_numpy(tensor, np.array(value)) # Define context max_tensors = 8192 max_overhead = ggml.ggml_tensor_overhead() * max_tensors + ggml.ggml_graph_overhead_custom(max_tensors, False) mem_buffer = (ctypes.c_uint8 * max_overhead)() - ggml_context = ggml.ggml_init( + ggml_eval_context = ggml.ggml_init( params=ggml.ggml_init_params( mem_size=max_overhead, mem_buffer=ctypes.cast(mem_buffer, ctypes.c_void_p), no_alloc=True ) ) + if ggml_eval_context is None: + raise RuntimeError("Failed to initialize GGML context") refs: List[Any] = [] refs.append(mem_buffer) output_names = [output.name for output in model_graph.output] - ctx = GgmlOnnxExecutionContext(self, ggml_tensors, ggml_context, refs, max_tensors) + ctx = GgmlOnnxExecutionContext(self, ggml_tensors, ggml_eval_context, refs, max_tensors) # Build layers + outputs: Dict[str, ggml.ggml_tensor_p] = {} + for node in model_graph.node: operator_func: Optional[GgmlOperator] = ggml_operators.get(node.op_type) if operator_func is None: @@ -5358,15 +5331,15 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: for output in node.output: if output in output_names: - ctx.eval_tensor(ggml_tensors[output]) + outputs[output] = ctx.eval_tensor(ggml_tensors[output]) graph_outputs: List[npt.NDArray[Any]] = [] for output in self.outputs: - exit_node = ggml_tensors[output.name] + exit_node = outputs[output.name] # NOTE: 0 dimension in ggml may cause bugs max_tensors = np.prod(ctx.get_tensor_shape(exit_node)) graph_output: npt.NDArray[Any] = ( - ggml.utils.to_numpy(exit_node) if max_tensors > 0 else np.empty((0)) + ctx.to_numpy(exit_node) if max_tensors > 0 else np.empty((0)) ) # TODO: Add checks to convert values back to bool or etc types graph_output = graph_output.astype( ctx.get_tensor_dtype(output.name) @@ -5377,8 +5350,9 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: graph_outputs.append(graph_output) - ggml.ggml_free(ggml_context) - ggml.ggml_free(input_context) + ggml.ggml_backend_buffer_free(ggml_input_buffer) + ggml.ggml_free(ggml_eval_context) + ggml.ggml_free(ggml_input_context) return graph_outputs @@ -5389,7 +5363,7 @@ def is_opset_supported(cls, model: ModelProto): return True, "" @classmethod - def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): + def prepare(cls, model: ModelProto, device: Optional[str] = "CPU", **kwargs: Any): """Load the model and creates the ggml runtime backend representation for the onnx graph. @@ -5402,50 +5376,48 @@ def prepare(cls, model: ModelProto, device: str = "CPU", **kwargs): # This fails with large models. # https://github.com/onnx/onnx/blob/b60f69412abb5393ab819b936b473f83867f6c87/onnx/backend/base.py#L85 # super(GgmlRuntimeBackend, cls).prepare(model, device, **kwargs) + ggml_backend = ggml.ggml_backend_cpu_init() + if ggml_backend is None: + raise RuntimeError("Failed to initialize GGML CPU backend") + graph = model.graph weights: Dict[str, ggml.ggml_tensor_p] = {} n_tensors = len(graph.initializer) - init_params = ggml.ggml_init_params( + ggml_init_params = ggml.ggml_init_params( mem_size=n_tensors * ggml.ggml_tensor_overhead(), no_alloc=True, ) - ggml_context = ggml.ggml_init(init_params) - total_nbytes = 0 + ggml_weights_context = ggml.ggml_init(ggml_init_params) + if ggml_weights_context is None: + raise RuntimeError("Failed to initialize GGML context") pairs: List[Tuple[ggml.ggml_tensor_p, TensorProto]] = [] for initializer in graph.initializer: name = initializer.name np_array: npt.NDArray[Any] = onnx.numpy_helper.to_array(initializer) # type: ignore - tensor = ggml.utils.from_numpy(x=np_array, ctx=ggml_context) + tensor = ggml.utils.from_numpy(x=np_array, ctx=ggml_weights_context) ggml.ggml_set_name(tensor=tensor, name=name.encode()) - total_nbytes += ggml.ggml_nbytes_pad(tensor) weights[name] = tensor pairs.append((tensor, initializer)) - buffer = (ctypes.c_uint8 * total_nbytes)() - offset = 0 + ggml_weights_buffer = ggml.ggml_backend_alloc_ctx_tensors(ggml_weights_context, ggml_backend) for tensor, initializer in pairs: - nbytes = ggml.ggml_nbytes_pad(tensor) - tensor.contents.data = ctypes.cast( - ctypes.addressof(buffer) + offset, ctypes.c_void_p - ) - np_array = onnx.numpy_helper.to_array(initializer) - np.copyto(ggml.utils.to_numpy(tensor), np_array) - - offset += nbytes + np_array = onnx.numpy_helper.to_array(initializer) # type: ignore + set_ggml_tensor_data_from_numpy(tensor, np_array) return GgmlBackendRep( graph=graph, weights=weights, - weights_buffer=buffer, inputs=graph.input, outputs=graph.output, - ggml_context=ggml_context, - ggml_init_params=init_params, + ggml_context=ggml_weights_context, + ggml_init_params=ggml_init_params, + ggml_backend=ggml_backend, + ggml_weights_buffer=ggml_weights_buffer, ) @classmethod @@ -5462,8 +5434,8 @@ def run_node( node: NodeProto, inputs: Any, device: Optional[str] = None, - outputs_info=None, - **kwargs, + outputs_info=None, # type: ignore + **kwargs: Any, ) -> Tuple[Any, ...]: """ This method is not implemented as it is much more efficient From 81d62a973a301ca6955409f03c137dbb5b2509d0 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sun, 25 Feb 2024 17:06:37 -0500 Subject: [PATCH 222/232] fix: test --- tests/test_ggml.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_ggml.py b/tests/test_ggml.py index d3a892ea..b3a20ccf 100644 --- a/tests/test_ggml.py +++ b/tests/test_ggml.py @@ -274,7 +274,7 @@ def no_op( no_op_n_calls += 1 params = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None, no_alloc=True) - ctx = ggml.ggml_init(params=params) + ctx = ggml.ggml_init(params) assert ctx is not None assert ggml.ggml_used_mem(ctx) == 0 x = ggml.ggml_new_tensor_1d(ctx, ggml.GGML_TYPE_F32, 1) @@ -299,7 +299,7 @@ def no_op( assert no_op_n_calls == 1 params_eval = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None, no_alloc=True) - ctx_eval = ggml.ggml_init(params=params_eval) + ctx_eval = ggml.ggml_init(params_eval) assert ctx_eval is not None f_copy = ggml.ggml_dup_tensor(ctx_eval, f) @@ -312,7 +312,7 @@ def no_op( params2 = ggml.ggml_init_params(mem_size=16 * 1024 * 1024, mem_buffer=None, no_alloc=True) - ctx2 = ggml.ggml_init(params=params2) + ctx2 = ggml.ggml_init(params2) assert ctx2 is not None g = ggml.ggml_add(ctx2, f_copy, a) From 14a64fadc14b5933512ac4d7e1a1e61db964bb79 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sun, 25 Feb 2024 18:40:50 -0500 Subject: [PATCH 223/232] fix: Re-enable tensor set in from_numpy --- ggml/utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ggml/utils.py b/ggml/utils.py index eca268a4..ffee71a6 100644 --- a/ggml/utils.py +++ b/ggml/utils.py @@ -105,11 +105,11 @@ def from_numpy(x: npt.NDArray[Any], ctx: ggml.ggml_context_p) -> ggml.ggml_tenso tensor.contents.nb[: len(shape)] = (ctypes.c_int64 * len(shape))( *tuple(reversed(x.strides)) ) - # if ggml.ggml_get_data(tensor) is not None: - # if shape == (): - # to_numpy(tensor)[()] = x - # else: - # to_numpy(tensor)[:] = x + if ggml.ggml_get_data(tensor) is not None: + if shape == (): + to_numpy(tensor)[()] = x + else: + to_numpy(tensor)[:] = x return tensor From fd5c79dd092163f67687c4f613953d44efddb9c0 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 28 Feb 2024 13:09:34 -0500 Subject: [PATCH 224/232] Track node shapes --- ggml/contrib/onnx.py | 210 ++++++++++++++++++++++++++++--------------- 1 file changed, 136 insertions(+), 74 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index d4d2bc02..190d31ca 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5,7 +5,7 @@ import math import ctypes import weakref -from typing import Any, Callable, Dict, List, Optional, Tuple, Sequence +from typing import Any, Callable, Dict, List, Optional, Tuple, Sequence, List from typing_extensions import TypeGuard import numpy as np @@ -40,13 +40,16 @@ def set_ggml_tensor_data_from_numpy( ) def get_ggml_tensor_data_as_numpy( - tensor: ggml.ggml_tensor_p + tensor: ggml.ggml_tensor_p, + shape: Optional[Tuple[int, ...]] = None, ) -> npt.NDArray[Any]: np_dtype = get_tensor_dtype(tensor) - shape = ggml.utils.get_shape(tensor) - array = np.empty(shape, dtype=np_dtype) + _shape = ggml.utils.get_shape(tensor) + _strides = ggml.utils.get_strides(tensor) + size = sum(s * _strides[i] for i, s in enumerate(_shape)) + array = np.empty(_shape, dtype=np_dtype) ggml.ggml_backend_tensor_get(tensor, array.ctypes.data_as(ctypes.c_void_p), 0, ggml.ggml_nbytes(tensor)) - return array + return array.reshape(shape) if shape else array def map_to_ggml_type(dtype: npt.DTypeLike): np_data_type_limit = np.dtype(str(dtype).replace("64", "32")) @@ -177,6 +180,7 @@ def ggml_operator_abs(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, ) ctx.ggml_tensors_dict[output_name] = abs_result + ctx.shapes[output_name] = ctx.shapes[node.input[0]] @register_ggml_operator("Add") @@ -193,7 +197,7 @@ def ggml_operator_add(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, b = broadcast_shapes(ctx, a, b) if ggml.utils.GGML_TYPE(a.contents.type) == ggml.utils.GGML_TYPE.I32: np_dtype = get_tensor_dtype(a) - x = np.empty(ctx.get_tensor_shape(a), dtype=np_dtype) + x = np.empty(ctx.shapes[node.input[0]], dtype=np_dtype) x_t = ctx.from_numpy(x) @ggml.ggml_custom3_op_t @@ -224,6 +228,7 @@ def custom_add( b, ) ctx.ggml_tensors_dict[output_name] = add_result + ctx.shapes[output_name] = tuple(reversed(add_result.contents.ne[:max(len(ctx.shapes[node.input[0]]), len(ctx.shapes[node.input[1]]))])) @register_ggml_operator("And") @@ -235,9 +240,9 @@ def ggml_operator_and(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": Operation "And" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) - a_shape = get_tensor_shape(node_inputs[0]) + a_shape = ctx.shapes[node.input[0]] a_dtype = get_tensor_dtype(node_inputs[0]) - b_shape = get_tensor_shape(node_inputs[1]) + b_shape = ctx.shapes[node.input[1]] name = node.output[0] output_shape = np.broadcast(np.empty(a_shape), np.empty(b_shape)).shape @@ -302,7 +307,7 @@ def ggml_operator_arg_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): (attr.i for attr in node.attribute if attr.name == "select_last_index"), 0 ) - x_shape = get_tensor_shape(data) + x_shape = ctx.shapes[node.input[0]] x_dtype = get_tensor_dtype(data) x_ndims = ggml.utils.get_ndims(data) @@ -390,7 +395,7 @@ def ggml_operator_arg_min(ctx: "GgmlOnnxExecutionContext", node: NodeProto): (attr.i for attr in node.attribute if attr.name == "select_last_index"), 0 ) - x_shape = get_tensor_shape(data) + x_shape = self.shapes[node.input[0]] dummpy_data = np.empty(x_shape, dtype=np.int32) @@ -473,7 +478,7 @@ def ggml_operator_cast(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] np_data_type = tensor_dtype_to_np_dtype(onnx_type) np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) - x = np.empty(ctx.get_tensor_shape(a), dtype=np_data_type_limit) + x = np.empty(ctx.shapes[node.input[0]], dtype=np_data_type_limit) x_t = ctx.from_numpy(x) @@ -501,7 +506,7 @@ def custom_cast( 1, ctypes.pointer(onnx_type_c), ) - ctx.set_tensor_shape(new_tensor, ctx.get_tensor_shape(a)) + ctx.set_tensor_shape(new_tensor, ctx.shapes[node.input[0]]) ctx.refs.append(custom_cast) ctx.refs.append(onnx_type_c) @@ -523,7 +528,7 @@ def ggml_operator_castlike(ctx: "GgmlOnnxExecutionContext", node: NodeProto): onnx_type = np_dtype_to_tensor_dtype(np_data_dtype) onnx_type_c = ctypes.c_int(onnx_type) - x = np.empty(get_tensor_shape(a), dtype=np_data_type_limit) + x = np.empty(ctx.shapes[node.input[0]], dtype=np_data_type_limit) x_t = ctx.from_numpy(x) @ggml.ggml_custom2_op_t @@ -567,7 +572,7 @@ def ggml_operator_ceil(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a = node_inputs[0] np_dtype = get_tensor_dtype(a) - x = np.empty(get_tensor_shape(a), dtype=np_dtype) + x = np.empty(ctx.shapes[node.input[0]], dtype=np_dtype) x_t = ctx.from_numpy(x) @ggml.ggml_custom1_op_t @@ -597,7 +602,7 @@ def custom_ceil( def ggml_operator_clip(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] x_t, a_min, a_max = node_inputs - shape = ctx.get_tensor_shape(x_t) + shape = ctx.shapes[node.input[0]] name = node.output[0] @ggml.ggml_custom3_op_t @@ -627,7 +632,7 @@ def ggml_operator_concat(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs = [ctx.ggml_tensors_dict[inp] for inp in node.input] axis = next((attr.i for attr in node.attribute if attr.name == "axis"), 0) - shapes = [ctx.get_tensor_shape(tensor) for tensor in node_inputs] + shapes = [ctx.shapes[input_] for input_ in node.input] if not all( shape[:axis] == shapes[0][:axis] and shape[axis + 1 :] == shapes[0][axis + 1 :] @@ -652,7 +657,7 @@ def custom_concat( x = np.concatenate([a, b], axis=axis) ctx.set_tensor_data(tensor_out, x) - def concat_2(tensor_a, tensor_b): + def concat_2(name, tensor_a, tensor_b): shape_a = ctx.get_tensor_shape(tensor_a) shape_b = ctx.get_tensor_shape(tensor_b) total_dim = shape_a[axis] + shape_b[axis] @@ -675,8 +680,8 @@ def concat_2(tensor_a, tensor_b): ctx.refs.append(custom_concat) new_tensor = ctx.ggml_tensors_dict[node.output[0]] = node_inputs[0] - for tensor in node_inputs[1:]: - new_tensor = concat_2(new_tensor, tensor) + for name, tensor in zip(node.input[1:], node_inputs[1:]): + new_tensor = concat_2(name, new_tensor, tensor) @register_ggml_operator("Constant") @@ -726,31 +731,45 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x_t = ctx.from_numpy(x) - @ggml.ggml_custom2_op_t - def custom_constant( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], - ): - shape = get_tensor_shape(tensor_in_1) - constant_data = ctx.to_numpy(tensor_in_2) - new_tensor = constant_data.reshape(shape) - ctx.set_tensor_data(tensor_out, new_tensor) - - new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_eval_context, - x_t, - data_tensor, - custom_constant, - 1, - None, - ) - ctx.refs.append(custom_constant) - ctx.set_tensor_shape(new_tensor, tensor_shape) - ctx.set_tensor_dtype(name, np_data_type) + ctx.shapes[node.output[0]] = tensor_shape + ctx.ggml_tensors_dict[node.output[0]] = data_tensor + + tensor_in_1 = x_t + tensor_in_2 = data_tensor + + shape = get_tensor_shape(tensor_in_1) + constant_data = ctx.to_numpy(tensor_in_2) + new_tensor = constant_data.reshape(shape) + # ctx.ggml_tensors_dict[node.output[0]] = new_tensor + # ctx.shapes[node.output[0]] = + + # ctx.set_tensor_data(tensor_out, new_tensor) + + # @ggml.ggml_custom2_op_t + # def custom_constant( + # tensor_out: ggml.ggml_tensor_p, + # tensor_in_1: ggml.ggml_tensor_p, + # tensor_in_2: ggml.ggml_tensor_p, + # ith: int, + # nth: int, + # userdata: Optional[ctypes.c_void_p], + # ): + # shape = get_tensor_shape(tensor_in_1) + # constant_data = ctx.to_numpy(tensor_in_2) + # new_tensor = constant_data.reshape(shape) + # ctx.set_tensor_data(tensor_out, new_tensor) + + # new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + # ctx.ggml_eval_context, + # x_t, + # data_tensor, + # custom_constant, + # 1, + # None, + # ) + # ctx.refs.append(custom_constant) + # ctx.set_tensor_shape(new_tensor, tensor_shape) + # ctx.set_tensor_dtype(name, np_data_type) @register_ggml_operator("ConstantOfShape") @@ -2346,11 +2365,15 @@ def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": Operation "MatMul" requires exactly two inputs. Actual number of inputs: {len(node_inputs)}' ) + a_name, b_name = node.input + output_name = node.output[0] a, b = node_inputs b_shape = get_tensor_shape(b) a_shape = get_tensor_shape(a) + a_shape, b_shape = ctx.shapes[a_name], ctx.shapes[b_name] + # TODO: is this check required? broadcast alone wont pass ONNX tests but is broadcasting itself even required or should it fail if a,b are not correct? try: np.matmul(np.empty(a_shape), np.empty(b_shape)) @@ -2397,7 +2420,7 @@ def ggml_operator_mat_mul(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) ctx.ggml_tensors_dict[output_name] = mul_mat_result - + ctx.shapes[output_name] = tuple(reversed(mul_mat_result.contents.ne[:max(len(a_shape), len(b_shape))])) @register_ggml_operator("Max") def ggml_operator_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -2578,6 +2601,7 @@ def custom_mul( ctx.refs.append(custom_mul) ctx.ggml_tensors_dict[output_name] = mul_result + ctx.shapes[output_name] = tuple(reversed(mul_result.contents.ne[:max(len(ctx.shapes[node.input[0]]), len(ctx.shapes[node.input[1]]))])) @register_ggml_operator("Neg") @@ -2699,41 +2723,61 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_inputs += [None] * (4 - len(node_inputs)) x_in, pads, value, axes = node_inputs - input_rank = x_in.contents.n_dims + input_rank = len(ctx.shapes[node.input[0]]) mode = next( (attr.s for attr in node.attribute if attr.name == "mode"), b"constant" ).decode("utf-8") + axes_eval = None if axes is None: - axes = list(range(input_rank)) + axes_list = list(range(input_rank)) else: axes_eval = ctx.eval_tensor(axes) - axes = ctx.to_numpy(axes_eval) - axes = [axis if axis >= 0 else axis + input_rank for axis in axes] - num_axes = len(axes) - pad_width = [] + axes_list = ggml.utils.to_numpy(axes_eval, shape=ctx.shapes[node.input[3]]) + axes_list = [axis if axis >= 0 else axis + input_rank for axis in axes_list] + num_axes = len(axes_list) + pad_width: List[Tuple[int, int]] = [] for _ in range(input_rank): - pad_width += [[0, 0]] # init to zero + pad_width += [(0, 0)] # init to zero + + assert pads is not None + pads_eval = ctx.eval_tensor(pads) + c_ = get_ggml_tensor_data_as_numpy(pads_eval).reshape(ctx.get_tensor_shape(pads_eval)) + a_ = ctx.to_numpy(pads_eval).reshape(ctx.shapes[node.input[1]]) + # c_ = get_ggml_tensor_data_as_numpy(pads_eval).reshape(ctx.get_tensor_shape(pads_eval)) + b_ = ggml.utils.to_numpy(pads_eval, shape=ctx.shapes[node.input[1]]) - raw_pads = ctx.to_numpy(ctx.eval_tensor(pads)) + if np.array_equal(a_, b_): + breakpoint() + + raw_pads = ctx.to_numpy(ctx.eval_tensor(pads)).reshape(ctx.shapes[node.input[1]]) # re-order to np.pad accepted order ((x1_begin, x1_end), (x2_begin, x2_end), ...) for i in range(num_axes): - axis = axes[i] + axis = axes_list[i] if axis < 0: axis = input_rank + axis - pad_width[axis] = [raw_pads[i], raw_pads[i + num_axes]] + if axis > len(pad_width) - 1: + breakpoint() + pad_width[axis] = (raw_pads[i], raw_pads[i + num_axes]) expand_by = [sum(pad) for pad in pad_width] - prev_shape = get_tensor_shape(x_in) + # prev_shape = get_tensor_shape(x_in) + prev_shape = ctx.shapes[node.input[0]] + if any([x > 100 or x < 0 for x in expand_by]): + breakpoint() + output_shape = [sum(x) for x in zip(prev_shape, expand_by)] + assert x_in is not None a_dtype = get_tensor_dtype(x_in) x = np.empty(output_shape, dtype=a_dtype) x_t = ctx.from_numpy(x) - constant_value = None + constant_values = None if value is not None: - constant_values = ctx.to_numpy(ctx.eval_tensor(value)) + constant_values = ctx.to_numpy(ctx.eval_tensor(value)).reshape( + ctx.shapes[node.input[2]] + ) @ggml.ggml_custom2_op_t def custom_pad( @@ -5098,28 +5142,30 @@ def __init__( ggml_eval_context: ggml.ggml_context_p, refs: List[Any], max_tensors: int, + shapes: Dict[str, Tuple[int, ...]], ): self.backend = backend self.ggml_tensors_dict = ggml_tensors_dict self.ggml_eval_context = ggml_eval_context self.refs = refs - self.shapes: Dict[int, Tuple[int, ...]] = {} + self.ggml_tensor_shapes: Dict[int, Tuple[int, ...]] = {} self.dtypes: Dict[str, npt.DTypeLike] = {} self.max_tensors = max_tensors self.ggml_graph = ggml.ggml_new_graph_custom(self.ggml_eval_context, max_tensors, False) self.ggml_graph = None self.n_threads = 8 + self.shapes = shapes def set_tensor_shape(self, tensor: ggml.ggml_tensor_p, shape: Tuple[int, ...]): key = ctypes.addressof(tensor.contents) - self.shapes[key] = shape + self.ggml_tensor_shapes[key] = shape def get_tensor_shape(self, tensor: ggml.ggml_tensor_p) -> Tuple[int, ...]: key = ctypes.addressof(tensor.contents) - if key not in self.shapes: - self.shapes[key] = get_tensor_shape(tensor) - return self.shapes[key] - + if key not in self.ggml_tensor_shapes: + self.ggml_tensor_shapes[key] = get_tensor_shape(tensor) + return self.ggml_tensor_shapes[key] + def set_tensor_dtype(self, name: str, dtype: npt.DTypeLike): self.dtypes[name] = dtype @@ -5137,23 +5183,28 @@ def from_numpy(self, array: npt.NDArray[Any]) -> ggml.ggml_tensor_p: tensor = ggml.utils.from_numpy(array, self.ggml_eval_context) tensor_buffer = ggml.ggml_backend_alloc_buffer(self.backend.ggml_backend, ggml.ggml_nbytes(tensor)) + assert tensor_buffer is not None weakref.finalize(tensor, ggml.ggml_backend_buffer_free, tensor_buffer) tallocr = ggml.ggml_tallocr_new(tensor_buffer) + assert tallocr is not None ggml.ggml_tallocr_alloc(tallocr, tensor) ggml.ggml_tallocr_free(tallocr) if array.size > 0: set_ggml_tensor_data_from_numpy(tensor, array) - self.set_tensor_shape(tensor, shape) return tensor def eval_tensor(self, tensor: ggml.ggml_tensor_p): + if not tensor.contents.src[0]: + return tensor self.ggml_graph = ggml.ggml_new_graph_custom(self.ggml_eval_context, self.max_tensors, False) ggml.ggml_set_output(tensor) ggml.ggml_build_forward_expand(self.ggml_graph, tensor) - gallocr = ggml.ggml_gallocr_new(ggml.ggml_backend_get_default_buffer_type(self.backend.ggml_backend)) + default_buffer_type = ggml.ggml_backend_get_default_buffer_type(self.backend.ggml_backend) + assert default_buffer_type is not None + gallocr = ggml.ggml_gallocr_new(default_buffer_type) if gallocr is None: raise RuntimeError("Failed to create GGML graph allocator") @@ -5166,8 +5217,10 @@ def eval_tensor(self, tensor: ggml.ggml_tensor_p): tensor_copy = ggml.ggml_dup_tensor(self.ggml_eval_context, tensor) tensor_copy_buffer = ggml.ggml_backend_alloc_buffer(self.backend.ggml_backend, ggml.ggml_nbytes(tensor_copy)) + assert tensor_copy_buffer is not None weakref.finalize(tensor_copy, ggml.ggml_backend_buffer_free, tensor_copy_buffer) tallocr = ggml.ggml_tallocr_new(tensor_copy_buffer) + assert tallocr is not None ggml.ggml_tallocr_alloc(tallocr, tensor_copy) ggml.ggml_backend_tensor_copy(tensor, tensor_copy) @@ -5176,8 +5229,6 @@ def eval_tensor(self, tensor: ggml.ggml_tensor_p): ggml.ggml_tallocr_free(tallocr) ggml.ggml_gallocr_free(gallocr) - self.set_tensor_shape(tensor_copy, self.get_tensor_shape(tensor)) - return tensor_copy def set_tensor_data(self, tensor: ggml.ggml_tensor_p, array: npt.NDArray[Any]): @@ -5191,6 +5242,7 @@ def __init__( weights: Dict[str, ggml.ggml_tensor_p], inputs: Sequence[ValueInfoProto], outputs: Sequence[ValueInfoProto], + shapes: Dict[str, Tuple[int, ...]], ggml_context: ggml.ggml_context_p, ggml_init_params: ggml.ggml_init_params, ggml_backend: ggml.ggml_backend_t, @@ -5201,6 +5253,7 @@ def __init__( self.weights = weights self.inputs = inputs self.outputs = outputs + self.shapes = shapes self.ggml_context = ggml_context self.ggml_init_params = ggml_init_params self.ggml_backend = ggml_backend @@ -5233,9 +5286,10 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: model_graph = self.graph exit_node = None ggml_tensors = self.weights.copy() + shapes = self.shapes.copy() ggml_input_context = ggml.ggml_init( - params=ggml.ggml_init_params( + ggml.ggml_init_params( mem_size=2 * ggml.GGML_DEFAULT_GRAPH_SIZE * ggml.ggml_tensor_overhead(), # FIXME: Reduce to n inputs or combine with tensors context @@ -5250,6 +5304,8 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: input_name = model_input.name input_data = np.array(inputs[input_name]) + shapes[input_name] = input_data.shape + # Check if the input includes expected values if input_name not in inputs: raise KeyError(f'"{input_name}" must be included in the inputs.') @@ -5287,6 +5343,8 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: len(shape), (ctypes.c_int64 * len(shape))(*shape), ) + ggml.ggml_set_input(tensor) + ggml.ggml_set_output(tensor) ggml_tensors[input_name] = tensor @@ -5302,7 +5360,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: max_overhead = ggml.ggml_tensor_overhead() * max_tensors + ggml.ggml_graph_overhead_custom(max_tensors, False) mem_buffer = (ctypes.c_uint8 * max_overhead)() ggml_eval_context = ggml.ggml_init( - params=ggml.ggml_init_params( + ggml.ggml_init_params( mem_size=max_overhead, mem_buffer=ctypes.cast(mem_buffer, ctypes.c_void_p), no_alloc=True ) ) @@ -5314,7 +5372,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: output_names = [output.name for output in model_graph.output] - ctx = GgmlOnnxExecutionContext(self, ggml_tensors, ggml_eval_context, refs, max_tensors) + ctx = GgmlOnnxExecutionContext(self, ggml_tensors, ggml_eval_context, refs, max_tensors, shapes) # Build layers outputs: Dict[str, ggml.ggml_tensor_p] = {} @@ -5337,7 +5395,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: for output in self.outputs: exit_node = outputs[output.name] # NOTE: 0 dimension in ggml may cause bugs - max_tensors = np.prod(ctx.get_tensor_shape(exit_node)) + max_tensors = np.prod(ctx.shapes[output.name]) graph_output: npt.NDArray[Any] = ( ctx.to_numpy(exit_node) if max_tensors > 0 else np.empty((0)) ) # TODO: Add checks to convert values back to bool or etc types @@ -5345,7 +5403,8 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ctx.get_tensor_dtype(output.name) ) # TODO: add a second dict to keep track of types and use that instead - shape = ctx.get_tensor_shape(exit_node) + shape = ctx.shapes.get(output.name, ctx.get_tensor_shape(exit_node)) + # shape = ctx.get_tensor_shape(exit_node) graph_output = graph_output.reshape(shape) graph_outputs.append(graph_output) @@ -5382,6 +5441,7 @@ def prepare(cls, model: ModelProto, device: Optional[str] = "CPU", **kwargs: Any graph = model.graph weights: Dict[str, ggml.ggml_tensor_p] = {} + shapes: Dict[str, Tuple[int, ...]] = {} n_tensors = len(graph.initializer) ggml_init_params = ggml.ggml_init_params( @@ -5399,8 +5459,9 @@ def prepare(cls, model: ModelProto, device: Optional[str] = "CPU", **kwargs: Any name = initializer.name np_array: npt.NDArray[Any] = onnx.numpy_helper.to_array(initializer) # type: ignore tensor = ggml.utils.from_numpy(x=np_array, ctx=ggml_weights_context) - ggml.ggml_set_name(tensor=tensor, name=name.encode()) + ggml.ggml_set_name(tensor, name.encode()) weights[name] = tensor + shapes[name] = np_array.shape pairs.append((tensor, initializer)) ggml_weights_buffer = ggml.ggml_backend_alloc_ctx_tensors(ggml_weights_context, ggml_backend) @@ -5414,6 +5475,7 @@ def prepare(cls, model: ModelProto, device: Optional[str] = "CPU", **kwargs: Any weights=weights, inputs=graph.input, outputs=graph.output, + shapes=shapes, ggml_context=ggml_weights_context, ggml_init_params=ggml_init_params, ggml_backend=ggml_backend, From 7c8d10fd5b5cc68fedea2e9ace652d224a2edeee Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 28 Feb 2024 13:10:28 -0500 Subject: [PATCH 225/232] Add simple parameterized test to compare runtimes --- tests/test_ggml_onnx.py | 117 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 4 deletions(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index ae1a011f..1c0a8815 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -1,6 +1,8 @@ import io import numpy as np +import numpy.typing as npt + import onnx from onnx import helper from onnx.onnx_pb import TensorProto @@ -11,6 +13,10 @@ from ggml.contrib.onnx import GgmlRuntimeBackend +import typing +import onnx.onnx_pb as onnx_pb + +import pytest def test_ggml_onnx_runtime_basic(): # The name of the input tensor @@ -87,10 +93,113 @@ def test_ggml_onnx_runtime_basic(): assert ggml_result == runtime_result -def test_ggml_onnx_graph_optimization(): - # Construct an onnx graph and optimize it - # The graph is of the form y = (A^T)^T * x + b - # the optimization should remove the transpose operations +class OnnxModelBuilder: + """Helper class to build ONNX models.""" + + def __init__(self, name: str): + self.name = name + self.nodes: typing.List[onnx_pb.NodeProto] = [] + self.inputs: typing.List[onnx_pb.ValueInfoProto] = [] + self.outputs: typing.List[onnx_pb.ValueInfoProto] = [] + self.initializers: typing.List[onnx_pb.TensorProto] = [] + self.counter = 0 # Counter for unique names + + def add_input( + self, + name: str, + elem_type: int, + shape: typing.Optional[typing.List[typing.Union[str, int, None]]], + ): + self.inputs.append(helper.make_tensor_value_info(name, elem_type, shape)) + return self + + def add_node( + self, + op_type: str, + inputs: typing.List[str], + outputs: typing.List[str], + name: typing.Optional[str] = None, + ): + if name is None: + name = f"node{self.counter}" + self.counter += 1 + self.nodes.append(helper.make_node(op_type, inputs, outputs, name=name)) + return self + + def add_initializer( + self, name: str, data_type: int, dims: typing.Sequence[int], vals: typing.Any + ): + self.initializers.append(helper.make_tensor(name, data_type, dims, vals)) + return self + + def add_output( + self, name: str, elem_type: int, shape: typing.Optional[typing.List[typing.Union[str, int, None]]] + ): + self.outputs.append(helper.make_tensor_value_info(name, elem_type, shape)) + return self + + def build_graph(self): + return helper.make_graph( + self.nodes, self.name, self.inputs, self.outputs, self.initializers + ) + + def build_model(self, name: typing.Optional[str] = None): + return helper.make_model(self.build_graph(), producer_name=name or self.name) + + @staticmethod + def model_bytes(model: onnx_pb.ModelProto) -> bytes: + f = io.BytesIO() + onnx.save(model, f) + return f.getvalue() + + +def build_simple_graph(): + builder = OnnxModelBuilder("simple_expression_model") + builder.add_input("X", TensorProto.FLOAT, [None, 1]) + builder.add_initializer("A", TensorProto.FLOAT, [1], np.ones(1, dtype=float).astype(np.float32)) + builder.add_initializer("B", TensorProto.FLOAT, [1], np.ones(1, dtype=float).astype(np.float32)) + builder.add_node("Mul", ["X", "X"], ["X_squared"]) + builder.add_node("Mul", ["X_squared", "A"], ["X_squared_times_a"]) + builder.add_node("Add", ["X_squared_times_a", "B"], ["Y"]) + builder.add_output("Y", TensorProto.FLOAT, [None, 1]) + return builder.build_model() + + +def build_2d_graph(): + builder = OnnxModelBuilder("simple_expression_model") + builder.add_input("X", TensorProto.FLOAT, [None, 2]) + builder.add_initializer("A", TensorProto.FLOAT, [2], np.ones(2, dtype=float).astype(np.float32)) + builder.add_initializer("B", TensorProto.FLOAT, [2], np.ones(2, dtype=float).astype(np.float32)) + builder.add_node("Mul", ["X", "X"], ["X_squared"]) + builder.add_node("Mul", ["X_squared", "A"], ["X_squared_times_a"]) + builder.add_node("Add", ["X_squared_times_a", "B"], ["Y"]) + builder.add_output("Y", TensorProto.FLOAT, [None, 2]) + return builder.build_model() + +def build_matmul_graph(): + builder = OnnxModelBuilder("simple_expression_model") + builder.add_input("X", TensorProto.FLOAT, [None, 2]) + builder.add_initializer("A", TensorProto.FLOAT, [2, 3], np.ones((2, 3), dtype=float).astype(np.float32)) + builder.add_initializer("B", TensorProto.FLOAT, [3, 4], np.ones((3, 4), dtype=float).astype(np.float32)) + builder.add_node("MatMul", ["X", "A"], ["X_times_A"]) + builder.add_node("MatMul", ["X_times_A", "B"], ["Y"]) + builder.add_output("Y", TensorProto.FLOAT, [None, 4]) + return builder.build_model() + + +@pytest.mark.parametrize( + "model, input_data", [ + # (build_simple_graph(), {"X": np.array([[6.0]], dtype=np.float32)}), + # (build_2d_graph(), {"X": np.array([[6.0, 7.0]], dtype=np.float32)}), + (build_matmul_graph(), {"X": np.array([[6.0, 7.0]], dtype=np.float32)}), + ] +) +def test_compare_runtimes(model: onnx_pb.ModelProto, input_data: typing.Dict[str, npt.NDArray[typing.Any]]): + runtime_result = InferenceSession(OnnxModelBuilder.model_bytes(model)).run(None, input_data) # type: ignore + ggml_dummy_model = GgmlRuntimeBackend.prepare(model) + ggml_result = ggml_dummy_model.run(input_data) + assert np.array_equal(ggml_result, runtime_result) + # The name of the input tensor input_name = "x" From 7d3c8eeca971bb4ad85990d8e0b7a529459a4d10 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Wed, 28 Feb 2024 14:23:54 -0500 Subject: [PATCH 226/232] Add shape tracking to more ops --- ggml/contrib/onnx.py | 64 ++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 190d31ca..0feff363 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -2335,6 +2335,7 @@ def ggml_operator_log(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, ) ctx.ggml_tensors_dict[output_name] = log_result + ctx.shapes[output_name] = ctx.shapes[node.input[0]] @register_ggml_operator("LogSoftmax") @@ -2354,6 +2355,7 @@ def ggml_operator_log_soft_max(ctx: "GgmlOnnxExecutionContext", node: NodeProto) soft_max_result, ) ctx.ggml_tensors_dict[output_name] = log_result + ctx.shapes[output_name] = ctx.shapes[node.input[0]] @register_ggml_operator("MatMul") @@ -2621,6 +2623,7 @@ def ggml_operator_neg(ctx: "GgmlOnnxExecutionContext", node: NodeProto): x, ) ctx.ggml_tensors_dict[output_name] = x_neg + ctx.shapes[output_name] = ctx.shapes[node.input[0]] @register_ggml_operator("Not") @@ -2733,22 +2736,14 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axes_list = list(range(input_rank)) else: axes_eval = ctx.eval_tensor(axes) - axes_list = ggml.utils.to_numpy(axes_eval, shape=ctx.shapes[node.input[3]]) - axes_list = [axis if axis >= 0 else axis + input_rank for axis in axes_list] + axes_array = ctx.to_numpy(axes_eval).reshape(ctx.shapes[node.input[3]]) + axes_list = [axis if axis >= 0 else axis + input_rank for axis in axes_array] num_axes = len(axes_list) pad_width: List[Tuple[int, int]] = [] for _ in range(input_rank): pad_width += [(0, 0)] # init to zero assert pads is not None - pads_eval = ctx.eval_tensor(pads) - c_ = get_ggml_tensor_data_as_numpy(pads_eval).reshape(ctx.get_tensor_shape(pads_eval)) - a_ = ctx.to_numpy(pads_eval).reshape(ctx.shapes[node.input[1]]) - # c_ = get_ggml_tensor_data_as_numpy(pads_eval).reshape(ctx.get_tensor_shape(pads_eval)) - b_ = ggml.utils.to_numpy(pads_eval, shape=ctx.shapes[node.input[1]]) - - if np.array_equal(a_, b_): - breakpoint() raw_pads = ctx.to_numpy(ctx.eval_tensor(pads)).reshape(ctx.shapes[node.input[1]]) @@ -2757,17 +2752,13 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): axis = axes_list[i] if axis < 0: axis = input_rank + axis - if axis > len(pad_width) - 1: - breakpoint() pad_width[axis] = (raw_pads[i], raw_pads[i + num_axes]) expand_by = [sum(pad) for pad in pad_width] - # prev_shape = get_tensor_shape(x_in) prev_shape = ctx.shapes[node.input[0]] - if any([x > 100 or x < 0 for x in expand_by]): - breakpoint() output_shape = [sum(x) for x in zip(prev_shape, expand_by)] + ctx.shapes[node.output[0]] = tuple(output_shape) assert x_in is not None a_dtype = get_tensor_dtype(x_in) x = np.empty(output_shape, dtype=a_dtype) @@ -2789,23 +2780,22 @@ def custom_pad( userdata: Optional[ctypes.c_void_p], ): a = ctx.to_numpy(tensor_in_2) - if mode == "constant": - x = np.pad( - a, - pad_width=pad_width, - mode=mode, - constant_values=constant_values, - ) - - else: - x = np.pad( - a, - pad_width=pad_width, - mode=mode, - ) - ctx.set_tensor_data(tensor_out, x) - - new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + # if mode == "constant": + # x = np.pad( + # a, + # pad_width=pad_width, + # mode=mode, + # # constant_values=constant_values, + # ) + # else: + # x = np.pad( + # a, + # pad_width=pad_width, + # mode=mode, + # ) + ctx.set_tensor_data(tensor_out, a) + + ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( ctx.ggml_eval_context, x_t, x_in, @@ -4169,7 +4159,7 @@ def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": Operation "Shape" requires exactly one input. Actual number of inputs: {len(node_inputs)}' ) - tensor_shape = np.array(get_tensor_shape(node_inputs[0]), dtype=np.int32) + tensor_shape = np.array(ctx.shapes[node.input[0]], dtype=np.int32) name = node.output[0] start = next((attr.i for attr in node.attribute if attr.name == "start"), None) end = next( @@ -4177,9 +4167,9 @@ def ggml_operator_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): None, ) shape_slice = tensor_shape[start:end] - new_tensor = ctx.ggml_tensors_dict[name] = ctx.from_numpy(shape_slice) - + ctx.ggml_tensors_dict[name] = ctx.from_numpy(shape_slice) ctx.set_tensor_dtype(name, np.dtype(np.int64)) + ctx.shapes[node.output[0]] = (len(shape_slice),) @register_ggml_operator("Sigmoid") @@ -4692,6 +4682,7 @@ def custom_squeeze( ) ctx.set_tensor_shape(new_tensor, dummy_data.shape) ctx.refs.append(custom_squeeze) + ctx.shapes[node.output[0]] = dummy_data.shape @register_ggml_operator("Sub") @@ -4713,6 +4704,7 @@ def ggml_operator_sub(ctx: "GgmlOnnxExecutionContext", node: NodeProto): b, ) ctx.ggml_tensors_dict[output_name] = sub_result + ctx.shapes[output_name] = ctx.shapes[node.input[0]] # TODO: Wrong @register_ggml_operator("Sum") @@ -4740,6 +4732,7 @@ def ggml_operator_sum(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) ctx.ggml_tensors_dict[output_name] = next_item + ctx.shapes[output_name] = ctx.shapes[node.input[0]] @register_ggml_operator("Tanh") @@ -5043,6 +5036,7 @@ def custom_unsqueeze( None, ) ctx.refs.append(custom_unsqueeze) + ctx.shapes[node.output[0]] = new_shape @register_ggml_operator("Where") From 207ff2e3686f0d38fe0e652207bf3baa657f4f53 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sun, 3 Mar 2024 13:49:24 -0500 Subject: [PATCH 227/232] Fix more onnx ops --- ggml/contrib/onnx.py | 310 ++++------- tests/test_ggml_onnx.py | 1071 ++++++++++++++++++++------------------- 2 files changed, 636 insertions(+), 745 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 0feff363..12d2f4e0 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -32,6 +32,9 @@ def set_ggml_tensor_data_from_numpy( tensor: ggml.ggml_tensor_p, array: npt.NDArray[Any] ): + array = array.astype(np.int32) if array.dtype == np.int64 else array + array = array.astype(np.float32) if array.dtype == np.float64 else array + array = array.astype(np.int8) if array.dtype == np.bool_ else array ggml.ggml_backend_tensor_set( tensor, array.ctypes.data_as(ctypes.c_void_p), @@ -687,7 +690,6 @@ def concat_2(name, tensor_a, tensor_b): @register_ggml_operator("Constant") def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): node_attributes = node.attribute - name = node.output[0] value_attr = next(attr for attr in node_attributes if "value" in attr.name) if value_attr.HasField("t"): @@ -727,50 +729,9 @@ def ggml_operator_constant(ctx: "GgmlOnnxExecutionContext", node: NodeProto): tensor_shape = data_value.shape - x = np.empty(tensor_shape, dtype=np_data_type_limit) - - x_t = ctx.from_numpy(x) - ctx.shapes[node.output[0]] = tensor_shape ctx.ggml_tensors_dict[node.output[0]] = data_tensor - tensor_in_1 = x_t - tensor_in_2 = data_tensor - - shape = get_tensor_shape(tensor_in_1) - constant_data = ctx.to_numpy(tensor_in_2) - new_tensor = constant_data.reshape(shape) - # ctx.ggml_tensors_dict[node.output[0]] = new_tensor - # ctx.shapes[node.output[0]] = - - # ctx.set_tensor_data(tensor_out, new_tensor) - - # @ggml.ggml_custom2_op_t - # def custom_constant( - # tensor_out: ggml.ggml_tensor_p, - # tensor_in_1: ggml.ggml_tensor_p, - # tensor_in_2: ggml.ggml_tensor_p, - # ith: int, - # nth: int, - # userdata: Optional[ctypes.c_void_p], - # ): - # shape = get_tensor_shape(tensor_in_1) - # constant_data = ctx.to_numpy(tensor_in_2) - # new_tensor = constant_data.reshape(shape) - # ctx.set_tensor_data(tensor_out, new_tensor) - - # new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - # ctx.ggml_eval_context, - # x_t, - # data_tensor, - # custom_constant, - # 1, - # None, - # ) - # ctx.refs.append(custom_constant) - # ctx.set_tensor_shape(new_tensor, tensor_shape) - # ctx.set_tensor_dtype(name, np_data_type) - @register_ggml_operator("ConstantOfShape") def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): @@ -787,7 +748,6 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP tensor = value_attr.t data_type = tensor.data_type np_data_type = tensor_dtype_to_np_dtype(data_type) - np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) if tensor.raw_data: data_value = np.frombuffer(tensor.raw_data, dtype=np_data_type) @@ -797,7 +757,6 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP else: data_type = value_attr.type np_data_type = tensor_dtype_to_np_dtype(data_type) - np_data_type_limit = np.dtype(str(np_data_type).replace("64", "32")) if np.issubdtype(np_data_type, np.floating): data_value = np.array(value_attr.f) elif np.issubdtype(np_data_type, np.integer): @@ -807,37 +766,13 @@ def ggml_operator_constant_of_shape(ctx: "GgmlOnnxExecutionContext", node: NodeP f'Error for node "{node.name}": Constant node not set correctly or incomplete implantation.' ) - data_tensor = ctx.from_numpy(data_value.astype(np_data_type_limit)) node_inputs_0 = ctx.eval_tensor(node_inputs[0]) - shape = ctx.to_numpy(node_inputs_0) - x = np.empty(shape, dtype=np_data_type_limit) - x_t = ctx.from_numpy(x) - - @ggml.ggml_custom2_op_t - def custom_constant_of_shape( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], - ): - shape = get_tensor_shape(tensor_out) - value = ctx.to_numpy(tensor_in_2) - new_tenor = np.full(tuple(shape), value) - - ctx.set_tensor_data(tensor_out, new_tenor) - - new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_eval_context, - x_t, - data_tensor, - custom_constant_of_shape, - 1, - None, - ) - - ctx.refs.append(custom_constant_of_shape) + shape = tuple(ctx.to_numpy(node_inputs_0).reshape(ctx.shapes[node.input[0]])) + value = data_value[0] + new_tensor = np.full(shape, value) + x_t = ctx.from_numpy(new_tensor) + ctx.ggml_tensors_dict[node.output[0]] = x_t + ctx.shapes[node.output[0]] = shape @register_ggml_operator("Cos") @@ -2724,86 +2659,91 @@ def ggml_operator_pad(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) node_inputs += [None] * (4 - len(node_inputs)) - x_in, pads, value, axes = node_inputs + data, pads, value, axes = node_inputs + output_name = node.output[0] - input_rank = len(ctx.shapes[node.input[0]]) + input_shape = ctx.shapes[node.input[0]] + input_rank = len(input_shape) mode = next( (attr.s for attr in node.attribute if attr.name == "mode"), b"constant" ).decode("utf-8") + # axes axes_eval = None if axes is None: - axes_list = list(range(input_rank)) + axes_ = list(range(input_rank)) else: axes_eval = ctx.eval_tensor(axes) - axes_array = ctx.to_numpy(axes_eval).reshape(ctx.shapes[node.input[3]]) - axes_list = [axis if axis >= 0 else axis + input_rank for axis in axes_array] - num_axes = len(axes_list) - pad_width: List[Tuple[int, int]] = [] - for _ in range(input_rank): - pad_width += [(0, 0)] # init to zero + axes_shape = ctx.shapes[node.input[3]] + axes_array = ctx.to_numpy(axes_eval).reshape(axes_shape) + axes_ = [axis if axis >= 0 else axis + input_rank for axis in axes_array] + assert pads is not None - raw_pads = ctx.to_numpy(ctx.eval_tensor(pads)).reshape(ctx.shapes[node.input[1]]) + pads_eval = ctx.eval_tensor(pads) + pads_shape = ctx.shapes[node.input[1]] + pads_ = ctx.to_numpy(pads_eval).reshape(pads_shape) + # pads is in format [x1_begin, x2_begin, ... x1_end, x2_end, ...] # re-order to np.pad accepted order ((x1_begin, x1_end), (x2_begin, x2_end), ...) + num_axes = len(axes_) + pad_width: List[Tuple[int, int]] = [(0, 0) for _ in range(input_rank)] for i in range(num_axes): - axis = axes_list[i] + axis = axes_[i] if axis < 0: axis = input_rank + axis - pad_width[axis] = (raw_pads[i], raw_pads[i + num_axes]) + pad_width[axis] = (pads_[i], pads_[i + num_axes]) expand_by = [sum(pad) for pad in pad_width] - prev_shape = ctx.shapes[node.input[0]] + prev_shape = input_shape output_shape = [sum(x) for x in zip(prev_shape, expand_by)] - ctx.shapes[node.output[0]] = tuple(output_shape) - assert x_in is not None - a_dtype = get_tensor_dtype(x_in) + assert data is not None + a_dtype = get_tensor_dtype(data) x = np.empty(output_shape, dtype=a_dtype) - x_t = ctx.from_numpy(x) + output_shape_tracker = ctx.from_numpy(x) constant_values = None if value is not None: - constant_values = ctx.to_numpy(ctx.eval_tensor(value)).reshape( - ctx.shapes[node.input[2]] - ) + value_shape = ctx.shapes[node.input[2]] + constant_values = ctx.to_numpy(ctx.eval_tensor(value)).reshape(value_shape) @ggml.ggml_custom2_op_t def custom_pad( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, + dst: ggml.ggml_tensor_p, + a: ggml.ggml_tensor_p, + b: ggml.ggml_tensor_p, ith: int, nth: int, userdata: Optional[ctypes.c_void_p], ): - a = ctx.to_numpy(tensor_in_2) - # if mode == "constant": - # x = np.pad( - # a, - # pad_width=pad_width, - # mode=mode, - # # constant_values=constant_values, - # ) - # else: - # x = np.pad( - # a, - # pad_width=pad_width, - # mode=mode, - # ) - ctx.set_tensor_data(tensor_out, a) - - ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + b_array = ctx.to_numpy(b).reshape(input_shape) + if mode == "constant": + padded = np.pad( + b_array, + pad_width=pad_width, + mode=mode, + constant_values=constant_values, + ) # type: ignore + else: + padded = np.pad( + b_array, + pad_width=pad_width, + mode=mode, + ) # type: ignore + ctx.set_tensor_data(dst, padded) + + ctx.ggml_tensors_dict[output_name] = ggml.ggml_map_custom2( ctx.ggml_eval_context, - x_t, - x_in, + output_shape_tracker, + data, custom_pad, 1, None, ) ctx.refs.append(custom_pad) + ctx.shapes[output_name] = tuple(output_shape) @register_ggml_operator("PRelu") @@ -3930,33 +3870,11 @@ def ggml_operator_reshape(ctx: "GgmlOnnxExecutionContext", node: NodeProto): keep_idxs = np.where(new_shape == 0)[0] new_shape[keep_idxs] = np.array(old_shape)[keep_idxs] + temp_a = np.empty(old_shape, dtype=get_tensor_dtype(a)) x = temp_a.reshape(new_shape) - x_t = ctx.from_numpy(x) - - @ggml.ggml_custom2_op_t - def custom_reshape( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], - ): - x = ctx.to_numpy(tensor_in_2) - x_reshape = np.reshape(x, new_shape) - ctx.set_tensor_data(tensor_out, x_reshape) - - new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( - ctx.ggml_eval_context, - x_t, - a, - custom_reshape, - 1, - None, - ) - - ctx.refs.append(custom_reshape) + ctx.shapes[node.output[0]] = x.shape + ctx.ggml_tensors_dict[node.output[0]] = a @register_ggml_operator("Resize") @@ -4273,32 +4191,8 @@ def ggml_operator_size(ctx: "GgmlOnnxExecutionContext", node: NodeProto): ) # Add a rank so ggml doesnt break the value, inside the custom reshape to scalar as expected TODO: Fix the ranking, ggml skalars or make sure broadcasting works fine tensor_size_t = ctx.from_numpy(np.array([tensor_size_np])) - ggml_type = map_to_ggml_type(tensor_size_np.dtype).value - x = np.empty(tensor_shape, dtype=tensor_size_np.dtype) - x_t = ctx.from_numpy(x) - - @ggml.ggml_custom2_op_t - def custom_size( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], - ): - tensor = ctx.to_numpy(tensor_in_2) - ctx.set_tensor_data(tensor_out, tensor) - - new_tensor = ctx.ggml_tensors_dict[name] = ggml.ggml_map_custom2_inplace( - ctx.ggml_eval_context, - x_t, - tensor_size_t, - custom_size, - 1, - None, - ) - - ctx.refs.append(custom_size) + ctx.ggml_tensors_dict[name] = tensor_size_t + ctx.shapes[name] = (1,) ctx.set_tensor_dtype(name, np.dtype(np.int64)) @@ -4354,9 +4248,10 @@ def custom_slice( ctx.set_tensor_data(tensor_out, y) - new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2_inplace( + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom2( ctx.ggml_eval_context, x_t, node_inputs[0], custom_slice, 1, None ) + ctx.shapes[node.output[0]] = x.shape ctx.refs.append(custom_slice) @@ -4377,6 +4272,7 @@ def ggml_operator_softmax(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, ) ctx.ggml_tensors_dict[output_name] = soft_max_result + ctx.shapes[output_name] = ctx.shapes[node.input[0]] @register_ggml_operator("Softplus") @@ -4627,6 +4523,7 @@ def ggml_operator_sqrt(ctx: "GgmlOnnxExecutionContext", node: NodeProto): a, ) ctx.ggml_tensors_dict[output_name] = sqrt_result + ctx.shapes[output_name] = ctx.shapes[node.input[0]] @register_ggml_operator("Squeeze") @@ -4950,7 +4847,7 @@ def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): output_name = node.output[0] x = node_inputs[0] - input_shape = get_tensor_shape(x) + input_shape = ctx.shapes[node.input[0]] perm_attr = next((attr for attr in node.attribute if attr.name == "perm"), None) @@ -4959,6 +4856,13 @@ def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): else: perms = list(perm_attr.ints) + print("perms", perms) + + if len(set(perms)) != len(perms): + raise ValueError( + f'Error for node "{node.name}": Duplicate axes in "perm" attribute' + ) + # TODO: This can probably be simplified idxs = list(reversed(range(len(perms)))) new_idxs = [-1] * len(perms) @@ -4966,9 +4870,13 @@ def ggml_operator_transpose(ctx: "GgmlOnnxExecutionContext", node: NodeProto): new_idxs[ax] = idxs[idx] axes = list(reversed(new_idxs)) + list(range(4)[len(perms) :]) + print("axes", axes) + + ndims = len(input_shape) ax0, ax1, ax2, ax3 = axes transpose_result = ggml.ggml_permute(ctx.ggml_eval_context, x, ax0, ax1, ax2, ax3) ctx.ggml_tensors_dict[output_name] = transpose_result + ctx.shapes[output_name] = tuple(reversed(transpose_result.contents.ne[:ndims])) @register_ggml_operator("Unsqueeze") @@ -4983,9 +4891,9 @@ def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): data = node_inputs[0] axes_input = node_inputs[1] - x_shape = ctx.get_tensor_shape(data) + x_shape = ctx.shapes[node.input[0]] x_dtype = get_tensor_dtype(data) - x_ndims = ggml.utils.get_ndims(data) + x_ndims = len(x_shape) axes_eval = ctx.eval_tensor( axes_input, @@ -5004,39 +4912,9 @@ def ggml_operator_unsqueeze(ctx: "GgmlOnnxExecutionContext", node: NodeProto): raise ValueError( f'Error for node "{node.name}": {len(new_shape)}D arrays are not allowed.' ) - x_t = ctx.from_numpy(x) - - @ggml.ggml_custom3_op_t - def custom_unsqueeze( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, - ith: int, - nth: int, - userdata: Optional[ctypes.c_void_p], - ): - x = ctx.to_numpy(tensor_in_2) - axes = ctx.to_numpy(tensor_in_3) - - axes_values = [ax if ax >= 0 else ax + x.ndim + 1 for ax in axes] - axes_values.sort() - axes_values = np.array(axes_values) - for axis in axes_values: - x = np.expand_dims(x, axis=axis) - ctx.set_tensor_data(tensor_out, x) - new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( - ctx.ggml_eval_context, - x_t, - data, - axes_input, - custom_unsqueeze, - 1, - None, - ) - ctx.refs.append(custom_unsqueeze) ctx.shapes[node.output[0]] = new_shape + ctx.ggml_tensors_dict[node.output[0]] = data @register_ggml_operator("Where") @@ -5048,24 +4926,29 @@ def ggml_operator_where(ctx: "GgmlOnnxExecutionContext", node: NodeProto): f'Error for node "{node.name}": Operation "Where" requires exactly three inputs. Actual number of inputs: {len(node_inputs)}' ) + c_shape, x_shape, y_shape = ctx.shapes[node.input[0]], ctx.shapes[node.input[1]], ctx.shapes[node.input[2]] + output_shape = np.broadcast_shapes( + c_shape, x_shape, y_shape + ) + @ggml.ggml_custom3_op_t def custom_where( - tensor_out: ggml.ggml_tensor_p, - tensor_in_1: ggml.ggml_tensor_p, - tensor_in_2: ggml.ggml_tensor_p, - tensor_in_3: ggml.ggml_tensor_p, + dst: ggml.ggml_tensor_p, + a: ggml.ggml_tensor_p, + b: ggml.ggml_tensor_p, + c: ggml.ggml_tensor_p, ith: int, nth: int, userdata: Optional[ctypes.c_void_p], ): - y = ctx.to_numpy(tensor_in_1) - x = ctx.to_numpy(tensor_in_2) + y = ctx.to_numpy(a).reshape(y_shape) + x = ctx.to_numpy(b).reshape(x_shape) + condition_array = ctx.to_numpy(c).reshape(c_shape) - condition_array = ctx.to_numpy(tensor_in_3) new_tensor = np.where(condition_array, x, y) - ctx.set_tensor_data(tensor_out, new_tensor) + ctx.set_tensor_data(dst, new_tensor) - new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom3_inplace( + new_tensor = ctx.ggml_tensors_dict[node.output[0]] = ggml.ggml_map_custom3( ctx.ggml_eval_context, node_inputs[2], node_inputs[1], @@ -5074,6 +4957,7 @@ def custom_where( 1, None, ) + ctx.shapes[node.output[0]] = output_shape ctx.refs.append(custom_where) @@ -5145,7 +5029,7 @@ def __init__( self.ggml_tensor_shapes: Dict[int, Tuple[int, ...]] = {} self.dtypes: Dict[str, npt.DTypeLike] = {} self.max_tensors = max_tensors - self.ggml_graph = ggml.ggml_new_graph_custom(self.ggml_eval_context, max_tensors, False) + # self.ggml_graph = ggml.ggml_new_graph_custom(self.ggml_eval_context, max_tensors, False) self.ggml_graph = None self.n_threads = 8 self.shapes = shapes @@ -5183,6 +5067,8 @@ def from_numpy(self, array: npt.NDArray[Any]) -> ggml.ggml_tensor_p: assert tallocr is not None ggml.ggml_tallocr_alloc(tallocr, tensor) ggml.ggml_tallocr_free(tallocr) + ggml.ggml_set_input(tensor) + ggml.ggml_set_output(tensor) if array.size > 0: set_ggml_tensor_data_from_numpy(tensor, array) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index 1c0a8815..dd991840 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -201,438 +201,443 @@ def test_compare_runtimes(model: onnx_pb.ModelProto, input_data: typing.Dict[str assert np.array_equal(ggml_result, runtime_result) - # The name of the input tensor - input_name = "x" - - # The name of the weights tensor - weight_name_a = "A" - weight_name_b = "b" - - # The name of the output - output_name = "y" - - # Create the nodes (operations) in our graph - node1 = helper.make_node( - "Transpose", [weight_name_a], ["A_transposed"], name="node1" - ) # A^T - node2 = helper.make_node( - "Transpose", ["A_transposed"], ["A_transposed_transposed"], name="node2" - ) # (A^T)^T - node3 = helper.make_node( - "MatMul", [input_name, "A_transposed_transposed"], ["x_times_A"], name="node3" - ) # x * (A^T)^T - node4 = helper.make_node( - "Add", ["x_times_A", weight_name_b], [output_name], name="node4" - ) # x * (A^T)^T + b - - # Define the tensors (values) in our graph - X_value_info = helper.make_tensor_value_info( - input_name, TensorProto.FLOAT, [None, 32] - ) - - output_value_info = helper.make_tensor_value_info( - output_name, TensorProto.FLOAT, [None, 32] - ) - - # Set A and b as parameters/weights - weights_a = np.random.randn(32, 32).astype(np.float32) - - weights_b = np.random.randn(32).astype(np.float32) - - A_init = helper.make_tensor( - weight_name_a, - TensorProto.FLOAT, - [ - 32, - 32, - ], - weights_a, - ) - B_init = helper.make_tensor( - weight_name_b, - TensorProto.FLOAT, - [ - 32, - ], - weights_b, - ) - - # Create the graph (model). - graph_def = helper.make_graph( - [node1, node2, node3, node4], - "simple_expression_model", - [X_value_info], - [output_value_info], - [A_init, B_init], - ) - - model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") - - from typing import Optional, List - from ggml.contrib.onnx import OnnxGraphRuleEngine, OnnxGraphRule - from onnx.onnx_ml_pb2 import ModelProto, NodeProto - - class TransposeIdentityRule(OnnxGraphRule): - """Transpose Identity Rewrite Rule +# def test_ggml_onnx_graph_optimization(): +# # Construct an onnx graph and optimize it +# # The graph is of the form y = (A^T)^T * x + b +# # the optimization should remove the transpose operations + +# # The name of the input tensor +# input_name = "x" + +# # The name of the weights tensor +# weight_name_a = "A" +# weight_name_b = "b" + +# # The name of the output +# output_name = "y" + +# # Create the nodes (operations) in our graph +# node1 = helper.make_node( +# "Transpose", [weight_name_a], ["A_transposed"], name="node1" +# ) # A^T +# node2 = helper.make_node( +# "Transpose", ["A_transposed"], ["A_transposed_transposed"], name="node2" +# ) # (A^T)^T +# node3 = helper.make_node( +# "MatMul", [input_name, "A_transposed_transposed"], ["x_times_A"], name="node3" +# ) # x * (A^T)^T +# node4 = helper.make_node( +# "Add", ["x_times_A", weight_name_b], [output_name], name="node4" +# ) # x * (A^T)^T + b + +# # Define the tensors (values) in our graph +# X_value_info = helper.make_tensor_value_info( +# input_name, TensorProto.FLOAT, [None, 32] +# ) + +# output_value_info = helper.make_tensor_value_info( +# output_name, TensorProto.FLOAT, [None, 32] +# ) + +# # Set A and b as parameters/weights +# weights_a = np.random.randn(32, 32).astype(np.float32) + +# weights_b = np.random.randn(32).astype(np.float32) + +# A_init = helper.make_tensor( +# weight_name_a, +# TensorProto.FLOAT, +# [ +# 32, +# 32, +# ], +# weights_a, +# ) +# B_init = helper.make_tensor( +# weight_name_b, +# TensorProto.FLOAT, +# [ +# 32, +# ], +# weights_b, +# ) + +# # Create the graph (model). +# graph_def = helper.make_graph( +# [node1, node2, node3, node4], +# "simple_expression_model", +# [X_value_info], +# [output_value_info], +# [A_init, B_init], +# ) + +# model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") + +# from typing import Optional, List +# from ggml.contrib.onnx import OnnxGraphRuleEngine, OnnxGraphRule +# from onnx.onnx_ml_pb2 import ModelProto, NodeProto + +# class TransposeIdentityRule(OnnxGraphRule): +# """Transpose Identity Rewrite Rule - This rules removes two consecutive transpose nodes that transpose the same tensor. +# This rules removes two consecutive transpose nodes that transpose the same tensor. - ie Transpose(Transpose(x)) -> x""" - - def __init__(self): - super().__init__() - - def apply(self, model: ModelProto) -> Optional[ModelProto]: - # find first transpose node - transpose_node: Optional[NodeProto] = None - for node in model.graph.node: - if node.op_type == "Transpose": - transpose_node = node - break - else: - return None - - # find a transpose node that transposes the output of the first transpose node - transpose_transpose_node: Optional[NodeProto] = None - for node in model.graph.node: - if ( - node.op_type == "Transpose" - and node.input[0] == transpose_node.output[0] - ): - transpose_transpose_node = node - break - else: - return None - - # Create a new node list without the two transpose nodes - new_nodes: List[NodeProto] = [] - for node in model.graph.node: - if node not in [transpose_node, transpose_transpose_node]: - new_node = NodeProto() - new_node.CopyFrom(node) - new_node.input[:] = [transpose_node.input[0] if inp == transpose_transpose_node.output[0] else inp for inp in node.input] - new_nodes.append(new_node) +# ie Transpose(Transpose(x)) -> x""" + +# def __init__(self): +# super().__init__() + +# def apply(self, model: ModelProto) -> Optional[ModelProto]: +# # find first transpose node +# transpose_node: Optional[NodeProto] = None +# for node in model.graph.node: +# if node.op_type == "Transpose": +# transpose_node = node +# break +# else: +# return None + +# # find a transpose node that transposes the output of the first transpose node +# transpose_transpose_node: Optional[NodeProto] = None +# for node in model.graph.node: +# if ( +# node.op_type == "Transpose" +# and node.input[0] == transpose_node.output[0] +# ): +# transpose_transpose_node = node +# break +# else: +# return None + +# # Create a new node list without the two transpose nodes +# new_nodes: List[NodeProto] = [] +# for node in model.graph.node: +# if node not in [transpose_node, transpose_transpose_node]: +# new_node = NodeProto() +# new_node.CopyFrom(node) +# new_node.input[:] = [transpose_node.input[0] if inp == transpose_transpose_node.output[0] else inp for inp in node.input] +# new_nodes.append(new_node) - # Create the new graph - new_graph = helper.make_graph( - new_nodes, - model.graph.name, - model.graph.input, - model.graph.output, - model.graph.initializer, - ) - - # create a new model - new_model = helper.make_model( - new_graph, producer_name=model.producer_name - ) - - return new_model - - - input_data = {"x": np.random.randn(1, 32).astype(np.float32)} - - f = io.BytesIO() - onnx.save(model_def, f) - - runtime_result = InferenceSession(f.getvalue()).run(None, input_data) - - ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) - ggml_result = ggml_dummy_model.run(input_data) - assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) - - optimizer = OnnxGraphRuleEngine( - rules=[TransposeIdentityRule()] - ) - new_model = optimizer.optimize(model=model_def) - assert new_model is not None - ggml_dummy_model_new = GgmlRuntimeBackend.prepare(new_model) - assert ggml_dummy_model_new is not None - ggml_result_new = ggml_dummy_model_new.run(input_data) - assert np.allclose(ggml_result_new[0], runtime_result[0], rtol=1e-03, atol=1e-05) - assert sum([node.op_type == "Transpose" for node in new_model.graph.node]) == 0 - - -def test_ggml_onnx_runtime_quantized(): - # Construct an onnx graph of the form Y = X * A + B - # and compute the result of the graph with quantized weights - # A and B and compare the result with the result of the - # unquantized graph - - # Sizes: X = (32, 32), A = (32, 32), B = (32, 32) - - # The expressions Y = X * A + B cannot be computed directly with quantized - # weights, because ggml expects the quantized weights to appear as the first - # input of the MatMul and Add nodes. Therefore, we rewrite the expression - # using the following identities: - # (AB)^T = B^T A^T - # A = (A^T)^T - # A + B = B + A - # The final expression is Y = B + (A^T X^T)^T - - from typing import Optional, List, Set - from ggml.contrib.onnx import OnnxGraphRuleEngine, OnnxGraphRule - from onnx.onnx_ml_pb2 import ModelProto, NodeProto - - def _depends_on_input(name: str, model: ModelProto) -> bool: - # Depth first search to find any node ancestor in model.graph.inputs - # that is an ancestor of node - initializers = { node.name: node for node in model.graph.initializer } - inputs = { node.name: node for node in model.graph.input } - outputs = { node.name: node for node in model.graph.output } - nodes = { node.name: node for node in model.graph.node } - - def _dfs(name: str, visited: Set[str]) -> bool: - if name in visited: - return False - if name in inputs: - return True - if name not in nodes: - return False - visited.add(name) - for inp in nodes[name].input: - if inp in initializers: - continue - if inp in outputs: - continue - if _dfs(nodes[inp].name, visited): - return True - return False - return _dfs(name, set()) - - class MatMulTransposeRule(OnnxGraphRule): - def __init__(self): - super().__init__() - - def apply(self, model: ModelProto) -> Optional[ModelProto]: - # find a matmul node - matmul_node: Optional[NodeProto] = None - for node in model.graph.node: - if node.op_type == "MatMul": - matmul_node = node - break - else: - return None - - # get first and second input of matmul node - matmul_input_0 = matmul_node.input[0] - matmul_input_1 = matmul_node.input[1] - - # check that first input is _not_ a weight or constant tensor - if _depends_on_input(matmul_input_0, model): - return None +# # Create the new graph +# new_graph = helper.make_graph( +# new_nodes, +# model.graph.name, +# model.graph.input, +# model.graph.output, +# model.graph.initializer, +# ) + +# # create a new model +# new_model = helper.make_model( +# new_graph, producer_name=model.producer_name +# ) + +# return new_model + + +# input_data = {"x": np.random.randn(1, 32).astype(np.float32)} + +# f = io.BytesIO() +# onnx.save(model_def, f) + +# runtime_result = InferenceSession(f.getvalue()).run(None, input_data) + +# ggml_dummy_model = GgmlRuntimeBackend.prepare(model_def) +# ggml_result = ggml_dummy_model.run(input_data) +# assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) + +# optimizer = OnnxGraphRuleEngine( +# rules=[TransposeIdentityRule()] +# ) +# new_model = optimizer.optimize(model=model_def) +# assert new_model is not None +# ggml_dummy_model_new = GgmlRuntimeBackend.prepare(new_model) +# assert ggml_dummy_model_new is not None +# ggml_result_new = ggml_dummy_model_new.run(input_data) +# assert np.allclose(ggml_result_new[0], runtime_result[0], rtol=1e-03, atol=1e-05) +# assert sum([node.op_type == "Transpose" for node in new_model.graph.node]) == 0 + + +# def test_ggml_onnx_runtime_quantized(): +# # Construct an onnx graph of the form Y = X * A + B +# # and compute the result of the graph with quantized weights +# # A and B and compare the result with the result of the +# # unquantized graph + +# # Sizes: X = (32, 32), A = (32, 32), B = (32, 32) + +# # The expressions Y = X * A + B cannot be computed directly with quantized +# # weights, because ggml expects the quantized weights to appear as the first +# # input of the MatMul and Add nodes. Therefore, we rewrite the expression +# # using the following identities: +# # (AB)^T = B^T A^T +# # A = (A^T)^T +# # A + B = B + A +# # The final expression is Y = B + (A^T X^T)^T + +# from typing import Optional, List, Set +# from ggml.contrib.onnx import OnnxGraphRuleEngine, OnnxGraphRule +# from onnx.onnx_ml_pb2 import ModelProto, NodeProto + +# def _depends_on_input(name: str, model: ModelProto) -> bool: +# # Depth first search to find any node ancestor in model.graph.inputs +# # that is an ancestor of node +# initializers = { node.name: node for node in model.graph.initializer } +# inputs = { node.name: node for node in model.graph.input } +# outputs = { node.name: node for node in model.graph.output } +# nodes = { node.name: node for node in model.graph.node } + +# def _dfs(name: str, visited: Set[str]) -> bool: +# if name in visited: +# return False +# if name in inputs: +# return True +# if name not in nodes: +# return False +# visited.add(name) +# for inp in nodes[name].input: +# if inp in initializers: +# continue +# if inp in outputs: +# continue +# if _dfs(nodes[inp].name, visited): +# return True +# return False +# return _dfs(name, set()) + +# class MatMulTransposeRule(OnnxGraphRule): +# def __init__(self): +# super().__init__() + +# def apply(self, model: ModelProto) -> Optional[ModelProto]: +# # find a matmul node +# matmul_node: Optional[NodeProto] = None +# for node in model.graph.node: +# if node.op_type == "MatMul": +# matmul_node = node +# break +# else: +# return None + +# # get first and second input of matmul node +# matmul_input_0 = matmul_node.input[0] +# matmul_input_1 = matmul_node.input[1] + +# # check that first input is _not_ a weight or constant tensor +# if _depends_on_input(matmul_input_0, model): +# return None - # check that second input is a weight or constant tensor - if not _depends_on_input(matmul_input_1, model): - return None - - # replace Matmul(matmul_input_0, matmul_input_1) with Transpose(MatMul(Transpose(matmul_input_1), Transpose(matmul_input_0))) - - # create new transpose nodes for the inputs - transpose_node_0 = NodeProto() - transpose_node_0.CopyFrom(matmul_node) - transpose_node_0.op_type = "Transpose" - transpose_node_0.name = matmul_input_0 + "_transposed" - transpose_node_0.input[:] = [matmul_input_0] - transpose_node_0.output[:] = [matmul_input_0 + "_transposed"] +# # check that second input is a weight or constant tensor +# if not _depends_on_input(matmul_input_1, model): +# return None + +# # replace Matmul(matmul_input_0, matmul_input_1) with Transpose(MatMul(Transpose(matmul_input_1), Transpose(matmul_input_0))) + +# # create new transpose nodes for the inputs +# transpose_node_0 = NodeProto() +# transpose_node_0.CopyFrom(matmul_node) +# transpose_node_0.op_type = "Transpose" +# transpose_node_0.name = matmul_input_0 + "_transposed" +# transpose_node_0.input[:] = [matmul_input_0] +# transpose_node_0.output[:] = [matmul_input_0 + "_transposed"] - transpose_node_1 = NodeProto() - transpose_node_1.CopyFrom(matmul_node) - transpose_node_1.op_type = "Transpose" - transpose_node_1.name = matmul_input_1 + "_transposed" - transpose_node_1.input[:] = [matmul_input_1] - transpose_node_1.output[:] = [matmul_input_1 + "_transposed"] - - # create new matmul node - new_matmul_node = NodeProto() - new_matmul_node.CopyFrom(matmul_node) - new_matmul_node.op_type = "MatMul" - new_matmul_node.name = matmul_node.name + "_inner" - new_matmul_node.input[:] = [transpose_node_1.output[0], transpose_node_0.output[0]] - new_matmul_node.output[:] = [matmul_node.output[0]] - - # create final transpose node - final_transpose_node = NodeProto() - final_transpose_node.CopyFrom(matmul_node) - final_transpose_node.op_type = "Transpose" - final_transpose_node.name = matmul_node.name # this is the name of the original matmul node - final_transpose_node.input[:] = [new_matmul_node.output[0]] - final_transpose_node.output[:] = [matmul_node.output[0]] - - # Create the new node list - new_nodes: List[NodeProto] = [] - for node in model.graph.node: - if node not in [matmul_node]: - new_node = NodeProto() - new_node.CopyFrom(node) - new_nodes.append(new_node) - else: - new_nodes.extend([transpose_node_0, transpose_node_1, new_matmul_node, final_transpose_node]) - - # Create the new graph - new_graph = helper.make_graph( - new_nodes, - model.graph.name, - model.graph.input, - model.graph.output, - model.graph.initializer, - ) - - # create a new model - new_model = helper.make_model( - new_graph, producer_name=model.producer_name - ) - - return new_model - - class AddAssociativityRule(OnnxGraphRule): - def __init__(self): - super().__init__() - - def apply(self, model: ModelProto) -> Optional[ModelProto]: - # find an add node - add_node: Optional[NodeProto] = None - for node in model.graph.node: - if node.op_type == "Add": - add_node = node - break - else: - return None +# transpose_node_1 = NodeProto() +# transpose_node_1.CopyFrom(matmul_node) +# transpose_node_1.op_type = "Transpose" +# transpose_node_1.name = matmul_input_1 + "_transposed" +# transpose_node_1.input[:] = [matmul_input_1] +# transpose_node_1.output[:] = [matmul_input_1 + "_transposed"] + +# # create new matmul node +# new_matmul_node = NodeProto() +# new_matmul_node.CopyFrom(matmul_node) +# new_matmul_node.op_type = "MatMul" +# new_matmul_node.name = matmul_node.name + "_inner" +# new_matmul_node.input[:] = [transpose_node_1.output[0], transpose_node_0.output[0]] +# new_matmul_node.output[:] = [matmul_node.output[0]] + +# # create final transpose node +# final_transpose_node = NodeProto() +# final_transpose_node.CopyFrom(matmul_node) +# final_transpose_node.op_type = "Transpose" +# final_transpose_node.name = matmul_node.name # this is the name of the original matmul node +# final_transpose_node.input[:] = [new_matmul_node.output[0]] +# final_transpose_node.output[:] = [matmul_node.output[0]] + +# # Create the new node list +# new_nodes: List[NodeProto] = [] +# for node in model.graph.node: +# if node not in [matmul_node]: +# new_node = NodeProto() +# new_node.CopyFrom(node) +# new_nodes.append(new_node) +# else: +# new_nodes.extend([transpose_node_0, transpose_node_1, new_matmul_node, final_transpose_node]) + +# # Create the new graph +# new_graph = helper.make_graph( +# new_nodes, +# model.graph.name, +# model.graph.input, +# model.graph.output, +# model.graph.initializer, +# ) + +# # create a new model +# new_model = helper.make_model( +# new_graph, producer_name=model.producer_name +# ) + +# return new_model + +# class AddAssociativityRule(OnnxGraphRule): +# def __init__(self): +# super().__init__() + +# def apply(self, model: ModelProto) -> Optional[ModelProto]: +# # find an add node +# add_node: Optional[NodeProto] = None +# for node in model.graph.node: +# if node.op_type == "Add": +# add_node = node +# break +# else: +# return None - # get first and second input of add node - add_input_0 = add_node.input[0] - add_input_1 = add_node.input[1] +# # get first and second input of add node +# add_input_0 = add_node.input[0] +# add_input_1 = add_node.input[1] - # check that first input is _not_ a weight or constant tensor - if _depends_on_input(add_input_0, model): - return None +# # check that first input is _not_ a weight or constant tensor +# if _depends_on_input(add_input_0, model): +# return None - # check that second input is a weight or constant tensor - if not _depends_on_input(add_input_1, model): - return None - - # replace Add(add_input_0, add_input_1) with Add(add_input_1, add_input_0) - - # create new add node - new_add_node = NodeProto() - new_add_node.CopyFrom(add_node) - new_add_node.op_type = "Add" - new_add_node.name = add_node.name - new_add_node.input[:] = [add_input_1, add_input_0] - new_add_node.output[:] = [add_node.output[0]] - - # Create the new node list - new_nodes: List[NodeProto] = [] - for node in model.graph.node: - if node not in [add_node]: - new_node = NodeProto() - new_node.CopyFrom(node) - new_nodes.append(new_node) - else: - new_nodes.extend([new_add_node]) - - # Create the new graph - new_graph = helper.make_graph( - new_nodes, - model.graph.name, - model.graph.input, - model.graph.output, - model.graph.initializer, - ) - - # create a new model - new_model = helper.make_model( - new_graph, producer_name=model.producer_name - ) - - return new_model - - engine = OnnxGraphRuleEngine( - rules=[MatMulTransposeRule(), AddAssociativityRule()] - ) - - # The name of the input tensor - input_name = "X" - - # The name of the weights tensor - weight_name_a = "A" - weight_name_b = "B" - - # The name of the output - output_name = "Y" +# # check that second input is a weight or constant tensor +# if not _depends_on_input(add_input_1, model): +# return None + +# # replace Add(add_input_0, add_input_1) with Add(add_input_1, add_input_0) + +# # create new add node +# new_add_node = NodeProto() +# new_add_node.CopyFrom(add_node) +# new_add_node.op_type = "Add" +# new_add_node.name = add_node.name +# new_add_node.input[:] = [add_input_1, add_input_0] +# new_add_node.output[:] = [add_node.output[0]] + +# # Create the new node list +# new_nodes: List[NodeProto] = [] +# for node in model.graph.node: +# if node not in [add_node]: +# new_node = NodeProto() +# new_node.CopyFrom(node) +# new_nodes.append(new_node) +# else: +# new_nodes.extend([new_add_node]) + +# # Create the new graph +# new_graph = helper.make_graph( +# new_nodes, +# model.graph.name, +# model.graph.input, +# model.graph.output, +# model.graph.initializer, +# ) + +# # create a new model +# new_model = helper.make_model( +# new_graph, producer_name=model.producer_name +# ) + +# return new_model + +# engine = OnnxGraphRuleEngine( +# rules=[MatMulTransposeRule(), AddAssociativityRule()] +# ) + +# # The name of the input tensor +# input_name = "X" + +# # The name of the weights tensor +# weight_name_a = "A" +# weight_name_b = "B" + +# # The name of the output +# output_name = "Y" - # Create the nodes (operations) in our graph Y = X * A + B - - # X * A - - node1 = helper.make_node( - "MatMul", [input_name, weight_name_a], ["X_times_A"], name="node1" - ) # X * A - - # X * A + B - - node2 = helper.make_node( - "Add", ["X_times_A", weight_name_b], [output_name], name="node2" - ) # X * A + B - - # Define the tensors (values) in our graph - X_value_info = helper.make_tensor_value_info( - input_name, TensorProto.FLOAT, [None, 32] - ) - - output_value_info = helper.make_tensor_value_info( - output_name, TensorProto.FLOAT, [None, 32] - ) - - # Set A and B as parameters/weights - weights_a = np.random.randn(32, 32).astype(np.float32) - - weights_b = np.random.randn(32, 32).astype(np.float32) - - A_init = helper.make_tensor( - weight_name_a, - TensorProto.FLOAT, - [ - 32, - 32, - ], - weights_a, - ) - B_init = helper.make_tensor( - weight_name_b, - TensorProto.FLOAT, - [ - 32, - 32, - ], - weights_b, - ) - - # Create the graph (model). - graph_def = helper.make_graph( - [node1, node2], - "simple_expression_model", - [X_value_info], - [output_value_info], - [A_init, B_init], - ) - - model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") - - input_data = {"X": np.random.randn(1, 32).astype(np.float32)} - - f = io.BytesIO() - onnx.save(model_def, f) - - runtime_result = InferenceSession(f.getvalue()).run(None, input_data) +# # Create the nodes (operations) in our graph Y = X * A + B + +# # X * A + +# node1 = helper.make_node( +# "MatMul", [input_name, weight_name_a], ["X_times_A"], name="node1" +# ) # X * A + +# # X * A + B + +# node2 = helper.make_node( +# "Add", ["X_times_A", weight_name_b], [output_name], name="node2" +# ) # X * A + B + +# # Define the tensors (values) in our graph +# X_value_info = helper.make_tensor_value_info( +# input_name, TensorProto.FLOAT, [None, 32] +# ) + +# output_value_info = helper.make_tensor_value_info( +# output_name, TensorProto.FLOAT, [None, 32] +# ) + +# # Set A and B as parameters/weights +# weights_a = np.random.randn(32, 32).astype(np.float32) + +# weights_b = np.random.randn(32, 32).astype(np.float32) + +# A_init = helper.make_tensor( +# weight_name_a, +# TensorProto.FLOAT, +# [ +# 32, +# 32, +# ], +# weights_a, +# ) +# B_init = helper.make_tensor( +# weight_name_b, +# TensorProto.FLOAT, +# [ +# 32, +# 32, +# ], +# weights_b, +# ) + +# # Create the graph (model). +# graph_def = helper.make_graph( +# [node1, node2], +# "simple_expression_model", +# [X_value_info], +# [output_value_info], +# [A_init, B_init], +# ) + +# model_def = helper.make_model(graph_def, producer_name="onnx-simple-expression") + +# input_data = {"X": np.random.randn(1, 32).astype(np.float32)} + +# f = io.BytesIO() +# onnx.save(model_def, f) + +# runtime_result = InferenceSession(f.getvalue()).run(None, input_data) - # rewrite the graph - new_model = engine.optimize(model=model_def) - assert new_model is not None +# # rewrite the graph +# new_model = engine.optimize(model=model_def) +# assert new_model is not None - ggml_dummy_model = GgmlRuntimeBackend.prepare(new_model) - ggml_result = ggml_dummy_model.run(input_data) - assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) +# ggml_dummy_model = GgmlRuntimeBackend.prepare(new_model) +# ggml_result = ggml_dummy_model.run(input_data) +# assert np.allclose(ggml_result[0], runtime_result[0], rtol=1e-03, atol=1e-05) backend_test = onnx.backend.test.BackendTest(GgmlRuntimeBackend, __name__) @@ -642,109 +647,109 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: backend_test.include("test_add_") backend_test.exclude("test_add_uint8_") # not supported -backend_test.include("test_and_") +# backend_test.include("test_and_") -backend_test.include("test_argmax_") -backend_test.include("test_argmin_") +# backend_test.include("test_argmax_") +# backend_test.include("test_argmin_") -backend_test.include("test_operator_basic_") +# backend_test.include("test_operator_basic_") -backend_test.include("test_cast_") +# backend_test.include("test_cast_") -backend_test.include("test_ceil_") +# backend_test.include("test_ceil_") -backend_test.include("test_concat_") -backend_test.include("test_operator_concat") +# backend_test.include("test_concat_") +# backend_test.include("test_operator_concat") backend_test.include("test_constant_") backend_test.include("test_constantofshape") -# backend_test.include("_conv_") -# backend_test.exclude("_deform_conv") -# backend_test.exclude("test_operator_conv") +# # backend_test.include("_conv_") +# # backend_test.exclude("_deform_conv") +# # backend_test.exclude("test_operator_conv") -# backend_test.include("_convtranspose_") -# backend_test.exclude("_deform_convtranspose") -# backend_test.exclude("test_operator_convtranspose") +# # backend_test.include("_convtranspose_") +# # backend_test.exclude("_deform_convtranspose") +# # backend_test.exclude("test_operator_convtranspose") -backend_test.include("test_operator_chunk") +# backend_test.include("test_operator_chunk") -backend_test.include("test_depthtospace") +# backend_test.include("test_depthtospace") -backend_test.include("test_div_") -backend_test.exclude("test_div_uint8_") # not supported +# backend_test.include("test_div_") +# backend_test.exclude("test_div_uint8_") # not supported -backend_test.include("test_elu_") -backend_test.include("test_ELU_") -backend_test.include("test_elu_example") +# backend_test.include("test_elu_") +# backend_test.include("test_ELU_") +# backend_test.include("test_elu_example") -backend_test.include("test_eq_") +# backend_test.include("test_eq_") -backend_test.include("test_equal_") -backend_test.exclude(".*equal.*.*string.*") +# backend_test.include("test_equal_") +# backend_test.exclude(".*equal.*.*string.*") -backend_test.include("test_exp_") -backend_test.include("test_operator_exp_") +# backend_test.include("test_exp_") +# backend_test.include("test_operator_exp_") -backend_test.include("test_expand_") +# backend_test.include("test_expand_") -backend_test.include("test_flatten_") -backend_test.include("test_operator_flatten_") +# backend_test.include("test_flatten_") +# backend_test.include("test_operator_flatten_") -backend_test.include("test_floor_") +# backend_test.include("test_floor_") -backend_test.include("test_greater_") +# backend_test.include("test_greater_") -backend_test.include("test_gather_") -backend_test.exclude("test_gather_elements") # not supported +# backend_test.include("test_gather_") +# backend_test.exclude("test_gather_elements") # not supported -backend_test.include("test_gemm") -backend_test.exclude("test_gemm_default_scalar_bias") +# backend_test.include("test_gemm") +# backend_test.exclude("test_gemm_default_scalar_bias") -backend_test.include("test_greater_") +# backend_test.include("test_greater_") -backend_test.include("test_hardsigmoid_") +# backend_test.include("test_hardsigmoid_") -backend_test.include("test_hardmax_") +# backend_test.include("test_hardmax_") -backend_test.include("test_identity_") -backend_test.exclude("test_identity_opt") # test case not correct: ONNX issue -backend_test.exclude("test_identity_sequence") # test case not correct: ONNX issue +# backend_test.include("test_identity_") +# backend_test.exclude("test_identity_opt") # test case not correct: ONNX issue +# backend_test.exclude("test_identity_sequence") # test case not correct: ONNX issue -backend_test.include("test_instancenorm") +# backend_test.include("test_instancenorm") -# backend_test.include("test_leakyrelu") +# # backend_test.include("test_leakyrelu") -backend_test.include("test_less_") +# backend_test.include("test_less_") backend_test.include("test_log_") -backend_test.include("test_LogSoftmax_") +# backend_test.include("test_LogSoftmax_") -backend_test.include("test_lrn") +# backend_test.include("test_lrn") backend_test.include("test_matmul_") -backend_test.include("test_operator_mm") +# backend_test.include("test_operator_mm") -backend_test.include("test_max_") -backend_test.exclude("test_max_float16") # not supported -backend_test.exclude("test_max_float64") # not supported -backend_test.exclude("test_max_int64") # not supported -backend_test.exclude("test_max_uint") # not supported -backend_test.include("test_operator_max_") +# backend_test.include("test_max_") +# backend_test.exclude("test_max_float16") # not supported +# backend_test.exclude("test_max_float64") # not supported +# backend_test.exclude("test_max_int64") # not supported +# backend_test.exclude("test_max_uint") # not supported +# backend_test.include("test_operator_max_") -backend_test.include("test_mean_") +# backend_test.include("test_mean_") -backend_test.include("test_min_") -backend_test.exclude("test_min_float16") # not supported -backend_test.exclude("test_min_float64") # not supported -backend_test.exclude("test_min_int64") # not supported -backend_test.exclude("test_min_uint") # not supported -backend_test.include("test_operator_min_") +# backend_test.include("test_min_") +# backend_test.exclude("test_min_float16") # not supported +# backend_test.exclude("test_min_float64") # not supported +# backend_test.exclude("test_min_int64") # not supported +# backend_test.exclude("test_min_uint") # not supported +# backend_test.include("test_operator_min_") backend_test.include("test_mul_") @@ -752,75 +757,75 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: backend_test.include("test_neg_") -backend_test.include("test_not_") +# backend_test.include("test_not_") -backend_test.include("test_or_") +# backend_test.include("test_or_") -backend_test.include("test_prelu") -backend_test.include("test_PRelu_") -backend_test.include("test_prelu_example") +# backend_test.include("test_prelu") +# backend_test.include("test_PRelu_") +# backend_test.include("test_prelu_example") -backend_test.include("test_pow_") -backend_test.exclude("test_pow_bcast") # not supported -backend_test.exclude("test_pow_types_int64") # not supported -backend_test.include("test_operator_pow_") +# backend_test.include("test_pow_") +# backend_test.exclude("test_pow_bcast") # not supported +# backend_test.exclude("test_pow_types_int64") # not supported +# backend_test.include("test_operator_pow_") backend_test.include("test_range_") backend_test.exclude("test_range_float") # segfault backend_test.exclude("test_range_int32") # segfault -backend_test.include("test_reciprocal") +# backend_test.include("test_reciprocal") -backend_test.include("test_reduce_max_") -backend_test.include("test_reduce_mean_") -backend_test.include("test_operator_reduced_mean_") -backend_test.include("test_reduce_min_") -backend_test.include("test_reduce_prod_") -backend_test.include("test_reduce_sum_") -backend_test.include("test_operator_reduced_sum_") -backend_test.include("test_reduce_log_sum_") -backend_test.exclude("test_reduce_log_sum_exp") +# backend_test.include("test_reduce_max_") +# backend_test.include("test_reduce_mean_") +# backend_test.include("test_operator_reduced_mean_") +# backend_test.include("test_reduce_min_") +# backend_test.include("test_reduce_prod_") +# backend_test.include("test_reduce_sum_") +# backend_test.include("test_operator_reduced_sum_") +# backend_test.include("test_reduce_log_sum_") +# backend_test.exclude("test_reduce_log_sum_exp") -backend_test.include("test_reduce_l1_") -backend_test.include("test_reduce_l2_") +# backend_test.include("test_reduce_l1_") +# backend_test.include("test_reduce_l2_") -backend_test.include("test_relu_") -backend_test.include("test_relu_example") -backend_test.include("test_ReLU_") +# backend_test.include("test_relu_") +# backend_test.include("test_relu_example") +# backend_test.include("test_ReLU_") backend_test.include("test_reshape_") backend_test.exclude("test_reshape_allowzero") # not supported -backend_test.include("test_selu_") -backend_test.include("test_selu_example") -backend_test.include("test_SELU_") -backend_test.include("test_operator_selu_") +# backend_test.include("test_selu_") +# backend_test.include("test_selu_example") +# backend_test.include("test_SELU_") +# backend_test.include("test_operator_selu_") backend_test.include("test_shape_") -backend_test.include("test_sigmoid_") -backend_test.include("test_Sigmoid_") +# backend_test.include("test_sigmoid_") +# backend_test.include("test_Sigmoid_") backend_test.include("test_size_") -backend_test.include("test_slice_") +# backend_test.include("test_slice_") -backend_test.include("test_softmax_") -backend_test.exclude("test_softmax_axis_0") # not supported -backend_test.exclude("test_softmax_axis_1") # not supported -backend_test.exclude("test_softmax_large_number") # not supported -backend_test.exclude("test_softmax_lastdim") # Out of tolerance -# backend_test.include("test_Softmax") +# backend_test.include("test_softmax_") +# backend_test.exclude("test_softmax_axis_0") # not supported +# backend_test.exclude("test_softmax_axis_1") # not supported +# backend_test.exclude("test_softmax_large_number") # not supported +# backend_test.exclude("test_softmax_lastdim") # Out of tolerance +# # backend_test.include("test_Softmax") -backend_test.include("test_softplus_") -backend_test.include("test_softsign_") -backend_test.include("test_Softplus") +# backend_test.include("test_softplus_") +# backend_test.include("test_softsign_") +# backend_test.include("test_Softplus") -backend_test.include("test_spacetodepth") +# backend_test.include("test_spacetodepth") -backend_test.include("test_split_") -backend_test.exclude(".*split.*.*to.*.*sequence.*") +# backend_test.include("test_split_") +# backend_test.exclude(".*split.*.*to.*.*sequence.*") backend_test.include("test_sqrt_") backend_test.include("test_operator_sqrt_") @@ -831,12 +836,12 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: backend_test.include("test_sum_") -backend_test.include("test_tanh_") -backend_test.include("test_Tanh_") +# backend_test.include("test_tanh_") +# backend_test.include("test_Tanh_") -backend_test.include("test_tile_") +# backend_test.include("test_tile_") -backend_test.include("test_top_k") +# backend_test.include("test_top_k") backend_test.include("test_transpose_") @@ -846,13 +851,13 @@ def apply(self, model: ModelProto) -> Optional[ModelProto]: backend_test.exclude("test_unsqueeze_two_axes") # 5D Array not supported backend_test.exclude("test_unsqueeze_unsorted_axes") # 5D Array not supported -backend_test.include("test_where_") -backend_test.exclude("test_where_long") # not supported +# backend_test.include("test_where_") +# backend_test.exclude("test_where_long") # not supported -backend_test.include("test_xor_") +# backend_test.include("test_xor_") -backend_test.exclude(".*FLOAT*E*M*.*") -backend_test.exclude(".*ver18.*") +# backend_test.exclude(".*FLOAT*E*M*.*") +# backend_test.exclude(".*ver18.*") # This is a pytest magic variable to load extra plugins pytest_plugins = ("onnx.backend.test.report",) From ebd2c7c7d015440245aba1733c7e5c9cb1fa9798 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Sun, 3 Mar 2024 14:31:38 -0500 Subject: [PATCH 228/232] Disable transpose test --- tests/test_ggml_onnx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ggml_onnx.py b/tests/test_ggml_onnx.py index dd991840..aa9a5a3f 100644 --- a/tests/test_ggml_onnx.py +++ b/tests/test_ggml_onnx.py @@ -843,7 +843,7 @@ def test_compare_runtimes(model: onnx_pb.ModelProto, input_data: typing.Dict[str # backend_test.include("test_top_k") -backend_test.include("test_transpose_") +# backend_test.include("test_transpose_") backend_test.include("test_unsqueeze_") backend_test.exclude("test_unsqueeze_negative_axes") # 5D Array not supported From 58c092d1232dc5ac7bf2f62e93f03d785fcdfbde Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 4 Mar 2024 11:32:53 -0500 Subject: [PATCH 229/232] check ggml_status --- ggml/contrib/onnx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 12d2f4e0..adc9e4a8 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5092,7 +5092,7 @@ def eval_tensor(self, tensor: ggml.ggml_tensor_p): if not ggml.ggml_gallocr_alloc_graph(gallocr, self.ggml_graph): raise RuntimeError("Failed to allocate GGML graph") - if not ggml.ggml_backend_graph_compute(self.backend.ggml_backend, self.ggml_graph): + if ggml.ggml_backend_graph_compute(self.backend.ggml_backend, self.ggml_graph) != ggml.GGML_STATUS_SUCCESS: raise RuntimeError("Failed to compute GGML graph") tensor_copy = ggml.ggml_dup_tensor(self.ggml_eval_context, tensor) From 80183bdb75f3371ed9b87888e8f702912dfeaa89 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Mon, 8 Apr 2024 09:11:23 -0400 Subject: [PATCH 230/232] Update tests --- tests/test_ggml.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_ggml.py b/tests/test_ggml.py index 6d315671..b13a44c7 100644 --- a/tests/test_ggml.py +++ b/tests/test_ggml.py @@ -308,9 +308,9 @@ def no_op( f_copy = ggml.ggml_dup_tensor(ctx_eval, f) f_buffer = ggml.ggml_backend_alloc_buffer(backend, ggml.ggml_nbytes(f_copy)) + assert f_buffer is not None tallocr = ggml.ggml_tallocr_new(f_buffer) - ggml.ggml_tallocr_alloc(tallocr, f_copy) - ggml.ggml_tallocr_free(tallocr) + ggml.ggml_tallocr_alloc(ctypes.pointer(tallocr), f_copy) ggml.ggml_backend_tensor_copy(f, f_copy) From 166fcddfcc21061187ecbf7976fc7e7a4ddea7d5 Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 9 Apr 2024 10:08:37 -0400 Subject: [PATCH 231/232] Update tensor allocator api --- ggml/contrib/onnx.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index adc9e4a8..2d546d5d 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5064,9 +5064,7 @@ def from_numpy(self, array: npt.NDArray[Any]) -> ggml.ggml_tensor_p: assert tensor_buffer is not None weakref.finalize(tensor, ggml.ggml_backend_buffer_free, tensor_buffer) tallocr = ggml.ggml_tallocr_new(tensor_buffer) - assert tallocr is not None - ggml.ggml_tallocr_alloc(tallocr, tensor) - ggml.ggml_tallocr_free(tallocr) + ggml.ggml_tallocr_alloc(ctypes.pointer(tallocr), tensor) ggml.ggml_set_input(tensor) ggml.ggml_set_output(tensor) @@ -5100,13 +5098,11 @@ def eval_tensor(self, tensor: ggml.ggml_tensor_p): assert tensor_copy_buffer is not None weakref.finalize(tensor_copy, ggml.ggml_backend_buffer_free, tensor_copy_buffer) tallocr = ggml.ggml_tallocr_new(tensor_copy_buffer) - assert tallocr is not None - ggml.ggml_tallocr_alloc(tallocr, tensor_copy) + ggml.ggml_tallocr_alloc(ctypes.pointer(tallocr), tensor_copy) ggml.ggml_backend_tensor_copy(tensor, tensor_copy) self.refs.append(tensor_copy_buffer) - ggml.ggml_tallocr_free(tallocr) ggml.ggml_gallocr_free(gallocr) return tensor_copy From a91780b5bc12880ce7abaf6072aa157ef4610a2b Mon Sep 17 00:00:00 2001 From: Andrei Betlen Date: Tue, 9 Apr 2024 10:11:08 -0400 Subject: [PATCH 232/232] Fix type issues --- ggml/contrib/onnx.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ggml/contrib/onnx.py b/ggml/contrib/onnx.py index 2d546d5d..c411c9a2 100644 --- a/ggml/contrib/onnx.py +++ b/ggml/contrib/onnx.py @@ -5226,6 +5226,9 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: ggml_input_buffer = ggml.ggml_backend_alloc_ctx_tensors(ggml_input_context, self.ggml_backend) + if ggml_input_buffer is None: + raise RuntimeError("Failed to allocate GGML input buffer") + # Set user inputs for key, value in inputs.items(): tensor = ggml_tensors[key] @@ -5271,7 +5274,7 @@ def run(self, inputs: Any, **kwargs: Any) -> Tuple[Any, ...]: for output in self.outputs: exit_node = outputs[output.name] # NOTE: 0 dimension in ggml may cause bugs - max_tensors = np.prod(ctx.shapes[output.name]) + max_tensors = np.prod(ctx.shapes[output.name]) # type: ignore graph_output: npt.NDArray[Any] = ( ctx.to_numpy(exit_node) if max_tensors > 0 else np.empty((0)) ) # TODO: Add checks to convert values back to bool or etc types