大模型中常用的分词器Tokenizer学习总结记录与代码实现

最近大模型领域内如火如荼,很多企业、个人组织都陆续进入这个领域,笔者最近也是在接触大模型相关的技术领域,本文的主要目的就是想记录总结汇总大模型常用到的分词器算法,总结记录,学习备忘!由于博主本身知识缺乏总结内容难免会有错误,欢迎指正!

一、Byte Pair Encoding (BPE)

Byte Pair Encoding (BPE):BPE是一种基于字符级别的分词算法,常用于处理未分词的文本。它从字符级别开始,逐步合并出现频率最高的字符或字符组合,形成更长的词汇。

Byte Pair Encoding (BPE)是一种基于字符级别的无监督分词算法,常用于将未分词的文本划分为更小的单元。BPE算法的原理如下:

初始化:将所有字符作为初始词汇表中的单元。

统计频次:对文本进行统计,记录每个字符或字符组合的频次。

合并:在每次迭代中,选择频次最高的字符或字符组合,将其合并为一个新的单元,并将其作为新的词汇表中的单元。

更新词汇表:更新词汇表,将新合并的单元添加到词汇表中。

重复步骤2和3,直到达到预设的词汇表大小或满足停止条件。

BPE算法的优缺点如下:

优点:

无监督学习:BPE是一种无监督学习算法,不需要人工标注的分词数据即可进行词汇划分。

适应性强:BPE可以根据语料库进行自适应,能够学习到不同语种、领域的词汇特点,适用范围广。

有效处理未登录词:BPE可以将未登录词(Out-of-Vocabulary)分割成较小的子词,从而提高模型对未登录词的处理能力。

缺点:

Out-of-Vocabulary问题:由于BPE算法基于统计,其词汇表是固定大小的,如果遇到未在词汇表中出现的单元,将其分割为子词可能会增加语义上的困惑。

等分割问题:由于BPE算法在合并时选择频次最高的字符或字符组合,可能会导致某些词被过于粗糙地分割,产生一些半词或半短语。

分词效率较低:BPE算法是一个迭代的过程,可能需要大量的计算资源和时间来处理大规模的文本数据。

总之,BPE算法是一种常用的分词算法,能够有效地处理未分词文本,并且无需标注数据。然而,它也存在一些缺点,如Out-of-Vocabulary问题和等分割问题,需要在应用中加以考虑和处理。

demo代码实现如下所示:

python 复制代码
from collections import defaultdict

def get_stats(vocab):
    pairs = defaultdict(int)
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols)-1):
            pairs[symbols[i], symbols[i+1]] += freq
    return pairs

def merge_vocab(pair, v_in):
    v_out = {}
    bigram = ' '.join(pair)
    for word in v_in:
        v_out[word] = v_in[word]
        new_word = word.replace(' '.join(pair), bigram)
        if new_word != word:
            v_out[new_word] = v_in[word]
    return v_out

def bpe(text, num_iters):
    vocab = defaultdict(int)
    for word in text:
        vocab[' '.join(word)] += 1
    
    for i in range(num_iters):
        pairs = get_stats(vocab)
        if not pairs:
            break
        best_pair = max(pairs, key=pairs.get)
        vocab = merge_vocab(best_pair, vocab)
        
    return vocab

# 示例用法
text = ['low', 'lower', 'newest', 'widest', 'room', 'rooms']
num_iters = 10

vocab = bpe(text, num_iters)
print(vocab)

结果输出如下所示:

python 复制代码
{'l o w': 1, 'l o w e r': 1, 'n e w e s t': 1, 'w i d e s t': 1, 'r o o m': 1, 'r o o m s': 1}

二、WordPiece

WordPiece:WordPiece是一种基于子词级别的分词算法,常用于将文本划分为更小的单元。它通过合并出现频率最高的子词或子词组合,构建词汇表,并将文本划分为这些子词。

WordPiece是一种基于子词级别的分词算法,常用于将文本划分为更小的单元。WordPiece算法的原理如下:

初始化:将每个字符作为初始词汇表中的单元。

统计频次:对语料进行统计,记录每个单词及子词的频次。

合并:在每次迭代中,选择频次最高的相邻两个单元(字符或子词),将其合并为一个新的单元,并将其作为新的词汇表中的单元。

