From 0c34ea7dcb19f5d8f34ee1dfef48b5737fa6e5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dean=5B=EB=B0=B1=EB=B3=91=EB=82=A8=5D?= Date: Thu, 12 Feb 2026 18:48:14 +0900 Subject: [PATCH] hyperparam_with_modeltype --- build.gradle | 43 ++++ .../cd/training/common/dto/HyperParam.java | 5 + .../cd/training/common/enums/ModelType.java | 5 + .../hyperparam/HyperParamApiController.java | 21 +- .../hyperparam/dto/HyperParamDto.java | 4 + .../hyperparam/service/HyperParamService.java | 11 +- .../model/ModelTrainMngApiController.java | 5 +- .../postgres/core/HyperParamCoreService.java | 192 ++++++++++-------- .../core/ModelTrainMngCoreService.java | 148 ++++++++------ .../entity/ModelHyperParamEntity.java | 14 +- .../HyperParamRepositoryCustom.java | 15 +- .../hyperparam/HyperParamRepositoryImpl.java | 32 ++- src/main/resources/application-prod.yml | 38 ++-- .../dump-kamco_training_db-202512261611.sql | 6 +- 14 files changed, 354 insertions(+), 185 deletions(-) diff --git a/build.gradle b/build.gradle index bb3df95..8e8f7ea 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ plugins { id 'org.springframework.boot' version '3.5.7' id 'io.spring.dependency-management' version '1.1.7' id 'com.diffplug.spotless' version '6.25.0' + id 'idea' } group = 'com.kamco.cd' @@ -21,11 +22,23 @@ configurations { } } +// QueryDSL 생성된 소스 디렉토리 정의 +def generatedSourcesDir = file("$buildDir/generated/sources/annotationProcessor/java/main") + repositories { mavenCentral() maven { url "https://repo.osgeo.org/repository/release/" } } +// Gradle이 생성된 소스를 컴파일 경로에 포함하도록 설정 +sourceSets { + main { + java { + srcDirs += generatedSourcesDir + } + } +} + dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' @@ -87,6 +100,21 @@ dependencies { implementation 'org.apache.commons:commons-csv:1.10.0' } +// IntelliJ가 생성된 소스를 인식하도록 설정 +idea { + module { + // 소스 디렉토리로 인식 + sourceDirs += generatedSourcesDir + + // Generated Sources Root로 마킹 (IntelliJ에서 특별 처리) + generatedSourceDirs += generatedSourcesDir + + // 소스 및 Javadoc 다운로드 + downloadJavadoc = true + downloadSources = true + } +} + configurations.configureEach { exclude group: 'javax.media', module: 'jai_core' } @@ -95,6 +123,21 @@ tasks.named('test') { useJUnitPlatform() } +// 컴파일 전 생성된 소스 디렉토리 생성 보장 +tasks.named('compileJava') { + doFirst { + generatedSourcesDir.mkdirs() + } +} + +// 생성된 소스 정리 태스크 +tasks.register('cleanGeneratedSources', Delete) { + delete generatedSourcesDir +} + +tasks.named('clean') { + dependsOn 'cleanGeneratedSources' +} bootJar { archiveFileName = 'ROOT.jar' diff --git a/src/main/java/com/kamco/cd/training/common/dto/HyperParam.java b/src/main/java/com/kamco/cd/training/common/dto/HyperParam.java index cfc78fc..5175c5f 100644 --- a/src/main/java/com/kamco/cd/training/common/dto/HyperParam.java +++ b/src/main/java/com/kamco/cd/training/common/dto/HyperParam.java @@ -1,5 +1,6 @@ package com.kamco.cd.training.common.dto; +import com.kamco.cd.training.common.enums.ModelType; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -14,6 +15,10 @@ public class HyperParam { // ------------------------- // Important // ------------------------- + + @Schema(description = "모델", example = "large") + private ModelType model; // backbone + @Schema(description = "백본 네트워크", example = "large") private String backbone; // backbone diff --git a/src/main/java/com/kamco/cd/training/common/enums/ModelType.java b/src/main/java/com/kamco/cd/training/common/enums/ModelType.java index 8eb327d..63d5e94 100644 --- a/src/main/java/com/kamco/cd/training/common/enums/ModelType.java +++ b/src/main/java/com/kamco/cd/training/common/enums/ModelType.java @@ -2,6 +2,7 @@ package com.kamco.cd.training.common.enums; import com.kamco.cd.training.common.utils.enums.CodeExpose; import com.kamco.cd.training.common.utils.enums.EnumType; +import java.util.Arrays; import lombok.AllArgsConstructor; import lombok.Getter; @@ -15,6 +16,10 @@ public enum ModelType implements EnumType { private String desc; + public static ModelType getValueData(String modelNo) { + return Arrays.stream(ModelType.values()).filter(m -> m.getId().equals(modelNo)).findFirst().orElse(G1); + } + @Override public String getId() { return name(); diff --git a/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java b/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java index 964ba74..827148e 100644 --- a/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java +++ b/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java @@ -1,6 +1,7 @@ package com.kamco.cd.training.hyperparam; import com.kamco.cd.training.common.dto.HyperParam; +import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.config.api.ApiResponseDto; import com.kamco.cd.training.hyperparam.dto.HyperParamDto; import com.kamco.cd.training.hyperparam.dto.HyperParamDto.List; @@ -65,7 +66,7 @@ public class HyperParamApiController { mediaType = "application/json", schema = @Schema(implementation = String.class))), @ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content), - @ApiResponse(responseCode = "422", description = "HPs_0001 수정 불가", content = @Content), + @ApiResponse(responseCode = "422", description = "default는 삭제불가", content = @Content), @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) }) @PutMapping("/{uuid}") @@ -87,8 +88,9 @@ public class HyperParamApiController { @ApiResponse(responseCode = "404", description = "하이퍼파라미터를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) }) - @GetMapping("/list") + @GetMapping("{model}/list") public ApiResponseDto> getHyperParam( + @PathVariable ModelType model, @Parameter( description = "구분 CREATE_DATE(생성일), LAST_USED_DATE(최근사용일)", example = "CREATE_DATE") @@ -98,7 +100,7 @@ public class HyperParamApiController { LocalDate startDate, @Parameter(description = "종료일", example = "2026-02-28") @RequestParam(required = false) LocalDate endDate, - @Parameter(description = "버전명", example = "HPs_0001") @RequestParam(required = false) + @Parameter(description = "버전명", example = "G_000001") @RequestParam(required = false) String hyperVer, @Parameter( description = "정렬", @@ -124,7 +126,7 @@ public class HyperParamApiController { searchReq.setSort(sort); searchReq.setPage(page); searchReq.setSize(size); - Page list = hyperParamService.getHyperParamList(searchReq); + Page list = hyperParamService.getHyperParamList(model, searchReq); return ApiResponseDto.ok(list); } @@ -133,7 +135,7 @@ public class HyperParamApiController { @ApiResponses( value = { @ApiResponse(responseCode = "200", description = "삭제 성공", content = @Content), - @ApiResponse(responseCode = "422", description = "HPs_0001 삭제 불가", content = @Content), + @ApiResponse(responseCode = "422", description = "default 삭제 불가", content = @Content), @ApiResponse(responseCode = "404", description = "하이퍼파라미터를 찾을 수 없음", content = @Content), }) @DeleteMapping("/{uuid}") @@ -179,8 +181,11 @@ public class HyperParamApiController { @ApiResponse(responseCode = "404", description = "하이퍼파라미터를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) }) - @GetMapping("/init") - public ApiResponseDto getInitHyperParam() { - return ApiResponseDto.ok(hyperParamService.getInitHyperParam()); + @GetMapping("/init/{model}") + public ApiResponseDto getInitHyperParam( + @PathVariable ModelType model + + ) { + return ApiResponseDto.ok(hyperParamService.getInitHyperParam(model)); } } diff --git a/src/main/java/com/kamco/cd/training/hyperparam/dto/HyperParamDto.java b/src/main/java/com/kamco/cd/training/hyperparam/dto/HyperParamDto.java index 2ed4934..8a804cf 100644 --- a/src/main/java/com/kamco/cd/training/hyperparam/dto/HyperParamDto.java +++ b/src/main/java/com/kamco/cd/training/hyperparam/dto/HyperParamDto.java @@ -1,5 +1,6 @@ package com.kamco.cd.training.hyperparam.dto; +import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.common.utils.enums.CodeExpose; import com.kamco.cd.training.common.utils.enums.EnumType; import com.kamco.cd.training.common.utils.interfaces.JsonFormatDttm; @@ -24,6 +25,7 @@ public class HyperParamDto { @AllArgsConstructor public static class Basic { + private ModelType model; // 20250212 modeltype추가 private UUID uuid; private String hyperVer; @JsonFormatDttm private ZonedDateTime createdDttm; @@ -98,6 +100,8 @@ public class HyperParamDto { private Integer gpuCnt; private String gpuIds; private Integer masterPort; + + private Boolean isDefault; } @Getter diff --git a/src/main/java/com/kamco/cd/training/hyperparam/service/HyperParamService.java b/src/main/java/com/kamco/cd/training/hyperparam/service/HyperParamService.java index d738af3..4d355b7 100644 --- a/src/main/java/com/kamco/cd/training/hyperparam/service/HyperParamService.java +++ b/src/main/java/com/kamco/cd/training/hyperparam/service/HyperParamService.java @@ -1,8 +1,10 @@ package com.kamco.cd.training.hyperparam.service; import com.kamco.cd.training.common.dto.HyperParam; +import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.hyperparam.dto.HyperParamDto; import com.kamco.cd.training.hyperparam.dto.HyperParamDto.List; +import com.kamco.cd.training.hyperparam.dto.HyperParamDto.SearchReq; import com.kamco.cd.training.postgres.core.HyperParamCoreService; import java.util.UUID; import lombok.RequiredArgsConstructor; @@ -20,11 +22,12 @@ public class HyperParamService { /** * 하이퍼 파라미터 목록 조회 * + * @param model * @param req * @return 목록 */ - public Page getHyperParamList(HyperParamDto.SearchReq req) { - return hyperParamCoreService.findByHyperVerList(req); + public Page getHyperParamList(ModelType model, SearchReq req) { + return hyperParamCoreService.findByHyperVerList(model, req); } /** @@ -59,8 +62,8 @@ public class HyperParamService { } /** 하이퍼파라미터 최적화 설정값 조회 */ - public HyperParamDto.Basic getInitHyperParam() { - return hyperParamCoreService.getInitHyperParam(); + public HyperParamDto.Basic getInitHyperParam(ModelType model) { + return hyperParamCoreService.getInitHyperParam(model); } /** diff --git a/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java b/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java index 016c778..0a81e96 100644 --- a/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java +++ b/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java @@ -74,13 +74,12 @@ public class ModelTrainMngApiController { @ApiResponses( value = { @ApiResponse(responseCode = "200", description = "삭제 성공", content = @Content), - @ApiResponse(responseCode = "409", description = "HPs_0001 삭제 불가", content = @Content) + @ApiResponse(responseCode = "409", description = "G1_000001 삭제 불가", content = @Content) }) @DeleteMapping("/{uuid}") public ApiResponseDto deleteModelTrain( @Parameter(description = "학습 모델 uuid", example = "f2b02229-90f2-45f5-92ea-c56cf1c29f79") - @PathVariable - UUID uuid) { + @PathVariable UUID uuid) { modelTrainMngService.deleteModelTrain(uuid); return ApiResponseDto.ok(null); } diff --git a/src/main/java/com/kamco/cd/training/postgres/core/HyperParamCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/HyperParamCoreService.java index 16262e5..79ec4a8 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/HyperParamCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/HyperParamCoreService.java @@ -1,10 +1,12 @@ package com.kamco.cd.training.postgres.core; import com.kamco.cd.training.common.dto.HyperParam; +import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.common.exception.CustomApiException; import com.kamco.cd.training.common.utils.UserUtil; import com.kamco.cd.training.hyperparam.dto.HyperParamDto; import com.kamco.cd.training.hyperparam.dto.HyperParamDto.Basic; +import com.kamco.cd.training.hyperparam.dto.HyperParamDto.SearchReq; import com.kamco.cd.training.postgres.entity.ModelHyperParamEntity; import com.kamco.cd.training.postgres.repository.hyperparam.HyperParamRepository; import java.time.ZonedDateTime; @@ -17,6 +19,7 @@ import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class HyperParamCoreService { + private final HyperParamRepository hyperParamRepository; private final UserUtil userUtil; @@ -27,7 +30,7 @@ public class HyperParamCoreService { * @return 등록된 버전명 */ public Basic createHyperParam(HyperParam createReq) { - String firstVersion = getFirstHyperParamVersion(); + String firstVersion = getFirstHyperParamVersion(createReq.getModel()); ModelHyperParamEntity entity = new ModelHyperParamEntity(); entity.setHyperVer(firstVersion); @@ -47,17 +50,17 @@ public class HyperParamCoreService { /** * 하이퍼파라미터 수정 * - * @param uuid uuid + * @param uuid uuid * @param createReq 등록 요청 * @return ver */ public String updateHyperParam(UUID uuid, HyperParam createReq) { ModelHyperParamEntity entity = - hyperParamRepository - .findHyperParamByUuid(uuid) - .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + hyperParamRepository + .findHyperParamByUuid(uuid) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); - if (entity.getHyperVer().equals("HPs_0001")) { + if (entity.getIsDefault()) { throw new CustomApiException("UNPROCESSABLE_ENTITY_UPDATE", HttpStatus.UNPROCESSABLE_ENTITY); } applyHyperParam(entity, createReq); @@ -69,11 +72,112 @@ public class HyperParamCoreService { return entity.getHyperVer(); } + + /** + * 하이퍼파라미터 삭제 + * + * @param uuid + */ + public void deleteHyperParam(UUID uuid) { + ModelHyperParamEntity entity = + hyperParamRepository + .findHyperParamByUuid(uuid) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + +// if (entity.getHyperVer().equals("HPs_0001")) { +// throw new CustomApiException("UNPROCESSABLE_ENTITY", HttpStatus.UNPROCESSABLE_ENTITY); +// } + + //디폴트면 삭제불가 + if (entity.getIsDefault()) { + throw new CustomApiException("UNPROCESSABLE_ENTITY", HttpStatus.UNPROCESSABLE_ENTITY); + } + + entity.setDelYn(true); + entity.setUpdatedUid(userUtil.getId()); + entity.setUpdatedDttm(ZonedDateTime.now()); + } + + /** + * 하이퍼파라미터 최적화 설정값 조회 + * + * @return + */ + public HyperParamDto.Basic getInitHyperParam(ModelType model) { + ModelHyperParamEntity entity = + hyperParamRepository + .getHyperparamByType(model) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + return entity.toDto(); + } + + /** + * 하이퍼파라미터 상세 조회 + * + * @return + */ + public HyperParamDto.Basic getHyperParam(UUID uuid) { + ModelHyperParamEntity entity = + hyperParamRepository + .findHyperParamByUuid(uuid) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + return entity.toDto(); + } + + /** + * 하이퍼파라미터 목록 조회 + * + * @param model + * @param req + * @return + */ + public Page findByHyperVerList(ModelType model, SearchReq req) { + return hyperParamRepository.findByHyperVerList(model, req); + } + + /** + * 하이퍼파라미터 버전 조회 + * + * @param model 모델 타입 + * @return ver + */ + public String getFirstHyperParamVersion(ModelType model) { + return hyperParamRepository + .findHyperParamVerByModelType(model) + .map(ModelHyperParamEntity::getHyperVer) + .map(ver -> increase(ver, model)) + .orElse(model.name() + "_000001"); + } + + /** + * 하이퍼 파라미터의 버전을 증가시킨다. + * + * @param hyperVer 현재 버전 + * @param modelType 모델 타입 + * @return 증가된 버전 + */ + private String increase(String hyperVer, ModelType modelType) { + String prefix = modelType.name() + "_"; + int num = Integer.parseInt(hyperVer.substring(prefix.length())); + return prefix + String.format("%06d", num + 1); + } + private void applyHyperParam(ModelHyperParamEntity entity, HyperParam src) { + + ModelType model = src.getModel(); + + // 하드코딩 모델별로 다른경우 250212 bbn 하드코딩 + if (model == ModelType.G3) { + entity.setCropSize("512,512"); + } else { + entity.setCropSize("256,256"); + } + // entity.setCropSize(src.getCropSize()); + // Important + entity.setModelType(model); // 20250212 modeltype추가 entity.setBackbone(src.getBackbone()); entity.setInputSize(src.getInputSize()); - entity.setCropSize(src.getCropSize()); entity.setBatchSize(src.getBatchSize()); // Data @@ -111,78 +215,4 @@ public class HyperParamCoreService { entity.setMemo(src.getMemo()); } - /** - * 하이퍼파라미터 삭제 - * - * @param uuid - */ - public void deleteHyperParam(UUID uuid) { - ModelHyperParamEntity entity = - hyperParamRepository - .findHyperParamByUuid(uuid) - .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); - - if (entity.getHyperVer().equals("HPs_0001")) { - throw new CustomApiException("UNPROCESSABLE_ENTITY", HttpStatus.UNPROCESSABLE_ENTITY); - } - - entity.setDelYn(true); - entity.setUpdatedUid(userUtil.getId()); - entity.setUpdatedDttm(ZonedDateTime.now()); - } - - /** - * 하이퍼파라미터 최적화 설정값 조회 - * - * @return - */ - public HyperParamDto.Basic getInitHyperParam() { - ModelHyperParamEntity entity = - hyperParamRepository - .findHyperParamByHyperVer("HPs_0001") - .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); - return entity.toDto(); - } - - /** - * 하이퍼파라미터 상세 조회 - * - * @return - */ - public HyperParamDto.Basic getHyperParam(UUID uuid) { - ModelHyperParamEntity entity = - hyperParamRepository - .findHyperParamByUuid(uuid) - .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); - return entity.toDto(); - } - - /** - * 하이퍼파라미터 목록 조회 - * - * @param req - * @return - */ - public Page findByHyperVerList(HyperParamDto.SearchReq req) { - return hyperParamRepository.findByHyperVerList(req); - } - - /** - * 하이퍼파라미터 버전 조회 - * - * @return ver - */ - public String getFirstHyperParamVersion() { - return hyperParamRepository - .findHyperParamVer() - .map(ModelHyperParamEntity::getHyperVer) - .map(this::increase) - .orElse("HPs_0001"); - } - - private String increase(String hyperVer) { - String prefix = "HPs_"; - int num = Integer.parseInt(hyperVer.substring(prefix.length())); - return prefix + String.format("%04d", num + 1); - } } 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 0a331d4..cc0a0ef 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 @@ -65,9 +65,9 @@ public class ModelTrainMngCoreService { */ public void deleteModel(UUID uuid) { ModelMasterEntity entity = - modelMngRepository - .findByUuid(uuid) - .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + modelMngRepository + .findByUuid(uuid) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); entity.setDelYn(true); entity.setUpdatedDttm(ZonedDateTime.now()); entity.setUpdatedUid(userUtil.getId()); @@ -83,13 +83,15 @@ public class ModelTrainMngCoreService { ModelMasterEntity entity = new ModelMasterEntity(); ModelHyperParamEntity hyperParamEntity = new ModelHyperParamEntity(); - // 최적화 파라미터는 HPs_0001 사용 +// 최적화 파라미터는 모델 type의 디폴트사용 if (HyperParamSelectType.OPTIMIZED.getId().equals(addReq.getHyperParamType())) { - hyperParamEntity = hyperParamRepository.findByHyperVer("HPs_0001").orElse(null); + ModelType modelType = ModelType.getValueData(addReq.getModelNo()); + hyperParamEntity = hyperParamRepository.getHyperparamByType(modelType).orElse(null); +// hyperParamEntity = hyperParamRepository.findByHyperVer("HPs_0001").orElse(null); } else { hyperParamEntity = - hyperParamRepository.findHyperParamByUuid(addReq.getHyperUuid()).orElse(null); + hyperParamRepository.findHyperParamByUuid(addReq.getHyperUuid()).orElse(null); } if (hyperParamEntity == null || hyperParamEntity.getHyperVer() == null) { @@ -97,8 +99,8 @@ public class ModelTrainMngCoreService { } String modelVer = - String.join( - ".", addReq.getModelNo(), hyperParamEntity.getHyperVer(), entity.getUuid().toString()); + String.join( + ".", addReq.getModelNo(), hyperParamEntity.getHyperVer(), entity.getUuid().toString()); entity.setModelVer(modelVer); entity.setHyperParamId(hyperParamEntity.getId()); entity.setModelNo(addReq.getModelNo()); @@ -130,7 +132,7 @@ public class ModelTrainMngCoreService { * data set 저장 * * @param modelId 저장한 모델 학습 id - * @param addReq 요청 파라미터 + * @param addReq 요청 파라미터 */ public void saveModelDataset(Long modelId, ModelTrainMngDto.AddReq addReq) { TrainingDataset dataset = addReq.getTrainingDataset(); @@ -163,9 +165,9 @@ public class ModelTrainMngCoreService { */ public void updateModelMaster(Long modelId, ModelTrainMngDto.UpdateReq req) { ModelMasterEntity entity = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); if (req.getRequestPath() != null && !req.getRequestPath().isEmpty()) { entity.setRequestPath(req.getRequestPath()); } @@ -178,7 +180,7 @@ public class ModelTrainMngCoreService { /** * 모델 데이터셋 mapping 테이블 저장 * - * @param modelId 모델학습 id + * @param modelId 모델학습 id * @param datasetList 선택한 data set */ public void saveModelDatasetMap(Long modelId, List datasetList) { @@ -195,7 +197,7 @@ public class ModelTrainMngCoreService { * 모델학습 config 저장 * * @param modelId 모델학습 id - * @param req 요청 파라미터 + * @param req 요청 파라미터 * @return */ public void saveModelConfig(Long modelId, ModelTrainMngDto.ModelConfig req) { @@ -215,7 +217,7 @@ public class ModelTrainMngCoreService { /** * 데이터셋 매핑 생성 * - * @param modelUid 모델 UID + * @param modelUid 모델 UID * @param datasetIds 데이터셋 ID 목록 */ public void createDatasetMappings(Long modelUid, List datasetIds) { @@ -237,8 +239,8 @@ public class ModelTrainMngCoreService { public ModelMasterEntity findByUuid(UUID uuid) { try { return modelMngRepository - .findByUuid(uuid) - .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + .findByUuid(uuid) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); } catch (IllegalArgumentException e) { throw new BadRequestException("잘못된 UUID 형식입니다: " + uuid); } @@ -252,9 +254,9 @@ public class ModelTrainMngCoreService { */ public Long findModelIdByUuid(UUID uuid) { ModelMasterEntity entity = - modelMngRepository - .findByUuid(uuid) - .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + modelMngRepository + .findByUuid(uuid) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); return entity.getId(); } @@ -267,8 +269,8 @@ public class ModelTrainMngCoreService { public ModelConfigDto.Basic findModelConfigByModelId(UUID uuid) { ModelMasterEntity modelEntity = findByUuid(uuid); return modelConfigRepository - .findModelConfigByModelId(modelEntity.getId()) - .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + .findModelConfigByModelId(modelEntity.getId()) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); } /** @@ -299,19 +301,21 @@ public class ModelTrainMngCoreService { */ public ModelTrainMngDto.Basic findModelById(Long id) { ModelMasterEntity entity = - modelMngRepository - .findById(id) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + id)); + modelMngRepository + .findById(id) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + id)); return entity.toDto(); } - /** 마스터를 IN_PROGRESS로 전환하고, 현재 실행 jobId를 연결 - UI/중단/상태조회 모두 currentAttemptId를 기준으로 동작 */ + /** + * 마스터를 IN_PROGRESS로 전환하고, 현재 실행 jobId를 연결 - UI/중단/상태조회 모두 currentAttemptId를 기준으로 동작 + */ @Transactional public void markInProgress(Long modelId, Long jobId) { ModelMasterEntity master = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); master.setStatusCd(TrainStatusType.IN_PROGRESS.getId()); master.setCurrentAttemptId(jobId); @@ -319,46 +323,54 @@ public class ModelTrainMngCoreService { // 필요하면 시작시간도 여기서 찍어줌 } - /** 마지막 에러 메시지 초기화 - 재시작/새 실행 때 이전 에러 흔적 제거 */ + /** + * 마지막 에러 메시지 초기화 - 재시작/새 실행 때 이전 에러 흔적 제거 + */ @Transactional public void clearLastError(Long modelId) { ModelMasterEntity master = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); master.setLastError(null); } - /** 중단 처리(옵션) - cancel에서 쓰려고 하면 같이 구현 */ + /** + * 중단 처리(옵션) - cancel에서 쓰려고 하면 같이 구현 + */ @Transactional public void markStopped(Long modelId) { ModelMasterEntity master = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); master.setStatusCd(TrainStatusType.STOPPED.getId()); } - /** 완료 처리(옵션) - Worker가 성공 시 호출 */ + /** + * 완료 처리(옵션) - Worker가 성공 시 호출 + */ @Transactional public void markCompleted(Long modelId) { ModelMasterEntity master = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); master.setStatusCd(TrainStatusType.COMPLETED.getId()); } - /** step 1오류 처리(옵션) - Worker가 실패 시 호출 */ + /** + * step 1오류 처리(옵션) - Worker가 실패 시 호출 + */ @Transactional public void markError(Long modelId, String errorMessage) { ModelMasterEntity master = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); master.setStatusCd(TrainStatusType.ERROR.getId()); master.setStep1State(TrainStatusType.ERROR.getId()); @@ -367,13 +379,15 @@ public class ModelTrainMngCoreService { master.setUpdatedDttm(ZonedDateTime.now()); } - /** step 2오류 처리(옵션) - Worker가 실패 시 호출 */ + /** + * step 2오류 처리(옵션) - Worker가 실패 시 호출 + */ @Transactional public void markStep2Error(Long modelId, String errorMessage) { ModelMasterEntity master = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); master.setStatusCd(TrainStatusType.ERROR.getId()); master.setStep2State(TrainStatusType.ERROR.getId()); @@ -385,9 +399,9 @@ public class ModelTrainMngCoreService { @Transactional public void markSuccess(Long modelId) { ModelMasterEntity master = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); // 모델 상태 완료 처리 master.setStatusCd(TrainStatusType.COMPLETED.getId()); @@ -415,9 +429,9 @@ public class ModelTrainMngCoreService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void markStep1InProgress(Long modelId, Long jobId) { ModelMasterEntity entity = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); entity.setStatusCd(TrainStatusType.IN_PROGRESS.getId()); entity.setStep1StrtDttm(ZonedDateTime.now()); @@ -435,9 +449,9 @@ public class ModelTrainMngCoreService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void markStep2InProgress(Long modelId, Long jobId) { ModelMasterEntity entity = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); entity.setStatusCd(TrainStatusType.IN_PROGRESS.getId()); entity.setStep2StrtDttm(ZonedDateTime.now()); @@ -455,9 +469,9 @@ public class ModelTrainMngCoreService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void markStep1Success(Long modelId) { ModelMasterEntity entity = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); entity.setStatusCd(TrainStatusType.COMPLETED.getId()); entity.setStep1State(TrainStatusType.COMPLETED.getId()); @@ -474,9 +488,9 @@ public class ModelTrainMngCoreService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void markStep2Success(Long modelId) { ModelMasterEntity entity = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + modelMngRepository + .findById(modelId) + .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); entity.setStatusCd(TrainStatusType.COMPLETED.getId()); entity.setStep2State(TrainStatusType.COMPLETED.getId()); @@ -487,9 +501,9 @@ public class ModelTrainMngCoreService { public void updateModelMasterBestEpoch(Long modelId, int epoch) { ModelMasterEntity entity = - modelMngRepository - .findById(modelId) - .orElseThrow(() -> new IllegalArgumentException("Model not found: " + modelId)); + 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/ModelHyperParamEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelHyperParamEntity.java index b1fe789..ec18265 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelHyperParamEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelHyperParamEntity.java @@ -1,5 +1,6 @@ package com.kamco.cd.training.postgres.entity; +import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.hyperparam.dto.HyperParamDto; import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; @@ -311,8 +312,17 @@ public class ModelHyperParamEntity { @Column(name = "m3_use_cnt") private Long m3UseCnt = 0L; + @Column(name = "model_type") + @Enumerated(EnumType.STRING) + private ModelType modelType; + + + @Column(name = "default_param") + private Boolean isDefault = false; + public HyperParamDto.Basic toDto() { return new HyperParamDto.Basic( + this.modelType, this.uuid, this.hyperVer, this.createdDttm, @@ -385,6 +395,8 @@ public class ModelHyperParamEntity { // ------------------------- this.gpuCnt, this.gpuIds, - this.masterPort); + this.masterPort + , this.isDefault + ); } } diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepositoryCustom.java b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepositoryCustom.java index b50511b..fc06f23 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepositoryCustom.java @@ -1,6 +1,8 @@ package com.kamco.cd.training.postgres.repository.hyperparam; +import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.hyperparam.dto.HyperParamDto; +import com.kamco.cd.training.hyperparam.dto.HyperParamDto.SearchReq; import com.kamco.cd.training.postgres.entity.ModelHyperParamEntity; import java.util.Optional; import java.util.UUID; @@ -13,11 +15,22 @@ public interface HyperParamRepositoryCustom { * * @return */ + @Deprecated Optional findHyperParamVer(); + /** + * 모델 타입별 마지막 버전 조회 + * + * @param modelType 모델 타입 + * @return + */ + Optional findHyperParamVerByModelType(ModelType modelType); + Optional findHyperParamByHyperVer(String hyperVer); Optional findHyperParamByUuid(UUID uuid); - Page findByHyperVerList(HyperParamDto.SearchReq req); + Page findByHyperVerList(ModelType model, SearchReq req); + + Optional getHyperparamByType(ModelType modelType); } diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepositoryImpl.java b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepositoryImpl.java index 7a2949d..eed1036 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepositoryImpl.java @@ -2,8 +2,10 @@ package com.kamco.cd.training.postgres.repository.hyperparam; import static com.kamco.cd.training.postgres.entity.QModelHyperParamEntity.modelHyperParamEntity; +import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.hyperparam.dto.HyperParamDto; import com.kamco.cd.training.hyperparam.dto.HyperParamDto.HyperType; +import com.kamco.cd.training.hyperparam.dto.HyperParamDto.SearchReq; import com.kamco.cd.training.postgres.entity.ModelHyperParamEntity; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Projections; @@ -41,6 +43,23 @@ public class HyperParamRepositoryImpl implements HyperParamRepositoryCustom { .fetchOne()); } + @Override + public Optional findHyperParamVerByModelType(ModelType modelType) { + + return Optional.ofNullable( + queryFactory + .select(modelHyperParamEntity) + .from(modelHyperParamEntity) + .where( + modelHyperParamEntity + .delYn + .isFalse() + .and(modelHyperParamEntity.modelType.eq(modelType))) + .orderBy(modelHyperParamEntity.hyperVer.desc()) + .limit(1) + .fetchOne()); + } + @Override public Optional findHyperParamByHyperVer(String hyperVer) { @@ -68,10 +87,11 @@ public class HyperParamRepositoryImpl implements HyperParamRepositoryCustom { } @Override - public Page findByHyperVerList(HyperParamDto.SearchReq req) { + public Page findByHyperVerList(ModelType model, SearchReq req) { Pageable pageable = req.toPageable(); BooleanBuilder builder = new BooleanBuilder(); + builder.and(modelHyperParamEntity.modelType.eq(model)); builder.and(modelHyperParamEntity.delYn.isFalse()); if (req.getHyperVer() != null && !req.getHyperVer().isEmpty()) { @@ -161,4 +181,14 @@ public class HyperParamRepositoryImpl implements HyperParamRepositoryCustom { return new PageImpl<>(content, pageable, totalCount); } + + @Override + public Optional getHyperparamByType(ModelType modelType) { + return Optional.ofNullable( + queryFactory + .select(modelHyperParamEntity) + .from(modelHyperParamEntity) + .where(modelHyperParamEntity.delYn.isFalse().and(modelHyperParamEntity.modelType.eq(modelType))) + .fetchOne()); + } } diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 39f8aec..2668b13 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -4,7 +4,7 @@ spring: on-profile: prod jpa: - show-sql: false + show-sql: true hibernate: ddl-auto: validate properties: @@ -12,41 +12,43 @@ spring: default_batch_fetch_size: 100 # ✅ 성능 - N+1 쿼리 방지 order_updates: true # ✅ 성능 - 업데이트 순서 정렬로 데드락 방지 use_sql_comments: true # ⚠️ 선택 - SQL에 주석 추가 (디버깅용) + format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성) datasource: - url: jdbc:postgresql://10.100.0.10:25432/temp - username: temp - password: temp123! + url: jdbc:postgresql://127.0.01:15432/kamco_training_db + # url: jdbc:postgresql://localhost:15432/kamco_training_db + username: kamco_training_user + password: kamco_training_user_2025_!@# hikari: minimum-idle: 10 maximum-pool-size: 20 + connection-timeout: 60000 # 60초 연결 타임아웃 + idle-timeout: 300000 # 5분 유휴 타임아웃 + max-lifetime: 1800000 # 30분 최대 수명 + leak-detection-threshold: 60000 # 연결 누수 감지 + + transaction: + default-timeout: 300 # 5분 트랜잭션 타임아웃 jwt: - secret: "kamco_token_prod_dfc6446d-68fc-4eba-a2ff-c80a14a0bf3a" + secret: "kamco_token_dev_dfc6446d-68fc-4eba-a2ff-c80a14a0bf3a" access-token-validity-in-ms: 86400000 # 1일 refresh-token-validity-in-ms: 604800000 # 7일 token: refresh-cookie-name: kamco # 개발용 쿠키 이름 - refresh-cookie-secure: true # 로컬 http 테스트면 false + refresh-cookie-secure: false # 로컬 http 테스트면 false + +springdoc: + swagger-ui: + persist-authorization: true # 스웨거 새로고침해도 토큰 유지, 로컬스토리지에 저장 member: init_password: kamco1234! -swagger: - local-port: 9080 - -file: - sync-root-dir: /app/original-images/ - sync-tmp-dir: ${file.sync-root-dir}tmp/ - sync-file-extention: tfw,tif - - dataset-dir: /home/kcomu/data/request/ - dataset-tmp-dir: ${file.dataset-dir}tmp/ - train: docker: - image: "kamco-cd-train:love_latest" + image: "kamco-cd-train:latest" requestDir: "/home/kcomu/data/request" responseDir: "/home/kcomu/data/response" containerPrefix: "kamco-cd-train" diff --git a/src/main/resources/db/migration/dump-kamco_training_db-202512261611.sql b/src/main/resources/db/migration/dump-kamco_training_db-202512261611.sql index 16b5869..226df24 100644 --- a/src/main/resources/db/migration/dump-kamco_training_db-202512261611.sql +++ b/src/main/resources/db/migration/dump-kamco_training_db-202512261611.sql @@ -9667,7 +9667,7 @@ INSERT INTO public.tb_audit_log VALUES (1813, 3, 'CREATE', 'SUCCESS', 'SYSTEM', INSERT INTO public.tb_audit_log VALUES (1814, 3, 'READ', 'SUCCESS', 'SYSTEM', '127.0.0.1', NULL, '2025-12-26 00:44:49.832926+00', NULL, '', '/api/models/train'); INSERT INTO public.tb_audit_log VALUES (1815, NULL, 'CREATE', 'FAILED', 'SYSTEM', '127.0.0.1', NULL, '2025-12-26 00:53:40.899603+00', 467, '{ "username": "1234567", - "password":"****" + "password":"****" }', '/api/auth/signin'); INSERT INTO public.tb_audit_log VALUES (1816, NULL, 'CREATE', 'SUCCESS', 'SYSTEM', '127.0.0.1', NULL, '2025-12-26 00:55:27.731595+00', NULL, '{ "username": "1234567", @@ -30396,6 +30396,8 @@ ALTER TABLE ONLY public.tb_menu ADD CONSTRAINT fksw914diut87r7lfykekc7xm2a FOREIGN KEY (parent_menu_uid) REFERENCES public.tb_menu(menu_uid); + + -- Completed on 2025-12-26 16:11:11 KST -- @@ -30404,3 +30406,5 @@ ALTER TABLE ONLY public.tb_menu \unrestrict IYrUYfSgA4Fo2gubHcb84jDXfbBZEIiOZnyLtZgnMi641GaRQa5QDogarpTr7IG + +