Editor/Inference/FlowDoubleBlock.cs
// C# adaptation of FlowHMR's MMDoubleStreamBlock. See THIRD_PARTY_NOTICES.md.
using System;
using System.Threading;
namespace HumanoidMocapX.Inference;
internal sealed class FlowDoubleBlock
{
readonly Branch motion, video;
internal FlowDoubleBlock(FlowWeights weights, int index, int width, int heads)
{
var name = "double_blocks." + index;
motion = new(weights, name + ".motion", width, heads);
video = new(weights, name + ".text", width, heads);
}
internal void Run(Span<float> features, ReadOnlySpan<float> activatedAdapter, FlowBlockBuffers buffers, CancellationToken cancellation)
{
var count = buffers.StreamElements; var width = buffers.Width;
var motionGates = buffers.Gates.AsSpan(0, 6 * width); var videoGates = buffers.Gates.AsSpan(6 * width, 6 * width);
motion.Prepare(features[..count], activatedAdapter, motionGates, buffers, 0, cancellation);
video.Prepare(features[count..], activatedAdapter, videoGates, buffers, buffers.Frames, cancellation);
buffers.Attend(cancellation);
motion.Finish(features[..count], buffers.Attended.AsSpan(0, count), motionGates, buffers, cancellation);
video.Finish(features[count..], buffers.Attended.AsSpan(count), videoGates, buffers, cancellation);
}
sealed class Branch
{
readonly FlowLinear modulation, qkv, projection, mlpFirst, mlpSecond;
readonly Tensor queryScale, keyScale;
internal Branch(FlowWeights weights, string name, int width, int heads)
{
modulation = new(weights, name + "_mod.linear", width, 6 * width);
qkv = new(weights, name + "_qkv", width, 3 * width);
projection = new(weights, name + "_out_proj", width, width);
mlpFirst = new(weights, name + "_mlp.fc1", width, 4 * width);
mlpSecond = new(weights, name + "_mlp.fc2", 4 * width, width);
queryScale = weights.Get(name + "_q_norm.weight", width / heads);
keyScale = weights.Get(name + "_k_norm.weight", width / heads);
}
internal void Prepare(ReadOnlySpan<float> features, ReadOnlySpan<float> adapter, Span<float> gates,
FlowBlockBuffers buffers, int firstRow, CancellationToken cancellation)
{
var width = buffers.Width; var count = buffers.StreamElements;
modulation.Run(adapter, 1, gates, cancellation);
var normalized = buffers.Normalized.AsSpan(0, count);
buffers.LayerNorm.Run(features, normalized);
FlowConditioning.Modulate(normalized, gates[..width], gates.Slice(width, width));
var packed = buffers.Packed.AsSpan(0, 3 * count);
qkv.Run(normalized, buffers.Frames, packed, cancellation);
buffers.PrepareQkv(packed, buffers.Frames, 3 * width, firstRow, queryScale, keyScale);
}
internal void Finish(Span<float> features, ReadOnlySpan<float> attended, ReadOnlySpan<float> gates,
FlowBlockBuffers buffers, CancellationToken cancellation)
{
var width = buffers.Width; var count = buffers.StreamElements;
var projected = buffers.Projected.AsSpan(0, count);
projection.Run(attended, buffers.Frames, projected, cancellation);
FlowConditioning.AddGated(features, projected, gates.Slice(2 * width, width));
var normalized = buffers.Normalized.AsSpan(0, count);
buffers.LayerNorm.Run(features, normalized);
FlowConditioning.Modulate(normalized, gates.Slice(3 * width, width), gates.Slice(4 * width, width));
var hidden = buffers.Packed.AsSpan(0, 4 * count);
mlpFirst.Run(normalized, buffers.Frames, hidden, cancellation); FlowConditioning.Gelu(hidden);
mlpSecond.Run(hidden, buffers.Frames, projected, cancellation);
FlowConditioning.AddGated(features, projected, gates.Slice(5 * width, width));
}
}
}