bert的训练数据的简单构建

一.简介

大家都知道原始bert预训练模型有两大任务:

1.masked lm:带mask的语言模型

2.next sentence prediction:是否为下一句话

bert模型的训练数据有三部分,如下:

1.字的token embeddings

2.句子的embeddings

3.句子位置的embeddings

下面就简单的构建一个bert的训练数据二.程序

import re
import math
import numpy as np
import random

text = (
    '这里是文本。' 
)

sentences = re.sub("[.。,“”,!?-]", '', text.lower()).split('n') # 过滤特殊符号
word_list = list("".join(sentences))
# 以下是词典的构建
word2idx = {'[pad]':0, '[cls]':1, '[sep]':2, '[unk]':3, '[mask]':4}

for i, w in enumerate(word_list):
    word2idx[w] = i + 5
idx2word = {i : w for i, w in enumerate(word2idx)}
vocab_size = len(word2idx)

token_list = list()
for sentence in sentences:
    arr = [word2idx[s] for s in list(sentence)]
    token_list.append(arr)

# 数据预处理,

maxlen = 120 # 最大句子长度
max_pred = 5 # 预测每个序列的单词个数
batch_size = 6
n_segments = 2 # 输入的几句话


'''
1.Next Sentence Prediction

50%的情况下,句子B是句子A的下一句,而50%的情况下,B不是A的下一句

2.Masked LM and the Masking Procedure
随机mask一句话中的15% token,拼接2句话

    80% 的时间:用[MASK]替换目标单词
    10% 的时间:用随机的单词替换目标单词
    10% 的时间:不改变目标单词
'''
def build_data():
    batch = []
    positive = negative = 0
    while (positive != (batch_size/2)) or (negative != (batch_size/2)):
        # 随机选择句子的index,作为A,B句
        tokens_a_index, tokens_b_index = random.randrange(len(sentences)), random.randrange(len(sentences))
        
        tokens_a, tokens_b = token_list[tokens_a_index], token_list[tokens_b_index]
        
        # 拼接A句与B句,格式为:[cls] + A句 + [sep] + B句 + [sep]
        input_ids = [word2idx['[cls]']] + tokens_a + [word2idx['[sep]']] + tokens_b + [word2idx['[sep]']]
        
        # 这里是为了表示两个不同的句子,如A句用0表示,B句用1表示
        segment_ids = [0] * (1 + len(tokens_a) + 1) + [1] * (len(tokens_b) + 1)
    
        # mask lm,15%随机选择token
        n_pred = min(max_pred, max(1, int(len(input_ids) * 0.15))) # 句子中的15%的token
        
        # 15%随机选择的token,去除特殊符号[cls]与[sep]
        cand_maked_pos = [i for i, token in enumerate(input_ids) if token != word2idx['[cls]'] and token != word2idx['[sep]']] # 候选masked 位置
        
        random.shuffle(cand_maked_pos)
        
        # 存储被mask的词的位置与token
        masked_tokens, masked_pos = [], []
        
        # 对input_ids进行mask, 80%的时间用于mask替换,10%的时间随机替换,10%的时间不替换。
        for pos in cand_maked_pos[:n_pred]:
            masked_pos.append(pos) # mask的位置
            masked_tokens.append(input_ids[pos]) # mask的token
            if random.random() < 0.8: # 80%的时间用mask替换
                input_ids[pos] = word2idx['[mask]']
            elif random.random() > 0.9: # 10%的时间随机替换
                index = random.randint(0, vocab_size - 1)
                while index < 5:
                    index = random.randint(0, vocab_size - 1) # 不包含几个特征符号
                input_ids[pos] = index
            
        # 进行padding,input_ids与segment_ids补齐到最大长度max_len
        n_pad = maxlen - len(input_ids)
        input_ids.extend([0] * n_pad)
        segment_ids.extend([0] * n_pad)
        #print('n_pad:{}'.format(n_pad))
        
        # 不同句子中的mask长度不同,所以需要进行相同长度补齐
        if max_pred > n_pred:
            n_pad = max_pred - n_pred
            masked_tokens.extend([0] * n_pad)
            masked_pos.extend([0] * n_pad)

        if ((tokens_a_index + 1) == tokens_b_index) and (positive < (batch_size / 2)):
            batch.append([input_ids, segment_ids, masked_tokens, masked_pos, True]) # isnext
            positive += 1
        elif ((tokens_a_index + 1) != tokens_b_index) and (negative < (batch_size / 2)):
            batch.append([input_ids, segment_ids, masked_tokens, masked_pos, False]) # notnext
            negative += 1
    return batch

'''
构建的数据里除了input_ids,segment_ids外,还有masked_tokens,masked_pos被mask掉的字和其位置(用于bert训练时用),isNext是否为下一句。
'''
batch = build_data()
input_ids, segment_ids, masked_tokens, masked_pos, isNext = zip(*batch)


class MyDataset(Data.Dataset):
    def __init__(self, input_ids, segment_ids, masked_tokens, masked_pos, isNext):
        self.input_ids = input_ids
        self.segment_ids = segment_ids
        self.masked_tokens = masked_tokens
        self.masked_pos = masked_pos 
        self.isNext = isNext
        
    def __len__(self):
        return len(self.input_ids)
    
    def __getitem__(self, idx):
        return self.input_ids[idx], self.segment_ids[idx], self.masked_tokens[idx], self.masked_pos[idx], self.isNext[idx]
    
loader = Data.DataLoader(MyDataset(input_ids, segment_ids, masked_tokens, masked_pos, isNext), batch_size, shuffle=True)

 当然这上面还缺了一个信息就是position embeddings,这个可以在bert模型中进行设置,如下:

  #位置信息  
  pos = torch.arange(0, src_len).unsqueeze(0).repeat(batch_size, 1)

参考:graykode - Overview

训练BERT模型使用自己的数据集,你可以按照以下步骤进行操作: 1. 准备一个包含你要训练数据的文本文件。这个文件应该包含你的领域特定的术语和黑话等内容,以便让BERT模型熟悉这些内容\[1\]。 2. 使用transformers库中的BertForPreTraining API来构建模型。首先,你需要创建一个BertConfig对象,其中vocab_size参数应该设置为你的词汇表大小加1。然后,使用BertForPreTraining类和配置对象来实例化模型\[2\]。 3. 进行训练。你可以使用一个循环来迭代训练数据集。在每个epoch中,遍历数据加载器中的数据,并将数据传递给模型。确保将输入数据转移到适当的设备上,并提供正确的标签。然后,通过调用模型的forward方法来获取模型的输出。计算损失并执行反向传播,最后更新模型的参数\[2\]。 4. 在训练之前,你需要确保你已经拥有Google Cloud账户,并且知道如何使用其shell和storage。激活Google Cloud的shell,并执行命令"ctpu up --name=yourname-tpu --tpu-size=v3-8 --preemptible"来启动TPU实例。其中,yourname是你自己定义的名称。添加"--preemptible"参数可以选择使用更便宜的预留实例,但可能会被Google随时终止\[3\]。 通过按照以上步骤,你可以使用自己的数据集训练BERT模型。这样,模型将能够更好地理解你的领域特定内容,并提供更好的性能。 #### 引用[.reference_title] - *1* *3* [使用自己的数据训练BERT](https://blog.csdn.net/bayou3/article/details/99655171)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v12^insert_chatgpt"}} ] [.reference_item] - *2* [【记录】使用transformers从头开始训练bert](https://blog.csdn.net/Finks_Chen/article/details/119334214)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v12^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值