更新词汇表:更新词汇表,将新合并的单元添加到词汇表中。

重复步骤2和3,直到达到预设的词汇表大小或满足停止条件。

WordPiece算法的优缺点如下:

优点:

语言无关性:WordPiece算法是一种通用的分词算法,不依赖于特定的语言或语料库,能够适应不同的语种和领域。

词汇控制:通过合并相邻的单元,WordPiece算法可以根据词汇表的需求,动态控制词汇大小,使得词汇表能够适应不同的任务和数据规模。

有效处理未登录词:WordPiece算法将文本划分为子词,可以有效处理未登录词,并提供更好的语义表示能力。

缺点:

Out-of-Vocabulary问题:由于词汇表是固定大小的,WordPiece算法在遇到未在词汇表中出现的单元时,将其分割为子词可能会导致一些语义上的困惑。

词的不连续性:WordPiece算法将单词分割为子词,可能导致词的不连续性,使得模型需要更长的上下文来理解词的语义。

分割歧义:由于WordPiece算法仅根据频次合并单元,并不能解决所有的分割歧义问题,可能产生一些歧义的分词结果。

总之,WordPiece算法是一种常用的基于子词级别的分词算法,具有语言无关性和词汇控制的优点。然而,它也存在一些缺点,如Out-of-Vocabulary问题和词的不连续性,需要在实际应用中进行一定的处理和权衡。

demo代码实现如下所示:

python 复制代码
from collections import defaultdict

def get_stats(vocab):
    pairs = defaultdict(int)
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols)-1):
            pairs[symbols[i], symbols[i+1]] += freq
    return pairs

def merge_vocab(pair, v_in):
    v_out = {}
    bigram = ''.join(pair)
    for word in v_in:
        v_out[word] = v_in[word]
        new_word = word.replace(' '.join(pair), bigram)
        if new_word != word:
            v_out[new_word] = v_in[word]
    return v_out

def wordpiece(text, num_iters):
    vocab = defaultdict(int)
    for word in text:
        vocab[' '.join(list(word))+' </w>'] += 1
    
    for i in range(num_iters):
        pairs = get_stats(vocab)
        if not pairs:
            break
        best_pair = max(pairs, key=pairs.get)
        vocab = merge_vocab(best_pair, vocab)
        
    return vocab

# 示例用法
text = ['low', 'lower', 'newest', 'widest', 'room', 'rooms']
num_iters = 10

vocab = wordpiece(text, num_iters)
print(vocab)

结果输出如下所示:

python 复制代码
{'l o w </w>': 1, 'lo w </w>': 1, 'l o w e r </w>': 1, 'lo w e r </w>': 1, 'l o w e r</w>': 1, 'lo w e r</w>': 1, 'l o we r </w>': 1, 'lo we r </w>': 1, 'l o we r</w>': 1, 'lo we r</w>': 1, 'n e w e s t </w>': 1, 'n e we s t </w>': 1, 'w i d e s t </w>': 1, 'r o o m </w>': 1, 'r o o m s </w>': 1}

三、SentencePiece

SentencePiece:SentencePiece是一种基于未分词语料的无监督分词算法,可以用于构建多语言的分词器。它可以通过训练,自动识别出多种语言的词汇,并对文本进行分词。

SentencePiece是一种基于子词级别的分词算法,常用于将文本划分为更小的单元。SentencePiece算法的原理如下:

初始化:将每个字符作为初始词汇表中的单元。

统计频次:对语料进行统计,记录每个单词及子词的频次。

合并:在每次迭代中,选择频次最高的相邻两个单元(字符或子词),将其合并为一个新的单元,并将其作为新的词汇表中的单元。

更新词汇表:更新词汇表,将新合并的单元添加到词汇表中。

重复步骤2和3,直到达到预设的词汇表大小或满足停止条件。

SentencePiece算法的优缺点如下:

优点:

语言无关性:SentencePiece算法不依赖于特定的语言或语料库,可以适应不同的语种和领域。

动态词汇表:通过合并单元,SentencePiece算法可以动态控制词汇大小,使得词汇表能够适应不同的任务和数据规模,能够在大模型中高效地使用。

