微调神经机器翻译模型全流程
MBART: Multilingual Denoising Pre-training for Neural Machine Translation
模型下载
mBART 是一个基于序列到序列的去噪自编码器,使用 BART 目标在多种语言的大规模单语语料库上进行预训练。mBART 是首批通过去噪完整文本在多种语言上预训练序列到序列模型的方法之一,而以往的方法则仅集中在编码器、解码器或重构文本的部分内容。
首先需要在github上下载mbart的预训练模型,我们要完成的任务是微调:README
下载mbart.CC25模型,下载解压后的目录如下:
├── mbart.cc25.v2└── dict.txt└── model.pt└── sentence.bpe.model
dict是模型的词典文件,model是mbart的预训练模型,sentence.bpe.model是sentencepiece训练分词的模型。
我们在en->vi
双语对上对预训练模型进行微调:
数据为IWSLT15的双语对,下载好数据之后对训练集、验证集和测试集重新命名,整理后的目录如下
├── en_vi └── test.en_XX└── test.vi_VN└── train.en_XX└── train.vi_VN└── valid.en_XX└── valid.vi_VN
环境准备
这里需要特定的fairseq版本来完成以下的这些命令,因此推荐新创建一个conda环境来隔离版本,这里我们命名为mbart_ft.
fairseq=0.10.2
python=3.8
numpy=1.19.5
数据分词
首先使用sentencepiece模型对数据进行分词,由于原文中描述没有额外的 true-casing、normalizing punctuation / characters.因此我们直接分词即可。
#!/bin/bashSPM=/path/to/sentencepiece/build/src/spm_encode
MODEL=/mbart/mbart.cc25.v2/sentence.bpe.model
DATA=/mbart/en_vi
DEST=/mbart/en_vi/spm
TRAIN=train
VALID=valid
TEST=test
SRC=en_XX
TGT=vi_VN ${SPM} --model=${MODEL} < ${DATA}/${TRAIN}.${SRC} > ${DEST}/${TRAIN}.spm.${SRC} &
${SPM} --model=${MODEL} < ${DATA}/${TRAIN}.${TGT} > ${DEST}/${TRAIN}.spm.${TGT} &
${SPM} --model=${MODEL} < ${DATA}/${VALID}.${SRC} > ${DEST}/${VALID}.spm.${SRC} &
${SPM} --model=${MODEL} < ${DATA}/${VALID}.${TGT} > ${DEST}/${VALID}.spm.${TGT} &
${SPM} --model=${MODEL} < ${DATA}/${TEST}.${SRC} > ${DEST}/${TEST}.spm.${SRC} &
${SPM} --model=${MODEL} < ${DATA}/${TEST}.${TGT} > ${DEST}/${TEST}.spm.${TGT} &wait
echo "SentencePiece encoding completed!"
我们创建spm目录,分词后的目录文件为:
├── en_vi├── spm └── test.spm.en_XX└── test.spm.vi_VN└── train.spm.en_XX└── train.spm.vi_VN└── valid.spm.en_XX└── valid.spm.vi_VN
数据预处理
使用fairseq将数据处理为满足训练的、输入模型的格式。包含两种语言的词典文件、二进制格式和分词转换为id的文件。
#!/bin/bashBASEDIR=/mbart/en_vi
DATA=${BASEDIR}/spm
DEST=${BASEDIR}/ids
DICT=/mbart/mbart.cc25.v2/dict.txt
SRC=en_XX
TGT=en_viTRAIN=train
VALID=valid
TEST=testfairseq-preprocess \
--source-lang ${SRC} \
--target-lang ${TGT} \
--trainpref ${DATA}/${TRAIN}.spm \
--validpref ${DATA}/${VALID}.spm \
--testpref ${DATA}/${TEST}.spm \
--destdir ${DEST}/ \
--thresholdtgt 0 \
--thresholdsrc 0 \
--srcdict ${DICT} \
--tgtdict ${DICT} \
--workers 70
预处理后的模型数据准备的目录为:
├── en_vi├── ids └── dict.en_XX.txt└── dict.vi_VN.txt└── preprocess.log└── test.en_XX-vi_VN.en_XX.bin└── test.en_XX-vi_VN.en_XX.idx└── test.en_XX-vi_VN.vi_VN.bin└── test.en_XX-vi_VN.vi_VN.idx└── train.en_XX-vi_VN.en_XX.bin└── train.en_XX-vi_VN.en_XX.idx└── train.en_XX-vi_VN.vi_VN.bin└── train.en_XX-vi_VN.vi_VN.idx└── valid.en_XX-vi_VN.en_XX.bin└── valid.en_XX-vi_VN.en_XX.idx└── valid.en_XX-vi_VN.vi_VN.bin└── valid.en_XX-vi_VN.vi_VN.idx
训练集和验证集在训练过程中被用到,而测试集只在评价生成中被用到。
模型的训练
需要注意的是,与官方文档设置的参数相比,有一处需要修改。
--max-update 40000
:模型参数更新次数。
----total-num-update 40000
这是设置学习率调度器的更新次数,即学习率更新40k次训练停止。
在mbart的原文中:
We use a maximum of 40K training updates for all low and medium resource pairs and 100K for high resource pairs.
我们的en-vi双语数据属于低资源语言对,因此参数更新次数40K次,即应该设置--max-update 40000
#!/bin/bash
source /path/to/conda/etc/profile.d/conda.sh
conda activate mbart_ftBASEDIR=/mbart/en_vi
PRETRAIN=/mbart/mbart.cc25.v2/model.pt # 已下载的预训练模型路径
DATA=${BASEDIR}/ids # 预处理后的二进制数据路径SRC=en_XX
TGT=vi_VNlangs=ar_AR,cs_CZ,de_DE,en_XX,es_XX,et_EE,fi_FI,fr_XX,gu_IN,hi_IN,it_IT,ja_XX,kk_KZ,ko_KR,lt_LT,lv_LV,my_MM,ne_NP,nl_XX,ro_RO,ru_RU,si_LK,tr_TR,vi_VN,zh_CNfairseq-train ${DATA} \--encoder-normalize-before --decoder-normalize-before \--arch mbart_large --layernorm-embedding \--task translation_from_pretrained_bart \--source-lang ${SRC} --target-lang ${TGT} \--criterion label_smoothed_cross_entropy --label-smoothing 0.2 \--optimizer adam --adam-eps 1e-06 --adam-betas '(0.9, 0.98)' \--lr-scheduler polynomial_decay --lr 3e-05 --warmup-updates 2500 --max-update 40000 \--dropout 0.3 --attention-dropout 0.1 --weight-decay 0.0 \--max-tokens 1024 --update-freq 2 \--save-interval 1 --save-interval-updates 5000 --keep-interval-updates 10 --no-epoch-checkpoints \--seed 222 --log-format simple --log-interval 2 \--restore-file $PRETRAIN \--reset-optimizer --reset-meters --reset-dataloader --reset-lr-scheduler \--langs $langs \--save-dir ${BASEDIR} \--ddp-backend no_c10d
在一块RTX 4090显卡上,运行3个小时后,训练结束。我们设置了每5000次更新保存一次检查点,微调模型保存的文件位置为 --save-dir ${BASEDIR}
微调后的目录文件为:
├── en_vi├── ids ├── spm└── dict.en_XX.txt└── checkpoint_2_5000.pt└── checkpoint_4_10000.pt└── checkpoint_6_15000.pt└── checkpoint_8_20000.pt└── checkpoint_10_25000.pt└── checkpoint_12_30000.pt└── checkpoint_14_35000.pt└── checkpoint_16_40000.pt└── checkpoint_best.pt└── checkpoint_last.pt└── ...train...test...valid
模型的解码
我们使用checkpoint_best.pt
对其进行解码以及测BLEU分数。
这里我将分词模型复制到了en_vi文件夹中,并且添加--cpu
使得解码在cpu上运行。解码生成的文件为/mbart/en_vi/ids/en_vi
2025.1.13修订:
需要注意的是,相比于官方文档,这里删除了--bpe "sentencepiece"
、--sentencepiece-model $model_dir/sentence.bpe.model
以及--sacrebleu
若保留--sacrebleu
,由于版本间不匹配会报错
若保留--bpe "sentencepiece"
,则除了模型推理行“H”,其他源句子、目标句子和行“D”均没有空格出现。说明解码过程中并不需要此参数。
--remove-bpe 'sentencepiece'
:用于去除分词过程中产生的spm标记。
#!/bin/bash
source /path/to/conda/etc/profile.d/conda.sh
conda activate mbart_ft
model_dir=/mbart/en_vi/ids langs=ar_AR,cs_CZ,de_DE,en_XX,es_XX,et_EE,fi_FI,fr_XX,gu_IN,hi_IN,it_IT,ja_XX,kk_KZ,ko_KR,lt_LT,lv_LV,my_MM,ne_NP,nl_XX,ro_RO,ru_RU,si_LK,tr_TR,vi_VN,zh_CN
TOKENIZER=${model_dir}/sentence.bpe.modelfairseq-generate ${model_dir} \--path $model_dir/../checkpoint_best.pt \--task translation_from_pretrained_bart \--gen-subset test \--cpu \-t vi_VN -s en_XX \--remove-bpe 'sentencepiece' \--batch-size 32 \--langs $langs > ${model_dir}/en_vi
查看生成文件en_vi的片段:
S-74 I lost all hope .[en_XX]
T-74 Tôi hoàn toàn tuyệt vọng .
H-74 -0.4808153808116913 Tôi đã mất hết hy vọng .
D-74 -0.4808153808116913 Tôi đã mất hết hy vọng .
P-74 -0.3194 -0.9490 -0.5736 -0.8777 -0.7397 -0.0389 -0.4746 -0.2814 -0.2920 -0.2618
S-372 Today I am 22 .[en_XX]
T-372 Hôm nay tôi 22 tuổi .
H-372 -0.3478223383426666 Hôm nay tôi 22 tuổi .
D-372 -0.3478223383426666 Hôm nay tôi 22 tuổi .
P-372 -0.5605 -0.0631 -0.4549 -0.2989 -0.4617 -0.4079 -0.3166 -0.3061 -0.2606
S-336 Thank you very much .[en_XX]
T-336 Cám ơn rất nhiều .
H-336 -0.46486935019493103 Cám ơn các bạn rất nhiều .
D-336 -0.46486935019493103 Cám ơn các bạn rất nhiều .
P-336 -1.8484 -0.0979 -0.1278 -0.9053 -0.2160 -0.4894 -0.1446 -0.4404 -0.2856 -0.3061 -0.2521
S-1267 Thank you very much .[en_XX]
T-1267 Cảm ơn rất nhiều .
H-1267 -0.46486935019493103 Cám ơn các bạn rất nhiều .
D-1267 -0.46486935019493103 Cám ơn các bạn rất nhiều .
P-1267 -1.8484 -0.0979 -0.1278 -0.9053 -0.2160 -0.4894 -0.1446 -0.4404 -0.2856 -0.3061 -0.2521
S-21 But many die .[en_XX]
T-21 Nhưng rất nhiều người đã chết .
H-21 -0.5680863261222839 Nhưng nhiều người chết .
D-21 -0.5680863261222839 Nhưng nhiều người chết .
P-21 -0.3266 -1.4395 -0.1804 -1.2362 -0.5122 -0.2999 -0.2973 -0.2526
S:是源句子,在en->vi
双语对上,源语言是英语。
T:是人工翻译句子,即测试集中的句子;
H:是模型输出的解码句子,第一个数字为其得分;
D:第一个数字为得分和H一致,但相比于H去掉了所有的空格,和S、T格式相同;
P:翻译过程中每个单词的预测概率。
运行解码脚本后,在ids目录中会生成 en_vi 文件。
├── en_vi├── ids └── sentence.bpe.model└── en_vi└── train...test...valid...dict...├── spm├── train...valid...test...
模型的评价
cat en_vi | grep -P "^H" |sort -V |cut -f 3- | sed 's/\[vi_VN\]//g' > en_vi.hyp
cat en_vi | grep -P "^T" |sort -V |cut -f 2- | sed 's/\[vi_VN\]//g' > en_vi.ref
sacrebleu en_vi.ref -i en_vi.hyp -m bleu
这里将 H 开头的行提取,并去掉前两个字段,仅保留模型输出的解码句子,将他们合成 en_vi.hyp文件;
将 T 开头的行提取,并去掉第一个字段,保留test文件中的目标句子,将他们合成 en_vi.ref 文件。
这两行代码运行后,目录ids中应该多出两个文件。
├── en_vi├── ids └── en_vi└── en_vi.hyp└── en_vi.ref└── train...test...valid...dict...├── spm├── train...valid...test...
这两个文件的行数应该一致,使用sacrebleu来测bleu的分数,指定 -tok 分词方式是 “spm” 即sentencepiece。
我们测试的模型评价结果为:
{"name": "BLEU","score": 34.7,"signature": "nrefs:1|case:mixed|eff:no|tok:13a|smooth:exp|version:2.4.3","verbose_score": "66.2/42.0/27.8/18.7 (BP = 1.000 ratio = 1.007 hyp_len = 33986 ref_len = 33738)","nrefs": "1","case": "mixed","eff": "no","tok": "13a","smooth": "exp","version": "2.4.3"
}
附录
2025.1.13修订:
原版本未删除--bpe "sentencepiece"
、--sentencepiece-model $model_dir/sentence.bpe.model
参数,fairseq推理后生成的en_vi文件为:
S-74 Ilostallhope.[en_XX]
T-74 Tôihoàntoàntuyệtvọng.
H-74 -0.4808153808116913 Tôi đã mất hết hy vọng .
D-74 -0.4808153808116913 Tôiđãmấthếthyvọng.
P-74 -0.3194 -0.9490 -0.5736 -0.8777 -0.7397 -0.0389 -0.4746 -0.2814 -0.2920 -0.2618
S-372 TodayIam22.[en_XX]
T-372 Hômnaytôi22tuổi.
H-372 -0.3478223383426666 Hôm nay tôi 22 tuổi .
D-372 -0.3478223383426666 Hômnaytôi22tuổi.
P-372 -0.5605 -0.0631 -0.4549 -0.2989 -0.4617 -0.4079 -0.3166 -0.3061 -0.2606
S-336 Thankyouverymuch.[en_XX]
T-336 Cámơnrấtnhiều.
H-336 -0.46486935019493103 Cám ơn các bạn rất nhiều .
D-336 -0.46486935019493103 Cámơncácbạnrấtnhiều.
P-336 -1.8484 -0.0979 -0.1278 -0.9053 -0.2160 -0.4894 -0.1446 -0.4404 -0.2856 -0.3061 -0.2521
S-1267 Thankyouverymuch.[en_XX]
T-1267 Cảmơnrấtnhiều.
H-1267 -0.46486935019493103 Cám ơn các bạn rất nhiều .
D-1267 -0.46486935019493103 Cámơncácbạnrấtnhiều.
P-1267 -1.8484 -0.0979 -0.1278 -0.9053 -0.2160 -0.4894 -0.1446 -0.4404 -0.2856 -0.3061 -0.2521
S-21 Butmanydie.[en_XX]
T-21 Nhưngrấtnhiềungườiđãchết.
H-21 -0.5680863261222839 Nhưng nhiều người chết .
D-21 -0.5680863261222839 Nhưngnhiềungườichết.
P-21 -0.3266 -1.4395 -0.1804 -1.2362 -0.5122 -0.2999 -0.2973 -0.2526
可以看到,测试集源句子S以及目标句子T的空格被误删除。由此提取的模型生成文件en_vi.hyp和翻译参考文件en_vi.ref同样误删空格。且模型输出句子H是正常的,这就说明是在解码过程中出现的问题。
2025.1.15修订:
在使用sacrebleu测bleu分数时,-tok 参数指定分词器。
默认为“13a”,即不添加此参数时的默认,我们测出评分为34.7.
指定为"spm" 等同于 “flores101”,使用基于Flores-101和Flores-200数据集构建的SentencePiece模型。
{"name": "BLEU","score": 35.4,"signature": "nrefs:1|case:mixed|eff:no|tok:flores101|smooth:exp|version:2.4.3","verbose_score": "66.3/42.8/28.8/19.5 (BP = 0.997 ratio = 0.997 hyp_len = 34971 ref_len = 35063)","nrefs": "1","case": "mixed","eff": "no","tok": "flores101","smooth": "exp","version": "2.4.3"
}
指定为“none”,将不应用任何分词,测出评分为:
{"name": "BLEU","score": 34.6,"signature": "nrefs:1|case:mixed|eff:no|tok:none|smooth:exp|version:2.4.3","verbose_score": "66.2/42.0/27.8/18.6 (BP = 1.000 ratio = 1.008 hyp_len = 33948 ref_len = 33682)","nrefs": "1","case": "mixed","eff": "no","tok": "none","smooth": "exp","version": "2.4.3"
}
相关文章:

