原帖的堆栈落在 F.embedding,而不是分类损失;因此应优先检查输入编号与嵌入表:
IndexError: index out of range in self
同一句 IndexError,要从 embedding 堆栈选对象
原题调用 BERT 时堆栈落在 embedding,优先核对 token ID,而不是先把分类 labels 降到某个范围。BERT 内还有词、位置、类型等不同嵌入表;词表范围合法后,仍需按完整堆栈继续缩小到具体那一张表。
在调用 BERT 前,检查实际 token ID、词表大小和序列长度。b_input_ids 是原题当前批输入,model 是正在训练的模型:
embedding = model.get_input_embeddings()
print("josh050608")
print("ids:", b_input_ids.shape, b_input_ids.dtype)
print("range:", b_input_ids.min().item(), b_input_ids.max().item())
print("embedding rows:", embedding.num_embeddings)
print("max positions:", getattr(model.config, "max_position_embeddings", None))
token ID 必须非负且小于输入 embedding 行数。若 tokenizer 与模型来自不同 checkpoint,改用配套 tokenizer;不要通过取模、截断 ID 等方法让越界消失,这会改变词义。
如果项目确实新增了 special tokens,先完成 tokenizer 的添加,再调用 model.resize_token_embeddings(len(tokenizer)),并在建立优化器前完成模型调整。保存模型时同时保存 tokenizer。仅更改 config.vocab_size 不会自动重建已有权重。
若 token 范围正常,继续从完整堆栈区分是词、位置还是 token_type embedding:检查序列是否超过位置表范围,手工 position_ids/token_type_ids 是否越界。原题传 token_type_ids=None,不应凭错误名就认定类别标签越界。
在 CPU 上对同一失败批次重跑有助于获得明确索引错误。修复后先完成一个 batch 前向,再验证 loss/backward;若用了新增 token,确认对应 embedding 已进入训练参数。原帖没有 tokenizer 和模型来源,无法确认具体是哪张表越界。
用小词表重现边界,并验证修复含义
下面是合成 Embedding 例子:有 5 行时合法编号为 0–4,编号 5 会越界。它不下载 BERT,也不冒充原题 tokenizer:
import torch
from torch import nn
table = nn.Embedding(5, 3)
good_ids = torch.tensor([[0, 4]], dtype=torch.long)
assert table(good_ids).shape == (1, 2, 3)
bad_ids = torch.tensor([[0, 5]], dtype=torch.long)
print("rows/range:", table.num_embeddings, bad_ids.min().item(), bad_ids.max().item())
try:
table(bad_ids)
except IndexError as exc:
print("out of table:", exc)
真实模型中若发现最大 token ID 大于等于 embedding 行数,先问它来自哪里。用错 tokenizer 应换配套版本;确实新增 token 才应扩展嵌入表。新增后的行需要训练,不是扩大维数后就自动具备语义。
若词 ID 正常,检查序列长度与 max_position_embeddings;手工 position_ids 的最大值也必须在表内。token_type_ids 的取值范围由模型类型表决定,不是任意句子编号。不要拿 token 词表大小去验证位置或类型编号。
新增 token 后在建立优化器前调整模型,保存时连同 tokenizer 一起保存,重载时检查两者长度与参数行数。验收使用同一失败批次先在 CPU 前向,再验证 loss/backward 和保存重载;取模或截断 token ID 可能消除越界,却把词义替换成了别的 token。
参考:原始求助帖;技术依据:Embedding(2.5)、Transformers BERT(4.46)、Transformers Tokenizer(4.46)。