C#與AI聯姻:零依賴!用Keras.NET訓練深度學習模型實錄
作者:CONAN
在C#中實現深度學習通常需要依賴復雜的框架,但通過Keras.NET,我們可以在零外部依賴的情況下訓練強大的深度學習模型。下面我將分享一個完整的實戰案例,展示如何用C#和Keras.NET訓練一個圖像分類模型。
在C#中實現深度學習通常需要依賴復雜的框架,但通過Keras.NET,我們可以在零外部依賴的情況下訓練強大的深度學習模型。下面我將分享一個完整的實戰案例,展示如何用C#和Keras.NET訓練一個圖像分類模型。
這個實現具有以下特點:
- 零外部依賴:僅使用Keras.NET和Numpy.NET庫,無需安裝Python或其他深度學習框架
- 完整的訓練流程:包括模型構建、數據加載、訓練、評估和保存
- 卷積神經網絡:使用現代CNN架構進行圖像分類
- 模型檢查點:自動保存驗證集表現最佳的模型
- 靈活的配置:可調整圖像尺寸、批次大小和訓練輪數
要運行此代碼,你需要安裝以下NuGet包:
- Keras.NET
- Numpy.NET
- SciSharp.TensorFlow.Redist
在實際應用中,你需要替換LoadData方法中的模擬數據加載邏輯,使用真實的圖像數據。你可以使用如ImageSharp等庫來處理圖像加載和預處理。
通過這種方法,你可以在C#環境中完全實現深度學習模型的訓練和部署,無需依賴Python環境,特別適合需要集成深度學習功能的.NET應用程序。
using Keras;
using Keras.Layers;
using Keras.Models;
using Keras.Optimizers;
using Numpy;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace DeepLearningExample
{
public class DeepLearningTrainer
{
private Sequential model;
// 構建卷積神經網絡模型
public void BuildModel(int imgWidth, int imgHeight, int numClasses)
{
// 創建序貫模型
model = new Sequential();
// 添加卷積層和池化層
model.Add(new Conv2D(32, new Shape(3, 3), activation: "relu", input_shape: new Shape(imgWidth, imgHeight, 3)));
model.Add(new MaxPooling2D(pool_size: new Shape(2, 2)));
model.Add(new Conv2D(64, new Shape(3, 3), activation: "relu"));
model.Add(new MaxPooling2D(pool_size: new Shape(2, 2)));
model.Add(new Conv2D(128, new Shape(3, 3), activation: "relu"));
model.Add(new MaxPooling2D(pool_size: new Shape(2, 2)));
// 展平并添加全連接層
model.Add(new Flatten());
model.Add(new Dense(128, activation: "relu"));
model.Add(new Dropout(0.5));
model.Add(new Dense(numClasses, activation: "softmax"));
// 編譯模型
var opt = new Adam(lr: 0.001f);
model.Compile(optimizer: opt, loss: "categorical_crossentropy", metrics: new string[] { "accuracy" });
Console.WriteLine("模型結構已構建:");
model.Summary();
}
// 加載圖像數據
public (NDarray xTrain, NDarray yTrain, NDarray xVal, NDarray yVal) LoadData(string dataPath, int imgWidth, int imgHeight)
{
Console.WriteLine($"開始加載數據: {dataPath}");
// 這里應該實現實際的圖像加載和預處理邏輯
// 為簡化示例,我們創建一些隨機數據作為占位符
int trainSamples = 8000;
int valSamples = 2000;
// 創建隨機訓練數據
var xTrain = np.random.rand(trainSamples, imgWidth, imgHeight, 3);
var yTrain = np.zeros((trainSamples, 10));
// 創建隨機驗證數據
var xVal = np.random.rand(valSamples, imgWidth, imgHeight, 3);
var yVal = np.zeros((valSamples, 10));
// 為簡化示例,隨機分配類別
for (int i = 0; i < trainSamples; i++)
{
int label = new Random().Next(0, 10);
yTrain[i, label] = 1;
}
for (int i = 0; i < valSamples; i++)
{
int label = new Random().Next(0, 10);
yVal[i, label] = 1;
}
Console.WriteLine($"數據加載完成: 訓練樣本={trainSamples}, 驗證樣本={valSamples}");
return (xTrain, yTrain, xVal, yVal);
}
// 訓練模型
public void TrainModel(NDarray xTrain, NDarray yTrain, NDarray xVal, NDarray yVal, int epochs = 10, int batchSize = 32)
{
Console.WriteLine($"開始訓練模型: 輪數={epochs}, 批次大小={batchSize}");
// 設置回調函數
var callbacks = new List<BaseCallback>
{
new ModelCheckpoint("best_model.h5", monitor: "val_accuracy", save_best_only: true, verbose: 1),
new EarlyStopping(monitor: "val_loss", patience: 3, verbose: 1),
new TensorBoard(log_dir: "logs", histogram_freq: 1)
};
// 訓練模型
var history = model.Fit(xTrain, yTrain,
batch_size: batchSize,
epochs: epochs,
validation_data: new NDarray[] { xVal, yVal },
callbacks: callbacks.ToArray(),
verbose: 1);
// 輸出訓練結果
Console.WriteLine("訓練歷史:");
foreach (var key in history.HistoryDict.Keys)
{
Console.WriteLine($"{key}: {string.Join(", ", history.HistoryDict[key].Select(v => v.ToString("0.0000")))}");
}
}
// 評估模型
public void EvaluateModel(NDarray xVal, NDarray yVal)
{
Console.WriteLine("開始評估模型...");
var scores = model.Evaluate(xVal, yVal, verbose: 1);
Console.WriteLine($"驗證集損失: {scores[0]:0.0000}");
Console.WriteLine($"驗證集準確率: {scores[1] * 100:0.00}%");
}
// 保存模型
public void SaveModel(string modelPath)
{
Console.WriteLine($"保存模型到: {modelPath}");
model.Save(modelPath);
}
}
}
責任編輯:武曉燕
來源:
程序員編程日記