Engram 中的多头哈希理解举例

我们以处理句子“DeepSeek improves memory retrieval with Multi-Head Hashing”为例,完整演示多头哈希(Multi-Head Hashing)的具体执行流程。为简化理解,我们设定关键参数:N-gram阶数=2(即提取连续2个Token组成的语义单元)、哈希头数量K=2(并行使用2个独立哈希函数)、嵌入表大小=101(选择质数以优化哈希分布)。

步骤1:上下文压缩(Tokenizer Compression)

首先通过词表规范化合并语义等价Token。

常见误解澄清:词表规范化压缩的是词表的ID空间大小,而非输入Token序列的长度。输入序列长度在此步骤中保持不变

原始词表中,同一语义的不同形态(大小写、形态变体)被分配了不同的ID,造成嵌入表冗余。规范化的目标是将这些语义等价的Token归并到统一ID

原始词表条目原始ID压缩后ID处理说明
DeepSeek102102保留标准形式
improves345345保留标准形式
memory789789保留标准形式
retrieval210210保留标准形式
with567567保留标准形式
Multi-Head432432保留,作为标准形式
multi-head578432归并至432
MULTI-HEAD623432归并至432
Hashing890890保留,作为标准形式
hashing901890归并至890

压缩结果:

  • 词表大小:从原始N个条目压缩至更小的N'个条目
  • 嵌入表冗余条目减少,语义等价Token共享同一嵌入向量
  • 输入Token ID序列长度不变,仍为7个Token:

步骤2:生成2-gram序列

对压缩后的Token序列提取连续2个Token组成的N-gram(2-gram)。对于长度为7的序列,共生成6个2-gram:

  • 2-gram₁:(102, 345)(对应“DeepSeek improves”)
  • 2-gram₂:(345, 789)(对应“improves memory”)
  • 2-gram₃:(789, 210)(对应“memory retrieval”)
  • 2-gram₄:(210, 567)(对应“retrieval with”)
  • 2-gram₅:(567, 890)(对应“with Multi-Head”)
  • 2-gram₆:(890, 432)(对应“Multi-Head Hashing”)

步骤3:多哈希头并行映射(核心步骤)

为每个2-gram分配2个独立哈希头(Hash Head 1和Hash Head 2),分别计算索引并检索嵌入表。

哈希函数定义

两个哈希头使用不同的hash_key(随机初始化的整数参数),哈希公式为:
index = (N-gram_value * hash_key) XOR hash_key mod 101
其中,N-gram_value是将2-gram的两个Token ID拼接为整数的结果(如(a, b) → a×1000 + b,避免数值溢出)。

具体计算 以2-gram₅ (567, 432) 为例完整计算

① 计算N-gram_value:

Vngram=567×1000+432=567432

② Hash Head 1(hash_key = 12345):

index1=(567432×12345)⊕12345mod 101

=7,003,987,640⊕12345mod 101

=7,003,999,985mod 101

=38

③ Hash Head 2(hash_key = 67890):

index2=(567432×67890)⊕67890mod 101

=38,532,899,480⊕67890mod 101

=38,532,967,370mod 101

=61

检索嵌入向量

两个哈希头分别从嵌入表E₁(Hash Head 1对应)和E₂(Hash Head 2对应)中取出向量:

  • E₁[38] = [0.2, 0.5, -0.1, 0.3](4维嵌入向量)
  • E₂[61] = [0.4, -0.2, 0.6, -0.4]

步骤4:上下文感知门控融合

 为什么需要门控融合?

多头哈希检索出的候选向量,可能因以下原因引入噪声:

噪声来源说明示例
哈希冲突不同N-gram映射到相同索引,检索出无关语义的向量2-gram (789, 210) 与 2-gram (567, 432) 恰好映射到同一index=61
一词多义同一Token在不同语境语义不同,导致检索向量语义偏移"with"在"with tears"与"with Multi-Head"中语义完全不同

门控融合的核心思路:让模型自己判断哪个检索结果是可信的


Hidden State的获取

Transformer在正向传播过程中,对位置5(对应"with Multi-Head")计算得到Hidden State

h₅ = [0.3, 0.4, -0.05, 0.25]

这是模型对当前位置综合上下文语义后的内部表示,包含了整个句子的语境信息。

⚠️ 关键点:门控打分的依据是 Hidden State h(连续向量),而非原始Token ID(离散整数)。模型无法直接计算Token ID与嵌入向量的相似度,只能在向量空间中进行比较。

注意力打分:h与候选Embedding做点积

用 h₅ 分别与两个候选Embedding做点积打分,衡量语义吻合程度:

对 E₁38 打分:

score1=h5⋅E1[38]

=0.3×0.2+0.4×0.5+(−0.05)×(−0.1)+0.25×0.3

=0.06+0.20+0.005+0.075=0.34  ✓

对 E₂61 打分:

score2=h5⋅E2[61]

=0.3×0.4+0.4×(−0.2)+(−0.05)×0.6+0.25×(−0.4)

=0.12−0.08−0.03−0.10=−0.09  ×

冲突判定与噪声抑制

score₁ = 0.34 → E₁[38] 与当前语义吻合 ✅ 保留

score₂ = -0.09 → E₂[61] 与当前语义不符 ❌ 判定为噪声,抑制

E₂61 噪声来源推断:

可能性A(哈希冲突):   某个无关2-gram(如"memory retrieval")   经Hash Head 2计算后,恰好也映射到 index=61   → E₂[61] 实际存储的是"memory retrieval"的语义   → 与当前"with Multi-Head"语义不符,点积为负 可能性B(一词多义):   "with"在训练语料中大量出现于情感语境("with tears")   → E₂[61] 捕获了"with"的情感语义分量   → 与技术文档语境下的"with Multi-Head"不匹配

Softmax加权融合

对打分结果做Softmax,计算各头的融合权重:

w1=e0.34e0.34+e−0.09=1.4051.405+0.914≈0.6

w2=e−0.09e0.34+e−0.09=0.9141.405+0.914≈0.39

💡 工程实践:在实际实现中,score极低(如低于阈值θ)的哈希头可直接mask掉(权重置0),而非参与Softmax,以更彻底地消除噪声干扰。

最终融合向量:

et=w1×E1[38]+w2×E2[61]

=0.61×[0.2, 0.5, −0.1, 0.3]+0.39×[0.4, −0.2, 0.6, −0.4]

=[0.122, 0.305, −0.061, 0.183]+[0.156, −0.078, 0.234, −0.156]

=[0.278, 0.227, 0.173, 0.027]

这个融合向量 etet​ 即为2-gram₅ "with Multi-Head" 的最终记忆表示,将被送入后续的模型层参与计算。

多头哈希通过多路并行检索 + 语义感知筛选,在保持O(1)检索效率的同时,将哈希冲突和一词多义带来的噪声降到最低,是大模型高效记忆检索的重要基础组件。

设计要素解决的问题实现方式
多个独立哈希头单一哈希冲突率高K个不同hash_key并行检索
质数嵌入表大小哈希分布不均匀选取质数101作为模数
词表规范化语义等价Token占用冗余空间归并形态变体到统一ID
Hidden State打分无法直接判断检索质量用连续向量做点积相似度计算
动态门控融合冲突/歧义向量污染结果低分向量mask或降权

Read more

终极解决方案:Visual C++ Redistributable安装失败完全修复指南

终极解决方案:Visual C++ Redistributable安装失败完全修复指南 【免费下载链接】vcredistAIO Repack for latest Microsoft Visual C++ Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾在安装游戏或专业软件时,被"缺少MSVCP140.dll"或"VCRUNTIME140_1.dll丢失"等错误困扰?作为运行C++程序的必备组件,Microsoft Visual C++ Redistributable(简称VC Redist)的安装问题常常成为普通用户和运维人员的技术障碍。本文将系统梳理vcredist项目README.md中最常见的安装失败场景,提供从自动修复到手动排障的全流程解决方案,确保你在5分钟内解决99%的VC运行库问题。 问题诊断:

By Ne0inhk
《C++二叉搜索树原理剖析:从原理到高效实现教学》

《C++二叉搜索树原理剖析:从原理到高效实现教学》

前引:二叉搜索树(Binary Search Tree, BST)作为一种基础且强大的数据结构,凭借其高效的查找与插入效率,成为算法设计与内存优化的核心工具。在C++中,BST不仅能实现高效的数据管理,更为平衡树(如AVL树)奠定理论基础。本文将深入剖析BST的有序性本质(结合C++特性详解插入、删除、遍历等关键操作,并提供内存安全的现代C++实现范式! 目录 【一】二叉搜索树介绍 【二】特点剖析 【三】二叉搜索树实现 (1)结构创建 (2)插入节点 (3)中序遍历 (4)查找节点 (5)删除节点 (6)析构 (7)拷贝构造 【一】二叉搜索树介绍 二叉搜索树又称二叉排序树,我们根据它的名字猜到是一颗二叉树完成了排序的工作?二叉树如何排序?下面我们来看看它和我们之前学习的大小顶堆有和区别! 【二】

By Ne0inhk

关于STL中的二分(lower_bound&upper_bound)

lower_bound&upper_bound 这两个函数是为了支持随机访问随机访问迭代器而设计的。 1.lower_bound 模版结构 // 查找第一个【大于或等于】value 的位置template<classForwardIt,classT> ForwardIt lower_bound(ForwardIt first, ForwardIt last,const T& value); * first / last: 搜索范围(必须是有序序列)。 * value: 要查找的目标值。 * 返回值: 返回一个指向该元素的迭代器;如果找不到,则返回 last。 操作示例 vector<int> v ={1,2,4,4,

By Ne0inhk
【C++:unordered_set和unordered_map】C++无序容器深度解析:unordered_set和unordered_map的使用

【C++:unordered_set和unordered_map】C++无序容器深度解析:unordered_set和unordered_map的使用

🔥艾莉丝努力练剑:个人主页 ❄专栏传送门:《C语言》、《数据结构与算法》、C/C++干货分享&学习过程记录、Linux操作系统编程详解、笔试/面试常见算法:从基础到进阶、测试开发要点全知道 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬艾莉丝的简介: 🎬艾莉丝的C++专栏简介: 目录 C++的两个参考文档 1  ~>  unordered_set 1.1  容器介绍 1.2  unordered_set和set的使用差异 2  ~>  unordered_map 2.1  容器介绍 2.2  unordered_map和map的使用差异 2.3  unordered_

By Ne0inhk