ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ComfyUI批量测试画师风格LoRA:用Python脚本一键出图

ComfyUI批量测试画师风格LoRA:用Python脚本一键出图 先问你一个实际场景你刚下载了一个动漫风格的底模比如 Anima又花了几天时间从社区收集了几百个画师风格 LoRA几百个文件躺在models/loras目录里。下一步你打算怎么做大概率是打开 ComfyUI手动拖一个 LoRA 节点挑个测试 prompt点运行看图不满意换下一个 LoRA再点运行。几百个 LoRA 如果都这么测一遍哪怕每个只花两分钟也要大半天而且中途你还会犯困、看走眼、记错顺序。批量测试画师风格并不是什么高深技术但它是从“能用”走向“好用”的关键一步。这篇文章从 Anima 这个动漫底模出发讲清楚什么是 4w 画师风格资源、为什么要做批量测试、以及如何用 Python 脚本配合 ComfyUI 工作流实现一键批量出图。文末给出可直接复制运行的代码示例并补充常见的坑和排查思路。1. 为什么说批量测试画师风格是刚需先看传统工作流的效率瓶颈在哪里。ComfyUI 的画图流程本质是“节点图”加载大模型、加载 LoRA、输入提示词、采样、解码、保存。手动测试画师风格时每换一个风格都要改 LoRA 节点这中间的操作成本很小真正贵的是人盯着图看的那段时间。如果一个风格要出 4 张不同参数的图才能判断风格契合度几百个风格就是上千次点击和上千次等待。成本还不只是时间。手动测试最大的问题不是慢而是不标准。你今天用seed100测了 A 画师明天用seed200测 B 画师两张图的构图、姿态、光线全不一样你根本分不清风格差异是 LoRA 带来的还是 seed 变化带来的。这种情况下得出的“这个画师风格不适合”结论参考价值很低。批量测试要解决的就是这两点把重复劳动交给代码节省人工盯图和切换节点的时间。固定每个画师 LoRA 的测试条件用同一 prompt、同一 seed、同一采样器、同一分辨率去跑让对比结果真正可比。从工程角度看这其实是一个批量实验管理问题。你不需要每次手动改参数而是把画师 LoRA 清单变成输入把出图结果变成输出中间的过程全部脚本化。这也是 Agent 时代里“工作流”二字被频繁提起的原因当操作步骤可以被描述成确定性流程时它就可以被自动化。2. Anima 是什么4w 画师风格意味着什么Anima 是一个以动漫风格为导向的 AI 绘画底模。它和 SD 1.5、SDXL 这类通用底模的定位不同Anima 更侧重二次元角色、日系动漫、平面插画等风格。实际使用中Anima 通常作为 checkpoint 大模型放在 ComfyUI 的models/checkpoints目录下。“4w 画师风格”这个数字怎么理解这不是说 Anima 模型内部内置了 4 万个风格。通常的说法是社区围绕 Anima 生态收集、整理、训练了大量画师风格 LoRA风格库总量已经达到数万规模也就是标题里提到的 4w。这些 LoRA 文件本质上是非常小的模型补丁通常只有几十 MB 到两百 MB 左右用于在生成图像时注入特定画师的笔触、配色和构图习惯。这带来的一个直接好处是你不需要重新训练底模就能获得成百上千种画师风格。打个比方Anima 底模像一张白纸画师风格 LoRA 像不同品牌的画笔。同一个姿势、同一个构图换一支画笔出来的气质就完全不同。LoRA 让风格切换的边际成本变得极低——你已经有了底模只需要再准备一批 LoRA 文件即可。不过这里要特别提醒一句画师风格 LoRA 的训练和使用涉及版权问题尤其是还在世、还在创作的画师。技术上的可行不等于法律和道德上的合理。在自己的学习、研究中测试风格迁移没有问题但如果要商用、要发布到公开平台建议先确认风格授权情况或者使用明确开放授权的风格资源。3. 批量测试的整体方案设计批量测试画师风格本质上就是一个批处理流水线。流水线要处理的问题有三个动态选择 LoRA 文件。固定除 LoRA 之外的所有生成参数。记录每一次生成使用的 LoRA 和种子方便回看。实现方式有两条路线路线 A在 ComfyUI 界面里手动改 LoRA 节点跑一张存一张。路线 B通过 Python 脚本调用 ComfyUI 的 API自动替换 LoRA 并批量出图。路线 A 简单适合偶尔试 5 到 10 个风格。路线 B 适合规模化测试因为脚本可以做到读取一份风格清单逐条运行最终生成一套带命名的图片甚至输出一份统计表。这篇文章重点讲路线 B。整体架构如下风格清单JSON/TXT - Python 脚本逐条读取 - 动态替换 ComfyUI API 请求 JSON 中的 LoRA 名称 - 提交到本地 ComfyUI 服务 - 等待生成完成 - 按命名规则保存图片 - 进入下一轮这套方案的核心优势在于一旦通了以后任何批量测试需求都能复用。不仅仅测画师风格以后测 checkpoint、测 prompt 模板、测采样器组合都可以改一改脚本跑起来。4. 环境准备与基础配置4.1 必需的软件环境开始之前先确认本地环境是否满足最低要求。操作系统Windows / Linux / macOS 均可本文以 Windows 为主说明Linux 命令类似。Python3.10 及以上建议使用独立虚拟环境。ComfyUI建议安装最新稳定版。具体版本请以实际安装为准本文重点演示通用逻辑。显卡建议至少有 8 GB 显存。显存不足时可将图片分辨率调低或者使用 CPU 模式速度慢很多不推荐批量测试。网络本机运行不需要外网。首次下载模型时可能需要联网这里不展开。如果你已经有 ComfyUI 环境可以直接跳到下一节。4.2 Anima 模型与画师 LoRA 的放置目录ComfyUI 对模型目录有固定约定。最容易踩的坑就是把模型放错了文件夹导致界面或 API 找不到文件。常见目录结构如下ComfyUI/ ├── models/ │ ├── checkpoints/ # 大模型Anima 底模放这里 │ ├── loras/ # LoRA 模型画师风格 LoRA 放这里 │ ├── vae/ # VAE 模型 │ └── ... ├── custom_nodes/ # 自定义节点 ├── input/ # 输入图片 └── output/ # 输出图片Anima 底模文件放在models/checkpoints画师风格 LoRA 文件放在models/loras。文件名尽量用英文和数字命名避免中文或特殊字符因为 API 请求中需要直接引用文件名。4.3 启动 ComfyUI 并确认 API 服务可用启动方式根据你安装的方式略有不同。Windows 下通常直接运行脚本python main.py启动成功后ComfyUI 默认会监听127.0.0.1:8188。这时可以用浏览器访问http://127.0.0.1:8188确认界面能正常打开后再验证 API 是否可用浏览器访问http://127.0.0.1:8188/system_stats如果返回一段 JSON包含系统信息、设备信息等说明 API 服务正常。5. 核心代码实现一键批量测试脚本下面进入本文的重点部分。我会用一个最小可运行示例带你完成从“逐个手动切换”到“一条命令批量出图”的转变。5.1 准备画师风格清单批量测试的第一步不是写脚本而是整理一份风格清单。我把清单定义成一个 JSON 文件放在项目根目录下。它的内容如下// 文件路径styles.json [ { name: painter_a, lora: painter_a.safetensors, weight: 0.8 }, { name: painter_b, lora: painter_b.safetensors, weight: 0.9 }, { name: painter_c, lora: painter_c.safetensors, weight: 0.7 } ]字段说明name用于输出文件命名方便回看。lora实际的 LoRA 文件名必须和models/loras目录下的文件名完全一致。weightLoRA 融合权重默认 0.8不同画师风格可能需要微调。当然如果你有几百个 LoRA不可能手写 JSON。更实际的做法是写一段小脚本扫描models/loras目录自动生成清单# 文件路径make_style_list.py import os import json loras_dir models/loras style_list [] for fname in os.listdir(loras_dir): if fname.endswith(.safetensors) or fname.endswith(.ckpt): style_list.append({ name: fname.split(.)[0], lora: fname, weight: 0.8 }) with open(styles.json, w, encodingutf-8) as f: json.dump(style_list, f, ensure_asciiFalse, indent2) print(f已生成 {len(style_list)} 条风格记录)这个脚本会扫描models/loras目录下所有.safetensors和.ckpt文件并为每个文件生成一条默认权重 0.8 的记录。文件名去掉了扩展名作为name字段。5.2 准备 ComfyUI API 请求模板ComfyUI 的 API 调用方式很直接把工作流节点图序列化成一个 JSONPOST 到/prompt接口ComfyUI 就会开始执行。一个简化版的文生图工作流 JSON 如下{ 3: { class_type: KSampler, inputs: { seed: 42, steps: 28, cfg: 7.0, sampler_name: dpmpp_2m, scheduler: karras, denoise: 1.0, model: [4, 0], positive: [6, 0], negative: [7, 0], latent_image: [5, 0] } }, 4: { class_type: CheckpointLoaderSimple, inputs: { ckpt_name: anima_model.safetensors } }, 5: { class_type: EmptyLatentImage, inputs: { width: 512, height: 768, batch_size: 1 } }, 6: { class_type: CLIPTextEncode, inputs: { text: 1girl, anime style, masterpiece, best quality, clip: [4, 1] } }, 7: { class_type: CLIPTextEncode, inputs: { text: bad anatomy, bad hands, worst quality, clip: [4, 1] } }, 8: { class_type: VAEDecode, inputs: { samples: [3, 0], vae: [4, 2] } }, 9: { class_type: SaveImage, inputs: { filename_prefix: anima_test, images: [8, 0] } } }这个 JSON 里节点4加载大模型节点3执行采样节点9保存图片。这里故意先不写 LoRA 节点因为等一下我会用 Python 脚本在运行时动态插入。注意model: [4, 0]这种写法是 ComfyUI API 的节点引用方式表示“取节点 4 的输出第 0 个值”。这个结构是固定的不需要背从 ComfyUI 界面导出工作流时可以看到同格式。5.3 Python 脚本动态注入 LoRA 并批量生成现在写核心脚本。它要完成四件事读取styles.json。读取workflow.json作为模板。对每一条风格记录向模板中插入一个LoraLoader节点并连接到大模型和采样器之间。提交到 ComfyUI API等待生成完成然后继续下一条。# 文件路径batch_test_styles.py import json import time import urllib.request import os WORKFLOW_FILE workflow.json STYLE_LIST_FILE styles.json COMFY_URL http://127.0.0.1:8188 OUTPUT_DIR output/styles def load_json(path): with open(path, r, encodingutf-8) as f: return json.load(f) def build_workflow(template, lora_name, lora_weight): workflow json.loads(json.dumps(template)) # 新增 LoRA 节点节点 ID 使用 10避免和已有节点冲突 workflow[10] { class_type: LoraLoader, inputs: { lora_name: lora_name, strength_model: lora_weight, strength_clip: lora_weight, model: [4, 0], clip: [4, 1] } } # 让采样器从 LoRA 节点加载模型和 CLIP workflow[3][inputs][model] [10, 0] workflow[3][inputs][positive] [6, 0] # 正负提示词编码器的 CLIP 也要从 LoRA 节点取 workflow[6][inputs][clip] [10, 1] workflow[7][inputs][clip] [10, 1] # 修改保存文件名前缀方便区分 workflow[9][inputs][filename_prefix] fanima_{lora_name.split(.)[0]} return workflow def submit_prompt(workflow): data json.dumps({prompt: workflow}).encode(utf-8) req urllib.request.Request( f{COMFY_URL}/prompt, datadata, headers{Content-Type: application/json} ) with urllib.request.urlopen(req) as resp: result json.loads(resp.read().decode(utf-8)) return result.get(prompt_id) def wait_for_completion(prompt_id, timeout300): start time.time() while time.time() - start timeout: try: with urllib.request.urlopen(f{COMFY_URL}/history/{prompt_id}) as resp: history json.loads(resp.read().decode(utf-8)) if prompt_id in history: status history[prompt_id].get(status, {}) if status.get(completed) or status.get(status_str) success: return True if status.get(status_str) error: return False except Exception: pass time.sleep(2) return False def main(): os.makedirs(OUTPUT_DIR, exist_okTrue) template load_json(WORKFLOW_FILE) styles load_json(STYLE_LIST_FILE) for idx, style in enumerate(styles, start1): print(f[{idx}/{len(styles)}] 测试风格: {style[name]}) workflow build_workflow( template, style[lora], style.get(weight, 0.8) ) prompt_id submit_prompt(workflow) if not prompt_id: print(f - 提交失败) continue success wait_for_completion(prompt_id) if success: print(f - 生成完成) else: print(f - 生成失败或超时) if __name__ __main__: main()这段代码有几个关键点值得展开第一动态插入 LoRA 节点。我没有在workflow.json里预留 LoRA 节点而是在运行时动态构造节点 10再把采样器的 model 输入、正负提示词编码器的 CLIP 输入都指向该节点。这样做的好处是模板干净适配不同编号的 LoRA 节点时只需要改一处。第二深拷贝模板。脚本里用了json.loads(json.dumps(template))这是为了完全复制一份模板对象防止修改一个workflow时污染下一轮循环。第三等待机制。wait_for_completion轮询/history/{prompt_id}接口直到任务完成或超时。这是批量调度必须的一步。如果不等待脚本会一口气提交几百个任务显卡负担过重反而拖慢整个测试流程。如果你希望批量测试跑完后自动把所有图片归档到独立目录可以在main末尾加一步复制逻辑或者直接在 ComfyUI 的图片保存节点里把filename_prefix按“风格名”区分即可。上面代码已经在文件名前缀中加入了 LoRA 名称输出目录会变成ComfyUI/output/anima_painter_a_00001_.png ComfyUI/output/anima_painter_b_00001_.png这样不至于所有图片混在一起没法识别。5.4 运行时指定测试数量如果风格库数量很大比如上万条一次性跑完不现实。更稳妥的做法是支持只测前 N 个风格# 在 main() 中增加一个测试数量限制参数 import sys def main(): limit None if len(sys.argv) 1: limit int(sys.argv[1]) # ... 读取 styles 后 if limit: styles styles[:limit] # ... 后续逻辑不变命令行用法python batch_test_styles.py 10这样只测试前 10 个 LoRA适合先小批量验证流程是否正常。6. 工作流里真正的坑参数基准一致性很多教程讲批量测试讲完代码就结束了。但实际跑过的人会有体会代码只是表面真正的坑在参数基准一致性上。什么叫参数基准一致性就是说除了 LoRA 名称和权重其他所有影响出图结果的因素都必须保持固定。包括底模文件名称采样器名称和调度器采样步数 stepsCFG 值图片分辨率seed 值正负提示词是否开启高清修复VAE 是否固定为什么强调这点因为很多人以为只要 prompt 一样、seed 一样结果就可比。但实际上ComfyUI 对seed的解析方式会受节点顺序影响。如果你在工作流模板里手动改了 LoRA 的strength_modelseed 相同但结果完全不同的情况也经常出现。在批量测试中我建议把测试基准参数单独抽象出来集中管理// 文件路径base_config.json { checkpoint: anima_model.safetensors, seed: 12345, steps: 28, cfg: 7.0, sampler_name: dpmpp_2m, scheduler: karras, width: 512, height: 768, positive_prompt: 1girl, anime style, masterpiece, best quality, negative_prompt: bad anatomy, bad hands, worst quality }然后修改build_workflow函数让它先读取基准配置再应用 LoRA。这样以后你只需要改base_config.json中的 seed 或 prompt所有风格测试都会统一更新不需要改动脚本逻辑。这里也解释一个新手容易误解的概念LoRA 权重不是越高越好。默认 0.8 只是经验值。有些画师风格 LoRA 在 0.6 时更协调有些要到 1.0 才明显。所以在批量测试一轮之后建议对表现不错的 LoRA 做一次权重扫描比如以 0.05 为步长测试 0.6 到 1.0挑选最合适的权重值。这也是一轮小规模批量测试可以直接复用本文的脚本。7. 运行结果与效果验证脚本跑完后怎么验证是成功还是失败7.1 正常完成的效果在 ComfyUI 的output目录下你会看到类似这样的文件ComfyUI/output/ ├── anima_painter_a_00001_.png ├── anima_painter_b_00001_.png └── anima_painter_c_00001_.png如果你的filename_prefix里只用了 LoRA 名称没有加序号文件名可能会是ComfyUI/output/anima_painter_a_.png这也能用但建议保留序号因为同一风格如果测试多张图序号可以帮助区分。打开图片后主要看两个维度风格是否体现画风、配色、线条质感是否贴近该画师的代表性风格。画面质量是否稳定有没有出现肢体崩坏、畸变、色彩浑浊等明显质量问题。7.2 需要检查的状态指标如果脚本逻辑正确跑完后终端应该逐条输出[1/3] 测试风格: painter_a - 生成完成 [2/3] 测试风格: painter_b - 生成完成 [3/3] 测试风格: painter_c - 生成完成如果某条显示“生成失败或超时”优先做三件事查看 ComfyUI 服务端控制台日志是否有异常堆栈。检查该 LoRA 文件名是否真的存在于models/loras目录。检查该 LoRA 是否损坏。可以单独在 ComfyUI 界面里手动加载一次试试。7.3 批量测试结果的整理当测试数量较多时直接翻图片不方便。建议生成一个简单的 HTML 预览页用脚本扫描输出目录把图片并排展示在网页上。这不属于必选项但在实际批量测试几百个风格时非常有用。实现思路# 文件路径make_preview.py import os import json output_dir ComfyUI/output images [f for f in os.listdir(output_dir) if f.endswith(.png)] images.sort() html [htmlheadmeta charsetutf-8/headbody] html.append(h1批量风格测试结果预览/h1) for img in images: html.append(fdiv styledisplay:inline-block;margin:10px;) html.append(fimg src{img} width256 height384) html.append(fp{img}/p/div) html.append(/body/html) with open(preview.html, w, encodingutf-8) as f: f.write(\n.join(html)) print(f已生成 preview.html包含 {len(images)} 张图片)运行后用浏览器打开preview.html就能在一个页面里快速浏览所有风格测试结果。8. 常见问题与排查思路批量测试的问题往往集中在环境配置、API 调用、模型路径三个方面。这里整理了一份排查表问题现象可能原因排查方式解决方案启动 ComfyUI 失败提示代码 2Python 依赖缺失或版本冲突查看终端完整报错检查依赖安装情况在 Python 环境中执行依赖安装命令补齐缺失的包API 提交后立即失败JSON 中节点 ID 重复或引用错误检查build_workflow生成的 JSON确认节点引用完整将节点 ID 改成未使用的值确认[10, 0]这类引用存在LoRA 找不到文件名不匹配或目录不对对比models/loras下的实际文件名与 JSON 中lora字段统一文件名或重新扫描生成风格清单所有图片风格效果都很弱LoRA 权重过低或未生效检查生成的 JSON 中是否真正插入了 LoraLoader 节点提高strength_model或在正负提示词编码器中检查 CLIP 引用显存不足分辨率或批量大小设置过高观察进程占用和报错信息降低分辨率、降低 batch_size或加上--lowvram参数部分 LoRA 生成时间远长于其他部分 LoRA 尺寸较大或节点结构不同查看单个任务的耗时和显卡占用可针对大 LoRA 单独降低采样步数图片中画师风格串味LoRA 权重过高导致过拟合对比不同权重下的结果对候选风格做权重扫描找到平衡点这些问题的共同教训是不要一次性跑几千个 LoRA。先在 5 到 10 个风格上验证流程确认输出质量和文件名都没有问题再松开绳子跑全量。9. 批量测试的最佳实践与工程建议9.1 风格清单要纳入版本管理styles.json不要随手放在桌面。把它放到项目目录里并纳入 git 管理。这样当测试结果争议时可以回看“当时用哪个清单跑的”。每次批量测试之前记录当前的styles.json和base_config.json输出结果时把这两个文件一并复制到结果目录。9.2 命名规范决定回看效率建议文件名统一使用以下格式{实验名称}_{LoRA名称}_{seed}_{时间戳}.png例如anime_style_painter_a_12345_202501151230.png这样你看到文件名就能还原完整的生成条件不需要打开图片属性再排查。脚本里目前的命名是anima_{lora_name}你可以按实际需求扩展。9.3 每次只改变一个变量批量测试画师风格时seed、steps、cfg、prompt 都应当保持不变。一次只改变 LoRA。如果连提示词都要测试多个版本建议把“风格测试”和“prompt 测试”分成两个独立实验流程否则你无法辨认结果差异来自哪个变量。9.4 设置单风格超时机制在生产环境或长时间批量任务中wait_for_completion里的timeout参数可以根据模型复杂度和显卡性能调整。默认 300 秒对一张图通常够用但如果显存小、图片分辨率高建议调整到 600 秒以上避免任务正常生成但被判定为超时。9.5 注意版权与合规边界这是整个工作流里最容易忽略的问题。画师风格 LoRA 本质上是对特定画师作品的风格模仿。如果你计划把这些风格用于商业项目、公开作品集或者模型再训练需要提前确认授权范围。批量测试让你能快速筛选出“风格最合适”的 LoRA但它不能替你排除法律风险。9.6 从批量到自动化评估当你已经跑通批量生成下一步可以考虑“生成后自动评估”。比如用图像相似度算法将生成结果与原画师风格图片做对比或者用 CLIP score 对风格契合度打分。这不是必须的但它能把“人工看几百张图”的门槛进一步降低。不过自动评估只能做初筛最终的风格判断仍然需要人来完成。10. 总结与后续学习方向这篇文章从 Anima 批量测试画师风格的实际需求出发拆解了传统手动测试的痛点给出了一个基于 ComfyUI API 和 Python 脚本的批量测试方案。核心思路并不复杂准备风格清单、动态注入 LoRA、固定基准参数、批量提交任务、自动命名输出。当你真正跑通之后这套脚本可以扩展到 checkpoint 对比、采样器对比、prompt 模板对比甚至反推工程中的参数搜索实验。接下来值得深入的方向有三个。第一是 ComfyUI API 的更多底层用法比如如何获取图片 base64 数据而不是依赖保存节点这对远程调度更有用。第二是批量任务队列和并发控制比如同一时间只允许一个任务运行避免显存溢出。第三是风格评估把“看风格”从人工经验逐步变成可量化的指标。最后给一个小建议不要把风格测试的目标定成“找到一个最好的画师风格”而是“摸清这个 LoRA 库里每个风格擅长什么”。A 风格可能适合光影强烈的场景B 风格可能适合传统赛璐璐这些信息记录下来比你反复测试某个单一风格要值钱得多。建议收藏这篇文章下次整理模型库时直接按这个流程跑一遍批量测试。
返回列表