ML.NET库学习009:花卉图像分类模型

发布于:2025-02-22 ⋅ 阅读:(15) ⋅ 点赞:(0)

ML.NET库学习009:花卉图像分类模型

进行图像分类训练的实现

功能分析

该C#程序使用Microsoft的ML.NET库来构建一个花卉图像分类模型。主要功能包括:

  1. 下载和加载数据集:从指定URL下载花卉图片数据集,并解压到本地目录。
  2. 训练模型:基于预训练的TensorFlow模型(如Inception v3),通过迁移学习训练新的分类器,以识别不同种类的花卉。
  3. 评估模型性能:在测试数据集上评估模型的准确性、精确度等指标。
  4. 保存模型:将训练好的模型保存为ML.NET和TensorFlow格式,以便后续使用。
  5. 单张图片预测:加载一张图片,使用训练好的模型进行预测,并输出结果。

代码结构

  1. 主函数(Main Method)

    • 下载数据集
    • 加载并预处理图像数据
    • 训练模型
    • 评估模型
    • 保存模型
    • 进行单张图片的预测测试
  2. 辅助方法

    • LoadImagesFromDirectory:从指定目录加载图像,并生成ImageData对象。
    • DownloadImageSet:下载并解压远程数据集文件。
    • EvaluateModel:评估模型在测试集上的性能。
    • TrySinglePrediction:使用训练好的模型对单张图片进行预测。

核心组件

  • 迁移学习:利用预训练的TensorFlow模型,通过微调来适应新的花卉分类任务。这可以减少训练时间,并提高模型性能。

  • 图像处理:加载、缩放和归一化处理图像数据,使其适合输入到深度学习模型中。

  • 模型评估:使用准确率、精确度、召回率等指标来衡量模型的性能。

示例输出

运行该程序后,控制台将显示以下内容:

  1. 训练时间:显示训练模型所用的时间。
  2. 评估结果:显示测试集上的分类准确率和其它相关指标。
  3. 单张图片预测:输出被预测图片的文件名、预测标签及其概率。

代码实现

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.ML.Core.Data;
using Microsoft.ML.Transforms.Image;
using Microsoft.ML.Models;

public class Program
{
    public static void Main(string[] args)
    {
        // 下载数据集并加载图像
        string imagesFolderPath = "images";
        DownloadImages(imagesFolderPath);
        
        // 加载训练和测试数据
        var data = LoadImageData(imagesFolderPath);
        
        // 划分训练集和测试集
        var splits = data.TrainTestSplit(0.7, shuffle: true);
        var trainData = splits.Train;
        var testData = splits.Test;
        
        // 定义模型管道
        IEstimator<ImageData, ImagePrediction> pipeline =
            new LearningPipeline(
                new ConvertImageToFloat(),
                new DenseVectorizer<ImageData>(),
                new StochasticGradientDescent<LogisticRegression>()
                    .SetMaximumNumberOfIterations(100)
            );
        
        // 训练模型
        var trainedModel = pipeline.Fit(trainData);
        
        // 评估模型性能
        Evaluate(trainedModel, testData);
        
        // 保存模型
        SaveModel(trainedModel, trainData.Schema, "trained-model.zip");
        
        // 单张图片预测示例
        TrySinglePrediction("test-images", trainedModel);
    }
    
    private static void DownloadImages(string folder)
    {
        var url = "https://example.com/flower-dataset.zip";
        DownloadFile(url, folder + "/dataset.zip");
        Unzip(folder + "/dataset.zip", folder);
    }
    
    private static List<ImageData> LoadImageData(string folder)
    {
        return Directory.GetFiles(folder)
            .Select(f => new ImageData {ImagePath = f})
            .ToList();
    }
    
    private static void Evaluate(IEstimator<ImageData, ImagePrediction> model, IDataView testData)
    {
        var prediction = model.Predict(testData);
        var accuracy = prediction.Accuracy();
        Console.WriteLine($"Accuracy: {accuracy}");
    }
    
    private static void SaveModel(IEstimator<ImageData, ImagePrediction> model, Schema<ImageData> schema, string filename)
    {
        // 实现模型保存逻辑
    }
    
    private static void TrySinglePrediction(string testFolder, IEstimator<ImageData, ImagePrediction> model)
    {
        var imagePaths = Directory.GetFiles(testFolder);
        foreach (var imagePath in imagePaths)
        {
            var prediction = model.Predict(new ImageData {ImagePath = imagePath});
            Console.WriteLine($"Image: {imagePath}, Prediction: {prediction.PredictedLabel}");
        }
    }
}

