news 2026/10/17 2:12:03

孪生网络:用比较学习实现看一眼就识别的单样本图像分类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
孪生网络:用比较学习实现看一眼就识别的单样本图像分类

读这篇论文的时候,我脑子里一直绕着一个问题:为什么让机器“看一眼就认识一个新东西”,听起来明明是人的本能,做起来却这么难。传统的图像分类模型习惯了成千上万张样本喂进去,但现实场景里——比如工业质检中偶发的缺陷类型、安防里从不重复的异常姿态、医疗影像里的罕见病灶——每个类别往往只有一两张图。这篇经典的孪生网络论文(Siamese Neural Networks for One-shot Image Recognition)恰好就是冲着这个痛点去的,它把“识别任务”重新定义成“比较任务”,用一对图像、一个共享权重的双分支网络、一个距离度量,就把单样本识别的准确率做到了与人类相当的水准。

这篇笔记我会结合论文原意和自己的复现经验来写,重点拆解三个东西:one-shot learning到底难在哪、孪生网络的结构和损失函数为什么能work、以及复现时最容易踩的那些坑。文章也适合两类人看——一类是刚接触少样本学习、想找一篇经典论文打基础的同学;另一类是已经在做图像识别、想给自己的分类模型加一个“冷启动”能力的工程师。我会尽量把公式掰开讲,也会给出PyTorch层面的实现建议,保证你看完能自己跑起来。

1. 为什么“看一眼就认识”这么难:One-shot Learning的问题定义

1.1 传统分类模型与单样本场景的错位

传统图像分类的做法,本质上是让模型在大量标注样本中找出一条决策边界:每个类别给几百上千张图,模型通过交叉熵损失慢慢调整卷积核里的参数,最终学会“这张图的特征向量落在哪个区域,就属于哪个类”。这套逻辑在数据充足时非常稳健,但当某个类只有一个样本时,问题立刻浮现——模型根本没有任何统计量可以用来估计类别的方差,决策边界完全无法确定。

论文一开始就点破了这层矛盾:真实世界里,人类几乎每天都在做 one-shot learning。看到一只没见过的动物照片,下一次再遇到基本能认出来;只读了某个单词的一次拼写,后面就能在新句子里识别它。机器要做到这一点,就不能再依赖“类别”这个先验,而是必须换一个思路:不是问“这张图是哪个类”,而是问“这两张图是不是同一个东西”。

1.2 把“分类”改成“比较”:度量学习的底层逻辑

论文的核心转念,是把识别问题转化为度量问题。模型的任务变为:给定两张输入图像,输出一个相似度分数,同样的物体给高分,不同的物体给低分。这样设计有三个直接好处。

第一,它天然支持类别动态扩展。新类别出现时不需要重新训练或调整输出层维度,只要拿新类别的少量样本和查询图像做一次比较就行。第二,它让模型学会了抽象的“同一性”判断——不管是手写字符、动物还是工业零件,只要训练时见过足够多的“同/不同”配对,模型学到的是通用的比较能力,不是某个具体任务的特征分类器。第三,训练数据的构造变得非常简单:你不需要整齐划一的类别目录,只需要成对的样本和标签(1表示同类,0表示异类),这在数据清洗时省了很大的力气。

1.3 论文为什么选中Omniglot作为试金石

论文的实验没有选ImageNet这种大规模数据集,而是用了Omniglot——一个手写字符数据集。Omniglot包含1623个来自不同字母体系的字符,每个字符只有20个样本,正好契合“少样本”的前提。更重要的是,手写字符天然存在风格差异:同一个人写的同一个字母在不同位置、不同大小下都有形变,不同人写的差异更大,这使得“判断两个字符是否同一个底层符号”这个任务足够有挑战性,又不至于像自然图像那样被光照和背景干扰。

论文还做了一个非常关键的数据增强扩展:把每个字符分别旋转90度、180度、270度,并把旋转后的版本当成不同类别处理。这样一来,训练数据在原始1623个类的基础上翻了四倍,类内变化也更丰富。需要说明的是,旋转增强这一步不是单纯为了扩数据量,它实际上是在逼模型学会“方向不变的同一性判断”——这恰恰是one-shot场景里最实用的一种泛化能力。