微调神经机器翻译模型全流程
MBART: Multilingual Denoising Pre-training for Neural Machine Translation 模型下载 mBART 是一个基于序列到序列的去噪自编码器,使用 BART 目标在多种语言的大规模单语语料库上进行预训练。mBART 是首批通过去噪完整文本在多种语言上预训练序列到序列模型的方…...
Cesium加载地形
Cesium的地形来源大致可以分为两种,一种是由Cesium官方提供的数据源,一种是第三方的数据源,官方源依赖于Cesium Assets,如果设置了AccessToken后,就可以直接使用Cesium的地形静态构造方法来获取数据源CesiumTerrainPro…...

gitlab runner正常连接 提示 作业挂起中,等待进入队列 解决办法
方案1 作业挂起中,等待进入队列 重启gitlab-runner gitlab-runner stop gitlab-runner start gitlab-runner run方案2 启动 gitlab-runner 服务 gitlab-runner start成功启动如下 [rootdocserver home]# gitlab-runner start Runtime platform …...
C#对动态加载的DLL进行依赖注入,并对DLL注入服务
文章目录 什么是依赖注入概念常用的依赖注入实现什么是动态加载定义示例对动态加载的DLL进行依赖注入什么是依赖注入 概念 依赖注入(Dependency Injection,简称 DI)是一种软件设计模式,用于解耦软件组件之间的依赖关系。在 C# 开发中,它主要解决的是类与类之间的强耦合问题…...

