一, 概述
这次要解决的问题是输入一张照片, 输出人物的颜值数据.
学习样本来源于华南理工大学发布的 SCUT-FBP5500 数据集, 数据集包括 5500 人, 每人按颜值魅力打分, 分值在 1 到 5 分之间. 其中包括男性, 女性, 中国人, 外国人四个分类.
SCUT-FBP5500_full.CSV 文件标记了每个图片人物的颜值打分数据.(我把分值一项乘以了 20, 变成了满分 100 分, 不影响计算结果)
整个程序处理流程和前一篇图片分类的基本一致, 唯一的区别, 分类用的是多元分类算法, 这次采用的是回归算法.
二, 源码
下面是全部代码:
- namespace TensorFlow_ImageClassification
- {
- class Program
- {
- //Assets files download from:https://gitee.com/seabluescn/ML_Assets
- static readonly string AssetsFolder = @"D:\StepByStep\Blogs\ML_Assets";
- static readonly string TrainDataFolder = Path.Combine(AssetsFolder, "FaceValueDetection", "SCUT-FBP5500");
- static readonly string TrainTagsPath = Path.Combine(AssetsFolder, "FaceValueDetection", "SCUT-FBP5500_asia_full.csv");
- static readonly string TestDataFolder = Path.Combine(AssetsFolder, "FaceValueDetection", "testimages");
- static readonly string inceptionPb = Path.Combine(AssetsFolder, "TensorFlow", "tensorflow_inception_graph.pb");
- static readonly string imageClassifierZip = Path.Combine(Environment.CurrentDirectory, "MLModel", "imageClassifier.zip");
- // 配置用常量
- private struct ImageNetSettings
- {
- public const int imageHeight = 224;
- public const int imageWidth = 224;
- public const float mean = 117;
- public const float scale = 1;
- public const bool channelsLast = true;
- }
- static void Main(string[] args)
- {
- TrainAndSaveModel();
- LoadAndPrediction();
- Console.WriteLine("Hit any key to finish the app");
- Console.ReadKey();
- }
- public static void TrainAndSaveModel()
- {
- MLContext mlContext = new MLContext(seed: 1);
- // STEP 1: 准备数据
- var fulldata = mlContext.Data.LoadFromTextFile<ImageNetData>(path: TrainTagsPath, separatorChar: ',', hasHeader: true);
- var trainTestData = mlContext.Data.TrainTestSplit(fulldata, testFraction: 0.2);
- var trainData = trainTestData.TrainSet;
- var testData = trainTestData.TestSet;
- // STEP 2: 创建学习管道
- var pipeline = mlContext.Transforms.LoadImages(outputColumnName: "input", imageFolder: TrainDataFolder, inputColumnName: nameof(ImageNetData.ImagePath))
- .Append(mlContext.Transforms.ResizeImages(outputColumnName: "input", imageWidth: ImageNetSettings.imageWidth, imageHeight: ImageNetSettings.imageHeight, inputColumnName: "input"))
- .Append(mlContext.Transforms.ExtractPixels(outputColumnName: "input", interleavePixelColors: ImageNetSettings.channelsLast, offsetImage: ImageNetSettings.mean))
- .Append(mlContext.Model.LoadTensorFlowModel(inceptionPb).
- ScoreTensorFlowModel(outputColumnNames: new[] { "softmax2_pre_activation" }, inputColumnNames: new[] { "input" }, addBatchDimensionInput: true))
- .Append(mlContext.Regression.Trainers.LbfgsPoissonRegression(labelColumnName: "Label", featureColumnName: "softmax2_pre_activation"));
- // STEP 3: 通过训练数据调整模型
- ITransformer model = pipeline.Fit(trainData);
- // STEP 4: 评估模型
- var predictions = model.Transform(testData);
- var metrics = mlContext.Regression.Evaluate(predictions, labelColumnName: "Label", scoreColumnName: "Score");
- PrintRegressionMetrics( metrics);
- //STEP 5: 保存模型
- Console.WriteLine("====== Save model to local file =========");
- mlContext.Model.Save(model, trainData.Schema, imageClassifierZip);
- }
- static void LoadAndPrediction()
- {
- MLContext mlContext = new MLContext(seed: 1);
- // Load the model
- ITransformer loadedModel = mlContext.Model.Load(imageClassifierZip, out var modelInputSchema);
- // Make prediction function (input = ImageNetData, output = ImageNetPrediction)
- var predictor = mlContext.Model.CreatePredictionEngine<ImageNetData, ImageNetPrediction>(loadedModel);
- DirectoryInfo testdir = new DirectoryInfo(TestDataFolder);
- foreach (var jpgfile in testdir.GetFiles("*.jpg"))
- {
- ImageNetData image = new ImageNetData();
- image.ImagePath = jpgfile.FullName;
- var pred = predictor.Predict(image);
- Console.WriteLine($"Filename:{jpgfile.Name}:\tPredict Result:{pred.FaceValue}");
- }
- }
- }
- public class ImageNetData
- {
- [LoadColumn(0)]
- public string ImagePath;
- [LoadColumn(1)]
- public float Label;
- }
- public class ImageNetPrediction
- {
- [ColumnName("Score")]
- public float FaceValue;
- }
- }
- View Code
三, 分析
1, 数据处理通道
- // STEP 2: 创建学习管道
- var pipeline = mlContext.Transforms.LoadImages(...)
- .Append(mlContext.Transforms.ResizeImages(...)
- .Append(mlContext.Transforms.ExtractPixels(...)
- .Append(mlContext.Model.LoadTensorFlowModel(inceptionPb)
- .ScoreTensorFlowModel(outputColumnNames: new[] { "softmax2_pre_activation" }, inputColumnNames: new[] { "input" }, addBatchDimensionInput: true))
- .Append(mlContext.Regression.Trainers.LbfgsPoissonRegression(labelColumnName: "Label", featureColumnName: "softmax2_pre_activation"));
LoadImages,ResizeImages,ExtractPixels: 上篇文章都已经介绍过了;
ScoreTensorFlowModel 方法把图片像素值转换为图片特征数据, 并存储在 softmax2_pre_activation 列, Label 列保存的是颜值数据, 通过回归算法形成模型, 当输入新的特征数据时就可以得出对应的颜值数据.
算法采用的是: L-BFGS Poisson Regression (拟牛顿法泊松回归)
2, 预测结果
在网上找了一些大头照, 通过程序进行预测, 右侧是预测结果:
预测结果虽然和我认为的不完全一致, 但总体上可以接受, 大方向没什么问题, 存在偏差主要有以下几个因素:
1, 学习样本的客观性存疑, 其打分数据可能是分配给多人打分后汇总的, 每个人标准不一致;
2, 被检测图片不是很规范, 如尺寸, 比例, 背景等;
3, 颜值本身就不具备客观性, 不存在标准答案, 如果我说林心如比如花漂亮, 大家肯定都同意, 但我如果说古力娜扎比迪丽热巴漂亮, 肯定有人不赞成.
四, 资源获取
源码下载地址: https://github.com/seabluescn/Study_ML.NET
工程名称: TensorFlow_FaceValueDetection
资源获取: https://gitee.com/seabluescn/ML_Assets (SCUT-FBP5500)
点击查看机器学习框架 ML.NET 学习笔记系列文章目录
来源: https://www.cnblogs.com/seabluescn/p/10947650.html