1
This commit is contained in:
@@ -39,6 +39,9 @@ type TrainingRunner interface {
|
||||
FetchResult(ctx context.Context, job *TrainingJob) (string, error)
|
||||
// FetchArtifact 把训练机产物文件拉回服务器本地路径
|
||||
FetchArtifact(ctx context.Context, job *TrainingJob, remoteName, localPath string) error
|
||||
// PushArtifact 把服务器本地文件推到训练机(增量训练基座权重,2026-09-09;
|
||||
// remoteName 相对训练机 workdir)
|
||||
PushArtifact(ctx context.Context, job *TrainingJob, remoteName, localPath string) error
|
||||
// SyncYoloDataset 把训练集包落到训练机(subprocess 直写 workdir;ssh 走 tar 流式管道,本地不落盘)
|
||||
SyncYoloDataset(ctx context.Context, job *TrainingJob, pkg *YoloPackage) error
|
||||
// WriteTaskJson 把任务参数文件写到训练机(随 Start 前的准备阶段调用)
|
||||
@@ -222,6 +225,15 @@ func (r *subprocessRunner) FetchArtifact(ctx context.Context, job *TrainingJob,
|
||||
return WriteFileAtomic(localPath, data)
|
||||
}
|
||||
|
||||
func (r *subprocessRunner) PushArtifact(ctx context.Context, job *TrainingJob, remoteName, localPath string) error {
|
||||
data, err := os.ReadFile(localPath)
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "读取待推送文件失败")
|
||||
}
|
||||
dst := filepath.Join(job.Workdir, filepath.FromSlash(remoteName))
|
||||
return WriteFileAtomic(dst, data)
|
||||
}
|
||||
|
||||
func (r *subprocessRunner) SyncYoloDataset(ctx context.Context, job *TrainingJob, pkg *YoloPackage) error {
|
||||
// 同机训练:训练进程直接读 workdir 下文件,包直写目标目录(无中间暂存)
|
||||
dst := filepath.Join(job.Workdir, job.DatasetDir, "yolo", job.DatasetName)
|
||||
@@ -395,6 +407,28 @@ func (r *sshRunner) FetchArtifact(ctx context.Context, job *TrainingJob, remoteN
|
||||
return WriteFileAtomic(localPath, data)
|
||||
}
|
||||
|
||||
func (r *sshRunner) PushArtifact(ctx context.Context, job *TrainingJob, remoteName, localPath string) error {
|
||||
client, err := r.dial(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = client.Close() }()
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = session.Close() }()
|
||||
dst := filepath.Join(job.Workdir, filepath.FromSlash(remoteName))
|
||||
cmd := fmt.Sprintf("mkdir -p %s && cat > %s", filepath.Dir(dst), dst)
|
||||
f, err := os.Open(localPath)
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "读取待推送文件失败")
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
session.Stdin = f
|
||||
return session.Run(cmd)
|
||||
}
|
||||
|
||||
func (r *sshRunner) SyncYoloDataset(ctx context.Context, job *TrainingJob, pkg *YoloPackage) error {
|
||||
// tar 流式管道:原图直接读数据集目录打包,stdin 推远端解包,本地不落盘
|
||||
client, err := r.dial(ctx)
|
||||
|
||||
@@ -14,6 +14,9 @@ import (
|
||||
// datasets/<name>/ 数据集图片(平铺,文件名唯一,标注存 DB dataset_image.labels_json)
|
||||
// trainings/<model>.tflite 某数据集当前生效模型(训练成功即直写,客户端固定下载,无存档回退;
|
||||
// <model> = 数据集文件名前缀 name_prefix,空则回退数据集名,2026-08-28)
|
||||
// trainings/weights/<基名>.pt 增量训练基座权重存档(2026-09-09:基名同 tflite——单物种
|
||||
// <前缀或数据集名>[_n]、综合 combined[_n];下次训练推训练机热启动,
|
||||
// 删除即回落全量基座)
|
||||
//
|
||||
// 训练机与 Go 服务器异机时,数据集经 training 通道同步(见 common/training_runner.go)。
|
||||
|
||||
@@ -38,6 +41,12 @@ func TrainingModelPath(ctx context.Context, modelName string) string {
|
||||
return filepath.Join(DatasetDir(ctx), "trainings", modelName+".tflite")
|
||||
}
|
||||
|
||||
// TrainingWeightsPath 增量训练基座权重存档路径(trainings/weights/<基名>.pt,基名同 tflite 基名;
|
||||
// 存在则下次训练推训练机热启动,删除即回落全量基座)
|
||||
func TrainingWeightsPath(ctx context.Context, baseName string) string {
|
||||
return filepath.Join(DatasetDir(ctx), "trainings", "weights", baseName+".pt")
|
||||
}
|
||||
|
||||
// Sha256Hex 计算文件内容 SHA-256 十六进制(模型版本校验用)
|
||||
func Sha256Hex(data []byte) (string, error) {
|
||||
sum := sha256.Sum256(data)
|
||||
|
||||
Reference in New Issue
Block a user