using System; using UnityEngine; using System.Collections.Generic; namespace Unity.Barracuda { /// /// Proxy `IOps` implementation for tracking computational expenses for specific model /// public class StatsOps : IOps, IModelCompiler { class Transcendental { // Table of approximate alu operation costs // mul 1 // rcp/mad 2 // div/sqrt 10 // log/exp 100 // pow 200 // see: https://www.sciencedirect.com/topics/computer-science/division-operation // see: https://colfaxresearch.com/arithmetics-on-intels-sandy-bridge-and-westmere-cpus-not-all-flops-are-created-equal/ public const long Reciprocal = 2L; public const long Div = 10L; public const long Root = 10L; public const long Exponent = 100L; public const long Pow = 200L; public const long Trigonometric = 200L; } private IOps m_Ops; private LayerStat m_Alu; private LayerStat m_Mem; private readonly struct LayerStat { public readonly long total; public readonly long layer; public LayerStat(long totalBeforeLayer, long layer) { this.total = totalBeforeLayer + layer; this.layer = layer; } public static implicit operator long(LayerStat d) => d.total; public static LayerStat operator +(LayerStat a, long b) => new LayerStat(a.total, b); }; #if ENABLE_BARRACUDA_STATS public IEnumerable GetTempMemoryStatistics() { return m_Ops.GetTempMemoryStatistics(); } #endif //ENABLE_BARRACUDA_STATS /// /// Create `StatsOps` /// /// target ops public StatsOps(IOps ops) { m_Ops = ops; m_Alu = new LayerStat(0L,0L); m_Mem = new LayerStat(0L,0L); } /// public virtual void PostLayerCleanup() { m_Ops.PostLayerCleanup(); } /// public virtual void PrepareModel(Model model, IDictionary inputShapes, IVars vars) { if (m_Ops is IModelCompiler) ((IModelCompiler)m_Ops).PrepareModel(model, inputShapes, vars); } /// public virtual void PreExecuteLayer(Layer layer, Tensor[] inputs) { if (m_Ops is IModelCompiler) ((IModelCompiler)m_Ops).PreExecuteLayer(layer, inputs); } /// Tensor IOps.MatMul(Tensor X, int rankX, Tensor Y, int rankY) { var O = m_Ops.MatMul(X, rankX, Y, rankY); m_Alu += (long)X.height * (long)X.width * (long)Y.width * 2L * (long)X.batch * (long)X.channels; m_Mem += (long)X.length + (long)Y.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.MatMul(Tensor X, bool xTranspose, Tensor Y, bool yTranspose) { var O = m_Ops.MatMul(X, xTranspose, Y, yTranspose); m_Alu += (long)X.flatHeight * (long)X.flatWidth * (long)Y.flatWidth * 2L; m_Mem += (long)X.length + (long)Y.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Dense(Tensor X, Tensor W, Tensor B, Layer.FusedActivation fusedActivation) { var O = m_Ops.Dense(X, W, B, fusedActivation); m_Alu += (long)X.flatHeight * (long)X.flatWidth * (long)W.flatWidth * 2L; m_Mem += (long)X.length + (long)W.length + (long)B.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Dense3(Tensor X, Tensor W, Tensor B) { var O = m_Ops.Dense3(X, W, B); m_Alu += (long)X.height * (long)X.width * (long)W.width * 2L * (long)X.batch * (long)X.channels; m_Mem += (long)X.length + (long)W.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Conv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) { var O = m_Ops.Conv2D(X, K, B, stride, pad, fusedActivation); long m = (long)O.batch * (long)O.width * (long)O.height; long n = (long)X.channels; long k = (long)K.kernelWidth * (long)K.kernelHeight * (long)K.channels; m_Alu += m * n * k * 2L; m_Mem += (long)X.length + (long)K.length + (long)B.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Conv3D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) { var O = m_Ops.Conv3D(X, K, B, stride, pad, fusedActivation); long m = (long)O.batch * (long)O.width * (long)O.height * O.depth; long n = (long)X.channels; long k = (long)K.kernelSpatialDepth * K.kernelWidth * (long)K.kernelHeight * (long)K.channels; m_Alu += m * n * k * 2L; m_Mem += (long)X.length + (long)K.length + (long)B.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.DepthwiseConv2D(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, Layer.FusedActivation fusedActivation) { var O = m_Ops.DepthwiseConv2D(X, K, B, stride, pad, fusedActivation); long m = (long)O.batch * (long)O.width * (long)O.height; long n = (long)X.channels; long k = (long)K.kernelWidth * (long)K.kernelHeight; m_Alu += m * n * k * 2L; m_Mem += (long)X.length + (long)K.length + (long)B.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Conv2DTrans(Tensor X, Tensor K, Tensor B, int[] stride, int[] pad, int[] outputAdjustment, Layer.FusedActivation fusedActivation) { var O = m_Ops.Conv2DTrans(X, K, B, stride, pad, outputAdjustment, fusedActivation); long m = (long)O.batch * (long)O.width * (long)O.height; long n = (long)X.channels; long k = (long)(K.kernelWidth/stride[1]) * (long)(K.kernelHeight/stride[0]) * (long)K.channels; m_Alu += m * n * k * 2L; m_Mem += (long)X.length + (long)K.length + (long)B.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Upsample2D(Tensor X, int[] scale, bool bilinear) { var O = m_Ops.Upsample2D(X, scale, bilinear); m_Alu += (long)O.length * (bilinear ? 8 : 1); m_Mem += (long)X.length * (bilinear ? 4 : 1) + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Upsample3D(Tensor X, int[] scale, bool trilinear) { var O = m_Ops.Upsample3D(X, scale, trilinear); m_Alu += (long)O.length * (trilinear ? 18 : 1); m_Mem += (long)X.length * (trilinear ? 8 : 1) + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Resample2D(Tensor X, int[] size, bool bilinear) { var O = m_Ops.Resample2D(X, size, bilinear); m_Alu += (long)O.length * (bilinear ? 8 : 1); m_Mem += (long)X.length * (bilinear ? 4 : 1) + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.DepthToSpace(Tensor X, int[] scale, Layer.DepthToSpaceMode mode) { var O = m_Ops.DepthToSpace(X, scale, mode); m_Mem += (long)X.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.SpaceToDepth(Tensor X, int[] scale) { var O = m_Ops.SpaceToDepth(X, scale); m_Mem += (long)X.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.MaxPool2D(Tensor X, int[] pool, int[] stride, int[] pad) { var O = m_Ops.MaxPool2D(X, pool, stride, pad); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.AvgPool2D(Tensor X, int[] pool, int[] stride, int[] pad) { var O = m_Ops.AvgPool2D(X, pool, stride, pad); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.GlobalMaxPool2D(Tensor X) { var O = m_Ops.GlobalMaxPool2D(X); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.GlobalAvgPool2D(Tensor X) { var O = m_Ops.GlobalAvgPool2D(X); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.GlobalAvgVariancePool2D(Tensor X) { var O = m_Ops.GlobalAvgVariancePool2D(X); m_Alu += (long)X.length * 2L + (long)O.length; m_Mem += (long)X.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Border2D(Tensor X, int[] pad, float value) { var O = m_Ops.Border2D(X, pad, value); m_Alu += 0; m_Mem += (long)X.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Border3D(Tensor X, int[] pad, float value) { var O = m_Ops.Border3D(X, pad, value); m_Alu += 0; m_Mem += (long)X.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Pad2DReflect(Tensor X, int[] pad) { var O = m_Ops.Pad2DReflect(X, pad); m_Alu += 0; m_Mem += (long)X.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Pad2DSymmetric(Tensor X, int[] pad) { var O = m_Ops.Pad2DSymmetric(X, pad); m_Alu += 0; m_Mem += (long)X.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Pad2DEdge(Tensor X, int[] pad) { var O = m_Ops.Pad2DEdge(X, pad); m_Alu += 0; m_Mem += (long)X.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.ScaleBias(Tensor X, Tensor S, Tensor B) { Elementwise(X, 2L); RegisterLayerStats(); return m_Ops.ScaleBias(X, S, B); } /// Tensor IOps.Normalization(Tensor X, Tensor S, Tensor B, int pool, int axis, float epsilon, Layer.FusedActivation fusedActivation) { var O = m_Ops.Normalization(X, S, B, pool, axis, epsilon, fusedActivation); m_Alu += (long)X.length * 4L + (long)O.length * 2L; m_Mem += (long)X.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.LRN(Tensor X, float alpha, float beta, float bias, int size) { var O = m_Ops.LRN(X, alpha, beta, bias, size); //A bit over conservative. Number of read/alu is lower than `size` when normalisation windows is too large for data at current index. long sizeL = size; m_Alu += (long)X.length * (5L + sizeL * 2L); m_Mem += (long)X.length * (sizeL + 2L); RegisterLayerStats(); return O; } /// Tensor IOps.Dropout(Tensor X, float alpha) { Elementwise(X); return m_Ops.Dropout(X, alpha); } /// Tensor IOps.RandomNormal(TensorShape s, float mean, float scale, int seed) { var O = m_Ops.RandomNormal(s, mean, scale, seed); // @TODO: not implemented m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return O; } /// Tensor IOps.RandomUniform(TensorShape s, float mean, float scale, int seed) { var O = m_Ops.RandomUniform(s, mean, scale, seed); // @TODO: not implemented m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return O; } /// Tensor IOps.Multinomial(Tensor X, int count, int seed) { var O = m_Ops.Multinomial(X, count, seed); // @TODO: not implemented m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return O; } /// Tensor IOps.OneHot(Tensor X, int depth, float onValue, float offValue, int inputRank) { var O = m_Ops.OneHot(X, depth, onValue, offValue, inputRank); // @TODO: not implemented m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return O; } /// Tensor IOps.RoiAlign(Tensor X, Tensor rois, Tensor indices, int outputHeight, int outputWidth, int samplingRatio, float spatialScale) { var O = m_Ops.RoiAlign(X, rois, indices, outputHeight, outputWidth, samplingRatio, spatialScale); m_Alu += 4 * outputHeight * outputWidth * samplingRatio * samplingRatio; m_Mem += 4 * outputHeight * outputWidth * samplingRatio * samplingRatio; RegisterLayerStats(); return O; } /// Tensor IOps.TopKIndices(Tensor X, int k, int axis, bool largest, bool sorted) { var O = m_Ops.TopKIndices(X, k, axis, largest, sorted); // @TODO: not implemented m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return O; } /// public Tensor TopKValues(Tensor X, Tensor I, int axis) { var O = m_Ops.TopKValues(X, I, axis); // @TODO: not implemented m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return O; } /// public Tensor NonZero(Tensor X) { var O = m_Ops.NonZero(X); // @TODO: not implemented m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return O; } /// Tensor IOps.Relu(Tensor X) { Elementwise(X); RegisterLayerStats(); return m_Ops.Relu(X); } /// Tensor IOps.Softmax(Tensor X, int axis) { Elementwise(X, Transcendental.Exponent); RegisterLayerStats(); return m_Ops.Softmax(X, axis); } /// Tensor IOps.LogSoftmax(Tensor X, int axis) { Elementwise(X, Transcendental.Exponent); RegisterLayerStats(); return m_Ops.LogSoftmax(X, axis); } /// Tensor IOps.Tanh(Tensor X) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Tanh(X); } /// Tensor IOps.Softplus(Tensor X) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Softplus(X); } /// Tensor IOps.Sigmoid(Tensor X) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Sigmoid(X); } /// Tensor IOps.HardSigmoid(Tensor X, float alpha, float beta) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.HardSigmoid(X, alpha, beta); } /// Tensor IOps.Relu6(Tensor X) { Elementwise(X, 4L); RegisterLayerStats(); return m_Ops.Relu6(X); } /// Tensor IOps.Elu(Tensor X, float alpha) { Elementwise(X, Transcendental.Exponent); RegisterLayerStats(); return m_Ops.Elu(X, alpha); } /// Tensor IOps.LeakyRelu(Tensor X, float alpha) { Elementwise(X, 4L); RegisterLayerStats(); return m_Ops.LeakyRelu(X, alpha); } /// Tensor IOps.Selu(Tensor X, float alpha, float gamma) { Elementwise(X, Transcendental.Exponent); RegisterLayerStats(); return m_Ops.Selu(X, alpha, gamma); } /// Tensor IOps.PRelu(Tensor X, Tensor S) { Elementwise(X, 4L); RegisterLayerStats(); return m_Ops.PRelu(X, S); } /// Tensor IOps.Swish(Tensor X) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Swish(X); } /// Tensor IOps.Abs(Tensor X) { Elementwise(X); RegisterLayerStats(); return m_Ops.Abs(X); } /// Tensor IOps.Neg(Tensor X) { Elementwise(X); RegisterLayerStats(); return m_Ops.Neg(X); } /// Tensor IOps.Ceil(Tensor X) { Elementwise(X); RegisterLayerStats(); return m_Ops.Ceil(X); } /// Tensor IOps.Clip(Tensor X, float min, float max) { Elementwise(X, 2L); RegisterLayerStats(); return m_Ops.Clip(X, min, max); } /// Tensor IOps.Floor(Tensor X) { Elementwise(X); RegisterLayerStats(); return m_Ops.Floor(X); } /// Tensor IOps.Round(Tensor X) { Elementwise(X); RegisterLayerStats(); return m_Ops.Round(X); } /// Tensor IOps.Reciprocal(Tensor X) { Elementwise(X, Transcendental.Reciprocal); RegisterLayerStats(); return m_Ops.Reciprocal(X); } /// Tensor IOps.Pow(Tensor X, float alpha) { Elementwise(X, Transcendental.Pow); RegisterLayerStats(); return m_Ops.Pow(X, alpha); } /// Tensor IOps.Exp(Tensor X) { Elementwise(X, Transcendental.Exponent); RegisterLayerStats(); return m_Ops.Exp(X); } /// Tensor IOps.Log(Tensor X) { Elementwise(X, Transcendental.Exponent); RegisterLayerStats(); return m_Ops.Log(X); } /// Tensor IOps.Sqrt(Tensor X) { Elementwise(X, Transcendental.Root); RegisterLayerStats(); return m_Ops.Sqrt(X); } /// Tensor IOps.Acos(Tensor X) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Acos(X); } /// Tensor IOps.Acosh(Tensor X) { Elementwise(X, Transcendental.Exponent + 1 + Transcendental.Root + 3); RegisterLayerStats(); return m_Ops.Acosh(X); } /// Tensor IOps.Asin(Tensor X) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Asin(X); } /// Tensor IOps.Asinh(Tensor X) { Elementwise(X, Transcendental.Exponent + 1 + Transcendental.Root + 3); RegisterLayerStats(); return m_Ops.Asinh(X); } /// Tensor IOps.Atan(Tensor X) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Atan(X); } /// Tensor IOps.Atanh(Tensor X) { Elementwise(X, 1 + Transcendental.Exponent + 2 + Transcendental.Div); RegisterLayerStats(); return m_Ops.Atanh(X); } /// Tensor IOps.Cos(Tensor X) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Cos(X); } /// Tensor IOps.Cosh(Tensor X) { Elementwise(X, 2 + 2*Transcendental.Exponent); RegisterLayerStats(); return m_Ops.Cosh(X); } /// Tensor IOps.Sin(Tensor X) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Sin(X); } /// Tensor IOps.Sinh(Tensor X) { Elementwise(X, 2 + 2*Transcendental.Exponent); RegisterLayerStats(); return m_Ops.Sinh(X); } /// Tensor IOps.Tan(Tensor X) { Elementwise(X, Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Tan(X); } /// Tensor IOps.Erf(Tensor X) { Elementwise(X, 1 + Transcendental.Trigonometric); RegisterLayerStats(); return m_Ops.Erf(X); } /// Tensor IOps.Add(Tensor[] tensors) { var O = m_Ops.Add(tensors); ElementwiseBroadcast(tensors, O); RegisterLayerStats(); return O; } /// Tensor IOps.Sub(Tensor[] tensors) { var O = m_Ops.Sub(tensors); ElementwiseBroadcast(tensors, O); RegisterLayerStats(); return O; } /// Tensor IOps.Mul(Tensor[] tensors) { var O = m_Ops.Mul(tensors); ElementwiseBroadcast(tensors, O); RegisterLayerStats(); return O; } /// Tensor IOps.Div(Tensor[] tensors) { var O = m_Ops.Div(tensors); ElementwiseBroadcast(tensors, O, Transcendental.Div); RegisterLayerStats(); return O; } /// Tensor IOps.Pow(Tensor[] tensors) { var O = m_Ops.Pow(tensors); ElementwiseBroadcast(tensors, O, Transcendental.Pow); RegisterLayerStats(); return O; } /// Tensor IOps.Min(Tensor[] tensors) { var O = m_Ops.Min(tensors); ElementwiseBroadcast(tensors, O); RegisterLayerStats(); return O; } /// Tensor IOps.Max(Tensor[] tensors) { var O = m_Ops.Max(tensors); ElementwiseBroadcast(tensors, O); RegisterLayerStats(); return O; } /// Tensor IOps.Mean(Tensor[] tensors) { var O = m_Ops.Mean(tensors); ElementwiseBroadcast(tensors, O); RegisterLayerStats(); return O; } /// Tensor IOps.ArgMax(Tensor X, int axis) { var O = m_Ops.ArgMax(X, axis); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.ArgMin(Tensor X, int axis) { var O = m_Ops.ArgMin(X, axis); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.ReduceMax(Tensor X, int axis) { var O = m_Ops.ReduceMax(X, axis); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.ReduceMean(Tensor X, int axis) { var O = m_Ops.ReduceMean(X, axis); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.ReduceMin(Tensor X, int axis) { var O = m_Ops.ReduceMin(X, axis); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.ReduceProd(Tensor X, int axis) { var O = m_Ops.ReduceProd(X, axis); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.ReduceSum(Tensor X, int axis) { var O = m_Ops.ReduceSum(X, axis); Reduce(X, O); RegisterLayerStats(); return O; } /// Tensor IOps.Greater(Tensor a, Tensor b) { var O = m_Ops.Greater(a, b); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.GreaterEqual(Tensor a, Tensor b) { var O = m_Ops.GreaterEqual(a, b); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.Less(Tensor a, Tensor b) { var O = m_Ops.Less(a, b); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.LessEqual(Tensor a, Tensor b) { var O = m_Ops.LessEqual(a, b); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.Equal(Tensor a, Tensor b) { var O = m_Ops.Equal(a, b); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.LogicalOr(Tensor a, Tensor b) { var O = m_Ops.LogicalOr(a, b); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.LogicalAnd(Tensor a, Tensor b) { var O = m_Ops.LogicalAnd(a, b); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.LogicalXor(Tensor a, Tensor b) { var O = m_Ops.LogicalXor(a, b); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.LogicalNot(Tensor x) { var O = m_Ops.LogicalNot(x); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.Sign(Tensor x) { var O = m_Ops.Sign(x); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.Where(Tensor c, Tensor a, Tensor b) { var O = m_Ops.Where(c, a, b); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.Flatten(Tensor X) { m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return m_Ops.Flatten(X); } /// Tensor IOps.Reshape(Tensor X, TensorShape shape) { m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return m_Ops.Reshape(X, shape); } /// Tensor IOps.Expand(Tensor X, TensorShape shape) { var O = m_Ops.Expand(X, shape); m_Alu += 0; m_Mem += (long)X.length + (long)O.length; RegisterLayerStats(); return O; } /// Tensor IOps.Transpose(Tensor X) { Elementwise(X); RegisterLayerStats(); return m_Ops.Transpose(X); } /// Tensor IOps.Transpose(Tensor X, int[] permutations) { Elementwise(X); RegisterLayerStats(); return m_Ops.Transpose(X, permutations); } /// Tensor IOps.Gather(Tensor[] tensors, int axis) { var O = m_Ops.Gather(tensors, axis); Elementwise(O); RegisterLayerStats(); return O; } // Tensor IOps.ScatterND(Tensor X, Tensor indices, Tensor updates, Layer.ScatterNDReductionMode reduction) { var O = m_Ops.ScatterND(X, indices, updates, reduction); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.NonMaxSuppression(Tensor[] tensors, int maxOutputBoxesPerClass, float iouThreshold, float scoreThreshold, int centerPointBox) { var O = m_Ops.NonMaxSuppression(tensors, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, centerPointBox); m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return O; } /// public Tensor[] LSTM(Tensor X, Tensor[] W, Tensor[] R, Tensor[] Wb, Tensor[] Rb, Tensor hidden, Tensor cell) { var O = m_Ops.LSTM(X, W, R, Wb, Rb, hidden, cell); // @TODO: not implemented m_Alu += 0; m_Mem += 0; RegisterLayerStats(); return O; } /// Tensor IOps.Concat(Tensor[] tensors, int axis) { var O = m_Ops.Concat(tensors, axis); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.StridedSlice(Tensor X, int[] starts, int[] ends, int[] strides) { var O = m_Ops.StridedSlice(X, starts, ends, strides); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.Tile(Tensor X, int[] repeats) { var O = m_Ops.Tile(X, repeats); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.Shape(Tensor X, int axis) { var O = m_Ops.Shape(X, axis); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.ConstantOfShape(TensorShape X, DataType type, float value) { var O = m_Ops.ConstantOfShape(X, type, value); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.Copy(Tensor x) { var O = m_Ops.Copy(x); Elementwise(O); RegisterLayerStats(); return O; } /// Tensor IOps.Prepare(Tensor X) { return m_Ops.Prepare(X); } /// Tensor IOps.PrepareNoAlloc(Tensor X) { return m_Ops.PrepareNoAlloc(X); } /// void IOps.ResetAllocator(bool keepCachedMemory) { m_Ops.ResetAllocator(keepCachedMemory); m_Alu = new LayerStat(0L, 0L); m_Mem = new LayerStat(0L, 0L); } /// void IOps.SetModelExecutionsReporter(IModelExecutionsReporter executionsReporter) { m_Ops.SetModelExecutionsReporter(executionsReporter); } /// public IModelExecutionsReporter GetModelExecutionsReporter() { return m_Ops.GetModelExecutionsReporter(); } /// /// Build execution summary /// /// execution summary public override string ToString() { string alu = m_Alu.ToString(); if (m_Alu > 1e12) alu = $"{(double)m_Alu / (1e12):###.0}T"; else if (m_Alu > 1e9) alu = $"{(double)m_Alu / (1e9):###.0}G"; else if (m_Alu > 1e6) alu = $"{(double)m_Alu / (1e6):###.0}M"; var mem4 = m_Mem * 4L; string mem = mem4.ToString(); if (mem4 > 1024*1024*1024) mem = $"{(double)mem4 / (1024*1024*1024):###.0}Gb"; else if (mem4 > 1024*1024) mem = $"{(double)mem4 / (1024*1024):###.0}Mb"; return $"ALU operations: {alu} bytes accessed: {mem}"; } private void RegisterLayerStats() { #if ENABLE_BARRACUDA_STATS GetModelExecutionsReporter()?.SetLayerALUAndMemStats(m_Alu.layer, m_Mem.layer); #endif //ENABLE_BARRACUDA_STATS } // ----- internal void Elementwise(Tensor X, long aluOperationsPerElement = 1L) { m_Alu += (long)X.length * aluOperationsPerElement; m_Mem += (long)X.length * 2L; } internal void ElementwiseBroadcast(Tensor[] tensors, Tensor X, long aluOperationsPerElement = 1L) { m_Alu += (long)X.length * aluOperationsPerElement; long mem = (long)X.length; foreach (var t in tensors) mem += (long)t.length; m_Mem += mem; } internal void Reduce(Tensor X, Tensor O, long aluOperationsPerElement = 1L) { m_Alu += (long)X.length * aluOperationsPerElement; m_Mem += (long)X.length + (long)O.length; } } } // namespace Unity.Barracuda