機器學習框架ML.NET學習筆記【7】人物圖片顏值判斷

1、概述html

 此次要解決的問題是輸入一張照片,輸出人物的顏值數據。git

學習樣原本源於華南理工大學發佈的SCUT-FBP5500數據集,數據集包括 5500 人,每人按顏值魅力打分,分值在 1 到 5 分之間。其中包括男性、女性、中國人、外國人四個分類。github

 

SCUT-FBP5500_full.csv文件標記了每一個圖片人物的顏值打分數據。(我把分值一項乘以了20,變成了滿分100分,不影響計算結果)算法

整個程序處理流程和前一篇圖片分類的基本一致,惟一的區別,分類用的是多元分類算法,此次採用的是迴歸算法。app

 

2、源碼框架

 下面是所有代碼:機器學習

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

  

3、分析ide

一、數據處理通道學習

// 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:上篇文章都已經介紹過了;lua

ScoreTensorFlowModel方法把圖片像素值轉換爲圖片特徵數據,並存儲在softmax2_pre_activation列,Label列保存的是顏值數據,經過迴歸算法造成模型,當輸入新的特徵數據時就能夠得出對應的顏值數據。

算法採用的是:L-BFGS Poisson Regression (擬牛頓法泊松迴歸)

 

二、預測結果

 在網上找了一些大頭照,經過程序進行預測,右側是預測結果:

 

 

預測結果雖然和我認爲的不徹底一致,但整體上能夠接受,大方向沒什麼問題,存在誤差主要有如下幾個因素:

一、學習樣本的客觀性存疑,其打分數據多是分配給多人打分後彙總的,每一個人標準不一致;

二、被檢測圖片不是很規範,如尺寸、比例、背景、使用美顏軟件等;

三、顏值自己就不具有客觀性,不存在標準答案,若是我說林心如好比花漂亮,你們確定都贊成,但我若是說古力娜扎比迪麗熱巴漂亮,確定有人不同意。

 

4、資源獲取 

源碼下載地址:https://github.com/seabluescn/Study_ML.NET

工程名稱:TensorFlow_FaceValueDetection

資源獲取:https://gitee.com/seabluescn/ML_Assets (SCUT-FBP5500)

點擊查看機器學習框架ML.NET學習筆記系列文章目錄

相關文章
相關標籤/搜索