分词效果好:SentencePiece算法精细地将单词划分为子词,提供了更好的语义表示能力和更好的分词效果。

显著降低Out-of-Vocabulary问题:SentencePiece算法将未登录词分割成子词,显著降低了Out-of-Vocabulary问题的出现,提高了模型的泛化能力。

缺点:

分词复杂性:SentencePiece算法在处理大规模的文本数据时可能需要较长的时间,因为它是一个迭代的过程,并且使用了统计方法进行合并。

模型大小:由于SentencePiece算法通过生成一个大词汇表来表示子词,可能会导致模型的大小增加,占用更多的存储空间。

分词结果不唯一:由于合并过程是基于统计的,SentencePiece算法可能产生多个合理的分词结果,导致分词结果不唯一。

总之,SentencePiece算法是一种常用且效果优秀的基于子词级别的分词算法,具有语言无关性和动态词汇表的优点,能够显著降低Out-of-Vocabulary问题。然而,它也存在一些缺点,如分词复杂性和分词结果的不唯一性,需要在实际应用中进行权衡和处理。

demo代码实现如下所示:

python 复制代码
from collections import defaultdict

def train_sentencepiece(corpus, vocab_size, max_iters):
    """
    基于词频统计来迭代地进行符号合并,直到达到指定的词汇表大小或达到最大迭代次数
    """
    vocab = get_vocabulary(corpus)
    for _ in range(max_iters):
        pairs = get_stats(vocab)
        if not pairs:
            break
        best_pair = max(pairs, key=pairs.get)
        vocab = merge_vocab(best_pair, vocab)
        if len(vocab) >= vocab_size:
            break
    return vocab

def get_vocabulary(corpus):
    """
    从语料库中获取初始词汇表
    """
    vocab = defaultdict(int)
    with open(corpus, 'r', encoding='utf-8') as file:
        for line in file:
            line = line.strip()
            tokens = line.split()
            for token in tokens:
                vocab[token] += 1
    return vocab

def get_stats(vocab):
    """
    获取每个字符或字符组合的频
    """
    pairs = defaultdict(int)
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols)-1):
            pairs[symbols[i], symbols[i+1]] += freq
    return pairs

def merge_vocab(pair, vocab):
    """
    根据频次最高的字符组合进行合并
    """
    vocab_out = {}
    bigram = ''.join(pair)
    for word in vocab:
        vocab_out[word] = vocab[word]
        new_word = word.replace(' '.join(pair), bigram)
        if new_word != word:
            vocab_out[new_word] = vocab[word]
    return vocab_out

def encode_sentencepiece(text, vocab):
    """
    将文本编码为SentencePiece标记序列
    """
    encoded_text = []
    for token in text.split():
        if token in vocab:
            encoded_text.extend(vocab[token].split())
        else:
            encoded_text.append(token)
    return encoded_text

def decode_sentencepiece(encoded_text, reverse_vocab):
    """
    将标记序列解码为原始文本
    """
    decoded_text = ' '.join(encoded_text)
    for token, replacement in reverse_vocab.items():
        decoded_text = decoded_text.replace(token, replacement)
    return decoded_text

# 示例用法
corpus = "data.txt"  # 输入语料文件路径
vocab_size = 1000  # 词汇表大小
max_iters = 10  # 最大迭代次数

vocab = train_sentencepiece(corpus, vocab_size, max_iters)

text = "This is a sample sentence to encode with SentencePiece."
encoded_text = encode_sentencepiece(text, vocab)
print(f"Encoded text: {encoded_text}")

reverse_vocab = {v: k for k, v in vocab.items()}
decoded_text = decode_sentencepiece(encoded_text, reverse_vocab)
print(f"Decoded text: {decoded_text}")

上述代码是一个简化的实现,并不完全符合SentencePiece算法的细节和复杂性。如果需要更强大和高效的SentencePiece实现,建议使用现有的开源库,如sentencepiece。下面同样给出实例代码:

python 复制代码
import sentencepiece as spm

def train_sentencepiece(corpus, model_prefix, vocab_size):
    spm.SentencePieceTrainer.train(
        input=corpus,
        model_prefix=model_prefix,
        vocab_size=vocab_size
    )

