Yükleniyor

ML.NET ile Görsel Sınıflandırma: .NET 10 ile Uçtan Uca Web API Geliştirme

Blog Kategorileri

.Net Core Mimariler
Tasarım Desenleri
ORM Araçları
API Geliştirme
Web Geliştirme
Veritabanları
19 Şubat 2026 Perşembe
ML.NET ile Görsel Sınıflandırma: .NET 10 ile Uçtan Uca Web API Geliştirme

Merhaba,

Günümüzde görseller, güvenlikten perakendeye, sağlıktan üretime kadar birçok alanda kritik bir veri kaynağı haline geldi. Ancak binlerce resmi manuel olarak inceleyip içindeki nesneleri tespit etmek zaman bir süreç olabilir. İşte burada makine öğrenmesi devreye giriyor: Görüntü verilerini otomatik olarak analiz ederek, bir resimde hangi nesnelerin bulunduğunu hızlıca sınıflandırabiliyoruz. Bu yazıda, ML.NET kullanarak bir Web API üzerinden görsellerdeki nesneleri tanıyan basit bir model geliştireceğiz ve adım adım nasıl çalıştığını göstereceğim.

ML.NET Nedir?

ML.NET, .NET geliştiricileri için tasarlanmış açık kaynaklı ve platformlar arası bir makine öğrenmesi çerçevesidir. Bu araç sayesinde veri hazırlama, model eğitimi ve tahminleme süreçlerinin tamamı doğrudan C# veya F# kullanılarak .NET ekosistemi içerisinde gerçekleştirilebilir. Harici bir dil veya çalışma ortamına ihtiyaç duymadan, makine öğrenmesi modellerini mevcut uygulamalara entegre etme imkanı tanır.

Görsel sınıflandırma senaryolarında ML.NET; resimlerin yüklenmesi, ön işlenmesi, özellik çıkarımı ve eğitilmiş bir model aracılığıyla nesne tahmini yapılmasını sağlar. Böylece görüntü işleme ve makine öğrenmesi süreçleri tek bir .NET uygulaması içinde yönetilebilir.

Neden Makine Öğrenmesi?

Bir güvenlik sisteminde yüzlerce kamera görüntüsü olduğunu düşünün. Bu görüntülerde insan, araç veya belirli nesneleri manuel olarak tespit etmek hem zaman alıcı hem de ölçeklenemez bir iş olur. Makine öğrenmesi sayesinde modelimizi eğitip, yeni gelen görselleri otomatik olarak analiz edebiliriz. Böylece bir resimde insan, araba, kedi veya başka bir nesne olup olmadığını hızlıca sınıflandırmak mümkün hâle gelir.

Bu yaklaşım, büyük miktarda görsel veriyi otomatik olarak işleyerek hata riskini azaltır ve gerçek zamanlı analiz imkânı sunar. Aynı zamanda uygulamalara akıllı karar mekanizmaları kazandırır. Özellikle e-ticaret, güvenlik, sağlık ve üretim gibi alanlarda görsel sınıflandırma, iş süreçlerini ciddi ölçüde hızlandırır ve verimliliği artırır.

Problem Tanımı ve Veri Seti

Bu projede, görsel sınıflandırma yani resimden obje tanıma problemi ele alınmaktadır. Amaç, modele verilen bir görselin hangi nesne sınıfına ait olduğunu otomatik olarak tahmin etmektir; örneğin kedi, köpek veya araba gibi. Data klasörü altında ilgili görseller bulunmalıdır ve model, klasör isimlerini sınıf etiketi olarak kabul edecek şekilde yapılandırılır. Yani her klasör bir nesne sınıfını temsil eder. Veri setimiz aşağıdaki gibi bir klasör yapısına sahip:

Data/
│
├── kedi/
│   ├── kedi1.jpg
│   ├── kedi2.jpg
│   └── kedi3.jpg
│
├── kopek/
│   ├── kopek1.jpg
│   ├── kopek2.jpg
│   └── kopek3.jpg
│
└── araba/
    ├── araba1.jpg
    ├── araba2.jpg
    └── araba3.jpg

