private Layer ConvertDepthwiseConv2d(tflite.Operator op) { var inputs = op.GetInputsArray(); var input = _graph.Tensors(inputs[0]).Value; var options = op.BuiltinOptions <tflite.DepthwiseConv2DOptions>().Value; var weights = _graph.Tensors(inputs[1]).Value; var bias = _graph.Tensors(inputs[2]).Value; var depthMul = options.DepthMultiplier; if (input.GetShapeArray().ToNCHW()[1] == 1 && depthMul != 1) { var layer = new Conv2d(input.GetShapeArray().ToNCHW(), _model.GetTensor <float>(weights).ToOIHW().Transpose(new[] { 1, 0, 2, 3 }), _model.GetTensor <float>(bias), options.Padding.ToPadding(), options.StrideW, options.StrideH, options.FusedActivationFunction.ToActivationFunction()); _inputs.Add(layer.Input, inputs[0]); _outputs.Add(op.Outputs(0), layer.Output); return(layer); } else if (depthMul != 1) { throw new LayerNotSupportedException("DEPTHWISE_CONV_2D", "depth_multiplier must be 1"); } { var layer = new DepthwiseConv2d(input.GetShapeArray().ToNCHW(), _model.GetTensor <float>(weights).ToOIHW(), _model.GetTensor <float>(bias), options.Padding.ToPadding(), options.StrideW, options.StrideH, options.FusedActivationFunction.ToActivationFunction()); _inputs.Add(layer.Input, inputs[0]); _outputs.Add(op.Outputs(0), layer.Output); return(layer); } }
public override void Process(TransformContext context) { var space = (SpaceToBatchNd)context.MatchedLayers[0]; var dwConv2d = (DepthwiseConv2d)context.MatchedLayers[1]; var conv2d = (Conv2d)context.MatchedLayers[2]; var input = space.Input.Connection.From; var output = conv2d.Output; space.Input.ClearConnection(); var newDwConv2d = new DepthwiseConv2d(input.Dimensions, dwConv2d.Weights, dwConv2d.Bias, Padding.Same, 1, 1, dwConv2d.FusedActivationFunction); var quantize = new Quantize(newDwConv2d.Output.Dimensions); var upload = new K210Upload(quantize.Output.Dimensions); var newConv2d = new K210Conv2d(upload.Output.Dimensions, K210Conv2dType.Conv2d, conv2d.Weights, conv2d.Bias, K210PoolType.LeftTop, conv2d.FusedActivationFunction, null); var dequantize = new Dequantize(newConv2d.Output.Dimensions); newDwConv2d.Input.SetConnection(input); quantize.Input.SetConnection(newDwConv2d.Output); upload.Input.SetConnection(quantize.Output); newConv2d.Input.SetConnection(upload.Output); dequantize.Input.SetConnection(newConv2d.Output); var oldOuts = output.Connections.Select(o => o.To).ToList(); foreach (var oldOut in oldOuts) { oldOut.SetConnection(dequantize.Output); } }
private Layer ConvertConv2d(paddle.OpDesc op) { var padding = GetAttr(op, "paddings").Ints; var strides = GetAttr(op, "strides").Ints.ToArray(); var groups = GetAttr(op, "groups").I; if (strides[0] == 0) { strides[0] = 1; } if (strides[1] == 0) { strides[1] = 1; } var input = GetParameter(op.Inputs, "Input").Arguments[0]; var weights = GetParameter(op.Inputs, "Filter").Arguments[0]; var weightsShape = GetVarShape(weights); var kernelWidth = weightsShape[3]; var kernelHeight = weightsShape[2]; var output = GetParameter(op.Outputs, "Output").Arguments[0]; if (groups == 1) { Conv2d conv2d; if (padding[0] == 1 && padding[1] == 1 && strides[0] == 2 && strides[1] == 2 && kernelWidth == 3 && kernelHeight == 3) { var space = new SpaceToBatchNd(GetVarShape(input), new[] { 1, 1 }.ToTensor(), new[, ] { { 1, 1 }, { 1, 1, } }.ToTensor()); conv2d = new Conv2d(space.Output.Dimensions, LoadVarData <float>(weights), null, Padding.Valid, strides[1], strides[0], ActivationFunctionType.Linear); conv2d.Input.SetConnection(space.Output); _inputs.Add(space.Input, input); } else { if (padding[0] != padding[1] || (padding[0] != 0 && padding[0] != 1)) { throw new NotSupportedException(); } conv2d = new Conv2d(GetVarShape(input), LoadVarData <float>(weights), null, Padding.Same, strides[1], strides[0], ActivationFunctionType.Linear); _inputs.Add(conv2d.Input, input); } _outputs.Add(output, conv2d.Output); return(conv2d); } else if (groups == weightsShape[0]) { var w = LoadVarData <float>(weights).Transpose(new[] { 1, 0, 2, 3 }); DepthwiseConv2d dwConv2d; if (padding[0] == 1 && padding[1] == 1 && strides[0] == 2 && strides[1] == 2 && kernelWidth == 3 && kernelHeight == 3) { var space = new SpaceToBatchNd(GetVarShape(input), new[] { 1, 1 }.ToTensor(), new[, ] { { 1, 1 }, { 1, 1, } }.ToTensor()); dwConv2d = new DepthwiseConv2d(space.Output.Dimensions, w, null, Padding.Valid, strides[1], strides[0], ActivationFunctionType.Linear); dwConv2d.Input.SetConnection(space.Output); _inputs.Add(space.Input, input); } else { if (padding[0] != padding[1] || (padding[0] != 0 && padding[0] != 1)) { throw new NotSupportedException(); } dwConv2d = new DepthwiseConv2d(GetVarShape(input), w, null, Padding.Same, strides[1], strides[0], ActivationFunctionType.Linear); _inputs.Add(dwConv2d.Input, input); } _outputs.Add(output, dwConv2d.Output); return(dwConv2d); } else { throw new NotSupportedException(); } }
public override void Process(TransformContext context) { var space = context.MatchedLayers[0]; var dwConv2d = (DepthwiseConv2d)context.MatchedLayers[1]; var conv2d = (Conv2d)context.MatchedLayers.Last(); var input = space.InputConnectors[0].Connection.From; var output = conv2d.Output; space.InputConnectors[0].ClearConnection(); var newDwConv2d = new DepthwiseConv2d(input.Dimensions, dwConv2d.Weights, dwConv2d.Bias, Padding.Same, 1, 1, dwConv2d.FusedActivationFunction); var quantize = new Quantize(newDwConv2d.Output.Dimensions); var upload = new K210Upload(quantize.Output.Dimensions); var newConv2d = new K210Conv2d(upload.Output.Dimensions, K210Conv2dType.Conv2d, conv2d.Weights, conv2d.Bias, K210PoolType.LeftTop, conv2d.FusedActivationFunction, null); var dequantize = new Dequantize(newConv2d.Output.Dimensions); newDwConv2d.Input.SetConnection(input); quantize.Input.SetConnection(newDwConv2d.Output); upload.Input.SetConnection(quantize.Output); newConv2d.Input.SetConnection(upload.Output); dequantize.Input.SetConnection(newConv2d.Output); var oldOuts = output.Connections.Select(o => o.To).ToList(); if (context.MatchedLayers.Count == 3) { foreach (var oldOut in oldOuts) { oldOut.SetConnection(dequantize.Output); } } else { var newOutput = dequantize.Output; foreach (var middleLayer in context.MatchedLayers.Skip(2).Take(context.MatchedLayers.Count - 3)) { Layer newLayer; switch (middleLayer) { case Quantize _: newLayer = new Quantize(newOutput.Dimensions); break; case Dequantize _: newLayer = new Dequantize(newOutput.Dimensions); break; case LeakyRelu l: newLayer = new LeakyRelu(newOutput.Dimensions, l.Slope); break; default: throw new NotImplementedException(); } newLayer.InputConnectors[0].SetConnection(newOutput); newOutput = newLayer.OutputConnectors[0]; } foreach (var oldOut in oldOuts) { oldOut.SetConnection(newOutput); } } }
private Layer ConvertConvolution(LayerParameter layerParam) { var input = _outputs[layerParam.Bottom[0]]; var param = layerParam.ConvolutionParam; uint[] GetDefault(Google.Protobuf.Collections.RepeatedField <uint> field) { if (field.Count == 0) { return new uint[] { 1, 1 } } ; else if (field.Count == 1) { return new[] { field[0], field[0] } } ; else { return(field.ToArray()); } } var padding = GetDefault(param.Pad); var strides = GetDefault(param.Stride); var kernelSize = param.KernelSize.Count == 1 ? new[] { param.KernelSize[0], param.KernelSize[0] } : (param.KernelSize.Count == 0 ? new[] { param.KernelH, param.KernelW } : param.KernelSize.ToArray()); var group = param.Group == 0 ? 1 : param.Group; if (group == 1) { var weights = LoadBlob(layerParam.Blobs[0]); Conv2d conv2d; if (padding[0] != 0 || padding[1] != 0) { if (padding[0] == 1 && padding[1] == 1 && strides[0] == 1 && strides[1] == 1) { conv2d = new Conv2d(input.Dimensions, weights, null, Padding.Same, 1, 1, ActivationFunctionType.Linear); conv2d.Input.SetConnection(input); } else { var space = new SpaceToBatchNd(input.Dimensions, new[] { 1, 1 }.ToTensor(), new[, ] { { (int)padding[0], (int)padding[0] }, { (int)padding[1], (int)padding[1], } }.ToTensor()); conv2d = new Conv2d(space.Output.Dimensions, weights, null, Padding.Valid, (int)strides[1], (int)strides[0], ActivationFunctionType.Linear); space.Input.SetConnection(input); conv2d.Input.SetConnection(space.Output); } } else { conv2d = new Conv2d(input.Dimensions, weights, null, Padding.Valid, (int)strides[1], (int)strides[0], ActivationFunctionType.Linear); conv2d.Input.SetConnection(input); } _outputs.Add(layerParam.Top[0], conv2d.Output); return(conv2d); } else if (group == param.NumOutput) { var weights = LoadBlob(layerParam.Blobs[0]).Transpose(new[] { 1, 0, 2, 3 }); DepthwiseConv2d dwConv2d; if (padding[0] != 0 || padding[1] != 0) { if (padding[0] == 1 && padding[1] == 1 && strides[0] == 1 && strides[1] == 1) { dwConv2d = new DepthwiseConv2d(input.Dimensions, weights, null, Padding.Same, 1, 1, ActivationFunctionType.Linear); dwConv2d.Input.SetConnection(input); } else { var space = new SpaceToBatchNd(input.Dimensions, new[] { 1, 1 }.ToTensor(), new[, ] { { (int)padding[0], (int)padding[0] }, { (int)padding[1], (int)padding[1], } }.ToTensor()); dwConv2d = new DepthwiseConv2d(space.Output.Dimensions, weights, null, Padding.Valid, (int)strides[1], (int)strides[0], ActivationFunctionType.Linear); space.Input.SetConnection(input); dwConv2d.Input.SetConnection(space.Output); } } else { dwConv2d = new DepthwiseConv2d(input.Dimensions, weights, null, Padding.Valid, (int)strides[1], (int)strides[0], ActivationFunctionType.Linear); dwConv2d.Input.SetConnection(input); } _outputs.Add(layerParam.Top[0], dwConv2d.Output); return(dwConv2d); } else { throw new NotSupportedException("Grouped conv2d is not supported."); } }