我尝试在 ML.NET 中使用 CenterFace ONNX,但不断收到各种错误,主要与输入大小有关。
CenterFace 元数据指出它应该有一个
10, 3, 32, 32
的输入,这对于图像检测来说已经没有任何意义 - 为算法提供 10 批(每批 32x32 像素)有什么意义?
这是我的主要代码:
string modelPath = "centerface.onnx";
var mlContext = new MLContext();
string imagePath = "photo1.jpg";
var img = Image.FromFile(imagePath);
var DH = (int)(Math.Ceiling((float)img.Height / 32) * 32);
var DW = (int)(Math.Ceiling((float)img.Width / 32) * 32);
var inputData = new[] { new ModelInput { ImagePath = imagePath } };
IDataView imageData = mlContext.Data.LoadFromEnumerable(inputData);
var pipeline = mlContext.Transforms.LoadImages(outputColumnName: "input.1", imageFolder: "", inputColumnName: nameof(ModelInput.ImagePath))
.Append(mlContext.Transforms.ResizeImages(outputColumnName: "input.1", imageWidth: DW, imageHeight: DH))
.Append(mlContext.Transforms.ExtractPixels(outputColumnName: "input.1"))
.Append(mlContext.Transforms.ApplyOnnxModel(
outputColumnNames: ["537", "538", "539", "540"],
inputColumnNames: ["input.1"],
modelFile: modelPath
));
var model = pipeline.Fit(imageData);
var predictionEngine = mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(model);
var prediction = predictionEngine.Predict(new ModelInput { ImagePath = imagePath });
我的 2 个模型类:
public class ModelInput
{
public string ImagePath { get; set; }
}
public class ModelOutput
{
[ColumnName("537")]
public float[] HeatMap { get; set; }
[ColumnName("538")]
public float[] Scale { get; set; }
[ColumnName("539")]
public float[] Offset { get; set; }
[ColumnName("540")]
public float[] Landmarks { get; set; }
}
但我确实不断收到有关输入大小的错误:
System.ArgumentException:“内存长度 (3686400) 必须与维度的乘积 (30720) 匹配。”
30720 显然是 10x3x32x32。但话又说回来,这有什么意义呢? 我认为我的 ONNX 坏了,但我确实有一个使用 OpenCVSharp 的有效实现:
// Here is computer DW and DH same way as in ML.NET example
CenterFaceParams p = new(image, resizedSize.Width, resizedSize.Height, scoreThreshold, nmsThreshold);
Size size = new(p.DW, p.DH);
using Mat input = new();
Cv2.Resize(image, input, size);
using Mat blobInput = CvDnn.BlobFromImage(input, 1.0, size, new Scalar(0, 0, 0), true, false);
_net.SetInput(blobInput, "input.1");
using (Mat heatMap = new())
using (Mat scale = new())
using (Mat offset = new())
using (Mat landmarks = new())
{
_net.Forward([heatMap, scale, offset, landmarks], ["537", "538", "539", "540"]);
CenterFaceDecoder decoder = new(heatMap, scale, offset, landmarks, p);
return decoder.GetOutput();
}
这个实现给了我所有 4 层,建模后我得到了我想要的值。
您看到的错误“内存长度 (3686400) 必须与尺寸乘积 (30720) 匹配”是因为您的 ONNX 模型需要输入形状为 (10, 3, 32, 32),这表示一批10 张图像,具有 3 个颜色通道,每个尺寸为 32x32 像素。 以下是在 ML.NET 中使用此形状的步骤:
准备一批 10 张图像:CenterFace 需要一批 10 张图像,因此您需要:
代码:
var inputData = Enumerable.Repeat(new ModelInput { ImagePath = imagePath }, 10).ToArray();
调整为 32x32 像素:虽然 32x32 对于人脸检测来说可能看起来很小,但该模型很可能使用完全卷积网络结构来处理跨网格的特征。确保每个图像的大小调整为 32x32,如管道中所示:
.Append(mlContext.Transforms.ResizeImages(outputColumnName: "input.1", imageWidth: 32, imageHeight: 32))
使用浮点像素提取:ML.NET 处理像素提取的方式可能与 OpenCV 不同。如果您的模型需要的话,以标准化浮点格式提取像素。
调整管道:确保管道符合模型的要求并提供所有四个预期输出(537、538、539、540)。