Bu yapıda, kedi klasöründeki tüm görseller kedi etiketiyle, köpek klasöründeki görseller kopek etiketiyle ve araba klasöründeki görseller ise araba etiketiyle eşleştirilir. Model eğitimi sırasında sistem, Data klasörünü tarar, alt klasör isimlerini sınıf etiketi olarak alır ve her görseli ilgili klasör adına göre etiketleyerek öğrenme sürecini gerçekleştirir.

Not olarak belirtmek gerekir ki bu veri seti oldukça küçük ve yalnızca deneme amaçlıdır. Modelimizi eğitmek ve temel kavramları göstermek için yeterli olsa da, gerçek dünyadaki görsel sınıflandırma problemlerinde yüksek doğruluk ve güvenilirlik elde edebilmek için çok daha büyük ve çeşitli bir veri setine ihtiyaç vardır. Farklı ışık koşulları, açılar, arka planlar ve çözünürlüklerde toplanmış veriler, modelin genelleme yeteneğini önemli ölçüde artıracaktır.

Bu projeyi, 3 katmanlı bir mimari kullanarak ve .NET 10 üzerinde geliştireceğiz. Henüz kod yazmaya başlamadan önce, proje yapısını doğru bir şekilde oluşturmak önem taşıyor. Öncelikle, bir boş Solution oluşturuyoruz ve adını ImageClassification koyuyoruz. Bu Solution, projenin temelini oluşturacak ve katmanlı mimarimizin her bir katmanını düzenli bir şekilde yönetmemize olanak sağlayacak.

Shared Katmanı

Solution içerisine bir Class Library ekleyerek ImageClassification.Shared adını veriyoruz. Bu katman, proje genelinde ortak olarak kullanılacak sınıfları ve yapıları barındıracak. Model eğitimi sırasında ihtiyaç duyacağımız veri yapısını temsil edecek bir input sınıfına ihtiyacımız var. Bu nedenle Models klasörü altında ModelInput sınıfımızı oluşturuyoruz. Bu sınıf, hem eğitim hem de tahmin süreçlerinde kullanılacak temel özellikleri içeriyor:

namespace ImageClassification.Shared.Models
{
    public class ModelInput
    {
        public byte[] Image { get; set; }
        public string Label { get; set; }
        public string ImagePath { get; set; }
    }
}

Alanların Açıklaması

Image: Görselin byte dizisi  Model eğitimi ve tahmin sırasında doğrudan işlenecek olan piksel verisini temsil eder.

Label: Görselin ait olduğu sınıf bilgisidir. Eğitim aşamasında model bu etiketi öğrenir. Örneğin: kedi, köpek, araba.

ImagePath: Görsel dosyasının sistem üzerindeki yolunu tutar. 

ModelStorageConfig

Eğitilen modeli merkezi bir konumda saklamak için, ImageClassification.Shared projesi içerisinde Settings klasörü altında ModelStorageConfig sınıfını oluşturuyoruz.

namespace ImageClassification.Shared.Settings
{
    public static class ModelStorageConfig
    {
        public const string ModelDirectory = @"C:\MLModels\image-classification";
    }
}

Bu sınıf, eğitilmiş modelin saklanacağı dizin yolunu merkezi olarak tutar. Shared class library içerisinde yer aldığı için, Train projesi modeli .zip formatında bu klasöre kaydederken, Predict projesi aynı yolu kullanarak modeli yükler ve tahmin işlemini gerçekleştirir. Böylece model yolu tek bir noktadan yönetilmiş olur ve iki proje arasında tutarlılık sağlanır.

Not olarak belirtmek gerekir ki burada basit bir local file storage kullanıyoruz. Ancak canlı ortamlar için bu yöntem önerilmez. Gerçek projelerde model dosyaları genellikle cloud storage (örneğin Azure Blob Storage veya AWS S3) üzerinden yönetilerek daha güvenli ve ölçeklenebilir bir yapı sağlanabilir.

Kurulması Gereken Paketler

Bu projeye aşağıdaki NuGet paketlerini ekliyoruz:

  1. Microsoft.ML
  2. Microsoft.ML.Vision
  3. SciSharp.TensorFlow.Redist

Bu paketler görsel sınıflandırma ve ML.NET Vision altyapısı için gereklidir.

Neden SciSharp.TensorFlow.Redist Ekledik?

ML.NET, görsel sınıflandırma işlemini gerçekleştirmek için arka planda TensorFlow motorunu kullanır. Bu paket, TensorFlow'un kütüphanelerini .NET projenize dahil ederek; bilgisayarınıza harici bir TensorFlow kurulumu yapmanıza gerek kalmadan derin öğrenme modellerini (MobilenetV2 gibi) çalıştırmanıza olanak tanır. Kısacası, modelin eğitilmesi ve tahminde bulunması için gereken matematiksel motoru sisteme yükler.

Model Eğitim Katmanı

Solution içerisine bir Console App ekleyerek adını ImageClassification.ML.Trainer koyuyoruz. Bu projeye ayrıca ImageClassification.Shared referansını eklememiz gerekiyor. Böylece Shared katmanında tanımladığımız ModelInput ve ModelStorageConfig sınıflarını Trainer projesinde tekrar tanımlamaya gerek kalmadan kullanabiliriz; bu sayede kod tekrarından kaçınmış oluruz.

Referans ekleme işleminden sonra, Trainer projesi içerisinde aşağıdaki klasör yapısını oluşturuyoruz:

ImageClassification.ML.Trainer
│
└── Services
    → Eğitim ve pipeline işlemlerini yönetecek servisler

Services klasörü, modelin eğitim sürecini ve veri pipeline işlemlerini yönetecek sınıfları barındıracak. Bu yapı, projenin düzenli kalmasını sağlar ve sorumlulukları net bir şekilde ayırmamıza yardımcı olur.

TrainingService Sınıfı

using ImageClassification.Shared.Models;
using ImageClassification.Shared.Settings;
using Microsoft.ML;
using Microsoft.ML.Vision;

namespace ImageClassification.ML.Trainer.Services
{
    public class TrainingService
    {
        public void TrainModel(string path)
        {
            try
            {
                var mlContext = new MLContext();

                if (!Directory.Exists(path))
                {
                    Console.WriteLine("Verilen klasör bulunamadı.");
                    return;
                }

                var data = LoadDataFromFreeText(mlContext, path);

                var pipeline = mlContext.Transforms.Conversion.MapValueToKey("LabelAsKey", "Label")
                .Append(mlContext.MulticlassClassification.Trainers.ImageClassification(new ImageClassificationTrainer.Options
                {
                    FeatureColumnName = "Image",
                    LabelColumnName = "LabelAsKey",
                    Arch = ImageClassificationTrainer.Architecture.MobilenetV2,
                }))
                .Append(mlContext.Transforms.Conversion
               .MapKeyToValue(
                   outputColumnName: "PredictedLabel",
                   inputColumnName: "PredictedLabel"));

                var model = pipeline.Fit(data);
                string outputPath = ModelStorageConfig.ModelDirectory;
                mlContext.Model.Save(model, data.Schema, Path.Combine(outputPath, "model.zip"));
                Console.WriteLine("Eğitim tamamlandı zip dosyası hazırlandı..");
            }
            catch (Exception)
            {
                Console.WriteLine("Eğitim aşamasında bir hata oluştu.");
            }
        }
        private IDataView LoadDataFromFreeText(MLContext mlContext, string folderPath)
        {
            var images = new List<ModelInput>();

            var directories = Directory.GetDirectories(folderPath);

            foreach (var directory in directories)
            {
                var label = Path.GetFileName(directory);

                var files = Directory.GetFiles(directory, "*.*").Where(file => file.EndsWith(".jpg") || file.EndsWith(".png") || file.EndsWith(".jpeg"));

                foreach (var file in files)
                {
                    images.Add(new ModelInput
                    {
                        ImagePath = file,
                        Label = label,
                        Image = File.ReadAllBytes(file)
                    });
                }
            }

            return mlContext.Data.LoadFromEnumerable(images);
        }
    }
}

Services klasörü içerisine TrainingService sınıfını oluşturuyoruz. Bu sınıf, görsel sınıflandırma modelinin eğitiminden ve eğitilen modelin diske kaydedilmesinden sorumludur. Temel amacı, belirli bir klasör yapısındaki görselleri okuyarak ML.NET üzerinden bir görüntü sınıflandırma modeli oluşturmak ve sonucu .zip formatında saklamaktır.

