当前位置: 首页 > news >正文

【大模型实战篇】大模型分词算法Unigram及代码示例

1. 算法原理介绍

        与 BPE 分词(参考《BPE原理及代码示例》)和 WordPiece 分词(参考《WordPiece原理及代码示例》)不同,Unigram 分词方法【1】是从一个包含足够多字符串或词元的初始集合开始,迭代地删除其中的词元,直到达到预期的词表大小。该方法假设通过删除某个词元能够增加训练语料的似然性,并以此作为选择标准。这个过程依赖于一个训练好的单一语言模型。

        为了估计单一语言模型,在每次迭代中,首先根据旧的语言模型找到当前最优的分词方式,然后重新估计单一概率以更新语言模型。通常,使用动态规划算法(如维特比算法,Viterbi Algorithm)来高效找到语言模型对词汇的最优分词方案。

        Unigram算法通常用于SentencePiece,这是AlBERT、T5、mBART、Big Bird和XLNet等模型使用的分词算法。如前述,Unigram训练算法与BPE和WordPiece相比,Unigram的工作方式相反:它从一个大词汇开始,逐步删除其中的标记,直到达到所需的词汇大小。可以使用多种方法构建基础词汇,例如提取预分词单词中最常见的子串,或在具有较大词汇量的初始语料库上应用BPE。

        在训练的每一步,Unigram算法根据当前词汇计算语料库的损失。然后,对于词汇中的每个符号,算法计算如果移除该符号整体损失将增加多少,并寻找对整体损失影响最小的符号。这些符号对语料库的整体损失影响较小,因此在某种意义上,它们是“需求较低”的,最适合被删除。可以预见,这个过程非常耗时。需要注意基本字符绝不删除,以确保任何单词都可以被分词。

