几个match

MixMatch

转载:https://zhuanlan.zhihu.com/p/66281890

人类的学习方法是半监督学习,他们能从大量的未标记数据和极少量的标记数据学习,迅速理解这个世界。半监督学习最近有没有什么大的突破呢?这篇博客介绍了 DeepMind 的 MixMatch 【2】方法,此方法仅用少量的标记数据,就使半监督学习的预测精度逼近监督学习。深度学习领域的未来可能因此而刷新。

以前的半监督学习方案,一直以来表现其实都很差。你可能会想到 BERT 和 GPT,这两个超强的自然语言预训练模型。但这两个模型的微调只能算迁移学习,而非半监督学习。因为它们最开始训练的时候,使用了监督学习方法。比如通过语言模型,输入前言,预测后语;输入语境,完形填空;输入前言和后语,预测是否前言不搭后语。这几种方法,很难称作无监督学习。

下面这几种大家很容易想到的半监督学习方法,效果都不是很好。比如使用主成分分析PCA,提取数据中方差最大的特征,再在少量标记数据上,做监督学习;又比如使用自编码机 AutoEncoder,以重建输入图像的方式,获得数据潜在表示,对小数据监督学习;再比如使用生成对抗网络 GAN,以生成以假乱真图像的方式,获得数据潜在表示,对小数据做监督学习。半监督训练很久的精度,还比不上直接在小数据上做监督学习的精度!大家的猜测是,这些非监督方法学到的特征可能并不是分类器真正需要的特征。

什么才是半监督学习的正确打开方式呢?近期的一些半监督学习方法,通过在损失函数中添加与未标记数据相关的项,来鼓励模型举一反三,增加对陌生数据的泛化能力。

第一种方案是自洽正则化(Consistency Regularization)【3,4】。以前遇到标记数据太少,监督学习泛化能力差的时候,人们一般进行训练数据增广,比如对图像做随机平移,缩放,旋转,扭曲,剪切,改变亮度,饱和度,加噪声等。数据增广能产生无数的修改过的新图像,扩大训练数据集。自洽正则化的思路是,对未标记数据进行数据增广,产生的新数据输入分类器,预测结果应保持自洽。即同一个数据增广产生的样本,模型预测结果应保持一致。此规则被加入到损失函数中,有如下形式,

[公式]

其中 x 是未标记数据,Augment(x) 表示对x做随机增广产生的新数据, [公式] 是模型参数,y 是模型预测结果。注意数据增广是随机操作,两个 Augment(x) 的输出不同。这个 L2 损失项,约束机器学习模型,对同一个图像做增广得到的所有新图像,作出自洽的预测。

MixMatch 集成了自洽正则化。数据增广使用了对图像的随机左右翻转和剪切(Crop)。

第二种方案称作 最小化熵(Entropy Minimization)【5】。许多半监督学习方法都基于一个共识,即分类器的分类边界不应该穿过边际分布的高密度区域。具体做法就是强迫分类器对未标记数据作出低熵预测。实现方法是在损失函数中简单的增加一项,最小化 [公式] 对应的熵。

MixMatch 使用 “sharpening” 函数,最小化未标记数据的熵。这一部分后面会介绍。

第三种方案称作传统正则化(Traditional Regularization)。为了让模型泛化能力更好,一般的做法对模型参数做 L2 正则化,SGD下L2正则化等价于Weight Decay。MixMaxtch 使用了 Adam 优化器,而之前有篇文章发现 Adam 和 L2 正则化同时使用会有问题,因此 MixMatch 从谏如流使用了单独的Weight decay。

最近发明的一种数据增广方法叫 Mixup 【6】,从训练数据中任意抽样两个样本,构造混合样本和混合标签,作为新的增广数据,

[公式]

其中 [公式] 是一个 0 到 1 之间的正数,代表两个样本的混合比例。MixMatch 将 Mixup 同时用在了标记数据和未标记数据中。

MixMatch 方案

MixMatch 偷学各派武功,取三家之长,补三家之短,最终成为天下第一高手 – 最强半监督学习模型。这种 MixMatch 方法在小数据上做半监督学习的精度,远超其他同类模型。比如,在 CIFAR-10 数据集上,只用250个标签,他们就将误差减小了4倍(从38%降到11%)。在STL-10数据集上,将误差降低了两倍。 方法示意图如下,

