[论文阅读] FontRL Chinese Font Synthesis via Deep Reinforcement Learning

pre

title: FontRL: Chinese Font Synthesis via Deep Reinforcement Learning
accepted: AAAI 2021
paper: https://ojs.aaai.org/index.php/AAAI/article/view/16318
code: https://github.com/lsflyt-pku/FontRL

亮点: 深度强化学习、学习绘制skeleton再渲染glyph

针对问题

汉字合成结果结构不正确、轮廓模糊,或质量不高

核心思想

借助深度强化学习,学习绘制给定汉字的书写轨迹(skeleton?),然后将这个字的skeleton通过I2I模型转换为字形图片

相关研究

现存方法大致分为两组:处理字形图片跟处理序列数据

第一组将汉字看作图片,就是经典的提取风格、内容特征,再合成目标字形,大多直接使用CNN。作者认为它们忽略汉字的 high-level 信息,因此合成结果经常出现不正确的拓扑结构跟轮廓模糊

书写过程天然含有时间、位置信息,基于此,第二组方法将汉字看作点的序列,比如FontRNN(2019),它学习输入序列到目标序列的转换,可以有效地模拟人类的书写习惯。但该类方法无法合成高质量的字形轮廓。

Neural Style Transfer
pix2pix、CycleGAN那些,略

Chinese Font Generation
汉字字体生成从Rewrite讲到HCCG-CycleGAN(2017),说他们面临复杂结构汉字效果都不好,然后讲一些融入了汉字high-level先验知识到生成模型的方法。然后介绍SA-VAE(2017),用字形结构信息、偏旁部首?(radical)和index codes。还有SCFont(2019),使用分解的字符skeleton,并合成书写轨迹。FontRNN(2019)直接以目标字体风格合成书写轨迹,对弯曲的手写字很有效果。

注:skeleton即字的骨架,可看作粗细一致的线条组成的字,跟目标字笔画形状大小一样,但缺少粗细、笔锋、衬线等风格/装饰,需要渲染后才是最终生成的字。

Reinforcement Learning-based Generation
深度强化学习DRL能做很多事情,如下围棋、文本生成和机器人控制。这些任务的决策自然形成一个序列,而书写过程也是类似。
有些基于DRL的重画图片(repaint images),主要差别是不同action、reward和相应算法中drawing window的使用。PaintBot通过改变训练和测试集进行风格转换,但字形图片缺乏颜色和纹理信息,用它转换字体风格的结果并不好。还提到有个用DRL的机器人手臂可以画汉字笔画,但精度低,笔画轮廓模糊且只能写数据集里有的字。

方法(模型)流程

Overview

图1 模型概述

如图1所示,将汉字书写轨迹看作笔画skeleton的组合,由点的序列组成,但不像FontRNN那样直接生成书写轨迹的序列数据,流程如下所示

  1. 训练一个深度强化学习模型(搜索最优的RL-action)来获取 Thin-Plate Spline (TPS) 变换,可以将平均字体风格的参考笔画skeleton修改为所需风格的skeleton,可用于每个未知汉字的每个笔画
  2. 用CNN预测这些笔画的位置跟缩放信息(bounding box),再将其组装得到相应字符的skeleton
  3. 最终用I2I模型将合成的字符skeleton转换为字形图片

图2 FontRL架构。包含四个模块:MPNet, TPS变换模块, BBoxNet和Image Rendering Module(IRM)。有groundtruth的虚线部分仅出现于训练过程