Eğitim süreci, TrainModel(string path) metodu ile başlar. Buradaki path parametresi, eğitim verilerinin bulunduğu klasör yolunu temsil eder ve bu değer kullanıcıdan alınır. Yani uygulama çalıştırıldığında kullanıcıdan Data klasörünün konumu istenir ve bu yol TrainModel metoduna parametre olarak gönderilir. Böylece eğitim verisinin konumu dinamik hâle gelir ve kod içerisinde sabit bir veri yolu tanımlamak gerekmez.

Metot içerisinde ilk olarak bir MLContext nesnesi oluşturulur. ML.NET içerisindeki tüm makine öğrenmesi işlemleri bu context üzerinden yürütülür. Ardından klasörün varlığı kontrol edilir; eğer klasör bulunamazsa eğitim güvenli bir şekilde durdurulur ve kullanıcı bilgilendirilir.

Klasör doğrulandıktan sonra sistem, belirtilen dizin içerisindeki tüm alt klasörleri tarar. Her alt klasör bir sınıfı (label) temsil eder. Örneğin kedi, kopek veya araba gibi klasör isimleri doğrudan modelin öğreneceği etiketler olarak kullanılır. Her görsel dosyası okunur, byte dizisine dönüştürülür ve ModelInput nesnesine aktarılır. Böylece tüm veri, ML.NET’in çalışabileceği IDataView formatına dönüştürülmüş olur.

Veri hazırlandıktan sonra eğitim pipeline’ı oluşturulur. İlk aşamada string tipindeki etiketler sayısal anahtarlara (key) dönüştürülür çünkü makine öğrenmesi algoritmaları metinsel verilerle değil sayısal temsillerle çalışır. Ardından ImageClassificationTrainer kullanılarak model eğitimi gerçekleştirilir. Bu projede MobilenetV2 mimarisi tercih edilmiştir. Bu mimari, transfer learning yaklaşımıyla çalışır; yani daha önce büyük veri setleri üzerinde eğitilmiş bir model, bizim veri setimize uyarlanarak yeniden eğitilir. Bu yöntem, küçük veri setleriyle daha verimli sonuç elde edilmesini sağlar. Son aşamada modelin ürettiği sayısal tahminler tekrar string etiketlere dönüştürülür.

Pipeline oluşturulduktan sonra Fit metodu çağrılarak model eğitilir. Eğitim tamamlandığında ortaya çıkan model, ModelStorageConfig içerisinde tanımlanan merkezi dizine model.zip olarak kaydedilir. 

Console App ile Eğitim Başlatma

ImageClassification.ML.Trainer Console uygulaması çalıştırıldığında, kullanıcıdan veri setinin yolu istenir. Kullanıcı yol bilgisini girdikten sonra bu değer, TrainModel metoduna parametre olarak iletilir. Eğer kullanıcı herhangi bir yol girmezse, uygulama uyarı verir ve eğitim süreci başlamaz.

Kullanıcı geçerli bir yol girdiğinde, TrainingService sınıfı devreye girer ve daha önce tanımladığımız pipeline ile model eğitimi başlatılır. Eğitim sırasında veri klasörü taranır, her alt klasör bir sınıf etiketi olarak kullanılır ve görseller üzerinden model öğrenme işlemi gerçekleştirilir.

Eğer eğitim sırasında herhangi bir hata oluşmazsa, ortaya çıkan model .zip formatında, ModelStorageConfig içerisinde tanımlanan merkezi dizine kaydedilir. 

using ImageClassification.ML.Trainer.Services;

var service = new TrainingService();
Console.Write("Eğitim İçin Lütfen Veri Setinin Yolunu Yapıştırın: ");
string path = Console.ReadLine();
if (string.IsNullOrEmpty(path))
{
    Console.WriteLine("Lütfen veri setinin yolunu yapıştırın.");
    return;
}
service.TrainModel(path);

Tahmin Katmanı (Web API)

Eğitilen modelin tahminler yapabilmesi için Solution’a bir Web API projesi ekliyoruz:

Proje Adı: ImageClassification.ML.Predict