def encode_sentencepiece(model_prefix, text):
    sp = spm.SentencePieceProcessor(model_file=f"{model_prefix}.model")
    encoded_text = sp.encode_as_pieces(text)
    return encoded_text

def decode_sentencepiece(model_prefix, encoded_text):
    sp = spm.SentencePieceProcessor(model_file=f"{model_prefix}.model")
    decoded_text = sp.decode_pieces(encoded_text)
    return decoded_text

# 示例用法
corpus = "data.txt"  # 输入语料文件路径
model_prefix = "spm_model"  # SentencePiece模型前缀
vocab_size = 1000  # 词汇表大小

train_sentencepiece(corpus, model_prefix, vocab_size)

text = "This is a sample sentence to encode with SentencePiece."
encoded_text = encode_sentencepiece(model_prefix, text)
print(f"Encoded text: {encoded_text}")

decoded_text = decode_sentencepiece(model_prefix, encoded_text)
print(f"Decoded text: {decoded_text}")

四、Transformer

Transformer分词(如BERT Tokenizer):Transformer模型中常使用一种称为BERT Tokenizer的分词器。它可以将文本划分为基于词、子词或字符级别的标记,并生成对应的词嵌入。

Transformer是一种基于注意力机制的分词算法,常用于处理序列数据,其中包括自然语言处理任务。Transformer算法的原理如下:

自注意力机制(Self-Attention):Transformer使用自注意力机制来建立词与词之间的关系。对于输入的序列,通过计算每个词与其他词之间的相似度得到注意力权重,然后将注意力权重作用于词向量上,从而关注到序列中重要的关键词。

编码器-解码器结构(Encoder-Decoder Architecture):在机器翻译等任务中,Transformer使用了编码器-解码器结构。编码器将输入序列转换为中间表示,解码器通过自注意力机制和编码器的输出生成目标序列。

多头注意力机制(Multi-Head Attention):为了对不同的词之间的依赖关系进行建模,Transformer使用了多头注意力机制。它将注意力机制应用到多个线性映射的投影中,然后将它们拼接起来并通过一个线性映射得到最终的表示。

位置编码(Positional Encoding):为了处理序列中的位置信息,Transformer引入了位置编码。位置编码是一种对词的位置进行编码的方式,它可以与词向量相加获得每个词的综合表示。

Transformer算法的优缺点如下:

优点:

并行计算:由于Transformer使用自注意力机制,每个词都可以并行计算其与其他词之间的关系,从而加快计算速度,使得Transformer在大规模数据上具有较高的效率。

长距离依赖性:通过自注意力机制,Transformer更好地处理长距离的依赖关系,能够捕捉到更远距离的上下文信息,提供更准确的语义表示能力。

上下文感知:Transformer利用自注意力机制可以对每个词进行不同程度的关注,从而更好地理解上下文的语意。

可解释性:由于Transformer使用自注意力机制,可以直观地观察到哪些词对于当前词最重要,提供了一定的可解释性。

缺点:

训练复杂性:Transformer中包含了大量的参数和复杂的计算过程,导致训练过程相对较慢,尤其在处理大规模数据时需要更多的计算资源。

学习长距离依赖性的挑战:尽管Transformer可以较好地处理长距离的依赖关系,但在某些复杂任务中,仍可能存在对长距离依赖的挑战。

总之,Transformer是一种在大模型中常用的分词算法,通过自注意力机制处理序列数据,具有并行计算、长距离依赖性、上下文感知和可解释性的优点。然而,它也存在训练复杂性和学习长距离依赖性的挑战。

demo代码实现如下所示:

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(p=0.1)
        
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0).transpose(0, 1)
        self.register_buffer('pe', pe)
        
    def forward(self, x):
        x = x + self.pe[:x.size(0), :]
        return self.dropout(x)

class TransformerEncoderLayer(nn.Module):
    def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1):
        super(TransformerEncoderLayer, self).__init__()
        self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
        self.linear1 = nn.Linear(d_model, dim_feedforward)
        self.dropout = nn.Dropout(dropout)
        self.linear2 = nn.Linear(dim_feedforward, d_model)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)
        
    def forward(self, src, src_mask=None, src_key_padding_mask=None):
        src2 = self.self_attn(src, src, src, attn_mask=src_mask, key_padding_mask=src_key_padding_mask)[0]
        src = src + self.dropout1(src2)
        src = self.norm1(src)
        src2 = self.linear2(self.dropout(F.relu(self.linear1(src))))
        src = src + self.dropout2(src2)
        src = self.norm2(src)
        return src