imgMixMatch 实现方法:对无标签数据,做数据增广,得到 K 个新的数据。因为数据增广引入噪声,将这 K 个新的数据,输入到同一个分类器,得到不同的预测分类概率。MinMax 利用算法(Sharpen),使多个概率分布的平均(Average)方差更小,预测结果更加自洽,系统熵更小。

注:Google原文并未比较 MixMatch 和使用生成对抗网络GAN做半监督学习时的表现孰好孰坏。但从搜索到的资料来看,2016年 OpenAI 的 Improved GAN 【8】,使用4000张CIFAR10的标记数据,做半监督学习得到测试误差18.6。2017年,GAN做半监督学习的测试误差,在4000张CIFAR10标记数据上,将测试误差降低到14.41 【10】。2018年,GAN + 流形正则化,得到测试误差14.45。目前并没有看到来自GAN的更好结果。对比 MixMatch 使用 250 张标记图片,就可以将测试误差降低到 11.08,使用4000张标记图片,可以将测试误差降低到 6.24,应该算是大幅度超越使用GAN做半监督学习的效果。

具体步骤:

  1. 使用 MixMatch 算法,对一个 Batch 的标记数据 [公式] 和一个 Batch 的未标记数据 [公式] 做数据增广,分别得到一个 Batch 的增广数据 [公式] 和 K 个Batch的 [公式]

[公式]

其中 T, K, [公式] 是超参数,后面会介绍。MixMatch 数据增广算法如下,

imgMixMatch 算法。

算法描述:for 循环对一个Batch的标记图片和未标记图片做数据增广。对标记图片,只做一次增广,标签不变,记为 [公式] 。对未标记数据,做 K 次随机增广(文章中超参数K=2),输入分类器,得到平均分类概率,应用温度Sharpen 算法(T 是温度参数,此算法后面介绍),得到未标记数据的“猜测”标签 [公式] 。此时增广后的标记数据 [公式] 有一个Batch,增广后的未标记数据 [公式] 有 K 个Batch。将 [公式][公式] 混合在一起,随机重排得到数据集 [公式] 。最终 MixMatch 增广算法输出的,是将 [公式][公式] 做了MixUp() 的一个 Batch 的标记数据 [公式] ,以及 [公式][公式] 做了MixUp() 的 K 个Batch 的无标记增广数据 [公式]

\2. 对增广后的标记数据 [公式] ,和无标记增广数据 [公式] 分别计算损失项,

[公式]

其中 [公式] 等于 Batch Size, [公式]等于 K 倍 Batch Size,L 是分类类别个数, [公式] 是简单的 Cross Entropy 函数, [公式] 是增广的标记数据输入和标签, [公式] 是增广的未标记数据输入以及猜测的标签。

对未标记数据损失 [公式] 使用 L2 Loss 而不是像 [公式] 一样使用 Cross Entropy Loss 的原因文章中没有提到。但在引用的NVIDIA文章【3】第三页提供了一个解释。即 L2 Loss 比 Cross Entropy Loss 更加严格。原因是 Cross Entropy 计算是需要先使用 Softmax 函数,将Dense Layer输出的类分数 [公式] 转化为类概率,

[公式]

而 softmax 函数对于常数叠加不敏感,即如果将最后一个 Dense Layer 的所有输出类分数 [公式] 同时添加一个常数 c, 则类概率不发生改变,Cross Entropy Loss 不发生改变。

[公式]

因此,如果对未标记数据使用 Cross Entropy Loss, 由同一张图片增广得到的两张新图片,最后一个Dense Layer的输出被允许相差一个常数。使用 L2 Loss, 约束更加严格。

\3. 最终的整体损失函数是两者的加权,

[公式]

其中 [公式] 是非监督学习损失函数的加权因子,这个超参数的数值可调,文章使用 [公式]

在上面的步骤描述中,还有另外两个超参数,温度 T 和 [公式] 。T 被用在 Sharpening 过程中, [公式] 是 Mixup 的超参数。下面分别解释这两个超参数的来历。

不是说未标记数据没标签吗?我们可以用分类器“猜测”一些标签。算法描述中的这一步,就是分类器对 K 次增广的无标签数据分类结果做平均,猜测的“伪”标签。对应示意图中 Average 分布。但这个平均预测分布比较平坦,就像在猫狗二分类中,分类器说,这张图片中 50% 几率是猫,50%几率是狗一样,对各类别分类概率预测比较平均。

