public Tensor call(TensorShape shape, TF_DataType dtype = TF_DataType.DtInvalid) { throw new NotImplementedException(); }
Dictionary <Layer.Type, Action <Layer, ModelBuilder> > InstantiateRewriterNHWCToNHWC() { var rewritersNHWC = new Dictionary <Layer.Type, Action <Layer, ModelBuilder> >(); // TODO, upsample is sometimes in NHWC mode rewritersNHWC.Add(Layer.Type.Reshape, (layer, net) => { if (layer.inputs.Length == 1) { var size = layer.pool; // Don't use Tensorshape as this can remove a wild card const int _ = 1; if (size.Length == 1) { layer.pool = new[] { _, _, size[0], _, _, 1, 1, 1 } } ; // [1,1,N,1,1,1,1,1] else if (size.Length == 2) { layer.pool = new[] { _, _, size[0], _, _, 1, 1, size[1] } } ; // [1, 1, N, 1, 1, 1, 1, C] else if (size.Length == 3) { layer.pool = new[] { _, _, size[0], _, _, _, size[1], size[2] } } ; // [1,1,N,1,1,1,W,C] else if (size.Length == 4) { layer.pool = new[] { _, _, size[0], _, _, size[1], size[2], size[3] } } ; // [1,1,N,1,1,H,W,C] else if (size.Length == 5) { layer.pool = new[] { _, _, size[0], _, size[1], size[2], size[3], size[4] } } ; // [1,1,N,1,D,H,W,C] else if (size.Length == 6) { layer.pool = new[] { _, _, size[0], size[1], size[2], size[3], size[4], size[5] } } ; // [1,1,N,T,D,H,W,C] else { layer.pool = new[] { size[0], size[1], size[2], size[3], size[4], size[5], size[6], size[7] } }; // [S,R,N,T,D,H,W,C] } }); rewritersNHWC.Add(Layer.Type.Concat, ConvertAxisNHWC); rewritersNHWC.Add(Layer.Type.ReduceMax, ConvertAxisNHWC); rewritersNHWC.Add(Layer.Type.ReduceMean, ConvertAxisNHWC); rewritersNHWC.Add(Layer.Type.ReduceMin, ConvertAxisNHWC); rewritersNHWC.Add(Layer.Type.ReduceProd, ConvertAxisNHWC); rewritersNHWC.Add(Layer.Type.ReduceSum, ConvertAxisNHWC); rewritersNHWC.Add(Layer.Type.ArgMax, ConvertAxisNHWC); rewritersNHWC.Add(Layer.Type.ArgMin, ConvertAxisNHWC); rewritersNHWC.Add(Layer.Type.Activation, ConvertAxisNHWC); rewritersNHWC.Add(Layer.Type.StridedSlice, (layer, net) => { int rank = 4; if (m_RanksByName.ContainsKey(layer.name) && m_RanksByName[layer.name] != null) { rank = m_RanksByName[layer.name].Value; } var name = layer.name; var starts = layer.pad; var ends = layer.pool; var steps = layer.stride; var axes = layer.axes; var onnxStarts = Enumerable.Repeat(0, rank).ToArray(); var onnxEnds = Enumerable.Repeat(int.MaxValue, rank).ToArray(); // by default copy the whole axis till the end var onnxSteps = Enumerable.Repeat(1, rank).ToArray(); // NOTE: begin=0, end=0, stride=1 <= full range from existing axis // begin=0, end=inf,stride=1 <= full range from existing axis // begin=0, end=X, stride=1 <= full range from existing axis, if X==last element on this axis // begin=0, end=0, stride=0 <= new axis OR shrink axis to single 1st element // begin=N, end=N, stride=0 <= shrink axis to single Nth element // These notes are copied from TensorExtensions.ApplyStridedSlice(...) for (int i = 0; i < axes.Length; ++i) { var axis = axes[i]; if (axis < 0) { axis += rank; } axis = Math.Min(Math.Max(axis, 0), rank); onnxStarts[axis] = starts[i]; onnxEnds[axis] = ends[i]; onnxSteps[axis] = steps[i]; } switch (rank) { case 1: layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, 0, 0, 0 }; layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue }; layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, 1, 1, 1 }; break; case 2: layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, 0, 0, onnxStarts[1] }; layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, onnxEnds[1] }; layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, 1, 1, onnxSteps[1] }; break; case 3: layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, 0, onnxStarts[1], onnxStarts[2] }; layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, int.MaxValue, onnxEnds[1], onnxEnds[2] }; layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, 1, onnxSteps[1], onnxSteps[2] }; break; case 4: layer.pad = new[] { 0, 0, onnxStarts[0], 0, 0, onnxStarts[1], onnxStarts[2], onnxStarts[3] }; layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, int.MaxValue, onnxEnds[1], onnxEnds[2], onnxEnds[3] }; layer.stride = new[] { 1, 1, onnxSteps[0], 1, 1, onnxSteps[1], onnxSteps[2], onnxSteps[3] }; break; case 5: layer.pad = new[] { 0, 0, onnxStarts[0], 0, onnxStarts[1], onnxStarts[2], onnxStarts[3], onnxStarts[4] }; layer.pool = new[] { int.MaxValue, int.MaxValue, onnxEnds[0], int.MaxValue, onnxEnds[1], onnxEnds[2], onnxEnds[3], onnxEnds[4] }; layer.stride = new[] { 1, 1, onnxSteps[0], 1, onnxSteps[1], onnxSteps[2], onnxSteps[3], onnxSteps[4] }; break; default: throw new ArgumentException($"Unsupported tensor rank {rank} for StridedSlice"); } }); rewritersNHWC.Add(Layer.Type.Flatten, (layer, net) => { layer.type = Layer.Type.Nop; }); rewritersNHWC.Add(Layer.Type.Load, (layer, net) => { int rank = layer.axis; if (rank != 2 && rank != 3) { return; } var constX = layer.DataSetToTensor(0); var shape = constX.shape; switch (rank) { case 2: // _,_,N,_,_,C,_,_ => _,_,N,_,_,_,_,C shape = new TensorShape(shape.batch, shape.height); break; case 3: // _,_,N,_,_,W,C,_ => _,_,N,_,_,_,W,C shape = new TensorShape(shape.batch, shape.height, shape.width); break; } var reshapedX = m_Ops.Reshape(constX, shape); layer.ApplyTensorToDataSet(reshapedX, 0); reshapedX.Dispose(); constX.Dispose(); }); return(rewritersNHWC); }
/// <summary> /// Outputs random values from a normal distribution. /// </summary> /// <param name="shape"></param> /// <param name="mean"></param> /// <param name="stddev"></param> /// <param name="dtype"></param> /// <param name="seed"></param> /// <param name="name"></param> /// <returns></returns> public Tensor random_normal(TensorShape shape, float mean = 0.0f, float stddev = 1.0f, TF_DataType dtype = TF_DataType.TF_FLOAT, int?seed = null, string name = null) => random_ops.random_normal(shape, mean, stddev, dtype, seed, name);
public static Dimension dimension_at_index(TensorShape shape, int index) { return(shape.rank < 0 ? new Dimension(-1) : new Dimension(shape.dims[index])); }
public _GraphTensorArray(TF_DataType dtype, Tensor size, bool?dynamic_size = null, bool?clear_after_read = null, string tensor_array_name = null, Tensor handle = null, Tensor flow = null, bool infer_shape = true, TensorShape element_shape = null, bool colocate_with_first_write_call = true, string name = null) { clear_after_read = clear_after_read ?? true; dynamic_size = dynamic_size ?? false; _dynamic_size = dynamic_size.Value; _dtype = dtype; _colocate_with_first_write_call = colocate_with_first_write_call; if (colocate_with_first_write_call) { _colocate_with = new List <Tensor>(); } // Record the current static shape for the array elements. The element // shape is defined either by `element_shape` or the shape of the tensor // of the first write. If `infer_shape` is true, all writes checks for // shape equality. if (element_shape == null) { _infer_shape = infer_shape; _element_shape = new List <TensorShape> { }; } else { _infer_shape = true; _element_shape = new List <TensorShape> { element_shape }; } tf_with(ops.name_scope(name, "TensorArray", new { handle, size, flow }), scope => { if (handle != null) { _handle = handle; _flow = flow; } else { Func <(Tensor, Tensor)> create = () => gen_data_flow_ops.tensor_array_v3(size, dtype: dtype, element_shape: element_shape, identical_element_shapes: infer_shape, dynamic_size: dynamic_size.Value, clear_after_read: clear_after_read.Value, tensor_array_name: tensor_array_name, name: scope); // Construct the TensorArray with an empty device. The first // write into the TensorArray from a Tensor with a set device // will retroactively set the device value of this op. if (colocate_with_first_write_call) { ops.colocate_with(ignore_existing: true); (_handle, _flow) = create(); } else { (_handle, _flow) = create(); } } }); }
protected override void build(Tensors inputs) { TensorShape input_shape = inputs.shape; var ndims = input_shape.ndim; foreach (var(idx, x) in enumerate(axis)) { if (x < 0) { axis[idx] = ndims + x; } } fused = ndims == 4; if (fused) { if (Enumerable.SequenceEqual(axis, new int[] { 1 })) { _data_format = "NCHW"; } else if (Enumerable.SequenceEqual(axis, new int[] { 3 })) { _data_format = "NHWC"; } else { throw new ValueError($"Unsupported axis, fused batch norm only supports axis == [1] or axis == [3]"); } } var axis_to_dim = new Dictionary <int, int>(); foreach (var x in axis) { axis_to_dim[x] = input_shape[x]; } inputSpec = new InputSpec(ndim: ndims, axes: axis_to_dim); var param_dtype = DType == TF_DataType.DtInvalid ? TF_DataType.TF_FLOAT : DType; var param_shape = inputSpec.AllAxisDim; if (scale) { gamma = add_weight("gamma", param_shape, dtype: param_dtype, initializer: gamma_initializer, trainable: true); } else { throw new NotImplementedException("add_weight gamma"); } if (center) { beta = add_weight("beta", param_shape, dtype: param_dtype, initializer: beta_initializer, trainable: true); } else { throw new NotImplementedException("add_weight beta"); } moving_mean = add_weight("moving_mean", param_shape, dtype: param_dtype, initializer: moving_mean_initializer, synchronization: VariableSynchronization.OnRead, aggregation: VariableAggregation.Mean, trainable: false); moving_variance = add_weight("moving_variance", shape: param_shape, dtype: param_dtype, initializer: moving_variance_initializer, synchronization: VariableSynchronization.OnRead, aggregation: VariableAggregation.Mean, trainable: false); if (renorm) { throw new NotImplementedException("build when renorm is true"); } built = true; }
private void _build(TensorShape shape) => throw new NotImplementedException();
public void Case7() { TensorShape shape = new TensorShape(); Assert.AreEqual(shape.rank, -1); }
public Tensor reduce_sum(Tensor input, TensorShape axis, int?reduction_indices = null, bool keepdims = false, string name = null) => math_ops.reduce_sum(input, axis, keepdims: keepdims, name: name);
internal static Tensor CastDataAndReturnAsTensor <T>(T[] data, TensorShape tfShape) { var dims = tfShape.dims.Select(x => (long)x).ToArray(); if (typeof(T) == typeof(sbyte)) { return(new Tensor((sbyte[])(object)data, dims, TF_DataType.TF_INT8)); } else if (typeof(T) == typeof(long)) { return(new Tensor((long[])(object)data, dims, TF_DataType.TF_INT64)); } else if (typeof(T) == typeof(Int32)) { return(new Tensor((Int32[])(object)data, dims, TF_DataType.TF_INT32)); } else if (typeof(T) == typeof(Int16)) { return(new Tensor((Int16[])(object)data, dims, TF_DataType.TF_INT16)); } else if (typeof(T) == typeof(byte)) { return(new Tensor((byte[])(object)data, dims, TF_DataType.TF_UINT8)); } else if (typeof(T) == typeof(ulong)) { return(new Tensor((ulong[])(object)data, dims, TF_DataType.TF_UINT64)); } else if (typeof(T) == typeof(UInt32)) { return(new Tensor((UInt32[])(object)data, dims, TF_DataType.TF_UINT32)); } else if (typeof(T) == typeof(UInt16)) { return(new Tensor((UInt16[])(object)data, dims, TF_DataType.TF_UINT16)); } else if (typeof(T) == typeof(bool)) { return(new Tensor((bool[])(object)data, dims, TF_DataType.TF_BOOL)); } else if (typeof(T) == typeof(float)) { return(new Tensor((float[])(object)data, dims, TF_DataType.TF_FLOAT)); } else if (typeof(T) == typeof(double)) { return(new Tensor((double[])(object)data, dims, TF_DataType.TF_DOUBLE)); } else if (typeof(T) == typeof(ReadOnlyMemory <char>)) { string[] strings = new string[data.Length]; for (int i = 0; i < strings.Length; i++) { strings[i] = data[i].ToString(); } return(new Tensor(strings)); } return(new Tensor(new NDArray(data, tfShape))); }
public override TensorShape compute_output_shape(TensorShape input_shape) { var outputShape = input_shape.as_list(); outputShape[^ 1] = this.innerLayers[^ 1].units;
public Tensor ones(TensorShape shape, TF_DataType dtype = TF_DataType.TF_FLOAT, string name = null) => array_ops.ones(shape, dtype, name);
protected virtual void build(TensorShape input_shape) { built = true; }
public void Case5() { TensorShape shape = (1, Unknown, 3); shape.GetPrivate <Shape>("shape").Should().BeShaped(1, -1, 3); }
public Tensor reshape(Tensor tensor, TensorShape shape, string name = null) => gen_array_ops.reshape(tensor, shape, name);
public void Case6() { TensorShape shape = (Unknown, 1, 2, 3, Unknown); shape.GetPrivate <Shape>("shape").Should().BeShaped(-1, 1, 2, 3, -1); }
public virtual TensorShape ComputeOutputShape(TensorShape input_shape) => throw new NotImplementedException("");
public void _merge_element_shape(TensorShape shape) { _element_shape.Add(shape); }
public void Run(ref Model model) { // MatMul (rank3) + known input -> Add/Sub => Dense3 var constLayers = new Dictionary <string, Layer>(); foreach (var l in model.layers) { if (l.type == Layer.Type.Load) { constLayers[l.name] = l; } } var preserve = new HashSet <string>( model.memories.Select(mem => mem.input).Concat( model.memories.Select(mem => mem.output)).Concat( model.outputs)); var removeLayers = new HashSet <string>(); var remap = new Dictionary <string, string>(); for (int l = 0; l < model.layers.Count - 1; ++l) { Layer layer = model.layers[l]; List <Layer> downStreamLayers = GetDownStreamLayers(model, layer.name); if (!IsLayerDense3(layer, downStreamLayers, constLayers)) { continue; } if (preserve.Contains(layer.name) || preserve.Contains(downStreamLayers[0].name)) { continue; } string weights = (layer.inputs.Where(x => constLayers.ContainsKey(x)).ToList())[0]; Layer constWeights = constLayers[weights]; var weightArray = constWeights.weights; var weightShape = constWeights.datasets[0].shape; Layer downStreamLayer = downStreamLayers[0]; string bias = (downStreamLayer.inputs.Where(x => x != layer.name).ToList())[0]; Layer constBias = constLayers[bias]; TensorShape biasShape = new TensorShape(1, 1, 1, Mathf.Max(weightShape.channels, constBias.datasets[0].shape.length)); var biasArray = constBias.weights; var inputs = layer.inputs.Where(x => x != weights).ToArray(); Layer mergedLayer = new Layer(layer.name, Layer.Type.Dense3); mergedLayer.inputs = inputs; mergedLayer.datasets = new Layer.DataSet[2]; mergedLayer.datasets[0].name = $"{mergedLayer.name}/W"; mergedLayer.datasets[0].shape = weightShape; mergedLayer.datasets[0].itemSizeInBytes = 4; mergedLayer.datasets[0].length = weightShape.length; mergedLayer.datasets[0].offset = 0; mergedLayer.datasets[1].name = $"{mergedLayer.name}/B"; mergedLayer.datasets[1].shape = biasShape; mergedLayer.datasets[1].itemSizeInBytes = 4; mergedLayer.datasets[1].length = biasShape.length; mergedLayer.datasets[1].offset = weightShape.length; mergedLayer.weights = new float[weightShape.length + biasShape.length]; weightArray.CopyTo(mergedLayer.weights, 0); if (constBias.datasets[0].shape.length == 1) { for (int i = 0; i < biasShape.length; i++) { mergedLayer.weights[mergedLayer.datasets[1].offset + i] = biasArray[0]; } } else { biasArray.CopyTo(mergedLayer.weights, mergedLayer.datasets[1].offset); } model.layers[l] = mergedLayer; if (!preserve.Contains(constWeights.name)) { removeLayers.Add(constWeights.name); } removeLayers.Add(downStreamLayer.name); if (!preserve.Contains(constBias.name)) { removeLayers.Add(constBias.name); } remap[downStreamLayer.name] = mergedLayer.name; } model.layers.RemoveAll(l => removeLayers.Contains(l.name)); for (int l = 0; l < model.layers.Count; ++l) { Layer layer = model.layers[l]; for (int i = 0; i < layer.inputs.Length; i++) { var input = layer.inputs[i]; if (remap.ContainsKey(input)) { model.layers[l].inputs[i] = remap[input]; } } } }
public override TensorShape ComputeOutputShape(TensorShape input_shape) { return(input_shape); }
public TapeTensor(long id, TF_DataType dtype, TensorShape shape) { this.id = id; this.dtype = dtype; this.shape = shape; }
protected virtual IVariableV1 add_weight(string name, TensorShape shape, TF_DataType dtype = TF_DataType.TF_FLOAT, IInitializer initializer = null, IRegularizer regularizer = null, VariableSynchronization synchronization = VariableSynchronization.Auto, VariableAggregation aggregation = VariableAggregation.None, bool trainable = true, Func <VariableArgs, IVariableV1> getter = null) { // Initialize variable when no initializer provided if (initializer == null) { // If dtype is DT_FLOAT, provide a uniform unit scaling initializer if (dtype.is_floating()) { initializer = tf.glorot_uniform_initializer; } else if (dtype.is_integer()) { initializer = tf.zeros_initializer; } else { throw new ValueError($"An initializer for variable {name} of type {dtype.as_base_dtype()} is required for layer {name}"); } } if (synchronization == VariableSynchronization.OnRead) { trainable = false; } var args = new VariableArgs { Name = name, Shape = shape, DType = dtype, Getter = getter ?? base_layer_utils.make_variable, Overwrite = true, Initializer = initializer, Synchronization = synchronization, Aggregation = aggregation, Trainable = trainable }; var variable = _add_variable_with_custom_getter(args); if (regularizer != null) { var name_in_scope = variable.Name.Split(':')[0]; _handle_weight_regularization(name_in_scope, variable, regularizer); } //backend.track_variable(variable); if (trainable == true) { trainableWeights.Add(variable); } else { nonTrainableWeights.Add(variable); } return(variable); }
public static Model NASNetLarge(TensorShape input_shape = null, bool include_top = true, string weights = "imagenet", Tensor input_tensor = null, string pooling = null, int classes = 1000) => throw new NotImplementedException();
public Tensor random_uniform(TensorShape shape, float minval = 0, float maxval = 1, TF_DataType dtype = TF_DataType.TF_FLOAT, int?seed = null, string name = null) => random_ops.random_uniform(shape, minval, maxval, dtype, seed, name);
public static Model NASNet(TensorShape input_shape = null, int penultimate_filters = 4032, int num_blocks = 6, int stem_block_filters = 96, bool skip_reduction = true, int filter_multiplier = 2, bool include_top = true, string weights = null, Tensor input_tensor = null, string pooling = null, int classes = 1000, int?default_size = null) => throw new NotImplementedException();
protected override void build(TensorShape input_shape) { var ndims = input_shape.NDim; foreach (var(idx, x) in Python.enumerate(axis)) { if (x < 0) { axis[idx] = ndims + x; } } if (fused) { if (Enumerable.SequenceEqual(axis, new int[] { 3 })) { _data_format = "NHWC"; } } var param_dtype = _dtype == TF_DataType.DtInvalid ? TF_DataType.TF_FLOAT : _dtype; var param_shape = new int[] { input_shape.Dimensions[axis[0]] }; if (scale) { gamma = add_weight("gamma", param_shape, dtype: param_dtype, initializer: gamma_initializer, trainable: true); } else { throw new NotImplementedException("add_weight gamma"); } if (center) { beta = add_weight("beta", param_shape, dtype: param_dtype, initializer: beta_initializer, trainable: true); } else { throw new NotImplementedException("add_weight beta"); } if (_scope != null) { } moving_mean = add_weight("moving_mean", param_shape, dtype: param_dtype, initializer: moving_mean_initializer, synchronization: VariableSynchronization.OnRead, trainable: false, aggregation: VariableAggregation.Mean); moving_variance = add_weight("moving_variance", shape: param_shape, dtype: param_dtype, initializer: moving_variance_initializer, synchronization: VariableSynchronization.OnRead, trainable: false, aggregation: VariableAggregation.Mean); if (renorm) { throw new NotImplementedException("build when renorm is true"); } built = true; }
public void FuseInputsIntoLayer(ref Layer layer, Dictionary <string, Tensor> knownLayersValue, IDictionary <string, int?> ranksByName) { switch (layer.type) { case Layer.Type.Upsample2D: { if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) { return; } float[] scales = knownLayersValue[layer.inputs[1]].ToReadOnlyArray(); if (scales[0] == 1 && scales[1] == 1 && scales[2] < 1.0f && scales[3] < 1.0f) { scales = new[] { scales[2], scales[3] }; layer.type = Layer.Type.AvgPool2D; layer.pad = new[] { 0, 0 }; var inverseScalesRoundedToInt = scales.Select(x => (int)Mathf.Round(1f / x)).ToArray(); layer.stride = new[] { 1, 1 }; layer.pool = inverseScalesRoundedToInt; } else { layer.inputs = new[] { layer.inputs[0] }; layer.pool = Array.ConvertAll(scales, x => (int)x); } return; } case Layer.Type.Resample2D: { if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) { return; } int[] sizes = Array.ConvertAll(knownLayersValue[layer.inputs[1]].ToReadOnlyArray(), x => (int)x); layer.inputs = new[] { layer.inputs[0] }; layer.pool = sizes; return; } case Layer.Type.Expand: { if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) { return; } float[] shapeValue = knownLayersValue[layer.inputs[1]].ToReadOnlyArray(); var shape = new int[shapeValue.Length]; for (int i = 0; i < shapeValue.Length; i++) { shape[i] = (int)shapeValue[i]; } layer.pool = shape; layer.inputs = new[] { layer.inputs[0] }; return; } case Layer.Type.MatMul: { var input0 = layer.inputs[0]; var input1 = layer.inputs[1]; if (!ranksByName.ContainsKey(input0) || !ranksByName[input0].HasValue) { return; } if (!ranksByName.ContainsKey(input1) || !ranksByName[input1].HasValue) { return; } int rank0 = ranksByName[input0].Value; int rank1 = ranksByName[input1].Value; if (rank0 > 2 || rank1 > 2) { return; } if (!IsLayerKnown(input1, knownLayersValue)) { return; } layer.type = Layer.Type.Dense; var weight = knownLayersValue[input1]; weight = weight.Reshape(new TensorShape(weight.batch, weight.height)); var biasShape = new TensorShape(1, 1, 1, weight.shape.channels); layer.inputs = new [] { input0 }; layer.datasets = new Layer.DataSet[2]; layer.datasets[0].name = $"{layer.name}/W"; layer.datasets[0].shape = weight.shape; layer.datasets[0].itemSizeInBytes = 4; layer.datasets[0].length = weight.shape.length; layer.datasets[0].offset = 0; layer.datasets[1].name = $"{layer.name}/B"; layer.datasets[1].shape = biasShape; layer.datasets[1].itemSizeInBytes = 4; layer.datasets[1].length = biasShape.length; layer.datasets[1].offset = weight.shape.length; layer.weights = new float[weight.shape.length + biasShape.length]; weight.ToReadOnlyArray().CopyTo(layer.weights, 0); return; } case Layer.Type.Tile: { if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) { return; } var shape = Array.ConvertAll(knownLayersValue[layer.inputs[1]].ToReadOnlyArray(), x => (int)x); layer.pool = shape; layer.inputs = new[] { layer.inputs[0] }; return; } case Layer.Type.Reshape: { if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue)) { return; } float[] shapeValue = knownLayersValue[layer.inputs[1]].ToReadOnlyArray(); var shape = new int[shapeValue.Length]; for (int i = 0; i < shapeValue.Length; i++) { shape[i] = (int)shapeValue[i]; } layer.pool = shape; layer.inputs = new[] { layer.inputs[0] }; return; } case Layer.Type.ConstantOfShape: { if (layer.inputs.Length < 1 || !IsLayerKnown(layer.inputs[0], knownLayersValue)) { return; } Tensor input = knownLayersValue[layer.inputs[0]]; var shape = Array.ConvertAll(input.ToReadOnlyArray(), x => (int)x); var tensorShape = IRShapeInferenceHelper.ShapeInference.OnnxLayoutToTensorShape(shape); layer.type = Layer.Type.Load; layer.axis = shape.Length; layer.datasets = new Layer.DataSet[1]; layer.datasets[0].name = layer.name; layer.datasets[0].shape = tensorShape; layer.datasets[0].itemSizeInBytes = 4; layer.datasets[0].length = tensorShape.length; layer.datasets[0].offset = 0; layer.weights = new float[tensorShape.length]; var tensor = new Tensor(tensorShape); tensor.Fill(layer.alpha); tensor.ToReadOnlyArray().CopyTo(layer.weights, 0); layer.inputs = new string[0]; return; } case Layer.Type.LSTM: { if (layer.inputs.Length <= 3 || !knownLayersValue.TryGetValue(layer.inputs[1], out Tensor W) || !knownLayersValue.TryGetValue(layer.inputs[2], out Tensor R) || !knownLayersValue.TryGetValue(layer.inputs[3], out Tensor B)) { return; } var ops = new ReferenceCPUOps(); using (var td = new TensorScope()) { TensorScope.F _ = td._; W = _(ops.Transpose(W, new[] { 2, 0, 3, 1 })); R = _(ops.Transpose(R, new[] { 2, 0, 3, 1 })); B = _(ops.Transpose(B, new[] { 0, 2, 3, 1 })); OpsUtils.BakeConstantWRBIntoLSTMLayer(layer, W, R, B); } layer.inputs = new[] { layer.inputs[0], layer.inputs[4], layer.inputs[5] }; return; } case Layer.Type.Activation: { if (layer.activation == Layer.Activation.None) { if (layer.inputs.Length < 1 || !IsLayerKnown(layer.inputs[0], knownLayersValue)) { return; } Tensor input = knownLayersValue[layer.inputs[0]]; var tensorShape = input.shape; layer.type = Layer.Type.Load; layer.axis = input.dimensions; // TODO real rank layer.datasets = new Layer.DataSet[1]; layer.datasets[0].name = layer.name; layer.datasets[0].shape = tensorShape; layer.datasets[0].itemSizeInBytes = 4; layer.datasets[0].length = tensorShape.length; layer.datasets[0].offset = 0; layer.weights = new float[tensorShape.length]; input.ToReadOnlyArray().CopyTo(layer.weights, 0); layer.inputs = new string[0]; } return; } case Layer.Type.StridedSlice: { if (layer.inputs.Length <= 1 || !IsLayerKnown(layer.inputs[1], knownLayersValue) || !IsLayerKnown(layer.inputs[2], knownLayersValue) || !IsLayerKnown(layer.inputs[3], knownLayersValue) || !IsLayerKnown(layer.inputs[4], knownLayersValue)) { return; } var starts = Array.ConvertAll(knownLayersValue[layer.inputs[1]].ToReadOnlyArray(), x => x <= (float)int.MinValue ? int.MinValue : x >= (float)int.MaxValue ? int.MaxValue : (int)x); var ends = Array.ConvertAll(knownLayersValue[layer.inputs[2]].ToReadOnlyArray(), x => x <= (float)int.MinValue ? int.MinValue : x >= (float)int.MaxValue ? int.MaxValue : (int)x); var strides = Enumerable.Repeat(1, starts.Length).Select(v => (int)v).ToArray(); if (layer.inputs.Length >= 4) { strides = Array.ConvertAll(knownLayersValue[layer.inputs[3]].ToReadOnlyArray(), x => (int)x); } var axes = Enumerable.Range(0, starts.Length).Select(v => (int)v).ToArray(); if (layer.inputs.Length == 5) { axes = Array.ConvertAll(knownLayersValue[layer.inputs[4]].ToReadOnlyArray(), x => (int)x); } layer.pad = starts; layer.pool = ends; layer.stride = strides; layer.axes = axes; layer.inputs = new[] { layer.inputs[0] }; return; } default: return; } }