Skip to content

Export

Model export to standard interchange formats.

  • ONNXExporter — Export SC networks to ONNX (.onnx protobuf) or JSON (.json legacy). SC layers map to custom domain sc_neurocore with op types SC_Dense and SC_Custom. Standard layers use ONNX standard ops.

Two export paths: - .onnx — Standard ONNX ModelProto via the onnx library (optional dependency) - .json — Dependency-free JSON schema for lightweight deployment

Python
from sc_neurocore.export import ONNXExporter

exporter = ONNXExporter()
exporter.export(model, "model.onnx")

sc_neurocore.export.onnx_exporter

ONNX export for SC networks.

Supports two formats: - .onnx (protobuf) — standard ONNX ModelProto via onnx library - .json — legacy JSON schema (no external dependencies)

SC layers use stochastic bitstream ops not in the ONNX standard. We map them to a custom domain sc_neurocore with op types SC_Dense and SC_Custom.

SCOnnxExporter

Export SC networks to ONNX protobuf or legacy JSON.

Source code in src/sc_neurocore/export/onnx_exporter.py
Python
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
class SCOnnxExporter:
    """Export SC networks to ONNX protobuf or legacy JSON."""

    @staticmethod
    def export(layers: list[Any], filename: str) -> None:
        """Export *layers* to *filename*.

        File extension selects format: ``.onnx`` → protobuf,
        anything else → legacy JSON.
        """
        if filename.endswith(".onnx"):
            SCOnnxExporter._export_protobuf(layers, filename)
        else:
            SCOnnxExporter._export_json(layers, filename)

    # ── protobuf path ────────────────────────────────────────────

    @staticmethod
    def _export_protobuf(layers: list[Any], filename: str) -> None:
        try:
            import onnx
            from onnx import TensorProto, helper, numpy_helper
        except ImportError:
            from sc_neurocore.exceptions import SCDependencyError

            raise SCDependencyError(
                "ONNX protobuf export requires onnx: pip install sc-neurocore[full]"
            )

        nodes: list[Any] = []
        initializers: list[Any] = []
        prev = "input_0"
        n_in = layers[0].n_inputs

        for i, layer in enumerate(layers):
            out = f"output_{i}"
            attrs: dict[str, Any] = {
                "n_neurons": getattr(layer, "n_neurons", -1),
                "length": getattr(layer, "length", 256),
            }

            node = helper.make_node(
                _classify_op(layer),
                inputs=[prev],
                outputs=[out],
                name=f"Layer_{i}",
                domain=_CUSTOM_DOMAIN,
                **{k: v for k, v in attrs.items()},
            )
            nodes.append(node)

            if hasattr(layer, "weights"):
                w_name = f"Layer_{i}_weights"
                tensor = numpy_helper.from_array(
                    np.asarray(layer.weights, dtype=np.float32), name=w_name
                )
                initializers.append(tensor)
                node.input.append(w_name)

            prev = out

        input_vi = helper.make_tensor_value_info("input_0", TensorProto.FLOAT, ["batch", n_in])
        output_vi = helper.make_tensor_value_info(prev, TensorProto.FLOAT, None)

        graph = helper.make_graph(
            nodes,
            "sc_neurocore_graph",
            [input_vi],
            [output_vi],
            initializer=initializers,
        )

        opset_imports = [
            helper.make_opsetid("", 17),
            helper.make_opsetid(_CUSTOM_DOMAIN, _OPSET_VERSION),
        ]

        model = helper.make_model(graph, opset_imports=opset_imports)
        model.producer_name = "sc-neurocore"
        model.ir_version = 8

        onnx.save(model, filename)
        logger.info("Exported ONNX protobuf to %s", filename)

    # ── legacy JSON path ─────────────────────────────────────────

    @staticmethod
    def _export_json(layers: list[Any], filename: str) -> None:
        graph: dict[str, Any] = {
            "producer_name": "sc-neurocore",
            "producer_version": "2.0.0",
            "nodes": [],
            "inputs": [],
            "outputs": [],
        }

        graph["inputs"].append(
            {
                "name": "input_0",
                "type": "tensor(float)",
                "shape": ["batch", layers[0].n_inputs],
            }
        )

        prev = "input_0"
        for i, layer in enumerate(layers):
            out = f"output_{i}"
            node = {
                "op_type": _classify_op(layer),
                "name": f"Layer_{i}",
                "input": [prev],
                "output": [out],
                "attributes": {
                    "n_neurons": getattr(layer, "n_neurons", -1),
                    "length": getattr(layer, "length", 256),
                },
            }
            if hasattr(layer, "weights"):
                node["attributes"]["has_weights"] = True  # type: ignore[index]
                np.save(f"{filename}_layer_{i}_weights.npy", layer.weights)
                node["attributes"]["weights_file"] = f"{filename}_layer_{i}_weights.npy"  # type: ignore[index]
            graph["nodes"].append(node)
            prev = out

        graph["outputs"].append({"name": prev, "type": "tensor(float)"})

        try:
            with open(filename, "w") as f:
                json.dump(graph, f, indent=4)
        except OSError as exc:
            logger.error("Failed to export ONNX schema to %s: %s", filename, exc)
            raise

        logger.info("Exported ONNX-schema JSON to %s", filename)

export(layers, filename) staticmethod

Export layers to filename.

File extension selects format: .onnx → protobuf, anything else → legacy JSON.

Source code in src/sc_neurocore/export/onnx_exporter.py
Python
44
45
46
47
48
49
50
51
52
53
54
@staticmethod
def export(layers: list[Any], filename: str) -> None:
    """Export *layers* to *filename*.

    File extension selects format: ``.onnx`` → protobuf,
    anything else → legacy JSON.
    """
    if filename.endswith(".onnx"):
        SCOnnxExporter._export_protobuf(layers, filename)
    else:
        SCOnnxExporter._export_json(layers, filename)