首页
/ FaceSwap scripts 包深度解析:faceswap.py 子命令分发与 extract/train/convert/gui 五大入口模块

FaceSwap scripts 包深度解析:faceswap.py 子命令分发与 extract/train/convert/gui 五大入口模块

2026-09-06 17:38:53作者:何将鹤

本文以 FaceSwap 的 Sphinx API 文档 docs/full/scripts.rst 为主体,系统讲解 scripts 包作为整个项目入口的架构设计:从 faceswap.py 如何注册 extract、train、convert、gui 四个子命令,到 scripts/extract.pyscripts/train.pyscripts/convert.pyscripts/fs_media.pyscripts/gui.py 五个模块各自的职责、关键类与底层依赖关系。读完本文,你将能够理解 FaceSwap 命令行与 GUI 两种使用方式如何共享同一套处理管线,并能在源码层面定位每个子命令的入口实现。

一、scripts 包:Faceswap 的统一入口

docs/full/scripts.rst 开篇给出了一句核心定位:

The Scripts Package is the entry point into Faceswap.(scripts 包是进入 Faceswap 的入口)

该文档通过五个 Sphinx automodapi 指令分别展开五个模块的 API 文档:

RST 指令 对应模块 职责
automodapi:: scripts.convert scripts/convert.py 换脸转换主流程(源画面 → 模型推理 → 后处理合成)
automodapi:: scripts.extract scripts/extract.py 从图片/视频中检测人脸并裁剪出训练样本
automodapi:: scripts.fs_media scripts/fs_media.py extract 与 convert 共享的媒体对象(Alignments)及统计输出
automodapi:: scripts.gui scripts/gui.py 可选的 tkinter 图形界面
automodapi:: scripts.train scripts/train.py 训练人脸交换模型的主流程

scripts 目录内除了上述五个文件外还有一个空的 scripts/__init__.py,用于将目录声明为 Python 包。

这里有一个值得注意的文档生成约定:五个模块文件末尾都写有

__all__ = get_module_objects(__name__)

(例如 scripts/gui.pyscripts/fs_media.py)。get_module_objects 来自 lib.utils,它扫描当前模块收集顶层定义写入 __all__。这样做的直接收益是:automodapi 指令配合 :include-all-objects: 选项即可自动把模块内所有公开类/函数纳入 API 文档,无需手工维护对象列表。这也是五个模块能被 docs/full/scripts.rst 一篇 RST 统一覆盖的原因。

二、总入口 faceswap.py:子命令注册与参数分发

