/// <summary> /// Creates new array /// </summary> /// <param name="shape">shape</param> public BurstTensorData(TensorShape shape) : base(shape) { }
public virtual IEnumerator StartManualSchedule() { Profiler.BeginSample("Barracuda.Execute"); ResetAllocatorIfRequested(); m_Vars.PrepareStorage(m_Model, m_Ops, m_InputShapes); if (m_ModelCompiler != null) { m_ModelCompiler.PrepareModel(m_Model, m_InputShapes); } int idx = 0; foreach (var l in m_Model.layers) { idx++; m_Progress = idx / (float)m_Model.layers.Count; Profiler.BeginSample(l.name); var inputs = m_Vars.GatherInputs(l); Tensor X = inputs.Length > 0 ? inputs[0] : m_DummyInput; if (m_Verbose) { D.Log("Layer: " + l.type + ((l.type == Layer.Type.Activation) ? ("." + l.activation) : "") + " " + l.name); } m_Vars.PrepareStorage(l); if (m_ModelCompiler != null) { m_ModelCompiler.PreExecuteLayer(l, inputs); } // No operation, identity if (l.type == Layer.Type.Nop) { Profiler.BeginSample("Barracuda.Nop"); X = m_Ops.Copy(X); } // Load const else if (l.type == Layer.Type.Load) { Profiler.BeginSample("Barracuda.Load"); } // GEMM else if (l.type == Layer.Type.Dense) { Assert.AreEqual(inputs.Length, 3); Profiler.BeginSample("Barracuda.Dense"); X = m_Ops.Dense(X, inputs[1], inputs[2], GetAndVerifyFusedActivation(l)); } // 2D else if (l.type == Layer.Type.Conv2D) { Assert.AreEqual(inputs.Length, 3); Profiler.BeginSample("Barracuda.Conv2D"); var pad = X.AdjustPadToKernel(inputs[1], l.stride, l.pad); X = m_Ops.Conv2D(X, inputs[1], inputs[2], l.stride, pad, GetAndVerifyFusedActivation(l)); } else if (l.type == Layer.Type.DepthwiseConv2D) { Assert.AreEqual(inputs.Length, 3); Profiler.BeginSample("Barracuda.DepthwiseConv2D"); var pad = X.AdjustPadToKernel(inputs[1], l.stride, l.pad); X = m_Ops.DepthwiseConv2D(X, inputs[1], inputs[2], l.stride, pad, GetAndVerifyFusedActivation(l)); } else if (l.type == Layer.Type.Conv2DTrans) { Assert.AreEqual(inputs.Length, 3); Profiler.BeginSample("Barracuda.Conv2DTrans"); // pool size is treated as output_adjustment aka output_padding here var outputAdjustment = l.pool; var pad = X.AdjustPadToKernel(inputs[1], l.stride, l.pad); X = m_Ops.Conv2DTrans(X, inputs[1], inputs[2], l.stride, pad, outputAdjustment, GetAndVerifyFusedActivation(l)); } else if (l.type == Layer.Type.Upsample2D) { Profiler.BeginSample("Barracuda.Upsample2D"); // pool size is treated as upsample scale coefficient here var scale = l.pool; // axis is treated as upsample point/bilinear flag var bilinear = l.axis > 0; if (scale.Length == 0 && inputs.Length > 1) { var scaleTensor = inputs[1]; Assert.AreEqual(scaleTensor.length, 4); scale = new int[] { (int)scaleTensor[2], (int)scaleTensor[1] }; } X = m_Ops.Upsample2D(X, scale, bilinear); } else if (l.type == Layer.Type.Resample2D) { Profiler.BeginSample("Barracuda.Resample2D"); // pool size is treated as resample size here var size = l.pool; // axis is treated as upsample point/bilinear flag var bilinear = l.axis > 0; if (inputs.Length > 1) { var sizeTensor = inputs[1]; Assert.AreEqual(sizeTensor.length, 4); size = new int[] { (int)sizeTensor[2], (int)sizeTensor[1] }; } X = m_Ops.Resample2D(X, size, bilinear); } else if (l.type == Layer.Type.DepthToSpace) { Profiler.BeginSample("Barracuda.DepthToSpace"); // pool size is treated as blocksize var blocksize = l.pool; // axis is treated as mode enum var mode = (Layer.DepthToSpaceMode)l.axis; X = m_Ops.DepthToSpace(X, blocksize, mode); } else if (l.type == Layer.Type.SpaceToDepth) { Profiler.BeginSample("Barracuda.SpaceToDepth"); // pool size is treated as blocksize var blocksize = l.pool; X = m_Ops.SpaceToDepth(X, blocksize); } else if (l.type == Layer.Type.MaxPool2D) { Profiler.BeginSample("Barracuda.MaxPool2D"); var pad = X.AdjustPadToPool(l.pool, l.stride, l.pad); X = m_Ops.MaxPool2D(X, l.pool, l.stride, pad); } else if (l.type == Layer.Type.AvgPool2D) { Profiler.BeginSample("Barracuda.AvgPool2D"); var pad = X.AdjustPadToPool(l.pool, l.stride, l.pad); X = m_Ops.AvgPool2D(X, l.pool, l.stride, pad); } else if (l.type == Layer.Type.GlobalMaxPool2D) { Profiler.BeginSample("Barracuda.GlobalMaxPool2D"); X = m_Ops.GlobalMaxPool2D(X); } else if (l.type == Layer.Type.GlobalAvgPool2D) { Profiler.BeginSample("Barracuda.GlobalAvgPool2D"); X = m_Ops.GlobalAvgPool2D(X); } else if (l.type == Layer.Type.Border2D) { Profiler.BeginSample("Barracuda.Border2D"); Assert.IsNotNull(l.pad); // NOTE: beta is used to retrieve fillin value // because beta is 0 by default (while alpha is 1 by default) // 0 value is more inline with zero padding float fillValue = l.beta; X = m_Ops.Border2D(X, l.pad, fillValue); } else if (l.type == Layer.Type.Pad2DReflect) { Profiler.BeginSample("Barracuda.Pad2DReflect"); Assert.IsNotNull(l.pad); X = m_Ops.Pad2DReflect(X, l.pad); } else if (l.type == Layer.Type.Pad2DSymmetric) { Profiler.BeginSample("Barracuda.Pad2DSymmetric"); Assert.IsNotNull(l.pad); X = m_Ops.Pad2DSymmetric(X, l.pad); } else if (l.type == Layer.Type.Pad2DEdge) { Profiler.BeginSample("Barracuda.Pad2DEdge"); Assert.IsNotNull(l.pad); X = m_Ops.Pad2DEdge(X, l.pad); } // 3D else if (l.type == Layer.Type.Conv3D || l.type == Layer.Type.Conv3DTrans || l.type == Layer.Type.Upsample3D || l.type == Layer.Type.MaxPool3D || l.type == Layer.Type.AvgPool3D || l.type == Layer.Type.GlobalMaxPool3D || l.type == Layer.Type.GlobalAvgPool3D || l.type == Layer.Type.Border3D) { throw new NotImplementedException("3D operations are not implemented yet!"); } else if (l.type == Layer.Type.ScaleBias) { Assert.AreEqual(inputs.Length, 3); Profiler.BeginSample("Barracuda.ScaleBias"); X = m_Ops.ScaleBias(X, inputs[1], inputs[2]); } else if (l.type == Layer.Type.Normalization) { Assert.AreEqual(inputs.Length, 3); Profiler.BeginSample("Barracuda.Normalization"); // @TODO: support other types of Normalization at test time. // Currently supported only pool=1 (InstanceNormalization) // NOTE: beta is used to retrieve epsilon value // because beta is 0 by default (while alpha is 1 by default) // 0 value is more inline with very small epsilon var epsilon = l.beta; if (epsilon == 0) { epsilon = Mathf.Epsilon; // safety check to prevent division by zero } X = m_Ops.Normalization(X, inputs[1], inputs[2], 1, l.axis, epsilon, GetAndVerifyFusedActivation(l)); } else if (l.type == Layer.Type.LRN) { Profiler.BeginSample("Barracuda.LRN"); Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 1); int count = l.pool[0]; float bias = (l.weights.Length > 0) ? l.weights[0] : 1.0f; X = m_Ops.LRN(X, l.alpha, l.beta, bias, count); } // Stochastic layers else if (l.type == Layer.Type.Dropout) { Profiler.BeginSample("Barracuda.Dropout"); X = m_Ops.Dropout(X, l.alpha); } else if (l.type == Layer.Type.RandomNormal) { Profiler.BeginSample("Barracuda.RandomNormal"); Assert.IsNotNull(l.pool); // pool size is treated as shape constant, if not empty // otherwise shape of the previous tensor is used var shape = X.shape; if (l.pool.Length > 0) { shape = new TensorShape(l.pool); } int seed = (l.pad.Length > 0) ? l.pad[0] : 1337; float scale = l.alpha, mean = l.beta; X = m_Ops.RandomNormal(shape, mean, scale, seed); } else if (l.type == Layer.Type.RandomUniform) { Profiler.BeginSample("Barracuda.RandomUniform"); Assert.IsNotNull(l.pool); // pool size is treated as shape constant, if not empty // otherwise shape of the previous tensor is used var shape = X.shape; if (l.pool.Length > 0) { shape = new TensorShape(l.pool); } int seed = (l.pad.Length > 0) ? l.pad[0] : 1337; float scale = l.alpha, mean = l.beta; X = m_Ops.RandomUniform(shape, mean, scale, seed); } else if (l.type == Layer.Type.Multinomial) { Profiler.BeginSample("Barracuda.Multinomial"); Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 1); int count = l.pool[0]; int seed = (l.pad.Length > 0) ? l.pad[0] : 1337; X = m_Ops.Multinomial(X, count, seed); } else if (l.type == Layer.Type.OneHot) { Profiler.BeginSample("Barracuda.OneHot"); Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 1); int depth = l.pool[0]; float on = l.alpha, off = l.beta; X = m_Ops.OneHot(X, depth, on, off); } // Broadcast layers else if (l.type == Layer.Type.Add) { Profiler.BeginSample("Barracuda.Add"); X = m_Ops.Add(inputs); } else if (l.type == Layer.Type.Sub) { Profiler.BeginSample("Barracuda.Sub"); X = m_Ops.Sub(inputs); } else if (l.type == Layer.Type.Mul) { Profiler.BeginSample("Barracuda.Mul"); X = m_Ops.Mul(inputs); } else if (l.type == Layer.Type.Div) { Profiler.BeginSample("Barracuda.Div"); X = m_Ops.Div(inputs); } else if (l.type == Layer.Type.Pow) { Profiler.BeginSample("Barracuda.Pow"); X = m_Ops.Pow(inputs); } else if (l.type == Layer.Type.Min) { Profiler.BeginSample("Barracuda.Min"); X = m_Ops.Min(inputs); } else if (l.type == Layer.Type.Max) { Profiler.BeginSample("Barracuda.Max"); X = m_Ops.Max(inputs); } else if (l.type == Layer.Type.Mean) { Profiler.BeginSample("Barracuda.Mean"); X = m_Ops.Mean(inputs); } // Reduction layers else if (l.type == Layer.Type.ReduceMax) { Profiler.BeginSample("Barracuda.ReduceMax"); X = m_Ops.ReduceMax(X, l.axis); } else if (l.type == Layer.Type.ReduceMean) { Profiler.BeginSample("Barracuda.ReduceMean"); X = m_Ops.ReduceMean(X, l.axis); } else if (l.type == Layer.Type.ReduceMin) { Profiler.BeginSample("Barracuda.ReduceMin"); X = m_Ops.ReduceMin(X, l.axis); } else if (l.type == Layer.Type.ReduceProd) { Profiler.BeginSample("Barracuda.ReduceProd"); X = m_Ops.ReduceProd(X, l.axis); } else if (l.type == Layer.Type.ReduceSum) { Profiler.BeginSample("Barracuda.ReduceSum"); X = m_Ops.ReduceSum(X, l.axis); } else if ( l.type == Layer.Type.ReduceL1 || l.type == Layer.Type.ReduceL2 || l.type == Layer.Type.ReduceLogSum || l.type == Layer.Type.ReduceLogSumExp || l.type == Layer.Type.ReduceSumSquare) { throw new NotImplementedException("This reduction operation is not implemented yet!"); } // Logical operators with broadcast else if (l.type == Layer.Type.Greater) { Assert.AreEqual(inputs.Length, 2); Profiler.BeginSample("Barracuda.Greater"); X = m_Ops.Greater(X, inputs[1]); } else if (l.type == Layer.Type.GreaterEqual) { Assert.AreEqual(inputs.Length, 2); Profiler.BeginSample("Barracuda.GreaterEqual"); X = m_Ops.GreaterEqual(X, inputs[1]); } else if (l.type == Layer.Type.Less) { Assert.AreEqual(inputs.Length, 2); Profiler.BeginSample("Barracuda.Less"); X = m_Ops.Less(X, inputs[1]); } else if (l.type == Layer.Type.LessEqual) { Assert.AreEqual(inputs.Length, 2); Profiler.BeginSample("Barracuda.LessEqual"); X = m_Ops.LessEqual(X, inputs[1]); } else if (l.type == Layer.Type.Equal) { Assert.AreEqual(inputs.Length, 2); Profiler.BeginSample("Barracuda.Equal"); X = m_Ops.Equal(X, inputs[1]); } else if (l.type == Layer.Type.LogicalOr) { Assert.AreEqual(inputs.Length, 2); Profiler.BeginSample("Barracuda.LogicalOr"); X = m_Ops.LogicalOr(X, inputs[1]); } else if (l.type == Layer.Type.LogicalAnd) { Assert.AreEqual(inputs.Length, 2); Profiler.BeginSample("Barracuda.LogicalAnd"); X = m_Ops.LogicalAnd(X, inputs[1]); } else if (l.type == Layer.Type.LogicalXor) { Assert.AreEqual(inputs.Length, 2); Profiler.BeginSample("Barracuda.LogicalXor"); X = m_Ops.LogicalXor(X, inputs[1]); } else if (l.type == Layer.Type.LogicalNot) { Profiler.BeginSample("Barracuda.LogicalNot"); X = m_Ops.LogicalNot(X); } // Shape affecting layers else if (l.type == Layer.Type.Flatten) { Profiler.BeginSample("Barracuda.Flatten"); X = m_Ops.Flatten(X); } else if (l.type == Layer.Type.Reshape) { Profiler.BeginSample("Barracuda.Reshape"); // pool size is treated as reshape coefficient, if not empty // otherwise shape of the 2nd input tensor is used var size = l.pool; Assert.IsNotNull(size); if (size.Length == 0 && inputs.Length > 1) { size = inputs[1].shape.ToArray(); } var newShape = X.shape.Reshape(size); X = m_Ops.Reshape(X, newShape); } else if (l.type == Layer.Type.Expand) { Profiler.BeginSample("Barracuda.Expand"); // pool size is treated as new shape var newShape = l.pool; Assert.IsNotNull(newShape); Assert.AreEqual(newShape.Length, 4); X = m_Ops.Expand(X, new TensorShape(newShape)); } else if (l.type == Layer.Type.Transpose) { Profiler.BeginSample("Barracuda.Transpose"); X = m_Ops.Transpose(X); } else if (l.type == Layer.Type.Gather) { Profiler.BeginSample("Barracuda.Gather"); X = m_Ops.Gather(inputs, l.axis); } else if (l.type == Layer.Type.Squeeze || l.type == Layer.Type.Unsqueeze) { throw new NotImplementedException(); } else if (l.type == Layer.Type.Concat) { Profiler.BeginSample("Barracuda.Concat"); X = m_Ops.Concat(inputs, l.axis); } else if (l.type == Layer.Type.StridedSlice) { Profiler.BeginSample("Barracuda.StridedSlice"); Assert.IsNotNull(l.pad); Assert.IsNotNull(l.pool); Assert.IsNotNull(l.stride); X = m_Ops.StridedSlice(X, l.pad, l.pool, l.stride); } else if (l.type == Layer.Type.Tile) { throw new NotImplementedException(); } // Activations else if (l.type == Layer.Type.Activation) { Profiler.BeginSample("Barracuda.Activation"); if (l.activation == Layer.Activation.Relu) { X = m_Ops.Relu(X); } else if (l.activation == Layer.Activation.Softmax) { X = m_Ops.Softmax(X); } else if (l.activation == Layer.Activation.LogSoftmax) { X = m_Ops.LogSoftmax(X); } else if (l.activation == Layer.Activation.Tanh) { X = m_Ops.Tanh(X); } else if (l.activation == Layer.Activation.Sigmoid) { X = m_Ops.Sigmoid(X); } else if (l.activation == Layer.Activation.Relu6) { X = m_Ops.Relu6(X); } else if (l.activation == Layer.Activation.Elu) { X = m_Ops.Elu(X, l.alpha); } else if (l.activation == Layer.Activation.LeakyRelu) { X = m_Ops.LeakyRelu(X, l.alpha); } else if (l.activation == Layer.Activation.Selu) { X = m_Ops.Selu(X, l.alpha, l.beta); } else if (l.activation == Layer.Activation.Swish) { X = m_Ops.Swish(X); } else if (l.activation == Layer.Activation.PRelu) { Assert.AreEqual(inputs.Length, 2); X = m_Ops.PRelu(X, inputs[1]); } else if ( l.activation == Layer.Activation.Softplus || l.activation == Layer.Activation.Softsign || l.activation == Layer.Activation.Hardmax || l.activation == Layer.Activation.HardSigmoid) { throw new NotImplementedException("This activation function is not implemented yet!"); } else if (l.activation == Layer.Activation.Abs) { X = m_Ops.Abs(X); } else if (l.activation == Layer.Activation.Neg) { X = m_Ops.Neg(X); } else if (l.activation == Layer.Activation.Ceil) { X = m_Ops.Ceil(X); } else if (l.activation == Layer.Activation.Clip) { X = m_Ops.Clip(X, l.alpha, l.beta); } else if (l.activation == Layer.Activation.Floor) { X = m_Ops.Floor(X); } else if (l.activation == Layer.Activation.Reciprocal) { X = m_Ops.Reciprocal(X); } else if (l.activation == Layer.Activation.Pow) { X = m_Ops.Pow(X, l.alpha); } else if (l.activation == Layer.Activation.Exp) { X = m_Ops.Exp(X); } else if (l.activation == Layer.Activation.Log) { X = m_Ops.Log(X); } else if (l.activation == Layer.Activation.Sqrt) { X = m_Ops.Sqrt(X); } else if ((int)l.activation >= (int)Layer.Activation.Acos && (int)l.activation <= (int)Layer.Activation.Tan) { throw new NotImplementedException("Trig functions are not implemented yet!"); } else { X = m_Ops.Copy(X); } } else { Profiler.BeginSample("Barracuda.Dummy"); Assert.AreEqual(l.activation, Layer.Activation.None); } m_Vars.Store(l, X); m_SyncTensor = X; // optype Profiler.EndSample(); // layer.name Profiler.EndSample(); yield return(null); } // request ResetAllocator before next Execute() starts m_RequestResetAllocator = true; Profiler.EndSample(); if (m_Verbose) { D.Log(m_Vars.GetAllocator()); } }
/// <summary> /// Apply shape to the input tensor. Number of elements in the shape must match number of elements in input tensor. /// </summary> public Layer Reshape(string name, object input, TensorShape shape) { return(Reshape(name, input, shape.ToArray())); }
/// <summary> /// Upload data to internal storage /// </summary> /// <param name="data">data</param> /// <param name="shape">shape</param> /// <param name="managedBufferStartIndex">`data` start index</param> public override void Upload(float[] data, TensorShape shape, int managedBufferStartIndex = 0) { CompleteAllPendingOperations(); base.Upload(data, shape, managedBufferStartIndex); }
static internal TensorShape ApplyPool(this TensorShape shape, int[] pool, int[] stride, int[] pad, bool ceilMode = false) { return(ApplyPool(shape, (pool[0], pool[1]), stride, pad, ceilMode)); }
static internal TensorShape ApplyKernel(this TensorShape shape, TensorShape kernel, int[] stride, int[] pad) { int[] shapeArray = ApplyPool(shape, (kernel.kernelWidth, kernel.kernelHeight), stride, pad).ToArray(); shapeArray[7] = kernel.kernelCount; return(new TensorShape(shapeArray)); }
static internal int[] AdjustPadToKernel(this TensorShape shape, TensorShape kernel, int[] stride, int[] pad) { return(AdjustPadToPool(shape, (kernel.kernelWidth, kernel.kernelHeight), stride, pad)); }
static internal int[] AdjustPadToPool(this TensorShape shape, int[] pool, int[] stride, int[] pad) { return(AdjustPadToPool(shape, (pool[0], pool[1]), stride, pad)); }
/// <summary> /// Reshape TensorShape into new shape specified by `size`. At most one dimension of the new shape can be -1. /// See: https://github.com/onnx/onnx/blob/master/docs/Operators.md#Reshape /// </summary> /// <param name="shape">TensorShape</param> /// <param name="size">new shape</param> /// <returns>output shape</returns> /// <exception cref="ArgumentException">more than one dimension is unspecified</exception> static public TensorShape Reshape(this TensorShape shape, int[] size) { size = Get8DParametersFromNHWCParametersAndShape(shape, size, 1); var newShapeArray = shape.ToArray(); // From: https://github.com/onnx/onnx/blob/master/docs/Operators.md#Reshape // // At most one dimension of the new shape can be -1. // In this case, the value is inferred from the size of the tensor and the remaining dimensions. // // A dimension could also be 0, // in which case the actual dimension value is unchanged (i.e. taken from the input tensor). var multipleOf = 1; var unknownIndex = -1; for (int q = 0; q < size.Length; ++q) { if (size[q] > 0) { multipleOf *= size[q]; newShapeArray[q] = size[q]; } else if (size[q] == 0) { multipleOf *= newShapeArray[q]; } else if (unknownIndex == -1) { unknownIndex = q; } else { throw new ArgumentException("Can only specify one unknown dimension"); } } if (unknownIndex == -1) { // all dimensions are given var newShape = new TensorShape(newShapeArray); if (shape.length != newShape.length) { throw new ArgumentException("Cannot reshape array of size " + shape.length + " into shape " + newShape); } return(newShape); } var solveForIndex = shape.length / multipleOf; bool remainderLeft = shape.length % multipleOf != 0; if (remainderLeft) { throw new ArgumentException("Cannot reshape array of size " + shape.length + " into shape with multiple of " + multipleOf + " elements"); } newShapeArray[unknownIndex] = solveForIndex; return(new TensorShape(newShapeArray)); }
public static TensorShape?[] ListTemporaryTensorShapes(Model model, IDictionary <string, TensorShape> inputShapes, out IDictionary <string, TensorShape?> shapesByName) { Profiler.BeginSample("Barracuda.ListTemporaryTensorShapes"); var shapes = new List <TensorShape?>(); shapesByName = new Dictionary <string, TensorShape?>(); foreach (var entry in inputShapes) { shapesByName.Add(entry.Key, entry.Value); } TensorShape?Xn; shapesByName.TryGetValue(GetDefaultInputName(model), out Xn); // default input TensorShape?O = Xn; foreach (var l in model.layers) { if (l.inputs.Length > 0 && shapesByName.TryGetValue(l.inputs[0], out TensorShape? xShape)) { Xn = xShape; } else { Xn = O; // previous output is used, if-and-only-if layer has no explicit inputs } if (Xn == null) { shapes.Add(Xn); shapesByName.Add(l.name, Xn); continue; } TensorShape X = Xn.Value; if (l.type == Layer.Type.Dense) { Assert.IsNotNull(l.datasets); var W = l.datasets[0].shape; O = new TensorShape(X.flatHeight, W.flatWidth); } else if (l.type == Layer.Type.MatMul) { if (!shapesByName.ContainsKey(l.inputs[1]) || shapesByName[l.inputs[1]] == null) { O = null; break; } var Y = shapesByName[l.inputs[1]].Value; // MatMul on 2D input: N,1,1,C // MatMul on ND inputs: N,H,W,C with N*C = batches var isStackOfMatrices = (X.dimensions != 2) || (Y.dimensions != 2); if (isStackOfMatrices) { // X is multidim so N,H,W,c with H,W matmul dims var batches = X.batch * X.channels; Assert.AreEqual(X.batch * X.channels, Y.batch * Y.channels); O = new TensorShape(X.batch, X.height, Y.width, X.channels); } else { O = new TensorShape(X.flatHeight, Y.flatWidth); } } else if ( l.type == Layer.Type.Conv2D || l.type == Layer.Type.DepthwiseConv2D) { var K = l.datasets[0].shape; Assert.IsNotNull(l.stride); Assert.IsNotNull(l.pad); var pad = X.AdjustPadToKernel(K, l.stride, l.pad); O = X.ApplyKernel(K, l.stride, pad); } else if ( l.type == Layer.Type.Conv2DTrans) { var K = l.datasets[0].shape; Assert.IsNotNull(l.stride); Assert.IsNotNull(l.pad); // pool size is treated as output_adjustment aka output_padding here var outputAdjustment = l.pool; var pad = X.AdjustPadToKernel(K, l.stride, l.pad); O = X.ApplyKernelInverse(K, l.stride, pad, outputAdjustment); } else if ( l.type == Layer.Type.Upsample2D) { if (inputShapes.Count > 1) { O = null; } else { // pool size is treated as upsample coefficient here Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 2); O = new TensorShape(X.batch, X.height * l.pool[1], X.width * l.pool[0], X.channels); } } else if ( l.type == Layer.Type.Resample2D) { if (inputShapes.Count > 1) { O = null; } else { // pool is treated as resample size here var size = l.pool; Assert.IsNotNull(size); Assert.AreEqual(size.Length, 2); O = new TensorShape(X.batch, size[1], size[0], X.channels); } } else if ( l.type == Layer.Type.DepthToSpace) { // pool size is treated as blocksize here Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 2); Assert.AreEqual(X.channels % (l.pool[0] * l.pool[1]), 0); O = new TensorShape(X.batch, X.height * l.pool[1], X.width * l.pool[0], X.channels / (l.pool[0] * l.pool[1])); } else if ( l.type == Layer.Type.SpaceToDepth) { // pool size is treated as blocksize here Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 2); O = new TensorShape(X.batch, X.height / l.pool[1], X.width / l.pool[0], X.channels * (l.pool[0] * l.pool[1])); } else if ( l.type == Layer.Type.MaxPool2D || l.type == Layer.Type.AvgPool2D) { Assert.IsNotNull(l.pool); Assert.IsNotNull(l.stride); Assert.IsNotNull(l.pad); var pad = X.AdjustPadToPool(l.pool, l.stride, l.pad); O = X.ApplyPool(l.pool, l.stride, pad); } else if ( l.type == Layer.Type.GlobalMaxPool2D || l.type == Layer.Type.GlobalAvgPool2D) { O = new TensorShape(X.batch, 1, 1, X.channels); } else if ( l.type == Layer.Type.Border2D || l.type == Layer.Type.Pad2DReflect || l.type == Layer.Type.Pad2DSymmetric || l.type == Layer.Type.Pad2DEdge) { Assert.IsNotNull(l.pad); O = X.ApplyBorder(l.pad); } else if ( l.type == Layer.Type.Conv3D || l.type == Layer.Type.Conv3DTrans || l.type == Layer.Type.Upsample3D || l.type == Layer.Type.MaxPool3D || l.type == Layer.Type.AvgPool3D || l.type == Layer.Type.GlobalMaxPool3D || l.type == Layer.Type.GlobalAvgPool3D || l.type == Layer.Type.Border3D) { throw new NotImplementedException(); } else if ( l.type == Layer.Type.RandomNormal || l.type == Layer.Type.RandomUniform) { Assert.IsNotNull(l.pool); // pool size is treated as shape constant, if not empty // otherwise shape of the previous tensor is used if (l.pool.Length > 0) { O = new TensorShape(l.pool); } else { O = X; } } else if ( l.type == Layer.Type.Multinomial) { Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 1); O = new TensorShape(X.batch, l.pool[0]); } else if ( l.type == Layer.Type.OneHot) { Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 1); int features = X.flatWidth; int depth = l.pool[0]; O = new TensorShape(X.batch, 1, features, depth); } else if ( l.type == Layer.Type.Add || l.type == Layer.Type.Sub || l.type == Layer.Type.Mul || l.type == Layer.Type.Div || l.type == Layer.Type.Pow || l.type == Layer.Type.Min || l.type == Layer.Type.Max || l.type == Layer.Type.Mean || l.type == Layer.Type.Greater || l.type == Layer.Type.GreaterEqual || l.type == Layer.Type.Less || l.type == Layer.Type.LessEqual || l.type == Layer.Type.Equal || l.type == Layer.Type.LogicalOr || l.type == Layer.Type.LogicalAnd || l.type == Layer.Type.LogicalXor) { // gather shapes by names var list = new List <TensorShape>(l.inputs.Length); bool allShapesKnown = true; foreach (var i in l.inputs) { if (shapesByName.TryGetValue(i, out TensorShape? shape) && shape != null) { list.Add(shape.Value); } else { allShapesKnown = false; } } O = allShapesKnown ? TensorExtensions.Max(list.ToArray()) : default(TensorShape?); } else if ( l.type == Layer.Type.ReduceL1 || l.type == Layer.Type.ReduceL2 || l.type == Layer.Type.ReduceLogSum || l.type == Layer.Type.ReduceLogSumExp || l.type == Layer.Type.ReduceMax || l.type == Layer.Type.ReduceMean || l.type == Layer.Type.ReduceMin || l.type == Layer.Type.ReduceProd || l.type == Layer.Type.ReduceSum || l.type == Layer.Type.ReduceSumSquare) { O = X.Reduce(l.axis); } else if ( l.type == Layer.Type.Flatten) { O = X.Flatten(); } else if ( l.type == Layer.Type.Reshape) { // pool size is treated as the shape, if not empty var size = l.pool; Assert.IsNotNull(size); if (size.Length == 0 && l.inputs.Length > 1) { switch (l.axis) { // Legacy - use the shape of the input tensor as the shape case -1: if (shapesByName.TryGetValue(l.inputs[1], out TensorShape? shape)) { size = shape.Value.ToArray(); } break; // Use the tensor values as the shape; Calculated at runtime case 1: O = null; break; } if (O == null) { break; } } Assert.IsTrue((size.Length == 4) || (size.Length == 8)); O = X.Reshape(size); } else if ( l.type == Layer.Type.Expand) { // pool size is treated as new shape var newShape = l.pool; Assert.IsNotNull(newShape); Assert.IsTrue(newShape.Length == 8 || newShape.Length == 4); O = new TensorShape(newShape); } else if ( l.type == Layer.Type.Transpose) { var permutations = l.pool; if (permutations == null) { O = new TensorShape(X.flatWidth, X.flatHeight); } else { Assert.IsTrue(permutations.Length == 8 || permutations.Length == 4); O = X.Permute(permutations); } } else if ( l.type == Layer.Type.Gather) { if (!shapesByName.TryGetValue(l.inputs[0], out TensorShape? input0Shape) || input0Shape == null || !shapesByName.TryGetValue(l.inputs[1], out TensorShape? input1Shape) || input1Shape == null) { O = null; break; } int[] shape = input0Shape.Value.ToArray(); shape[l.axis] = input1Shape.Value.length; O = new TensorShape(shape); } else if ( l.type == Layer.Type.Squeeze || l.type == Layer.Type.Unsqueeze) { throw new NotImplementedException(); } else if ( l.type == Layer.Type.Concat) { // gather shapes by names var list = new List <TensorShape>(l.inputs.Length); bool allShapesKnown = true; foreach (var i in l.inputs) { if (!shapesByName.TryGetValue(i, out var shape) || shape == null) { allShapesKnown = false; continue; } list.Add(shape.Value); } O = allShapesKnown ? TensorExtensions.Concat(list.ToArray(), l.axis) : default(TensorShape?); } else if ( l.type == Layer.Type.StridedSlice) { Assert.IsNotNull(l.pad); Assert.IsNotNull(l.pool); Assert.IsNotNull(l.stride); O = X.ApplyStridedSlice(l.pad, l.pool, l.stride); } else if ( l.type == Layer.Type.Tile) { // pool size is treated as tiling coefficient here Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 4); var scale = l.pool; O = X.Scale(scale); } else if ( l.type == Layer.Type.Load) { O = l.datasets[0].shape; } else if (// elementwise operations l.type == Layer.Type.Nop || l.type == Layer.Type.Activation || l.type == Layer.Type.ScaleBias || l.type == Layer.Type.Normalization || l.type == Layer.Type.LRN || l.type == Layer.Type.Dropout || l.type == Layer.Type.LogicalNot || l.activation == Layer.Activation.PRelu) { // works in place, keeps the same shape size O = X; } else if ( l.type == Layer.Type.TopKIndices || l.type == Layer.Type.TopKValues || l.type == Layer.Type.NonMaxSuppression || l.type == Layer.Type.NonZero) { // Calculated at runtime O = null; } else if (l.type == Layer.Type.Shape) { int shapeRank = l.axis > 0 ? 1 : X.length; O = new TensorShape(shapeRank, 1, 1, 1); } else if (l.type == Layer.Type.Where) { O = X; } else if ( l.type == Layer.Type.Conv3D || l.type == Layer.Type.Conv3DTrans || l.type == Layer.Type.Upsample3D || l.type == Layer.Type.MaxPool3D || l.type == Layer.Type.AvgPool3D || l.type == Layer.Type.GlobalMaxPool3D || l.type == Layer.Type.GlobalAvgPool3D || l.type == Layer.Type.Border3D) { throw new NotImplementedException("3D operations are not implemented yet!"); } else { throw new NotImplementedException($"Layer type {l.type} needs to be explicitly handled"); } shapes.Add(O); shapesByName.Add(l.name, O); } Profiler.EndSample(); return(shapes.ToArray()); }
public static bool TryGetOutputTensorShape(Model model, IDictionary <string, TensorShape> inputShapes, string output, out TensorShape shape) { shape = new TensorShape(); IDictionary <string, TensorShape?> shapesByName; ListTemporaryTensorShapes(model, inputShapes, out shapesByName); TensorShape?dynamicShape; bool found = shapesByName.TryGetValue(output, out dynamicShape); if (found && (dynamicShape != null)) { shape = dynamicShape.Value; } return(found); }
public static TensorShape?[] ListTemporaryTensorShapes(Model model, IDictionary <string, TensorShape> inputShapes, out IDictionary <string, TensorShape?> shapesByName) { Profiler.BeginSample("Barracuda.ListTemporaryTensorShapes"); var shapes = new List <TensorShape?>(); shapesByName = new Dictionary <string, TensorShape?>(); foreach (var entry in inputShapes) { shapesByName.Add(entry.Key, entry.Value); } TensorShape?Xn; shapesByName.TryGetValue(GetDefaultInputName(model), out Xn); // default input TensorShape?O = Xn; foreach (var l in model.layers) { if (l.inputs.Length > 0 && shapesByName.TryGetValue(l.inputs[0], out TensorShape? xShape)) { Xn = xShape; } else { Xn = O; // previous output is used, if-and-only-if layer has no explicit inputs } if (Xn == null) { shapes.Add(Xn); shapesByName.Add(l.name, Xn); continue; } TensorShape X = Xn.Value; if (l.type == Layer.Type.Dense) { Assert.IsNotNull(l.datasets); var W = l.datasets[0].shape; O = new TensorShape(X.flatHeight, W.flatWidth); } else if (l.type == Layer.Type.Dense3) { Assert.IsNotNull(l.datasets); var W = l.datasets[0].shape; O = new TensorShape(X.batch, 1, W.channels, X.channels); } else if (l.type == Layer.Type.MatMul) { if (!shapesByName.ContainsKey(l.inputs[1]) || shapesByName[l.inputs[1]] == null) { O = null; break; } var Y = shapesByName[l.inputs[1]].Value; int rankX; int rankY; List <int> onnxXshape; List <int> onnxYshape; if (l.pool == null || l.pool.Length == 0) { LegacyGetXYRanks(X, Y, out rankX, out rankY); } else { rankX = l.pool[0]; rankY = l.pool[1]; } onnxXshape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToOnnxLayout(X, rankX); onnxYshape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToOnnxLayout(Y, rankY); int rankO = Math.Max(rankX, rankY); // pad 1 on front of shape to both be rankO shape for (int i = 0; i < (rankX - rankY); i++) { onnxYshape.Insert(0, 1); } for (int i = 0; i < (rankY - rankX); i++) { onnxXshape.Insert(0, 1); } if (rankO == 2) { O = new TensorShape(onnxXshape[0], 1, 1, onnxYshape[1]); } else if (rankO == 3) { O = new TensorShape(Math.Max(onnxXshape[0], onnxYshape[0]), 1, onnxYshape[2], onnxXshape[1]); } else { O = new TensorShape(Math.Max(onnxXshape[0], onnxYshape[0]), onnxXshape[2], onnxYshape[3], Math.Max(onnxXshape[1], onnxYshape[1])); } } else if ( l.type == Layer.Type.Conv2D || l.type == Layer.Type.Conv3D || l.type == Layer.Type.DepthwiseConv2D) { var K = l.datasets[0].shape; Assert.IsNotNull(l.stride); Assert.IsNotNull(l.pad); var pad = X.AdjustPadToKernel(K, l.stride, l.pad); O = X.ApplyKernel(K, l.stride, pad); } else if ( l.type == Layer.Type.Conv2DTrans) { var K = l.datasets[0].shape; Assert.IsNotNull(l.stride); Assert.IsNotNull(l.pad); // pool size is treated as output_adjustment aka output_padding here var outputAdjustment = l.pool; var pad = X.AdjustPadToKernel(K, l.stride, l.pad); O = X.ApplyKernelInverse(K, l.stride, pad, outputAdjustment); } else if ( l.type == Layer.Type.Upsample2D) { if (inputShapes.Count > 1) { O = null; } else { // pool size is treated as upsample coefficient here Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 2); O = new TensorShape(X.batch, X.height * l.pool[1], X.width * l.pool[0], X.channels); } } else if ( l.type == Layer.Type.Upsample3D) { if (inputShapes.Count > 1) { O = null; } else { // pool size is treated as upsample coefficient here Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 3); O = new TensorShape(1, 1, X.batch, 1, X.depth * l.pool[2], X.height * l.pool[1], X.width * l.pool[0], X.channels); } } else if ( l.type == Layer.Type.Resample2D) { if (inputShapes.Count > 1) { O = null; } else { // pool is treated as resample size here var size = l.pool; Assert.IsNotNull(size); Assert.AreEqual(size.Length, 2); O = new TensorShape(X.batch, size[1], size[0], X.channels); } } else if ( l.type == Layer.Type.DepthToSpace) { // pool size is treated as blocksize here Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 2); Assert.AreEqual(X.channels % (l.pool[0] * l.pool[1]), 0); O = new TensorShape(X.batch, X.height * l.pool[1], X.width * l.pool[0], X.channels / (l.pool[0] * l.pool[1])); } else if ( l.type == Layer.Type.SpaceToDepth) { // pool size is treated as blocksize here Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 2); O = new TensorShape(X.batch, X.height / l.pool[1], X.width / l.pool[0], X.channels * (l.pool[0] * l.pool[1])); } else if ( l.type == Layer.Type.MaxPool2D || l.type == Layer.Type.AvgPool2D) { Assert.IsNotNull(l.pool); Assert.IsNotNull(l.stride); Assert.IsNotNull(l.pad); var pad = X.AdjustPadToPool(l.pool, l.stride, l.pad); O = X.ApplyPool(l.pool, l.stride, pad); } else if ( l.type == Layer.Type.GlobalMaxPool2D || l.type == Layer.Type.GlobalAvgPool2D) { O = new TensorShape(X.batch, 1, 1, X.channels); } else if (l.type == Layer.Type.Border3D) { Assert.IsNotNull(l.pad); // legacy support if (l.pad.Length == 6) { X = X.ApplyBorder(new[] { l.pad[0], l.pad[1], l.pad[2], 0, l.pad[3], l.pad[4], l.pad[5], 0 }); } else { O = X.ApplyBorder(l.pad); } } else if ( l.type == Layer.Type.Border2D || l.type == Layer.Type.Pad2DReflect || l.type == Layer.Type.Pad2DSymmetric || l.type == Layer.Type.Pad2DEdge) { Assert.IsNotNull(l.pad); // legacy support if (l.pad.Length == 4) { X = X.ApplyBorder(new[] { l.pad[0], l.pad[1], 0, l.pad[2], l.pad[3], 0 }); } else { O = X.ApplyBorder(l.pad); } } else if ( l.type == Layer.Type.Conv3D || l.type == Layer.Type.Conv3DTrans || l.type == Layer.Type.Upsample3D || l.type == Layer.Type.MaxPool3D || l.type == Layer.Type.AvgPool3D || l.type == Layer.Type.GlobalMaxPool3D || l.type == Layer.Type.GlobalAvgPool3D || l.type == Layer.Type.Border3D) { throw new NotImplementedException(); } else if ( l.type == Layer.Type.RandomNormal || l.type == Layer.Type.RandomUniform) { Assert.IsNotNull(l.pool); // pool size is treated as shape constant, if not empty // otherwise shape of the previous tensor is used if (l.pool.Length > 0) { O = new TensorShape(l.pool); } else { O = X; } } else if (l.type == Layer.Type.ConstantOfShape) { if (l.axis != 1) { O = null; } else { O = X; } } else if ( l.type == Layer.Type.Multinomial) { Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 1); O = new TensorShape(X.batch, l.pool[0]); } else if ( l.type == Layer.Type.OneHot) { Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 1); int features = X.flatWidth; int depth = l.pool[0]; if (X.flatWidth == 1) // 1D input { O = new TensorShape(X.batch, depth); } else { O = new TensorShape(X.batch, 1, depth, features); } } else if (l.type == Layer.Type.RoiAlign) { Assert.IsNotNull(l.pool); Assert.AreEqual(l.pool.Length, 2); if (shapesByName.TryGetValue(l.inputs[1], out TensorShape? shape) && shape != null) { int batches = shape.Value.flatHeight; O = new TensorShape(batches, l.pool[0], l.pool[1], X.channels); } else { O = null; } } else if ( l.type == Layer.Type.Add || l.type == Layer.Type.Sub || l.type == Layer.Type.Mul || l.type == Layer.Type.Div || l.type == Layer.Type.Pow || l.type == Layer.Type.Min || l.type == Layer.Type.Max || l.type == Layer.Type.Mean || l.type == Layer.Type.Greater || l.type == Layer.Type.GreaterEqual || l.type == Layer.Type.Less || l.type == Layer.Type.LessEqual || l.type == Layer.Type.Equal || l.type == Layer.Type.LogicalOr || l.type == Layer.Type.LogicalAnd || l.type == Layer.Type.LogicalXor || l.type == Layer.Type.Where) { // gather shapes by names var list = new List <TensorShape>(l.inputs.Length); bool allShapesKnown = true; foreach (var i in l.inputs) { if (shapesByName.TryGetValue(i, out TensorShape? shape) && shape != null) { list.Add(shape.Value); } else { allShapesKnown = false; } } O = allShapesKnown ? TensorExtensions.Max(list.ToArray()) : default(TensorShape?); } else if ( l.type == Layer.Type.ReduceL1 || l.type == Layer.Type.ReduceL2 || l.type == Layer.Type.ReduceLogSum || l.type == Layer.Type.ReduceLogSumExp || l.type == Layer.Type.ReduceMax || l.type == Layer.Type.ReduceMean || l.type == Layer.Type.ReduceMin || l.type == Layer.Type.ReduceProd || l.type == Layer.Type.ReduceSum || l.type == Layer.Type.ReduceSumSquare || l.type == Layer.Type.ArgMax || l.type == Layer.Type.ArgMin) { O = X.Reduce(l.axis); } else if ( l.type == Layer.Type.Flatten) { O = X.Flatten(); } else if ( l.type == Layer.Type.Reshape) { // pool size is treated as the shape, if not empty var size = l.pool; Assert.IsNotNull(size); if (size.Length == 0 && l.inputs.Length > 1) { switch (l.axis) { // Legacy - use the shape of the input tensor as the shape case -1: if (shapesByName.TryGetValue(l.inputs[1], out TensorShape? shape)) { size = shape.Value.ToArray(); } break; // Use the tensor values as the shape; Calculated at runtime case 1: O = null; break; } if (O == null) { break; } } Assert.IsTrue((size.Length == 4) || (size.Length == 8)); O = X.Reshape(size); } else if ( l.type == Layer.Type.Expand) { // pool size is treated as new shape var newShape = l.pool; Assert.IsNotNull(newShape); Assert.IsTrue(newShape.Length == 8 || newShape.Length == 4); O = new TensorShape(newShape); } else if ( l.type == Layer.Type.Transpose) { var permutations = l.pool; if (permutations == null) { O = new TensorShape(X.flatWidth, X.flatHeight); } else { Assert.IsTrue(permutations.Length == 8 || permutations.Length == 4); O = X.Permute(permutations); } } else if ( l.type == Layer.Type.Gather) { if (!shapesByName.TryGetValue(l.inputs[0], out TensorShape? input0Shape) || input0Shape == null || !shapesByName.TryGetValue(l.inputs[1], out TensorShape? input1Shape) || input1Shape == null) { O = null; break; } int[] shape = input0Shape.Value.ToArray(); shape[l.axis] = input1Shape.Value.length; O = new TensorShape(shape); if (l.pool != null && l.pool.Length == 2 && l.pool[1] > 1) { int xRank = l.pool[0]; int indicesRank = l.pool[1]; var oShape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToList(O.Value, xRank); var indicesShape = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaShapeToList(input1Shape.Value, indicesRank); int axis = Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaAxisToTensor(l.axis, xRank); oShape.InsertRange(axis, indicesShape); oShape.RemoveAt(axis + indicesShape.Count); O = (O.Value).Reshape(Compiler.IRShapeInferenceHelper.ShapeInference.BarracudaLayoutToTensorShapeLayout(oShape.ToArray())); // rank 2 -> 3 if (xRank == 2 && oShape.Count == 3) { O = (O.Value).Permute(new int[] { 0, 1, 3, 2 }); } } } else if (l.type == Layer.Type.ScatterND) { O = X; } else if ( l.type == Layer.Type.Squeeze || l.type == Layer.Type.Unsqueeze) { O = X; } else if ( l.type == Layer.Type.Concat) { // gather shapes by names var list = new List <TensorShape>(l.inputs.Length); bool allShapesKnown = true; foreach (var i in l.inputs) { if (!shapesByName.TryGetValue(i, out var shape) || shape == null) { allShapesKnown = false; continue; } list.Add(shape.Value); } O = allShapesKnown ? TensorExtensions.Concat(list.ToArray(), l.axis) : default(TensorShape?); } else if ( l.type == Layer.Type.StridedSlice) { Assert.IsNotNull(l.pad); Assert.IsNotNull(l.pool); Assert.IsNotNull(l.stride); O = X.ApplyStridedSlice(l.pad, l.pool, l.stride); } else if ( l.type == Layer.Type.Tile) { // pool size is treated as tiling coefficient here Assert.IsNotNull(l.pool); var scale = l.pool; O = X.Scale(scale); } else if ( l.type == Layer.Type.Load) { O = l.datasets[0].shape; } else if (// elementwise operations l.type == Layer.Type.Nop || l.type == Layer.Type.Activation || l.type == Layer.Type.ScaleBias || l.type == Layer.Type.Normalization || l.type == Layer.Type.LRN || l.type == Layer.Type.Dropout || l.type == Layer.Type.LogicalNot || l.type == Layer.Type.Sign) { // works in place, keeps the same shape size O = X; } else if ( l.type == Layer.Type.TopKIndices || l.type == Layer.Type.TopKValues || l.type == Layer.Type.NonMaxSuppression || l.type == Layer.Type.LSTM || l.type == Layer.Type.NonZero) { // Calculated at runtime O = null; } else if (l.type == Layer.Type.Shape) { int shapeRank = l.axis > 0 ? 1 : X.length; O = new TensorShape(shapeRank, 1, 1, 1); } else if ( l.type == Layer.Type.Conv3D || l.type == Layer.Type.Conv3DTrans || l.type == Layer.Type.Upsample3D || l.type == Layer.Type.MaxPool3D || l.type == Layer.Type.AvgPool3D || l.type == Layer.Type.GlobalMaxPool3D || l.type == Layer.Type.GlobalAvgPool3D || l.type == Layer.Type.Border3D) { throw new NotImplementedException("3D operations are not implemented yet!"); } else { throw new NotImplementedException($"Layer type {l.type} needs to be explicitly handled"); } shapes.Add(O); shapesByName.Add(l.name, O); } Profiler.EndSample(); return(shapes.ToArray()); }
Tensor IOps.Reshape(Tensor X, TensorShape shape) { return(m_Ops.Reshape(X, shape)); }