Editor/Inference/SamPredictionHead.cs
// C# adaptation of SAM 3D Body's body/hand prediction heads. See LICENSE-SAM and THIRD_PARTY_NOTICES.md.
// Copyright (c) Meta Platforms, Inc. and affiliates.
using System;
using System.Threading;
namespace HumanoidMocapX.Inference;
/// <summary>Predicts pose or camera parameters from one normalized decoder token.
/// Each layer adds the fixed learned initialization, not the preceding prediction.</summary>
internal sealed class SamPredictionHead
{
readonly FlowLinear first, second;
readonly Tensor initial;
readonly float[] hidden;
readonly int width;
internal int Parameters => initial.Data.Length;
internal SamPredictionHead(FlowWeights weights, bool hand = false, bool camera = false, int width = 1024)
{
if (width < 1) throw new ArgumentOutOfRangeException(nameof(width));
this.width = width;
var part = camera ? "camera" : "pose"; var suffix = hand ? "_hand" : "";
var name = "head_" + part + suffix + ".proj.layers.";
var count = camera ? 3 : SamMhrParameters.Predictions;
first = new(weights, name + "0.0", width, width); second = new(weights, name + "1", width, count);
initial = weights.Get("init_" + part + suffix + ".weight", count, 1);
hidden = new float[width];
}
/// <summary>Writes the complete prediction. Rejects non-finite tokens, bad
/// dimensions or overlapping buffers. Reuse sequentially; cancellation propagates.</summary>
internal void Run(ReadOnlySpan<float> token, Span<float> output, CancellationToken cancellation = default)
{
cancellation.ThrowIfCancellationRequested();
if (token.Length != width || output.Length != Parameters || token.Overlaps(output) || output.Overlaps(initial.Data))
throw new ArgumentException("SAM prediction head input/output dimensions are invalid or overlap.");
SamDecoder.Finite(token);
first.Run(token, 1, hidden, cancellation); NeuralOps.Relu(hidden);
second.Run(hidden, 1, output, cancellation); NeuralOps.AddInPlace(output, initial.Data);
SamDecoder.Finite(output);
}
internal void CopyInitial(Span<float> output)
{
if (output.Length != Parameters) throw new ArgumentException("SAM initial prediction output has the wrong size.");
initial.Data.AsSpan().CopyTo(output);
}
}