2. 案例说明

        重用在BPE中的语料库:

         ("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5)

        在这个例子中,将所有严格子串作为初始词汇:

         ["h", "u", "g", "hu", "ug", "p", "pu", "n", "un", "b", "bu", "s", "hug", "gs", "ugs"]

        分词算法 Unigram模型是一种语言模型,认为每个标记与之前的标记是独立的。这是最简单的语言模型,因为给定之前的上下文,标记X的概率仅为标记X的概率。因此,如果使用Unigram语言模型生成文本,总是会预测最常见的标记。给定标记的概率是其在原始语料库中的频率(出现次数),除以词汇中所有标记频率的总和(以确保概率总和为1)。例如,“ug”出现在“hug”、“pug”和“hugs”中,因此在当前语料库中它的频率为20。

        以下是词汇中所有可能子词的频率:

 ("h", 15) ("u", 36) ("g", 20) ("hu", 15) ("ug", 20) ("p", 17) ("pu", 17) ("n", 16) ("un", 16) ("b", 4) ("bu", 4) ("s", 5) ("hug", 15) ("gs", 5) ("ugs", 5)

        因此,所有频率的总和为210,而子词“ug”的概率为20/210。

        现在,为了对给定单词进行分词,查看所有可能的分词方式,并根据Unigram模型计算每种方式的概率。由于所有标记被视为独立,因此该概率只是每个标记概率的乘积。例如,单词“pug”的分词["p", "u", "g"]的概率为:

P ( [ "p" , "u" , "g" ] ) = P ( "p" ) × P ( "u" ) × P ( "g" ) = 5/210 × 36/210 × 20/210= 0.000389 

        相比之下,分词["pu", "g"]的概率为:

        P ( [ "pu" , "g" ] ) = P ( "pu" ) × P ( "g" ) = 5/210 × 20/210 = 0.0022676

        因此,这种分词的概率要高得多。一般来说,标记数量最少的分词将具有最高的概率(因为对于每个标记都有210的除法),这对应于直观上的目的:将单词分成尽可能少的标记。

        使用Unigram模型对单词进行分词的结果是概率最高的分词。在“pug”的例子中,为每个可能的分词计算的概率如下:

         ["p", "u", "g"] : 0.000389

         ["p", "ug"] : 0.0022676

         ["pu", "g"] : 0.0022676

        因此,“pug”的分词将为["p", "ug"]或["pu", "g"],具体取决于首先遇到的分词。

        在这个情况下,很容易找到所有可能的分词并计算它们的概率,但通常这会更困难。采用维特比算法,可以构建一个图来检测给定单词的可能分词,通过说如果从字符a到字符b有一个子词,则从a到b有一个分支,并将子词的概率赋予该分支。

        为了找到在该图中具有最佳分数的路径,维特比算法确定每个单词位置的最佳分词,它结束于该位置。由于是从开始到结束,因此通过遍历所有以当前字符结束的子词来找到最佳分数,然后使用该子词起始位置的最佳分词分数。接下来,只需解开到达结尾的路径。

        看一个使用我们的词汇和单词“unhug”的例子。对于每个位置,最佳分数的子词如下:

        字符0 (u): "u" (分数0.171429)

        字符1 (n): "un" (分数0.076191)

        字符2 (h): "un" "h" (分数0.005442)

        字符3 (u): "un" "hu" (分数0.005442)

        字符4 (g): "un" "hug" (分数0.005442)

        因此,“unhug”的分词将为["un", "hug"]。

        基于上述例子,已经了解了分词是如何工作的,进一步探讨训练期间使用的损失函数。在任何给定阶段,这个损失是通过对语料库中的每个单词进行分词计算的,使用当前的词汇表和根据每个标记在语料库中的频率确定的单语模型。

        语料库中的每个单词都有一个分数,损失则是这些分数的负对数似然——即语料库中所有单词的 -log(P(单词)) 的总和。

        回到以下示例语料库:

        ("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5)

        每个单词的分词及其相应的分数为:

"hug": ["hug"] (分数 0.071428)
"pug": ["pu", "g"] (分数 0.007710)
"pun": ["pu", "n"] (分数 0.006168)
"bun": ["bu", "n"] (分数 0.001451)
"hugs": ["hug", "s"] (分数 0.001701)

        因此,损失为:

10 * (-log(0.071428)) + 5 * (-log(0.007710)) + 12 * (-log(0.006168)) + 4 * (-log(0.001451)) + 5 * (-log(0.001701)) = 169.8

        现在需要计算每个标记的移除如何影响损失。为了简化,只为两个标记进行计算,并将整个过程留到有代码帮助时再进行。在这个特殊的情况下,有两个等价的标记化:例如,"pug" 可以标记为 ["p", "ug"],并具有相同的分数。因此,从词汇表中移除 "pu" 将产生相同的损失。

        另一方面,移除 "hug" 将导致损失增加,因为 "hug" 和 "hugs" 的标记化将变为:

"hug": ["hu", "g"] (分数 0.006802)
"hugs": ["hu", "gs"] (分数 0.001701)

        这些变化将导致损失上升:

10 * (-log(0.071428)) + 10 * (-log(0.006802)) = 23.5

        因此,标记 "pu" 可能会从词汇表中移除,但 "hug" 则不会。

3. 代码实现

        依然沿用在BPE中的语料,在jupyter环境进行测试。本来我们验证的预训练模型为xlnet-base-cased,但model scope没有对应的,所以我们更换成T5,效果是一样的,因为使用的分词器是一样的。

corpus = ["This is the Hugging Face Course.","This chapter is about tokenization.","This section shows several tokenizer algorithms.","Hopefully, you will be able to understand how they are trained and generate tokens.",
]

同样,下载和加载T5预训练模型:

import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
from transformers import AutoTokenizermodel_dir = snapshot_download('AI-ModelScope/t5-base', cache_dir='/root/autodl-tmp', revision='master')
mode_name_or_path = '/root/autodl-tmp/AI-ModelScope/t5-base'
tokenizer = AutoTokenizer.from_pretrained(mode_name_or_path, trust_remote_code=True)

统计预分词的词频:

from collections import defaultdictword_freqs = defaultdict(int)
for text in corpus:words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text)new_words = [word for word, offset in words_with_offsets]for word in new_words:word_freqs[word] += 1word_freqs

        接下来,需要将词汇初始化为一个比我们最终希望的词汇量更大的值。必须包含所有基本字符(否则将无法标记每个单词),但对于较大的子字符串,将仅保留最常见的,因此按频率对它们进行排序:        

char_freqs = defaultdict(int)
subwords_freqs = defaultdict(int)
for word, freq in word_freqs.items():for i in range(len(word)):char_freqs[word[i]] += freq# 循环遍历至少长度为2的子单词for j in range(i + 2, len(word) + 1):subwords_freqs[word[i:j]] += freq# 按频率对子单词进行排序
sorted_subwords = sorted(subwords_freqs.items(), key=lambda x: x[1], reverse=True)
sorted_subwords[:10]
 

        将字符与最佳子单词分组,以达到初始词汇大小 300:

token_freqs = list(char_freqs.items()) + sorted_subwords[: 300 - len(char_freqs)]
token_freqs = {token: freq for token, freq in token_freqs}

        接下来,计算所有频率的总和,将频率转换为概率。对于我们的模型,将存储概率的对数,因为将对数相加比乘以小数字更数值稳定,并且这将简化模型损失的计算:

from math import logtotal_sum = sum([freq for token, freq in token_freqs.items()])
model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()}

        现在,主要函数是使用维特比算法进行单词标记化。如前所述,该算法计算每个子字符串的最佳分段,将其存储在名为 best_segmentations 的变量中。为单词中的每个位置(从 0 到单词的总长度)存储一个字典,包含两个键:最佳分段中最后一个标记的起始索引,以及最佳分段的分数。通过最后一个标记的起始索引,将能够在列表完全填充后检索完整的分段。

        填充列表只需两个循环:主循环遍历每个起始位置,第二个循环尝试从该起始位置开始的所有子字符串。如果子字符串在词汇中,我们就得到了到该结束位置的单词的新分段,将其与 best_segmentations 中的内容进行比较。一旦主循环完成,只需从末尾开始,跳过一个起始位置,记录标记,直到到达单词的起始位置:        

