From 8d416317a8b3f213d7036af5a765f8712cbe59e3 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Thu, 12 Feb 2026 12:07:44 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B2=A0=EC=8A=A4=ED=8A=B8=20=EC=97=90?= =?UTF-8?q?=ED=8F=AD=20API,=202=EB=8B=A8=EA=B3=84=20=EC=8B=A4=ED=96=89=20?= =?UTF-8?q?=EC=8B=9C=20best=20epoch=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/ModelTrainDetailApiController.java | 22 +++++++++++++ .../model/dto/ModelTrainDetailDto.java | 14 ++++++++ .../service/ModelTrainDetailService.java | 5 +++ .../core/ModelTrainDetailCoreService.java | 5 +++ .../core/ModelTrainMngCoreService.java | 9 ++++++ .../postgres/entity/ModelMasterEntity.java | 3 ++ .../model/ModelDetailRepositoryCustom.java | 3 ++ .../model/ModelDetailRepositoryImpl.java | 32 +++++++++++++++++++ .../train/service/TestJobService.java | 3 ++ 9 files changed, 96 insertions(+) diff --git a/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java b/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java index 1dff752..8cf8a34 100644 --- a/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java +++ b/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java @@ -3,6 +3,7 @@ package com.kamco.cd.training.model; import com.kamco.cd.training.config.api.ApiResponseDto; import com.kamco.cd.training.model.dto.ModelTrainDetailDto; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelBestEpoch; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelTestMetrics; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelTrainMetrics; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelValidationMetrics; @@ -200,4 +201,25 @@ public class ModelTrainDetailApiController { UUID uuid) { return ApiResponseDto.ok(modelTrainDetailService.getModelTestMetricResult(uuid)); } + + @Operation(summary = "모델관리 > 모델 상세 > 성능 정보 (Test)", description = "모델 상세 > 성능 정보 (Test) API") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = TransferDetailDto.class))), + @ApiResponse(responseCode = "404", description = "데이터셋을 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/best-epoch/{uuid}") + public ApiResponseDto getModelTrainBestEpoch( + @Parameter(description = "모델 uuid", example = "95cb116c-380a-41c0-98d8-4d1142f15bbf") + @PathVariable + UUID uuid) { + return ApiResponseDto.ok(modelTrainDetailService.getModelTrainBestEpoch(uuid)); + } } diff --git a/src/main/java/com/kamco/cd/training/model/dto/ModelTrainDetailDto.java b/src/main/java/com/kamco/cd/training/model/dto/ModelTrainDetailDto.java index 6cdfe17..912588b 100644 --- a/src/main/java/com/kamco/cd/training/model/dto/ModelTrainDetailDto.java +++ b/src/main/java/com/kamco/cd/training/model/dto/ModelTrainDetailDto.java @@ -231,4 +231,18 @@ public class ModelTrainDetailDto { private Long detectionCount; private Long gtCount; } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class ModelBestEpoch { + private Integer epoch; + private Double loss; + private Float f1Score; + private Float precision; + private Float recall; + private Float iou; + private Float accuracy; + } } diff --git a/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java b/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java index 57c5b26..486fa16 100644 --- a/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java +++ b/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java @@ -6,6 +6,7 @@ import com.kamco.cd.training.model.dto.ModelConfigDto; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.DetailSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.HyperSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelBestEpoch; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelTestMetrics; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelTrainMetrics; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelValidationMetrics; @@ -111,4 +112,8 @@ public class ModelTrainDetailService { public List getModelTestMetricResult(UUID uuid) { return modelTrainDetailCoreService.getModelTestMetricResult(uuid); } + + public ModelBestEpoch getModelTrainBestEpoch(UUID uuid) { + return modelTrainDetailCoreService.getModelTrainBestEpoch(uuid); + } } diff --git a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java index 6da6aba..a0efb09 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java @@ -7,6 +7,7 @@ import com.kamco.cd.training.model.dto.ModelConfigDto; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.DetailSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.HyperSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelBestEpoch; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelTestMetrics; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelTrainMetrics; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelValidationMetrics; @@ -92,4 +93,8 @@ public class ModelTrainDetailCoreService { public List getModelTestMetricResult(UUID uuid) { return modelDetailRepository.getModelTestMetricResult(uuid); } + + public ModelBestEpoch getModelTrainBestEpoch(UUID uuid) { + return modelDetailRepository.getModelTrainBestEpoch(uuid); + } } diff --git a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java index b08c633..ddfee9f 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java @@ -457,4 +457,13 @@ public class ModelTrainMngCoreService { entity.setUpdatedDttm(ZonedDateTime.now()); entity.setUpdatedUid(userUtil.getId()); } + + public void updateModelMasterBestEpoch(Long modelId, int epoch) { + ModelMasterEntity entity = + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + + entity.setBestEpoch(epoch); + } } diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelMasterEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelMasterEntity.java index 61d9b75..4aca805 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelMasterEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelMasterEntity.java @@ -103,6 +103,9 @@ public class ModelMasterEntity { @Column(name = "last_error") private String lastError; + @Column(name = "best_epoch") + private Integer bestEpoch; + public ModelTrainMngDto.Basic toDto() { return new ModelTrainMngDto.Basic( this.id, diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java index 21ae644..2c74db6 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java @@ -3,6 +3,7 @@ package com.kamco.cd.training.postgres.repository.model; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.DetailSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.HyperSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelBestEpoch; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelTestMetrics; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelTrainMetrics; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelValidationMetrics; @@ -31,4 +32,6 @@ public interface ModelDetailRepositoryCustom { List getModelValidationMetricResult(UUID uuid); List getModelTestMetricResult(UUID uuid); + + ModelBestEpoch getModelTrainBestEpoch(UUID uuid); } diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java index edd556d..779368c 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java @@ -12,6 +12,7 @@ import static com.kamco.cd.training.postgres.entity.QModelMetricsValidationEntit import com.kamco.cd.training.model.dto.ModelTrainDetailDto.DetailSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.HyperSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelBestEpoch; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelTestMetrics; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelTrainMetrics; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.ModelValidationMetrics; @@ -26,8 +27,10 @@ import java.util.List; import java.util.Optional; import java.util.UUID; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Repository; +@Slf4j @Repository @RequiredArgsConstructor public class ModelDetailRepositoryImpl implements ModelDetailRepositoryCustom { @@ -237,4 +240,33 @@ public class ModelDetailRepositoryImpl implements ModelDetailRepositoryCustom { .where(modelMetricsTestEntity.model.id.eq(modelMasterEntity.getId())) .fetch(); } + + @Override + public ModelBestEpoch getModelTrainBestEpoch(UUID uuid) { + ModelMasterEntity modelMasterEntity = findByModelByUUID(uuid); + if (modelMasterEntity == null) { + return null; + } + + return queryFactory + .select( + Projections.constructor( + ModelBestEpoch.class, + modelMetricsTrainEntity.epoch, + modelMetricsTrainEntity.loss, + modelMetricsValidationEntity.mFscore, + modelMetricsValidationEntity.mPrecision, + modelMetricsValidationEntity.mRecall, + modelMetricsValidationEntity.mIou, + modelMetricsValidationEntity.mAcc)) + .from(modelMetricsTrainEntity) + .leftJoin(modelMetricsValidationEntity) + .on( + modelMetricsTrainEntity.model.eq(modelMetricsValidationEntity.model), + modelMetricsTrainEntity.epoch.eq(modelMetricsValidationEntity.epoch)) + .where( + modelMetricsTrainEntity.model.id.eq(modelMasterEntity.getId()), + modelMetricsTrainEntity.epoch.eq(modelMasterEntity.getBestEpoch())) + .fetchOne(); + } } diff --git a/src/main/java/com/kamco/cd/training/train/service/TestJobService.java b/src/main/java/com/kamco/cd/training/train/service/TestJobService.java index e7b5dfa..a7cf035 100644 --- a/src/main/java/com/kamco/cd/training/train/service/TestJobService.java +++ b/src/main/java/com/kamco/cd/training/train/service/TestJobService.java @@ -29,6 +29,9 @@ public class TestJobService { // 마스터 확인 modelTrainMngCoreService.findModelById(modelId); + // best epoch 업데이트 + modelTrainMngCoreService.updateModelMasterBestEpoch(modelId, epoch); + Map params = new java.util.LinkedHashMap<>(); params.put("jobType", "EVAL"); params.put("uuid", String.valueOf(uuid)); -- 2.49.1