InferenceWorker/OnnxGraph.cs
using System.Text;

namespace HumanoidMocap.Worker;

/// <summary>Writes the small part of the ONNX format a transformer backbone needs, directly as protobuf
/// wire bytes. The published checkpoints are PyTorch files and their licences do not allow converted
/// copies to be redistributed, so the graph is assembled on the player's machine from the weights the
/// worker has already downloaded and verified. Weights go to an external data file beside the graph,
/// aligned for memory mapping; the serialized graph itself is a few hundred kilobytes.</summary>
public sealed class OnnxGraph
{
    public const int Float=1,Int64=7,Float16=10;
    readonly MemoryStream nodes=new(),initializers=new(),inputs=new(),outputs=new();
    readonly Stream? data;readonly string dataName;int counter;
    /// <param name="data">Receives the weights; <paramref name="dataName"/> is its file name next to the graph.
    /// Null keeps the weights inside the graph, for models well under the 2 GB protobuf limit.</param>
    public OnnxGraph(Stream? data,string dataName=""){this.data=data;this.dataName=dataName;}

    static void Varint(Stream s,ulong value){while(value>=0x80){s.WriteByte((byte)(value|0x80));value>>=7;}s.WriteByte((byte)value);}
    static void Tag(Stream s,int field,int wire)=>Varint(s,(ulong)(field<<3|wire));
    static void Int(Stream s,int field,long value){Tag(s,field,0);Varint(s,unchecked((ulong)value));}
    static void Bytes(Stream s,int field,ReadOnlySpan<byte> value){Tag(s,field,2);Varint(s,(ulong)value.Length);s.Write(value);}
    static void Text(Stream s,int field,string value)=>Bytes(s,field,Encoding.UTF8.GetBytes(value));
    static void Message(Stream s,int field,Action<Stream> write){using var body=new MemoryStream();write(body);Bytes(s,field,body.GetBuffer().AsSpan(0,(int)body.Length));}

    static void ValueInfo(Stream s,string name,int type,long[] shape)
    {
        Text(s,1,name);
        Message(s,2,t=>Message(t,1,tensor=>{Int(tensor,1,type);Message(tensor,2,dims=>{foreach(var d in shape)Message(dims,1,dim=>Int(dim,1,d));});}));
    }
    public void Input(string name,int type,params long[] shape)=>Message(inputs,11,s=>ValueInfo(s,name,type,shape));
    public void Output(string name,int type,params long[] shape)=>Message(outputs,12,s=>ValueInfo(s,name,type,shape));
    /// <summary>A weight stored in the external data file.</summary>
    public string Weight(string name,int type,long[] shape,ReadOnlySpan<byte> bytes)
    {
        if(data is null)
        {
            var raw=bytes.ToArray();
            Message(initializers,5,t=>{foreach(var d in shape)Int(t,1,d);Int(t,2,type);Text(t,8,name);Bytes(t,9,raw);});
            return name;
        }
        var padding=(int)((4096-data.Position%4096)%4096);if(padding>0)data.Write(new byte[padding]);
        var offset=data.Position;var length=bytes.Length;data.Write(bytes);
        Message(initializers,5,t=>
        {
            foreach(var d in shape)Int(t,1,d);Int(t,2,type);Text(t,8,name);
            Message(t,13,e=>{Text(e,1,"location");Text(e,2,dataName);});
            Message(t,13,e=>{Text(e,1,"offset");Text(e,2,offset.ToString(System.Globalization.CultureInfo.InvariantCulture));});
            Message(t,13,e=>{Text(e,1,"length");Text(e,2,length.ToString(System.Globalization.CultureInfo.InvariantCulture));});
            Int(t,14,1); // EXTERNAL
        });
        return name;
    }
    /// <summary>A small integer constant stored in the graph, such as a reshape target.</summary>
    public string Constant(params long[] values)
    {
        var name="const_"+counter++;var raw=new byte[values.Length*8];Buffer.BlockCopy(values,0,raw,0,raw.Length);
        Message(initializers,5,t=>{Int(t,1,values.Length);Int(t,2,Int64);Text(t,8,name);Bytes(t,9,raw);});
        return name;
    }
    /// <summary>A small float vector stored in the graph, such as resize scales.</summary>
    public string Floats(params float[] values)
    {
        var name="floats_"+counter++;var raw=new byte[values.Length*4];Buffer.BlockCopy(values,0,raw,0,raw.Length);
        Message(initializers,5,t=>{Int(t,1,values.Length);Int(t,2,Float);Text(t,8,name);Bytes(t,9,raw);});
        return name;
    }
    /// <summary>A scalar in the graph's floating type.</summary>
    public string Scalar(float value,int type)
    {
        var name="scalar_"+counter++;
        var raw=type==Float16?BitConverter.GetBytes(BitConverter.HalfToUInt16Bits((Half)value)):BitConverter.GetBytes(value);
        Message(initializers,5,t=>{Int(t,2,type);Text(t,8,name);Bytes(t,9,raw);});
        return name;
    }
    public string Node(string op,string[] from,Action<Attributes>? attributes=null)=>Node(op,from,1,attributes)[0];
    public string[] Node(string op,string[] from,int results,Action<Attributes>? attributes=null)
    {
        var id=counter++;var produced=Enumerable.Range(0,results).Select(i=>$"{op}_{id}_{i}").ToArray();
        Message(nodes,1,n=>
        {
            foreach(var name in from)Text(n,1,name);foreach(var name in produced)Text(n,2,name);
            Text(n,3,$"{op}_{id}");Text(n,4,op);attributes?.Invoke(new(n));
        });
        return produced;
    }
    public sealed class Attributes(Stream node)
    {
        public Attributes Int(string name,long value){Message(node,5,a=>{Text(a,1,name);OnnxGraph.Int(a,3,value);OnnxGraph.Int(a,20,2);});return this;}
        public Attributes Float(string name,float value){Message(node,5,a=>{Text(a,1,name);Tag(a,2,5);a.Write(BitConverter.GetBytes(value));OnnxGraph.Int(a,20,1);});return this;}
        public Attributes String(string name,string value){Message(node,5,a=>{OnnxGraph.Text(a,1,name);OnnxGraph.Text(a,4,value);OnnxGraph.Int(a,20,3);});return this;}
        public Attributes Ints(string name,params long[] values){Message(node,5,a=>{Text(a,1,name);foreach(var v in values)OnnxGraph.Int(a,8,v);OnnxGraph.Int(a,20,7);});return this;}
    }
    /// <summary>Rename a produced value to a graph output.</summary>
    public void Identity(string from,string to)=>Message(nodes,1,n=>{Text(n,1,from);Text(n,2,to);Text(n,3,"out_"+to);Text(n,4,"Identity");});
    public byte[] Build(string name,int opset=17)
    {
        using var model=new MemoryStream();
        Int(model,1,8); // ir_version
        Text(model,2,"sbox-humanoid-mocap");
        Message(model,7,g=>
        {
            g.Write(nodes.GetBuffer(),0,(int)nodes.Length);Text(g,2,name);
            g.Write(initializers.GetBuffer(),0,(int)initializers.Length);
            g.Write(inputs.GetBuffer(),0,(int)inputs.Length);g.Write(outputs.GetBuffer(),0,(int)outputs.Length);
        });
        Message(model,8,o=>{Text(o,1,"");Int(o,2,opset);});
        return model.ToArray();
    }
}