def encode_word(word, model):best_segmentations = [{"start": 0, "score": 1}] + [{"start": None, "score": None} for _ in range(len(word))]for start_idx in range(len(word)):# This should be properly filled by the previous steps of the loopbest_score_at_start = best_segmentations[start_idx]["score"]for end_idx in range(start_idx + 1, len(word) + 1):token = word[start_idx:end_idx]if token in model and best_score_at_start is not None:score = model[token] + best_score_at_start# If we have found a better segmentation ending at end_idx, we updateif (best_segmentations[end_idx]["score"] is Noneor best_segmentations[end_idx]["score"] > score):best_segmentations[end_idx] = {"start": start_idx, "score": score}segmentation = best_segmentations[-1]if segmentation["score"] is None:# We did not find a tokenization of the word -> unknownreturn ["<unk>"], Nonescore = segmentation["score"]start = segmentation["start"]end = len(word)tokens = []while start != 0:tokens.insert(0, word[start:end])next_start = best_segmentations[start]["start"]end = startstart = next_starttokens.insert(0, word[start:end])return tokens, score

在一些单词上尝试下初始模型:

        

计算模型在语料库上的损失:

def compute_loss(model):loss = 0for word, freq in word_freqs.items():_, word_loss = encode_word(word, model)loss += freq * word_lossreturn loss

计算删除每个标记后模型的损失:

import copydef compute_scores(model):scores = {}model_loss = compute_loss(model)for token, score in model.items():# 始终保留长度为1的标记if len(token) == 1:continuemodel_without_token = copy.deepcopy(model)_ = model_without_token.pop(token)scores[token] = compute_loss(model_without_token) - model_lossreturn scores

        由于 "ll" 用于 "Hopefully" 的标记化,移除它可能会导致使用标记 "l" 两次,因此预期它会产生正损失。

        这种方法效率非常低,因此 SentencePiece 使用了一个近似的模型损失计算:它并不是从头开始,而是用剩余词汇中标记 X 的分割替换标记 X。这样,所有分数可以在计算模型损失的同时一次性计算出来。在此基础上,需要做的最后一件事是将模型使用的特殊标记添加到词汇表中,然后循环直到我们从词汇表中修剪出足够的标记以达到所需大小:

percent_to_remove = 0.1
while len(model) > 100:scores = compute_scores(model)sorted_scores = sorted(scores.items(), key=lambda x: x[1])# 移除具有最低分数的 percent_to_remove 标记。for i in range(int(len(model) * percent_to_remove)):_ = token_freqs.pop(sorted_scores[i][0])total_sum = sum([freq for token, freq in token_freqs.items()])model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()}

        然后,为了对一些文本进行标记化,只需应用预标记化,然后使用 encode_word() 函数:

def tokenize(text, model):words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text)pre_tokenized_text = [word for word, offset in words_with_offsets]encoded_words = [encode_word(word, model)[0] for word in pre_tokenized_text]return sum(encoded_words, [])tokenize("This is the amazing course.", model)

4. 参考材料

【1】Unigram tokenization

相关文章:

【大模型实战篇】大模型分词算法Unigram及代码示例

1. 算法原理介绍 与 BPE 分词&#xff08;参考《BPE原理及代码示例》&#xff09;和 WordPiece 分词&#xff08;参考《WordPiece原理及代码示例》&#xff09;不同&#xff0c;Unigram 分词方法【1】是从一个包含足够多字符串或词元的初始集合开始&#xff0c;迭代地删除其中的…...

Dockerfile搭建ELK

使用 Dockerfile 安装 ELK 一、引言 ELK Stack&#xff08;Elasticsearch, Logstash, Kibana&#xff09;是一种流行的日志管理和分析解决方案。它允许用户实时搜索、分析和可视化日志数据。通过 Docker&#xff0c;可以方便地部署 ELK &#xff0c;快速获取一个功能齐全的日…...

在合规的地方怎么用EACO地球链兑换交换价值?

地球链EACO&#xff08;EarthChain&#xff0c;简称$E&#xff09;是一种虚拟数字资产。 目前在中国大陆&#xff0c;虚拟资产相关业务活动属于金融活动&#xff0c;包括虚拟资产的交易、兑换等操作&#xff0c;因此应该谨慎去寻求如何用它来交换价值。 虚拟资产交易炒作活动&…...

VS无法安装Win10SDK_10.0.2200,快捷方法

Visual Studio无法安装Win10SDK_10.0.2200&#xff0c;我在安装VS2019、2022提示&#xff0c;软件就不能编译。 因为之前安装过VS软件&#xff0c;重新安装软件提示“无法安装”。 原因 之前安装在D盘&#xff0c;现在没有D盘了 说明 因为电脑第一次安装VS&#xff0c;会自动安…...

github多个账号配置多个SSH秘钥

背景 对于有多个github账号的同学&#xff0c;需要配置多个ssh秘钥分别管理多个账号。 方法 1、生成多个SSH秘钥 # 为第一个 GitHub 账号生成密钥 ssh-keygen -t ed25519 -C "your_email_1example.com" -f ~/.ssh/id_ed25519_github_work# 为第二个 GitHub 账号生…...

静态/动态代理详解,一次性看完再也不会搞不清!

代理官方原文翻译&#xff1a; 给其他对象提供一个代理或者占位符&#xff0c;来控制对这个对象的访问。 代理最核心的思想&#xff1a; 在客户端和目标对象之间创建一个“中介”&#xff0c;用于保护目标对象和增强目标对象 静态代理&#xff1a; 该代理对象需要我们手动…...

Webserver(2)GCC

目录 安装GCCVScode远程连接到虚拟机编写代码gcc编译过程gcc与g的区别Xftp连接虚拟机上传文件 安装GCC sudo apt install gcc g查看版本是7.5 touch test.c创建代码 但是在虚拟机中写代码很不方便 VScode远程连接到虚拟机编写代码 gcc test.c -o app在虚拟机中用gcc编译的…...

mac电脑设置chrome浏览器语言切换为日语英语等不生效问题

在chrome中设置了语言&#xff0c;并且已经置顶了&#xff0c;但是不生效&#xff0c;在windows上直接有设置当前语言为chrome显示语言&#xff0c;但是mac上没有。 解决办法 在系统里面有一个单独给chrome设置语言的&#xff1a; 单独给它设定成指定的语言&#xff0c;然后重…...

Python中的人工智能框架与实例

在人工智能(AI)领域&#xff0c;Python因其简洁的语法、丰富的库和强大的社区支持&#xff0c;成为了最受欢迎的编程语言之一。本文将详细介绍Python中的人工智能框架&#xff0c;并通过具体实例展示如何使用这些框架来实现不同的人工智能应用。 一、Python中的人工智能框架 …...

