Tensor/TensorKernels.Layout.cs
using System;
using Sandbox;
namespace HumanoidMocapX.TensorInference;
public sealed partial class TensorKernels
{
readonly ComputeShader layout = new("shaders/tensor-inference/layout/layout_compute.shader");
readonly ComputeShader rotary = new("shaders/tensor-inference/rotary/rotary_compute.shader");
readonly ComputeShader mean = new("shaders/tensor-inference/reduction/mean_compute.shader");
/// <summary>Extracts columns starting at firstColumn from input[rows,inputWidth]
/// into output[rows,columns]. Rejects invalid slices, undersized buffers and aliasing.</summary>
public void CopyColumns(GpuBuffer<float> input, GpuBuffer<float> output, int rows, int inputWidth, int firstColumn, int columns)
{
var count = MatrixElements(rows, columns);
if (firstColumn < 0 || inputWidth < 1 || (long)firstColumn + columns > inputWidth)
throw new ArgumentException("Requested columns fall outside the input matrix.");
Require(input, (long)rows * inputWidth, nameof(input)); Require(output, count, nameof(output));
Layout(input, input, output, count, inputWidth, 0, firstColumn, columns);
}
/// <summary>Concatenates first[rows,firstWidth] and second[rows,secondWidth] by row.
/// Rejects invalid dimensions, undersized buffers and output aliasing.</summary>
public void ConcatColumns(GpuBuffer<float> first, GpuBuffer<float> second, GpuBuffer<float> output,
int rows, int firstWidth, int secondWidth)
{
Require(first, MatrixElements(rows, firstWidth), nameof(first));
Require(second, MatrixElements(rows, secondWidth), nameof(second));
var columns = checked(firstWidth + secondWidth); var count = MatrixElements(rows, columns);
Require(output, count, nameof(output));
Layout(first, second, output, count, firstWidth, secondWidth, 0, columns);
}
void Layout(GpuBuffer<float> first, GpuBuffer<float> second, GpuBuffer<float> output, int count,
int firstWidth, int secondWidth, int firstColumn, int columns)
{
if (ReferenceEquals(first, output) || ReferenceEquals(second, output))
throw new ArgumentException("Layout output must not overlap its inputs.");
var attributes = layout.Attributes;
attributes.Set("First", first); attributes.Set("Second", second); attributes.Set("Output", output);
attributes.Set("Count", count); attributes.Set("FirstWidth", firstWidth); attributes.Set("SecondWidth", secondWidth);
attributes.Set("FirstColumn", firstColumn); attributes.Set("Columns", columns);
DispatchElements(layout, count);
CompleteWrite(output);
}
/// <summary>Rotates adjacent pairs in values[rows,width] in place. Factors are
/// [positions,headWidth] interleaved cos/sin values; positions repeat per stream.
/// splitHalves pairs the first and second half of each head instead of neighbors.
/// Rejects inconsistent dimensions, undersized buffers and factor/value aliasing.</summary>
public void Rotary(GpuBuffer<float> values, GpuBuffer<float> factors, int rows, int width, int headWidth, int positions, bool splitHalves = false)
{
var count = MatrixElements(rows, width);
if (headWidth < 2 || headWidth % 2 != 0 || width % headWidth != 0 || positions < 1 || rows % positions != 0)
throw new ArgumentException("Rotary embedding needs even heads and a position table covering each stream.");
Require(values, count, nameof(values)); Require(factors, (long)positions * headWidth, nameof(factors));
if (ReferenceEquals(values, factors)) throw new ArgumentException("Rotary factors must not overlap the values being rotated.");
var attributes = rotary.Attributes;
attributes.Set("Values", values); attributes.Set("Factors", factors); attributes.Set("Pairs", count / 2);
attributes.Set("Width", width); attributes.Set("HeadWidth", headWidth); attributes.Set("Positions", positions);
attributes.Set("SplitHalves", splitHalves ? 1 : 0);
DispatchElements(rotary, count / 2);
CompleteWrite(values);
}
/// <summary>Computes the mean of input[rows,width] into output[width]. Rejects
/// invalid dimensions, undersized buffers and input/output aliasing.</summary>
public void MeanRows(GpuBuffer<float> input, GpuBuffer<float> output, int rows, int width)
{
var count = MatrixElements(rows, width);
Require(input, count, nameof(input)); Require(output, width, nameof(output));
if (ReferenceEquals(input, output)) throw new ArgumentException("Mean output must not overlap its input.");
var attributes = mean.Attributes;
attributes.Set("Input", input); attributes.Set("Output", output); attributes.Set("Rows", rows); attributes.Set("Width", width);
DispatchElements(mean, width);
CompleteWrite(output);
}
}