c# - TensorFloat .netcore (CustomVision) 的问题
问题描述
好吧,我一直在做一些关于人工智能和对象检测的工作,最近我从 CustomVision 导出的模型遇到了一些问题。对于那些知道我在说什么的人,当您从 CustomVision 导出模型时,您会得到一个包含的 .cs 文件,该文件代表包含使用模型所需的一切的类。这开始了我所有的问题.. 第一个也是最重要的一个是在其中一种方法中,特别是在“ExtractBoxes”方法中接收一个 TensorFloat 对象和一个浮点数组的锚点。不管怎样.. 在这个方法里面有 4 个变量叫做“channels”、“height”和“width”,它们来自一个叫做“shape”的 TensorFloat 对象内部的列表。鉴于这一切.. 我的问题在于 TensorFloat 对象,
下面我将包含我正在谈论的 .cs 文件中的代码。提前致谢!
public async Task<IList<PredictionModel>> PredictImageAsync(VideoFrame image)
{
var imageWidth = image.SoftwareBitmap.PixelWidth;
var imageHeight = image.SoftwareBitmap.PixelHeight;
double ratio = Math.Sqrt((double)imageInputSize / (double)imageWidth / (double)imageHeight);
int targetWidth = 32 * (int)Math.Round(imageWidth * ratio / 32);
int targetHeight = 32 * (int)Math.Round(imageHeight * ratio / 32);
using (var resizedBitmap = await ResizeBitmap(image.SoftwareBitmap, targetWidth, targetHeight))
using (VideoFrame resizedVideoFrame = VideoFrame.CreateWithSoftwareBitmap(resizedBitmap))
{
var imageFeature = ImageFeatureValue.CreateFromVideoFrame(resizedVideoFrame);
var bindings = new LearningModelBinding(this.session);
bindings.Bind("input", imageFeature);
var result = await this.session.EvaluateAsync(bindings, "");
return Postprocess(result.Outputs["output"] as TensorFloat);
}
}
private List<PredictionModel> Postprocess(TensorFloat predictionOutputs)
{
var extractedBoxes = this.ExtractBoxes(predictionOutputs, ObjectDetection.Anchors);
return this.SuppressNonMaximum(extractedBoxes);
}
private ExtractedBoxes ExtractBoxes(TensorFloat predictionOutput, float[] anchors)
{
var shape = predictionOutput.Shape;
Debug.Assert(shape.Count == 4, "The model output has unexpected shape");
Debug.Assert(shape[0] == 1, "The batch size must be 1");
IReadOnlyList<float> outputs = predictionOutput.GetAsVectorView();
var numAnchor = anchors.Length / 2;
var channels = shape[1];
var height = shape[2];
var width = shape[3];
Debug.Assert(channels % numAnchor == 0);
var numClass = (channels / numAnchor) - 5;
Debug.Assert(numClass == this.labels.Count);
var boxes = new List<BoundingBox>();
var probs = new List<float[]>();
for (int gridY = 0; gridY < height; gridY++)
{
for (int gridX = 0; gridX < width; gridX++)
{
int offset = 0;
int stride = (int)(height * width);
int baseOffset = gridX + gridY * (int)width;
for (int i = 0; i < numAnchor; i++)
{
var x = (Logistic(outputs[baseOffset + (offset++ * stride)]) + gridX) / width;
var y = (Logistic(outputs[baseOffset + (offset++ * stride)]) + gridY) / height;
var w = (float)Math.Exp(outputs[baseOffset + (offset++ * stride)]) * anchors[i * 2] / width;
var h = (float)Math.Exp(outputs[baseOffset + (offset++ * stride)]) * anchors[i * 2 + 1] / height;
x = x - (w / 2);
y = y - (h / 2);
var objectness = Logistic(outputs[baseOffset + (offset++ * stride)]);
var classProbabilities = new float[numClass];
for (int j = 0; j < numClass; j++)
{
classProbabilities[j] = outputs[baseOffset + (offset++ * stride)];
}
var max = classProbabilities.Max();
for (int j = 0; j < numClass; j++)
{
classProbabilities[j] = (float)Math.Exp(classProbabilities[j] - max);
}
var sum = classProbabilities.Sum();
for (int j = 0; j < numClass; j++)
{
classProbabilities[j] *= objectness / sum;
}
if (classProbabilities.Max() > this.probabilityThreshold)
{
boxes.Add(new BoundingBox(x, y, w, h));
probs.Add(classProbabilities);
}
}
Debug.Assert(offset == channels);
}
}
Debug.Assert(boxes.Count == probs.Count);
return new ExtractedBoxes(boxes, probs);
}