[fix] PretrainDataset 按 token id 屏蔽 padding,会误伤正文里字面的 <|endoftext|>
pad_token 是 <|endoftext|>(id 0)。正文里字面出现这个串时会被编成同一个 id, 而 labels[input_ids == pad_token_id] = -100 是按 token id 屏蔽的, 于是这个真实的正文 token 被当成 padding 从 loss 里丢掉。 改为按位置屏蔽 labels[n_real:] = -100,n_real = len(bos + 正文 + eos)。 padding 只可能出现在序列尾部,所以按位置屏蔽在语义上更准确,也更便宜。 SFTDataset 不受影响:它的 generate_labels 从全 -100 出发、扫描 assistant 区间来填,不依赖 pad id。pull/861/head
parent
cc312c1cc6
commit
d6401cbb92
|
|
@ -48,10 +48,15 @@ class PretrainDataset(Dataset):
|
|||
sample = self.samples[index]
|
||||
tokens = self.tokenizer(str(sample['text']), add_special_tokens=False, max_length=self.max_length - 2, truncation=True).input_ids
|
||||
tokens = [self.tokenizer.bos_token_id] + tokens + [self.tokenizer.eos_token_id]
|
||||
input_ids = tokens + [self.tokenizer.pad_token_id] * (self.max_length - len(tokens))
|
||||
n_real = len(tokens) # bos + 正文 + eos,后面才是 padding
|
||||
input_ids = tokens + [self.tokenizer.pad_token_id] * (self.max_length - n_real)
|
||||
input_ids = torch.tensor(input_ids, dtype=torch.long)
|
||||
labels = input_ids.clone()
|
||||
labels[input_ids == self.tokenizer.pad_token_id] = -100
|
||||
# 按位置屏蔽,而不是按 token id。pad_token 是 <|endoftext|>(id 0),
|
||||
# 正文里字面出现这个串时会被编成同一个 id
|
||||
# (tokenizer('前面<|endoftext|>后面') -> [938, 605, 0, 701, 605]),
|
||||
# 用 `input_ids == pad_token_id` 会把这个真实的正文 token 一起屏蔽掉。
|
||||
labels[n_real:] = -100
|
||||
return input_ids, labels
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue