资讯动态

AI模型鲁棒性测试实战:从对抗攻击原理到评估流程设计

发布时间:2026/10/19 2:32:26 来源:尧图企业网站定制
AI应用架构师的核心工作往往不是把模型精度从99%提到99.1%而是守住那1%甚至0.1%的极端输入。今天聊一个落地时绕不开、但很多团队真到上线才想起来的问题——模型评估中的鲁棒性测试具体点说就是当输入被人为恶意构造时你的AI应用还能不能给出正确结果。这类输入在行业里有个统一称呼adversarial attacks中文常译作对抗性攻击或对抗样本攻击。这个概念直白解释是这样的模型的训练和常规评估都在正常数据分布下进行模型已经默认了输入符合某些统计规律。但现实世界中总有人会故意打破这些规律比如在图像上叠加一层肉眼几乎看不出区别的噪点就让分类器把熊猫识别成长臂猿在语音里加入微小的背景声就让语音助手把打开风扇识别成关闭空调。这种精心构造的输入扰动导致模型输出错误的现象就是鲁棒性缺失的表现。你会很快意识到这跟传统评估指标准确率、召回率、F1完全是两个维度的事情——后者衡量模型在干净数据上有多准前者衡量模型在脏数据上有多稳。这篇文章我想从一个AI应用架构师——也就是负责把模型真正部署到产品里、对线上效果负责的人——的角度把鲁棒性测试这一环拆开聊透。包括为什么常规评估手段测不出鲁棒性问题对抗攻击的几类主流做法和它们背后的核心逻辑作为架构师应该怎么设计一套可落地的鲁棒性测试流程以及踩过坑之后哪些防线值得投入哪些是纯浪费。适合做模型评估、算法平台、AI应用安全的朋友参考也适合那些刚把模型接到业务里、被线上诡异case搞得焦头烂额的同行。1. 为什么你的准确率是99%上线后却总被奇葩输入打穿先讲一个我接手过的模拟项目X。某图像识别Demo用于电商平台的商品自动分类团队给我展示的离线测试报告非常漂亮Top-1准确率99.2%在10万张标注图片上的混淆矩阵几乎完美。但这个模型上线不到一周就出现了大量匪夷所思的误分类case。印象最深的例子是一张用户上传的、带着厚厚水印的商品图被识别成了完全不相干的类目。第二例是商品图上叠加了促销角标、价格划线、夸张边框之后模型的置信度直接从0.97掉到0.41最终输出错误分类。第三例是一张经过简单旋转裁剪压缩的图片模型给出了和原图完全不同的判断。当时团队的直觉反应是数据不够全得再收集一批带水印的图片训练。但我把这三类图片拿去跑了一轮特征归因分析发现它们有一个共同特点在模型决策最依赖的像素区域上确实存在与原始训练分布显著偏离的模式。换句话说这些输入不是脏是被有意无意地加上了定向扰动——有的扰动是人肉眼能识别的水印有的扰动细微到连人都感知不到但模型都会因此改变判断。这类现象用一句话概括高准确率只能说明模型在训练分布覆盖的区域内表现好不能说明它在分布外或恶意构造的输入上仍然可靠。常规评估里测试集和训练集来自同一个分布所以测出来的准确率天然虚高。真正上线后用户不会按照你的分布来恶意攻击者更不会。这里要澄清一个关键误区很多人把鲁棒性和安全性混为一谈。鲁棒性关注的是模型对输入扰动的承受能力属于模型质量属性安全性则涉及攻击者利用鲁棒性缺陷达到特定恶意目的属于系统对抗属性。两者密切相关但不是一回事。作为架构师你在设计测试体系时首先要心里有数这一轮鲁棒性测试是为了发现模型在哪些扰动下会失效而不是直接去做完整的安全攻防对抗。跑偏的话工作量和复杂度会成倍增加但产出的结论反而不聚焦。还有一点必须提到对抗样本存在迁移性。在一个模型上构造成功的对抗样本往往也能让另一个结构不同、训练数据不同的模型犯错。这意味着什么问题呢就算你的模型训练时完全没接触过对抗样本攻击者完全可以在本地拿一个开源模型比如某公开的预训练权重生成对抗样本然后直接拿到你的线上模型上来试——因为在很多任务上对抗扰动有一定的模型无关性。这个特性让鲁棒性问题从理论风险直接变成了工程现实也决定了你没法靠保密来防攻击只能在模型本身下功夫。2. 对抗攻击的底牌扰动是方向问题而不是幅度问题想设计鲁棒性测试先得理解攻击者是怎么让模型翻车的。别看对抗攻击的论文一大摞方法名也是一个比一个唬人但它们几乎共享同一个数学框架——在原始输入上加一个人不易察觉或可察觉但可接受的扰动让模型输出的预测结果改变。核心可用一个带约束的优化问题来表达$$\max_{\delta} \mathcal{L}(f(x\delta), y_{true}) \quad \text{s.t.} \quad |\delta|_p \le \epsilon$$意思是在扰动向量δ的某种范数通常是L2或L∞不超过阈值ε的前提下最大化模型对xδ的预测与真实标签之间的损失。目标很明确——找出能让模型最难受的那个微小改动。为什么深度神经网络那么容易中招我的理解是神经网络学到的是高维空间里的复杂决策边界它对输入的梯度方向往往非常陡峭。沿着梯度方向走一小步损失函数就会剧烈变化而这一小步在人眼看来可能只是每个像素的RGB值增减了1到2个灰度级完全不可感知。换句话说模型对输入空间的平滑性假设是错的它在输入空间中存在大量盲区——这些区域离真实样本很近却位于决策边界的错误一侧。基于这个框架对抗攻击分成了两个流派就像两个风格完全不同的黑客。白盒攻击相当于攻击者已经拿到了模型的结构和参数或足够精确的代理模型。代表性方法像FGSM快速梯度符号法原理非常粗暴但有效——算出损失对输入的梯度然后让所有像素沿着梯度符号方向统一扰动εL∞约束下一步就构造出对抗样本。后续的PGD投影梯度下降是FGSM的迭代加强版走一步看一步每次走完后把扰动投影回ε球内多走几步找到让模型出错概率更高的点。黑盒攻击现实里更常见。攻击者不知道模型参数只能像用户一样向模型发起查询比如上传图片拿到输出结果或者完全盲打连查询都受限。最经典的做法是利用迁移性——在本地训练一个替代模型对它生成对抗样本再把这些样本扔向目标模型。还有一种基于查询的攻击通过观察目标模型对不同输入的输出变化逐步估算梯度方向也能构造出有效的对抗样本。这类攻击不需要模型细节但要牺牲一些效率和隐秘性。这两种攻击对应到你的测试设计复杂度差别很大。白盒攻击适合在模型开发阶段做内部评估效率高、覆盖面广黑盒攻击适合在系统联调阶段模拟真实攻击者更接近实战但成本高。说到底选择哪种取决于你想回答什么问题是我的模型理论上有多脆弱还是我的线上服务实际有多难被打穿。还需要考虑任务的差异性。图像分类任务里扰动通常是一个全图或局部的像素矩阵文本任务里扰动可以是替换同义词、插入无关字符、调整语序——这些都是为了让输入在语义上几乎不变但模型的输出改变语音任务里可以是加入了难以察觉的背景噪声或者微调了音频波形。现在大模型时代还有一类针对指令级输入的对抗攻击——通过在提示词里注入精心构造的文本让模型输出违背预期的内容。这部分处在鲁棒性和安全性尤其是AI内容安全的交界地带也更复杂。我们这里先把讨论范围收窄到模型评估中最经典的输入扰动弹型对抗攻击也就是攻击者以原始样本为基础叠加微小扰动目标是让模型分类/识别错误。这个框架足够你撑起一套基础鲁棒性测试体系了。3. 构建鲁棒性测试流程从拍脑袋选几个噪声到系统化评估说完了攻击原理就得聊聊测试设计。很多团队不是不做鲁棒性测试而是做得太随意——往测试集里统一加5%的高斯噪声跑一遍测试集看准确率掉了几个点然后写进报告里本模型具备一定鲁棒性。这其实是典型的自欺欺人因为高斯噪声和对抗攻击构造的有向扰动根本不是一码事。随机噪声是无方向性的统计上平均掉的影响可以互相抵消对抗扰动是有方向性的专门盯住模型的弱点打。评估模型抗随机噪声和评估模型抗对抗攻击之间的相关性非常弱。3.1 明确测试目标你要测的是最坏情况还是平均情况第一步建议先把鲁棒性测试的目标写清楚。这一步看起来像废话实际是后面所有工作的分水岭。如果你的目标是场景鲁棒性——比如自动驾驶系统在雨天、雾天、夜间这类自然扰动下的表现——那么你用的评估方法应该是构造仿真工具生成不同程度、不同种类的自然条件扰动然后看模型在大量随机扰动下的平均表现。这属于分布转移的范畴对抗样本测试在这个层面不是主角。如果你的目标是对抗鲁棒性——比如一个内容审核系统要抵挡恶意用户构造的、试图绕过检测的输入——那么你就要用对抗攻击方法来测试最坏情况针对性地寻找能让模型失效的极小扰动。评估指标也应相应调整核心看的是攻击成功率或鲁棒性下界而不是平均准确率。这两种目标下设计的测试流程完全不同混在一起做最后得到的结论八成是四不像。以AI应用架构师的职责来说你多数时候关心的是后者——因为自然扰动可以在数据采集中逐步解决但对对抗扰动的抵御能力设计错了上线即事故。3.2 搭一套最小可行的鲁棒性测试工具链明确了目标之后工具链的搭建就有方向了。我建议从以下三个层级逐步搭建不要一上来就追求论文级别的攻防工具那对工程团队是负担不是助力。第一层是自建轻量攻击器。写一套统一调用的对抗攻击函数库先实现FGSM和PGD这两个白盒基线——它们代码逻辑清晰、计算效率高既能生成对抗样本用于测试又能作为理解攻击原理的教学工具。在实现FGSM时有个工程细节需要注意梯度是相对于输入图片张量计算的不是相对于权重梯度好多人第一次写会搞混。第二步在PGD的实现中要处理投影步骤——比如L∞约束下对扰动做clip、L2约束下对扰动做归一化缩放。一笔带过一个实用代码片段这是在PyTorch环境下对单张图片进行FGSM攻击的核心逻辑import torch def fgsm_attack(image, epsilon, data_grad, true_label, model): # 计算损失对输入图片的梯度方向 loss torch.nn.functional.cross_entropy(model(image), true_label) model.zero_grad() loss.backward() # 符号梯度保留方向统一扰动步长 sign_data_grad data_grad.sign() # 原始输入 定向扰动L∞约束 perturbed_image image epsilon * sign_data_grad # 裁剪到合法像素范围 perturbed_image torch.clamp(perturbed_image, 0, 1) return perturbed_image需要注意的是真实工程里你不会逐张图单独调用这个函数而是应该批量构造并缓存成数据集文件避免每次测试都重复攻击计算特别是大模型场景下反复前向反向的成本不低。还有一个细节FGSM属于单步攻击扰动幅度ε设得太小会被模型扛住设得太大又失真严重通常需要跑一组ε扫描比如0.01到0.1之间取5-10个档位才能画出模型的鲁棒性曲线。第二层是引入成熟鲁棒性测试库。Google的CleverHans、IBM的Adversarial Robustness ToolboxART、以及Foolbox这类开源库都能直接调用。它们封装了大量攻击算法有些做到了十几二十种包括白盒和黑盒并且提供了统一的评测接口。我实际推荐先把Foolbox或ART跑通因为它们对新框架的支持比较及时。但这里也要提醒一句不要试图一开始就全部接入选3-4种具有代表性的攻击方法比如FGSM、PGD、DeepFool、CW attack再加上一种黑盒替代模型攻击就足够了。做鲁棒性测试的目的是评估和定位问题不是集邮。第三层是建立基准数据集。这个很容易被忽略。你不能指望拿一份业务评测集来跑对抗攻击就行因为攻击构造出来的样本和原始样本差别极小如果评测集本身规模不够大比如只有几千张攻击成功率的统计置信区间会很宽结论基本没有说服力。建议抽出专门的鲁棒性评测集——规模不低于5000张、覆盖各主要类别、包含一定比例的硬样本模型在干净数据上预测正确但置信度较低的样本。硬样本的价值在于它们通常离决策边界近更容易被扰动打翻是评估模型鲁棒性的高灵敏度探针。3.3 定清楚评估指标别只用攻击成功率跑完攻击之后拿什么指标衡量业界最常见的是攻击成功率Attack Success RateASR即对抗样本中导致模型预测改变的比例。这个指标直观但它有一个盲区它只看变没变不关心变到哪去了。举个例子二分类场景里攻击让正样本变成负样本和让正样本变成低置信度的正样本置信度从0.99降到0.6但标签没变ASR衡量的是前者后者对系统稳定性也有影响但不体现在ASR里。更严重的情况是攻击导致模型从正确类别跳到完全无关类别还是跳到语义相近类别这两者的业务危害差别巨大——商品分错到相近品类可能只是推荐不准分错到违禁品类直接触发安全问题。所以我建议至少搭配三个维度来看一个是ASR攻击前后预测标签变化的比例一个是平均置信度下降所有干净样本经过攻击后置信度的平均跌幅还有一个是在受限类别集下的攻防效果即攻击后预测是否落入预设的高危错误类别。这第三个维度往往最能帮业务方做风险分级——不是所有攻击成功都需要同等应对先处理危害大的。还有一个所有架构师都需要关注的指标鲁棒性-准确性权衡robustness-accuracy trade-off。做鲁棒性提升时你会发现一个魔咒防御策略增强了模型对干净输入的准确率往往也会下降。这个矛盾在图像模型上非常普遍业界主流解释是模型的泛化能力和鲁棒性要求本质上是在争夺模型容量与特征空间平滑度。因此在鲁棒性测试报告里我强烈建议同时汇报干净数据准确率和对抗攻击后的准确率/ASR让决策者直观看到这个权衡。4. 实测一轮完整的抗攻击评估操作步骤与关键决策点理论讲完了下面用一次实际执行的测试过程来串一遍这样你可以直接照抄流程。当时接手的是一个基于某大型预训练视觉模型微调的商品分类器任务是把商品图片分到50个叶子类目。团队已经部署了在线服务模型每张图返回Top-5类目及置信度。我们决定做一轮对抗鲁棒性摸底看看最坏情况下系统会不会被轻易打穿。4.1 从基础评测集开始先知道干净数据的底数这一步看起来多余实际上非常重要。我们在干净的评测集上先跑了一遍模型记录每张图的预测标签和置信度作为基线。同时筛出了三类样本预测正确的、预测错误的、预测正确但置信度低于0.6的。前两类用来做攻击样本池第三类单独标记后续攻击时要额外关注。基线数据让我吃了一惊那些预测正确但置信度低的样本大量集中在商品外观高度相似、背景复杂、商标区域遮挡严重的图片上。这类样本天然是鲁棒性的薄弱环节——如果攻击者只针对这些样本做定向攻击攻击成本极低而成功率极高。4.2 用小步长白盒攻击做快速筛查我们先用FGSM做快速筛查扰动幅度ε从0.01跑到0.1每隔0.01做一次全量测试。之所以先用FGSM而不是直接上PGD原因很简单FGSM单步攻击计算量小一轮筛查跑下来很快能快速估计模型对扰动的敏感区间。如果模型在ε0.02就开始出现明显的ASR上升说明它的决策边界可能很靠近训练样本后续需要重点防护如果ε到0.08才有明显效果模型鲁棒性底子就相对厚实。实测结果ε0.03时整体ASR大概是4%ε0.05时跳到11%ε0.08时到了22%。增长的斜率呈加速状态说明模型在轻微扰动下的失效模式是逐渐放大的并不是一个明确的阈值效应。这个信息本身就有价值——上线前你可以根据这条曲线设定业务侧的安全阈值如果业务能接受的最大错误率是5%那模型能承受的对抗扰动幅度大约就在ε0.03左右攻击者要构造这样的扰动成本不算高因此需要增加额外的输入校验或防御机制。4.3 PGD迭代攻击暴露真实痛点FGSM快速筛查后我们在ε0.05的档位上又跑了PGD迭代攻击迭代次数设20步长0.01随机初始化起点。为什么要这一步因为FGSM是单步攻击容易陷入局部最优PGD在约束球内多次迭代、随机重启能逼近给定扰动幅度下的最强攻击效果。如果说FGSM是抽查PGD就是体检。结果很有意思PGD攻击下的ASR比FGSM高了整整一倍多达到26%。更值得关注的是有一部分被PGD打翻的样本FGSM完全攻击不动——模型的决策边界在这部分区域沿单方向看是平滑的但沿某个特定迭代路径看存在尖锐的脆弱点。这种局部平滑但全局脆弱的特性也说明单靠一种攻击方法做评估会产生明显误判。我们做了一轮错误模式统计按攻击后落到哪个类目做分组。数据显示很多被攻击成功的样本最终落入了与真实类目视觉特征高度相近的相邻类目。真正属于完全乱飞的比例反而低。这个发现改变了我们的防护优先级——首要目标不是杜绝一切攻击成功而是减少攻击带来的危害性分类跳变。4.4 黑盒模拟模拟真实攻击者的做法在线服务场景里攻击者拿不到模型参数真正现实的攻击路径是黑盒替代模型攻击或基于查询的攻击。我们单独选了2000张样本用一个公开的开源预训练模型做替代模型对它生成对抗样本再把这些样本打到线上模型上做测试。想验证的就是对抗样本迁移性在商品分类场景下是否真的存在。结果是替代模型生成的对抗样本打到目标模型上的ASR能达到15%上下明显高于随机噪声的对照随机噪声同样幅度下ASR不到2%。迁移性的确存在攻击者完全不需要知道你的模型结构就能造成显著危害。这个结果也支撑了之前的一个判断——鲁棒性问题不可能通过隐藏模型细节来规避。顺带说一个操作上的大坑黑盒攻击测试的时候一定不要让替代模型和防御方的数据分布差距过大。你拿ImageNet预训练模型当替代模型去攻击在业务私有数据上微调过的分类器迁移成功率有时会失真。比较靠谱的做法是用你自己业务数据的同类公开模型或之前版本的模型当替代模型尽可能模拟攻击者用相似的代理模型发起攻击的现实场景。4.5 把评测结果转成可执行的安全等级我习惯把鲁棒性测试结果分成四个安全等级这样业务方和技术团队沟通成本低。R0级模型几乎无防御任何已知攻击都能轻易打穿R1级能抵抗部分已知攻击但大扰动或迭代攻击仍能显著破坏R2级在合理扰动范围如ε≤0.05内ASR可控在10%以下且危害性跳变少R3级基本免疫常见攻击高危害跳变极少。我们当时的结果在R1到R2之间——有一些基础的承压能力但面对迭代攻击明显不足。这个分级不是拍脑袋定的而是每一个等级都要对应具体的测试场景和目标。这样往上游汇报时你可以直接说当前模型达到R1级需要在输入嗅探、对抗训练方面投入X人日才能到R2。有了成本和时间维度决策才可执行。5. 评估之后增强鲁棒性的四类方案以及各自的实际代价做鲁棒性测试的最高价值不是出具一份模型很脆弱的报告而是给出修复路径。根据踩坑经验我愿意把常见方案分成四类讲清楚它们适合什么场景、代价有多高。5.1 对抗训练效果最扎实但成本也最高对抗训练的思路是把对抗样本纳入训练集让模型在训练阶段就见过被攻击的样本从而学到更强的鲁棒特征。具体操作不复杂在每个训练批次里先用当前模型对一部分训练样本做PGD攻击生成对抗样本然后把对抗样本和干净样本混在一起喂给模型学习。问题在于训练成本。PGD攻击的每次迭代都需要完整的前向反向训练轮数直接翻好几倍。当时我们试点时把训练的每一步都叠加PGD-10攻击训练时间从原来的两天涨到五天。而且对抗训练之后干净数据的准确率会下降——我们在实验里掉了接近1.5个百分点。这个trade-off能不能接受完全看业务目标如果模型面对的攻击风险是常态化的那这1.5个点值得如果只是理论威胁性价比就很差。另外一个容易被忽略的点对抗训练会引入梯度掩盖现象。有时候模型看起来鲁棒性提升了不是因为真的学到了更强的决策边界而是因为它的梯度变得非常小导致基于梯度的攻击计算找不到有效方向。这种情况下你用白盒攻击测试会显示很安全但用黑盒迁移攻击一打照样穿。检测这个现象有个小技巧对比PGD攻击和迁移攻击的ASR如果差异特别大就要警惕有没有梯度掩盖——真实鲁棒性应以迁移攻击或更强攻击如CW的表现为准。5.2 输入预处理防御投入小但只能挡业余攻击这类方案包括输入去噪、平滑化、随机化、JPEG压缩、随机裁剪缩放等。原理是试图在输入到达模型前先把精心构造的微小扰动破坏掉。实际效果区分明显轻度的随机化预处理比如随机缩放随机填充能有效降低部分黑盒攻击的迁移成功率因为替代模型生成扰动时假设了一个固定的输入变换你随机化之后这个对齐就被打乱了。但面对白盒攻击效果很弱——攻击者完全可以把预处理函数纳入梯度计算再次构造出能穿透的对抗样本。本质上预处理防御解决的是攻击者的信息不完整的问题一旦信息补全防御就会被绕过。架构师视角的建议是输入预处理可以作为第一道廉价防线但不要指望它承担核心防御责任。它的价值在于提升攻击者的成本而不是让攻击者失效。5.3 输入检测与离群点过滤适合在线服务场景与其让模型接纳对抗样本不如在入口处就把可疑输入拦下来。这个思路落地形式是训练一个样本检测器这个二分类模型专门区分干净样本和对抗样本或者基于输入在特征空间的距离做异常检测。我们实验中的效果是把对抗样本的检测率和误报率调到了一个可用区间——对白盒PGD攻击的检测率能有80%以上但误报率偏高误伤了不少正常的带水印、带滤镜用户图片。误报代价很实际真实用户的图片被多次拒绝或降级处理体验投诉立刻上升。而且攻击者有充分的适应性一旦知道你有检测器可以在攻击时加入一个欺骗检测器的优化目标绕过也只是时间问题。所以对这种方案我的态度是可以补充不能依赖。它的最佳位置是作为联合防线的一环而不是唯一防线。5.4 模型结构层面的改进平滑化与随机化推理近年来还有一类方法强调从模型结构上提升平滑性比如用平滑分类器Smoothed Classifier 随机扰动推理对输出做确定性保证。这种做法在面对L2范数约束的攻击时能给出数学上的鲁棒性下界等于把凭经验防御变成有保证防御。这个方法在图像分类任务上有很好的理论支撑但工程代价也不低。最典型的问题是推理开销成倍上升——需要对每个输入做多次带噪声的前向推理然后对预测做多数投票才能达到期望的平滑效果。在线业务如果对延迟和成本有硬约束这个方法可能暂时上不了线更适合离线或对延迟不敏感的场景。总结一下我的取舍建议对抗训练是解决根因预处理和检测是缓解症状模型结构改进是长期方向。不同阶段不同投入配合使用效果才能可控。单纯依赖任何单点方案上线后大概率会被绕过。6. 两个最容易踩的坑一个关于测试方法一个关于工程流程最后分享两个我在多次鲁棒性评估中反复见到的坑。第一个坑是过度相信白盒攻击的评估结果。很多团队用PGD在测试集上刷完ASR之后看到数值不高就得出模型鲁棒性不错的结论。但正如前面说的梯度掩盖会让白盒攻击失真而黑盒迁移攻击往往才是真实攻击路径的逼近。如果你只跑白盒攻击评估结果可能严重乐观。我建议至少每次评估都配置一条黑盒迁移攻击的测试路径跟白盒结果交叉对比。两个结果都低再下鲁棒性尚可的结论也不迟。第二个坑是把鲁棒性测试做成一次性项目。模型不是在测试那天之后就固定不变的后续每次迭代、微调、替换特征提取器都可能改变模型的对抗脆弱面。这次发现薄弱的地方修好了换一个模型版本可能又在别的地方出现新的缺口。所以鲁棒性测试应该嵌入到模型评估流水线里而不是作为上线前的一次性检查。我见过有的团队把对抗样本集缓存下来每次模型迭代后都跑一遍——这个做法值得推广因为虽然不能覆盖新攻击但至少能防住已知攻击的回归。最后一个实操体会做鲁棒性测试时团队里一定要有一个能站在攻击者角度思考的人。很多防御方案失败不是因为方案本身不行而是防御者默认攻击者只会用已知套路。当你开始问如果我有一小时、一台GPU、完全不了解模型结构想最快打穿这个系统我会怎么做的时候你对鲁棒性的理解才真正到位。AI应用架构师这个角色一半是建设者一半是模拟敌人的人两者缺一防线都会有明显的盲区。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