Bu projeye mutlaka ImageClassification.Shared referansını eklememiz gerekiyor. Böylece model sınıfları ve merkezi ayarlar (ModelStorageConfig, ModelInput vb.) tekrar tanımlanmadan kullanılabilir, kod tekrarından kaçınılır.

Gerekli Paket

Web API içerisinde eğitilmiş modeli dependency injection (DI) ile kullanabilmek için Microsoft.Extensions.ML paketini projeye ekliyoruz. Bu paket, ML.NET modellerini servis olarak uygulamaya eklemeyi kolaylaştırır. Böylece model yüklenir yüklenmez Web API’nin controller’ları üzerinden hızlı ve güvenli bir şekilde tahmin yapılabilir.

Test Araçları (Opsiyonel)

Web API’nin geliştirme ve test süreçlerini kolaylaştırmak için aşağıdaki araçlar kullanılabilir:

  1. Swagger 

  2. Postman

Bu araçlar sayesinde Web API’nin doğru çalıştığından emin olabilir ve tahmin sonuçlarını hızlıca kontrol edebilirsiniz.

BaseResult Pattern Kullanımı

API yanıtlarının tutarlı ve yönetilebilir olmasını sağlamak için BaseResult pattern kullandım. Bu yapı, Web API’nin tüm endpointlerinden dönen sonuçları standart bir formata oturtur ve hem başarı hem de hata durumlarını yönetmeyi kolaylaştırır.

Örnek olarak BaseResult sınıfı şu şekilde tanımlanmıştır:

using System.Text.Json.Serialization;

namespace ImageClassification.ML.Predict.Base
{
    public class BaseResult<T>
    {
        public T? Payload { get; set; }
        public List<Error>? Errors { get; set; }

        [JsonIgnore]
        public bool IsSuccess => Errors == null || !Errors.Any();

        [JsonIgnore]
        public bool IsFailure => !IsSuccess;

        public static BaseResult<T> Success(T payload)
        {
            return new BaseResult<T> { Payload = payload };
        }
        public static BaseResult<T> Fail(string errorMessage = "Beklenmeyen bir hata oluştu")
        {
            return new BaseResult<T>
            {
                Errors = [new Error { ErrorMessage = errorMessage }]
            };
        }
    }
    public class Error
    {
        public string ErrorMessage { get; set; }
    }
}

Modellerin oluşturulması

Eğitim aşamasında oluşturulan modelin tahmin sonuçlarını taşımak ve API üzerinden düzgün şekilde sunmak için iki temel sınıf tanımlayalım: ModelOutput ve PredictionResult.

using Microsoft.ML.Data;

namespace ImageClassification.ML.Predict.Models
{
    public class ModelOutput
    {
        [ColumnName("PredictedLabel")]
        public string Prediction { get; set; }

        public float[] Score { get; set; }
    }
}
namespace ImageClassification.ML.Predict.Models
{
    public class PredictionResult
    {
        public string Prediction { get; set; }
        public float Score { get; set; }
    }
}

ModelOutput

ML.NET tarafından modelin tahmin sonuçlarını döndürmek için kullanılır.

Prediction: [ColumnName("PredictedLabel")] attribute’u ile işaretlenmiştir. Bu, modelin ürettiği ana tahmin etiketini (örneğin kedi, kopek, araba) temsil eder.

Score: Modelin her sınıf için ürettiği olasılık değerlerini içeren bir float dizisidir. Örneğin bir görselin üç sınıf için olasılıkları [0.1, 0.7, 0.2] şeklinde olabilir. Bu sayede sadece tahmin edilen sınıf değil, modelin güven seviyesi de elde edilir.

PredictionResult

PredictionResult sınıfı ise API kullanıcılarına döndürülecek daha okunabilir bir sonuç formatı sağlar:

Prediction: Tahmin edilen sınıf etiketi

Score: Tahminin güven seviyesi veya olasılık değeri (float)

Bu yapı sayesinde modelin teknik tahmin verileri, kullanıcı dostu ve anlaşılır bir formata dönüştürülerek API üzerinden sunabiliriz.

Program.cs ve Dependency Injection Yapılandırması

ML.NET modelini Web API içerisinde dependency injection (DI) ile yönetmek, modelin ve ilgili servislerin tüm controller’lar tarafından kolayca erişilebilir olmasını sağlar. Bu nedenle Program.cs üzerinden gerekli servisler kaydedilir:

