Back to skills
extension
Category: Productivity & OfficeNo API key required

lora训练集创建

通用角色IP LoRA训练集构建全流程Skill。从设计稿解析、固化脚本创建与测试、提示词模板、迭代抽卡、逐张评估入库、同步打标到训练配置,任何AI agent可立即上手。适用于krea2+ComfyUI环境,基于9轮迭代实践提炼,合格率从18%提升至92%+,6-9轮可凑齐150-200张合格训练集。

personAuthor: c753717010hubModelScope

角色IP LoRA 训练集构建 Skill(通用版)

适用:krea2 模型 + ComfyUI + 任意LoRA训练平台(ModelScope / kohya / 本地) 前置:设计稿已就绪、ComfyUI可访问(默认 http://127.0.0.1:8188) 目标:6-9轮迭代产出150-200张合格训练集,可直接上传训练 本Skill自包含:迭代规则、固化脚本创建、测试流程全部内置,无需外部文档


一、触发条件

用户提出以下任一需求时启动本Skill:

  • "训练角色LoRA"、"构建训练集"、"抽卡凑样本"
  • "按照设计稿出图用于训练"、"迭代出图入训练集"
  • 已有设计稿,需要批量生成符合角色设定的图片

二、目录结构约定(首次执行时创建)

在AI agent的当前工作目录下创建 lora-dataset/ 目录。通用资源共享,项目文件按设计稿/项目名分开,避免不同角色的训练集、报告、出图混在一起。

lora-dataset/
├── core/                          # 【通用共享】固化脚本(所有项目共用,创建后勿改)
│   └── comfy_krea.py              # ComfyUI API 封装
├── knowledge/                     # 【通用共享】跨项目知识沉淀(越积累越厚)
│   ├── params.md                  # 关键参数沉淀(种子/工作流/LoRA权重)
│   ├── pitfalls.md                # 踩坑记录(触发条件/对策/状态)
│   └── prompts.md                 # 优秀提示词库(金牌片段/负面词库)
└── projects/                      # 【按项目分开】每个角色/设计稿一个子目录
    └── <项目名>/                   # 如:shenjingque / curve_body / 自定义名
        ├── iter/                  # 该项目的迭代出图脚本(按版本存放)
        │   └── configs/           # 每轮config JSON(含每张prompt/seed/权重)
        ├── dataset/               # 该项目的最终训练集(图片+同名.txt成对)
        │   ├── head/              # 大头照
        │   ├── half/              # 半身照
        │   └── full/              # 全身照
        ├── reports/               # 该项目的迭代报告
        │   ├── summaries/         # 每轮迭代总结(汇总级)
        │   └── analyses/          # 每轮图片逐张分析(逐张级,与总结分开)
        └── output/                # 该项目的每轮原始出图(round1_00001_.png等)

创建命令(agent执行一次即可,<项目名>替换为实际名称):

mkdir -p lora-dataset/{core,knowledge}
mkdir -p lora-dataset/projects/<项目名>/{iter/configs,dataset/{head,half,full},reports/{summaries,analyses},output}

目录划分原则: | 类型 | 位置 | 说明 | |---|---|---| | 固化脚本 | core/ | 通用,所有项目共用,只创建一次 | | 知识沉淀 | knowledge/ | 通用,跨项目积累,每个项目迭代后都往这里补充 | | 迭代脚本 | projects/<项目名>/iter/ | 项目专属,不同角色的提示词模板不同 | | 训练集 | projects/<项目名>/dataset/ | 项目专属,严格按角色分开,禁止混放 | | 迭代报告 | projects/<项目名>/reports/ | 项目专属,按角色归档 | | 原始出图 | projects/<项目名>/output/ | 项目专属,按角色分开便于回溯 |

2.1 core/ 与 iter/ 的核心区别(严禁混淆)

| 维度 | core/(固化脚本) | iter/(迭代脚本) | |---|---|---| | 本质 | 通用工具库,稳定不变 | 每轮临时执行脚本,频繁变化 | | 内容 | ComfyUI API封装、工作流构建、批量生成函数 | 具体提示词、种子、LoRA权重、本轮任务列表 | | 修改频率 | 创建后几乎不改,改了就是bug修复或功能升级 | 每轮都改,每轮一个新版本 | | 复用范围 | 所有项目、所有角色共用 | 仅当前项目、当前轮次使用 | | 是否含角色设定 | ❌ 不含任何角色/设计稿相关内容 | ✅ 含具体角色的提示词、服装、姿势等 | | 是否含具体参数 | ❌ 只提供函数接口,参数由调用方传入 | ✅ 硬编码本轮的种子、权重、尺寸、任务列表 | | 举例 | comfy_krea.py(generate_one / generate_batch) | round1_headshots.pyv2_round3_fullbody.py | | 存放位置 | lora-dataset/core/ | lora-dataset/projects/<项目名>/iter/ |

判断口诀

  • 换一个角色还能用的 → 放 core/
  • 换一个角色就不能用的 → 放 iter/
  • 写死了"沈惊鹊"、"绯红礼服"、"瑞凤眼"等具体角色内容的 → 必须放 iter/
  • 只是 generate_batch(wf, tasks, negative) 这种通用函数的 → 放 core/

常见错误:把包含具体提示词和任务列表的迭代脚本放进 core/。这会导致core目录越来越乱,不同角色的脚本混在一起,下次新项目无法直接复用core。正确做法是:迭代脚本 import core.comfy_krea,然后在iter脚本里写具体的提示词和任务。

iter脚本标准写法示例

# 文件:lora-dataset/projects/shenjingque/iter/v1_round1.py
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..", "core"))
from comfy_krea import generate_batch

# 这里写具体的提示词、种子、任务列表(每轮不同)
tasks = [
    {"name": "head_01", "prompt": "沈惊鹊,鹅蛋偏瓜子脸,瑞凤眼...", "seed": 77777777, "size": (1024,1024)},
    # ...
]
generate_batch("turbo", tasks, negative="...", out_prefix="projects/shenjingque/round1")

三、前置检查(开工前必须确认)

□ 设计稿文件已完整读取(用户提供路径或已上传)
□ ComfyUI 正在运行,API 可访问(默认 http://127.0.0.1:8188)
□ krea2 模型已加载(turbo / raw 工作流可用)
□ lora-dataset/ 目录结构已创建
□ 固化脚本 comfy_krea.py 已创建并通过测试(见第四节)

任一不满足→先解决再开工,禁止跳过。


四、固化脚本创建与测试(首次必做)

4.1 创建 comfy_krea.py

lora-dataset/core/comfy_krea.py 创建以下脚本(ComfyUI API封装,支持turbo/raw/hybrid三种工作流):

"""
comfy_krea.py - krea2 ComfyUI 固化生图工具
支持:turbo / raw / hybrid(混合流) 三种工作流
功能:单张生成、批量生成、多LoRA链式挂载、自动记录prompt/seed/权重
"""
import json, time, urllib.request, urllib.parse, os, random

COMFY_URL = "http://127.0.0.1:8188"
# 输出根目录:默认为当前工作目录下的 lora-dataset/,可通过环境变量 LORA_DATASET_ROOT 覆盖
OUTPUT_ROOT = os.environ.get("LORA_DATASET_ROOT", os.path.join(os.getcwd(), "lora-dataset"))

# ========== 工作流默认参数 ==========
WF_DEFAULTS = {
    "turbo":  {"steps": 8,  "cfg": 1.0, "sampler": "euler",   "scheduler": "simple", "shift": 3.0},
    "raw":    {"steps": 25, "cfg": 2.0, "sampler": "er_sde",  "scheduler": "simple", "shift": 3.0},
    "hybrid": {"raw_steps": 6, "total_steps": 12, "cfg": 1.0, "sampler": "euler", "scheduler": "simple", "shift": 3.0},
}

def _queue_prompt(prompt_workflow, client_id):
    """提交工作流到ComfyUI队列"""
    data = json.dumps({"prompt": prompt_workflow, "client_id": client_id}).encode()
    req = urllib.request.Request(f"{COMFY_URL}/prompt", data=data, headers={"Content-Type": "application/json"})
    return json.loads(urllib.request.urlopen(req).read())

def _get_history(prompt_id):
    """轮询等待生成完成"""
    while True:
        with urllib.request.urlopen(f"{COMFY_URL}/history/{prompt_id}") as r:
            history = json.loads(r.read())
        if prompt_id in history:
            return history[prompt_id]
        time.sleep(2)

def _build_workflow(wf, prompt, negative, seed, size, loras, **kwargs):
    """构建krea2工作流JSON(根据实际ComfyUI节点ID调整)"""
    w, h = size
    params = WF_DEFAULTS[wf].copy()
    params.update(kwargs)
    client_id = f"agent_{random.randint(10000,99999)}"

    # 基础工作流结构(需根据实际ComfyUI的krea2工作流节点ID适配)
    # 以下为模板,agent首次使用时需对照实际工作流JSON修正节点编号
    workflow = {
        "1": {"class_type": "KSampler", "inputs": {
            "seed": seed, "steps": params["steps"], "cfg": params["cfg"],
            "sampler_name": params["sampler"], "scheduler": params["scheduler"],
            "denoise": 1.0, "model": ["2", 0], "positive": ["3", 0], "negative": ["4", 0],
            "latent_image": ["5", 0]}},
        "2": {"class_type": "UNETLoader", "inputs": {
            "unet_name": "krea2_turbo_fp8_scaled.safetensors" if wf != "raw" else "krea2_raw_fp8_scaled.safetensors",
            "weight_dtype": "fp8_e4m3fn"}},
        "3": {"class_type": "CLIPTextEncode", "inputs": {"text": prompt, "clip": ["6", 0]}},
        "4": {"class_type": "CLIPTextEncode", "inputs": {"text": negative or "", "clip": ["6", 0]}},
        "5": {"class_type": "EmptyLatentImage", "inputs": {"width": w, "height": h, "batch_size": 1}},
        "6": {"class_type": "CLIPLoader", "inputs": {"clip_name": "qwen3vl_4b_fp8_scaled.safetensors", "type": "stable_cascade"}},
        "7": {"class_type": "VAELoader", "inputs": {"vae_name": "qwen_image_vae.safetensors"}},
        "8": {"class_type": "VAEDecode", "inputs": {"samples": ["1", 0], "vae": ["7", 0]}},
        "9": {"class_type": "SaveImage", "inputs": {"images": ["8", 0], "filename_prefix": "lora_dataset"}},
    }

    # LoRA链式挂载(插入LoraLoader节点)
    if loras:
        lora_node_id = "10"
        prev_model = ["2", 0]
        for i, (lora_name, weight) in enumerate(loras):
            if weight == 0:
                continue
            nid = str(10 + i)
            workflow[nid] = {"class_type": "LoraLoader", "inputs": {
                "lora_name": lora_name, "strength_model": weight, "strength_clip": weight,
                "model": prev_model, "clip": ["6", 0]}}
            prev_model = [nid, 0]
        workflow["1"]["inputs"]["model"] = prev_model

    # hybrid混合流:raw前N步 + turbo后M步(需用ModelSamplingSD3或自定义节点实现)
    # 简化版:hybrid用raw_steps参数控制,实际需根据工作流调整
    if wf == "hybrid":
        workflow["1"]["inputs"]["steps"] = params["total_steps"]
        # 注:完整hybrid实现需要raw+turbo双UNet切换,agent可根据实际工作流扩展

    return workflow, client_id

def generate_one(wf="turbo", prompt="", negative="", seed=None,
                 size=(1024,1024), loras=None, out_prefix="gen", timeout=300, **kwargs):
    """
    单张生成
    wf: turbo / raw / hybrid
    prompt: 正面提示词
    negative: 负面提示词(turbo/hybrid下cfg=1负面无效,可留空)
    seed: 随机种子,None=随机
    size: (宽,高)
    loras: [(lora文件名, 权重), ...],权重0跳过
    out_prefix: 输出文件名前缀
    返回: {ok, path, seed, prompt, negative, loras, size, wf}
    """
    if seed is None:
        seed = random.randint(1, 2**31 - 1)
    loras = loras or []

    workflow, client_id = _build_workflow(wf, prompt, negative, seed, size, loras, **kwargs)
    workflow["9"]["inputs"]["filename_prefix"] = out_prefix.replace("\\", "/")

    try:
        resp = _queue_prompt(workflow, client_id)
        prompt_id = resp["prompt_id"]
        history = _get_history(prompt_id)
        outputs = history.get("outputs", {})
        # 提取保存的图片路径
        img_path = None
        for node_id, out in outputs.items():
            if "images" in out:
                for img in out["images"]:
                    img_path = os.path.join(COMFY_URL.replace(":8188", ""), "view", f"?filename={img['filename']}&subfolder={img.get('subfolder','')}&type={img.get('type','output')}")
        return {"ok": True, "path": img_path, "seed": seed, "prompt": prompt,
                "negative": negative, "loras": loras, "size": size, "wf": wf}
    except Exception as e:
        return {"ok": False, "error": str(e), "seed": seed, "prompt": prompt}

def generate_batch(wf="turbo", tasks=None, negative="", size=(1024,1024),
                   out_prefix="batch", timeout=300, **kwargs):
    """
    批量生成(迭代抽卡主力)
    tasks: [{"name":"01","prompt":"...","seed":123,"loras":[...],"size":(1024,1344)}, ...]
           每条task可单独覆盖公共参数
    跑完自动写 record JSON 到 output/ 目录
    """
    tasks = tasks or []
    results = []
    for i, task in enumerate(tasks):
        name = task.get("name", f"{i:04d}")
        print(f"[{i+1}/{len(tasks)}] {name}")
        rec = generate_one(
            wf=task.get("wf", wf),
            prompt=task["prompt"],
            negative=task.get("negative", negative),
            seed=task.get("seed"),
            size=task.get("size", size),
            loras=task.get("loras", []),
            out_prefix=f"{out_prefix}/{name}",
            timeout=timeout,
            **{k:v for k,v in task.items() if k not in ["name","prompt","negative","seed","size","loras","wf"]}
        )
        rec["name"] = name
        results.append(rec)

    # 保存record到out_prefix所在目录(项目级output目录)
    record_dir = os.path.join(OUTPUT_ROOT, os.path.dirname(out_prefix)) if os.path.dirname(out_prefix) else OUTPUT_ROOT
    os.makedirs(record_dir, exist_ok=True)
    record_path = os.path.join(record_dir, f"{os.path.basename(out_prefix).replace('/','_')}_record.json")
    with open(record_path, "w", encoding="utf-8") as f:
        json.dump({"wf": wf, "total": len(tasks), "results": results}, f, ensure_ascii=False, indent=2)
    print(f"记录已保存: {record_path}")
    return results

def clear_queue():
    """清空ComfyUI队列(卡死时用)"""
    try:
        urllib.request.urlopen(f"{COMFY_URL}/queue", data=b"").read()
    except: pass

def interrupt():
    """中断当前生成"""
    try:
        urllib.request.urlopen(f"{COMFY_URL}/interrupt", data=b"").read()
    except: pass

重要:上述脚本中的工作流节点ID("1","2","3"...)和模型文件名是模板。agent首次创建后,必须对照本机ComfyUI中实际的krea2_turbo / krea2_raw工作流JSON,修正节点编号和模型文件名,否则无法运行。修正方法:在ComfyUI中打开工作流→右键→Export(API Format)→用实际JSON替换 _build_workflow 函数中的结构。

4.2 测试流程(创建后必须执行)

创建脚本后,依次测试三种基础工作流,每种生成1张测试图:

import sys, os
sys.path.insert(0, os.path.join("lora-dataset", "core"))
from comfy_krea import generate_one

TEST_PROMPT = "一位20岁东方女性,正面半身肖像,黑色长发,自然微笑,纯色背景,真实人像摄影"
TEST_NEG = "低画质,模糊,变形,多人"

# 测试1: turbo(应~30秒出图)
r1 = generate_one("turbo", TEST_PROMPT, TEST_NEG, seed=77777777, size=(1024,1024), out_prefix="test/turbo")
print(f"turbo: ok={r1['ok']}, seed={r1['seed']}")

# 测试2: hybrid混合流(应~40秒出图)
r2 = generate_one("hybrid", TEST_PROMPT, TEST_NEG, seed=77777777, size=(1024,1024), out_prefix="test/hybrid", raw_steps=6, total_steps=12)
print(f"hybrid: ok={r2['ok']}, seed={r2['seed']}")

# 测试3: raw(应~100秒出图,负面词生效)
r3 = generate_one("raw", TEST_PROMPT, TEST_NEG, seed=77777777, size=(1024,1024), out_prefix="test/raw")
print(f"raw: ok={r3['ok']}, seed={r3['seed']}")

测试通过标准

  • 三种工作流均返回 ok=True
  • 输出目录 lora-dataset/output/test/ 下有对应图片
  • 图片无明显崩坏(人脸正常、无黑图/灰图)

测试不通过:检查ComfyUI是否运行、模型文件名是否正确、节点ID是否匹配实际工作流。修正后重测,直到三种全部通过。

4.3 BBOX工作流(可选,需用户安装节点)

BBOX结构化构图工作流需要安装自定义节点:

  • 节点仓库:https://github.com/ukr8b3g-cmyk/Krea2-BBOX-Prompter
  • 安装方法:在ComfyUI的 custom_nodes/ 目录下 git clone 该仓库,重启ComfyUI
  • 适用场景:补角度短板(纯侧/背身)、稳定全身防裁切、精确控景别
  • 注意:BBOX对泪痣/银铃等小细节控制弱,面部锚点抽卡不推荐使用

提示用户:如果需要BBOX功能,请先告知用户安装上述自定义节点;未安装时只用turbo/hybrid/raw三种基础流。


五、迭代规则(内置,每轮必须遵守)

5.1 迭代总原则(不可妥协)

  1. 每轮必须评估、总结、调优后再进下一轮,禁止盲跑多轮。
  2. 每轮结束即出报告,不积压、不事后补写。
  3. 以设计稿为唯一验收标准,每轮对照检查不变量是否达标。
  4. 优秀提示词和参数必须沉淀,下一轮优先复用,避免重复踩坑。
  5. 失败原因必须记录,同类错误不允许出现第三次。

5.2 每轮闭环流程

设定本轮目标 → 批量出图 → 逐张评估 → 总结沉淀 → 调优下一轮
     ↑                                              │
     └──────────────────────────────────────────────┘

设定目标:明确本轮核心问题(如泪痣位置、脸型、服装形制),确定样本量/景别配比/工作流配比。

批量出图:使用固化脚本,种子/LoRA权重/尺寸/工作流必须记录到config JSON。

逐张评估:对照设计稿不变量逐项检查,统计合格数/淘汰数/淘汰原因分类。逐张分析记录存入 projects/<项目名>/reports/analyses/,与总结报告分开。

总结沉淀:归纳有效提示词片段、参数组合、失败根因,更新 knowledge/ 下三个文档。

调优下一轮:基于本轮结论调整提示词/LoRA权重/种子/工作流配比,保留有效参数,替换无效参数。

5.3 入库评判铁律

图片入库只看设计稿,不看提示词。 两个维度严格分离:

| 维度 | 评判标准 | 用途 | |---|---|---| | 图片入库 | 只看图片本身是否符合设计稿(脸型/眼型/发型/身材/服装/标记等) | 决定是否选入训练集 | | 提示词记录 | 只有"出图质量好且符合提示词"的才记录 | 用于优化提示词,与入库无关 |

具体执行:

  • 提示词写全身但出成半身/大头→按实际景别评判,符合设计稿就入对应训练集
  • 提示词写A服装但出成B服装→只要B服装符合设计稿就可入库
  • "不符合提示词"永远不是废图理由

5.4 入库与打标规则

  1. 合格图复制到 projects/<项目名>/dataset/head|half|full/,按规范重命名:<模块>_v<版本>r<轮次>_t<序号>.png
  2. 必须同步生成同名.txt,内容两段(见第七节5.2)
  3. 记录原始文件名→训练集新文件名对应关系
  4. 单套服装样本不超过总量10%,表情/姿势/光影/角度必须覆盖设计稿要求

5.5 迭代终止条件

满足任一可暂停:

  1. 连续2轮合格率≥70%,且不变量稳定
  2. 训练集数量达到目标(角色IP建议150-200张)
  3. 核心锚点(脸型/眼型/发型/身材)连续3轮达标率≥80%
  4. 用户明确喊停

暂停后输出全量汇总,包含所有轮次参数沉淀、提示词库、踩坑记录、训练集统计。


六、执行流程(7步)

Step 1:设计稿解析

通读设计稿,提取两张清单:

不变量(硬锚点,每张必须达标)

  • 脸型、眼型、发型、身材、标记物(痣/疤/饰品)、肤色妆容基调

可变维度(多样性来源)

  • 表情≥8种、姿势≥8种、角度≥6种、光影≥6种
  • 服装≥5色系×3形制,单套不超过总量10%
  • 背景≥5种

设计稿常见坑预判

  • 泪痣位置→模型对"右眼"理解=画面右侧,建议降级为偶发钩子(10-25%概率),不强制每张必出
  • 花钿→古风情绪词(温婉/明艳)会触发,负面词需强化+去掉情绪形容词
  • 银铃→半身照看不到脚踝,写了必跑手腕,半身不写银铃只在全身写

Step 2:提示词模板

三段式结构

【角色锚点段】脸型+眼型+发型+肤色+妆容(固定,所有景别共用)
【身材/服装段】身材描述+具体服装形制+颜色+刺绣+袖型(半身/全身用)
【构图/光影段】景别+姿势+表情+光影+背景+镜头(按景别换)

各景别参数: | 景别 | 尺寸 | 脸占比 | LoRA权重(如有身材LoRA) | 关键描述 | |---|---|---|---|---| | 大头 | 1024×1024 | 60-75% | 0.5 | 头部角度+表情+光影 | | 半身 | 1024×1344 | 30-40% | 0.9 | 头顶到大腿中段,面部完整可见双眼 | | 全身 | 1024×1600 | 15-25% | 1.0 | "镜头拉远+人物占九成高+双脚在底部+严禁裁脚" |

通用负面词库(复制即用):

网红脸,AI平均脸,圆脸,宽脸,大脸,方脸,圆下巴,钝下颌,
杏眼圆润,圆眼睛,大眼,狐狸眼吊梢眼,
花钿,额饰,面靥,眼尾花纹,多颗痣,双痣,痣串,雀斑,斑点,
旗袍,立领,盘扣,短袖,无袖,吊带,现代服装,高开衩,
平胸,小胸,无腰,臀下垂,瘦弱,骨感,比例失衡,
断肢,坏手,多指,缺指,畸形,多人,裁切,头部裁切,脚部裁切,
银铃在手腕,银铃在手上,多个银铃,双脚都有银铃,
低画质,模糊,塑料磨皮,文字水印

长度铁律:单条提示词≤400字(Qwen3-VL-4B文本编码器上限,超长会OOM)。

Step 3:迭代抽卡

每轮配置

  • 20-24张:大头10 + 半身6 + 全身8
  • 工作流配比:turbo 70% + hybrid 30%(角色脸禁用raw和bbox)
  • 种子区间:77777777-77777816(花钿率低,已验证)
  • 输出到 projects/<项目名>/output/round<N>_

工作流选择结论(已验证): | 工作流 | 速度 | 负面词 | 角色脸抽卡 | |---|---|---|---| | turbo | ~30s | ❌无效 | ⭐⭐⭐⭐⭐ 主力(发型/脸型锁定最稳) | | hybrid | ~38s | ❌无效 | ⭐⭐⭐⭐ 辅助(质量/速度平衡) | | raw | ~100s | ✅生效 | ⭐⭐ 禁用(发型5/6跑偏、脸型3/6偏圆) | | bbox | ~40s | ❌无效 | ⭐⭐ 禁用(小细节弱,泪痣变泪痕) |

Step 4:逐张评估

评估铁律:只看设计稿,不看提示词(见5.3)。

逐张检查清单

  • [ ] 脸型?眼型?发型?
  • [ ] 身材(半身/全身)?标记物位置?
  • [ ] 无花钿/多颗痣/短袖硬伤?
  • [ ] 无结构错误(断肢/多指/裁切)?
  • [ ] 画质清晰?

统计:合格数、淘汰数、淘汰原因TOP3分类。逐张分析存入 projects/<项目名>/reports/analyses/<模块>_图片分析_R<N>_<日期>.md

Step 5:入库与同步打标

入库:合格图复制到 projects/<项目名>/dataset/head|half|full/,重命名,记录对应关系。

同步打标(必须,格式严格统一):每张 xxx.png 必须伴随同名 xxx.txt,UTF-8编码,内容固定为以下两段格式:

【源提示词】
正向:<生成该图时实际使用的完整prompt,从record JSON提取,一字不改,含加权语法>
负面:<完整negative prompt,无负面词则写"无">
LoRA:<lora文件名> @ <权重>;<第二个lora> @ <权重>(无LoRA则写"无")
工作流:<turbo|hybrid|raw> | 种子:<数字> | 尺寸:<宽>×<高>
原始文件:<output目录中的原始文件名>

【训练caption】
<触发词>, <脸型>, <眼型>, <发型>, <身材描述>, <服装形制>, <服装颜色>, <姿势>, <表情>, <光影>, <背景>

格式铁律

  1. 两段标题固定为 【源提示词】【训练caption】,不可改名
  2. 字段名固定为 正向:负面:LoRA:工作流:原始文件:,冒号为中文全角
  3. 多个LoRA用分号分隔,如 curve_body_v2.safetensors @ 0.9; sjq_face_v1.safetensors @ 0.7
  4. 无LoRA时写 LoRA:无,不可留空
  5. 源提示词必须从当轮record JSON提取,不得凭记忆补写或改写
  6. 训练caption以触发词开头(如 shenjingque, ),后续用英文逗号+空格分隔
  7. 训练caption只保留角色特征+服装+姿势+表情+光影+背景,去掉镜头/画质/分辨率等套话
  8. 原始文件字段记录output目录中的文件名,便于回溯

完整示例

【源提示词】
正向:沈惊鹊,鹅蛋偏瓜子脸,下颌尖窄,瑞凤眼,眼尾飞挑,半挽垂发,颊边碎发,暖象牙白瓷光肌,沙漏身材,C杯胸,极细腰,绯红织金礼服,广袖,交领,腰封,长裙,侧身回眸,微微笑,暖侧光,竹林背景,真实人像摄影
负面:网红脸,圆脸,宽脸,花钿,额饰,多颗痣,短袖,平胸,断肢,坏手,低画质,模糊
LoRA:curve_body_v2.safetensors @ 0.9
工作流:turbo | 种子:77777801 | 尺寸:1024×1344
原始文件:round1_half_03_00001_.png

【训练caption】
shenjingque, 鹅蛋偏瓜子脸, 瑞凤眼, 半挽垂发, 沙漏身材, 绯红织金礼服, 广袖, 交领, 腰封, 长裙, 侧身回眸, 微笑, 暖侧光, 竹林背景

Step 6:迭代调优

本轮淘汰原因TOP3 → 针对性修改提示词/负面词/参数 → 下一轮验证
  ↓
有效参数→knowledge/params.md
踩坑→knowledge/pitfalls.md
金牌提示词→knowledge/prompts.md

每轮总结存入 projects/<项目名>/reports/summaries/<模块>_迭代总结_R<N>_<日期>.md

Step 7:训练配置(达标后)

通用训练参数(适用于ModelScope / kohya等): | 参数 | 推荐值 | 说明 | |---|---|---| | 网络大小(dim) | 32 | | | 网络Alpha | 32 | alpha=dim | | Unet学习率 | 0.0001 | 主力 | | 文本编码器学习率 | 0.00001 | 比Unet低10倍 | | 调度器 | cosine_with_restarts | 重启3次 | | 优化器 | AdamW | | | 混合精度 | fp16 | | | 图片分辨率 | 1024×1024 | 开启arb桶 | | 最大token | 225 | | | 打乱标注 | 开启 | | | 训练步数 | 先2000-3000步试效果 | 稳定后5000-6000步 | | 保存间隔 | 每500步 | 方便挑选最佳epoch |

训练集配比:大头40% + 半身35% + 全身25%,总量150-200张起步。


七、关键参数速查表

| 项目 | 值 | 置信度 | |---|---|---| | 主力工作流 | turbo(角色脸) | ✅已验证 | | 辅助工作流 | hybrid(多样性) | ✅已验证 | | 禁用工作流 | raw(发型锁不住)、bbox(小细节弱) | ✅已验证 | | 种子区间 | 77777777-77777816 | ✅已验证 | | 大头尺寸 | 1024×1024 | ✅ | | 半身尺寸 | 1024×1344 | ✅ | | 全身尺寸 | 1024×1600(非1536,1536易被裁) | ✅ | | 身材LoRA权重 | 大头0.5/半身0.9/全身1.0 | ✅ | | 单条提示词长度 | ≤400字 | ✅ | | batch_size | 1 | ✅ | | 每轮张数 | 20-24 | ✅ | | 目标训练集 | 150-200张 | ✅ | | 大头:半身:全身 | 4:3:3 | ✅ |


八、踩坑速查(Top 10)

| # | 坑 | 触发条件 | 对策 | 状态 | |---|---|---|---|---| | 1 | 泪痣位置反 | 写"右眼" | 降级为偶发钩子,不强制每张必出 | ✅闭环 | | 2 | 多颗痣 | 写"全脸仅此一颗" | 不写数量否定+负面"多颗痣" | ✅解决 | | 3 | 花钿 | 古风情绪形容词 | 去情绪词+负面"花钿,额饰" | ✅解决 | | 4 | 广袖变短袖 | turbo+广袖 | 半身/全身用宽袖款+负面"短袖" | ✅解决 | | 5 | 银铃跑手腕 | 半身照写银铃 | 半身不写银铃,只在全身写 | ✅解决 | | 6 | 银铃跑手上 | 全身+手部复杂 | 负面加"银铃在手上,挂手指,吊手上" | ⚠️偶发 | | 7 | raw锁不住发型 | raw+半挽垂发 | 角色脸用turbo,不用raw | ✅解决 | | 8 | bbox小细节弱 | bbox+泪痣/银铃 | 面部锚点不用bbox | ✅解决 | | 9 | ComfyUI OOM | 提示词>400字+batch=2 | ≤400字+batch=1+每轮重启 | ✅解决 | | 10 | 全身被裁脚 | 写"全身照"+1536高度 | 1600高度+"镜头拉远+脚在底部" | ✅解决 |


九、合格率进化参考

9轮迭代实测(沈惊鹊角色IP):

R1:18% → R2:41% → R3:69% → R4:82% → R5:91% → R6:100% → R7:83% → R8:92% → R9:92%

通常3-4轮后稳定在80%+,6-9轮凑齐150-200张。


十、交付物清单

一次完整的角色LoRA训练集构建,应交付:

  1. ✅ 训练集图片(150-200张,分head/half/full目录)
  2. ✅ 每张图片的同名.txt打标文件(源提示词+训练caption)
  3. ✅ 迭代报告(每轮总结+逐张分析记录)
  4. ✅ 知识沉淀(参数/踩坑/提示词库三个文档)
  5. ✅ 训练配置单
  6. ✅ 文件名对应关系登记表

Skill创建:2026-08-31 | 通用版,基于9轮迭代实践提炼 | 维护:每次新角色训练后更新