Editor/Gpu/FlowGpuRefiner.cs
// C# adaptation of FlowHMR's SingleTokenRefiner. See THIRD_PARTY_NOTICES.md.
using System.Threading;
using Sandbox;
using HumanoidMocapX.TensorInference;
namespace HumanoidMocapX.Inference;
internal sealed class FlowGpuRefiner
{
readonly FlowGpuLinear embed;
readonly FlowGpuMlp contextMlp, timeMlp;
readonly Block[] blocks;
readonly GpuBuffer<float> embedded, mean, context, time, condition, activated;
internal FlowGpuRefiner(FlowGpuStorage storage, FlowWeights weights, FlowGpuWorkspace workspace)
{
var width = workspace.Width;
const string prefix = "text_refiner.";
embed = new(storage, weights, prefix + "input_embedder", width, width);
contextMlp = new(storage, weights, prefix + "context_encoder.linears", width);
timeMlp = new(storage, weights, prefix + "timestep_encoder.blocks", width);
embedded = storage.Create<float>(workspace.StreamElements); mean = storage.Create<float>(width);
context = storage.Create<float>(width); time = storage.Create<float>(width);
condition = storage.Create<float>(width); activated = storage.Create<float>(width);
blocks = new Block[2];
for (var i = 0; i < blocks.Length; i++)
blocks[i] = new(storage, weights, prefix + "individual_token_refiner.blocks." + i, width);
}
internal void SetVideo(FlowGpuWorkspace workspace, GpuBuffer<float> input)
{
workspace.Kernels.MeanRows(input, mean, workspace.Frames, workspace.Width);
contextMlp.Run(workspace, mean, context);
embed.Run(workspace.Kernels, input, embedded, workspace.Frames);
}
internal void Run(FlowGpuWorkspace workspace, GpuBuffer<float> embedding, GpuBuffer<float> features,
CancellationToken cancellation)
{
timeMlp.Run(workspace, embedding, time);
workspace.Kernels.Add(time, context, condition, workspace.Width);
workspace.Kernels.Activate(condition, activated, workspace.Width, TensorActivation.Silu);
embedded.CopyTo(workspace.Slice, workspace.StreamElements);
foreach (var block in blocks)
{ cancellation.ThrowIfCancellationRequested(); block.Run(workspace, activated); }
workspace.Slice.CopyTo(features, 0, workspace.StreamElements, workspace.StreamElements);
}
sealed class Block
{
readonly FlowGpuLinear qkv, projection, first, second, modulation;
readonly GpuBuffer<float> norm1Scale, norm1Bias, norm2Scale, norm2Bias, queryScale, queryBias, keyScale, keyBias;
internal Block(FlowGpuStorage storage, FlowWeights weights, string name, int width)
{
qkv = new(storage, weights, name + ".self_attn_qkv", width, 3 * width);
projection = new(storage, weights, name + ".self_attn_proj", width, width);
first = new(storage, weights, name + ".mlp.fc1", width, 4 * width);
second = new(storage, weights, name + ".mlp.fc2", 4 * width, width);
modulation = new(storage, weights, name + ".adaLN_modulation.linear", width, 2 * width);
norm1Scale = storage.Weight(weights, name + ".norm1.weight", width);
norm1Bias = storage.Weight(weights, name + ".norm1.bias", width);
norm2Scale = storage.Weight(weights, name + ".norm2.weight", width);
norm2Bias = storage.Weight(weights, name + ".norm2.bias", width);
queryScale = storage.Weight(weights, name + ".self_attn_q_norm.weight", FlowGpuWorkspace.HeadWidth);
queryBias = storage.Weight(weights, name + ".self_attn_q_norm.bias", FlowGpuWorkspace.HeadWidth);
keyScale = storage.Weight(weights, name + ".self_attn_k_norm.weight", FlowGpuWorkspace.HeadWidth);
keyBias = storage.Weight(weights, name + ".self_attn_k_norm.bias", FlowGpuWorkspace.HeadWidth);
}
internal void Run(FlowGpuWorkspace w, GpuBuffer<float> condition)
{
var k = w.Kernels; var rows = w.Frames; var width = w.Width;
modulation.Run(k, condition, w.MotionGates);
k.Normalize(w.Slice, norm1Scale, norm1Bias, w.Normalized, rows, width);
qkv.Run(k, w.Normalized, w.Packed, rows);
w.PrepareQkv(rows, 3 * width, 0, queryScale, keyScale, queryBias, keyBias, false);
w.Attend(false);
projection.Run(k, w.Attended, w.Projected, rows);
k.GatedAdd(w.Slice, w.Projected, w.MotionGates, w.Next, rows, width, 0);
w.Next.CopyTo(w.Slice, w.StreamElements);
k.Normalize(w.Slice, norm2Scale, norm2Bias, w.Normalized, rows, width);
first.Run(k, w.Normalized, w.Hidden, rows);
k.Activate(w.Hidden, w.Activated, 4 * w.StreamElements, TensorActivation.Silu);
second.Run(k, w.Activated, w.Projected, rows);
k.GatedAdd(w.Slice, w.Projected, w.MotionGates, w.Next, rows, width, width);
w.Next.CopyTo(w.Slice, w.StreamElements);
}
}
}