모델관리 학습 조회 수정

This commit is contained in:
2026-02-02 19:13:18 +09:00
parent 8619ded142
commit 999e413305
5 changed files with 82 additions and 77 deletions

View File

@@ -27,7 +27,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@Tag(name = "모델관리", description = "모델관리 (학습 모델, 하이퍼파라미터, 메모)") @Tag(name = "모델관리", description = "어드민 홈 > 모델학습관리 > 모델관리 > 목록")
@RequestMapping("/api/models") @RequestMapping("/api/models")
public class ModelMngApiController { public class ModelMngApiController {
private final ModelMngService modelMngService; private final ModelMngService modelMngService;

View File

@@ -8,6 +8,7 @@ import jakarta.validation.constraints.NotNull;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
@@ -27,14 +28,16 @@ public class ModelMngDto {
public static class Basic { public static class Basic {
private Long id; private Long id;
private String modelNm; private UUID uuid;
private String modelVer;
@JsonFormatDttm private ZonedDateTime startDttm; @JsonFormatDttm private ZonedDateTime startDttm;
@JsonFormatDttm private ZonedDateTime trainingEndDttm; @JsonFormatDttm private ZonedDateTime step1EndDttm;
@JsonFormatDttm private ZonedDateTime testEndDttm; @JsonFormatDttm private ZonedDateTime step1Duration;
private String durationDttm; @JsonFormatDttm private ZonedDateTime step2EndDttm;
private String processStage; @JsonFormatDttm private ZonedDateTime step2Duration;
private String statusCd; private String step1Status;
private String status; private String step2Status;
private String transferStatus;
} }
@Schema(name = "searchReq", description = "모델 관리 목록조회 파라미터") @Schema(name = "searchReq", description = "모델 관리 목록조회 파라미터")
@@ -75,11 +78,11 @@ public class ModelMngDto {
@JsonFormatDttm private ZonedDateTime step1EndDttm; @JsonFormatDttm private ZonedDateTime step1EndDttm;
private String step1Duration; private ZonedDateTime step1Duration;
@JsonFormatDttm private ZonedDateTime step2EndDttm; @JsonFormatDttm private ZonedDateTime step2EndDttm;
private String step2Duration; private ZonedDateTime step2Duration;
private Integer progressRate; private Integer progressRate;
@JsonFormatDttm private ZonedDateTime createdDttm; @JsonFormatDttm private ZonedDateTime createdDttm;
@@ -109,11 +112,11 @@ public class ModelMngDto {
@JsonFormatDttm private ZonedDateTime step1EndDttm; @JsonFormatDttm private ZonedDateTime step1EndDttm;
private String step1Duration; private ZonedDateTime step1Duration;
@JsonFormatDttm private ZonedDateTime step2EndDttm; @JsonFormatDttm private ZonedDateTime step2EndDttm;
private String step2Duration; private ZonedDateTime step2Duration;
@JsonFormatDttm private ZonedDateTime createdDttm; @JsonFormatDttm private ZonedDateTime createdDttm;

View File

@@ -50,10 +50,8 @@ public class ModelMngCoreService {
return ModelMngDto.Detail.builder() return ModelMngDto.Detail.builder()
.uuid(entity.getUuid().toString()) .uuid(entity.getUuid().toString())
.modelVer(entity.getModelVer()) .modelVer(entity.getModelVer())
.hyperVer(entity.getHyperVer())
.epochVer(entity.getEpochVer()) .epochVer(entity.getEpochVer())
.processStep(entity.getProcessStep()) .processStep(entity.getProcessStep())
.statusCd(entity.getStatusCd())
.trainStartDttm(entity.getTrainStartDttm()) .trainStartDttm(entity.getTrainStartDttm())
.epochCnt(entity.getEpochCnt()) .epochCnt(entity.getEpochCnt())
.datasetRatio(entity.getDatasetRatio()) .datasetRatio(entity.getDatasetRatio())
@@ -97,7 +95,6 @@ public class ModelMngCoreService {
ModelMngDto.TrainListRes.builder() ModelMngDto.TrainListRes.builder()
.uuid(entity.getUuid().toString()) .uuid(entity.getUuid().toString())
.modelVer(entity.getModelVer()) .modelVer(entity.getModelVer())
.status(entity.getStatusCd())
.processStep(entity.getProcessStep()) .processStep(entity.getProcessStep())
.trainStartDttm(entity.getTrainStartDttm()) .trainStartDttm(entity.getTrainStartDttm())
.progressRate(entity.getProgressRate()) .progressRate(entity.getProgressRate())
@@ -135,10 +132,8 @@ public class ModelMngCoreService {
public ModelTrainMasterEntity createTrainMaster(ModelMngDto.TrainStartReq trainReq) { public ModelTrainMasterEntity createTrainMaster(ModelMngDto.TrainStartReq trainReq) {
ModelTrainMasterEntity entity = new ModelTrainMasterEntity(); ModelTrainMasterEntity entity = new ModelTrainMasterEntity();
entity.setModelVer(trainReq.getHyperVer()); entity.setModelVer(trainReq.getHyperVer());
entity.setHyperVer(trainReq.getHyperVer());
entity.setEpochVer(String.valueOf(trainReq.getEpoch())); entity.setEpochVer(String.valueOf(trainReq.getEpoch()));
entity.setProcessStep("STEP1"); entity.setProcessStep("STEP1");
entity.setStatusCd("READY");
entity.setTrainStartDttm(ZonedDateTime.now()); entity.setTrainStartDttm(ZonedDateTime.now());
entity.setEpochCnt(trainReq.getEpoch()); entity.setEpochCnt(trainReq.getEpoch());
entity.setDatasetRatio(trainReq.getDatasetRatio()); entity.setDatasetRatio(trainReq.getDatasetRatio());
@@ -191,9 +186,9 @@ public class ModelMngCoreService {
ModelTrainMasterEntity entity = findByUuid(uuid); ModelTrainMasterEntity entity = findByUuid(uuid);
// 진행 중인 모델은 삭제 불가 // 진행 중인 모델은 삭제 불가
if ("RUNNING".equals(entity.getStatusCd())) { // if ("RUNNING".equals(entity.getStatusCd())) {
throw new BadRequestException("진행 중인 모델은 삭제할 수 없습니다."); // throw new BadRequestException("진행 중인 모델은 삭제할 수 없습니다.");
} // }
entity.setDelYn(true); entity.setDelYn(true);
entity.setUpdatedDttm(ZonedDateTime.now()); entity.setUpdatedDttm(ZonedDateTime.now());

View File

@@ -3,10 +3,12 @@ package com.kamco.cd.training.postgres.entity;
import com.kamco.cd.training.model.dto.ModelMngDto; import com.kamco.cd.training.model.dto.ModelMngDto;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType; import jakarta.persistence.GenerationType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.PrePersist; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
@@ -16,6 +18,8 @@ import java.util.UUID;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
@Getter @Getter
@Setter @Setter
@@ -28,17 +32,14 @@ public class ModelTrainMasterEntity {
@Column(name = "model_uid", nullable = false) @Column(name = "model_uid", nullable = false)
private Long id; private Long id;
@Column(name = "uuid", columnDefinition = "uuid", nullable = false, updatable = false)
private UUID uuid;
@Size(max = 50) @Size(max = 50)
@NotNull @NotNull
@Column(name = "model_ver", nullable = false, length = 50) @Column(name = "model_ver", nullable = false, length = 50)
private String modelVer; private String modelVer;
@Size(max = 50) @ManyToOne(fetch = FetchType.LAZY)
@Column(name = "hyper_ver", length = 50) @JoinColumn(name = "hyper_ver")
private String hyperVer; private ModelHyperParamEntity hyperVer;
@Size(max = 50) @Size(max = 50)
@Column(name = "epoch_ver", length = 50) @Column(name = "epoch_ver", length = 50)
@@ -48,10 +49,6 @@ public class ModelTrainMasterEntity {
@Column(name = "process_step", length = 50) @Column(name = "process_step", length = 50)
private String processStep; private String processStep;
@Size(max = 20)
@Column(name = "status_cd", length = 20)
private String statusCd;
@Column(name = "train_start_dttm") @Column(name = "train_start_dttm")
private ZonedDateTime trainStartDttm; private ZonedDateTime trainStartDttm;
@@ -68,19 +65,18 @@ public class ModelTrainMasterEntity {
@Column(name = "step1_end_dttm") @Column(name = "step1_end_dttm")
private ZonedDateTime step1EndDttm; private ZonedDateTime step1EndDttm;
@Size(max = 50)
@Column(name = "step1_duration", length = 50) @Column(name = "step1_duration", length = 50)
private String step1Duration; private ZonedDateTime step1Duration;
@Column(name = "step2_end_dttm") @Column(name = "step2_end_dttm")
private ZonedDateTime step2EndDttm; private ZonedDateTime step2EndDttm;
@Size(max = 50)
@Column(name = "step2_duration", length = 50) @Column(name = "step2_duration", length = 50)
private String step2Duration; private ZonedDateTime step2Duration;
@NotNull
@ColumnDefault("false") @ColumnDefault("false")
@Column(name = "del_yn") @Column(name = "del_yn", nullable = false)
private Boolean delYn = false; private Boolean delYn = false;
@Column(name = "created_uid") @Column(name = "created_uid")
@@ -113,19 +109,6 @@ public class ModelTrainMasterEntity {
@Column(name = "error_msg", length = Integer.MAX_VALUE) @Column(name = "error_msg", length = Integer.MAX_VALUE)
private String errorMsg; private String errorMsg;
// ==================== Resume Training (학습 재시작) ====================
@Column(name = "last_checkpoint_epoch")
private Integer lastCheckpointEpoch;
@Size(max = 500)
@Column(name = "checkpoint_path", length = 500)
private String checkpointPath;
@ColumnDefault("false")
@Column(name = "can_resume")
private Boolean canResume = false;
@Column(name = "step2_start_dttm") @Column(name = "step2_start_dttm")
private Instant step2StartDttm; private Instant step2StartDttm;
@@ -136,35 +119,60 @@ public class ModelTrainMasterEntity {
@Column(name = "memo", length = Integer.MAX_VALUE) @Column(name = "memo", length = Integer.MAX_VALUE)
private String memo; private String memo;
@Column(name = "base_model_uid") @ManyToOne(fetch = FetchType.LAZY)
private Integer baseModelUid; @OnDelete(action = OnDeleteAction.SET_NULL)
@JoinColumn(name = "base_model_uid")
private ModelTrainMasterEntity baseModelUid;
@Size(max = 1000) @Size(max = 1000)
@Column(name = "pretrained_model_path", length = 1000) @Column(name = "pretrained_model_path", length = 1000)
private String pretrainedModelPath; private String pretrainedModelPath;
@PrePersist @Column(name = "last_checkpoint_epoch")
public void prePersist() { private Integer lastCheckpointEpoch;
if (this.uuid == null) {
this.uuid = UUID.randomUUID(); @Size(max = 500)
} @ColumnDefault("NULL")
} @Column(name = "checkpoint_path", length = 500)
private String checkpointPath;
@ColumnDefault("false")
@Column(name = "can_resume")
private Boolean canResume;
@NotNull
@ColumnDefault("uuid_generate_v4()")
@Column(name = "uuid", nullable = false)
private UUID uuid;
@Size(max = 10)
@Column(name = "step1_status", length = 10)
private String step1Status;
@Size(max = 10)
@Column(name = "step2_status", length = 10)
private String step2Status;
@Size(max = 10)
@Column(name = "transfer_status", length = 10)
private String transferStatus;
@Size(max = 10)
@Column(name = "status_cd", length = 10)
private String statusCd;
public ModelMngDto.Basic toDto() { public ModelMngDto.Basic toDto() {
ModelMngDto.Basic dto = new ModelMngDto.Basic(); return new ModelMngDto.Basic(
dto.setId(this.id); this.id,
dto.setModelNm(this.modelVer); this.uuid,
dto.setStartDttm(this.trainStartDttm); this.modelVer,
dto.setTrainingEndDttm(this.step1EndDttm); this.trainStartDttm,
dto.setTestEndDttm(this.step2EndDttm); this.step1EndDttm,
dto.setDurationDttm(this.step2Duration); this.step1Duration,
dto.setProcessStage(this.processStep); this.step2EndDttm,
dto.setStatusCd(this.statusCd); this.step2Duration,
return dto; this.step1Status,
} this.step2Status,
this.transferStatus);
/** UUID 필드가 제대로 설정되었는지 확인 (디버그용) */
public String getUuidString() {
return this.uuid != null ? this.uuid.toString() : null;
} }
} }

View File

@@ -8,7 +8,6 @@ import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@@ -31,10 +30,10 @@ public class ModelMngRepositoryImpl implements ModelMngRepositoryCustom {
public Page<ModelTrainMasterEntity> findByModels(ModelMngDto.SearchReq searchReq) { public Page<ModelTrainMasterEntity> findByModels(ModelMngDto.SearchReq searchReq) {
Pageable pageable = searchReq.toPageable(); Pageable pageable = searchReq.toPageable();
BooleanBuilder builder = new BooleanBuilder(); BooleanBuilder builder = new BooleanBuilder();
//
if (StringUtils.isNotBlank(searchReq.getStatus())) { // if (StringUtils.isNotBlank(searchReq.getStatus())) {
builder.and(modelMng.statusCd.eq(searchReq.getStatus())); // builder.and(modelMng.statusCd.eq(searchReq.getStatus()));
} // }
// Entity 직접 조회 (Projections 사용 지양) // Entity 직접 조회 (Projections 사용 지양)
List<ModelTrainMasterEntity> content = List<ModelTrainMasterEntity> content =