详细步骤说明

  1. 下载数据集

    • 使用DownloadImages方法从指定URL下载花卉图片数据集,并将其解压到本地目录。
  2. 加载和预处理图像

    • 使用LoadImageData方法将所有图像文件路径加载为ImageData对象列表,每个对象包含图像的路径信息。
  3. 训练模型

    • 构建一个机器学习管道,包括将图像转换为浮点数、将其向量化以及使用随机梯度下降优化逻辑回归模型。
    • 调用Fit方法在训练数据上训练模型。
  4. 评估模型性能

    • 使用测试数据集评估训练好的模型,并输出分类准确率等指标。
  5. 保存模型

    • 将训练好的模型保存为文件,以便后续使用。
  6. 单张图片预测

    • 加载一张测试图片,使用训练好的模型进行预测,并输出结果。

注意事项

  • 数据集路径:确保imagestest-images目录存在,并且包含正确的图像文件。
  • 依赖项管理:需要安装ML.NET库以及相关的NuGet包。
  • 性能优化:可以调整训练参数,如学习率、迭代次数等,以提高模型性能。

进行图像分类预测的实现

主要目的

本项目的目的是利用训练好的机器学习模型对输入的图像进行分类预测。具体来说,模型将根据输入的图片特征(如颜色、纹理等)输出图片所属的类别标签及其概率。

原理概述

  • 监督学习:使用预训练好的模型对新的数据进行预测。
  • 卷积神经网络 (CNN):通常用于图像分类任务,能够自动提取图像中的特征。
  • ML.NET:一个开源的机器学习框架,提供了丰富的功能来构建和部署机器学习模型。

实现的主要功能

  • 加载预训练好的 ML.NET 模型文件(.zip 格式)。
  • 使用模型对输入图像进行分类预测,并输出预测结果及其概率。
  • 测量单次和多次预测的时间,以评估模型的性能。

主要流程步骤

  1. 初始化 MLContext 对象。
  2. 加载预训练好的模型文件。
  3. 创建预测引擎(Prediction Engine),用于处理输入数据并生成预测结果。
  4. 读取输入目录中的所有图像文件,并将其转换为模型可接受的格式。
  5. 使用预测引擎对每张图片进行预测,输出结果。

使用的主要函数和方法

  • MLContext.Model.Load:加载预训练好的模型文件。
  • CreatePredictionEngine:创建预测引擎,用于处理输入数据并生成预测结果。
  • FileUtils.LoadInMemoryImagesFromDirectory:从指定目录读取所有图像文件,并将其转换为 InMemoryImageData 格式。

关键技术

  • 数据结构的设计(如 InMemoryImageDataImagePrediction)。
  • 模型加载和预测引擎的创建。
  • 图像数据预处理和结果解析。

功能详细解读

(1)模型加载与预测引擎创建
  • 使用 MLContext.Model.Load 方法加载 .zip 格式的模型文件。
  • 调用 CreatePredictionEngine 创建一个可以处理输入数据并输出预测结果的引擎。
(2)图像数据读取
  • 使用 FileUtils.LoadInMemoryImagesFromDirectory 从指定目录读取所有图像文件,并将它们转换为 InMemoryImageData 格式的对象。
  • 每个 InMemoryImageData 对象包含图片的字节数组、高度和宽度,以及图片文件名。
(3)单次预测与性能测量
  • 使用 predictionEngine.Predict 方法对单张图像进行预测,并记录预测时间。
  • 输出预测结果(类别标签及其概率)。
(4)批量预测
  • 对输入目录中的所有图像逐一进行预测,输出每张图片的预测结果。

实现步骤分步骤

// 初始化 MLContext
var mlContext = new MLContext(seed: 1);

// 加载模型
var loadedModel = mlContext.Model.Load(imageClassifierModelZipFilePath, out var modelInputSchema);

// 创建预测引擎
var predictionEngine = mlContext.Model.CreatePredictionEngine(modelInputSchema, loadedModel);

数据结构设计

  • InMemoryImageData:用于存储单张图像的数据,包括图片字节数组、高度、宽度和文件名。
public class InMemoryImageData
{
    public byte[] ImageBytes { get; set; }
    public int Height { get; set; }
    public int Width { get; set; }
    public string ImageFileName { get; set; }
}
  • ImagePrediction:用于存储模型输出的预测结果,包括类别标签和概率。
public class ImagePrediction
{
    public string PredictedLabel { get; set; }
    public float[] Score { get; set; }
}

关键技术

1. 数据结构与内容说明

  • InMemoryImageData:用于存储输入图片的原始数据和属性信息,方便模型处理。
  • ImagePrediction:用于存储模型输出的结果,包括预测类别标签及其概率。