class TransformerEncoder(nn.Module):
    def __init__(self, encoder_layer, num_layers, norm=None):
        super(TransformerEncoder, self).__init__()
        self.layers = nn.ModuleList([copy.deepcopy(encoder_layer) for _ in range(num_layers)])
        self.num_layers = num_layers
        self.norm = norm
        
    def forward(self, src, mask=None, src_key_padding_mask=None):
        output = src

        for layer in self.layers:
            output = layer(output, src_mask=mask, src_key_padding_mask=src_key_padding_mask)
            
        if self.norm is not None:
            output = self.norm(output)
            
        return output

# 示例用法
d_model = 512  # 词嵌入维度
nhead = 8  # 多头自注意力头数
dim_feedforward = 2048  # 前馈网络隐藏层维度
dropout = 0.1  # 丢弃率
num_layers = 6  # 编码器层数
src = torch.randn(10, 32, d_model)  # 输入张量

pos_encoder = PositionalEncoding(d_model)
encoder_layer = TransformerEncoderLayer(d_model, nhead, dim_feedforward, dropout)
transformer_encoder = TransformerEncoder(encoder_layer, num_layers)

src = pos_encoder(src)
output = transformer_encoder(src)
print(output.shape)

五、Unigram LM

在大模型中,常用的分词算法之一是unigram language model (unigram LM)。unigram LM算法是一种基于统计的单元划分方法,它基于语言模型构建分词规则,其原理如下:

数据预处理:将训练语料库进行预处理,包括分割句子、标记词性等,得到一组训练样本。

统计词频:统计训练样本中的每个词,得到每个词的出现频次。

构建词表:根据词频,将训练样本的词按照频次从大到小进行排序,构建一个词表。

构建分词模型:根据词表中每个词的出现频次,可以计算出每个词在整个语料中出现的概率。这样,将语料库中的文本数据拆分为最有可能的词序列。

分词:对于新的文本输入,利用unigram LM模型根据词的概率选择最可能的划分方式,进行分词操作。

unigram LM算法的优缺点如下所示:

优点:

简单高效:unigram LM算法的实现相对简单,计算效率较高,适合在大规模数据上使用。

数据驱动:unigram LM算法依靠训练语料库中的统计信息进行分词,具备较好的语言模型学习能力。

高度可定制化:通过对训练样本的预处理和统计词频,可以根据需要自定义不同规则,满足特定领域和任务的分词需求。

缺点:

上下文信息缺失:unigram LM算法只考虑了每个词自身的出现概率,缺乏上下文信息,可能导致一些模糊的划分结果。

未登录词问题:unigram LM算法对未登录词(未在训练集中出现的词)处理能力较差,可能无法正确划分未登录词。

歧义问题:某些词在不同的上下文中可能具有不同的含义,unigram LM算法可能无法准确划分。

总之,unigram LM算法是一种简单、高效的基于统计的分词算法,具有数据驱动和高度可定制化的优点。然而,它也存在上下文信息缺失、未登录词问题和歧义问题等缺点,需要在实际应用中进行改进和处理。

demo代码实现如下所示:

python 复制代码
import random
from collections import defaultdict

class UnigramLM:
    def __init__(self):
        self.word_counts = defaultdict(int)
        self.total_words = 0

    def train(self, corpus):
        with open(corpus, 'r', encoding='utf-8') as file:
            for line in file:
                line = line.strip()
                tokens = line.split()
                for token in tokens:
                    self.word_counts[token] += 1
                    self.total_words += 1

    def generate_sentence(self, length):
        sentence = []
        for _ in range(length):
            rand_idx = random.randint(0, self.total_words-1)
            for word, count in self.word_counts.items():
                rand_idx -= count
                if rand_idx < 0:
                    sentence.append(word)
                    break
        return ' '.join(sentence)

# 示例用法
corpus = "data.txt"  # 训练语料文件路径
length = 10  # 生成句子的长度