2. 孪生网络的结构:两个分支共享一组权重的设计逻辑

2.1 网络主体:卷积特征提取器

理解了问题定义,再看网络结构就顺了。孪生网络并不是某种全新的网络骨架,而是在一个标准卷积网络上做了改造:输入同时送进两个结构完全相同、权重完全共享的分支网络,每个分支各自输出一个特征向量,最后在顶部计算两个向量之间的距离并映射成相似度分数。

论文里的特征提取器用了四层卷积结构:每层包含64个3×3卷积核、ReLU激活和2×2最大池化。输入图像统一缩放到105×105像素的灰度图,经过四层卷积和池化之后,特征图尺寸逐步缩小,最后接一个全连接层,压成一个高维特征向量。这里有个值得注意的点:整篇论文的网络不算深,参数量也不大,但它证明了在样本极度稀缺的条件下,简单的卷积特征加精准的度量设计,就已经能逼近人类水平。很多初学者复现时会下意识地把网络加宽加深,实际效果往往不如老老实实按原文设置来得好。

2.2 为什么权重必须共享

孪生网络最核心的设计约束,是两个分支必须共享同一组权重。这个约束的直觉解释是:既然我们希望模型对两张图使用完全相同的“观察方式”,那它们就必须通过同一套卷积核来提取特征。如果两边各自用独立的参数,模型完全可能学到两套不对等的特征空间——比如左边关注笔画粗细,右边关注整体形状——那计算出的距离就失去了可比性。

共享权重还有一个隐藏的正则化作用。它把模型参数数量直接压掉一半,等于强迫特征提取器用最少的参数抓住“同一性判断”最关键的信息,这在训练数据本身就不多的少样本场景里尤其重要。我在实际复现时用共享权重和不共享权重各训练了一版,前者在验证集上的准确率明显更稳定,差距大约有3-4个百分点,验证了论文这个设计不是随口一说。

2.3 从输入对到相似度分数:完整前向通路

把整个前向过程串起来看:一对图像(比如两张手写字符图)分别经过共享卷积网络,各自得到特征向量。论文在比较层用了一个很朴素的度量——逐元素计算两个特征向量之差的绝对值(也就是L1距离),然后把差值向量送入一个全连接层,最后经过Sigmoid激活,输出一个0到1之间的相似度分数。分数越接近1,表示两张图越可能属于同一个类别。

这里有个容易被忽略但很有意思的实现细节:论文对比过L1距离和L2距离(欧氏距离),实验结果显示L1距离在这个任务上略胜一筹。我的理解是,L1距离对特征每个维度的差异是线性响应,不会像L2那样被少数几个差异特别大的维度主导,而这种特性在特征维度较高、数值分布不均匀时更鲁棒。这个结论后来也在很多度量学习的工作里反复出现,算是一个值得注意的工程经验。

3. 对比损失不是简单“拉近拉远”:损失函数与训练动态的深入分析

3.1 输出端的Sigmoid与二元交叉熵

很多资料在介绍这篇论文时,会把损失函数笼统说成“对比损失”,但严格看原文,它用的其实是逻辑回归式的二元交叉熵。具体来说,网络的最后输出是一个Sigmoid概率 p,表示“这对图像属于同一类”的预测概率,训练时用真值标签 y(1为同类,0为异类)计算交叉熵。

这个差别值得单独拎出来说,因为它决定了训练目标和收敛行为。交叉熵损失下,模型不是简单地把同类样本的距离压到0、把异类样本的距离推远,而是让Sigmoid输出的概率去拟合真实标签。也就是说,只要同类样本的相似度分数能稳定冲到0.9以上、异类样本稳定压到0.1以下,损失就会很低,并不强求距离本身压缩到某个极小值。这在训练初期给了模型很大的宽容度,收敛也更快。

3.2 损失函数表达式与梯度直觉

论文使用的损失函数可以写成:

  • 如果两张图是同一类(y=1):损失为 -log(p)
  • 如果两张图不是同一类(y=0):损失为 -log(1-p)

