From 86016da5f49cb5c1885eb6de47629adf5709dd0e Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Mon, 20 Jul 2026 19:09:12 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B6=84=EB=A5=98=20=ED=95=98=EC=9D=B4?= =?UTF-8?q?=ED=8D=BC=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D,=EC=83=81=EC=84=B8,=EB=93=B1=EB=A1=9D,=EC=88=98?= =?UTF-8?q?=EC=A0=95,=EC=82=AD=EC=A0=9C=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cd/training/common/dto/HyperClsParam.java | 75 +++++++ .../cd/training/common/enums/ModelType.java | 3 +- .../HyperClsParamApiController.java | 184 ++++++++++++++++ .../hyperparam/dto/HyperClsParamDto.java | 128 +++++++++++ .../service/HyperClsParamService.java | 78 +++++++ .../core/HyperClsParamCoreService.java | 189 ++++++++++++++++ .../entity/ModelHyperClsParamEntity.java | 177 +++++++++++++++ .../hyperparam/HyperClsParamRepository.java | 9 + .../HyperClsParamRepositoryCustom.java | 63 ++++++ .../HyperClsParamRepositoryImpl.java | 203 ++++++++++++++++++ 10 files changed, 1108 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/kamco/cd/training/common/dto/HyperClsParam.java create mode 100644 src/main/java/com/kamco/cd/training/hyperparam/HyperClsParamApiController.java create mode 100644 src/main/java/com/kamco/cd/training/hyperparam/dto/HyperClsParamDto.java create mode 100644 src/main/java/com/kamco/cd/training/hyperparam/service/HyperClsParamService.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/core/HyperClsParamCoreService.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/entity/ModelHyperClsParamEntity.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepository.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepositoryCustom.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepositoryImpl.java diff --git a/src/main/java/com/kamco/cd/training/common/dto/HyperClsParam.java b/src/main/java/com/kamco/cd/training/common/dto/HyperClsParam.java new file mode 100644 index 0000000..4f0267b --- /dev/null +++ b/src/main/java/com/kamco/cd/training/common/dto/HyperClsParam.java @@ -0,0 +1,75 @@ +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; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class HyperClsParam { + + @Schema(description = "모델", example = "CLS") + private ModelType model; // G1, G2, G3, G4, CLS + + // ------------------------- + // Model + // ------------------------- + + @Schema(description = "입력 이미지 크기", example = "256") + private String inputSize; // input_size + + @Schema(description = "배치 크기(Per GPU)", example = "64") + private Integer batchSize; // batch_size + + @Schema(description = "워커 수", example = "16") + private Integer workers; // batch_size + + // ------------------------- + // Augmentation + // ------------------------- + @Schema(description = "scale", example = "0.5") + private Double scale; + + @Schema(description = "translate", example = "0.1") + private Double translate; + + @Schema(description = "fliplr", example = "0.5") + private Double fliplr; + + @Schema(description = "flipud", example = "0.5") + private Double flipud; + + @Schema(description = "erasing") + private Double erasing; + + @Schema(description = "mixup", example = "0.1") + private Double mixup; + + @Schema(description = "hsv_h") + private Double hsvH; + + @Schema(description = "hsv_s") + private Double hsvS; + + @Schema(description = "hsv_v") + private Double hsvV; + + @Schema(description = "dropout") + private Double dropout; + + @Schema(description = "label_smoothing") + private Double labelSmoothing; + + // ------------------------- + // Memo + // ------------------------- + @Schema(description = "메모", example = "하이퍼파라미터 신규등록") + private String memo; // memo + + private Boolean isDefault = false; +} 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 5f9a0bf..f5d823d 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 @@ -13,7 +13,8 @@ public enum ModelType implements EnumType { G1("G1"), G2("G2"), G3("G3"), - G4("G4"); + G4("G4"), + CLS("CLS"); private String desc; diff --git a/src/main/java/com/kamco/cd/training/hyperparam/HyperClsParamApiController.java b/src/main/java/com/kamco/cd/training/hyperparam/HyperClsParamApiController.java new file mode 100644 index 0000000..57554b4 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/hyperparam/HyperClsParamApiController.java @@ -0,0 +1,184 @@ +package com.kamco.cd.training.hyperparam; + +import com.kamco.cd.training.common.dto.HyperClsParam; +import com.kamco.cd.training.common.enums.ModelType; +import com.kamco.cd.training.config.api.ApiResponseDto; +import com.kamco.cd.training.hyperparam.dto.HyperClsParamDto; +import com.kamco.cd.training.hyperparam.dto.HyperParamDto; +import com.kamco.cd.training.hyperparam.dto.HyperParamDto.List; +import com.kamco.cd.training.hyperparam.service.HyperClsParamService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import java.time.LocalDate; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "분류 하이퍼파라미터 관리", description = "분류 하이퍼파라미터 관리 API") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/hyper-param/cls") +public class HyperClsParamApiController { + + private final HyperClsParamService hyperClsParamService; + + @Operation(summary = "하이퍼파라미터 등록", description = "파라미터를 신규 저장") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "등록 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PostMapping + public ApiResponseDto createHyperParam(@Valid @RequestBody HyperClsParam createReq) { + String newVersion = hyperClsParamService.createHyperParam(createReq); + return ApiResponseDto.ok(newVersion); + } + + @Operation(summary = "하이퍼파라미터 수정", description = "파라미터를 수정") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "등록 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content), + @ApiResponse(responseCode = "422", description = "default는 삭제불가", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PutMapping("/{uuid}") + public ApiResponseDto updateHyperParam( + @PathVariable UUID uuid, @Valid @RequestBody HyperClsParam createReq) { + return ApiResponseDto.ok(hyperClsParamService.updateHyperParam(uuid, createReq)); + } + + @Operation(summary = "하이퍼파라미터 목록 조회", description = "하이퍼파라미터 목록 조회") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Page.class))), + @ApiResponse(responseCode = "404", description = "하이퍼파라미터를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/list") + public ApiResponseDto> getHyperParam( + @Parameter( + description = "구분 CREATE_DATE(생성일), LAST_USED_DATE(최근사용일)", + example = "CREATE_DATE") + @RequestParam(required = false) + String type, + @Parameter(description = "시작일", example = "2026-07-01") @RequestParam(required = false) + LocalDate startDate, + @Parameter(description = "종료일", example = "2026-12-31") @RequestParam(required = false) + LocalDate endDate, + @Parameter(description = "버전명", example = "CLS_000001") @RequestParam(required = false) + String hyperVer, + @Parameter(description = "모델 타입 (G1, G2, G3, G4, CLS 중 하나)", example = "CLS") + @RequestParam(required = false) + ModelType model, + @Parameter( + description = "정렬", + example = "createdDttm desc", + schema = + @Schema( + allowableValues = { + "createdDttm,desc", + "lastUsedDttm,desc", + "totalUseCnt,desc" + })) + @RequestParam(required = false) + String sort, + @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0") + int page, + @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20") + int size) { + HyperParamDto.SearchReq searchReq = new HyperParamDto.SearchReq(); + searchReq.setType(type); + searchReq.setStartDate(startDate); + searchReq.setEndDate(endDate); + searchReq.setHyperVer(hyperVer); + searchReq.setSort(sort); + searchReq.setPage(page); + searchReq.setSize(size); + Page list = hyperClsParamService.getHyperParamList(model, searchReq); + + return ApiResponseDto.ok(list); + } + + @Operation(summary = "하이퍼파라미터 삭제", description = "하이퍼파라미터 삭제") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "삭제 성공", content = @Content), + @ApiResponse(responseCode = "422", description = "default 삭제 불가", content = @Content), + @ApiResponse(responseCode = "404", description = "하이퍼파라미터를 찾을 수 없음", content = @Content), + }) + @DeleteMapping("/{uuid}") + public ApiResponseDto deleteHyperParam( + @Parameter(description = "하이퍼파라미터 uuid", example = "57fc9170-64c1-4128-aa7b-0657f08d6d10") + @PathVariable + UUID uuid) { + hyperClsParamService.deleteHyperParam(uuid); + return ApiResponseDto.ok(null); + } + + @Operation(summary = "하이퍼파라미터 상세 조회", description = "특정 버전의 하이퍼파라미터 상세 정보를 조회합니다") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = HyperParamDto.Basic.class))), + @ApiResponse(responseCode = "404", description = "하이퍼파라미터를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/{uuid}") + public ApiResponseDto getHyperParam( + @Parameter(description = "하이퍼파라미터 uuid", example = "57fc9170-64c1-4128-aa7b-0657f08d6d10") + @PathVariable + UUID uuid) { + return ApiResponseDto.ok(hyperClsParamService.getHyperParam(uuid)); + } + + @Operation(summary = "하이퍼파라미터 최적화 값 조회", description = "하이퍼파라미터 최적화 값 조회 API") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Page.class))), + @ApiResponse(responseCode = "404", description = "하이퍼파라미터를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/init/{model}") + public ApiResponseDto getInitHyperParam(@PathVariable ModelType model) { + + return ApiResponseDto.ok(hyperClsParamService.getInitHyperParam(model)); + } +} diff --git a/src/main/java/com/kamco/cd/training/hyperparam/dto/HyperClsParamDto.java b/src/main/java/com/kamco/cd/training/hyperparam/dto/HyperClsParamDto.java new file mode 100644 index 0000000..119abd1 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/hyperparam/dto/HyperClsParamDto.java @@ -0,0 +1,128 @@ +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; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; + +public class HyperClsParamDto { + + @Schema(name = "Basic", description = "하이퍼파라미터 조회") + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class Basic { + + private ModelType model; // 20250212 modeltype추가 + private UUID uuid; + private String hyperVer; + @JsonFormatDttm private ZonedDateTime createdDttm; + @JsonFormatDttm private ZonedDateTime lastUsedDttm; + private Integer totalUseCnt; + + // ------------------------- + // Model + // ------------------------- + private String inputSize; + private Integer batchSize; + private Integer workers; + + // ------------------------- + // Augmentation + // ------------------------- + private Double scale; + private Double translate; + private Double fliplr; + private Double flipud; + private Double erasing; + private Double mixup; + private Double hsvH; + private Double hsvS; + private Double hsvV; + private Double dropout; + private Double labelSmoothing; + + // ------------------------- + // Memo + // ------------------------- + private String memo; + + // ------------------------- + // Hardware + // ------------------------- + private Boolean isDefault; + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class List { + private UUID uuid; + private ModelType model; + private String hyperVer; + @JsonFormatDttm private ZonedDateTime createDttm; + @JsonFormatDttm private ZonedDateTime lastUsedDttm; + private String memo; + private Integer totalUseCnt; + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class SearchReq { + private String type; + private LocalDate startDate; + private LocalDate endDate; + private String hyperVer; + + // 페이징 파라미터 + private int page = 0; + private int size = 20; + private String sort; + + public Pageable toPageable() { + if (sort != null && !sort.isEmpty()) { + String[] sortParams = sort.split(","); + String property = sortParams[0]; + Sort.Direction direction = + sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC; + return PageRequest.of(page, size, Sort.by(direction, property)); + } + return PageRequest.of(page, size); + } + } + + @CodeExpose + @Getter + @AllArgsConstructor + public enum HyperType implements EnumType { + CREATE_DATE("생성일"), + LAST_USED_DATE("최근 사용일"); + + private final String desc; + + @Override + public String getId() { + return name(); + } + + @Override + public String getText() { + return desc; + } + } +} diff --git a/src/main/java/com/kamco/cd/training/hyperparam/service/HyperClsParamService.java b/src/main/java/com/kamco/cd/training/hyperparam/service/HyperClsParamService.java new file mode 100644 index 0000000..901a2fd --- /dev/null +++ b/src/main/java/com/kamco/cd/training/hyperparam/service/HyperClsParamService.java @@ -0,0 +1,78 @@ +package com.kamco.cd.training.hyperparam.service; + +import com.kamco.cd.training.common.dto.HyperClsParam; +import com.kamco.cd.training.common.enums.ModelType; +import com.kamco.cd.training.hyperparam.dto.HyperClsParamDto; +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.HyperClsParamCoreService; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class HyperClsParamService { + + private final HyperClsParamCoreService hyperClsParamCoreService; + + /** + * 하이퍼 파라미터 목록 조회 + * + * @param model + * @param req + * @return 목록 + */ + public Page getHyperParamList(ModelType model, SearchReq req) { + return hyperClsParamCoreService.findByHyperVerList(model, req); + } + + /** + * 하이퍼파라미터 등록 + * + * @param createReq 등록 요청 + * @return 생성된 버전명 + */ + @Transactional + public String createHyperParam(HyperClsParam createReq) { + return hyperClsParamCoreService.createHyperParam(createReq).getHyperVer(); + } + + /** + * 하이퍼파라미터 수정 + * + * @param createReq + * @return + */ + @Transactional + public String updateHyperParam(UUID uuid, HyperClsParam createReq) { + return hyperClsParamCoreService.updateHyperParam(uuid, createReq); + } + + /** + * 하이퍼파라미터 삭제 + * + * @param uuid + */ + public void deleteHyperParam(UUID uuid) { + hyperClsParamCoreService.deleteHyperParam(uuid); + } + + /** 하이퍼파라미터 최적화 설정값 조회 */ + public HyperClsParamDto.Basic getInitHyperParam(ModelType model) { + return hyperClsParamCoreService.getInitHyperParam(model); + } + + /** + * 하이퍼파라미터 상세 조회 + * + * @param uuid + * @return + */ + public HyperClsParamDto.Basic getHyperParam(UUID uuid) { + return hyperClsParamCoreService.getHyperParam(uuid); + } +} diff --git a/src/main/java/com/kamco/cd/training/postgres/core/HyperClsParamCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/HyperClsParamCoreService.java new file mode 100644 index 0000000..aaf8e9b --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/core/HyperClsParamCoreService.java @@ -0,0 +1,189 @@ +package com.kamco.cd.training.postgres.core; + +import com.kamco.cd.training.common.dto.HyperClsParam; +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.HyperClsParamDto; +import com.kamco.cd.training.hyperparam.dto.HyperParamDto; +import com.kamco.cd.training.hyperparam.dto.HyperParamDto.SearchReq; +import com.kamco.cd.training.postgres.entity.ModelHyperClsParamEntity; +import com.kamco.cd.training.postgres.repository.hyperparam.HyperClsParamRepository; +import java.time.ZonedDateTime; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class HyperClsParamCoreService { + + private final HyperClsParamRepository hyperClsParamRepository; + private final UserUtil userUtil; + + /** + * 하이퍼파라미터 등록 + * + * @param createReq ModelTrainMngDto.HyperParamDto + * @return 등록된 버전명 + */ + public HyperClsParamDto.Basic createHyperParam(HyperClsParam createReq) { + String firstVersion = getFirstHyperParamVersion(createReq.getModel()); + + ModelHyperClsParamEntity entity = new ModelHyperClsParamEntity(); + entity.setHyperVer(firstVersion); + applyHyperParam(entity, createReq); + + // user + entity.setCreatedUid(userUtil.getId()); + + ModelHyperClsParamEntity resultEntity = hyperClsParamRepository.save(entity); + HyperClsParamDto.Basic basic = new HyperClsParamDto.Basic(); + basic.setUuid(resultEntity.getUuid()); + basic.setHyperVer(resultEntity.getHyperVer()); + return basic; + } + + /** + * 하이퍼파라미터 수정 + * + * @param uuid uuid + * @param createReq 등록 요청 + * @return ver + */ + public String updateHyperParam(UUID uuid, HyperClsParam createReq) { + ModelHyperClsParamEntity entity = + hyperClsParamRepository + .findHyperParamByUuid(uuid) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + + if (entity.getIsDefault()) { + throw new CustomApiException("UNPROCESSABLE_ENTITY_UPDATE", HttpStatus.UNPROCESSABLE_ENTITY); + } + applyHyperParam(entity, createReq); + + // user + entity.setUpdatedUid(userUtil.getId()); + entity.setUpdatedDttm(ZonedDateTime.now()); + + return entity.getHyperVer(); + } + + /** + * 하이퍼파라미터 삭제 + * + * @param uuid + */ + public void deleteHyperParam(UUID uuid) { + ModelHyperClsParamEntity entity = + hyperClsParamRepository + .findHyperParamByUuid(uuid) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + + // 디폴트면 삭제불가 + if (entity.getIsDefault()) { + throw new CustomApiException("UNPROCESSABLE_ENTITY", HttpStatus.UNPROCESSABLE_ENTITY); + } + + entity.setDelYn(true); + entity.setUpdatedUid(userUtil.getId()); + entity.setUpdatedDttm(ZonedDateTime.now()); + } + + /** + * 하이퍼파라미터 최적화 설정값 조회 + * + * @return + */ + public HyperClsParamDto.Basic getInitHyperParam(ModelType model) { + ModelHyperClsParamEntity entity = + hyperClsParamRepository.getHyperParamByType(model).stream() + .filter(e -> e.getIsDefault() == Boolean.TRUE) + .findFirst() + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + return entity.toDto(); + } + + /** + * 하이퍼파라미터 상세 조회 + * + * @return + */ + public HyperClsParamDto.Basic getHyperParam(UUID uuid) { + ModelHyperClsParamEntity entity = + hyperClsParamRepository + .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 hyperClsParamRepository.findByHyperVerList(model, req); + } + + /** + * 하이퍼파라미터 버전 조회 + * + * @param model 모델 타입 + * @return ver + */ + public String getFirstHyperParamVersion(ModelType model) { + return hyperClsParamRepository + .findHyperParamVerByModelType(model) + .map(ModelHyperClsParamEntity::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(ModelHyperClsParamEntity entity, HyperClsParam src) { + + ModelType model = src.getModel(); + + entity.setInputSize(src.getInputSize()); + + // Model + entity.setModelType(model); + entity.setInputSize(src.getInputSize()); + entity.setBatchSize(src.getBatchSize()); + entity.setInputSize(src.getInputSize()); + + // Argument + entity.setScale(src.getScale()); + entity.setTranslate(src.getTranslate()); + entity.setFliplr(src.getFliplr()); + entity.setFlipud(src.getFlipud()); + entity.setErasing(src.getErasing()); + entity.setMixup(src.getMixup()); + entity.setHsvH(src.getHsvH()); + entity.setHsvS(src.getHsvS()); + entity.setHsvV(src.getHsvV()); + entity.setDropout(src.getDropout()); + entity.setLabelSmoothing(src.getLabelSmoothing()); + + // memo + entity.setMemo(src.getMemo()); + entity.setIsDefault(src.getIsDefault()); + } +} diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelHyperClsParamEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelHyperClsParamEntity.java new file mode 100644 index 0000000..07040cb --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelHyperClsParamEntity.java @@ -0,0 +1,177 @@ +package com.kamco.cd.training.postgres.entity; + +import com.kamco.cd.training.common.enums.ModelType; +import com.kamco.cd.training.hyperparam.dto.HyperClsParamDto; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.ZonedDateTime; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.UuidGenerator; + +@Getter +@Setter +@Entity +@Table( + name = "tb_model_cls_hyper_params", + indexes = {@Index(name = "idx_hyper_cls_params_hyper_ver", columnList = "hyper_ver")}) +public class ModelHyperClsParamEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "hyper_param_id", nullable = false) + private Long id; + + @NotNull + @UuidGenerator + @Column(name = "uuid", nullable = false, updatable = false) + private UUID uuid = UUID.randomUUID(); + + @Size(max = 50) + @NotNull + @Column(name = "hyper_ver", nullable = false, length = 50) + private String hyperVer; + + // ------------------------- + // Important (Default 반영) + // ------------------------- + + /** Choices: 256,256 or 512,512. Default: 256,256 */ + @Size(max = 15) + @NotNull + @Column(name = "input_size", nullable = false, length = 15) + private String inputSize = "256,256"; + + /** Range: >=1. Default: 16 (per GPU) */ + @NotNull + @Column(name = "batch_size", nullable = false) + private Integer batchSize = 16; + + /** Range: >=1. Default: 16 */ + @NotNull + @Column(name = "workers", nullable = false) + private Integer workers = 16; + + // ------------------------- + // Augmentation (Default 반영) + // ------------------------- + + @Column(name = "scale") + private Double scale = 0.5; + + @Column(name = "translate") + private Double translate = 0.1; + + @Column(name = "fliplr") + private Double fliplr = 0.5; + + @Column(name = "flipud") + private Double flipud = 0.5; + + @Column(name = "erasing") + private Double erasing; + + @Column(name = "mixup") + private Double mixup = 0.1; + + @Column(name = "hsv_h") + private Double hsvH; + + @Column(name = "hsv_s") + private Double hsvS; + + @Column(name = "hsv_v") + private Double hsvV; + + @Column(name = "dropout") + private Double dropout; + + @Column(name = "label_smoothing") + private Double labelSmoothing; + + // ------------------------- + // Common + // ------------------------- + + @Column(name = "memo") + private String memo; + + @NotNull + @ColumnDefault("false") + @Column(name = "del_yn", nullable = false, length = 1) + private Boolean delYn = false; + + @NotNull + @ColumnDefault("CURRENT_TIMESTAMP") + @Column(name = "created_dttm", nullable = false) + private ZonedDateTime createdDttm = ZonedDateTime.now(); + + @NotNull + @Column(name = "created_uid", nullable = false) + private Long createdUid; + + @ColumnDefault("CURRENT_TIMESTAMP") + @Column(name = "updated_dttm") + private ZonedDateTime updatedDttm; + + @Column(name = "updated_uid") + private Long updatedUid; + + @ColumnDefault("CURRENT_TIMESTAMP") + @Column(name = "last_used_dttm") + private ZonedDateTime lastUsedDttm; + + @Column(name = "model_type") + @Enumerated(EnumType.STRING) + private ModelType modelType; + + @Column(name = "default_param") + private Boolean isDefault = false; + + @Column(name = "total_use_cnt") + private Integer totalUseCnt = 0; + + public HyperClsParamDto.Basic toDto() { + return new HyperClsParamDto.Basic( + this.modelType, + this.uuid, + this.hyperVer, + this.createdDttm, + this.lastUsedDttm, + this.totalUseCnt, + // ------------------------- + // Model + // ------------------------- + this.inputSize, + this.batchSize, + this.workers, + + // ------------------------- + // Argument + // ------------------------- + this.scale, + this.translate, + this.fliplr, + this.flipud, + this.erasing, + this.mixup, + this.hsvH, + this.hsvS, + this.hsvV, + this.dropout, + this.labelSmoothing, + + // ------------------------- + // Memo + // ------------------------- + this.memo, + + // ------------------------- + // Hardware + // ------------------------- + this.isDefault); + } +} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepository.java b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepository.java new file mode 100644 index 0000000..c0eed17 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepository.java @@ -0,0 +1,9 @@ +package com.kamco.cd.training.postgres.repository.hyperparam; + +import com.kamco.cd.training.postgres.entity.ModelHyperClsParamEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface HyperClsParamRepository + extends JpaRepository, HyperClsParamRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepositoryCustom.java b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepositoryCustom.java new file mode 100644 index 0000000..26e0c4a --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepositoryCustom.java @@ -0,0 +1,63 @@ +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.ModelHyperClsParamEntity; +import com.kamco.cd.training.postgres.entity.ModelHyperParamEntity; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.domain.Page; + +public interface HyperClsParamRepositoryCustom { + + // TODO 미사용시작 + /** + * 마지막 버전 조회 + * + * @return + */ + @Deprecated + Optional findHyperParamVer(); + + // TODO 미사용 끝 + + /** + * 모델 타입별 마지막 버전 조회 + * + * @param modelType 모델 타입 + * @return + */ + Optional findHyperParamVerByModelType(ModelType modelType); + + // TODO 미사용시작 + Optional findHyperParamByHyperVer(String hyperVer); + + // TODO 미사용 끝 + + /** + * 하이퍼 파라미터 상세조회 + * + * @param uuid + * @return + */ + Optional findHyperParamByUuid(UUID uuid); + + /** + * 하이퍼 파라미터 목록 조회 + * + * @param model + * @param req + * @return + */ + Page findByHyperVerList(ModelType model, SearchReq req); + + /** + * 하이퍼 파라미터 모델타입으로 조회 + * + * @param modelType + * @return + */ + List getHyperParamByType(ModelType modelType); +} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepositoryImpl.java b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepositoryImpl.java new file mode 100644 index 0000000..1291bab --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperClsParamRepositoryImpl.java @@ -0,0 +1,203 @@ +package com.kamco.cd.training.postgres.repository.hyperparam; + +import static com.kamco.cd.training.postgres.entity.QModelHyperClsParamEntity.modelHyperClsParamEntity; +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.ModelHyperClsParamEntity; +import com.kamco.cd.training.postgres.entity.ModelHyperParamEntity; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQuery; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class HyperClsParamRepositoryImpl implements HyperClsParamRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + // TODO 미사용시작 + @Override + public Optional findHyperParamVer() { + + return Optional.ofNullable( + queryFactory + .select(modelHyperParamEntity) + .from(modelHyperParamEntity) + .where(modelHyperParamEntity.delYn.isFalse()) + .orderBy(modelHyperParamEntity.hyperVer.desc()) + .limit(1) + .fetchOne()); + } + + // TODO 미사용 끝 + + @Override + public Optional findHyperParamVerByModelType(ModelType modelType) { + + return Optional.ofNullable( + queryFactory + .select(modelHyperClsParamEntity) + .from(modelHyperClsParamEntity) + .where( + modelHyperClsParamEntity + .delYn + .isFalse() + .and(modelHyperClsParamEntity.modelType.eq(modelType))) + .orderBy(modelHyperClsParamEntity.hyperVer.desc()) + .limit(1) + .fetchOne()); + } + + // TODO 미사용시작 + @Override + public Optional findHyperParamByHyperVer(String hyperVer) { + + return Optional.ofNullable( + queryFactory + .select(modelHyperParamEntity) + .from(modelHyperParamEntity) + .where( + modelHyperParamEntity + .delYn + .isFalse() + .and(modelHyperParamEntity.hyperVer.eq(hyperVer))) + .limit(1) + .fetchOne()); + } + + // TODO 미사용 끝 + + @Override + public Optional findHyperParamByUuid(UUID uuid) { + return Optional.ofNullable( + queryFactory + .select(modelHyperClsParamEntity) + .from(modelHyperClsParamEntity) + .where(modelHyperClsParamEntity.uuid.eq(uuid)) + .fetchOne()); + } + + @Override + public Page findByHyperVerList(ModelType model, SearchReq req) { + Pageable pageable = req.toPageable(); + + BooleanBuilder builder = new BooleanBuilder(); + + builder.and(modelHyperClsParamEntity.delYn.isFalse()); + + if (model != null) { + builder.and(modelHyperClsParamEntity.modelType.eq(model)); + } + + if (req.getHyperVer() != null && !req.getHyperVer().isEmpty()) { + // 버전 + builder.and(modelHyperClsParamEntity.hyperVer.contains(req.getHyperVer())); + } + + if (req.getStartDate() != null && req.getEndDate() != null) { + + ZoneId zoneId = ZoneId.systemDefault(); + + ZonedDateTime start = req.getStartDate().atStartOfDay(zoneId); + + ZonedDateTime end = req.getEndDate().atTime(23, 59, 59).atZone(zoneId); + + if (HyperType.CREATE_DATE.getId().equals(req.getType())) { + // 생성일 + builder.and(modelHyperClsParamEntity.createdDttm.between(start, end)); + } else if (HyperType.LAST_USED_DATE.getId().equals(req.getType())) { + // 최종 사용일 + builder.and(modelHyperClsParamEntity.lastUsedDttm.between(start, end)); + } + } + + JPAQuery query = + queryFactory + .select( + Projections.constructor( + HyperParamDto.List.class, + modelHyperClsParamEntity.uuid, + modelHyperClsParamEntity.modelType.as("model"), + modelHyperClsParamEntity.hyperVer, + modelHyperClsParamEntity.createdDttm, + modelHyperClsParamEntity.lastUsedDttm, + modelHyperClsParamEntity.memo, + modelHyperClsParamEntity.totalUseCnt)) + .from(modelHyperClsParamEntity) + .where(builder); + + Sort.Order sortOrder = pageable.getSort().stream().findFirst().orElse(null); + + if (sortOrder == null) { + // 기본값 + query.orderBy(modelHyperClsParamEntity.createdDttm.desc()); + } else { + String property = sortOrder.getProperty(); + boolean asc = sortOrder.isAscending(); + + switch (property) { + case "createdDttm" -> + query.orderBy( + asc + ? modelHyperClsParamEntity.createdDttm.asc() + : modelHyperClsParamEntity.createdDttm.desc()); + + case "lastUsedDttm" -> + query.orderBy( + asc + ? modelHyperClsParamEntity.lastUsedDttm.asc() + : modelHyperClsParamEntity.lastUsedDttm.desc()); + case "totalUseCnt" -> + query.orderBy( + asc + ? modelHyperClsParamEntity.totalUseCnt.asc() + : modelHyperClsParamEntity.totalUseCnt.desc()); + + default -> query.orderBy(modelHyperClsParamEntity.createdDttm.desc()); + } + } + + List content = + query.offset(pageable.getOffset()).limit(pageable.getPageSize()).fetch(); + + Long total = + queryFactory + .select(modelHyperClsParamEntity.count()) + .from(modelHyperClsParamEntity) + .where(builder) + .fetchOne(); + + long totalCount = (total != null) ? total : 0L; + + return new PageImpl<>(content, pageable, totalCount); + } + + @Override + public List getHyperParamByType(ModelType modelType) { + return queryFactory + .select(modelHyperClsParamEntity) + .from(modelHyperClsParamEntity) + .where( + modelHyperClsParamEntity + .delYn + .isFalse() + .and(modelHyperClsParamEntity.modelType.eq(modelType))) + .fetch(); + } +}