lm = UnigramLM()
lm.train(corpus)
generated_sentence = lm.generate_sentence(length)
print(generated_sentence)

【总结分析】

Byte Pair Encoding (BPE)

优点:

能够处理未分词的文本,且容易实现和使用。

根据语料频率合并字符或字符组合,生成对应的词汇表。

对于语言中的常见词汇有较好的表示能力。

缺点:

没有考虑语义信息,可能造成词汇划分的歧义。

生成的词汇表可能较大,增加了存储和计算资源的需求。

WordPiece:

优点:

可以处理未分词的文本,并根据语料频率合并子词或子词组合。

考虑了语义信息,提供更好的词汇表示能力。

适用于多语言场景。

缺点:

生成的词汇表可能较大,增加了存储和计算资源的需求。

SentencePiece:

优点:

可以通过无监督学习方式构建多语言分词器。

能够根据语料自动学习语言的词汇,并生成对应的分词模型。

缺点:

对于特定语料和应用场景,学习过程可能需要较长的时间和计算资源。

生成的词汇表可能较大,增加了存储和计算资源的需求。

Transformer分词(如BERT Tokenizer):

优点:

基于Transformer模型,能够处理复杂的语言结构和上下文信息。

生成的词嵌入能同时表示词汇和上下文,提高模型对语义和上下文关系的理解能力。

缺点:

比较复杂,处理速度可能较慢。

Unigram LM:

优点:

根据语料中词的频率构建词汇表,能够有效捕捉常见词汇。

计算简单,速度较快。

缺点:

没有考虑语义信息,可能造成词汇划分的歧义。

对于非常见词汇的处理较为困难。

理想的分词器应具备以下特性:

能够处理未分词的文本,可适应不同语料和应用场景。

考虑语义信息,以准确划分词汇边界。

生成的词汇表大小适中,平衡存储和计算资源需求。

处理速度高,满足实时性需求。

跨语言分词能力较好,适用于多语言场景。

可定制和调整,以满足特定任务需求。

良好的稳定性和鲁棒性,能够应对输入中的错误或噪声。

【未来展望】

这里总结分析了已有各种大模型中用到的分词器模型,各种模型都有各自对应的优缺点,那么理想完美的分词器应该具备什么样的特性呢?这里简单展望一二:

一个理想完美的分词器应该具备以下特性:

  1. 对于不同语料和应用场景具有高适应性:

    • 能够处理未分词的文本,适用于不同领域和语言。
    • 能够根据语料自动学习或调整,以适应不同的数据特点。
  2. 准确划分词汇边界:

    • 能够考虑上下文和语法信息,准确区分词汇边界,避免歧义。
    • 能够捕捉词汇中的常见搭配和复合词结构。
  3. 考虑语义和结构信息:

    • 能够对词汇进行更好的语义表示,提供更丰富的语义信息。
    • 能够处理复杂的语言结构,包括长距离依赖关系和上下文依赖。
  4. 词汇表大小适中:

    • 生成的词汇表既能包含常见词汇,又不会过于庞大,以平衡存储和计算资源的需求。
    • 能够处理未登录词,识别和推断未见过的词汇。
  5. 高处理效率:

    • 具备快速的分词速度,以满足实时性要求。
    • 能够在大规模数据上高效训练和推断,充分利用计算资源。
  6. 跨语言分词能力:

    • 能够处理不同语言的分词需求,包括具有不同语法和结构的语言。
  7. 可定制和调整:

    • 允许用户根据特定任务需求进行定制和调整。
    • 提供丰富的参数配置选项,以便满足不同的分词需求。
  8. 鲁棒性和稳定性:

    • 能够应对输入中的错误、噪声和异常情况,具备良好的鲁棒性。
    • 在不同环境和数据分布下保持稳定的性能表现。

这些特性综合考虑了分词器在语义理解、上下文处理、效率和适应性等方面的需求,一个理想完美的分词器应该在这些方面有较好的表现。

相关推荐
西岸行者7 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意7 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码7 天前
嵌入式学习路线
学习
毛小茛7 天前
计算机系统概论——校验码
学习
babe小鑫7 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms7 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下7 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。7 天前
2026.2.25监控学习
学习
im_AMBER7 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J7 天前
从“Hello World“ 开始 C++
c语言·c++·学习