虽然 scripts.rst 的主题是 scripts 包本身,但要理解这五个模块如何被调用,必须先看清根目录的 faceswap.py。它的 _main 函数(faceswap.py#L37-L57)完成了三件事:

  1. 生成配置文件:调用 generate_configs()(来自 lib.config)。首次运行任意子命令后,会在 config/ 目录下生成 extract.initrain.iniconvert.ini 等插件配置文件——这也是 USAGE.md 中“需要至少运行过一次 Extract 或 GUI 才能看到 ini 文件”这一说法的源码出处。
  2. 构建参数解析器:使用 cli_args.FullHelpArgumentParser() 创建支持完整帮助的解析器,然后通过 add_subparsers() 注册四个子命令,每个子命令绑定一组参数类和一个处理函数:
subparser = _PARSER.add_subparsers()
ExtractArgs(subparser, "extract", _("Extract the faces from pictures or a video"))
TrainArgs(subparser, "train", _("Train a model for the two faces A and B"))
ConvertArgs(subparser, "convert", _("Convert source pictures or video to a new one with the face swapped"))
cli_args.GuiArgs(subparser, "gui", _("Launch the Faceswap Graphical User Interface"))
_PARSER.set_defaults(func=_bad_args)
arguments = _PARSER.parse_args()
arguments.func(arguments)

注意 _PARSER.set_defaults(func=_bad_args):当用户没有提供有效子命令时,会打印帮助并退出(_bad_args 定义于 faceswap.py#L30-L34)。解析完成后,arguments.func(arguments) 这一行把参数命名空间交给各子命令对应的处理函数,最终分别实例化 scripts 包中对应的 Extract()Train()Convert()Gui() 类并执行——这正是“scripts 包是入口”这句话的完整链路。

  1. 环境与国际化准备:入口处还通过 System().validate_python() 校验 Python 版本,并使用 gettext 加载 locales/ 下的翻译(对 Windows 平台通过 ctypes 修补 LANG 环境变量,见 faceswap.py#L8-L12)。

对应的四个用户侧命令(摘自 USAGE.md):

python faceswap.py extract -i ~/faceswap/src/trump -o ~/faceswap/faces/trump
python faceswap.py train -A ~/faceswap/faces/trump -B ~/faceswap/faces/cage -m ~/faceswap/trump_cage_model/
python faceswap.py convert -i ~/faceswap/src/trump/ -o ~/faceswap/converted/ -m ~/faceswap/trump_cage_model/
python faceswap.py gui

每个子命令都支持 -h 查看完整参数,例如 python faceswap.py extract -h

三、scripts.extract:人脸检测与训练样本生成

scripts/extract.py 是“从原始素材中提取可用训练样本”的模块。从源码头部导入即可看清它的能力边界与依赖:

from lib.align.aligned_utils import (batch_adjust_matrices, batch_align, batch_resize,
                                     batch_transform, get_adjusted_center, get_sub_crop_size)
from lib.align.constants import EXTRACT_RATIOS, LandmarkType, MEAN_FACE
from lib.infer import Detect, Align, Identity, Mask, File, Profiler
from lib.infer.identity import FilterLoader
from .fs_media import Alignments, finalize

几个关键信息:

  • 检测与对齐插件体系from lib.infer import Detect, Align, Identity, Mask, File, Profiler 表明 extract 阶段的检测器(Detect)、对齐器(Align)、身份过滤(Identity)、分割(Mask)、文件导入(File)与性能剖析(Profiler)均以插件形式注入。其中 File 插件允许直接复用已有的 alignments JSON 文件,而不是重新检测——这与 scripts/fs_media.pyplugin_is_file 参数的作用相呼应。
  • 批处理管线:模块内定义了 BatchInfo 数据类,持有当前批次的 loader(图片加载器)与 alignments(对齐数据),说明 extract 是按批(batch)驱动的检测→对齐→裁剪→保存流程,配合 lib.multithreading.FSThread 实现多线程处理。
  • 几何工具batch_alignbatch_resizeget_sub_crop_size 等批量几何变换函数,对应 USAGE.md 中“识别人脸关键点、把图像裁剪到一致尺寸并保存到输出目录”的描述。

典型用法(来自 USAGE.md):

# 从图片文件夹提取
python faceswap.py extract -i ~/faceswap/src/trump -o ~/faceswap/faces/trump
# 从视频文件提取
python faceswap.py extract -i ~/faceswap/src/trump.mp4 -o ~/faceswap/faces/trump

输出为裁剪好的人脸图片,同时在输入目录生成 alignments.json(faceswap 内部格式为 alignments.fsa),记录每张脸的位置、关键点等信息,供后续 train/convert 阶段使用。官方文档给出的建议是:每个主体收集约 500–5000 张高质量、角度/表情/光照多样的样本,且不要从视频中抽取每一帧(相邻帧高度相似)。插件的细粒度配置项保存在 config/extract.ini(首次运行后生成)。

四、scripts.train:模型训练主循环

scripts/train.py 定义了 Train 类,其 docstring 明确职责:“训练一个模型,使源人脸集合(A)与目标人脸集合(B)之间可以互换”。核心实现要点:

  • 训练器与预览:模块从 lib.training 导入 TrainerPreviewPreviewBufferTriggerType,并引用 plugins.train.trainer.baseTrainConfig。也就是说 train 脚本本身是编排层:真正的前向/反向计算发生在插件体系(模型、增强、损失等由 config/train.ini 选择与配置)中。
  • 最低图片数校验:源码中存在类方法 _validate_image_counts,校验每侧文件夹至少有 24 张图片——注释说明这不足以训练出成功模型,但足以让流程不报错地生成预览,属于“快速试跑”兜底。
  • GUI 联动触发器__init__ 中会创建 lib/gui/.cache 下的 .preview_mask_toggle.preview_trigger 文件路径,用于 GUI 侧点击按钮后触发“切换 mask / 刷新预览”等事件,体现 CLI 与 GUI 共享同一处理类的架构。
  • 优雅停止:模块导入 lib.keypress.KBHit,对应 USAGE.md 说明的“在预览窗口或控制台按 Enter 即可停止训练,模型会保存后退出”;训练模型约每 100 次迭代自动保存一次,loss 下降时还会备份(.bk 扩展名),可随时中断并从同一目录恢复训练。

标准命令:

python faceswap.py train -A ~/faceswap/faces/trump -B ~/faceswap/faces/cage -m ~/faceswap/trump_cage_model/
# 加 -p 开启实时预览窗口
python faceswap.py train -A ... -B ... -m ... -p

完整参数列表通过 python faceswap.py train -h 查看;若使用 mask 或 Warp to Landmarks 等功能,需要为每个人脸集合传入对应的 alignments 文件。

五、scripts.convert:推理与后处理管线

scripts/convert.py 是“把训练好的模型应用到源画面”的模块,头部 docstring 即声明其为 convert 流程的主入口。源码结构上有两个值得注意的设计:

  1. ConvertItem 数据类——描述一帧画面在整个转换管线中流转时携带的状态:
@dataclass
class ConvertItem:
    """A single frame with associated objects passing through the convert process."""
    inbound: FrameFaces
    feed_faces: list[AlignedFace] = field(default_factory=list)
    reference_faces: list[AlignedFace] = field(default_factory=list)
    swapped_faces: np.ndarray = field(default_factory=lambda: np.array([]))

inbound 是从磁盘加载的帧及其 DetectedFace 列表;feed_faces/reference_faces 是送入模型 predict 的输入脸与参考脸;swapped_faces 是模型输出的换脸结果。这个数据类清晰地勾勒出“检测 → 对齐 → 推理 → 后处理”的逐帧流水线。

  1. Convert 类与 ConverterConvert 的 docstring 说明其“负责把源帧的人脸替换为训练模型的输出,并调用一系列用户选定的后处理插件,这些插件由 lib.convert.Converter 执行”。后处理插件(如肤色匹配、边缘融合等)由 plugins/plugin_loader.PluginLoaderconfig/convert.ini 的配置动态加载。

convert 的前置条件是:源视频/图片目录必须已有 alignments 文件(即先用 extract 对源素材跑一遍检测,并建议清理误检与对齐失败的条目),否则 convert 无从知道脸在哪里。标准命令:

python faceswap.py convert -i ~/faceswap/src/trump/ -o ~/frameswap/converted/ -m ~/faceswap/trump_cage_model/

与 extract 一样支持图片目录与视频两种输入,python faceswap.py convert -h 可查看完整参数。

六、scripts.fs_media:extract 与 convert 共享的媒体层

scripts/fs_media.py 的模块 docstring 说明它“持有 Faceswap 两个主要媒体对象(Images 与 Alignments)的类,并提供 convert/extract 的可选前后处理函数”。该文件体量不大但逻辑关键,包含两部分:

1. finalize() 汇总输出scripts/fs_media.py#L25-L43):extract 与 convert 结束后统一打印统计——

Images found:        <处理的图片/帧数>
Faces detected:      <检测到的人脸数>

并当有单帧检测到多张脸时提示“Double check your results.”(请仔细核对结果)。

2. Alignmentsscripts/fs_media.py#L46-L237):继承自 lib.align.Alignments,核心作用是根据命令行参数定制 alignments 文件的加载与保存行为。其构造参数本身就是一个很好的“行为开关”说明书:

参数 含义
location alignments 文件完整路径;None 时从源文件位置推导
source_location 源媒体路径(图片文件夹或视频文件)
is_extract 调用方是否为 extract 流程
skip_existing_frames / skip_existing_faces extract 时“跳过已有帧 / 跳过已有脸”两个开关
plugin_is_file 检测/对齐是否选择了 File 插件(即从 JSON 导入)
save_alignments 流程结束时是否保存 alignments
input_is_video 输入是否为视频

命名推导逻辑在 _set_folder_filenamescripts/fs_media.py#L102-L162)中:

  • 未显式指定 location 且输入是视频:alignments 文件与视频同目录,命名为 <视频名>_alignments
  • 输入是图片文件夹:文件直接叫 alignments,存放在图片文件夹内;
  • 指定了 .json 后缀但检测/对齐插件并非 File 插件时,直接报错退出(“Json files are only valid with 'File' detect/align plugins”);
  • 使用 File 插件但找不到对应文件时,同样报错退出并提示检查路径。

JSON 导入逻辑在 _import_from_jsonscripts/fs_media.py#L206-L237):当外部 JSON 中某张脸缺少 detected(检测框)字段时,会断言其 landmarks_2d 恰好为 4 个 ROI 关键点,并把检测框直接设为该 ROI 的外接矩形——这对应“仅使用 4 点 ROI 关键点的外部标注”这一使用场景;导入过程中会把每张脸重建为 FileAlignments 对象并写回 AlignmentsEntry。此外,_load 的重写处理了“跳过已有帧/脸”的断点续跑语义,以及在 JSON 导入与已有 .fsa 文件共存时自动备份原文件的保护逻辑(self.backup())。

七、scripts.gui:tkinter 图形界面

scripts/gui.py 实现可选 GUI,仅两个类:

  • FaceswapGui(tk.Tk)scripts/gui.py#L17-L183):主窗口。构造时依次完成:加载 .ini 配置(cfg.load_config)→ 初始化全局常量与字体 → 设置 1200×640 窗口几何 → 清空预览缓存 → 注册 WM_DELETE_WINDOW 关闭钩子 → 构建界面。build_gui 方法(scripts/gui.py#L65-L88)按“TaskBar(任务栏)+ CommandNotebook(命令选项卡,即 extract/train/convert 的选项面板)+ DisplayNotebook(预览显示区)+ ConsoleOut(控制台输出)”四大组件搭建布局,全部组件来自 lib.guiTaskBarCliOptionsCommandNotebookConsoleOutDisplayNotebookProcessWrapperStatusBar 等)。
    • 配置变更重绘rebuild 方法在配置变化时保存 LastSession 会话状态、销毁并重建所有子组件,再恢复会话状态;
    • 安全关闭close_app 会在有任务运行时弹出确认框,确认后通过 wrapper.task.terminate() 终止后台进程,再保存最后会话并退出。
  • Guiscripts/gui.py#L186-L194):供 faceswap.py gui 子命令调用的薄封装,__init__ 创建 FaceswapGuiprocess() 进入 mainloop()

GUI 的价值在于把 CLI 的全部参数以可视化选项面板形式呈现(悬停可见帮助文字),并额外提供预览刷新、mask 切换等交互能力——这也解释了 train 模块中 .preview_trigger 等触发器文件为何存在。启动方式:

python faceswap.py gui

八、scripts 包的统一编码约定

对比五个模块,可以归纳出 scripts 包的一贯风格,这对阅读与扩展代码很有帮助:

  1. 懒类型导入if T.TYPE_CHECKING: 块内导入 argparse.NamespaceModelBase 等仅用于类型注解的类,运行时零开销;
  2. 调试日志规范:每个模块定义 logger = logging.getLogger(__name__),类初始化用 lib.logger.parse_class_init(locals()) 一行记录全部构造参数;
  3. 废弃参数兼容:extract/train/convert 均在构造时调用 handle_deprecated_cli_opts(arguments)(来自 lib.utils)迁移旧版命令行参数;
  4. 自包含原则:各 docstring 均声明“self contained and should not be referenced by any other scripts”(自包含、不应被其他脚本引用),模块间唯一的横向依赖是 scripts/fs_media.py 被 extract/convert 复用;
  5. __all__ 自动生成get_module_objects(__name__) 统一收尾,支撑 Sphinx 自动文档化。

九、小结:入口、模块与命令的对应关系

子命令 入口类 源码文件 共享/支撑组件
extract Extract scripts/extract.py lib.infer 插件、scripts/fs_media.py
train Train scripts/train.py lib.training.Trainer、预览触发器
convert Convert scripts/convert.py lib.convert.Converter 后处理链
gui Gui / FaceswapGui scripts/gui.py lib.gui 组件族、lib.utils

docs/full/scripts.rst 的五个 automodapi 指令正是围绕这张分工表展开:scripts 包是 Faceswap 的唯一入口层,faceswap.py 负责参数分发,五个模块分别承接提取、训练、转换、界面四大功能,而 fs_media 作为横切的媒体层保证 alignments 数据的加载、导入与保存行为在 extract 与 convert 之间保持一致。理解了这一分层,再配合 USAGE.md 中的标准工作流(extract → train → convert),即可在源码与命令行两个层面完整把握 FaceSwap 的运行机制。

登录后查看全文
热门项目推荐
相关项目推荐