diff --git a/OnnxStack.StableDiffusion/Helpers/TensorHelper.cs b/OnnxStack.StableDiffusion/Helpers/TensorHelper.cs index c7a368a8..60fbda3c 100644 --- a/OnnxStack.StableDiffusion/Helpers/TensorHelper.cs +++ b/OnnxStack.StableDiffusion/Helpers/TensorHelper.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; - +using System.Numerics.Tensors; namespace OnnxStack.StableDiffusion.Helpers { @@ -14,6 +14,7 @@ namespace OnnxStack.StableDiffusion.Helpers public static class TensorHelper { private static readonly int vectorSize = Vector.Count; + /// /// Creates a new tensor. /// @@ -44,17 +45,9 @@ public static DenseTensor CreateTensor(T[] data, ReadOnlySpan dimensi /// public static DenseTensor MultiplyTensorByFloat(this DenseTensor tensor, float value) { - var mullTensor = new DenseTensor(tensor.Dimensions); - for (int i = 0; i < tensor.Length / vectorSize; i++) - { - (new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)) * value) - .CopyTo(mullTensor.Buffer.Span.Slice(i * vectorSize, vectorSize)); - } - for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) - { - mullTensor.Buffer.Span[i] = tensor.Buffer.Span[i] * value; - } - return mullTensor; + var result = new DenseTensor(tensor.Dimensions); + TensorPrimitives.Multiply(tensor.Buffer.Span, value, result.Buffer.Span); + return result; } @@ -66,20 +59,12 @@ public static DenseTensor MultiplyTensorByFloat(this DenseTensor t /// public static DenseTensor SubtractFloat(this DenseTensor tensor, float value) { - var subTensor = new DenseTensor(tensor.Dimensions); - Vector vectorValue = new Vector(value); - for (int i = 0; i < tensor.Length / vectorSize; i++) - { - Vector.Subtract(new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)), vectorValue) - .CopyTo(subTensor.Buffer.Span.Slice(i * vectorSize, vectorSize)); - } - for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) - { - subTensor.Buffer.Span[i] = tensor.Buffer.Span[i] - value; - } - return subTensor; + var result = new DenseTensor(tensor.Dimensions); + TensorPrimitives.Subtract(tensor.Buffer.Span, value, result.Buffer.Span); + return result; } + /// /// Adds the tensors. /// @@ -88,18 +73,9 @@ public static DenseTensor SubtractFloat(this DenseTensor tensor, f /// public static DenseTensor AddTensors(this DenseTensor tensor, DenseTensor sumTensor) { - var addTensor = new DenseTensor(tensor.Dimensions); - for (int i = 0; i < tensor.Length / vectorSize; i++) - { - (new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)) - + new Vector(sumTensor.Buffer.Span.Slice(i * vectorSize, vectorSize))) - .CopyTo(addTensor.Buffer.Span.Slice(i * vectorSize, vectorSize)); - } - for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) - { - addTensor.Buffer.Span[i] = tensor.Buffer.Span[i] + sumTensor.Buffer.Span[i]; - } - return addTensor; + var result = new DenseTensor(tensor.Dimensions); + TensorPrimitives.Add(tensor.Buffer.Span, sumTensor.Buffer.Span, result.Buffer.Span); + return result; } @@ -111,12 +87,12 @@ public static DenseTensor AddTensors(this DenseTensor tensor, Dens /// public static DenseTensor SumTensors(this DenseTensor[] tensors, ReadOnlySpan dimensions) { - var sumTensor = new DenseTensor(dimensions); + var result = new DenseTensor(dimensions); for (int m = 0; m < tensors.Length; m++) { - sumTensor.Add(tensors[m]); + TensorPrimitives.Add(result.Buffer.Span, tensors[m].Buffer.Span, result.Buffer.Span); } - return sumTensor; + return result; } @@ -129,68 +105,31 @@ public static DenseTensor SumTensors(this DenseTensor[] tensors, R public static DenseTensor SubtractTensors(this DenseTensor tensor, DenseTensor subTensor) { var result = new DenseTensor(tensor.Dimensions); - for (int i = 0; i < tensor.Length / vectorSize; i++) - { - (new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)) - - new Vector(subTensor.Buffer.Span.Slice(i * vectorSize, vectorSize))) - .CopyTo(result.Buffer.Span.Slice(i * vectorSize, vectorSize)); - } - for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) - { - result.Buffer.Span[i] = tensor.Buffer.Span[i] - subTensor.Buffer.Span[i]; - } + TensorPrimitives.Subtract(tensor.Buffer.Span, subTensor.Buffer.Span, result.Buffer.Span); return result; } - /// - /// Reorders the tensor. + /// Divides the tensor by float, mutates the original /// - /// The input tensor. + /// The tensor to mutate. + /// The value to divide by. /// - public static DenseTensor ReorderTensor(this DenseTensor tensor, ReadOnlySpan dimensions) + public static DenseTensor DivideBy(this DenseTensor tensor, float value) { - //reorder from batch channel height width to batch height width channel - var inputImagesTensor = new DenseTensor(dimensions); - for (int y = 0; y < tensor.Dimensions[2]; y++) - { - for (int x = 0; x < tensor.Dimensions[3]; x++) - { - inputImagesTensor[0, y, x, 0] = tensor[0, 0, y, x]; - inputImagesTensor[0, y, x, 1] = tensor[0, 1, y, x]; - inputImagesTensor[0, y, x, 2] = tensor[0, 2, y, x]; - } - } - return inputImagesTensor; + value = 1 / value; + TensorPrimitives.Multiply(tensor.Buffer.Span, value, tensor.Buffer.Span); + return tensor; } /// - /// Clips the specified Tensor valuse to the specified minimum/maximum. + /// Multiples the tensor by float, mutates the original /// - /// The tensor. - /// The minimum value. - /// The maximum value. + /// The tensor to mutate. + /// The value to multiply by. /// - public static DenseTensor Clip(this DenseTensor tensor, float minValue, float maxValue) - { - Vector min = new Vector(minValue); - Vector max = new Vector(maxValue); - var clipTensor = new DenseTensor(tensor.Dimensions); - for (int i = 0; i < tensor.Length / vectorSize; i++) - { - Vector.Min(min, - Vector.Max(max, - new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)))) - .CopyTo(clipTensor.Buffer.Span.Slice(i * vectorSize, vectorSize)); - } - for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) - { - clipTensor.Buffer.Span[i] = Math.Clamp(tensor.Buffer.Span[i], minValue, maxValue); - } - return clipTensor; - - } + public static DenseTensor MultiplyBy(this DenseTensor tensor, float value) => DivideBy(tensor, 1 / value); /// @@ -200,16 +139,7 @@ public static DenseTensor Clip(this DenseTensor tensor, float minV /// public static DenseTensor Abs(this DenseTensor tensor) { - for (int i = 0; i < tensor.Length / vectorSize; i++) - { - Span buffer = tensor.Buffer.Span.Slice(i * vectorSize, vectorSize); - Vector.Abs(new Vector(buffer)) - .CopyTo(buffer); - } - for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) - { - tensor.Buffer.Span[i] = Math.Abs(tensor.Buffer.Span[i]); - } + TensorPrimitives.Abs(tensor.Buffer.Span, tensor.Buffer.Span); return tensor; } @@ -222,16 +152,7 @@ public static DenseTensor Abs(this DenseTensor tensor) /// public static DenseTensor Multiply(this DenseTensor tensor, DenseTensor mulTensor) { - for (int i = 0; i < tensor.Length / vectorSize; i++) - { - (new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)) - * new Vector(mulTensor.Buffer.Span.Slice(i * vectorSize, vectorSize))) - .CopyTo(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)); - } - for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) - { - tensor.Buffer.Span[i] = tensor.Buffer.Span[i] * mulTensor.Buffer.Span[i]; - } + TensorPrimitives.Multiply(tensor.Buffer.Span, mulTensor.Buffer.Span, tensor.Buffer.Span); return tensor; } @@ -244,17 +165,85 @@ public static DenseTensor Multiply(this DenseTensor tensor, DenseT /// public static DenseTensor Divide(this DenseTensor tensor, DenseTensor divTensor) { + TensorPrimitives.Divide(tensor.Buffer.Span, divTensor.Buffer.Span, tensor.Buffer.Span); + return tensor; + } + + + /// + /// Adds the tensors, mutates the original + /// + /// The tensor to mutate. + /// The tensor values to add to tensor. + /// + public static DenseTensor Add(this DenseTensor tensor, DenseTensor addTensor) + { + TensorPrimitives.Add(tensor.Buffer.Span, addTensor.Buffer.Span, tensor.Buffer.Span); + return tensor; + } + + + /// + /// Subtracts the tensors, mutates the original + /// + /// The tensor to mutate. + /// The tensor to subtract from tensor. + /// The dimensions. + /// + public static DenseTensor Subtract(this DenseTensor tensor, DenseTensor subTensor) + { + TensorPrimitives.Subtract(tensor.Buffer.Span, subTensor.Buffer.Span, tensor.Buffer.Span); + return tensor; + } + + + /// + /// Reorders the tensor. + /// + /// The input tensor. + /// + public static DenseTensor ReorderTensor(this DenseTensor tensor, ReadOnlySpan dimensions) + { + //reorder from batch channel height width to batch height width channel + var inputImagesTensor = new DenseTensor(dimensions); + for (int y = 0; y < tensor.Dimensions[2]; y++) + { + for (int x = 0; x < tensor.Dimensions[3]; x++) + { + inputImagesTensor[0, y, x, 0] = tensor[0, 0, y, x]; + inputImagesTensor[0, y, x, 1] = tensor[0, 1, y, x]; + inputImagesTensor[0, y, x, 2] = tensor[0, 2, y, x]; + } + } + return inputImagesTensor; + } + + + /// + /// Clips the specified Tensor valuse to the specified minimum/maximum. + /// + /// The tensor. + /// The minimum value. + /// The maximum value. + /// + public static DenseTensor Clip(this DenseTensor tensor, float minValue, float maxValue) + { + Vector min = new Vector(minValue); + Vector max = new Vector(maxValue); + var clipTensor = new DenseTensor(tensor.Dimensions); for (int i = 0; i < tensor.Length / vectorSize; i++) { - (new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)) - / new Vector(divTensor.Buffer.Span.Slice(i * vectorSize, vectorSize))) - .CopyTo(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)); + Vector.Min(min, + Vector.Max(max, + new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)))) + .CopyTo(clipTensor.Buffer.Span.Slice(i * vectorSize, vectorSize)); } for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) { - tensor.Buffer.Span[i] = tensor.Buffer.Span[i] / divTensor.Buffer.Span[i]; + clipTensor.Buffer.Span[i] = Math.Clamp(tensor.Buffer.Span[i], minValue, maxValue); } - return tensor; + return clipTensor; + } @@ -283,6 +272,7 @@ public static DenseTensor Concatenate(this DenseTensor tensor1, De return new DenseTensor(buffer, dimensions); } + private static DenseTensor Concatenate(DenseTensor tensor1, DenseTensor tensor2) { var dimensions = new int[] { tensor1.Dimensions[0], tensor1.Dimensions[1], tensor1.Dimensions[2] + tensor2.Dimensions[2] }; @@ -304,7 +294,6 @@ private static DenseTensor Concatenate(DenseTensor tensor1, DenseT } - /// /// Repeats the specified Tensor along the 0 axis. /// @@ -408,82 +397,5 @@ public static DenseTensor Join(this IList> tensors, in } return new DenseTensor(buffer, dimensions); } - - - /// - /// Adds the tensors, mutates the original - /// - /// The tensor to mutate. - /// The tensor values to add to tensor. - /// - public static DenseTensor Add(this DenseTensor tensor, DenseTensor addTensor) - { - for (int i = 0; i < tensor.Length / vectorSize; i++) - { - (new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)) - + new Vector(addTensor.Buffer.Span.Slice(i * vectorSize, vectorSize))) - .CopyTo(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)); - } - for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) - { - tensor.Buffer.Span[i] = tensor.Buffer.Span[i] + addTensor.Buffer.Span[i]; - } - return tensor; - } - - - /// - /// Subtracts the tensors, mutates the original - /// - /// The tensor to mutate. - /// The tensor to subtract from tensor. - /// The dimensions. - /// - public static DenseTensor Subtract(this DenseTensor tensor, DenseTensor subTensor) - { - for (int i = 0; i < tensor.Length / vectorSize; i++) - { - (new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)) - - new Vector(subTensor.Buffer.Span.Slice(i * vectorSize, vectorSize))) - .CopyTo(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)); - } - for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) - { - tensor.Buffer.Span[i] = tensor.Buffer.Span[i] - subTensor.Buffer.Span[i]; - } - return tensor; - } - - - /// - /// Divides the tensor by float, mutates the original - /// - /// The tensor to mutate. - /// The value to divide by. - /// - public static DenseTensor DivideBy(this DenseTensor tensor, float value) - { - value = 1 / value; - var mullTensor = new DenseTensor(tensor.Dimensions); - for (int i = 0; i < tensor.Length / vectorSize; i++) - { - (new Vector(tensor.Buffer.Span.Slice(i * vectorSize, vectorSize)) * value) - .CopyTo(mullTensor.Buffer.Span.Slice(i * vectorSize, vectorSize)); - } - for (int i = (int)(tensor.Length - tensor.Length % vectorSize); i < tensor.Length; i++) - { - mullTensor.Buffer.Span[i] = tensor.Buffer.Span[i] * value; - } - return mullTensor; - } - - - /// - /// Multiples the tensor by float, mutates the original - /// - /// The tensor to mutate. - /// The value to multiply by. - /// - public static DenseTensor MultiplyBy(this DenseTensor tensor, float value) => DivideBy(tensor, 1 / value); } }