11 Commits

17 changed files with 292 additions and 87 deletions

View File

@@ -14,7 +14,7 @@ import lombok.Setter;
public class HyperParam { public class HyperParam {
@Schema(description = "모델", example = "G1") @Schema(description = "모델", example = "G1")
private ModelType model; // G1, G2, G3 private ModelType model; // G1, G2, G3, G4
// ------------------------- // -------------------------
// Important // Important

View File

@@ -12,7 +12,8 @@ import lombok.Getter;
public enum ModelType implements EnumType { public enum ModelType implements EnumType {
G1("G1"), G1("G1"),
G2("G2"), G2("G2"),
G3("G3"); G3("G3"),
G4("G4");
private String desc; private String desc;

View File

@@ -254,6 +254,7 @@ public class DatasetDto {
private Long wasteCnt; private Long wasteCnt;
private Long landCoverCnt; private Long landCoverCnt;
private Integer solarPanelCnt;
public SelectDataSet( public SelectDataSet(
String modelNo, String modelNo,
@@ -308,6 +309,29 @@ public class DatasetDto {
this.containerCnt = containerCnt; this.containerCnt = containerCnt;
} }
public SelectDataSet(
String modelNo,
Long datasetId,
UUID uuid,
String dataType,
String title,
Long roundNo,
Integer compareYyyy,
Integer targetYyyy,
String memo,
Integer solarPanelCnt) {
this.datasetId = datasetId;
this.uuid = uuid;
this.dataType = dataType;
this.dataTypeName = getDataTypeName(dataType);
this.title = title;
this.roundNo = roundNo;
this.compareYyyy = compareYyyy;
this.targetYyyy = targetYyyy;
this.memo = memo;
this.solarPanelCnt = solarPanelCnt;
}
public String getDataTypeName(String groupTitleCd) { public String getDataTypeName(String groupTitleCd) {
LearnDataType type = Enums.fromId(LearnDataType.class, groupTitleCd); LearnDataType type = Enums.fromId(LearnDataType.class, groupTitleCd);
return type == null ? null : type.getText(); return type == null ? null : type.getText();

View File

@@ -101,7 +101,7 @@ public class HyperParamApiController {
LocalDate endDate, LocalDate endDate,
@Parameter(description = "버전명", example = "G1_000019") @RequestParam(required = false) @Parameter(description = "버전명", example = "G1_000019") @RequestParam(required = false)
String hyperVer, String hyperVer,
@Parameter(description = "모델 타입 (G1, G2, G3 중 하나)", example = "G1") @Parameter(description = "모델 타입 (G1, G2, G3, G4 중 하나)", example = "G1")
@RequestParam(required = false) @RequestParam(required = false)
ModelType model, ModelType model,
@Parameter( @Parameter(

View File

@@ -1,6 +1,7 @@
package com.kamco.cd.training.model; package com.kamco.cd.training.model;
import com.kamco.cd.training.common.dto.MonitorDto; import com.kamco.cd.training.common.dto.MonitorDto;
import com.kamco.cd.training.common.enums.ModelType;
import com.kamco.cd.training.common.service.SystemMonitorService; import com.kamco.cd.training.common.service.SystemMonitorService;
import com.kamco.cd.training.config.api.ApiResponseDto; import com.kamco.cd.training.config.api.ApiResponseDto;
import com.kamco.cd.training.dataset.dto.DatasetDto; import com.kamco.cd.training.dataset.dto.DatasetDto;
@@ -68,7 +69,7 @@ public class ModelTrainMngApiController {
@Parameter( @Parameter(
description = "모델", description = "모델",
example = "G1", example = "G1",
schema = @Schema(allowableValues = {"G1", "G2", "G3"})) schema = @Schema(allowableValues = {"G1", "G2", "G3", "G4"}))
@RequestParam(required = false) @RequestParam(required = false)
String modelNo, String modelNo,
@Parameter(description = "페이지 번호") @RequestParam(defaultValue = "0") int page, @Parameter(description = "페이지 번호") @RequestParam(defaultValue = "0") int page,
@@ -143,9 +144,9 @@ public class ModelTrainMngApiController {
@Parameter( @Parameter(
description = "모델 구분", description = "모델 구분",
example = "", example = "",
schema = @Schema(allowableValues = {"G1", "G2", "G3"})) schema = @Schema(allowableValues = {"G1", "G2", "G3", "G4"}))
@RequestParam @RequestParam
String modelType, ModelType modelType,
@Parameter( @Parameter(
description = "선택 구분", description = "선택 구분",
example = "", example = "",
@@ -153,7 +154,7 @@ public class ModelTrainMngApiController {
@RequestParam @RequestParam
String selectType) { String selectType) {
DatasetReq req = new DatasetReq(); DatasetReq req = new DatasetReq();
req.setModelNo(modelType); req.setModelNo(modelType.getId());
req.setDataType(selectType); req.setDataType(selectType);
return ApiResponseDto.ok(modelTrainMngService.getDatasetSelectList(req)); return ApiResponseDto.ok(modelTrainMngService.getDatasetSelectList(req));
} }

View File

@@ -139,7 +139,7 @@ public class ModelTrainMngDto {
public static class AddReq { public static class AddReq {
@NotNull @NotNull
@Schema(description = "모델 종류 G1, G2, G3", example = "G1") @Schema(description = "모델 종류 G1, G2, G3, G4", example = "G1")
private String modelNo; private String modelNo;
@NotNull @NotNull
@@ -197,10 +197,11 @@ public class ModelTrainMngDto {
@Schema(description = "폐기물", example = "0") @Schema(description = "폐기물", example = "0")
private Long wasteCnt; private Long wasteCnt;
@Schema( @Schema(description = "도로, 비닐하우스, 밭, 과수원, 초지, 숲, 물, 모재/자갈, 토분(무덤), 일반토지, 기타", example = "0")
description = "도로, 비닐하우스, 밭, 과수원, 초지, 숲, 물, 모재/자갈, 토분(무덤), 일반토지, 태양광, 기타",
example = "0")
private Long LandCoverCnt; private Long LandCoverCnt;
@Schema(description = "태양광", example = "0")
private Long solar;
} }
@Getter @Getter

View File

@@ -51,10 +51,10 @@ public class ModelTrainMngService {
@Value("${train.docker.response_dir}") @Value("${train.docker.response_dir}")
private String responseDir; private String responseDir;
@Value("${train.docker.symbolic_link_dir}") @Value("${train.docker.symbolic_link_dir}")
private String symbolicDir; private String symbolicDir;
/** /**
* 모델학습 조회 * 모델학습 조회
* *
@@ -324,6 +324,8 @@ public class ModelTrainMngService {
public List<SelectDataSet> getDatasetSelectList(DatasetReq req) { public List<SelectDataSet> getDatasetSelectList(DatasetReq req) {
if (req.getModelNo().equals(ModelType.G1.getId())) { if (req.getModelNo().equals(ModelType.G1.getId())) {
return modelTrainMngCoreService.getDatasetSelectG1List(req); return modelTrainMngCoreService.getDatasetSelectG1List(req);
} else if (req.getModelNo().equals(ModelType.G4.getId())) {
return modelTrainMngCoreService.getDatasetSelectG4List(req);
} else { } else {
return modelTrainMngCoreService.getDatasetSelectG2G3List(req); return modelTrainMngCoreService.getDatasetSelectG2G3List(req);
} }

View File

@@ -154,6 +154,8 @@ public class ModelTrainMngCoreService {
datasetEntity.setWasteCnt(dataset.getSummary().getWasteCnt()); datasetEntity.setWasteCnt(dataset.getSummary().getWasteCnt());
} else if (addReq.getModelNo().equals(ModelType.G3.getId())) { } else if (addReq.getModelNo().equals(ModelType.G3.getId())) {
datasetEntity.setLandCoverCnt(dataset.getSummary().getLandCoverCnt()); datasetEntity.setLandCoverCnt(dataset.getSummary().getLandCoverCnt());
} else if (addReq.getModelNo().equals(ModelType.G4.getId())) {
datasetEntity.setSolarCnt(dataset.getSummary().getSolar());
} }
datasetEntity.setCreatedUid(userUtil.getId()); datasetEntity.setCreatedUid(userUtil.getId());
@@ -337,6 +339,16 @@ public class ModelTrainMngCoreService {
return datasetRepository.getDatasetTransferSelectG2G3List(modelId, modelNo); return datasetRepository.getDatasetTransferSelectG2G3List(modelId, modelNo);
} }
/**
* 데이터셋 G4 목록
*
* @param req
* @return
*/
public List<SelectDataSet> getDatasetSelectG4List(DatasetReq req) {
return datasetRepository.getDatasetSelectG4List(req);
}
// TODO 미사용 끝 // TODO 미사용 끝
/** /**

View File

@@ -43,6 +43,9 @@ public class ModelDatasetEntity {
@Column(name = "land_cover_cnt") @Column(name = "land_cover_cnt")
private Long landCoverCnt; private Long landCoverCnt;
@Column(name = "solar_cnt")
private Long solarCnt;
@ColumnDefault("now()") @ColumnDefault("now()")
@Column(name = "created_dttm") @Column(name = "created_dttm")
private ZonedDateTime createdDttm = ZonedDateTime.now(); private ZonedDateTime createdDttm = ZonedDateTime.now();

View File

@@ -27,6 +27,8 @@ public interface DatasetRepositoryCustom {
List<SelectDataSet> getDatasetSelectG2G3List(DatasetReq req); List<SelectDataSet> getDatasetSelectG2G3List(DatasetReq req);
List<SelectDataSet> getDatasetSelectG4List(DatasetReq req);
Long getDatasetMaxStage(int compareYyyy, int targetYyyy); Long getDatasetMaxStage(int compareYyyy, int targetYyyy);
Long insertDatasetMngData(DatasetMngRegDto mngRegDto); Long insertDatasetMngData(DatasetMngRegDto mngRegDto);

View File

@@ -4,6 +4,7 @@ import static com.kamco.cd.training.postgres.entity.QDatasetObjEntity.datasetObj
import static com.kamco.cd.training.postgres.entity.QModelDatasetMappEntity.modelDatasetMappEntity; import static com.kamco.cd.training.postgres.entity.QModelDatasetMappEntity.modelDatasetMappEntity;
import static com.kamco.cd.training.postgres.entity.QModelMasterEntity.modelMasterEntity; import static com.kamco.cd.training.postgres.entity.QModelMasterEntity.modelMasterEntity;
import com.kamco.cd.training.common.enums.DetectionClassification;
import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.common.enums.ModelType;
import com.kamco.cd.training.dataset.dto.DatasetDto.DatasetMngRegDto; import com.kamco.cd.training.dataset.dto.DatasetDto.DatasetMngRegDto;
import com.kamco.cd.training.dataset.dto.DatasetDto.DatasetReq; import com.kamco.cd.training.dataset.dto.DatasetDto.DatasetReq;
@@ -104,10 +105,6 @@ public class DatasetRepositoryImpl implements DatasetRepositoryCustom {
builder.and(dataset.dataType.eq(req.getDataType())); builder.and(dataset.dataType.eq(req.getDataType()));
} }
if (StringUtils.isNotBlank(req.getDataType()) && !"CURRENT".equals(req.getDataType())) {
builder.and(dataset.dataType.eq(req.getDataType()));
}
if (req.getIds() != null) { if (req.getIds() != null) {
builder.and(dataset.id.in(req.getIds())); builder.and(dataset.id.in(req.getIds()));
} }
@@ -126,12 +123,15 @@ public class DatasetRepositoryImpl implements DatasetRepositoryCustom {
dataset.targetYyyy, dataset.targetYyyy,
dataset.memo, dataset.memo,
new CaseBuilder() new CaseBuilder()
.when(datasetObjEntity.targetClassCd.eq("building")) .when(
datasetObjEntity.targetClassCd.eq(DetectionClassification.BUILDING.getId()))
.then(1) .then(1)
.otherwise(0) .otherwise(0)
.sum(), .sum(),
new CaseBuilder() new CaseBuilder()
.when(datasetObjEntity.targetClassCd.eq("container")) .when(
datasetObjEntity.targetClassCd.eq(
DetectionClassification.CONTAINER.getId()))
.then(1) .then(1)
.otherwise(0) .otherwise(0)
.sum())) .sum()))
@@ -249,19 +249,31 @@ public class DatasetRepositoryImpl implements DatasetRepositoryCustom {
} }
// TODO 미사용 끝 // TODO 미사용 끝
@Override @Override
public List<SelectDataSet> getDatasetSelectG2G3List(DatasetReq req) { public List<SelectDataSet> getDatasetSelectG2G3List(DatasetReq req) {
String building = DetectionClassification.BUILDING.getId();
String container = DetectionClassification.CONTAINER.getId();
String waste = DetectionClassification.WASTE.getId();
String solar = DetectionClassification.SOLAR.getId();
BooleanBuilder builder = new BooleanBuilder(); BooleanBuilder builder = new BooleanBuilder();
builder.and(dataset.deleted.isFalse()); builder.and(dataset.deleted.isFalse());
NumberExpression<Long> selectedCnt = null; NumberExpression<Long> selectedCnt = null;
NumberExpression<Long> wasteCnt = NumberExpression<Long> wasteCnt =
datasetObjEntity.targetClassCd.when("waste").then(1L).otherwise(0L).sum(); datasetObjEntity
.targetClassCd
.when(DetectionClassification.WASTE.getId())
.then(1L)
.otherwise(0L)
.sum();
// G1, G2, G4 제외
NumberExpression<Long> elseCnt = NumberExpression<Long> elseCnt =
new CaseBuilder() new CaseBuilder()
.when(datasetObjEntity.targetClassCd.notIn("building", "container", "waste")) .when(datasetObjEntity.targetClassCd.notIn(building, container, waste, solar))
.then(1L) .then(1L)
.otherwise(0L) .otherwise(0L)
.sum(); .sum();
@@ -481,4 +493,51 @@ public class DatasetRepositoryImpl implements DatasetRepositoryCustom {
.where(dataset.uid.eq(uid), dataset.deleted.isFalse()) .where(dataset.uid.eq(uid), dataset.deleted.isFalse())
.fetchOne(); .fetchOne();
} }
@Override
public List<SelectDataSet> getDatasetSelectG4List(DatasetReq req) {
BooleanBuilder builder = new BooleanBuilder();
builder.and(dataset.deleted.isFalse());
if (StringUtils.isNotBlank(req.getDataType()) && !"CURRENT".equals(req.getDataType())) {
builder.and(dataset.dataType.eq(req.getDataType()));
}
if (req.getIds() != null) {
builder.and(dataset.id.in(req.getIds()));
}
return queryFactory
.select(
Projections.constructor(
SelectDataSet.class,
Expressions.constant(req.getModelNo()),
dataset.id,
dataset.uuid,
dataset.dataType,
dataset.title,
dataset.roundNo,
dataset.compareYyyy,
dataset.targetYyyy,
dataset.memo,
new CaseBuilder()
.when(datasetObjEntity.targetClassCd.eq(DetectionClassification.SOLAR.getId()))
.then(1)
.otherwise(0)
.sum()))
.from(dataset)
.leftJoin(datasetObjEntity)
.on(dataset.id.eq(datasetObjEntity.datasetUid))
.where(builder)
.groupBy(
dataset.id,
dataset.uuid,
dataset.dataType,
dataset.title,
dataset.roundNo,
dataset.memo)
.orderBy(dataset.createdDttm.desc())
.fetch();
}
} }

View File

@@ -1,9 +1,11 @@
package com.kamco.cd.training.postgres.repository.model; package com.kamco.cd.training.postgres.repository.model;
import static com.kamco.cd.training.postgres.entity.QDatasetEntity.datasetEntity; import static com.kamco.cd.training.postgres.entity.QDatasetEntity.datasetEntity;
import static com.kamco.cd.training.postgres.entity.QDatasetObjEntity.datasetObjEntity;
import static com.kamco.cd.training.postgres.entity.QModelDatasetMappEntity.modelDatasetMappEntity; import static com.kamco.cd.training.postgres.entity.QModelDatasetMappEntity.modelDatasetMappEntity;
import static com.kamco.cd.training.postgres.entity.QModelMasterEntity.modelMasterEntity; import static com.kamco.cd.training.postgres.entity.QModelMasterEntity.modelMasterEntity;
import com.kamco.cd.training.common.enums.DetectionClassification;
import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.common.enums.ModelType;
import com.kamco.cd.training.postgres.entity.ModelDatasetMappEntity; import com.kamco.cd.training.postgres.entity.ModelDatasetMappEntity;
import com.kamco.cd.training.postgres.entity.QDatasetObjEntity; import com.kamco.cd.training.postgres.entity.QDatasetObjEntity;
@@ -11,6 +13,7 @@ import com.kamco.cd.training.postgres.entity.QDatasetTestObjEntity;
import com.kamco.cd.training.postgres.entity.QDatasetValObjEntity; import com.kamco.cd.training.postgres.entity.QDatasetValObjEntity;
import com.kamco.cd.training.train.dto.ModelTrainLinkDto; import com.kamco.cd.training.train.dto.ModelTrainLinkDto;
import com.querydsl.core.types.Projections; import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory; import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -33,9 +36,44 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
@Override @Override
public List<ModelTrainLinkDto> findDatasetTrainPath(Long modelId) { public List<ModelTrainLinkDto> findDatasetTrainPath(Long modelId) {
QDatasetObjEntity datasetObjEntity = QDatasetObjEntity.datasetObjEntity; QDatasetObjEntity datasetObjEntity = QDatasetObjEntity.datasetObjEntity;
// =====================
// 조건 분리
// =====================
BooleanExpression g1 =
modelMasterEntity
.modelNo
.eq(ModelType.G1.getId())
.and(
datasetObjEntity.targetClassCd.in(
DetectionClassification.CONTAINER.getId(),
DetectionClassification.BUILDING.getId()));
BooleanExpression g2 =
modelMasterEntity
.modelNo
.eq(ModelType.G2.getId())
.and(datasetObjEntity.targetClassCd.eq(DetectionClassification.WASTE.getId()));
BooleanExpression g4 =
modelMasterEntity
.modelNo
.eq(ModelType.G4.getId())
.and(datasetObjEntity.targetClassCd.eq(DetectionClassification.SOLAR.getId()));
// G3 = 전체 허용 (fallback)
BooleanExpression g3 =
modelMasterEntity
.modelNo
.eq(ModelType.G3.getId())
.and(
datasetObjEntity.targetClassCd.notIn(
DetectionClassification.CONTAINER.getId(),
DetectionClassification.BUILDING.getId(),
DetectionClassification.WASTE.getId(),
DetectionClassification.SOLAR.getId()));
return queryFactory return queryFactory
.select( .select(
Projections.constructor( Projections.constructor(
@@ -60,17 +98,7 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
datasetObjEntity datasetObjEntity
.datasetUid .datasetUid
.eq(modelDatasetMappEntity.datasetUid) .eq(modelDatasetMappEntity.datasetUid)
.and( .and(g1.or(g2).or(g4).or(g3)))
modelMasterEntity
.modelNo
.eq(ModelType.G1.getId())
.and(datasetObjEntity.targetClassCd.upper().in("CONTAINER", "BUILDING"))
.or(
modelMasterEntity
.modelNo
.eq(ModelType.G2.getId())
.and(datasetObjEntity.targetClassCd.upper().eq("WASTE")))
.or(modelMasterEntity.modelNo.eq(ModelType.G3.getId()))))
.where(modelMasterEntity.id.eq(modelId)) .where(modelMasterEntity.id.eq(modelId))
.fetch(); .fetch();
} }
@@ -80,6 +108,42 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
QDatasetValObjEntity datasetValObjEntity = QDatasetValObjEntity.datasetValObjEntity; QDatasetValObjEntity datasetValObjEntity = QDatasetValObjEntity.datasetValObjEntity;
// =====================
// 조건 분리
// =====================
BooleanExpression g1 =
modelMasterEntity
.modelNo
.eq(ModelType.G1.getId())
.and(
datasetValObjEntity.targetClassCd.in(
DetectionClassification.CONTAINER.getId(),
DetectionClassification.BUILDING.getId()));
BooleanExpression g2 =
modelMasterEntity
.modelNo
.eq(ModelType.G2.getId())
.and(datasetValObjEntity.targetClassCd.eq(DetectionClassification.WASTE.getId()));
BooleanExpression g4 =
modelMasterEntity
.modelNo
.eq(ModelType.G4.getId())
.and(datasetValObjEntity.targetClassCd.eq(DetectionClassification.SOLAR.getId()));
// G3 = 전체 허용 (fallback)
BooleanExpression g3 =
modelMasterEntity
.modelNo
.eq(ModelType.G3.getId())
.and(
datasetValObjEntity.targetClassCd.notIn(
DetectionClassification.CONTAINER.getId(),
DetectionClassification.BUILDING.getId(),
DetectionClassification.WASTE.getId(),
DetectionClassification.SOLAR.getId()));
return queryFactory return queryFactory
.select( .select(
Projections.constructor( Projections.constructor(
@@ -104,17 +168,7 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
datasetValObjEntity datasetValObjEntity
.datasetUid .datasetUid
.eq(modelDatasetMappEntity.datasetUid) .eq(modelDatasetMappEntity.datasetUid)
.and( .and(g1.or(g2).or(g4).or(g3)))
modelMasterEntity
.modelNo
.eq(ModelType.G1.getId())
.and(datasetValObjEntity.targetClassCd.upper().in("CONTAINER", "BUILDING"))
.or(
modelMasterEntity
.modelNo
.eq(ModelType.G2.getId())
.and(datasetValObjEntity.targetClassCd.upper().eq("WASTE")))
.or(modelMasterEntity.modelNo.eq(ModelType.G3.getId()))))
.where(modelMasterEntity.id.eq(modelId)) .where(modelMasterEntity.id.eq(modelId))
.fetch(); .fetch();
} }
@@ -124,6 +178,42 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
QDatasetTestObjEntity datasetTestObjEntity = QDatasetTestObjEntity.datasetTestObjEntity; QDatasetTestObjEntity datasetTestObjEntity = QDatasetTestObjEntity.datasetTestObjEntity;
// =====================
// 조건 분리
// =====================
BooleanExpression g1 =
modelMasterEntity
.modelNo
.eq(ModelType.G1.getId())
.and(
datasetTestObjEntity.targetClassCd.in(
DetectionClassification.CONTAINER.getId(),
DetectionClassification.BUILDING.getId()));
BooleanExpression g2 =
modelMasterEntity
.modelNo
.eq(ModelType.G2.getId())
.and(datasetTestObjEntity.targetClassCd.eq(DetectionClassification.WASTE.getId()));
BooleanExpression g4 =
modelMasterEntity
.modelNo
.eq(ModelType.G4.getId())
.and(datasetTestObjEntity.targetClassCd.eq(DetectionClassification.SOLAR.getId()));
// G3 = 전체 허용 (fallback)
BooleanExpression g3 =
modelMasterEntity
.modelNo
.eq(ModelType.G3.getId())
.and(
datasetTestObjEntity.targetClassCd.notIn(
DetectionClassification.CONTAINER.getId(),
DetectionClassification.BUILDING.getId(),
DetectionClassification.WASTE.getId(),
DetectionClassification.SOLAR.getId()));
return queryFactory return queryFactory
.select( .select(
Projections.constructor( Projections.constructor(
@@ -148,17 +238,7 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
datasetTestObjEntity datasetTestObjEntity
.datasetUid .datasetUid
.eq(modelDatasetMappEntity.datasetUid) .eq(modelDatasetMappEntity.datasetUid)
.and( .and(g1.or(g2).or(g4).or(g3)))
modelMasterEntity
.modelNo
.eq(ModelType.G1.getId())
.and(datasetTestObjEntity.targetClassCd.upper().in("CONTAINER", "BUILDING"))
.or(
modelMasterEntity
.modelNo
.eq(ModelType.G2.getId())
.and(datasetTestObjEntity.targetClassCd.upper().eq("WASTE")))
.or(modelMasterEntity.modelNo.eq(ModelType.G3.getId()))))
.where(modelMasterEntity.id.eq(modelId)) .where(modelMasterEntity.id.eq(modelId))
.fetch(); .fetch();
} }

View File

@@ -262,9 +262,9 @@ public class DockerTrainService {
c.add("-v"); c.add("-v");
c.add(basePath + ":" + basePath); // 심볼릭 링크와 연결되는 실제 파일 경로도 마운트를 해줘야 함 c.add(basePath + ":" + basePath); // 심볼릭 링크와 연결되는 실제 파일 경로도 마운트를 해줘야 함
c.add("-v"); c.add("-v");
c.add(symbolicDir + ":/data"); //요청할경로 c.add(symbolicDir + ":/data"); // 요청할경로
c.add("-v"); c.add("-v");
c.add(responseDir + ":/checkpoints"); //저장될경로 c.add(responseDir + ":/checkpoints"); // 저장될경로
// 표준입력 유지 (-it 대신 -i만 사용) // 표준입력 유지 (-it 대신 -i만 사용)
c.add("-i"); c.add("-i");

View File

@@ -384,7 +384,20 @@ public class JobRecoveryOnStartupService {
return new OutputResult(false, "total-epoch-missing"); return new OutputResult(false, "total-epoch-missing");
} }
log.info("[RECOVERY] totalEpoch={}. jobId={}", totalEpoch, job.getId()); Integer valInterval = extractValInterval(job).orElse(null);
if (valInterval == null || valInterval <= 0) {
log.warn(
"[RECOVERY] valInterval missing or invalid. jobId={}, valInterval={}",
job.getId(),
valInterval);
return new OutputResult(false, "val-interval-missing");
}
log.info(
"[RECOVERY] totalEpoch={}. valInterval={}. jobId={}",
totalEpoch,
valInterval,
job.getId());
// 3) val.csv 존재 확인 // 3) val.csv 존재 확인
Path valCsv = outDir.resolve("val.csv"); Path valCsv = outDir.resolve("val.csv");
@@ -396,14 +409,17 @@ public class JobRecoveryOnStartupService {
// 4) val.csv 라인 수 확인 // 4) val.csv 라인 수 확인
long lines = countNonHeaderLines(valCsv); long lines = countNonHeaderLines(valCsv);
// expected = 실제 val 실행 횟수
int expectedLines = totalEpoch / valInterval;
log.info( log.info(
"[RECOVERY] val.csv lines counted. jobId={}, lines={}, expected={}", "[RECOVERY] val.csv lines counted. jobId={}, lines={}, expected={}",
job.getId(), job.getId(),
lines, lines,
totalEpoch); expectedLines);
// 5) 완료 판정 // 5) 완료 판정
if (lines == totalEpoch) { if (lines >= expectedLines) {
log.info("[RECOVERY] outputs look COMPLETE. jobId={}", job.getId()); log.info("[RECOVERY] outputs look COMPLETE. jobId={}", job.getId());
return new OutputResult(true, "ok"); return new OutputResult(true, "ok");
} }
@@ -412,7 +428,7 @@ public class JobRecoveryOnStartupService {
"[RECOVERY] val.csv line mismatch. jobId={}, lines={}, expected={}", "[RECOVERY] val.csv line mismatch. jobId={}, lines={}, expected={}",
job.getId(), job.getId(),
lines, lines,
totalEpoch); expectedLines);
return new OutputResult( return new OutputResult(
false, "val.csv-lines-mismatch lines=" + lines + " expected=" + totalEpoch); false, "val.csv-lines-mismatch lines=" + lines + " expected=" + totalEpoch);
@@ -530,4 +546,19 @@ public class JobRecoveryOnStartupService {
return reason; return reason;
} }
} }
/** paramsJson에서 valInterval 추출 */
private Optional<Integer> extractValInterval(ModelTrainJobDto job) {
Map<String, Object> params = job.getParamsJson();
if (params == null) return Optional.empty();
Object v = params.get("valInterval");
if (v == null) return Optional.empty();
try {
return Optional.of(Integer.parseInt(String.valueOf(v)));
} catch (Exception ignore) {
return Optional.empty();
}
}
} }

View File

@@ -85,34 +85,20 @@ public class ModelTrainMetricsJobService {
int epoch = Integer.parseInt(record.get("Epoch")); int epoch = Integer.parseInt(record.get("Epoch"));
float aAcc = parseFloatSafe(record.get("aAcc")); Float aAcc = parseFloatSafe(record.get("aAcc"));
float mFscore = parseFloatSafe(record.get("mFscore")); Float mFscore = parseFloatSafe(record.get("mFscore"));
float mPrecision = parseFloatSafe(record.get("mPrecision")); Float mPrecision = parseFloatSafe(record.get("mPrecision"));
float mRecall = parseFloatSafe(record.get("mRecall")); Float mRecall = parseFloatSafe(record.get("mRecall"));
float mIoU = parseFloatSafe(record.get("mIoU")); Float mIoU = parseFloatSafe(record.get("mIoU"));
float mAcc = parseFloatSafe(record.get("mAcc")); Float mAcc = parseFloatSafe(record.get("mAcc"));
float changed_fscore = parseFloatSafe(record.get("changed_fscore")); Float changed_fscore = parseFloatSafe(record.get("changed_fscore"));
float changed_precision = parseFloatSafe(record.get("changed_precision")); Float changed_precision = parseFloatSafe(record.get("changed_precision"));
float changed_recall = parseFloatSafe(record.get("changed_recall")); Float changed_recall = parseFloatSafe(record.get("changed_recall"));
float unchanged_fscore = parseFloatSafe(record.get("unchanged_fscore")); Float unchanged_fscore = parseFloatSafe(record.get("unchanged_fscore"));
float unchanged_precision = parseFloatSafe(record.get("unchanged_precision")); Float unchanged_precision = parseFloatSafe(record.get("unchanged_precision"));
float unchanged_recall = parseFloatSafe(record.get("unchanged_recall")); Float unchanged_recall = parseFloatSafe(record.get("unchanged_recall"));
// int epoch = Integer.parseInt(record.get("Epoch"));
// float aAcc = Float.parseFloat(record.get("aAcc"));
// float mFscore = Float.parseFloat(record.get("mFscore"));
// float mPrecision = Float.parseFloat(record.get("mPrecision"));
// float mRecall = Float.parseFloat(record.get("mRecall"));
// float mIoU = Float.parseFloat(record.get("mIoU"));
// float mAcc = Float.parseFloat(record.get("mAcc"));
// float changed_fscore = Float.parseFloat(record.get("changed_fscore"));
// float changed_precision = Float.parseFloat(record.get("changed_precision"));
// float changed_recall = Float.parseFloat(record.get("changed_recall"));
// float unchanged_fscore = Float.parseFloat(record.get("unchanged_fscore"));
// float unchanged_precision =
// Float.parseFloat(record.get("unchanged_precision"));
// float unchanged_recall = Float.parseFloat(record.get("unchanged_recall"));
batchArgs.add( batchArgs.add(
new Object[] { new Object[] {

View File

@@ -19,6 +19,7 @@ public class TmpDatasetService {
@Value("${train.docker.symbolic_link_dir}") @Value("${train.docker.symbolic_link_dir}")
private String symbolicDir; private String symbolicDir;
/** /**
* train, val, test 폴더별로 link * train, val, test 폴더별로 link
* *

View File

@@ -132,7 +132,9 @@ public class TrainJobWorker {
String failMsg = result.getStatus() + "\n" + result.getLogs(); String failMsg = result.getStatus() + "\n" + result.getLogs();
log.info("training fail exitCode={} Msg ={}", result.getExitCode(), failMsg); log.info("training fail exitCode={} Msg ={}", result.getExitCode(), failMsg);
if (result.getExitCode() == -1 || result.getExitCode() == 143) { if (result.getExitCode() == -1
|| result.getExitCode() == 143
|| result.getExitCode() == 137) {
// 실패 처리 // 실패 처리
modelTrainJobCoreService.markPaused( modelTrainJobCoreService.markPaused(
jobId, result.getExitCode(), result.getStatus() + "\n" + result.getLogs()); jobId, result.getExitCode(), result.getStatus() + "\n" + result.getLogs());