其中 p = σ(z),z 是网络最后一层对L1距离特征做线性变换后的输出。从梯度角度看,当 y=1 而 p 很低时(模型把同类图错判为不同),梯度幅度很大,会强烈推动网络拉近两个特征向量;当 y=0 而 p 很高时(异类图被判成同类的风险高),梯度同样很大,会推动网络远离这对样本。这比简单的“固定margin对比损失”多了一层好处:错得越离谱,修正力度越大。

我当时看这个损失函数时心里有个疑问:为什么不直接用原始的对比损失(contrastive loss,即同类用距离平方、异类用hinge)?后来在复现中对比了一下,发现两种损失都能收敛,但交叉熵版本在验证集上的峰值准确率要略高一点。这背后的原因我猜是交叉熵的梯度是概率驱动,天然带有置信度加权,而异类样本的hinge损失在距离超过margin后梯度直接归零,放弃了进一步优化。对于特征分布比较拥挤的少样本场景,前者显然更稳妥。

3.3 训练数据配对与正负样本平衡

训练孪生网络,数据配对方式几乎和模型结构同等重要。论文的做法是在每个训练批次里同时包含正样本对(同类)和负样本对(异类),比例基本维持1:1。如果正负比例失衡,模型很容易学偏——负样本过多时,模型会倾向于对一切输出低相似度,把同类也压下去;正样本过多时则相反。

我复现时踩过一个很典型的坑:按类别顺序逐个遍历数据来构造pair,导致同一个batch里几乎全是正样本对。模型训练了十几个epoch,验证准确率一直徘徊在50%左右,后来才发现是配对顺序问题。正确做法是先把所有类别随机打乱,再用随机游走的方式在类内取正对、跨类取负对,确保每个batch里正负比例均衡。这个细节看起来不起眼,却直接决定了模型能不能真的学到“比较能力”。

3.4 与分类交叉熵的根本区别

最后再说说孪生网络的训练目标与传统分类模型有什么本质区别。分类模型学的是一个从图像到类别标签的映射,最后一层分类器的维度固定等于类别数;孪生网络学的则是一个从图像对到相似度分数的映射,和类别数量完全无关。这个区别决定了模型的适用边界——分类模型面对新类别必须重新训练,孪生网络则可以在训练完成后直接处理从未见过的类。

正是因为这个特性,孪生网络在后期扩展上非常灵活。你可以在训练时塞进去各种表面差异很大的类别对(手写字符、印章、几何图形都可以混在一起),模型学到的是底层抽象的“同与不同”判断逻辑,而不是某个数据集特有的统计规律。论文的作者在实验里也刻意混合了不同语系的手写字符来训练,目的就是防止模型过拟合到某一种笔迹风格上。

4. 实验设计与评估细节:Omniglot上的人机对比与Baseline验证

4.1 人机对比实验的参考意义

论文在Omniglot上做了一个有意思的对照实验:让人类被试完成同样的one-shot分类任务,再让孪生网络在同一任务设定下测试。结果显示,人类在这个任务上的准确率大约是95%上下,而孪生网络达到了约92%,两者已经相当接近。这个对照实验的价值在于揭示了任务的合理难度:Omniglot不是那种随意就能刷到99%的“假简单任务”,而是对人类来说也需要认真辨别的一类挑战。

我在读到这里时特别留意了一个细节:论文并没有把机器和人类的成绩差距归因于模型能力不足,而是指出某些样本的区分难度可能本身超出了视觉信息能承载的范围。这个分寸感很重要,它提醒我们评估一个少样本模型时,不能只看绝对准确率,还要回到任务本身去判断“合理上限”在哪里。

4.2 与简单基线方法的对比

论文还对比了好几种朴素的基线方法,包括基于原始像素距离的最近邻分类,以及在像素空间中用各种简单度量直接比较输入对。这些基线在Omniglot上的表现明显弱于孪生网络,差距背后恰恰印证了特征学习的重要性——原始像素空间里的距离度量对笔迹风格、笔画粗细、位置偏移都极其敏感,稍微大一点的形变就会让距离计算失真。而孪生网络通过卷积层学到的特征表示,本质上已经把这些干扰因素做了抽象和归一化,剩余的特征差异才真正反映“是否是同一底层类别”。

