admin

  • 对于非 NLP 专业的人来说,要向理解大语言模型的基础其实是非常不容易的。在有了一定的神经网络基础、数学基础之后,算是可以更进一步了,在了解LLM的系列中,大概可以分成几个部分:输入(即本文的tokenize)、计算(Attention)、输出(beam search/top-k)。在本篇中:(a) 通过代码实践观察大模型(GPT2)如何进行 tokenize;(b) 如何查看 token id 列表 (c) 观察模型中所有token的 Embedding Matrix。

    这是我的大语言(LLM)学习系列中的一篇,完整的学习路径参考:我的大模型学习路线

    1. 理解 tokenize

    1.1 Token ID

    这里我们使用如下的提示词,来看看大模型是如何处理的:It’s very hot in summer. Swimming is

    大模型会使用预先设计好的“tokenize”实现,将上述的句子分解成独立的“Token”,并转换为对应的“Token ID”,而每个Token,都有自己的编码,也就是 Embedding ,这些 Embedding 就最终作为大语言模型的输入。

    对于上述的句子,“openai-community/gpt2” 在进行 tokenize 之后对应的 Token 和 Token ID 如下:

    itsveryhotinsummer . Swimmingis
    Token ID1026447247 82 84530242873931 13 245127428318
    TokenItâĢĻsĠveryĠhotĠinĠsummer.ĠSwimmingĠis

    “openai-community/gpt2” 使用了较为常见的BPE(Byte Pair Encoding)对句子进行处理,把每个词语按照“subword”进行处理,例如:

    • “Swimming”拆分为“Sw”与“imming”
    • 这里两个 Token 447、247 组成特殊字符 ‘ (撇号)
    • Ġ(U+0120)的作用:表示这是一个新的词语(而不是一个拆分后子词),可以看到 “Swimming”在拆分后的“imming”前面并没有Ġ,表示这是一个拆分后的子词

    1.2 词表大小

    “openai-community/gpt2” 模型的词表大小为:50257。词表中的前三个 Token 为 ’emb’、 ‘ĠDraft’、 ‘Ġreinvent’,对应的 Token ID 为 24419、 13650、 36608。

    1.3 根据 Token ID 打印字符

    这里打印了 Token ID 为 0、 1、 2 和 50254、 50255、 50256 的几个字符如下:

    Token IDChar
    0!
    1
    2#
    50254Ġinformants
    50255Ġgazed
    50256<|endoftext|>
    --- Token ID 转换为 Token 字符 ---
    Token ID: 0 | 对应 Token 字符: '!'
    Token ID: 1 | 对应 Token 字符: '"'
    Token ID: 2 | 对应 Token 字符: '#'
    Token ID: 50254 | 对应 Token 字符: 'Ġinformants'
    Token ID: 50255 | 对应 Token 字符: 'Ġgazed'
    Token ID: 50256 | 对应 Token 字符: '<|endoftext|>'

    2. Token Embedding

    在大模型的通常是从 Embedding 开始的,即对于所有字符的处理,都是依赖字符对应的“向量”。所以,大致的处理逻辑是这样:一个句子,先切分为 Token,然后根据 Token ID 在“Embedding Matrix”中找到对应的“向量”,把该“向量”组作为输入。

    这里,我们观察上述示例句子,根据对应的 Token ID 可以查询到对应的向量。因为这里的向量是768维的,这里仅显示前三个维度的分量,如下:

    Token      | wte[:3]                         |
    ----------------------------------------------
    It | [0.039, -0.0869, 0.0662 ,...] |
    âĢ | [-0.075, 0.0948, -0.0034,...] |
    Ļ | [-0.0223, 0.0182, 0.2631 ,...] |
    s | [-0.064, -0.0469, 0.2061 ,...] |
    Ġvery | [-0.0553, -0.0348, 0.0606 ,...] |
    Ġhot | [0.0399, -0.0053, 0.0742 ,...] |
    Ġin | [-0.0337, 0.0108, 0.0293 ,...] |
    Ġsummer | [0.0422, 0.0138, -0.0213,...] |
    . | [0.0466, -0.0113, 0.0283 ,...] |
    ĠSw | [0.0617, 0.0373, 0.1018 ,...] |
    imming | [-0.1385, -0.1774, -0.0181,...] |
    Ġis | [-0.0097, 0.0101, 0.0556 ,...] |

    更为完整的,上述的每个词语对应的向量是一个 1×768 的向量;整个句子 12 个向量,可以理解为一个 12×768 的输入矩阵。对于各 LLM 来说,这通常就是其将要处理的输入。

    3. Positional encoding

    在“GPT-2”使用了“Learned Positional Embeddings”(注:与 Transformer 论文中固定的Sinusoidal 实现不同)。这是一个 \(L \times d \) 的矩阵,其中,\(L \) 是最大接收字符数,\(d \) 是 Token Embedding 的维度。该矩阵通常随机初始化,最终通过训练确定。在“GPT-2”中,最终训练后的矩阵有如下形式:

    pos_emb_layer = model.transformer.wpe
    
    # .weight.data : Embedding Matrix(PyTorch Tensor)
    pos_emb_matrix = pos_emb_layer.weight.data
    
    print(pos_emb_matrix[:12,:3])

    输入如下:

    tensor([[-0.0188, -0.1974,  0.0040],
            [ 0.0240, -0.0538, -0.0949],
            [ 0.0042, -0.0848,  0.0545],
            [-0.0003, -0.0738,  0.1055],
            [ 0.0076, -0.0251,  0.1270],
            [ 0.0096, -0.0339,  0.1312],
            [ 0.0027, -0.0205,  0.1196],
            [ 0.0025, -0.0032,  0.1174],
            [-0.0012, -0.0018,  0.1110],
            [ 0.0049,  0.0021,  0.1178],
            [ 0.0016,  0.0062,  0.1004],
            [-0.0036,  0.0175,  0.1068]])

    示例与代码

    环境准备

    !pip install transformers torch
    
    from transformers import AutoTokenizer, AutoModelForCausalLM
    
    MODEL_NAME = "openai-community/gpt2"
    tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
    model = AutoModelForCausalLM.from_pretrained(MODEL_NAME)

    对句子进行 tokenize

    观察句子的tokenize:

    text = "It’s very hot in summer. Swimming is"
    
    # 1. 对句子进行 Tokenization
    # return_tensors='pt' 表示返回 PyTorch Tensor 格式 (虽然这里我们主要看 IDs)
    inputs = tokenizer(text, return_tensors='pt')
    
    # 2. 打印 Tokenization 结果
    print(f"--- 原始句子:{text} ---")
    
    # a. 打印 Token ID Tensor
    print("Token IDs (Tensor):")
    print(inputs['input_ids'])
    
    # b. 将 Token ID 转换回可读的 Token (Word Pieces)
    # .squeeze() 是为了去除 batch 维度
    tokens = tokenizer.convert_ids_to_tokens(inputs['input_ids'].squeeze().tolist())
    print("\nToken List (可读文本 Tokens):")
    print(tokens)
    
    # c. 打印 Attention Mask (1 表示是有效 Token,0 表示是 Padding Token)
    print("\nAttention Mask:")
    print(inputs['attention_mask'])
    
    --------------
    --- output ---
    --------------
    
    --- 原始句子:It’s very hot in summer. Swimming is ---
    Token IDs (Tensor):
    tensor([[ 1026,   447,   247,    82,   845,  3024,   287,  3931,    13,  2451,
             27428,   318]])
    
    Token List (可读文本 Tokens):
    ['It', 'âĢ', 'Ļ', 's', 'Ġvery', 'Ġhot', 'Ġin', 'Ġsummer', '.', 'ĠSw', 'imming', 'Ġis']
    
    Attention Mask:
    tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])

    词表大小查看

    查看词表大小,并打印词表中的前20个词:

    # 获取词汇表大小
    vocab_size = tokenizer.vocab_size
    print(f"--- GPT-2 模型支持的 Tokenize 总数 (词汇表大小): {vocab_size} ---")
    
    # 打印所有 Tokenize
    # tokenizer.get_vocab() 返回的是一个字典 {token: id}
    print("\n--- 打印前 20 个 Token (用于示例): ---")
    vocab = tokenizer.get_vocab()
    count = 0
    for token, id in vocab.items():
        if count < 20:
            # 使用 repr() 确保特殊字符(如空格 'Ġ')能被清晰展示
            print(f"ID: {id:<5} | Token: {repr(token)}")
            count += 1
        else:
            break
    
    --------------
    --- output ---
    --------------
    
    --- GPT-2 模型支持的 Tokenize 总数 (词汇表大小): 50257 ---
    
    --- 打印前 20 个 Token (用于示例): ---
    ID: 24419 | Token: 'emb'
    ID: 13650 | Token: 'ĠDraft'
    ID: 36608 | Token: 'Ġreinvent'
    ID: 36171 | Token: 'Recommended'
    ID: 20706 | Token: 'aunting'
    ID: 39558 | Token: 'Ġprotagonists'
    ID: 49309 | Token: 'raised'
    ID: 20589 | Token: 'Ġwicked'
    ID: 43074 | Token: 'ĠâĿ'
    ID: 22792 | Token: 'ĠTut'
    ID: 21620 | Token: 'erate'
    ...

    根据 Token ID 打印字符

    # 待查询的 Token ID 列表
    target_ids = [0, 1, 2, 50254 ,50255, 50256]
    
    tokens = tokenizer.convert_ids_to_tokens(target_ids)
    
    print(f"--- Token ID 转换为 Token 字符 ---")
    for id, token in zip(target_ids, tokens):
        # 使用 repr() 确保任何特殊的不可见字符(如空格或控制字符)能被清晰地展示
        print(f"Token ID: {id:<5} | 对应 Token 字符: {repr(token)}")
    
    # 额外打印这几个 Token 在词汇表中的 ID,以确认其对应关系
    # 这里的 token.id 并不是直接从 1, 2, 3 来的,而是从 tokenizer.get_vocab() 中查到的
    # 这是一个辅助验证步骤,确保 Tokenizer 的行为符合预期。
    print("\n--- 辅助验证 ---")
    for token in tokens:
        token_id_check = tokenizer.convert_tokens_to_ids(token)
        print(f"Token 字符: {repr(token):<10} | 查验 ID: {token_id_check}")
    
    --------------
    --- output ---
    --------------
    
    --- Token ID 转换为 Token 字符 ---
    Token ID: 0     | 对应 Token 字符: '!'
    Token ID: 1     | 对应 Token 字符: '"'
    Token ID: 2     | 对应 Token 字符: '#'
    Token ID: 50254 | 对应 Token 字符: 'Ġinformants'
    Token ID: 50255 | 对应 Token 字符: 'Ġgazed'
    Token ID: 50256 | 对应 Token 字符: '<|endoftext|>'

    根据 Token ID 查询对应向量

    在模型中,“词向量”(准确的应该是Token向量)存储在一个Embedding Matrix 中,可以使用如下的代码获取每个 token 对应 Embedding 后的向量:

    target_token = "ĠSw"  # 注意前面的特殊符号,确保它是模型词汇表中的 Token
    target_id = tokenizer.convert_tokens_to_ids(target_token)
    print(target_id)
    
    # embedding_matrix[target_id]
    target_embedding = embedding_matrix[target_id]
    print(target_embedding[:5].numpy())
    
    --------------
    --- output ---
    --------------
    
    2451
    [ 0.06167513  0.03733223  0.10182938  0.04881619 -0.09597597]
    Embedding 层的 dtype: torch.float32
    整个模型的默认 dtype: torch.float32

    句子到 Embedding 向量

    text = "It’s very hot in summer. Swimming is"
    inputs = tokenizer(text, return_tensors='pt')
    print("Token IDs (Tensor):")
    input_ids_tensor = inputs['input_ids']
    input_ids_list = input_ids_tensor.squeeze().tolist()
    
    for index, token_int in enumerate(input_ids_list):
        token_char = tokenizer.convert_ids_to_tokens(token_int)
        print(f"Token ID {token_int:<5} | Token: {repr(token_char):<9} | {embedding_matrix[token_int][:3]}")
    
    --------------
    --- output ---
    --------------
    
    Token ID 1026  | Token: 'It'      | tensor([ 0.0390, -0.0869,  0.0662])
    Token ID 447   | Token: 'âĢ'      | tensor([-0.0750,  0.0948, -0.0034])
    Token ID 247   | Token: 'Ļ'       | tensor([-0.0223,  0.0182,  0.2631])
    Token ID 82    | Token: 's'       | tensor([-0.0640, -0.0469,  0.2061])
    Token ID 845   | Token: 'Ġvery'   | tensor([-0.0553, -0.0348,  0.0606])
    Token ID 3024  | Token: 'Ġhot'    | tensor([ 0.0399, -0.0053,  0.0742])
    Token ID 287   | Token: 'Ġin'     | tensor([-0.0337,  0.0108,  0.0293])
    Token ID 3931  | Token: 'Ġsummer' | tensor([ 0.0422,  0.0138, -0.0213])
    Token ID 13    | Token: '.'       | tensor([ 0.0466, -0.0113,  0.0283])
    Token ID 2451  | Token: 'ĠSw'     | tensor([0.0617, 0.0373, 0.1018])
    Token ID 27428 | Token: 'imming'  | tensor([-0.1385, -0.1774, -0.0181])
    Token ID 318   | Token: 'Ġis'     | tensor([-0.0097,  0.0101,  0.0556])
    

    Embedding Matrix

    查看 Embedding Matrix

    # model.transformer.wte (Word Token Embeddings)
    embedding_layer = model.transformer.wte
    
    # .weight.data : Embedding Matrix(PyTorch Tensor)
    embedding_matrix = embedding_layer.weight.data
    
    print(embedding_matrix.shape)
    
    --------------
    --- output ---
    --------------
    
    torch.Size([50257, 768])

    最后

    大模型训练的第一步就是对于语料库(corpus)的处理,即将所有的语料转换为大模型训练能够接受的输入,即:tokenize。该过程会将语料库切分为独立的句子,多个句子可以作为一个批次(batch)作为输入进行训练。

  • 整体上,今年的魔力象限与去年的厂商完全相同,各厂商的相对位置变化也并不是很大。一些值得注意的点如下:

    • Redis 从 Visionaries 跌到 Niche Player 象限;这反应了 Redis 在社区所面临的困境,一方面是开源商业化的挑战;另一方,则是来自于 Valkey 社区–一个更加开放的 Key-Value 产品的竞争。
    • Neo4j 也从 Visionaries 跌到 Niche Player 象限。
    • 在第一军团(即Google AWS Microsoft Oracle)中,Oracle 位置略有下降。确实,Oracle 早就已经不再是一家数据库厂商了。
    • Databricks 和 Snowflake 凭借在数据处理上的领先,在横坐标(Visionaries)上前进了一大截
    • 此外,虽然没有在象限图中(仅前20的厂商),但依旧在Gartner关注对象中的厂商包括:Actian Broadcom ClickHouse InfluxData MotherDuck OceanBase PingCAP Tencent Cloud TigerGraph Yugabyte

    象限中的中国数据库厂商

    进入这次魔力象限的中国厂商与去年相同:阿里云数据库、华为云数据库。相比去年,两个厂商的位置变化也不太大,可以参考右图。

    阿里云数据库在 Vision 象限继续向前移动了一点。华为云则保持了相对位置几乎不变。

    此外,出现在“Honorable Mentions”部分的中国厂商有:

    • OceanBase
    • PingCAP
    • Tencent Cloud

    历史魔力象限列表

    2025-11

    其他

    作者最近几年持续对 Gartner 云数据库魔力象限保持关注,历史相关文章包括:

  • 标题:IBM $110亿收购Confluent; Gartner 云数据库魔力象限发布;AWS/阿里云支持PG18

    重要更新

    IBM 110亿美元收购数据流厂商 Confluent[1],该公司创建于2014年,最初致力于 Apache Kafka 的商业化,逐步扩展为完整的实时数据流平台。

    Gartner 2025云数据库魔力象限发布[2],阿里云依旧处于 Leaders 象限、华为云在 Challengers 象限。Redis、Neo4j从 Visionaries 象限落入 Niche Players。

    更新详情

    阿里云
    • RDS PostgreSQL新增支持PostgreSQL 18大版本。[16]
    • RDS SQL Server正式发布SQL Server 2025 企业集群版、SQL Server 2025 标准版。[21]
    火山云(字节)
    • SQL Server 按量计费实例支持暂停实例功能。实例暂停后,实例节点规格产生的费用将暂停计费,但使用存储空间的所产生的费用将持续计费[93]
    • 文档数据库 MongoDB 版新增支持查看事务平均响应时间、命令平均响应时间和写冲突次数等监控指标[95]
    • HBase 新增实例级别和 RegionServer 级别 Get、Scan、Put、BatchPut 请求的 QPS 和延迟监控指标[96]
    • 表格数据库 HBase 版支持为已开通容量型存储的实例申请冷存储桶路径,可直接将 HFile Bulkload 至对应冷存桶中[98]
    • 数据库工作台 DBW 支持为云数据库 MySQL 版、云数据库 veDB MySQL版、云数据库 PostgreSQL 版等类型的实例发起手动巡检、开启/关闭自动巡检,以及为开启安全管控的实例创建 SQL 审核工单。[101]
    • DBW 支持在 PostgreSQL 数据库的 SQL 数据交互台中导出 SQL 执行结果集,支持将当前页、所有页或选中的数据导出为 excel、csv、text 、JSON 和 insert SQL 格式的文件。[103]
    • DBW 对外开放 ExecuteSQL、ListDatabases、ListTables 和 GetTableInfo 接口,可以用来执行 SQL 语句,或查询数据库列表,所有表、或表元信息。[104]
    • DBW-在数据库工作台 DBW 中,SQL 助手与数据库智能助手(DBCopilot)合二为一,即在 SQL 窗口、观测诊断和导航栏 DB 智能助手中进入的会话中功能完全一样[105]
    Azure(微软云)
    • 将 Azure SRE 代理与 Azure Cosmos DB 结合使用 [26]
    GCP(谷歌云)
    • BigQuery 数据传输服务现在可以将数据从 Oracle 传输数据[29]
    • Cloud SQL for SQL Server 与 Microsoft Entra ID 集成[34]
    • AlloyDB 现已支持 C4 系列实例(Intel Granite Rapids 处理器),最高可达 288 个虚拟 CPU 和 2232 GiB 内存[35]
    • Oracle Database@Google Cloud 支持 us-central1(爱荷华州,北美)等区域 [38]
    • 您现在可以使用 BigQuery 远程 MCP 服务器[39]
    • 您可以使用 Gemini 来修复 AlloyDB Studio 查询编辑器中的查询错误[43]
    Oracle云
    • Autonomous AI Database API for DynamoDB 发布 [46]
    百度云
    • GaiaDB 支持设置SSL加密[48]
    • GaiaDB 支持暂停、启动GaiaDB集群[49]
    • GaiaDB支持暂停、启动、重启代理实例[50]
    华为云
    • GeminiDB 兼容DynamoDB接口支持按请求计费多租Serverless[62]
    • GeminiDB Redis接口性能版支持慢日志管理[63]
    • GeminiDB Cassandra接口云原生模式支持删除节点[64]
    • DDS实例鲲鹏CPU新增规格[65]
    • DDS支持容量预估[66]
    AWS(亚马逊云)
    • RDS 扩展支持版本 5.7.44-RDS.20251212 [67]
    • EC2 M8gn 和 M8gb 实例GA [68]
    • AWS 数据库现已在 Vercel Marketplace 上架[69]
    • RDS 数据库预览环境中支持 PostgreSQL 18.1[70]
    • Redshift Serverless 宣布正式推出支持 IPv6 的双栈模式[74]
    • Aurora DSQL 现在支持在几秒钟内创建集群[81]
    • Aurora PostgreSQL 现在支持与 Kiro powers(MCP)集成[82]
    • ElastiCache Serverless 现在支持 same-slot WATCH 命令[84]
    腾讯云
    • 云数据库 MySQL 发布数据库代理版本1.4.6。[87]
    • TDSQL-C MySQL 版发布数据库代理版本1.3.20和1.4.6。[88]
    • TDSQL-C MySQL 版于2025年12月16日起,优化了跨可用区部署功能:在集群出现故障的场景,当开启了跨可用区部署功能的集群本地切换失败后且集群90秒不可用时,集群将会自动进行跨可用区切换,请您及时关注集群运行状态。[89]
    • TDSQL-C MySQL 版发布了编译优化高性能版本的性能白皮书[90]
    • TDSQL-C MySQL 版发布了新版性能白皮书,其针对 MySQL 8.0版本刷新了在全缓存、大数据集场景下的不同规格的性能测试数据,为对性能有严苛要求的企业级场景提供了更可靠的数据库选择。[91]
    • 云数据库 SQL Server 云盘架构的单节点、双节点、RO 实例新增支持:北京金融一区、北京金融二区、利雅得一区、利雅得二区。[92]

    参考链接

  • DiskANN 是较为常见的向量数据库搜索算法,作者通过“贪婪搜索”和“健壮性剪枝”(“RobustPrune”)来构建一个“低直径”的图,从而实现高性能的向量搜索。这里的“低直径”很好的保障了点与点之间非常高效(只需要少数几条)完成搜索。“RobustPrune”则是构建低直径的“Vamana”图的关键步骤。本文通过计算推导、示例与试验的方式,来看看“RobustPrune”如何实现“低直径”图的构建,而这也正是 DiskANN 算法的核心之一。

    1. RobustPrune 概述

    论文中的原始描述如右图。

    可以这样理解:在找到 \(p \) 的若干“邻居”后(邻居集合记为 \(N_{out}(p) \) ),由于“边”(出度)数量有限(这里是 \(R \) ),故需要进行“剪枝”,那么这里的“剪枝”方法即为“RobustPrune”:

    • 在 \(N_{out}(p) \) 中找出距离 \(p \) 最近的点,记为 \(p^{*} \)
    • 需要“剪枝”时,将满足下列条件的点都“剪掉”:
      • \(\alpha \cdot d(p^{*},p’) \le d(p,p’) \)

    在初次看到,表达式 \(\alpha \cdot d(p^{*},p’) \le d(p,p’) \) 的时候,是比较难理解其背后的用意的,本文则较为详细以分析、推导、“试验”的方式介绍该公式在图构建过程中所取的效果。

    2. 二维空间的示例

    这里以二维空间为例,以一个具体的场景来观察 RobustPrune 的效果。具体的,将上述的“剪枝”操作描述为如下的数学形式:

    2.1 “剪枝”区域计算

    在二维坐标系中有 \(P = (0,0) \, A = (2,0) \) ,考虑该集合:

    $$
    \mathscr{L} = \{ X | \frac{d(X,P)}{d(X,A)} \le \alpha \quad \text{and} \quad d(X,A) < d(X,P) \} $$

    即,在 RobustPrune 中落入该区域的点,将被剪枝。

    这里 \(\alpha \) 是一个常数,且 \(\alpha \gt 1 \) 。 假设, \(\mathscr{L} \) 中的点 \(X\) 坐标是 \((x,y) \),那么推导 \(x \, y \) 需要满足怎样的限制条件。

    在上述的“数学”问题中,点 \(P = (0,0) \) 即为论文算法中的 \(p \),点 \(A \) 即为论文算法中距离 \(p \) 点最近的邻居 \(p^{*} \)。问题中的 \(x \, y \) 限制提交,即为论文中的“剪枝”条件。

    根据“简单”的数学推导(详细推导可以参考附录,为了连续性这里暂不详述),有如下结果,即坐标 \((x , y) \) 需满足如下条件:

    $$
    (x-\frac{2\alpha^2}{\alpha^2-1})^2 + y^2 \le \frac{4\alpha^2}{(\alpha^2-1)^2}
    $$

    可以看到,这是一个以 \(\frac{2\alpha}{\alpha^2 -1} \) 为半径,以 \((\frac{2\alpha^2}{\alpha^2-1},0) \) 为圆心的圆内部区域(包括边缘)。

    更为具体的,取 \(\alpha = 1.2 \),则在坐标系中,该区域为右图。

    即,当 \(P \) 点、 \(A \) 点确定时,落入右侧图形中阴影部分的点,均会被“剪枝”。

    2.2 实际“剪枝”区域

    更为一般的,如果在平面中任意去一些点,也有类似的结论。其对应的“剪枝圆”(有的地方会称为“遮蔽空间),则有如下的形式:

    考虑右图中, \(A \) 为距离 \(P \) 最近的邻居,那么看看点 \(B \)、\(C \) 是否会被遮蔽。

    与上述推导类似的,可以计算出对应的“剪枝圆”如右图阴影部分,因为 \(C \) 点恰好落在该区域(且又因为邻居数量超过最大出度),故 \(C \) 将被从邻居中删除。

    这就是 RobustPrune 在二维空间的效果。更进一步的,为什么这样进行剪枝就可以保障“低直径”呢?

    3. “剪枝”、不“剪枝”的对比

    为了进一步加深对 RobustPrune 效果的理解,我们考虑这样的问题:在一个 Vamana 图的构建过程中,使用 RobustPrune 进行“剪枝”和不使用该方法剪枝,构建的图会有什么不同?

    在进行正式的试验验证之前,我们有理由这样去考虑:因为“出度” \(R \) 是固定的值,将距离 \(A \) 很近的点从候选邻居中删除,可以避免某些区域邻居过于集中,并将该位置预留给距离 \(P \) 远一些的邻居,这可能会有利于降低图的直径。

    上述理解,即为 RobustPrune 的直觉建立的比较核心的理解。

    为了更好的理解上述内容,并验证上述“直觉”,这里通过程序随机生成30点,并尝试构建 Vamana 图,在构建过程中对比使用 RobustPrune 剪枝和不进行剪枝,看看两种方式构建的图有什么差异。

    3.1 剪枝、不剪枝对比图

    具体的实现程序参考:Vamana Graph.ipynb。程序中,先生成 30 个随机的点,如 Figure 1;然后分别使用带有“剪枝”、没有“剪枝”的算法,生成图,如 Figure 2、Figure3。

    这里可以较为直观的看到,因为这里的“出度” \(R = 3 \) 是固定的,点“3”和点“22”,在剪枝和不剪枝的情况下,两个点之间的距离相差非常大,这也最终导致图的“直径”相差很大。

    4. 拆解 RobustPrune “剪枝”过程

    这里以点“3”,记为 \(P_3 \), 为例,看看RobustPrune “剪枝”是如何进行的。

    首先,在该示例中使用“最近”初始化的方法(而不是随机初始化),即对于每一个点,例如这里的 \(P_3 \) ,初始其“出度”(out degree)候选邻居为距离其最近的10个点,即

    $$ N_{out}(p) = \{ P_{21}\,P_{16}\,P_5 \, P_{22}\, P_0 \, P_{20}\, P_{13}\, P_{12}\, P_8\, P_{23} \} $$

    这里考虑的欧式距离,故最近的点为 \(P_{21} \)。

    4.1 考虑RobustPrune剪枝

    在进行RobustPrune剪枝时,点 \(P_5 \, P_{16} \)处于点\(P_{21} \)的遮蔽区域,故进行剪枝。最终保留了点:\( N_{out}(p) = \{ P_{21} \, P_{22}\, P_0 \} \)

    4.2 不考虑剪枝

    不考虑“剪枝”,又因为这里最大出度\(R=3 \),故保留距离 \(P_3 \) 最近的三个点,则为:\( N_{out}(p) = \{ P_{5} \, P_{16}\, P_{21} \} \)

    4.3 剪枝区域

    在上述的示例中,我们可以绘制考虑 \(P_3 \) 时,取 \(\alpha = 1.2 \)时,剪枝所涉及的遮蔽区域如下,即落到该区域内的点(除了最近的 \(P_{21} \) ),都将被剪枝,如右图。

    并且,因为最大出度 \(R = 3 \),在剩余的点中,再额外选取两个最近的点保留,这里即为:\(\{ P_0 \, P_{22} \} \)。

    所以,经过RobustPrune剪枝,最终 \(\{ P_3 \} \) 保留的“出度”邻居点集为

    $$
    N_{out}(P_3) = \{ P_{21} \, P_{0} \, P_{22} \}
    $$

    可以看到,经过剪枝,在构建 \(P_3 \) 的出度邻居时,在最大出度限制为 \(R=3 \) 时,很好的避免了图邻居的“聚集”,从而最终减低了整个图的直径,就有了上述的最终构建效果:

    5. 最后

    这里给出的示例是二维的,在这个场景下,高维扩展并没有太大的不同。从构建“直觉”的角度,这里给出示例已经足够。对于更高维的场景,如果感兴趣的,可以自己进行推导。

    附录:数学推导

    这里,\(P = (0,0) \, A = (2,0) \),再根据剪枝公式有:

    $$
    \begin{aligned}
    \frac{d(X,P)}{d(X,A)} & \ge \alpha \\
    \frac{\sqrt{x^2+y^2}}{\sqrt{(x-2)^2+y^2}} & \ge \alpha \\
    \frac{x^2+y^2}{(x-2)^2+y^2} & \ge \alpha^2 \\
    x^2+y^2 & \ge \alpha^2((x-2)^2+y^2) \\
    x^2+y^2 & \ge \alpha^2x^2 -4\alpha^2 x + 4\alpha^2 + \alpha^2 y^2 \\
    0 & \ge x^2 – \frac{4\alpha^2 x}{(\alpha^2-1)} + \frac{4\alpha^2}{(\alpha^2-1)} + y^2 \\
    0 & \ge (x- \frac{2\alpha^2}{(\alpha^2-1)})^2 – (\frac{2\alpha^2}{(\alpha^2-1)})^2 + \frac{4\alpha^2}{(\alpha^2-1)} + y^2 \\
    (x- \frac{2\alpha^2}{(\alpha^2-1)})^2 + y^2 & \le (\frac{2\alpha^2}{(\alpha^2-1)})^2 – \frac{4\alpha^2}{(\alpha^2-1)}\\
    (x- \frac{2\alpha^2}{(\alpha^2-1)})^2 + y^2 & \le (\frac{2\alpha}{\alpha^2-1})^2 \quad \blacksquare
    \end{aligned}
    $$

  • This content is password-protected. To view it, please enter the password below.

  • 标题:阿里云/火山引擎MySQL均支持向量索引;PolarDB支持LLM推理PolarKVCache;火山MySQL支持ARM实例

    重要更新

    不约而同,近期火山引擎 MySQL[52]、阿里云 MySQL[10]分别支持向量类型的索引与搜索能力,均使用 HNSW 索引,非常大程度弥补了开源MySQL的弱项。

    阿里云 PolarDB 支持在进行大语言模型(LLM)推理时,提供额外的 PolarKVCache 以加速推理效率。该功能处于内测阶段[11]。从文档描述,提到了可以支持与SGLang、vLLM等集成。

    「第八届中国PostgreSQL数据库生态大会」上周在杭州圆满落幕。在颁奖环节:腾讯OpenTenBase获年度开源影响力奖;IvorySQL获年度产品创新奖;Pigsty获PostgreSQL万磁王奖[2]

    更新详情

    华为云
    • TaurusDB 支持动态脱敏[87]
    • TaurusDB 智能DBA SQL限流支持查询历史规格[88]
    • TaurusDB Serverless支持冷热分离能力[89]
    • TaurusDB 手动备份支持批量删除[90]
    • RDS for MySQL支持8.0.41内核版本。[91]
    • RDS for MySQL支持8.4。[92]
    • RDS for MySQL变更规格可以选择不占用IP。[93]
    • RDS for MySQL支持极速型SSD V2存储类型。[94]
    • RDS for MySQL异常智能诊断增加复制延迟。[95]
    • RDS for SQL Server支持规格变更自动还原。[96]
    • RDS for SQL Server支持搜索指定的数据库和账号名称。[97]
    阿里云
    • RDS MySQL深度集成企业级向量数据处理能力、原生支持最高16,383维向量存储与计算,集成优化的HNSW索引算法提供高性能检索能力,助力知识库检索、语义搜索、推荐系统等AI应用在MySQL生态快速落地。[10]
    • PolarDB 支持在进行大语言模型(LLM)推理时,提供额外的 PolarKVCache 以加速推理效率。该功能处于内测阶段[11]
    • PolarDB 提供兼容“文档数据库”的访问能力,即可通过标准的文档数据库驱动(如Python的pymongo、Node.js的mongoose以及Go的MongoDB驱动等)无缝接入[12]
    • PolarDB 支持 Ray 框架的集成,尝试帮助用户在数据库中直接使用常见的机器学习算法[13]
    Azure(微软云)
    • Database for PostgreSQL Flexible Server 比利时中心正式上线[31]
    • Database for PostgreSQL Flexible Server 中的 pg_squeeze 已更新至 1.9.1 版本[32]
    • Database for PostgreSQL Flexible Server 中的 ip4r 扩展正式上线[33]
    • Database for PostgreSQL Flexible Server 中的 credcheck 扩展正式上线[34]
    • Azure SQL T-SQL 中的正则表达式支持 [35]
    • Azure MCP Server for Azure Database for MySQL 正式上线[36]
    GCP(谷歌云)
    • BigQuery 数据传输服务现在支持增量数据传输[41]
    • Spanner 的默认版本现已设为查询优化器版本 8[47]
    • AlloyDB 现在支持读取池实例的水平自动扩缩容[48]
    Oracle云
    • GoldenGate 功能的增强:ZeroETL pipelines、High availability Cross-region等[49]
    火山云(字节)
    • 云数据库 MySQL 版提供了 FlexPL 云盘和 PL0 的云盘存储类型,最大分别为实例提供 32000 GiB 和 16000 GiB 的存储空间。[51]
    • MySQL-支持构建并使用 ANN 索引对存储的向量进行搜索,即 HNSW 算法构建向量索引。[52]
    • MySQL-允许在执行需要重建表的 DDL 的时候启动多个线程以索引为粒度并行地执行排序、insert 和 flush 操作,充分利用多核优势。[54]
    • 为 MySQL 5.7 引入 INSTANT(即时)算法,对部分 ADD COLUMN 操作,不再修改用户原有数据,只需对表元信息进行修改,从而大幅缩小大表加列所需的时间,减少对系统的影响。[55]
    • MySQL 提供一种配置默认合并阈值的方式,以便用户更灵活地调整 InnoDB 索引的合并阈值,从而在云盘等输入/输出(IO)带宽成为瓶颈的场景下,获得更优的性能。[56]
    • MySQL-支持基于 ARM 架构的产品规格。[64]
    • MySQL-支持 RockDB 的引擎类型。[65]
    • PostgreSQL-支持云盘存储类型,可创建存储类型为 FlexPL 云盘或 PL0 云盘的实例,最大分别支持 32000GB 和 16000GB 的存储空间。[72]
    • open serach-云搜索服务将 DiskANN 算法引入到 OpenSearch 中,实现了性能型和容量型的最优结合,并通过 RaBitQ 量化技术进行更高性能、更低成本的迭代,实现更大数据规模下更低成本的向量存储和检索能力。[75]
    • MongoDB-新增支持在创建 MongoDB 8.0 实例时,直接为实例开启向量索引功能。[81]
    百度云
    • 云数据库 RDS PostgreSQL 支持通用型实例
    • 云数据库 RDS MySQL创建页面重构,增加订单价格明细,方便用户查看不同资源的计费信息。
    AWS(亚马逊云)
    • RDS for SQL Server 支持 Developer Edition[98]
    • Amazon RDS 在数据库预览环境中支持 MySQL 9.5[99]
    • Amazon RDS for SQL Server 推出新一代实例,优化 CPU 使用率,价格最多可降低 55%。[102]
    • 现推出数据库节省计划,最高可节省 35% 的费用[105]
    • Amazon RDS for Oracle 和 SQL Server 现在支持高达 256 TiB 的存储空间,可通过添加额外的存储卷来实现。[107]
    腾讯云
    • 云数据库 MySQL 分析引擎发布了全新的内核版本4.2506.2.0和2.2410.14.0,支持了诸多全新的内核特性,并对系统问题进行了修复和优化。[124]
    • 云数据库 MySQL 8.0内核版本更新20221002、20241009。[125]
    • TDSQL-C MySQL 版数据库代理在调整配置时的切换时间支持选择滚动升级,并支持设置切换的等待时间,您可以根据业务实际情况,设置切换的等待时间以实现更平滑的变配。[126]
    • TDSQL-C MySQL 版分析引擎发布了全新的内核版本4.2506.2.0和2.2410.14.0,支持了诸多全新的内核特性,并对系统问题进行了修复和优化。[127]
    • TDSQL-C MySQL 版实例形态为 Serverless 的集群新增支持了圣保罗、曼谷地域。[128]

    参考链接