27 Commits

Author SHA1 Message Date
d7458e3c8b Merge pull request 'feat/training_260324' (#190) from feat/training_260324 into develop
Reviewed-on: #190
2026-04-03 16:05:07 +09:00
92492ca879 하이퍼 파라미터 컬럼 사이즈 변경 2026-04-03 16:04:49 +09:00
a5d79b2504 하이퍼 파라미터 컬럼 사이즈 변경 2026-04-03 16:03:17 +09:00
b8c53aae64 Merge pull request '데이터셋 조회 class count integer -> Long 로 변경' (#189) from feat/training_260324 into develop
Reviewed-on: #189
2026-04-03 15:34:19 +09:00
348d3d0052 데이터셋 조회 class count integer -> Long 로 변경 2026-04-03 15:33:54 +09:00
b85ead36b4 Merge pull request '데이터셋 조회 class count integer -> Long 로 변경' (#188) from feat/training_260324 into develop
Reviewed-on: #188
2026-04-03 15:17:41 +09:00
e77eae8f8b 데이터셋 조회 class count integer -> Long 로 변경 2026-04-03 15:17:17 +09:00
570952df7e Merge pull request 'spotless 적용' (#187) from feat/training_260324 into develop
Reviewed-on: #187
2026-04-03 10:20:58 +09:00
26d34d88eb spotless 적용 2026-04-03 10:20:40 +09:00
46a5d4c2d3 Merge pull request 'Save-best, Save-best-rule 컬럼 varchar100으로 변경, spotless 적용' (#186) from feat/training_260324 into develop
Reviewed-on: #186
2026-04-03 09:20:34 +09:00
91f022889b Save-best, Save-best-rule 컬럼 varchar100으로 변경 2026-04-03 09:18:26 +09:00
dean
f00296cf2c welcome 2026-04-02 21:17:01 +09:00
f98f6cb038 Merge pull request 'solar -> solarCnt 변경' (#185) from feat/training_260324 into develop
Reviewed-on: #185
2026-04-02 18:57:16 +09:00
d1593e57c3 solar -> solarCnt 변경 2026-04-02 18:56:52 +09:00
732dccf2e4 Merge pull request 'solar -> solarCnt 변경' (#184) from feat/training_260324 into develop
Reviewed-on: #184
2026-04-02 18:55:14 +09:00
f6cd553af8 solar -> solarCnt 변경 2026-04-02 18:54:52 +09:00
618dbe4047 Merge pull request '데이터셋 entity 수정, 데이터셋 저장 수정' (#183) from feat/training_260324 into develop
Reviewed-on: #183
2026-04-02 18:42:55 +09:00
5546e8ef89 데이터셋 entity 수정, 데이터셋 저장 수정 2026-04-02 18:42:25 +09:00
b952ec7b47 Merge pull request '임시 데이터셋 폴더 생성 G4 추가' (#182) from feat/training_260324 into develop
Reviewed-on: #182
2026-04-02 18:05:11 +09:00
e93f533c59 임시 데이터셋 폴더 생성 G4 추가 2026-04-02 18:04:41 +09:00
a5267d8065 Merge pull request 'select-dataset-list api solarPanelCnt 추가, spotless 적용' (#181) from feat/training_260324 into develop
Reviewed-on: #181
2026-04-02 17:45:16 +09:00
71d9835b03 select-dataset-list api solarPanelCnt 추가, spotless 적용 2026-04-02 17:44:27 +09:00
39f39a4f0c Merge pull request 'ModelType enum G4 추가' (#180) from feat/training_260324 into develop
Reviewed-on: #180
2026-04-02 16:55:14 +09:00
1df7142544 ModelType enum G4 추가 2026-04-02 16:54:25 +09:00
d99e18b38c val nan 일때 오류 수정, spotless 적용 2026-04-02 14:41:13 +09:00
d6aa612494 Merge pull request 'val nan 일때 오류 수정' (#179) from feat/training_260324 into develop
Reviewed-on: #179
2026-04-02 14:26:13 +09:00
8def356323 val nan 일때 오류 수정 2026-04-02 14:19:42 +09:00
20 changed files with 313 additions and 111 deletions

View File

@@ -14,7 +14,7 @@ import lombok.Setter;
public class HyperParam {
@Schema(description = "모델", example = "G1")
private ModelType model; // G1, G2, G3
private ModelType model; // G1, G2, G3, G4
// -------------------------
// Important
@@ -104,7 +104,7 @@ public class HyperParam {
@Schema(description = "Best 모델 선정 규칙", example = "less")
private String saveBestRule; // save_best_rule
@Schema(description = "검증 수행 주기(Epoch)", example = "10")
@Schema(description = "검증 수행 주기(Epoch)", example = "1")
private Integer valInterval; // val_interval
@Schema(description = "로그 기록 주기(Iteration)", example = "400")

View File

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

View File

@@ -248,12 +248,13 @@ public class DatasetDto {
private Integer targetYyyy;
private String memo;
@JsonIgnore private Long classCount;
private Integer buildingCnt;
private Integer containerCnt;
private Long buildingCnt;
private Long containerCnt;
private String dataTypeName;
private Long wasteCnt;
private Long landCoverCnt;
private Long solarPanelCnt;
public SelectDataSet(
String modelNo,
@@ -266,6 +267,7 @@ public class DatasetDto {
Integer targetYyyy,
String memo,
Long classCount) {
this.modelNo = modelNo;
this.datasetId = datasetId;
this.uuid = uuid;
this.dataType = dataType;
@@ -280,6 +282,8 @@ public class DatasetDto {
this.wasteCnt = classCount;
} else if (modelNo.equals(ModelType.G3.getId())) {
this.landCoverCnt = classCount;
} else if (modelNo.equals(ModelType.G4.getId())) {
this.solarPanelCnt = classCount;
}
}
@@ -293,8 +297,9 @@ public class DatasetDto {
Integer compareYyyy,
Integer targetYyyy,
String memo,
Integer buildingCnt,
Integer containerCnt) {
Long buildingCnt,
Long containerCnt) {
this.modelNo = modelNo;
this.datasetId = datasetId;
this.uuid = uuid;
this.dataType = dataType;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -181,15 +181,15 @@ public class ModelHyperParamEntity {
private String metrics = "mFscore,mIoU";
/** Default: changed_fscore */
@Size(max = 30)
@Size(max = 50)
@NotNull
@Column(name = "save_best", nullable = false, length = 30)
@Column(name = "save_best", nullable = false, length = 50)
private String saveBest = "changed_fscore";
/** Default: greater */
@Size(max = 10)
@Size(max = 50)
@NotNull
@Column(name = "save_best_rule", nullable = false, length = 10)
@Column(name = "save_best_rule", nullable = false, length = 50)
private String saveBestRule = "greater";
/** Default: 1 */

View File

@@ -27,6 +27,8 @@ public interface DatasetRepositoryCustom {
List<SelectDataSet> getDatasetSelectG2G3List(DatasetReq req);
List<SelectDataSet> getDatasetSelectG4List(DatasetReq req);
Long getDatasetMaxStage(int compareYyyy, int targetYyyy);
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.QModelMasterEntity.modelMasterEntity;
import com.kamco.cd.training.common.enums.DetectionClassification;
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.DatasetReq;
@@ -104,10 +105,6 @@ public class DatasetRepositoryImpl implements DatasetRepositoryCustom {
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) {
builder.and(dataset.id.in(req.getIds()));
}
@@ -126,14 +123,17 @@ public class DatasetRepositoryImpl implements DatasetRepositoryCustom {
dataset.targetYyyy,
dataset.memo,
new CaseBuilder()
.when(datasetObjEntity.targetClassCd.eq("building"))
.then(1)
.otherwise(0)
.when(
datasetObjEntity.targetClassCd.eq(DetectionClassification.BUILDING.getId()))
.then(1L)
.otherwise(0L)
.sum(),
new CaseBuilder()
.when(datasetObjEntity.targetClassCd.eq("container"))
.then(1)
.otherwise(0)
.when(
datasetObjEntity.targetClassCd.eq(
DetectionClassification.CONTAINER.getId()))
.then(1L)
.otherwise(0L)
.sum()))
.from(dataset)
.leftJoin(datasetObjEntity)
@@ -249,29 +249,40 @@ public class DatasetRepositoryImpl implements DatasetRepositoryCustom {
}
// TODO 미사용 끝
@Override
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();
builder.and(dataset.deleted.isFalse());
NumberExpression<Long> selectedCnt = null;
// G2
NumberExpression<Long> wasteCnt =
datasetObjEntity.targetClassCd.when("waste").then(1L).otherwise(0L).sum();
NumberExpression<Long> elseCnt =
new CaseBuilder()
.when(datasetObjEntity.targetClassCd.notIn("building", "container", "waste"))
datasetObjEntity
.targetClassCd
.when(DetectionClassification.WASTE.getId())
.then(1L)
.otherwise(0L)
.sum();
if (StringUtils.isNotBlank(req.getModelNo())) {
if (req.getModelNo().equals(ModelType.G2.getId())) {
selectedCnt = wasteCnt;
} else {
selectedCnt = elseCnt;
}
// G3 (G1, G2, G4 제외)
NumberExpression<Long> elseCnt =
new CaseBuilder()
.when(datasetObjEntity.targetClassCd.notIn(building, container, waste, solar))
.then(1L)
.otherwise(0L)
.sum();
if (req.getModelNo().equals(ModelType.G2.getId())) {
selectedCnt = wasteCnt;
} else {
selectedCnt = elseCnt;
}
if (StringUtils.isNotBlank(req.getDataType())) {
@@ -481,4 +492,51 @@ public class DatasetRepositoryImpl implements DatasetRepositoryCustom {
.where(dataset.uid.eq(uid), dataset.deleted.isFalse())
.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(1L)
.otherwise(0L)
.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;
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.QModelMasterEntity.modelMasterEntity;
import com.kamco.cd.training.common.enums.DetectionClassification;
import com.kamco.cd.training.common.enums.ModelType;
import com.kamco.cd.training.postgres.entity.ModelDatasetMappEntity;
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.train.dto.ModelTrainLinkDto;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
@@ -33,9 +36,44 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
@Override
public List<ModelTrainLinkDto> findDatasetTrainPath(Long modelId) {
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
.select(
Projections.constructor(
@@ -60,17 +98,7 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
datasetObjEntity
.datasetUid
.eq(modelDatasetMappEntity.datasetUid)
.and(
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()))))
.and(g1.or(g2).or(g4).or(g3)))
.where(modelMasterEntity.id.eq(modelId))
.fetch();
}
@@ -80,6 +108,42 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
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
.select(
Projections.constructor(
@@ -104,17 +168,7 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
datasetValObjEntity
.datasetUid
.eq(modelDatasetMappEntity.datasetUid)
.and(
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()))))
.and(g1.or(g2).or(g4).or(g3)))
.where(modelMasterEntity.id.eq(modelId))
.fetch();
}
@@ -124,6 +178,42 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
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
.select(
Projections.constructor(
@@ -148,17 +238,7 @@ public class ModelDatasetMappRepositoryImpl implements ModelDatasetMappRepositor
datasetTestObjEntity
.datasetUid
.eq(modelDatasetMappEntity.datasetUid)
.and(
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()))))
.and(g1.or(g2).or(g4).or(g3)))
.where(modelMasterEntity.id.eq(modelId))
.fetch();
}

View File

@@ -56,6 +56,12 @@ public class DockerTrainService {
@Value("${spring.profiles.active}")
private String profile;
@Value("${hyper.parameter.gpus}")
private String hyperGpus;
@Value("${hyper.parameter.gpu-ids}")
private String hyperGpuIds;
private final ModelTrainJobCoreService modelTrainJobCoreService;
/**
@@ -262,9 +268,9 @@ public class DockerTrainService {
c.add("-v");
c.add(basePath + ":" + basePath); // 심볼릭 링크와 연결되는 실제 파일 경로도 마운트를 해줘야 함
c.add("-v");
c.add(symbolicDir + ":/data"); //요청할경로
c.add(symbolicDir + ":/data"); // 요청할경로
c.add("-v");
c.add(responseDir + ":/checkpoints"); //저장될경로
c.add(responseDir + ":/checkpoints"); // 저장될경로
// 표준입력 유지 (-it 대신 -i만 사용)
c.add("-i");
@@ -285,11 +291,13 @@ public class DockerTrainService {
// addArg(c, "--gpu-ids", req.getGpuIds()); // null
if ("prod".equals(profile)) {
addArg(c, "--batch-size", 2); // 학습서버 GPU 1개인 곳은 batch-size:2 까지만 가능
addArg(c, "--gpus", "1"); // 학습서버 GPU 1개인 곳은 1이어야 함
addArg(c, "--gpu-ids", "0"); // 학습서버 GPU 1개인 곳은 0이어야 함
} else {
addArg(c, "--batch-size", req.getBatchSize()); // 학습서버 GPU 1개인 곳은 batch-size:2 까지만 가능
}
addArg(c, "--gpus", hyperGpus); // 학습서버 GPU 1개인 곳은 1이어야 함
addArg(c, "--gpu-ids", hyperGpuIds); // 학습서버 GPU 1개인 곳은 0이어야 함
addArg(c, "--lr", req.getLearningRate());
addArg(c, "--backbone", req.getBackbone());
addArg(c, "--epochs", req.getEpochs());

View File

@@ -384,7 +384,20 @@ public class JobRecoveryOnStartupService {
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 존재 확인
Path valCsv = outDir.resolve("val.csv");
@@ -396,14 +409,17 @@ public class JobRecoveryOnStartupService {
// 4) val.csv 라인 수 확인
long lines = countNonHeaderLines(valCsv);
// expected = 실제 val 실행 횟수
int expectedLines = totalEpoch / valInterval;
log.info(
"[RECOVERY] val.csv lines counted. jobId={}, lines={}, expected={}",
job.getId(),
lines,
totalEpoch);
expectedLines);
// 5) 완료 판정
if (lines == totalEpoch) {
if (lines >= expectedLines) {
log.info("[RECOVERY] outputs look COMPLETE. jobId={}", job.getId());
return new OutputResult(true, "ok");
}
@@ -412,7 +428,7 @@ public class JobRecoveryOnStartupService {
"[RECOVERY] val.csv line mismatch. jobId={}, lines={}, expected={}",
job.getId(),
lines,
totalEpoch);
expectedLines);
return new OutputResult(
false, "val.csv-lines-mismatch lines=" + lines + " expected=" + totalEpoch);
@@ -530,4 +546,19 @@ public class JobRecoveryOnStartupService {
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"));
float aAcc = parseFloatSafe(record.get("aAcc"));
float mFscore = parseFloatSafe(record.get("mFscore"));
float mPrecision = parseFloatSafe(record.get("mPrecision"));
float mRecall = parseFloatSafe(record.get("mRecall"));
float mIoU = parseFloatSafe(record.get("mIoU"));
float mAcc = parseFloatSafe(record.get("mAcc"));
Float aAcc = parseFloatSafe(record.get("aAcc"));
Float mFscore = parseFloatSafe(record.get("mFscore"));
Float mPrecision = parseFloatSafe(record.get("mPrecision"));
Float mRecall = parseFloatSafe(record.get("mRecall"));
Float mIoU = parseFloatSafe(record.get("mIoU"));
Float mAcc = parseFloatSafe(record.get("mAcc"));
float changed_fscore = parseFloatSafe(record.get("changed_fscore"));
float changed_precision = parseFloatSafe(record.get("changed_precision"));
float changed_recall = parseFloatSafe(record.get("changed_recall"));
Float changed_fscore = parseFloatSafe(record.get("changed_fscore"));
Float changed_precision = parseFloatSafe(record.get("changed_precision"));
Float changed_recall = parseFloatSafe(record.get("changed_recall"));
float unchanged_fscore = parseFloatSafe(record.get("unchanged_fscore"));
float unchanged_precision = parseFloatSafe(record.get("unchanged_precision"));
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"));
Float unchanged_fscore = parseFloatSafe(record.get("unchanged_fscore"));
Float unchanged_precision = parseFloatSafe(record.get("unchanged_precision"));
Float unchanged_recall = parseFloatSafe(record.get("unchanged_recall"));
batchArgs.add(
new Object[] {

View File

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

View File

@@ -132,7 +132,9 @@ public class TrainJobWorker {
String failMsg = result.getStatus() + "\n" + result.getLogs();
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(
jobId, result.getExitCode(), result.getStatus() + "\n" + result.getLogs());

View File

@@ -41,3 +41,7 @@ train:
container_prefix: kamco-cd-train
shm_size: 16g
ipc_host: true
hyper:
parameter:
gpus: 4
gpu-ids: 0,1,2,3

View File

@@ -78,3 +78,8 @@ management:
exposure:
include:
- "health"
hyper:
parameter:
gpus: 1
gpu-ids: 0