使用HuggingFace微调预训练LLM时遇‘index out of range in self’错误
纯文本微调LLM时
trainer.train()抛出"index out of range in self"错误的排查与解决思路 问题背景
我是机器学习新手,正在做一个项目:用公司的杂志文章、播客转录文本和讨论线程数据微调预训练LLM,目标是为在线社区打造定制聊天机器人。使用HuggingFace Transformers的load_dataset加载非结构化纯文本后,执行trainer.train()约10秒就抛出**"index out of range in self"**错误,执行到该步骤前的代码均正常。
简化代码
base_model = "tiiuae/falcon-7b" # 已尝试mpt_7b、distilbert_base_uncased等模型,均报错 number_of_threads = 4 tokenizer = AutoTokenizer.from_pretrained(base_model, cache_dir=hugging_face_cache_dir) if tokenizer.pad_token is None: tokenizer.add_special_tokens({'pad_token': padding_token}) train_dataset = load_dataset('text', data_files={'train': '/path/to/my/train/files', 'test': '/path/to/my/test/files'}, cache_dir=hugging_face_cache_dir, sample_by="paragraph") tokenized_train_dataset = train_dataset.map( lambda examples: tokenizer(examples["text"], padding="max_length", truncation=True, return_tensors="np"), batched=True, num_proc=number_of_threads) val_dataset = load_dataset('text', data_files={'validation': val_split_filename}, cache_dir=hugging_face_cache_dir, sample_by="paragraph") tokenized_val_dataset = val_dataset.map( lambda examples: tokenizer(examples["text"], padding="max_length", truncation=True, return_tensors="np"), batched=True, num_proc=number_of_threads) train_dataset = tokenized_train_dataset['train'].shuffle(seed=42) eval_dataset = tokenized_val_dataset['validation'] model = AutoModel.from_pretrained(base_model, trust_remote_code=True, cache_dir=hugging_face_cache_dir) training_args = TrainingArguments( output_dir=FileMgr.checkpoint_batch_dir, evaluation_strategy=IntervalStrategy.EPOCH, save_strategy=IntervalStrategy.EPOCH, num_train_epochs=3, save_total_limit=2, per_device_train_batch_size=8, per_device_eval_batch_size=8, logging_dir=FileMgr.checkpoint_batch_dir, eval_steps=500, load_best_model_at_end=True, save_steps=500, remove_unused_columns=True ) metric = evaluate.load("accuracy") def compute_metrics(eval_pred): logits, labels = eval_pred predictions = np.argmax(logits, axis=-1) return metric.compute(predictions=predictions, references=labels) trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, compute_metrics=compute_metrics ) trainer.train()
数据集示例
Some data on the first line. Some data on the second line. And this continues on and on. We have tried putting entire magazine articles on this line, replacing newlines with [SEP]. We've also tried ensuring lines don't exceed the max seq length of a model, as explained below.
已尝试的排查操作
- 缓存目录设为C盘外路径,以管理员身份运行PyCharm,读写文件无异常
- 尝试多个模型(falcon-7b、mpt_7b、distilbert_base_uncased),均报错
- 最初将换行符替换为
[SEP]并添加该特殊token,后改为限制每行仅1024字符(远小于模型token序列长度),问题依旧 - 尝试保留/删除文件末尾空行、使用完整/小型数据集(仅3条训练样本)、调整批大小(1/8/500),均无效
- 完整代码中缓存分词数据集后,加载时提示"An error occurred while generating the dataset",怀疑数据集格式有误
附带问题
- 整篇文章放一行(超过模型序列长度)是否可行?
- 是否应将
sample_by设为"document"而非"paragraph"?
解决思路
核心问题定位:数据集与模型输入不匹配
模型类型与任务不兼容
你用的是AutoModel,但微调聊天机器人属于因果语言建模(CLM)任务,应该使用AutoModelForCausalLM。AutoModel仅输出隐藏层特征,没有语言建模头,和Trainer的训练逻辑冲突,会导致维度不匹配,触发索引越界错误。标签缺失
当前代码仅处理了输入的tokenization,但因果语言建模需要标签(通常是输入token本身,偏移一个位置)。你的compute_metrics尝试获取labels,但数据集未生成该字段,Trainer无法找到对应数据,引发索引错误。分词后数据格式问题
- 去掉
return_tensors="np",使用默认的列表格式,避免numpy数组在Dataset中引发的维度异常 - 必须添加
labels字段,可直接将input_ids复制为标签(忽略padding部分)
- 去掉
数据集格式修正
sample_by的选择:如果每个txt文件是完整文章,用document;如果txt内是按空行分割的段落,用paragraph。聊天机器人建议保留完整上下文片段,优先用document,再通过tokenizer的truncation=True和max_length自动处理过长文本,无需手动拆分。- 不要手动替换换行符为
[SEP],大部分LLM的tokenizer会自动处理换行;手动添加的[SEP]若未加入tokenizer词汇表,会被拆分为单个字符,导致数据混乱。
代码修正要点
- 替换模型加载代码:
model = AutoModelForCausalLM.from_pretrained(base_model, trust_remote_code=True, cache_dir=hugging_face_cache_dir) - 修改tokenize函数,生成标签:
用该函数替换原lambda,去掉def tokenize_function(examples): outputs = tokenizer(examples["text"], padding="max_length", truncation=True) # 因果语言建模的标签即为input_ids,复制后可用于计算损失 outputs["labels"] = outputs["input_ids"].copy() return outputsreturn_tensors="np" - 调整TrainingArguments:CLM任务默认用语言建模损失,若无需自定义评估,可移除
compute_metrics;若保留,需确保labels正确传递 - 合理设置pad_token:建议用
tokenizer.eos_token代替自定义padding_token(很多LLM无默认pad_token,用eos_token更适配)
附带问题解答
- 整篇文章放一行可行,tokenizer的
truncation=True会自动截断到模型的max_length,手动拆分反而可能破坏文本上下文连贯性。 sample_by的选择取决于数据结构:完整文章用document,段落集合用paragraph,聊天机器人场景优先保留完整上下文,推荐document。
内容的提问来源于stack exchange,提问作者capnchat
相关产品推荐
相关产品推荐