HDMI接口
HDMI接口 前言各版本区别概述(Overview)接口接口类型Type A/E 引脚定义Type B 引脚定义Type C 引脚定义Type D 引脚定义 传输流程概述Control Period前导码字符边界同步Control Period 编/解码 Data Island PeriodLeading/Trailing Guard BandTERC4 编/解…...

A/B 测试:玩转假设检验、t 检验与卡方检验
一、背景:当“审判”成为科学 1.1 虚拟场景——法庭审判 想象这样一个场景:有一天,你在王国里担任“首席审判官”。你面前站着一位嫌疑人,有人指控他说“偷了国王珍贵的金冠”。但究竟是他干的,还是他是被冤枉的&…...

第143场双周赛:最小可整除数位乘积 Ⅰ、执行操作后元素的最高频率 Ⅰ、执行操作后元素的最高频率 Ⅱ、最小可整除数位乘积 Ⅱ
Q1、最小可整除数位乘积 Ⅰ 1、题目描述 给你两个整数 n 和 t 。请你返回大于等于 n 的 最小 整数,且该整数的 各数位之积 能被 t 整除。 2、解题思路 问题拆解: 题目要求我们找到一个整数,其 数位的积 可以被 t 整除。 数位的积 是指将数…...
【STM32】LED状态翻转函数
1.利用状态标志位控制LED状态翻转 在平常编写LED状态翻转函数时,通常利用状态标志位实现LED状态的翻转。如下所示: unsigned char led_turn_flag; //LED状态标志位,1-点亮,0-熄灭/***************************************函…...