2. 样本数据清洗方法

  • 在训练阶段,需要对图像进行预处理(如调整大小、归一化等)并按类别标签分组。
  • 使用 FileUtils.LoadInMemoryImagesFromDirectory 函数加载和转换图像数据。

3. 预测数据处理方法说明

  • 输入格式:预测阶段的图像数据需要以 InMemoryImageData 格式传递给模型。
  • 输出结果:模型返回一个 ImagePrediction 对象,包含类别标签及其概率。

示例代码

using Microsoft.ML;
using Microsoft.ML.Data;

public class InMemoryImageData
{
    public byte[] ImageBytes { get; set; }
    public int Height { get; set; }
    public int Width { get; set; }
    public string ImageFileName { get; set; }
}

public class ImagePrediction
{
    public string PredictedLabel { get; set; }
    public float[] Score { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var mlContext = new MLContext(seed: 1);

        // 加载模型文件路径
        string modelFilePath = @"path\to\model.zip";
        ITransformer loadedModel;
        var modelInputSchema = mlContext.Model.Load(modelFilePath, out loadedModel);

        // 创建预测引擎
        var predictionEngine = mlContext.Model.CreatePredictionEngine(modelInputSchema, loadedModel);

        // 加载输入图片目录
        string inputImagePath = @"path\to\input_images";
        var images = FileUtils.LoadInMemoryImagesFromDirectory(inputImagePath).ToList();

        foreach (var image in images)
        {
            var prediction = predictionEngine.Predict(image);
            Console.WriteLine($"Image: {image.ImageFileName}, Predicted Label: {prediction.PredictedLabel}, Probability: {prediction.Score.Max()}");
        }
    }
}

通过以上分析和实现,我们能够高效地利用 ML.NET 进行图像分类预测,并进一步优化模型性能以满足实际需求。


分步解释

  1. 加载并转换数据

    IDataView shuffledFullImagesDataset = mlContext.Transforms.Conversion.
        MapValueToKey(outputColumnName: "LabelAsKey", inputColumnName: "Label", keyOrdinality: KeyOrdinality.ByValue)
        .Append(mlContext.Transforms.LoadRawImageBytes(
            outputColumnName: "Image",
            imageFolder: fullImagesetFolderPath,
            inputColumnName: "ImagePath"))
        .Fit(shuffledFullImageFilePathsDataset)
        .Transform(shuffledFullImageFilePathsDataset);
    
MapValueToKey 函数
  • 作用:将字符串类型的标签(如“猫”、“狗”等)转换为整数类型的键。这是因为大多数机器学习算法更擅长处理数值类型的数据。
  • 参数
    • 输出列名: 新生成的列名,通常是 “LabelAsKey”。
    • 输入列名: 原始标签所在的列名,如 “Label”。
    • 键序数性: 指定如何为不同的类别分配数值。KeyOrdinality.ByName 表示根据类别名称的字典顺序来排序。
LoadRawImageBytes 函数
  • 作用:从指定的文件夹中加载图像,并将它们转换为适合机器学习模型处理的数据格式(通常是二维数组或张量)。
  • 参数
    • 输出列名: 存储图像数据的新列名,如 “Image”。
    • 图像文件夹: 包含训练图像的文件夹路径,例如 fullImagesetFolderPath
    • 输入列名: 包含图像文件路径的列名,如 “ImagePath”。
.Fit().Transform() 方法
  • 作用.Fit() 用于训练数据转换器,使其能够将原始数据转换为模型所需的格式。.Transform() 则应用已训练好的转换器到实际数据上。
  • 过程
    • 首先调用 .Fit(已打乱的全图像文件路径数据集),让转换器了解如何处理输入数据。
    • 然后调用 .Transform(已打乱的全图像文件路径数据集),将原始数据转换为目标格式,并存储在 shuffledFullImagesDataset 中。
  1. 划分训练集和测试集

    var trainTestData = mlContext.Data.TrainTestSplit(shuffledFullImagesDataset, testFraction: 0.2);
    IDataView trainDataView = trainTestData.TrainSet;
    IDataView testDataView = trainTestData.TestSet;
    
    • TrainTestSplit:将数据集按80%训练和20%测试的比例划分为两部分。
    • trainDataViewtestDataView:分别表示训练集和测试集的数据视图,用于后续模型训练和评估。
  2. 定义机器学习管道

