在C#中加载并使用Teachable Machine导出的TensorFlow图像分类模型求助
嘿,我完全懂你现在卡在C#里用Teachable Machine导出的TensorFlow图像分类模型的困境!之前的提问被关闭确实闹心,我这就给你捋清楚步骤,附上实用的示例代码,保证能帮你搞定这个事儿~
在C#中加载并使用Teachable Machine导出的TensorFlow图像分类模型
一、先做好准备工作
首先得明确Teachable Machine导出的模型格式,一般常用的有两种:TensorFlow SavedModel 和 TensorFlow Lite (TFLite)。针对不同格式,C#里要用的依赖库不一样:
- 要是用SavedModel:安装
TensorFlow.NET+TensorFlow.KerasNuGet包 - 要是用TFLite:安装
TensorFlowLite.NETNuGet包
另外,导出模型的时候一定要把**标签文件(labels.txt)**一起下载下来,不然模型输出的数字索引没法转成你能看懂的分类名称。把模型文件和标签文件放到项目里后,记得设置它们的“复制到输出目录”为“如果较新则复制”,这样运行时才能找到文件。
二、推荐方案:加载TensorFlow Lite模型(轻量简洁)
TFLite模型体积小、推理快,适合桌面或移动端场景,先给你这个更实用的示例:
完整代码实现
using System; using System.IO; using System.Linq; using TensorFlowLite; using System.Drawing; class TFLiteImageClassifier { private readonly Interpreter _modelInterpreter; private readonly string[] _categoryLabels; private readonly int _requiredImgHeight; private readonly int _requiredImgWidth; private readonly float[] _inputDataBuffer; public TFLiteImageClassifier(string modelFilePath, string labelsFilePath) { // 加载分类标签 _categoryLabels = File.ReadAllLines(labelsFilePath); // 初始化TFLite解释器 var interpreterOptions = new InterpreterOptions(); _modelInterpreter = new Interpreter(File.ReadAllBytes(modelFilePath), interpreterOptions); _modelInterpreter.AllocateTensors(); // 获取模型要求的输入尺寸(一般是[1, 高, 宽, 3],对应批量1、图像高宽、RGB通道) var inputTensor = _modelInterpreter.GetInputTensor(0); var inputShape = inputTensor.Shape; _requiredImgHeight = (int)inputShape[1]; _requiredImgWidth = (int)inputShape[2]; _inputDataBuffer = new float[inputShape.Size]; } public string ClassifySingleImage(string imageFilePath) { // 预处理图像:调整尺寸+像素归一化(Teachable Machine默认要求0-1范围) using var originalImg = new Bitmap(imageFilePath); using var resizedImg = new Bitmap(originalImg, _requiredImgWidth, _requiredImgHeight); // 把图像像素转成模型需要的float数组 int bufferIndex = 0; for (int y = 0; y < resizedImg.Height; y++) { for (int x = 0; x < resizedImg.Width; x++) { var pixel = resizedImg.GetPixel(x, y); _inputDataBuffer[bufferIndex++] = pixel.R / 255f; _inputDataBuffer[bufferIndex++] = pixel.G / 255f; _inputDataBuffer[bufferIndex++] = pixel.B / 255f; } } // 喂数据给模型并运行推理 _modelInterpreter.SetInputTensorData(0, _inputDataBuffer); _modelInterpreter.Invoke(); // 获取输出结果,找到概率最高的分类 var outputResults = _modelInterpreter.GetOutputTensor(0).DataAsFloatArray; int topResultIndex = outputResults .Select((probability, index) => (probability, index)) .OrderByDescending(item => item.probability) .First().index; return _categoryLabels[topResultIndex]; } public void Dispose() { _modelInterpreter.Dispose(); } } // 调用示例 class Program { static void Main(string[] args) { string modelPath = "model.tflite"; string labelsPath = "labels.txt"; string testImagePath = "your_test_image.jpg"; using var classifier = new TFLiteImageClassifier(modelPath, labelsPath); string classificationResult = classifier.ClassifySingleImage(testImagePath); Console.WriteLine($"识别结果:{classificationResult}"); } }
三、备选方案:加载TensorFlow SavedModel
如果你导出的是SavedModel格式,用TensorFlow.NET来实现,代码如下:
完整代码实现
using System; using System.IO; using System.Linq; using TensorFlow; using TensorFlow.Keras.Preprocessing.Image; class SavedModelImageClassifier { private readonly TFSession _inferenceSession; private readonly TFGraph _modelGraph; private readonly string[] _categoryLabels; private readonly int _requiredImgHeight; private readonly int _requiredImgWidth; public SavedModelImageClassifier(string modelDirPath, string labelsFilePath) { // 加载分类标签 _categoryLabels = File.ReadAllLines(labelsFilePath); // 加载SavedModel _modelGraph = new TFGraph(); _modelGraph.ImportSavedModel(modelDirPath, new[] { "serve" }, null); _inferenceSession = new TFSession(_modelGraph); // 获取模型输入尺寸(输入节点名可能需要调整,用saved_model_cli工具可查看) var inputOp = _modelGraph["serving_default_input_1"]; var inputShape = inputOp.Outputs[0].Shape; _requiredImgHeight = (int)inputShape[1]; _requiredImgWidth = (int)inputShape[2]; } public string ClassifySingleImage(string imageFilePath) { // 预处理图像:调整尺寸+转成模型需要的张量格式 var image = ImageDataGenerator.LoadImg(imageFilePath, targetSize: (_requiredImgHeight, _requiredImgWidth)); var imageArray = ImageDataGenerator.ImageToArray(image); var inputTensor = TFIOUtils.CreateTensorFromImageArray(new[] { imageArray }, TFDataType.Float); // 运行推理(输出节点名可能需要调整,用saved_model_cli工具可查看) var runner = _inferenceSession.GetRunner(); runner.AddInput(_modelGraph["serving_default_input_1"][0], inputTensor) .Fetch(_modelGraph["StatefulPartitionedCall"][0]); var output = runner.Run(); var outputResults = output[0].GetValue() as float[][]; // 找到概率最高的分类 int topResultIndex = outputResults[0] .Select((probability, index) => (probability, index)) .OrderByDescending(item => item.probability) .First().index; return _categoryLabels[topResultIndex]; } public void Dispose() { _inferenceSession.Dispose(); _modelGraph.Dispose(); } } // 调用示例 class Program { static void Main(string[] args) { string modelDir = "./saved_model"; string labelsPath = "labels.txt"; string testImagePath = "your_test_image.jpg"; using var classifier = new SavedModelImageClassifier(modelDir, labelsPath); string classificationResult = classifier.ClassifySingleImage(testImagePath); Console.WriteLine($"识别结果:{classificationResult}"); } }
几个要注意的小细节
- 节点名称调整:SavedModel的输入输出节点名可能和示例里的不一样,你可以用TensorFlow的
saved_model_cli工具查看:saved_model_cli show --dir ./saved_model --all,找到对应的节点名替换代码里的即可。 - 图像预处理要求:Teachable Machine训练的模型一般要求输入是RGB格式,尺寸和你训练时设置的一致,像素值归一化到0-1(少数模型是-1到1,看你训练时的配置)。
- 依赖版本兼容:安装NuGet包时尽量选稳定版本,确保TensorFlow.NET和相关依赖的版本匹配,避免出现奇怪的报错。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