builder.Services.RegisterProjectExtentions();

Proje Extension Metodu

API servislerini ve ML.NET modelini merkezi bir şekilde kaydetmek için bir extension metodu kullandım. Bu yöntem, Program.cs içindeki servis kayıtlarını temiz, okunabilir ve yeniden kullanılabilir hâle getirir.

Config sınıfı altında tanımlanan RegisterProjectExtentions metodu, IServiceCollection üzerinde iki önemli kayıt işlemini gerçekleştirir

namespace ImageClassification.ML.Predict.Extentions
{
    public static class Config
    {
        public static void RegisterProjectExtentions(this IServiceCollection services)
        {
            var path = Path.Combine(ModelStorageConfig.ModelDirectory, "model.zip");
            services.AddPredictionEnginePool<ModelInput, ModelOutput>().FromFile(path, watchForChanges: true); //watchForChanges production da önerilmez.
            services.AddSingleton<IMLImageService, MLImageService>();
        }
    }
}

ModelStorageConfig.ModelDirectory ile merkezi model yolu belirlenir ve .zip dosyası yüklenir.

PredictionEnginePool, modelin bellekte tek sefer yüklenmesini sağlar ve thread-safe bir şekilde kullanılmasına imkân tanır.

watchForChanges: true parametresi ile model dosyasında bir değişiklik olursa pool otomatik olarak güncellenir. Ancak production ortamında bu parametre önerilmez; çünkü performans ve stabilite riskleri doğurabilir.

AddSingleton<IMLImageService, MLImageService>() satırı, model tahminlerini ve ilgili işlemleri yöneten servisi uygulama genelinde tek bir instance olarak kaydeder.

ImageValidator Sınıfı

Web API’ye gönderilen görsel dosyalarının geçerliliğini kontrol etmek için ImageValidator sınıfını oluşturalım. Bu sınıf, kullanıcıdan gelen dosyaların hem türünü hem de boyutunu kontrol edecek, hatalı girişleri engeller ve kullanıcıya anlamlı geri bildirim sağlar.

using ImageClassification.ML.Predict.Base;
using ImageClassification.ML.Predict.Models;

namespace ImageClassification.ML.Predict.Validators
{
    public class ImageValidator
    {
        public BaseResult<PredictionResult> Validate(IFormFile file)
        {
            if (file == null || file.Length == 0)
                return BaseResult<PredictionResult>.Fail("Lütfen Dosya Seçiniz.");

            string[] extentions = { ".jpg", ".jpeg", ".png" };
            string fileExt = Path.GetExtension(file.FileName).ToLowerInvariant();
            if (!extentions.Contains(fileExt))
                return BaseResult<PredictionResult>.Fail("Lütfen JPG JPEG ve png uzantılı dosyalar seçiniz.");

            long maxFileSize = 5 * 1024 * 1024;
            if (file.Length > maxFileSize)
                return BaseResult<PredictionResult>.Fail("Dosya boyutu en fazla 5 MB olabilir.");

            var result = new PredictionResult();
            return BaseResult<PredictionResult>.Success(result);
        }
    }
}

MLImageService Sınıfı ve Interface

public interface IMLImageService
{
    Task<BaseResult<PredictionResult>> PredictAsync(IFormFile file);
}
using ImageClassification.ML.Predict.Base;
using ImageClassification.ML.Predict.Models;
using ImageClassification.ML.Predict.Validators;
using ImageClassification.Shared.Models;
using Microsoft.Extensions.ML;

namespace ImageClassification.ML.Predict.Services
{
    public class MLImageService : IMLImageService
    {
        private readonly PredictionEnginePool<ModelInput, ModelOutput> _predictionEnginePool;

