Android侧tokenizer的实现

引言

  • 背景介绍:最近一直在专注于解决端侧大模型的构建,发现端侧的大模型处理绕不开的一个核心点就是tokenizer。
  • 我们在对模型进行包装构建端侧可用的结构(如onnx、tflite、qnn等)时通常采取以下方式,我们发现主要的输入为input_ids、attention_mask、position_ids。其中attention_mask和position_ids相对很好构建,其中最主要核心input_ids就是tokenizer构建出的文本ID集合。
class ModelWrapper(torch.nn.Module):
    def __init__(self, model):
        super().__init__()
        self.model = model

    def forward(self, input_ids, attention_mask, position_ids):
        outputs = self.model(
            input_ids=input_ids,
            attention_mask=attention_mask,
            position_ids=position_ids,
            use_cache=True,
            return_dict=True
        )
        return outputs.logits 

一、tokenizer基础概念

Tokenizer(分词器)是将文本拆分为更小单元(如单词、子词或字符)的工具,是自然语言处理(NLP)任务的基础组件。其核心目标是将原始文本转换为模型可处理的数值形式。

主要功能

  1. 文本拆分
    将句子或段落拆分为词、子词或字符,例如:

    • 英文分词结果:"Hello world"["Hello", "world"]
    • 中文分词结果:"你好世界"["你好", "世界"]
  2. 词汇表映射
    为每个词汇单元分配唯一ID,构建词汇表(Vocabulary)。例如:

    {"hello": 1, "world": 2, "<unk>": 0}  
    
  3. 特殊标记处理
    添加预定义的符号(如[CLS][SEP]),用于模型控制或句子边界标识。

常见类型

  • 词级别(Word-based)
    以空格或语言规则分割单词,但难以处理未登录词(OOV)。
  • 子词级别(Subword-based)
    通过算法(如BPE、WordPiece)将单词拆分为更小子单元,平衡词汇表大小与OOV问题。
  • 字符级别(Character-based)
    按字符分割,词汇表极小但序列长度显著增加。

典型流程

  1. 标准化(Normalization)
    统一大小写、去除无效字符、Unicode规范化等。

  2. 预分词(Pre-tokenization)
    按空格或标点初步拆分文本,生成候选单元。

  3. 分词算法应用
    调用BPE、WordPiece等算法进一步处理,生成最终分词结果。

  4. 编码与解码

    • 编码:文本 → Token ID序列
    • 解码:Token ID序列 → 文本

代码示例

from transformers import AutoTokenizer  

# 加载预训练分词器  
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")  

# 编码文本  
text = "Hello, world!"  
encoded = tokenizer(text, return_tensors="pt")  
print(encoded.input_ids)  # 输出:tensor([[ 101, 7592, 1010, 2088,  999,  102]])  

# 解码  
decoded = tokenizer.decode(encoded.input_ids[0])  
print(decoded)  # 输出:"[CLS] hello, world! [SEP]"  

二、Android平台上的Tokenizer实现封装

static {
    System.loadLibrary("android_tokenizer");
}

方式一

利用vocab.json(词表文件)和merges.txt(合并文件),底层采用BPE分词算法,分词前会先根据空格进行预分词,然后根据词表进行分词。(PS:适用于采用BPE算法分词的模型,如clip)

handle = nativeCreate(vocabPath, mergesPath);
Log.d(TAG, "Tokenizer: handle= " + handle);
if (handle == 0) {
    Log.d(TAG, "Tokenizer: Failed to create tokenizer");
}

方式二

直接加载模型的tokenizer.json文件(PS:适用于LLM,如qwen、deepseek、llama等)

接口描述

提供了两个核心功能

  • Tokenizer.java(主要用于tokenizer相关功能的处理)
    Tokenizer.java
  • TokenSampler.java(主要用于对模型生成的logits进行采样处理,取值对应模型的generation_config.json)
    • 重复惩罚
    • 温度控制
    • top-k&top-p采样
      TokenSampler.java

示例(qwen2.5-1.5B onnx端侧推理)

模型转换时采用kv缓存,每步推理无需输入每层的kv张量
运行结果

### 大模型相关 APK 文件或移动应用 目前,大模型的部署主要集中在云端和本地环境中,而针对移动端的应用程序开发仍在快速发展阶段。尽管如此,已经有一些基于大模型构建的移动应用程序可供下载和使用。 #### 基于大模型的移动应用概述 一些公司和技术团队已经开始探索将大模型应用于移动端的可能性,并推出了相应的应用程序。这些应用通常通过优化模型大小、降低计算需求以及利用设备上的硬件加速来实现高效的推理能力[^3]。 #### 示例应用及其特点 以下是几个已知的大模型相关移动应用: 1. **通义千问 App (Qwen)** 阿里云推出的通义千问支持多种场景下的自然语言处理任务,包括问答、创作等。该应用能够在智能手机上运行,并提供离线模式选项以减少对网络连接的依赖[^3]。 2. **Hugging Face Transformers Mobile SDK** Hugging Face 提供了一个专门面向移动平台的 SDK,允许开发者轻松集成各种预训练的语言模型到他们的 Android 和 iOS 应用中。此 SDK 支持动态加载模型权重,从而节省存储空间[^2]。 3. **vLLM Demo Applications** vLLM 是一种高效的大规模语言模型推理引擎,其官方文档展示了如何创建简单的演示应用程序,这些应用可以作为模板帮助其他开发者快速启动自己的项目[^4]。 #### 技术挑战与解决方案 由于大多数先进的大模型都需要较高的内存资源,在移动设备上直接部署完整的大型神经网络存在诸多困难。为此,研究人员提出了几种策略来克服这些问题: - 使用低精度量化技术(如 4-bit 或者 INT8),这能够显著减小模型体积而不明显牺牲准确性[^1]; - 利用剪枝方法去除冗余部分进一步缩小规模; - 结合边缘云计算架构分流复杂运算至远程服务器执行后再返回结果给客户端显示。 对于希望自行开发此类产品的个人或者小型企业来说,则需要注意以下几点事项: - 明确目标用户的实际需求以便选取合适的底层框架和服务提供商; - 考虑版权归属问题确保所使用的各个组件均符合开源协议或许可条款规定; - 测试不同品牌型号终端之间的兼容性和表现差异调整最佳配置参数设置。 ```python import torch from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("model_path") model = AutoModelForCausalLM.from_pretrained("model_path", load_in_4bit=True) def generate_text(prompt): inputs = tokenizer.encode(prompt, return_tensors="pt").to('cuda') outputs = model.generate(inputs, max_length=50) text = tokenizer.decode(outputs[0], skip_special_tokens=True) return text ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值