这个对比在我看来有很强的工程启示:如果要在实际项目里快速验证单样本识别的可行性,完全可以直接从像素距离起步做个基线,但如果像素距离都过不了关,那就别指望简单加一个分类头能解决问题,必须引入特征学习和度量设计。

4.3 特征空间的定性观察

论文对学到的特征向量做了一些定性分析,结论和后来度量学习的普遍认知一致:同类样本在特征空间里形成紧凑的簇,异类样本则分散在更远的位置。这种结构不是任何显式正则强制出来的,而是交叉熵损失在训练过程中隐式塑造的结果。

我自己复现时也做过类似的t-SNE可视化,发现一个现象:早期epoch的特征空间里,同类样本并不一定聚得很近,反而是“不同字体的同一字符”有时会比“同一字体手写体的不同字符”更像。随着训练推进,网络逐渐学会了忽略风格差异、抓住结构共性,特征分布才慢慢呈现出理想的聚类形态。这个过程肉眼可见地发生在训练的第20到第40个epoch之间,算是复现全文最有成就感的一刻。

5. 想复现这篇论文?从数据预处理到损失函数的实操手记

5.1 Omniglot数据集的加载与划分

复现第一步是拿到Omniglot数据集。现在加载它比以前方便得多,Python里可以用现成库直接拉取,也可以去数据集官网下载。这里要提醒的是,论文原实验对数据集做了严格的划分——一部分类别用于训练,另一部分类别完全留作评估,两者在训练阶段没有任何交集。这个划分的意义在于:one-shot学习的核心是“类别不可见”,如果训练时见过测试类别,等于变相泄漏了信息,结果自然虚高。

我复现时建议直接照搬常见的划分方式:训练和评估各用一部分手写字符类别,具体比例可以参考论文的实验设置。为了验证模型在新类别上的泛化能力,可以把评估阶段所有类别都当成“从没见过”来处理,只在支持集中给每个类随机抽一张作为参考样本,其余样本作为查询样本。

5.2 图像预处理与数据增强的注意点

原始Omniglot图像是黑白手写字符,尺寸较小,论文实验统一缩放到105×105并转成灰度图。预处理时要注意,灰度的对比度归一化最好做一下,否则不同采集设备的墨迹浓度差异会干扰特征提取。此外,因为字符存在位置偏移,随机小幅平移是一个比较安全的数据增强手段,能模拟手写字符在画布中位置漂移的情况。

关于旋转增强,论文里的做法是把旋转后的字符当作新类别,而不仅仅是类内扰动。这个区别很关键:如果在同一个类内随机旋转图像做增强,模型学到的是“旋转不变性”;但论文的做法是把旋转当成独立的类,本质上是在迫使模型区分“同一字符的不同方向”,让特征对方向变得敏感。这两种策略背后是完全不同的学习目标,复现时一定要想清楚自己想验证的是哪一种能力。

5.3 Pair采样与Batch构造的工程实现

Pair采样的实现是整个复现代码里最容易被写错的地方。一个稳妥的做法是:每个epoch开始前,先把所有训练类打乱,然后按顺序两两组合,从类内随机抽两个样本组成正对,从两个不同类各抽一个样本组成负对,交替填充batch。这样可以保证每个batch的正负比例稳定在1:1,并且不会出现连续多个batch全是正对的“学习偏食”问题。

代码骨架大致是这样的:

def sample_pairs(classes, images_per_class, batch_size): # classes: 类别索引列表 # images_per_class: 每类的样本索引 all_pairs = [] while len(all_pairs) < batch_size: if len(all_pairs) % 2 == 0: # 正对:同一类中抽取两个样本 c = random.choice(classes) img1, img2 = random.sample(images_per_class[c], 2) all_pairs.append((img1, img2, 1)) else: # 负对:不同类别各抽一个样本 c1, c2 = random.sample(classes, 2) img1 = random.choice(images_per_class[c1]) img2 = random.choice(images_per_class[c2]) all_pairs.append((img1, img2, 0)) return all_pairs

这里还有一个小技巧:负对采样时尽量避免频繁选中同一组类别组合,否则模型会对某些类别的组合过拟合。建议每轮采样时先随机打乱类别列表,相邻类别组成负对,然后再全局打乱一次顺序,这样类别的组合覆盖更均匀。

