Editor/Inference/DinoImageEncoder.cs
// C# adaptation of the Omega and SAM DINO encoders. See LICENSE-VGGT, LICENSE-DINOV3 and THIRD_PARTY_NOTICES.md.
// Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved.
using System;
using System.Threading;
namespace HumanoidMocapX.Inference;
internal sealed class DinoImageEncoder
{
readonly DinoShape shape;
readonly Tensor weight, bias, classToken, registers, norm, normBias;
readonly OmegaBlock[] blocks;
readonly OmegaWorkspace workspace;
readonly FlowAttention attention;
readonly float[] features, positions, normalizedImage;
internal DinoImageEncoder(FlowWeights weights, OmegaShape shape) : this(weights, DinoShape.Omega(shape)) { }
internal DinoImageEncoder(FlowWeights weights, DinoShape shape)
{
if (shape.Channels == 0) throw new ArgumentException("Construct a valid DINO shape.", nameof(shape));
this.shape = shape; var width = shape.Channels;
var name = shape.Name; blocks = new OmegaBlock[shape.Depth];
weight = weights.Get(name + ".patch_embed.proj.weight", 16, 16, 3, width);
bias = weights.Get(name + ".patch_embed.proj.bias", width);
classToken = weights.Get(name + ".cls_token", width, 1, 1); registers = weights.Get(name + ".storage_tokens", width, 4, 1);
norm = weights.Get(name + ".norm.weight", width); normBias = weights.Get(name + ".norm.bias", width);
positions = OmegaPosition.Factors(shape.Height / 16, shape.Width / 16, DinoShape.PrefixTokens,
weights.Get(name + ".rope_embed.periods", width / shape.Heads / 4).Data, shape.IsSam);
for (var i = 0; i < blocks.Length; i++) blocks[i] = new(weights, name + ".blocks." + i, width, shape.Heads, false, shape.IsSam);
workspace = new(shape.Tokens, width, shape.IsSam); attention = new(shape.Tokens, width, shape.Heads, false);
features = new float[shape.Tokens * width]; normalizedImage = new float[shape.ImageElements];
}
/// <summary>Encodes one resized HWC RGB image in [0,1] into patch features. CPU
/// reference path; reuse the instance sequentially. Rejects invalid/aliased tensors.</summary>
internal void Run(ReadOnlySpan<float> image, Span<float> output, CancellationToken cancellation = default)
{
cancellation.ThrowIfCancellationRequested();
if (image.Length != shape.ImageElements || output.Length != shape.Patches * shape.Channels || image.Overlaps(output))
throw new ArgumentException("DINO image encoder tensors have invalid dimensions or overlap.");
NormalizeImage(image, normalizedImage); cancellation.ThrowIfCancellationRequested();
classToken.Data.CopyTo(features, 0); registers.Data.CopyTo(features, shape.Channels);
Project(cancellation);
foreach (var block in blocks) block.Run(features, workspace, attention, positions, cancellation);
features.AsSpan(DinoShape.PrefixTokens * shape.Channels).CopyTo(output);
NeuralOps.LayerNorm(output, shape.Patches, shape.Channels, norm, normBias);
}
internal static void NormalizeImage(ReadOnlySpan<float> image, Span<float> output)
{
if (image.Length != output.Length || image.Length % 3 != 0) throw new ArgumentException("DINO images need complete RGB pixels.");
for (var i = 0; i < image.Length; i++)
{
var pixel = image[i];
if (!float.IsFinite(pixel) || pixel < 0 || pixel > 1) throw new ArgumentException("DINO input pixels must be finite and between zero and one.");
var mean = i % 3 == 0 ? .485f : i % 3 == 1 ? .456f : .406f;
var deviation = i % 3 == 0 ? .229f : i % 3 == 1 ? .224f : .225f;
output[i] = (pixel - mean) / deviation;
}
}
void Project(CancellationToken cancellation)
{
for (var y = 0; y < shape.Height / 16; y++)
for (var x = 0; x < shape.Width / 16; x++)
{
cancellation.ThrowIfCancellationRequested();
var destination = ((y * (shape.Width / 16) + x) + DinoShape.PrefixTokens) * shape.Channels;
for (var channel = 0; channel < shape.Channels; channel++)
{
var sum = bias.Data[channel];
for (var color = 0; color < 3; color++)
for (var ky = 0; ky < 16; ky++)
for (var kx = 0; kx < 16; kx++)
sum += normalizedImage[((y * 16 + ky) * shape.Width + x * 16 + kx) * 3 + color]
* weight.Data[((channel * 3 + color) * 16 + ky) * 16 + kx];
features[destination + channel] = sum;
}
}
}
}