BERT训练之数据集处理(代码实现)

BERT训练之数据集处理(代码实现)代码 BERT 训练之数据集处理 代码实现 bert 数据集

大家好,欢迎来到IT知识分享网。

目录

1读取文件数据

 2.生成下一句预测任务的数据

 3.预测下一个句子

 4.生成遮蔽语言模型任务的数据

 5.从词元中得到遮掩的数据

 6.将文本转化为预训练数据集

7.封装函数类

8.调用


import os import random import torch import dltools

1读取文件数据

def _read_wiki(data_dir): #拼接文件路径 file_name = os.path.join(data_dir, 'wiki.train.tokens') #将输入参数中的两个名字拼接成一个完整的文件路径。 with open(file_name, 'r', encoding='utf-8') as f: #打开文件,逐行读取内容,并将每行作为一个元素添加到列表中。 lines = f.readlines() #大写字母转换为小写字母,获取分句之后的段落列表 paragraphs = [line.strip().lower().split('.') for line in lines if len(line.split('.')) >= 2] random.shuffle(paragraphs) #大陆那段落列表中的元素 return paragraphs _read_wiki('./wikitext-2/') #输出过长,不展示

 2.生成下一句预测任务的数据

def _get_next_sentence(sentence, next_sentence, paragraphs): if random.random() < 0.5: #若50%的概率发生时 is_next = True else: #否则,next_sentence就不是下一个句子,是随机抽取的其他句子 #paragraphs是三重列表的嵌套 #从所有列表中随机抽取一个段落,从这个段落中又随机抽取一个句子 next_sentence = random.choice(random.choice(paragraphs)) is_next =False return sentence, next_sentence, is_next 

 3.预测下一个句子

def _get_nsp_data_from_paragraph(paragraph, paragraphs, vocab, max_len): nsp_data_from_paragraph = [] #创建空列表,存放下一个句子的数据 for i in range(len(paragraph) - 1): #len(paragraph) - 1是因为索引是从0开始的,左闭右开,输出段落中的每一个句子的索引 #调用函数,获取用于预测下一个句子任务的数据 tokens_a, tokens_b , is_next = _get_next_sentence(paragraph[i], paragraph[i+1], paragraphs) #预测输入的两个句子结构是 --> <cls> tokens_a <sep> tokens_b <sep> # +3表示考虑 1个<cls> +2个<sep> if len(tokens_a) + len(tokens_b) + 3 > max_len: continue #这种情况超出了序列的最大长度,不需要 #将文本数据分割成词元(tokens)和句子分段(segments)。 #这个过程通常涉及到一系列的预处理步骤,如去除标点符号、转换为小写、数字处理等,以确保输入数据的标准化和一致性‌ tokens, segments = dltools.get_tokens_and_segments(tokens_a, tokens_b) nsp_data_from_paragraph.append((tokens, segments, is_next)) #三个数据以元祖的形式存放到列表中 return nsp_data_from_paragraph

 4.生成遮蔽语言模型任务的数据

#Mask Language Modle def _replace_mlm_tokens(tokens, candidate_pred_positions, num_mlm_preds, vocab): """ tokens:传入的词元 candidate_pred_positions:等待预测的词元位置索引编号(若传入句子的序列长度为100,那么它就是0-99) num_mlm_preds:预测遮掩的数量 vocab:整体词汇表 """ #为遮蔽语言模型的输入创建新的词元副本, 其中输入可能包含替换的<mask>或随机词元 mlm_input_tokens = [token for token in tokens] #复制词元数据,后期的替换不修改原数据 pred_positions_and_labels = [] #用于存放预测的词元位置和目标标签 #打乱顺序 等待预测的词元位置索引编号 random.shuffle(candidate_pred_positions) for mlm_pred_position in candidate_pred_positions: #遍历 #判断存放预测词元的个数是否已经超过了需要预测的数量 if len(pred_positions_and_labels) >= num_mlm_preds: break #若预测数量够了,就不预测了,直接退出当前for循环, continue是退出当前if判断 #否则,接着预测 mask_token = None #初始化变量:被15%抽中需要被替换的词元 为空 #80%的概率, 将抽取的15%的词元,替换成<mask>词元 if random.random() < 0.8: msaked_token = '<mask>' else: #否则,将剩下的其中10%的词元保持不变 从剩下的20%中抽取50%来表示 if random.random() < 0.5: mask_token = tokens[mlm_pred_position] else: #将剩下的其中10%的词元,用随机词替换 msaked_token = random.choice(vocab.idx_to_token) #将获取到的msaked_token按索引赋值替换原词元 mlm_input_tokens[mlm_pred_position] = mask_token #mlm_pred_position需要被预测的词元位置索引, tokens[mlm_pred_position]被遮掩预测的词元的标签(真实值是什么) pred_positions_and_labels.append((mlm_pred_position, tokens[mlm_pred_position])) return mlm_input_tokens, pred_positions_and_labels 

 5.从词元中得到遮掩的数据

