在很多场景下下,可能微调模型并不能带来一个较好的效果。因为特定领域场景下,通用话模型过于通用,出现多而不精。样样通样样松;本章主要介绍如何在特定的数据上对模型进行预训练;
训练自己的语言模型(从头开始训练)与微调(fine-tuning)预训练模型之间的选择取决于多个因素,包括但不限于数据特性、任务需求、计算资源和时间成本。以下是一些原因,解释为什么有时候你可能想要训练自己的语言模型,而不是仅仅微调现有的预训练模型:
训练自己的语言模型(从头开始训练)与微调(fine-tuning)预训练模型之间的选择取决于多个因素,包括但不限于数据特性、任务需求、计算资源和时间成本。以下是一些原因,解释为什么有时候你可能想要训练自己的语言模型,而不是仅仅微调现有的预训练模型:
1. **领域特异性**:如果你的工作涉及非常专业的领域,如医疗健康、法律或金融,那么现有的预训练模型可能没有包含足够的领域相关数据。在这种情况下,从头开始训练一个模型,使用专门领域的大量文本数据,可以让模型更好地理解和生成专业领域的文本。
2. **数据量大且独特**:如果你拥有大量的专有数据,这些数据具有独特的特点,那么训练一个模型以充分利用这些数据的独特性可能更有意义。预训练模型通常是在广泛的数据集上训练的,可能无法捕捉到特定数据集中存在的细微差别。
3. **控制模型架构**:训练自己的模型允许你完全控制模型架构的选择,包括层数、隐藏单元的数量以及其他超参数。这对于研究或开发新方法特别有用。
4. **避免偏见和数据污染**:预训练模型可能包含了来自其训练数据的某些偏见。如果你希望避免这些偏见,或者你的任务要求极高精度而不能容忍任何潜在的偏见,那么训练一个干净的新模型可能是更好的选择。
5. **数据隐私和安全**:对于处理敏感数据的情况,从头开始训练模型可以确保所有数据都保留在内部系统中,而不必担心将数据发送到外部服务器进行微调。
6. **探索新的模型架构**:对于学术研究来说,开发和训练新型的模型架构是一个重要的方向。这通常需要从零开始训练模型,以便全面地测试和验证新设计的有效性。
7. **资源可用性**:如果你有充足的计算资源(如高性能GPU集群),那么从头训练模型可能并不是一个问题,并且可能带来更好的长期投资回报。
尽管如此,训练自己的语言模型是一项耗时且资源密集型的任务。如果你的数据集不大,或者任务领域与现有预训练模型的数据集重叠较多,那么微调一个预训练模型通常是更为高效和实用的选择。微调可以让你快速地适应特定任务,同时保持较高的准确性和较低的成本。
1 数据准备
选择一个中文为主的语料进行训练。
https://huggingface.co/datasets/pleisto/wikipedia-cn-20230720-filtered
2 模型
选择使用BERT模型:
需要注意的是模型类别不同使用的方法也不一样的:
1. Encoder-Decoder Models(编码器-解码器模型):EncoderDecoderModel
典型代表:Transformer(如BERT)、Seq2Seq(如T5) 训练方法:
- 掩码语言建模(Masked Language Modeling, MLM):在训练过程中随机遮盖输入序列的一部分单词,然后让模型预测这些被遮盖的单词。
- 序列到序列任务(Sequence-to-Sequence Tasks):如机器翻译、文本摘要等,输入一个源序列,输出一个目标序列。
2. Decoder-Only Models(解码器模型):AutoModelForCausalLM
典型代表:GPT系列(如GPT-2、GPT-3)、BLOOM 训练方法:
- 因果语言建模(Causal Language Modeling, CLM):在训练过程中,模型预测序列中的下一个词,仅依赖于序列中的先前词。这是一种自回归式的训练方法,即每次预测下一个词时,只看前面的词。
- 文本生成:这类模型非常适合生成连贯的文本序列,因为它们可以逐词生成文本,并且保证生成的文本是连贯的。
3. Encoder-Only Models(编码器模型):AutoModelForMaskedLM
典型代表:RoBERTa 训练方法:
- 掩码语言建模(MLM):类似于BERT,但在训练过程中可能采用不同的掩码策略。
- 句子对预测(Next Sentence Prediction, NSP):虽然RoBERTa不再使用NSP,但在早期的一些模型中,这种方法用于预测两个句子是否相邻。
https://hf-mirror.com/google-bert/bert-base-chinese
下面是一个去掉部分词的标签:
from datasets import load_dataset, Dataset
from transformers import AutoTokenizer, AutoModelForMaskedLM, DataCollatorForLanguageModeling, TrainingArguments, Trainer
ds = Dataset.load_from_disk("../data/wiki_chines_filter/")
ds
#ds[1]
#定义一个过滤函数
def filter_function(example):
# 确保返回布尔值
if 'completion' in example and isinstance(example['completion'], str) and example['completion']:
return True
return False
ds = ds.filter(lambda example: filter_function(example))
ds
tokenizer = AutoTokenizer.from_pretrained("../bert-base-chinese/")
def process_func(examples):
#print(examples)
contents = [e + tokenizer.sep_token for e in examples["completion"]]
return tokenizer(contents, max_length=384, truncation=True)
# try:
# contents = [e + tokenizer.eos_token for e in examples["completion"]]
# return tokenizer(contents, max_length=384, truncation=True)
# except:
#print(examples['completion'])
#exit()
tokenized_ds = ds.map(process_func, batched=True, remove_columns=ds.column_names)
tokenized_ds
from torch.utils.data import DataLoader
dl = DataLoader(tokenized_ds, batch_size=2, collate_fn=DataCollatorForLanguageModeling(tokenizer, mlm=False))
model = AutoModelForMaskedLM.from_pretrained("../bert-base-chinese/")
args = TrainingArguments(
output_dir="./causal_lm",
per_device_train_batch_size=2,
gradient_accumulation_steps=16,
logging_steps=10,
num_train_epochs=1,
#fp16=True
)
trainer = Trainer(
args=args,
model=model,
tokenizer=tokenizer,
train_dataset=tokenized_ds,
data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=True, mlm_probability=0.15)
)
trainer.train()