行业背景与思考
随着GPT-4、GPTs的2C端已经被ChatGPT完全占据,然而由于训练数据库更新不及时,模型未及时进行微调,模型对于专业垂直领域的问题回答常常出现幻觉效应(illusion),对于2B和2G市场来说,本地化部署、领域or行业内回答精准、国产化无疑就成为了重要的考核指标。
垂直领域大模型或者说大模型领域化、行业化是大模型落地的核心要素。ChatLaw LLM(一款法律领域大模型)对于指定输出的回答要求极为精准,因此,如何保证回答的法规合理准确,直接决定了垂直领域大模型是否能够落地。
垂直大模型实践
主要使用的架构为RAG+SimCSE+chatchat(chatGLM架构),原模型使用的为bert-base-uncased,由于后续的语料库为中文语料,因此想将pretrained-model换成bert-base-Chinese架构,因此直接改了model_path之后报错
Indexing.cu:1292: block: [546,0,0], thread: [31,0,0] Assertion `srcIndex < srcSelectDimSize` failed.
***
RuntimeError: CUDA error: device-side assert triggered
debug
出现该问题,由于是CUDA报的assert错误,怀疑是网络结构/部分参数没有对齐,首先把训练模式改为cpu模式,查看主要问题,同时监控出现问题的地方。发现错误:
out = model(input_ids, attention_mask, token_type_ids)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
IndexError: index out of range in self
果然发现是参数没有对齐,因此查看两个参数对齐情况
tokenizer.vocab_size: 21128
config.vocab_size: 21128
max_input_id: 29486
由于tokenizer的vocab_size是从pretrained model读取来的,而config的vocab_size是config.json中读取来的,而max_input_id表示加载到的数据中最大的词表数量
而bert base uncased的"vocab_size"为 30522,bert chinese的仅为21128,实际加载的各类训练数据等语料数据包含的vocab种类高达29486种,因此说明bert chinese的语料较少,分词器分词较少,因此采用了两种解决方案:
方案1:将超出词汇表范围的索引映射到特殊未知词token的索引上
通常,BERT模型的词汇表中会有一个特殊的未知词token(如[UNK]),其索引通常是0(具体取决于分词器的实现)。但由于unknown造成的整体信息熵减少,使得信息存在损失,因此使得整体精度只有0.64左右。
方案2:将多个词汇表结合在一起,使得vocab_size增大
input_ids[input_ids >= config.vocab_size] = tokenizer.unk_token_id
由于部分vocab在原始预训练模型中并没有学习到特征,因此造成了最终的训练结果与原始模型mismatch,造成了最终精度极低,仅有0.35左右。需要重新用高质量数据重新训练整个bert base chinese模型(经调研需要1T高质量数据),因此放弃。
方案3:保持bert base uncased方案,研究vocab size影响
中文方案与英文语料方法相差不大,调研uncase的vocab.txt,能够发现其中包括了众多中文vocab,因此从理论上bert base chinese仅与uncased相差4%左右,而uncased具有更好的泛用性。最终训练的中文语料库包括bq_corpus, ChineseSTS, financialLaw(私有数据集), lcqmc,paws-x-zh,通用数据集有STSbenchmark, nil for simcse, wiki1m for simcse等。训练曲线如下图所示。
训练参数:
设备:4090mobile
hyperpara:batch size:64, lr 3e-5, dropout 0.2
微调耗时:30min
显存占用:8G
在Meta开源LLama模型后,大量的微调模型出现,大部分模型都在LLaMA2模型的基础上扩大了vocab词表。扩充词表最基本功能:1.缩小VRAM的占用,从而带来更长的输入输出;2.导致推理速度的下降
上述文章的结论:
模型性能:词汇表的大小会影响模型的性能。较大的词汇表可以包含更多的词汇,这有助于模型更好地理解和表达文本。然而,随着词汇表大小的增加,模型的计算复杂度和内存需求也会增加,可能导致训练时间变长和过拟合的风险增加。
未知词汇:词汇表大小决定了模型在处理文本时能够识别的词汇数量。较小的词汇表可能导致更多的未知词汇(out-of-vocabulary words),这些词汇在模型中会被映射到相同的嵌入向量,从而导致语义信息的丢失和模型性能下降。增加词汇表大小可以减少未知词汇的数量,提高模型性能。
内存需求和计算资源:较大的词汇表需要更多的内存来存储,这可能导致模型在训练和推理过程中需要更多的计算资源。在有限的硬件资源下,选择合适的词汇表大小是在模型性能和计算资源之间取得平衡的关键。
模型泛化能力:词汇表大小可能会影响模型的泛化能力。较小的词汇表可能导致模型在面对新的、未见过的词汇时泛化能力较差。而较大的词汇表可能提高模型的泛化能力,使其在不同的任务和领域中表现更好。
词汇表大小会影响模型处理词汇表外 (OOV) 单词的能力。更大的词汇表可以涵盖更多的单词,从而减少 OOV 单词的数量并提高模型处理不同文本的能力。 使用字节对编码 (BPE) 或 WordPiece 等子词标记化方案可以帮助创建更大的有效词汇表,同时仍然具有计算效率。这些方案将单词分解为子词单元,允许模型将生僻词表示为更频繁的子词的组合。 较大的词汇量可以提高模型的表现力和泛化能力。但是,在词汇量和计算效率之间需要权衡。非常大的词汇量会导致内存使用量增加,训练和推理时间变慢。
https://medium.com/@michaelhumor/understanding-tokens-and-tokenization-in-large-language-models-1058cd24b944
优点: 计算效率:较大的标记可以减少表示文本所需的标记数量,从而在计算方面提高处理效率。 更好的上下文:给定固定的最大标记数,较大的标记允许模型考虑更长的文本段,从而可能带来更好的理解和生成能力。 减少歧义:较大的标记可能会直接捕获更细微的含义,从而减少将单词分解为较小部分而产生的歧义。
缺点: 词汇量:较大的标记通常需要更大的词汇表来捕获相同范围的文本,这可能会占用大量内存。 灵活性降低:较大的标记可能会限制模型泛化到看不见或生僻的单词的能力,因为整个标记必须与模型词汇表中的某些内容匹配。 语言限制:对于具有复杂形态或语法的语言,或者对于需要理解多种语言的任务,较大的标记可能不那么有效。 处理可变性:较大的标记可能对拼写错误、拼写变化和文本中的其他细微变化很敏感。
Unigram:在训练的每个阶段,它计算每个子词标记的概率,并定义一个损失值,如果每个子词标记被丢弃,将导致该值。然后,它挑选出如果丢弃导致总损失最小的代币,本质上是那些对集合几乎没有价值的代币。Unigram 不直接用于转换器中的任何模型,但它与 SentencePiece 结合使用。 Sentence Piece:虽然现有的子词分割工具假设输入被预先标记成单词序列,但 SentencePiece 可以直接从原始句子中训练子词模型,这使我们能够制作一个纯粹的端到端和独立于语言的系统。
AI21 的侏罗纪模型:这些模型利用了独特的 250,000 个标记词汇表,不仅比大多数现有词汇表大得多(5 倍或更多),而且还是第一个包含多词标记的模型,例如表达式、短语和命名实体。正因为如此,侏罗纪 1 号需要更少的标记来表示给定数量的文本,从而提高计算效率并显着减少延迟。
https://www.jiqizhixin.com/articles/2023-10-04-5
研究结果总结如下:
编码方式上,TokenMonster(550256-strict-nocapcode)词表在所有指标上都比其他词表表现更好。
最佳词表规模为32000。
词表越简单,模型收敛得越快,但后期不一定会产生更好的结果。
字词比(每个token对应的平均字符数)增加,不会单独对模型质量产生负面影响。
单个token对应的多个单词的词表对SMLQA(真值)基准有5%的负面影响,但对字词比要高13%。
带有Capcode的词表的话,模型需要更长的时间来学习,但一旦模型收敛,似乎不会在任何方向上对SMLQA(真值)或SQuAD(Data Extraction)产生影响。
根据实验结果,englishcode-32000-consistent的结果是最佳的。研究者认为,通过强制80%的token对应一个单词,20%的token对应多个单词,可以最大限度地减少这种权衡,实现“两全其美”的词表。这种方法在性能上与one-word词表相同,同时字词比还能提高约50%。
研究者还详细解释了“分词器中的缺陷和复杂性对模型学习事实能力的影响大于对其语言能力的影响”的含义。这意味着一个更好的分词器就是一个更真实的模型,但不一定是一个更流畅的模型。反过来说:一个拥有低效分词器的模型仍然能学会流利地写作,但流利性的额外成本会降低模型的可信度。
关于词表规模的影响,实验结果证实了32000是最佳词表规模。在优化模式方面,研究者建议大家使用consistent模式,strict模式只能在禁用capcode的情况下使用。
https://developer.huawei.com/consumer/cn/forum/topic/0204138379175336953?fid=0101592429757310384
词表大小:词表的大小直接影响模型的复杂度和存储需求。较大的词表可以表示更多的词汇,有助于捕捉文本中的多样性,但同时也会增加模型的参数数量和计算复杂度。相反,较小的词表可能会丢失一些低频词的信息,导致模型表达能力受限。
未登录词(Out-of-Vocabulary, OOV)问题:当词表中不包含某些词汇时,模型无法为这些词汇生成表示。这可能导致模型在处理一些罕见词或领域特定词汇时性能下降。为了解决这个问题,可以使用子词(subword)单元,如Byte Pair Encoding(BPE)、WordPiece等方法,将词汇切分为更小的单元,从而减少未登录词的影响。
数据稀疏性:较大的词表可能导致数据稀疏性问题,即许多词在训练数据中出现的次数很少。这可能导致词向量难以充分学习,影响模型性能。为了缓解这个问题,可以使用词元表示(subword representation)或者预训练模型,通过捕捉词汇间的语义关系来提高模型的表达能力。
多语言支持:在处理多语言文本时,一个包含多种语言的统一词表可能会导致一些问题,例如不同语言的词汇混合在一起,使得模型难以学习到语言间的语义关联。为了解决这个问题,可以为每种语言分别构建词表,或者使用字节对编码(BPE)等方法在多语言数据上进行训练,以提高模型在多语言任务上的性能。