[公式]

MixMatch 使用了 Sharpen,来使得“伪”标签熵更低,即猫狗分类中,要么百分之九十多是猫,要么百分之九十多是狗。做法也是前人发明的,

[公式]

其中, [公式] 是类别概率,在 MixMatch 中对应 [公式] 。T 是温度参数,可以调节分类熵。调节 T 趋于0, [公式] 趋近于 One-Hot 分布,即对某一类别输出概率 1,其他所有类别输出概率0,此时分类熵最低。注: [公式] , 可以计算得到,在二分类中,两个类的输出概率是One-Hot时 [公式] 的熵远小于输出概率比较平均 [公式] 的熵。在 MixMatch 中,降低温度T,可以鼓励模型作出低熵预测。

最后一个尚未解释的超参数 [公式] 被用在 Mixup 数据增广中。与之前的 Mixup 方法不同,MixMatch方法将标记数据与未标记数据做了混合,进行 Mixup。对应算法描述中的混合与随机重排。

MixMatch 修改了 Mixup 算法。对于两个样本以及他们的标签 [公式][公式], 混合后的样本为,

[公式]

其中,权重因子 [公式] 使用超参数 [公式] 通过 Beta 函数抽样得到,

[公式]

文章使用超参数 [公式] , 如果将此 Beta 分布画图表示,则如下图所示,

img权重因子的分布。根据此 Beta(0.75, 0.75) 分布抽样,大部分数值落在接近 0 或 1 的区域。

原始的 Mixup 算法中,第一步不变,第二步 [公式] 。MixMatch 做了极小的修改,使用 [公式] 。如上图所示,根据 [公式] 抽样得到的 [公式] 数值大部分落在 0 或 1 附近, [公式] 函数则使得 [公式] 数值接近 1 。这样的好处是在 Mixup 标记数据 [公式] 与混合数据 [公式]时,增加 [公式]的权重;在 Mixup 未标记数据 [公式][公式]时,增加 [公式]的权重。分别对应于算法描述中的[公式][公式]

细节:损失函数中使用了对未标记数据猜测的标签 [公式] , 此标签依赖于模型参数 [公式] 。遵循标准处理方案,不将 [公式][公式] 的梯度做向后误差传递。

半监督学习 MixMatch 训练结果

img在 CIFAR-10 数据集上,使用全部五万个数据做监督学习,最低误差能降到百分之4.13。使用 MixMatch,250 个数据就能将误差降到百分之11,4000 个数据就能将误差降到百分之 6.24。结果惊艳。

更直观的效果对比

imgMixMatch 算法测试误差用黑色星号表示,监督学习算法用虚线表示。观察最底下,误差最小的两条线,可看到 MixMatch 测试误差直逼监督学习算法!

解剖各部分贡献 (Ablation Test )

img可以看到对结果贡献最大的是对未标记数据的 MixUp,Average 以及 Sharpen。

结论:

半监督学习是深度学习里面最可能接近人类智能的方法。这个方向的进展,这篇文章的突破,都是领域的极大进展。

ReMixMatch

转载:https://www.zhihu.com/search?type=content&q=ReMixMatch

ICLR2020的工作,主要就是针对MixMatch的改进,之前写过MixMatch,所以这个并不详细介绍,就简单记录下。因为整篇论文也并没有很仔细看,主要就关注了下改进点和伪代码,会用即可,还是很不错的方法

首先直接上伪代码

img

其实大部分和MixMatch差不多,主要注意一下伪代码中第7行,本文提出了一个distribution alignment

说一下作者思路(可能有的地方理解并不准确,因此可以参考原文观看)

distribution alignment 想要让无标签数据的prediction分布和有标签的相匹配。首先作者认为SSL任务就是通过无标签数据的加入来改善模型的performance,而一个直观的思路就是想办法让模型针对无标签数据的预测 [公式] 和输入 [公式] 之间的互信息最大。

[公式]

这个推导很简单,详情可以见原论文的附录。

来看最后推导的等式,首先可以注意到第二项,就是所有SSL工作都致力于的东西,即迫使模型的预测分布更sharp一点。而第一项则是说明,希望纵观整个数据 [公式] ,模型预测到每个类别的频率都应该相等,即模型应该保持“公平”