        public MLImageService(PredictionEnginePool<ModelInput, ModelOutput> predictionEnginePool)
        {
            _predictionEnginePool = predictionEnginePool;
        }
        public async Task<BaseResult<PredictionResult>> PredictAsync(IFormFile file)
        {
            var imageValidator = new ImageValidator();
            var validatorResult = imageValidator.Validate(file);
            if (!validatorResult.IsSuccess)
                return validatorResult;


            byte[] imageBytes = await GetImageBytes(file);

            var input = new ModelInput { Image = imageBytes };
            var prediction = _predictionEnginePool.Predict(input);

            var maxScore = (prediction.Score.Max() * 100).ToString("0.00");
            float score = float.Parse(maxScore);
            if (score == 0)
            {
                var result = Result("Bu görseli Hiç tanıyamadım..", score);
                return BaseResult<PredictionResult>.Success(result);
            }
            else if (score < 85f)
            {
                var result = Result($"Bu görseli tanıyamadım..", score);
                return BaseResult<PredictionResult>.Success(result);
            }
            else
            {
                var result = Result(prediction.Prediction, score);
                return BaseResult<PredictionResult>.Success(result);
            }
        }

        private async Task<byte[]> GetImageBytes(IFormFile file)
        {
            using var ms = new MemoryStream();
            await file.CopyToAsync(ms);
            return ms.ToArray();
        }
        private PredictionResult Result(string prediction, float score)
        {
            return new PredictionResult
            {
                Prediction = prediction,
                Score = score
            };
        }
    }
}

MLImageService sınıfı, temel olarak üç aşamada çalışır:

1. Dosya Doğrulama (Validation)

Gelen IFormFile, önce ImageValidator sınıfı ile kontrol edilir. Dosyanın varlığı, boyutu ve uzantısı validasyon kurallarına göre doğrulanır. Eğer dosya geçerli değilse, işlem burada durur ve BaseResult ile anlamlı bir hata mesajı döndürülür.

2. Görselin Byte Dizisine Dönüştürülmesi

Geçerli dosya, MemoryStream aracılığıyla byte dizisine çevrilir. Bu byte dizisi, ML.NET modelinin kabul ettiği ModelInput.Image property’sine aktarılır.

3. Model Tahmini ve Sonuç Yönetimi

PredictionEnginePool üzerinden model tahmini (Predict) yapılır. Tahmin sonuçları ModelOutput sınıfında elde edilir; burada hem tahmin edilen sınıf  hem de her sınıf için olasılık değerleri yer alır.

Tahminin güven seviyesi hesaplanır ve üç durum için kontrol yapılır:

  1. Score = 0 → Görsel tanınamadı, kullanıcıya "Bu görseli Hiç tanıyamadım.." mesajı döndürülür.

  2. Score < 85 → Model düşük güven ile tahmin yaptı, "Bu görseli tanıyamadım.." mesajı döndürülür.

  3. Score ≥ 85 → Tahmin güvenli, modelin ürettiği sınıf ve güven seviyesi kullanıcıya iletilir.

Tüm durumlar PredictionResult ile sarılır ve BaseResult<PredictionResult>.Success formatında geri döndürülür.

ClassificationController

Kullanıcıdan gelen görselleri alır, MLImageService üzerinden tahmin işlemini gerçekleştirir ve sonucu standart bir formatta döndürür.

using ImageClassification.ML.Predict.Models;
using ImageClassification.ML.Predict.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;

[ApiController]
[Route("api/[controller]")]
public class ClassificationController(IMLImageService _service) : ControllerBase
{
    [RequestFormLimits(MultipartBodyLengthLimit = 5000000)]
    [HttpPost("predict")]
    public async Task<IActionResult> Predict(IFormFile? file)
    {
        var result = await _service.PredictAsync(file);
        return result.IsSuccess ? Ok(result) : BadRequest(result);
    }
}

Sonuç ve Hatırlatma

Görsel sınıflandırma gibi karmaşık görevlerde makine öğrenmesi modellerinin yüksek doğrulukla çalışabilmesi için büyük ve çeşitli veri setlerine ihtiyaç vardır. Küçük veri setleriyle yapılan denemeler, temel mantığı anlamak ve prototip geliştirmek için yeterlidir; fakat gerçek dünyada modelin farklı durumları doğru şekilde tanıyabilmesi için kaliteli ve çeşitli verilerle eğitilmesi şarttır.

Unutmayın: Ne kadar fazla ve çeşitli veri kullanırsanız, modeliniz o kadar güvenilir ve güçlü olur.

Proje github: https://github.com/Sinantosun/ImageClassification

Diğer Bloglarımda Görüşmek Üzere👋