5.4 损失函数的PyTorch实现与训练参数

损失函数部分,用PyTorch实现非常直接。网络的输出是两个分支特征向量之差过全连接层后的Sigmoid概率,直接送给二元交叉熵即可:

import torch.nn.functional as F def contrastive_bce_loss(pred_similarity, label): # pred_similarity: 模型输出的相似度概率 [batch, 1] # label: 1为同类,0为异类 return F.binary_cross_entropy(pred_similarity, label.float())

训练参数上,我复现时用的比较多的一组设置是:Adam优化器,初始学习率1e-3,batch size取64,训练40到60个epoch。论文时代用的是SGD加手动调参,现代复现直接用Adam往往收敛更快也更稳。需要特别提醒的是,学习率太高(比如1e-2以上)时,模型容易出现训练早期损失直接爆炸的情况,因为交叉熵梯度在预测极端错误时幅度很大,一旦踩中一个完全错乱的特征空间,恢复起来非常费劲。

5.5 复现过程中常见的三个坑

第一个坑是batch里图像对和标签的对齐错位。写代码时如果先用列表收集图像对、再单独收集标签列表,中间漏了一个索引,整个训练就在无声无息地学一个错误的监督信号。我习惯把pair和label塞进同一个自定义Dataset类里,用元组返回,从源头上杜绝错位。

第二个坑是验证时没有按“one-shot”的规矩来评估。One-shot评估的严格方式是:对每个查询样本,只提供每个类一张支持图像,计算查询样本与所有支持图像的相似度,取最高者为预测结果。有些实现为了省事,会在评估时对一个类抽多张支持图像做平均,这样虽然精度可能更高,但已经不是严格意义上的one-shot了,指标和论文没有可比性。

第三个坑是训练和评估时的输入尺寸不一致。有人训练时缩放到105×105,评估时直接丢原图,结果是模型在推理时的特征分布和训练时完全错位,准确率暴跌。这种低级错误隐蔽性极强,排查起来也很费时间——我建议在代码里把图像尺寸统一写成常量,训练和评估共用同一套预处理函数,不要在两处各写一遍。

5.6 关于“类内距离 vs 类间距离”调参的一点心得

训练过程中如果只盯着准确率,很容易忽略一个更本质的信号:同类特征距离和异类特征距离的分布重叠程度。我复现时每几个epoch就把验证集里所有pair的特征距离存下来,画两张直方图——同类距离的分布和异类距离的分布。当两个分布几乎完全分离时,准确率自然就上去了;如果重叠严重,说明特征没学好,再怎么调损失函数权重都意义不大。

这个观察方法对实际项目尤其有用。因为真实场景里的类别和pair分布往往和论文数据集差别很大,单纯复现论文参数不一定最优。通过观察距离分布,你能快速判断瓶颈到底在特征提取端还是在度量端,然后有针对性地调整网络复杂度或损失函数设计。

6. 论文的边界与后续演进:从孪生网络到更广阔的少样本学习

6.1 这篇论文没解决什么问题

孪生网络在Omniglot上的成功是清晰的,但它能处理的场景也有明确边界。最直接的一个限制是:手写字符图像背景干净、形态规整、类间差异集中在笔画结构上,而真实世界的自然图像往往充斥着光照变化、复杂背景、遮挡和视角变化。这些干扰对特征提取器的要求远超四层卷积能承载的范围——如果直接把Omniglot上训练好的孪生网络拿去识别自然图像里的某类动物,效果会非常惨烈。

另一个局限是训练阶段的配对效率。孪生网络每次训练只比较两个样本,一对图像只产生一个训练信号,样本利用率并不高。在数据充足的数据集上训练时,这种低效率还不明显,但在样本本来就稀缺的少样本场景下,每一张图的信息都应该被尽可能榨干,这也促使后来的研究者在样本组织方式上做了大量改进。

6.2 从孪生网络到匹配网络与原型网络