对于推导得到的这两个优化目标基本可以理解,可以概括为:模型无偏 + 模型预测分布趋向于一个确切的类别(预测效果好)

作者认为对于第一项来说,其鼓励模型预测所有类别的频率相同,但对于本身每个类别概率就不是均匀分布的数据(即类别不均衡)来说,这样的优化目标就不太符合实际了,即我的理解为,由于本身数据中不同数据的样本数量就不一样,因此一个好的模型不可能把所有数据预测完后得到的结果是每个类别包含的数目相同(这样不符合实际label啊,肯定精度不高)。因此作者换了一个方式把这个“公平”的思想融合到了ReMixMatch方法中,即为distribution alignment

而对于第二项来说,其思想本身就存在于很多SSL方法中,包括MixMatch,即对应MixMatch中的 sharpen 操作,因此不需要再考虑这个优化目标了

distribution alignment的图示如下

img

参考图示简单叙述一下过程:训练过程中,时刻维护一个动态的模型在无标签数据集上的prediction [公式] (实际操作中为 last 128 batches 模型在无标签数据上预测的平均值),则给定一个无标签样本 [公式] ,其模型的prediction为 [公式] ,则我们将 [公式][公式] 相乘[公式] 通过有标签数据的标签进行统计各个类别的频率),然后再重新归一化成一个预测分布 [公式] ,其中, [公式] ,则得到的 [公式] 作为该无标签样本 [公式] 的预测值,之后与MixMatch一样进行 sharpen 等后续操作。

FixMatch

转载:https://zhuanlan.zhihu.com/p/340474319

算法、算力、数据是深度学习的三架马车。深度学习是数据驱动式方法,目前的从业基本者都有一个共识就是:数据是非常重要的且不可或缺的。在实际环境中对数据标注又是一个耗时和昂贵的过程。但是受束于资源的限制,可能你有很多的图片,但是只有一部分可以进行人工标注。例如工业频繁更换型号的场景,花费更多时间标注意味着上线运行时间的delay,会严重影响效率和产能。在这样的情况下,如何利用大量未标注的图像以及部分已标注的图像来提高模型的性能呢?答案是semi-supervised半监督学习。半监督学习(SSL)这个领域近年来得到飞速的发展,方法也有很多,但很多都是使用较为复杂的方法,标注降低了,但是训练复杂度等其他方面的代价上来了。本文提出FixMatch,是一种对现有SSL方法进行显著简化的算法。FixMatch使用模型的预测生成伪标签进行无标签数据的训练。

  • 本文贡献:利用一致性正则化( Consistency regularization)和伪标签(pseudo-labeling)技术进行无监督训练。SOTA 精度,其中CIFAR-10有250个标注,准确率为94.93%。甚至仅使用10张带有标注的图在CIFAR-10上达到78%精度。
  • 论文标题:FixMatch: Simplifying Semi-Supervised Learning with Consistency and Confidence
  • 论文地址https://arxiv.org/abs/2001.07685
  • 官方代码https://github.com/google-research/fixmatch

核心思想

img

如上图所示,训练过程包括两个部分,有监督训练和无监督训练。有label的数据,执行有监督训练,和普通分类任务训练没有区别。没有label的数据,经过首先经过弱增强获取伪标签。然后利用该伪标签去监督强增强的输出值,只有大于一定阈值条件才执行伪标签的生成。无监督的训练过程包含两种思想在里面,即一致性正则化和伪标签训练。

一致性正则化是当前半监督SOTA工作中一个重要的组件,其建立在一个基本假设:相同图片经过不同扰动(增强)经过网络会输出相同预测结果,因此对这二者进行loss计算便可以对网络进行监督训练,又被称为自监督训练。loss计算如下:

img

伪标签是利用模型本身为未标记数据获取人工标签的思想。通常是使用“hard”标签,也就是argmax获取的onehot标签,仅保留最大类概率超过阈值的标签。计算loss的时如下:

img

其中 [公式] , [公式] 为阈值。我们假设argmax一个概率分布产生一个有效的onehot概率分布。