var pipeline = mlContext.MulticlassClassification.Trainers
        .ImageClassification(featureColumnName: "Image",
                             labelColumnName: "LabelAsKey",
                            validationSet:testDataView) 
                          .Append(mlContext.Transforms.Conversion.MapKeyToValue(outputColumnName:"PredictedLabel", inputColumnName: "PredictedLabel"));
  • MapValueToKey:再次将标签列转换为键,确保模型训练时能够正确处理标签。
  • LoadRawImageBytes:加载图像数据到特征列"Image"中。
  • ImageClassification:定义一个图像分类器,使用转移学习在预训练模型上进行微调。
  • MapKeyToValue:将预测结果从键转换回原始标签值,输出列为"PredictedLabel"。
ImageClassification 函数
  • 作用:初始化一个图像分类器,通常基于深度神经网络(DNN),用于处理多类分类任务。
  • 参数
    • 特征列名: 输入数据中存储图像特征的列名,如 “Image”。
    • 标签列名: 存储类别标签的列名,如 “LabelAsKey”。
    • 验证集: 提供一个独立的数据子集用于模型评估和调优。
MapKeyToValue 函数
  • 作用:将模型预测的结果从数值形式(键)转换回原始的文本形式(值),以便于人类理解。
  • 参数
    • 输出列名: 存储转换后结果的列名,如 “PredictedLabel”。
    • 输入列名: 模型输出的数值结果所在的列名。
  1. 训练模型

    Console.WriteLine("*** Training the image classification model with DNN Transfer Learning on top of the selected pre-trained model/architecture ***");
    
    var watch = Stopwatch.StartNew();
    
    ITransformer trainedModel = pipeline.Fit(trainDataView);
    
    watch.Stop();
    Console.WriteLine($"Training completed in {watch.Elapsed.TotalSeconds} seconds.");
    
    • Fit:使用训练集数据对管道进行拟合,生成一个训练好的模型转换器trainedModel
    • 计时器:记录模型的训练时间,输出到控制台。

通过以上步骤,完整的图像分类模型训练流程得以实现。首先,数据经过预处理和转换以适应机器学习的要求;然后,数据被划分为训练集和测试集;接着,定义并配置了包含特征提取、模型训练和结果转译的管道;最后,使用训练数据拟合模型,并输出训练所需的时间。这一流程确保了模型能够有效地从数据中学习,并为后续的预测任务做好准备。

什么是 Shuffle 清洗操作?

在数据预处理和机器学习任务中,“Shuffle” 是一种常见的操作,主要用于随机打乱数据集的顺序。这种操作有助于确保模型在训练过程中不会因为数据的排列方式而引入不必要的偏倚,从而提高模型的泛化能力。


为什么需要 Shuffle?

  1. 防止顺序偏差

    • 在某些情况下,数据可能是按某种特定顺序排列的(例如时间序列数据),直接使用这种顺序进行训练可能导致模型记住这种顺序而不是学习数据本身的模式。
  2. 确保随机性

    • 打乱数据顺序可以增加训练过程中的随机性,使得模型在不同批次中看到的数据更加多样化,有助于避免过拟合。
  3. 提升模型泛化能力

    • 通过 Shuffle,模型不会因为特定的排列方式而记住某些模式,从而更有效地学习到数据的整体特征。

在 Python 中使用 random.shuffle()

import random

# 示例数据集
data = [1, 2, 3, 4, 5]

# 打乱数据顺序
random.shuffle(data)

print("打乱后的数据:", data)

在机器学习框架中:

  • Scikit-learn

    • 使用 train_test_split 函数时,可以通过设置 shuffle=True 来实现 Shuffle。
    from sklearn.model_selection import train_test_split
    
    # 示例数据集
    X = ...
    y = ...
    
    # 分割数据并打乱顺序
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=True)
    
  • TensorFlow/Keras

    • 在训练模型时,可以通过设置 shuffle=True 来启用 Shuffle。
    model.fit(X_train, y_train, epochs=10, batch_size=32, shuffle=True)
    

Shuffle 的注意事项

  1. 确保数据完整

    • Shuffle 应该在训练集、验证集和测试集之间分别进行,避免污染测试数据。
  2. 保持分组完整性(可选)

    • 如果某些情况下需要保持特定的分组关系(例如时间序列数据),则不应打乱顺序。此时需要谨慎使用 Shuffle。
  3. 随机种子(Optional)

    • 为了复现实验结果,可以在 Shuffle 时设置一个固定的随机种子。
    random.seed(42)
    random.shuffle(data)
    

Shuffle 是一种重要的数据清洗操作,主要用于随机打乱数据集的顺序,以避免模型因数据排列方式而引入偏差,并提升其泛化能力。在实际应用中,合理使用 Shuffle 可以显著改善模型性能。

总结

这个程序展示了如何使用ML.NET进行花卉图像分类。