首页 > 其他分享 >BERT训练之数据集处理(代码实现)

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

时间:2024-09-30 16:54:03浏览次数:8  
标签:BERT 训练 pred 代码 torch len mlm tokens positions

目录

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,训练,pred,代码,torch,len,mlm,tokens,positions
From: https://blog.csdn.net/Hiweir/article/details/142494483

相关文章

  • Python与自然语言处理库BERT
    Python与自然语言处理库BERT揭开BERT的神秘面纱:从零开始理解这个改变游戏规则的语言模型实战演练:用Python和BERT搭建你的第一个情感分析小助手不只是翻译:探索BERT在跨语言任务中的神奇表现文本生成新高度:利用BERT创造流畅连贯的文章段落优化与调优:让BERT更好地适应特定......
  • BERT训练环节(代码实现)
    1.代码实现#导包importtorchfromtorchimportnnimportdltools#加载数据需要用到的声明变量batch_size,max_len=1,64#获取训练数据迭代器、词汇表train_iter,vocab=dltools.load_data_wiki(batch_size,max_len)#其余都是二维数组#tokens,segments,valid......
  • 在Ubuntu下,为Vim配置C/C++代码补全
    1.安装vim-plugvim-plug是vim的一个插件管理器。(1)vim-plug的下载网址(2)新建目录~/.vim/autoload/(3)将 plug.vim文件放入该目录(4)添加vim-plug的代码到~/.vimrc文件,如下所示callplug#begin()"ListyourpluginsherePlug'tpope/vim-sensible'callplug#end......
  • 大规异构集群 混合并行分布式训练系统,解决算力不均衡问题 HETHUB
    视频教程在这:3.2大规模异构集群,混合并行分布式系统,解释算力不均衡问题HETHUB_哔哩哔哩_bilibili一、大规模异构集群出现的原因:同一种GPU数量有限难以构建大规模集群:训练大规模模型依赖于大量的计算资源。例如,训练GPT-4模型(1.8万亿个参数)需要25000个A100GPU。用一种GPU加速......
  • sizeof vs strlen - 关于代码可读性、性能考量和编译器优化
    1、起因经常在咱们代码里面见到sizeof(“HEADER”)这类代码来计算常量字符串的长度,例如上次的一个代码review:之所以这么写可能基于以下几点考虑:(1)sizeof()是运算符而不是函数调用,编译时确定而不是运行时执行,因此不占用运行时时间(2)strlen()是GLIBC标准库函数,运行时需要进行......
  • Kwin代码阅读——模板类
    首先,理解一些基本概念:1.模板:  在C++中,模板允许我们编写通用的代码,可以接受不同的数据类型,而不需要重复编写代码。模板有两种主要形式:函数模板和类模板。这里我们讨论的是类模板。2.继承:  继承是面向对象编程中的一个特性,允许一个类(子类)继承另一个类(父类)的属性和方......
  • [Python数据分析]最通俗入门Kmeans聚类分析,可视化展示代码。
     什么是k-means分析?【头条@William数据分析,看原版】    想象一下,你有一堆五颜六色的糖果,你想把它们按照颜色分成几堆。k-means分析就是这么一个自动分类的过程。它会根据糖果的颜色特征,把它们分成若干个组,每个组里的糖果颜色都比较相似。更专业一点说,k-means分析是一......
  • YOLOv8训练损失、mAP画图功能 | 支持多结果对比,多结果绘在一个图片(科研必备)
    鱼弦:公众号【红尘灯塔】,CSDN博客专家、内容合伙人、新星导师、全栈领域优质创作者、51CTO(Top红人+专家博主)、github开源爱好者(go-zero源码二次开发、游戏后端架构https://github.com/Peakchen)YOLOv8训练损失、mAP画图功能|支持多结果对比,多结果绘在一个图片(科研必备)......
  • pbootcms模板幻灯片调用代码大全
    在PbootCMS中,模板自带的幻灯片功能可以通过 {pboot:slide} 标签来实现。下面详细介绍该标签的使用方法及其控制参数。幻灯片标签详解标签语法html {pboot:slidegid=*num=*}<!--幻灯片内容-->{/pboot:slide}控制参数gid=*分组:必填参数,用于指定需要输......
  • 来欣赏10k分讨T1代码
    点击查看代码#include<bits/stdc++.h>#define_num[i]usingnamespacestd;constintmaxn=1e5+9;constintmod=998244353;intn,cnt,ans,s[7][maxn],num[maxn<<3];intlow(intx,intid){returnlower_bound(s[id]+1,s[id]+n+1,x)-s[id]-1;}intup(intx,int......