限时优惠上线特惠 · 一次买断仅 $9(原价 $19),全档位同步折扣截止 2026-06-30 · 剩 28

从 zi2zi 到扩散模型:手写汉字生成这几年都发生了什么

2026/05/29

我自学了 zi2zi,然后是 deepvecfont,再然后是一整摞需要先读完四篇 AAAI 论文才看得懂的扩散模型。

这句话不是凡尔赛。做 MoFont 之前,我天真地以为「手写汉字变字体」是个已经被论文解决了的问题——毕竟 GitHub 上一搜一大把,demo 图都漂亮得不得了。等我真的把这几年的论文按时间线读完,才发现:漂亮的 demo 图和一个你能装进电脑、打字打得出 6500 个字的 .otf 文件,中间隔着一条没人愿意讲的长尾。

这篇就当是一份导览。我按我读论文的顺序,讲讲汉字字体生成这几年到底发生了什么,以及为什么每一代方法都「差一口气」。

zi2zi 时代:把字当成图,做风格迁移

最早让我入门的,是田渊栋(网名 kaonashi-tyc)2017 年的 zi2zi。它的思路特别朴素,朴素到我第一次读懂的时候有点感动:把字体生成当成「图到图」的翻译问题。

它直接站在 pix2pix(Isola 等人那篇著名的「用条件对抗网络做图到图翻译」)的肩膀上。pix2pix 能把线稿翻译成照片、把卫星图翻译成地图;zi2zi 就把它改造成「把宋体的『字』翻译成你手写体的『字』」。再加上一个类别嵌入(category embedding),让一个模型同时学会很多种字体的风格,而不是一种字体训一个模型。

这个范式在当时是真的惊艳。给它几百个字的成对样本,它能脑补出剩下几千个字的大致样子。

但它会在哪里崩?复杂字。 因为它本质上是在像素平面上「画」字,笔画一多、结构一密(比如「囊」「鬻」「龘」这种),它就开始糊——笔画粘连、断笔、墨团。说白了,GAN 不理解「这是一横、那是一捺」,它只理解「这块区域应该是黑的」。一旦字的结构超出它的把握,它就用一团灰色蒙混过关。后来社区里像 DG-Font / CF-Font(CVPR 2023,做内容与风格解耦的少样本生成)这类工作,很大程度上就是在跟「复杂字崩坏」和「样本太少」这两件事死磕。

顺便说一句,田渊栋本人这几年也没闲着,他后来又做了 zi2zi-JiT,直接换成了像素空间的扩散 Transformer——这也算是从 GAN 到扩散这条主线的一个缩影了。

deepvecfont:别画像素了,直接吐矢量

我读 zi2zi 读到一半就卡在一个问题上:字体文件里存的根本不是图片,是矢量轮廓——一堆贝塞尔曲线的控制点。你 GAN 画出一张再清晰的位图,想变成能缩放、能渲染的字体,还得再描一遍边(矢量化),这一步又会引入新的失真。

所以当我读到 DeepVecFont(Wang & Lian,SIGGRAPH Asia 2021)的时候,有种「对啊就该这么干」的感觉。它的核心叫双模态学习(dual-modality learning):同时利用字的「图像」和「矢量序列」两种表示来学。图像那一路负责把握整体形状,矢量那一路负责生成真正能用的轮廓曲线,两边互相校准。输出的不是一张图,而是一组贝塞尔曲线——这才是字体真正需要的东西。

但 v1 有个老实人都承认的毛病:它处理长序列的能力有限,生成复杂轮廓时容易抖、容易留下毛刺,还很依赖一个「图像引导的轮廓后处理」来擦屁股。于是两年后有了 DeepVecFont-v2(CVPR 2023),把 RNN 换成 Transformer,又设计了一套松弛表示和自我精修模块,专门治「长而复杂的轮廓」的抖动和伪影。

矢量路线我个人是很欣赏的,它在拉丁字母、相对简单的字形上效果很漂亮。但放到几千个汉字、每个字几十上百个控制点的规模上,序列长度爆炸,稳定性依然是个硬骨头。它解决了「输出该是矢量」这个对的方向,却没能轻松扩到中文的体量。

扩散模型:复杂结构和少样本上的一次跃迁

然后就到了让我读得最痛苦、收获也最大的扩散模型阶段。

代表作是 FontDiffuser(AAAI 2024)。它把字体生成建模成「加噪—去噪」的过程:从一团噪声里,在内容和风格的引导下,一步步「显影」出目标字。它有两个我觉得特别聪明的设计:一个多尺度内容聚合模块,专门在不同尺度上保住复杂字的笔画细节(就是为了治 zi2zi 那个「复杂字糊成一团」的老毛病);还有一个风格对比模块,把风格从图像里干净地拆出来。

效果上,扩散模型确实在两件事上比 GAN 强:复杂结构少样本/一样本。给它一个字的参考风格,它就能把没见过的字也写成那个风格,而且复杂字不容易崩。读到这里我一度以为「这下问题真解决了」。

但它也有自己的天花板:长尾生僻字。 训练集里见得多的常用字,它写得有模有样;一旦碰到那些笔画刁钻、出现频率极低的字,它依然会编——编出一个看着像那么回事、但偏旁部首站错位置的「鬼画符」。模型对没怎么见过的东西,本质上是在合理地猜,而生僻字恰恰是「合理地猜」最容易翻车的地方。

我的大实话:没有一篇论文能直接给你一个能用的字体

读完这一摞论文,我最大的体会反而很扫兴:这些方法,没有任何一个单独拿出来,能 ship 一个真正可用的 OTF。

论文的终点通常是「在测试集上生成的字,图像质量/风格相似度指标超过了上一篇」。但一个真正能用的字体,要求的是另一回事:

  • 6500 个常用字一个都不能少,缺一个,用户打字就打出一个豆腐块(口口口);
  • 每个字的轮廓得是干净闭合的矢量,不能有自交、不能有碎点,否则 FontForge 编译不过、渲染发虚;
  • 字宽、基线、侧边距得对齐,不然排出来一行字高低错落像喝醉了;
  • 那些模型「合理地猜」也猜不对的生僻字,得有兜底——要么用结构拼合,要么干脆退回参考字形,绝不能让它瞎编。

这「最后一公里」全是脏活累活:FontForge 的脚本工程、轮廓清理、字形度量对齐、还有专门伺候长尾生僻字的一套兜底逻辑。论文不写这些,因为这些不发论文。但用户能不能真的把字体装进电脑、能不能打出每一个字,全靠这一公里。

这也是 MoFont 真正在做的事。模型那一层我站在这些论文的肩膀上,但产品那一层我把绝大部分精力花在了「最后一公里」:你写 30–50 个字,我帮你补齐 6500 个常用字,跑大约 3–4 小时,产出能直接安装的 .otf + .ttf。生僻字有兜底,轮廓过 FontForge 清洗,度量对齐过。买断,不订阅——因为字体是你的手迹,不该按月租给你自己。

论文教会我的,是这条路怎么走;但能不能走到用户手里,得自己把那一公里铺完。

—— 砚秋

顾砚秋

顾砚秋