论文阅读(二十六):Dual Attention Network for Scene Segmentation

文章目录 1.Introduction3.DANet3.1Position Attention Module3.2Channel Attention Module 论文&#xff1a;Dual Attention Network for Scene Segmentation   论文链接&#xff1a;Dual Attention Network for Scene Segmentation   代码链接&#xff1a;Github 1.Intr…...

Stack和Queue(3)

Stack和Queue&#xff08;3&#xff09; priority_queue的模拟实现 priority_queue.h #include <vector>namespace soobin {template<class T, class Container vector<T>>class priority_queue{public://强制生成默认构造priority_queue() default;temp…...

怎样把学生的成绩单独告知家长?

期中考试季的到来让校园里的气氛似乎也变得紧张起来。家长们开始频繁地联系老师&#xff0c;希望了解孩子的表现&#xff1b;孩子们则在考试后&#xff0c;绞尽脑汁地想出各种理由&#xff0c;以期在成绩不理想时能减轻家长的失望。老师们更是忙得不可开交&#xff0c;不仅要批…...

vue3父组件控制子组件表单验证及获取子组件数值方法

1、关键部分的代码如下&#xff0c;我努力交代清楚了&#xff0c;希望能让大家看懂。 <template><KeepAlive><component ref"comp" :is"compNames[steps[compIndex].comp]" /></KeepAlive><el-button click"prevBtn"…...

【JavaEE】【多线程】单例模式

目录 一、设计模式1.1 单例模式1.1.1 饿汉模式1.1.2 懒汉模式 1.2 线程安全问题1.3 懒汉模式线程安全问题的解决方法1.3.1 原子性问题解决1.3.2 解决效率问题1.3.3 解决内存可见性问题和指令重排序问题 一、设计模式 在讲解案例前&#xff0c;先介绍一个概念设计模式&#xff…...

Java.6--多态-设计模式-抽象父类-抽象方法

一、多态 1.定义--什么是多态&#xff1f; a.同一个父类的不同子类对象&#xff0c;在做同一行为的时候&#xff0c;有不同的表现形式&#xff0c;这就是多态。&#xff08;总结为&#xff1a;一个父类下的不同子类&#xff0c;同一行为&#xff0c;不同表现形式。&#xff0…...

JAVA Maven 的安装与配置

一、下载地址 官方网站&#xff1a;Maven – Download Apache Maven 我这里是3.8.6版本 二、安装步骤 maven安装之前要先安装jdk&#xff0c;请确保你的系统已经安装了jdk环境。 1.将下载好的 Maven 进行解压 apache-maven-3.6.8-bin.zip 2.配置本地仓库:修改 conf/settin…...

【程序分享】PCB元件坐标对齐工具 V1.3

↑↑↑点击上方蓝字&#xff0c;关注我们&#xff01; “PCB元件坐标对齐工具 V1.3”脚本程序在PCB文档中将元件的坐标自动移动到参考圆弧的中心&#xff0c;参考圆弧支持机械层1层和禁止布线层&#xff0c;参考图元的位置任意&#xff0c;不局限于栅格位置。 程序会自动…...

[bug] vllm 0.6.1 RuntimeError: operator torchvision::nms does not exist

[bug] vllm 0.6.1 RuntimeError: operator torchvision::nms does not exist 环境 python 3.10 torch 2.4.0cu118 torchvision 0.19.0cu118 vllm 0.6.1.post2cu118问题详情 if torch._C._d…...

处理Hutool的Http工具上传大文件报OOM

程序环境 JDK版本&#xff1a; 1.8Hutool版本&#xff1a; 5.8.25 问题描述 客服端文件上传主要代码&#xff1a; HttpRequest httpRequest HttpUtil.createPost(FILE_UPLOAD_URL); Resource urlResource new UrlResource(url, fileName); httpRequest.form("file&q…...

transforms的使用

示例代码 from PIL import Image from torch.utils.tensorboard import SummaryWriter from torchvision import transforms#打开该图片 img_path"hymenoptera_data/val/bees/10870992_eebeeb3a12.jpg" imgImage.open(img_path) writerSummaryWriter("logs&quo…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...