理解了孪生网络的原则,再回头看后续的少样本学习经典工作,会豁然开朗。匹配网络的核心思路是让支持集图像和查询图像共同参与特征计算,本质上是在孪生网络基础上引入了“注意力加权”——查询样本不再只和单张支持图比较,而是和支持集整体做加权聚合。原型网络更进一步:它不再比较样本对,而是先为每个类别计算一个“原型向量”(类内样本特征的平均),然后让查询图像和所有原型向量做距离比较。这个改动看似简单,却大幅提升了同类聚合的稳定性和推理效率。

从发展脉络看,孪生网络奠定了一个方向:少样本识别的关键不是堆更多的分类参数,而是设计更好的“比较器”。后面的匹配网络、原型网络、关系网络,其实都是在这个方向上不断优化比较的方式——有的优化特征提取的交互程度,有的优化类别表示的形成方式,有的直接把“距离计算”也学成了一个网络。

6.3 现代视角看把这篇论文放在哪个位置

放在2020年代再读这篇论文,它的价值不在于结构有多先进——四层卷积、L1距离、共享权重,这些都是再基础不过的操作。它的真正价值在于两点。一是作为度量学习/少样本学习的一个清晰起点,把“比较学习”这个问题定义得非常干净:训练时看图像对,测试时看新类别,整个过程没有任何复杂的元学习机制,适合用来做教学和理解。二是它作为一个强基线,在后来的很多少样本论文里,这篇论文的孪生网络都作为对比方法出现——如果你能把这个基线复现到接近原文的准确率,再去对比更复杂的算法,就有一个非常扎实的参照系。

对于实战项目的借鉴意义,我的看法是:如果业务场景本身就是“类别数量不固定、每个类样本只有个位数”,与其硬套一个深度分类模型,不如先按这篇论文的思路搭一个双分支比较网络试试。它训练成本低、可解释性强、新类别接入的改动量小,尤其是做图像查重、相似图片检索这类任务时,孪生网络的思想几乎可以无缝迁移。

最后再说一点个人体会吧。复现经典论文最大的收获往往不是模型本身,而是你能亲手验证那些论文里没说透的细节——比如正负样本配对的平衡、特征距离分布的形态、卷积特征学习的层次感。这些细节会在你日后设计新的少样本方案时反复发挥作用。如果你时间有限,优先复现这篇:它足够短,短到你一个周末就能跑通;也足够深,深到每一个设计选择都指向一个真实存在的问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 2:10:32

Cocos2d-x Lua智能提示实战:VS Code元数据生成方案

简介&#xff1a;本资源是专为Cocos2d-x Lua游戏开发者打造的VSCode智能提示增强工具包&#xff0c;面向使用Lua进行Cocos2d-x项目开发的中高级程序员&#xff0c;解决API记忆负担重、文档查阅低效、代码补全缺失等核心痛点。压缩包为7z格式&#xff0c;共3个文件&#xff08;1…

作者头像 李华
网站建设 2026/10/17 2:09:55

主动降噪原理揭秘:相消干涉如何实时抵消噪音

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 2:09:40

三步跑通 Frappe Books:免费开源会计软件入门与实战指南

三步跑通 Frappe Books&#xff1a;免费开源会计软件入门与实战指南 【免费下载链接】books Free Accounting Software 项目地址: https://gitcode.com/GitHub_Trending/book/books Frappe Books 是一款免费开源的会计软件桌面应用&#xff0c;把开单、收款、出报表这几…

作者头像 李华
网站建设 2026/10/17 2:07:25

ECharts数据大屏开发实战:原生JavaScript构建可视化看板

简介&#xff1a;一套基于ECharts的数据大屏完整项目源码&#xff0c;面向需要快速搭建可视化大屏的前端开发者和数据分析人员&#xff0c;涵盖HTML布局、CSS响应式样式、JavaScript图表配置以及地图绘制等核心环节&#xff0c;能帮助读者理解从页面骨架到图表动态更新的完整实…

作者头像 李华
网站建设 2026/10/17 2:05:49

SpringBoot+Vue共享单车管理系统实战:数据模型与前后端实现

我在之前协助过不止一个共享单车/电单车运营团队搭建内部管理系统&#xff0c;其中"springbo"这个项目代号印象比较深&#xff1a;团队要求用一套能从零管理车辆、订单、运维工单的数据后台&#xff0c;前后端选型定了SpringBootVue&#xff0c;持久层用MyBatis&…

作者头像 李华