# def _get_mlm_data_from_tokens(tokens, vocab): candidate_pred_positions = [] # tokens是一个字符串列表 for i, token in enumerate(tokens): # 在遮蔽语言模型任务中不会预测特殊词元 if token in ['<cls>', '<sep>']: continue candidate_pred_positions.append(i) # 遮蔽语言模型任务中预测15%的随机词元 num_mlm_preds = max(1, round(len(tokens) * 0.15)) mlm_input_tokens, pred_positions_and_labels = _replace_mlm_tokens( tokens, candidate_pred_positions, num_mlm_preds, vocab) pred_positions_and_labels = sorted(pred_positions_and_labels, key=lambda x: x[0]) pred_positions = [v[0] for v in pred_positions_and_labels] mlm_pred_labels = [v[1] for v in pred_positions_and_labels] return vocab[mlm_input_tokens], pred_positions, vocab[mlm_pred_labels]

 6.将文本转化为预训练数据集

def _pad_bert_inputs(examples, max_len, vocab): #词源需要预测的最大数量 max_num_mlm_preds = round(max_len * 0.15) all_tokens_ids, all_segments, valid_lens = [], [], [] all_pred_positions, all_mlm_weights, all_mlm_labels = [], [], [] nsp_labels = [] for (token_ids, pred_positions, mlm_pred_label_ids, segments, is_next) in examples: #对原有的tokens(每句话有长有短,补充《pad》使长度一致) all_tokens_ids.append(torch.tensor(token_ids + [vocab['<pad>']] * (max_len - len(token_ids)), dtype=torch.long)) all_segments.append(torch.tensor(segments + [0] * (max_len - len(segments)), dtype=torch.long)) #valid_lens不包括<pad>计数 valid_lens.append(torch.tensor(len(token_ids), dtype=torch.float32)) all_pred_positions.append(torch.tensor(pred_positions + [0] * (max_num_mlm_preds - len(pred_positions)), dtype=torch.long)) #填充词元的预测将通过乘以0权重在损失中过滤掉 all_mlm_weights.append(torch.tensor([1.0] * len(mlm_pred_label_ids) + [0.0] * (max_num_mlm_preds - len(pred_positions)), dtype=torch.float32)) all_mlm_labels.append(torch.tensor(mlm_pred_label_ids + [0] * (max_num_mlm_preds - len(mlm_pred_label_ids)), dtype=torch.long)) nsp_labels.append(torch.tensor(is_next, dtype=torch.long)) return (all_tokens_ids, all_segments, valid_lens, all_pred_positions, all_mlm_weights, all_mlm_labels, nsp_labels) 

7.封装函数类

class WikiTextDataset(torch.utils.data.Dataset): def __init__(self, paragraphs, max_len): #输入paragraphs[i]是代表段落的句子字符串列表 #输出paragraphs[i]是代表段落的句子列表,其中每个句子都是词元列表 paragraphs = [dltools.tokenize(paragraph, token='word') for paragraph in paragraphs] #获取句子的词元列表 sentences = [sentence for paragraph in paragraphs for sentence in paragraph] self.vocab = dltools.Vocab(sentences, min_freq=5, reserved_tokens=['<pad>', '<mask>', '<cls>', '<sep>']) #获取下一句子预测任务的数据 examples = [] for paragraph in paragraphs: examples.extend(_get_nsp_data_from_paragraph(paragraph, paragraphs, self.vocab, max_len)) #获取遮蔽语言模型任务的数据 examples = [(_get_mlm_data_from_tokens(tokens, self.vocab) + (segments, is_next)) for tokens, segments, is_next in examples] #填充输入 (self.all_token_ids, self.all_segments, self.valid_lens, self.all_pred_positions, self.all_mlm_weights, self.all_mlm_labels, self.nsp_labels) = _pad_bert_inputs(examples, max_len, self.vocab) def __getitem__(self, idx): return (self.all_token_ids[idx], self.all_segments[idx], self.valid_lens[idx], self.all_pred_positions[idx], self.all_mlm_weights[idx], self.all_mlm_labels[idx], self.nsp_labels[idx]) def __len__(self): return len(self.all_token_ids)

8.调用

def load_data_wiki(batch_size, max_len): """加载WikiText-2数据集""" num_workers = dltools.get_dataloader_workers() #快速获取或设置最佳的工作线程数 data_dir = './wikitext-2/' paragraphs = _read_wiki(data_dir) train_set = WikiTextDataset(paragraphs, max_len) train_iter = torch.utils.data.DataLoader(train_set, batch_size, shuffle=True, num_workers=num_workers) return train_iter, train_set.vocab 
batch_size, max_len = 512, 64 train_iter, vocab = load_data_wiki(batch_size, max_len) for (tokens_X, segments_X, valid_lens_x, pred_positions_X, mlm_weights_X, mlm_Y, nsp_y) in train_iter: print(tokens_X.shape, segments_X.shape, valid_lens_x.shape, pred_positions_X.shape, mlm_weights_X.shape, mlm_Y.shape, nsp_y.shape) break
torch.Size([512, 64]) torch.Size([512, 64]) torch.Size([512]) torch.Size([512, 10]) torch.Size([512, 10]) torch.Size([512, 10]) torch.Size([512])
len(vocab)

 20228

BERT训练之数据集处理(代码实现) 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/144960.html

(0)
上一篇 2025-04-22 22:45
下一篇 2024-12-01 09:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信