更确切地说:

  1. 先用基于DRL的MPNet为每个笔画估计TPS变换的参数
  2. 由于TPS变换的锚点固定于给定的画布上,而笔画可以在画布的任意位置,为了更好修改笔画,在TPS变换前先将笔画标准化(normalize)
  3. 标准化后的笔画skeleton大小会改变,位于画布中间,不带位置跟长度信息
  4. 使用TPS插值函数修改平均笔画skeleton为目标的样子
  5. 接着用BBoxNet预测所有合成的笔画skeleton 的 bounding squares,通过给出中心和边长(这样将
  6. 将笔画skeleton组合成完整的字符skeleton
  7. 在IRM模块,直接用SCFont的skeleton-image转换模型(StyleNet)渲染相应字形图片
  8. 给定字形图片,其笔画skeleton抽取方式也跟SCFont一样

所以有一个输入平均字符skeleton图片(mean character skeleton image),这好像对同一个字是通用的、无关风格的、从environment采样而来,模型在它的基础上将其修改为目标字体风格的skeleton再渲染。

MPNett即actor,给TPS变换模块每个笔画在当前state下的action,然后TPS据其变换后得到的笔画stroke'与目标笔画计算reward反馈给MPNet,它就知道给的这个action合不合适。

另一方面变换出来的笔画stroke'进行标准化,然后画出来(图2的normalized output stroke skeleton image),跟平均字符skeleton图片输入BBoxNet,计算出这个笔画在目标字符中的位置跟大小,然后将其绘制出来。

最终所有笔画绘制好,连在一起就成了character skeleton image,送入IRM渲染为最终的character image。

(注)关于强化学习

https://www.cnblogs.com/Stareven233/p/16883875.html
奇怪的是官方代码中却好像没有实现critic,只有actor(那个MPNet)

Modification Parameter Estimating Network (MPNet)

即DDPG里的actor,负责选取action
笔画skeleton从参考风格到目标风格的转换可以描述为多个TPS插值函数,这些函数形式相同但参数不同
这些函数不可乱选(怕随机到不好的影响结果),也不能全部都用于训练(不可能找出所有插值函数)
这里的MPNet就用深度强化学习训练,为TPS变换提供所需的参数,以此解决缺乏合适训练数据的问题

本文的训练集仅有775个汉字,包含7004个笔画。在强化学习中,重复更新 memory bank,这扩展数据来得到更好的效果。

图3 用25个锚点控制笔画skeleton的大小和形状

Anchor 如果笔画skeleton关键点的坐标有相同的x或y值,笔画最小的bounding rectangle就会退化为线段。因此每个笔画计算最小bounding square。 进行TPS变换前,笔画会被标准化然后放入图3的蓝色方框区域,其边长为1,中心坐标(0, 0),锚点共25个,红、黄色分别控制笔画的整体缩放跟形状细节

Action action \(a_t\)是 25x2 的向量,被定义为每个锚点的偏移量。因为锚点相对位置得保持不变,因此限制向量取值范围[-0.49, 0.49]

State state由环境给定,定义如下

\[state = (s^{skel}; c^{skel}; stepnum; coord), \tag{1} \]

其中\(s^{skel}\)表示标准化的笔画skeleton图片(或许是图2的stroke skeleton image),\(c^{skel}\)表示参考字skeleton图片(图2的mean character skeleton image?),stepnum标准化到[0, 1],cord是一个坐标系,其中x, y取值[-0.5, 0.5]
所有图片都通过在128x128画布上绘制、连接笔画skeleton关键点得来。

这个stepnum难道表示用了 n-step TD方法?,进行了step步之后才更新,后面提到当step==1就退化为监督学习...
看代码每一步的state, action, reward那些都会被存入一个memory(本文提及的memory bank),大小为max_steps,之后再拿出来更新policy net。

Reward 每个action的reward定义为生成的skeleton跟目标skeleton之间点的平均距离。如图2紫色虚线,计算距离跟奖励前会将skeleton标准化。

\[r\left(s_{t},a_{t}\right)=d i s t\left(s_{t}^{s k e l}\right)-d i s t\left(T P S\left(s_{t}^{s k e l},a_{t}\right)\right), \tag{2} \]

\[d i s t\left(s_{t}^{s k e l}\right) = \left||s_{t}^{s k e l}-s_{g e t}^{s k e l}\right||_2, \tag{3} \]

作者尝试过结合值Q跟奖励R使用Q学习来更新policy net,但效果不好。本任务中Q无法准确估计,因此只通过奖励更新policy net

Policy net policy net(即MPNet),或称为actor,基于state决定一个action,然后根据收到的奖励更新policy。对于强化学习,policy net不需理解action的物理意义,仅需建立reward跟action的联系。本文使用Resnet18加上一个FC层作为policy net

Environment 如图2所示,环境首先发送state给policy net,然后基于action通过TPS变换修改笔画skeleton。之后计算reward,将其返回给policy net更新参数。此外环境提供目标groundtruth bounding box计算给MPNet的reward(原文确实是for MPNet,感觉应该是BBoxNet啊?),并且训练BBoxNet。
加入环境可以将MPNet从FontRL的其他模块中解耦出来,允许在不重新训练其他部分的情况下使用不同的变换模块。

TPS Transformation Module (TPSTM)

TPS定义如下:平滑地弯曲一块薄板,可视作二位平面,这样N个源点\(\mathbf{P}_{s} = (P_{s1}, P_{s2}, ..., P_{sN})^T\)就会偏移到相应目标点\(\mathbf{P}_{t} = (P_{t1}, P_{t2}, ..., P_{tN})^T\)。为了最小化弯折的能量,按如下计算插值函数:

\[\Phi_{x}(P s_{i})=c_{x}+A_{x}^{T}P s_{i}+W_{x}^{T}S(P s_{i}), \tag{4} \]

\[\Phi_{y}(P s_{i})=c_{y}+A_{y}^{T}P_{s_{i}}+W_{y}^{T}S(P s_{i}), \tag{5} \]

目标点\(P t_{i}\)的x, y坐标值由\(\Phi_{x}(P s_{i}),\; \Phi_{y}(P s_{i})\)决定,函数\(S(P s_{i})\)定义如下:

\[S(P s_{i})=(\sigma\,(P s_{i}-P s_{1}), ..., \sigma\,(P s_{i}-P s_{N}))^{T}, \\ \sigma(\Delta P s_{i j}) = ||\Delta P s_{i j}||_{2}^{2}\log||\Delta P s_{i j}||_{2}, \tag{6} \]

其中\(\Delta P s_{i j}=P s_{i}-P s_{j}\),同时:

\[\left[\begin{array}{l l}{{W_{x}}}&{{W_{y}}}\\ {{c_{x}}}&{{c_{y}}}\\ {{A_{x}}}&{{A_{y}}}\end{array}\right]={\Gamma}^{-1}\left[\begin{array}{l l}{{\bf P t_{x}}}&{{\bf P t_{y}}}\\ {{0}}&{{0}}\\ {{0}}&{{0}}\end{array}\right], \tag{7} \]

\[\Gamma=\left[\begin{array}{c c c c}{{\mathrm{S}}}&{{\mathrm{1}}}&{{{\mathrm{Ps}}_{x}}}&{{{\mathrm{Ps}}_{y}}}\\ {{\mathrm{1}}}&{{\mathrm{0}}}&{{0}}&{{0}}\\ {{\mathrm{Ps}_{x}^{T}}}&{{0}}&{{0}}&{{0}}\\ {{\mathrm{Ps}_{y}^{T}}}&{{0}}&{{0}}&{{0}}\end{array}\right], \tag{8} \]

\[\mathrm{S=}\left[\begin{array}{c c c}{{\sigma\left(\Delta P s_{11}\right)}}&{{\sigma\left(\Delta P s_{12}\right)}}&{{\cdot\cdot\cdot}}&{{\sigma\left(\Delta P s_{1N}\right)}}\\ {{\sigma\left(\Delta P s_{21}\right)}}&{{\sigma\left(\Delta P s_{22}\right)}}&{{\cdots}}&{{\sigma\left(\Delta P P s_{N2}\right)}}\\ {{\vdots}}&{{\vdots}}&{{\ddots}}&{{\vdots}}\\ {{\sigma\left(\Delta P s_{N1}\right)}}&{{\sigma\left(\Delta P s_{N1}\right)}}&{{\cdots}}&{{\sigma\left(\Delta P s_{NN}\right)}}\end{array}\right], \tag{9} \]

本文中,\(Ps\)是锚点,\(Pt\)可以由\(\mathbf{Pt} = a c t i o n+\mathbf{Ps}\)计算而来,通过求解公式7,可知TPS变换参数:\(C = [c_x, c_y]^T,\; W = [W_x, W_y]^, and\; A = [A_x, A_y]^T\)

这样源笔画skeleton的每个关键点\(Pks\)可以变换为目标笔画skeleton相应关键点\(Pkt\),看公式10:

\[P k t=\Phi(P k s)=C+A^{T}P k s+W^{T}S(P k s). \tag{10} \]

看着是十分复杂,特别是\(Ps,\; Pt,\; Pks,\; Pkt\)这些感觉不够清晰,猜测为通过固定的锚点Ps跟不知道什么的目标点Pt先照着公式7计算出TPS变换的三个参数C, W, A,然后再利用算出的参数使用TPS将源字形的关键点Pks变为目标字形关键点Pkt,以此达到将源字转换为目标字的目的。

Bounding Box Predicting Network (BBoxNet)

通过TPS修改笔画后,需将这些合成的笔画skeleton组装成一个完整的字符skeleton,BBoxNet就是用于预测每个笔画bounding square的中心和大小。

bounding box预测模块跟笔画修改模块互相独立,因此BBoxNet可以替换成任意的目标检测网络(所以《Instance Segmentation for Chinese Character Stroke Extraction, Datasets and Benchmarks》才能直接迁移过来?)

为了验证有效性,用一个简单网络(Resnet34带单一FC层)预测笔画中心和边长,小网络减少过拟合概率。如图2所示,BBoxNet输入是生成的笔画skeleton跟平均字体风格的参考字skeleton。用了不同颜色标记不同笔画,以便模型能学习到每个笔画的关系跟它在平均字符skeleton上相应的位置,提高预测精度。

Loss function 作者通过实验对比GIoU跟MAE损失在BBoxNet上的效果,二者相近,出于简单考虑,选择MAE Loss来减少计算复杂度。

实验

数据集和指标

直接用SCFont提出的数据集,包含所有6763个汉字的字形跟手动标注的笔画skeleton,以5种不同的字体风格为目标,以平均字体风格为参考(应该指的是用于转换的源字体)。为了跟SCFont公平比较,使用(Lian, Zhao, and Xiao 2016)提出的输入字符集训练,其包含775个汉字,能覆盖GB2312 character set中所有笔画跟组件。

细节

MPNet跟BBoxNet的输入图片分辨率都为128x128,笔画skeleton关键点坐标标准化到[-0.5, 0.5]的范围。直接用SCFont的StyleNet作为FontRL的图片渲染模块,超参数保持默认值,其输入图片分辨率为320x320。

MPNet学习率为0.0003,6000iteration后衰减到0.0001,BBoxNet学习率0.001,40epoch后衰减到0.0005,再经过100epoch衰减到0.0001。

实验结果

表1 FontRL跟其他模型的定量比较

图4 文本渲染结果的对比

图5 个方法合成的字符skeleton比较

表1计算合成字跟相应groundtruth的L1损失跟IoU值,FontRL优势明显。图4zi2zi丢失不少细节,FontSL引入很多汉字先验知识,内容准确度有保障,但视觉效果跟笔画细节无法令人满意。SCFont在大多数场合表现都不错,但目标风格跟参考的很不一样(图4(c),FZTLJW)就很糟糕。

图5这些模型都是先产生字符skeleton再渲染成字形图片,因此比较它们的书写轨迹,FontRL的更加平滑

Text Rendering

图6 FontRL合成的、用5种不同字体渲染的诗

如图6,左上角标红的是机器生成的字,其他是人类设计/书写的,作者用这个证明模型合成的图片跟输入样本风格一致。且不说模型生成结果跟输入像应当是基本要求,就这里对比的mean skeleton,不知道从哪里mean过来的,而且人类手动设计一个平均的skeleton??意义不明

User Study

图7 用户调查问卷的例子。左边品红色的是模型生成的

表2 用户调查结果

总之做了个用户调查,找一些人让他们区分机器生成的字跟groundtruth,表2是用户识别的精度,都接近50%说明难以分辨,模型很厉害。但实际上图7可以看出来这些字并非是一一对比,即同一个字模型生成的跟gt放一起让人去对比区分,像这种手写的风格本就多样,随便歪斜一下也不能说偏离风格,自己写同一个字都很不好保证一定一模一样,再说也不能排除挑选了简单的字体、最好的结果呈现出来。

Ablation Studies

图8 TPS跟仿射变换的对比

表9 BBoxNet的影响

表3 不同最大step数量下,FZJHSXJW字体生成的skeleton跟目标skeleton之间点的平均距离

TPS or Affine Transformation
图8展示了使用TPS跟仿射变换的对比,仿射变换伸展形变范围都比TPS小,以蓝色框出,同时复杂的skeleton修改无法用线性变换得到,红色框出。而且仿射变换的修改偶尔会导致字符无法辨认,如图8第三列第一行

Effect of BBoxNet
如图9,红色框标记使用与不使用BBoxNet时差别巨大的区域,咏乐汇有更好的笔画细节,同时BBoxNet模型小,计算高效。

Maximum Number of Steps
如表3所示,计算这些平均距离来证明FontRL里强化学习使用的有效性。当maxstep设置为1,里面的强化学习退化为有监督学习,随着maxstep增加,平均距离减少且收敛。对比结果,说明强化学习的使用提高了FontRL合成的笔画skeleton的质量。

Limitations

图10 FontRL的某些失败样例

对于草书手写体(cursive handwriting fonts)(看着也不够草啊?)的合成仍然有改进空间,字形结构太复杂时FontRL和处理不好连笔的牵丝连带(ligatures),如图10(a)(b)(c)。

在这,目标skeleton跟参考平均skeleton差别过大时也很难通过TPS实现所有变形图10(d)(e)

某些字符的笔画bounding box预测精度低,导致合成效果差,如图10(f)

总结

MPNet跟TPS变换模型用于实现笔画skeleton从参考风格到目标风格的映射。BBoxNet估计每个笔画的中心和大小,然后将合成的笔画装配为字符skeleton。最终用已有的模型将字符skeleton渲染为图片

比起其他方法,FontRL简单易训练,不需要在大规模数据上预训练。
跟其他基于RNN的方法比,FontRL按照参考风格修改字符skeleton而不是直接从头生成,确保平滑且书写自然的生成。

文章本身看起来比较吃力,主要是强化学习似乎默认读者熟悉,模型架构画得也挺乱,把握不住,比如Environment给的State没有明确标出。
模型本身idea感觉挺新奇的,结合少见的强化学习,实验结果乍一看不错,但作为21年的工作对比的模型都是17, 19的,感觉有点欺负人了。

启发

  1. 也加入深度强化学习(还得学一学强化学习,感觉有些难度
  2. DG-Font改成修改skeleton再用一个I2I模型渲染

待解明

  1. State中 stroke skeleton image 和 mean character skeleton image 是什么关系?
  2. Environment为何给MPNet提供目标 groundtruth bounding box 算reward?
  3. MPNet的输入好像只有源字体风格的信息,它是根据什么给出action让TPS能变换出目标skeleton的?总不能每种目标字体都重新训练吧
  4. state里面的stepnum是什么意思?maxstep是啥?取1怎么就退化成监督学习了?本文的强化学习跟有监督学习差别在哪
posted @ 2022-11-15 16:23  NoNoe  阅读(408)  评论(0编辑  收藏  举报