这种机制为什么work?无监督训练过程实际上是一个孪生网络,可以提取到图片的有用特征。弱增强不至于图像失真,再加上输出伪标签阈值的设置,极大程度上降低了引入错误标签噪声的可能性。而仅仅使用弱增强可能会导致训练过拟合,无法提取到本质的特征,所以使用强增强。强增强带来图片的严重失真,但是依然是保留足够可以辨认类别的特征。有监督和无监督混合训练,逐步提高模型的表达能力。

算法流程图

img

  1. 输入的数据包括两个部分,有标注的数据和没有标注的数据,另外需要设定置信度阈值、采样比例、loss权重等超参。
  2. 对有标注的部分执行有监督训练,使用传统的CE loss。
  3. 遍历无标注的数据,利用弱增强获取伪标签。
  4. 对无标注的数据,利用获取的伪标签进行训练,同样利用CE loss。
  5. 根据一定的loss权重融合二者的loss。

loss计算

loss包括两部分,标注有监督分类任务loss和无监督为标签训练loss分别如下。其中 [公式] 表示弱增强,一般为flip、平移; [公式] 表示强增强,一般为色彩变换、对比度增强、旋转等,下面会细说。

img img

数据增强

上文提到了该方法应用到了两种数据增强,分别是weak Augmentation和strong Augmentation。weak Augmentation为标准的flip-and-shift增强策略,50%的概率进行flip和12.5%的概率进行shift,包括水平和竖直方向。对于strong Augmentation,论文主要应用RandAugment和CTAugment两种策略,都是为提高模型表现而提出的增强策略。首先进行严重失真的增强,然后再应用CutOut增强。增强函数来自PIL库。以前的SSL使用的是AutoAugment,这个工具训练了一个强化学习算法来寻找最佳准确率的增强方法。本文FixMatch使用了AutoAugment的两个变体之一,采用的是随机采样策略,减少网络对增强之间耦合程度的依赖。对于RandAugment:

  • 收集有一个包含数十种增强的列表,以及一系列增强幅度大小。
  • 从这个列表里随机选出N个增强,例如N为2。
  • 然后选择一个随机的幅度M,例如50%之类的。
  • 将所选的增强应用于图像,每种增强都有50%的可能性被应用。

img

上表为RandAugment涉及到的所有的增强和参数区间。对于CTAugment同理,主要有Autocontrast 、Brightness、Color、Contrast、Cutout、Equalize、Invert、Identity、Posterize、Rescale、Rotate、Sharpness、Shear_x、Shear_y、Smooth、Solarize、Translate_x、Translate_y,不再叙述。

实验效果

作者分别在CIFAR和SVHM等数据集上进行了训练测试,模型表现超过之前的网络。具体如下:

img

对于极端缺少标注的场景,仅仅使用每个类别1张共10张标注的图片就可以达到78%的最大accuracy,当然这种做法和挑选的样本质量有关,作者也做了相关实验论证。不过也证明本文的方法的确work。

img

另外,作者做了很多实验消融实验,包括一些训练超参调节的,不再叙述,有兴趣的可以阅读原文。

结语

本文介绍了一篇半监督领域经典论文,其做法简单有效,使用图像增强技术进行伪标签学习和一致性正则化训练,在CIFAR等多个数据集上仅仅利用少量的标注图片就可以达到一个不错的效果,这对于获取标注困难的场景非常有意义。例如在工业应用领域,可能会有海量数据,但是现实限制可能无法都进行人工标注,因此可以尝试利用半监督训练的方法,非常值得借鉴。

CoMatch

转载:https://zhuanlan.zhihu.com/p/400995369

Motivation

作者认为现有方法都存在几个limitations:1. 基于伪标签的模型(self-training,pseudo-label)十分依赖分类精度,因此如果模型学习过程中产生了一些bias,则这个bias会一直累积而不是被修正 2. self-supervised使用的对比学习方法所优化的方向并不完全于下游任务的优化方向一致,即对比学习通常关注的是实例级别,下游任务不一定是这个 3. 基于图的模型(graph-based)在大型数据集(如:ImageNet)上表现并不好

img

如上图所示,a,b分别表示基于伪标签(只考虑分类)和自监督的模型(只考虑embedding)训练逻辑,而(c)则是本文模型 CoMatch,其同时考虑了cls head 的分类概率和 projection head 的embedding,并将其用到co-training中,更具体的来说:对比学习的embedding对分类概率施加平滑约束使其生成更好的伪标签,而伪标签反过来被当作 target 训练cls head(CE loss)和 projection head(graph-based contrastive loss)

简单来说,半监督模型大体分为两种思想,一个是pseudo-based模型,一个是contrastive-loss-based模型,最近graph-based思想也比较火,但仍待开发。本模型就是直接将现有思想都结合到一起使其之间相互制约和促进,最后实验效果还不错

img

给定一个 batch [公式] 的有标签数据 [公式] (其中 [公式] 为 one-hot 编码)和无标签数据 [公式] (无标签数据个数是有标签数据的 [公式] 倍),模型主要构造包括:encoder [公式] ,cls head [公式] ,projection head [公式]

首先计算 Memory-smoothed pseudo-label,其主要是为了refine伪标签,减少模型可能存在的bias。我们首先要得到[公式][公式] 中样本的类别概率 [公式] :对于 [公式] 中数据其类别概率为给定的label [公式] ,对于 [公式] 中数据其类别概率定义为网络对其弱增强的预测 [公式] ,之后作者对 [公式] 中数据的 [公式] 进行distribution alignment 操作 [公式] 。除此之外,对于每个 [公式][公式] 中的样本通过 [公式][公式] 可以得到其弱增强的 embedding [公式] ,则根据 [公式][公式] 构建一个大小为 [公式] 的 memory bank [公式] ,其更新规则为 FIFO

此时对于一个当前 batch 中的无标签数据 [公式] 何其对应的 [公式] ,作者定义其伪标签 [公式] 为下式的最优结果

[公式]

其中第一项为迫使 [公式] 与 memory bank 中与其相邻样本的类别概率尽可能相似,其中 [公式] 为相似度度量。第二项为保证 [公式] 尽可能与网络预测的结果相似。

则对 [公式] 求导并令其为0,可得到最优解 [公式]

之后我们利用 [公式] 构建 pseudo-label graph,并用其促进 embedding 的训练。首先给定 batch 的无标签样本伪标签 [公式] ,按照如下方式构建大小为 [公式] 的graph,其中 [公式] 为超参数

[公式]

作者又构建了embedding graph:对于每个 [公式] ,计算其两个强增强的embedding,即 [公式] ,则按照如下方式构建大小为 [公式] 的graph

[公式]

最后我们将上述得到的两个graph进行行归一化 [公式] ,然后最小化二者的CE

[公式]

损失函数方面作者构建三个 loss 同时优化 [公式]

  • 针对有标签数据集上的 supervised classification loss [公式] 。该 loss 很简单就是在有标签数据集上算 CE loss

[公式]

  • 针对无标签数据集的 unsupervised classification loss [公式] ,该 loss 计算伪标签 [公式] 和模型对强增强的预测之间的 CE loss(只计算伪标签最大类别的概率大于 [公式] 的 loss,个人认为这样主要能够防止最开始模型随机初始化时乱给标签带来的无效训练)

[公式]

  • 针对两个图的对比学习损失 [公式] (该部分 loss 文章前面已经提及,不再叙述)

对于强增强作者的实现如下

img

CoMatch 算法迭代一次(计算一个batch)的伪代码如下

img

针对 large dataset 的 CoMatch

作者认为如果想要构建一个比较好的pseudo-label graph,一个batch中的每个类别样本必须要足够多(如果同类别样本不多图肯定是稀疏的,大多数边都是0,就没什么意义),这一点对于类别少的小数据集很容易实现,但对于类别很多的大型数据集来说一个batch中的数据很可能每个类别的样本很少,而扩大batch会极大的消耗内存,因此对于大型数据集来说,作者类似MoCo等工作的处理方法,构建 EMA 模型 [公式] ,该模型采用 momentum 更新,同时构建大小为 [公式] 的 momentum queue ,其存储经过强增强的无标签数据的 embedding 和对应的伪标签 [公式] 。相应的pseudo-label graph [公式] 修改为计算一个 batch 的无标签数据与 [公式] 之间的graph,即大小为 [公式] ,类似的 embedding graph [公式] 也修改为计算一个 batch 的无标签数据与 [公式] 之间的graph,即大小为 [公式]

除此之外,对于 memory-smoothed pseudo-labeling 的计算,我们也修改为将弱增强数据输给 EMA model 而不是原 model。通过 CoMatch 构造 [公式][公式] 的图示如下

img

最后给一个结果大致表示一下效果吧(提升还是可以的)

img