feat: models caching

This commit is contained in:
2026-08-10 15:09:04 +03:00
parent 67718629ae
commit ec054d88c4
2 changed files with 179 additions and 114 deletions
+1
View File
@@ -3,6 +3,7 @@
## ##
## Get latest from `dotnet new gitignore` ## Get latest from `dotnet new gitignore`
.models_cache
.zed .zed
*.png *.png
cache cache
@@ -141,6 +141,35 @@ public partial class AnalyzerService
var sampleRecords = _context.SampleRecords var sampleRecords = _context.SampleRecords
.Where(r => r.BrandId == brand.Id); .Where(r => r.BrandId == brand.Id);
var dataSb = new System.Text.StringBuilder();
dataSb.AppendLine(brand.Id.ToString());
dataSb.AppendLine(brand.EditDateTime.ToString());
foreach (var record in sampleRecords.OrderBy(r => r.Id))
{
dataSb.AppendLine(record.Id.ToString());
dataSb.AppendLine(record.EditDateTime.ToString());
}
dataSb.AppendLine(separator.Id.ToString());
dataSb.AppendLine(separator.EditDateTime.ToString());
var dataHashCode = Convert.ToHexString(
System.Security.Cryptography.MD5.HashData(
System.Text.Encoding.UTF8.GetBytes(dataSb.ToString())
)
);
_logger.LogInformation("Хэш калибровочных записей: {}", dataHashCode);
Directory.CreateDirectory(".models_cache");
var cachedModelPath = Path.Combine(".models_cache", dataHashCode) + ".zip";
if (File.Exists(cachedModelPath))
{
_logger.LogInformation("Модель найдена к кэше");
var model = _ml.Model.Load(cachedModelPath, out _);
_clusterizationEngine = _ml.Model.CreatePredictionEngine<ClusterizationData, ClusterizationPrediction>(model);
}
else
{
_logger.LogInformation("Найдено калибровочных записей проб для марки: {}", sampleRecords.Count()); _logger.LogInformation("Найдено калибровочных записей проб для марки: {}", sampleRecords.Count());
if (sampleRecords.Count() == 0) if (sampleRecords.Count() == 0)
throw new InvalidDataException($"Не найдено калибровочных записей для марки: \"{brand.BrandName} - {brand.MixtureName}\""); throw new InvalidDataException($"Не найдено калибровочных записей для марки: \"{brand.BrandName} - {brand.MixtureName}\"");
@@ -202,9 +231,13 @@ public partial class AnalyzerService
var model = pipeline.Fit(trainData); var model = pipeline.Fit(trainData);
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
_ml.Model.Save(model, trainData.Schema, cachedModelPath);
_clusterizationEngine = _ml.Model.CreatePredictionEngine<ClusterizationData, ClusterizationPrediction>(model); _clusterizationEngine = _ml.Model.CreatePredictionEngine<ClusterizationData, ClusterizationPrediction>(model);
model.Dispose(); model.Dispose();
} }
}
private async Task InitializeMlRegressionEngine(BrandRecord brand, CancellationToken cancellationToken) private async Task InitializeMlRegressionEngine(BrandRecord brand, CancellationToken cancellationToken)
{ {
_logger.LogInformation("Инициализация модели регрессии для марки \"{} - {}\"", brand.BrandName, brand.MixtureName); _logger.LogInformation("Инициализация модели регрессии для марки \"{} - {}\"", brand.BrandName, brand.MixtureName);
@@ -217,6 +250,33 @@ public partial class AnalyzerService
var sampleRecords = _context.SampleRecords var sampleRecords = _context.SampleRecords
.Where(r => r.BrandId == brand.Id); .Where(r => r.BrandId == brand.Id);
var dataSb = new System.Text.StringBuilder();
dataSb.AppendLine(brand.Id.ToString());
dataSb.AppendLine(brand.EditDateTime.ToString());
foreach (var record in sampleRecords.OrderBy(r => r.Id))
{
dataSb.AppendLine(record.Id.ToString());
dataSb.AppendLine(record.EditDateTime.ToString());
}
var dataHashCode = Convert.ToHexString(
System.Security.Cryptography.MD5.HashData(
System.Text.Encoding.UTF8.GetBytes(dataSb.ToString())
)
);
_logger.LogInformation("Хэш калибровочных записей: {}", dataHashCode);
Directory.CreateDirectory(".models_cache");
var cachedModelPath = Path.Combine(".models_cache", dataHashCode) + ".zip";
if (File.Exists(cachedModelPath))
{
_logger.LogInformation("Модель найдена к кэше");
var model = _ml.Model.Load(cachedModelPath, out _);
_regressionEngine = _ml.Model.CreatePredictionEngine<RegressionData, RegressionPrediction>(model);
}
else
{
_logger.LogInformation("Найдено калибровочных записей проб для марки: {}", sampleRecords.Count()); _logger.LogInformation("Найдено калибровочных записей проб для марки: {}", sampleRecords.Count());
if (sampleRecords.Count() == 0) if (sampleRecords.Count() == 0)
throw new InvalidDataException($"Не найдено калибровочных записей для марки: \"{brand.BrandName} - {brand.MixtureName}\""); throw new InvalidDataException($"Не найдено калибровочных записей для марки: \"{brand.BrandName} - {brand.MixtureName}\"");
@@ -250,6 +310,7 @@ public partial class AnalyzerService
.ToList(); .ToList();
_logger.LogInformation("Загружено векторов для обучения: {}", trainDataSet.Count()); _logger.LogInformation("Загружено векторов для обучения: {}", trainDataSet.Count());
if (trainDataSet.Count() == 0) if (trainDataSet.Count() == 0)
throw new InvalidDataException($"Не найдено калибровочных данных для марки: \"{brand.BrandName} - {brand.MixtureName}\""); throw new InvalidDataException($"Не найдено калибровочных данных для марки: \"{brand.BrandName} - {brand.MixtureName}\"");
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@@ -287,10 +348,13 @@ public partial class AnalyzerService
_logger.LogInformation("Обучение модели"); _logger.LogInformation("Обучение модели");
var model = pipeline.Fit(trainData); var model = pipeline.Fit(trainData);
_ml.Model.Save(model, trainData.Schema, cachedModelPath);
_regressionEngine = _ml.Model.CreatePredictionEngine<RegressionData, RegressionPrediction>(model); _regressionEngine = _ml.Model.CreatePredictionEngine<RegressionData, RegressionPrediction>(model);
model.Dispose(); model.Dispose();
} }
}
public async Task<(Mat avgImage, Rect roi, Mat mask, IEnumerable<Point[]> contours, Mat result)?> Analyze(IEnumerable<ImageData> imagesData) public async Task<(Mat avgImage, Rect roi, Mat mask, IEnumerable<Point[]> contours, Mat result)?> Analyze(IEnumerable<ImageData> imagesData)
{ {