uniapp 小程序 textarea 层级穿透,聚焦光标位置错误怎么办?
前言 在开发微信小程序时,使用 textarea 组件可能会遇到一些棘手的问题。最近我在使用 uniapp 开发微信小程序时,就遇到了两个非常令人头疼的问题: 层级穿透:由于 textarea 是原生组件,任何元素都无法遮盖住它。当其…...

汽车 SOA 架构下的信息安全新问题及对策漫谈
摘要:随着汽车行业的快速发展,客户和制造商对车辆功能的新需求促使汽车架构从面向信号向面向服务的架构(SOA)转变。本文详细阐述了汽车 SOA 架构的协议、通信模式,并与传统架构进行对比,深入分析了 SOA 给信…...

Unity-Mirror网络框架-从入门到精通之RigidbodyPhysics示例
文章目录 前言示例一、球体的基础配置二、三个球体的设置差异三、示例意图LatencySimulation前言 在现代游戏开发中,网络功能日益成为提升游戏体验的关键组成部分。本系列文章将为读者提供对Mirror网络框架的深入了解,涵盖从基础到高级的多个主题。Mirror是一个用于Unity的开…...

小程序如何引入腾讯位置服务
小程序如何引入腾讯位置服务 1.添加服务 登录 微信公众平台 注意:小程序要企业版的 第三方服务 -> 服务 -> 开发者资源 -> 开通腾讯位置服务 在设置 -> 第三方设置 中可以看到开通的服务,如果没有就在插件管理中添加插件 2.腾讯位置服务…...

H3CNE-12-静态路由(一)
静态路由应用场景: 静态路由是指由管理员手动配置和维护的路由 路由表:路由器用来妆发数据包的一张“地图” 查看命令: dis ip routing-table 直连路由:接口配置好IP地址并UP后自动生成的路由 静态路由配置: ip…...
多线程锁
在并发编程中,锁(Lock)是一种用于控制多个线程对共享资源访问的机制。正确使用锁可以确保数据的一致性和完整性,避免出现竞态条件(Race Condition)、死锁(Deadlock)等问题。Java 提供…...
ZooKeeper 核心知识全解析:架构、角色、节点与应用
1.ZooKeeper 分布式锁怎么实现的 ZooKeeper 是一个高效的分布式协调服务,它提供了简单的原语集来构建更复杂的同步原语和协调数据结构。利用 ZooKeeper 实现分布式锁主要依赖于它的顺序节点(Sequential Node)特性以及临时节点(Ep…...

笔记本电脑 选购 回收 特权模式使用 指南
笔记本电脑 factor 无线网卡:有些笔记本无法检测到特定频段的信息,会导致连不上校园网 sudo iwlist wlp2s0 scan | grep Frequency > net.txt cat net.txt>表示用终端输出覆盖后续文件,>>表示添加到后续文件的末尾 一种更简…...

2023-2024 学年 广东省职业院校技能大赛(高职组)“信息安全管理与评估”赛题一
2023-2024 学年 广东省职业院校技能大赛(高职组“信息安全管理与评估”赛题一) 模块一:网络平台搭建与设备安全防护第一阶段任务书任务 1:网络平台搭建任务 2:网络安全设备配置与防护DCRS:DCFW:DCWS:DCBC:WAF: 模块二:网络安全事件…...

C#补充----反射,特性,迭代器,特殊语法,值类型运用类型。
1.反射:通过type 获取类中的数据。创建实例,并赋值。 《1》获取类的方式 《2》反射的应用 <1>获取类型的所有公共成员 <2>获取构造函数 <3>获取类型的 公共成员变量 <4>获取类型的 公共方法 <5>.获取类型的 属性 <6&g…...

深度学习核函数
一、核函数的基本概念 核函数在机器学习中具有重要应用价值,常用于支持向量机(SVM)等算法中。 核函数是面试中经常被考到的知识点,对于找工作和实际数据转换都有重要作用。 二、数据建模与核函数的作用 数据越多,可…...

Spring MVC流程一张图理解
由于现在项目中大部分都是使用springboot了,但是ssm中的springmvc还是可以了解一下 1 、用户发送请求至前端控制器 DispatcherServlet 。 2 、 DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。 3 、处理器映射器找到具体的处理器 ( 可以根据 xml 配…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)
cd /home 进入home盘 安装虚拟环境: 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境: virtualenv myenv 3、激活虚拟环境(激活环境可以在当前环境下安装包) source myenv/bin/activate 此时,终端…...

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...