【BERT-多标签文本分类实战】之六——数据加载与模型代码

本文涉及的产品
模型训练 PAI-DLC,100CU*H 3个月
交互式建模 PAI-DSW,每月250计算时 3个月
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
简介: 【BERT-多标签文本分类实战】之六——数据加载与模型代码

·请参考本系列目录:【BERT-多标签文本分类实战】之一——实战项目总览

·下载本实战项目资源:>=点击此处=<

  前5篇文章中,介绍了实战项目的前置知识,下面正式介绍项目的代码。本项目主要分为6部分:

image.png

  1、bert-base-uncasedbert的预训练文件;

  2、model:存放bert模型代码;

  3、Reuters-21578:存放数据集;

  4、run.py:项目运行主程序;

  5、utils.py:处理数据集并且预加载;

  6、train_eval.py:模型训练、验证、测试代码。

  本篇介绍:5、utils.py:处理数据集并且预加载2、model:存放bert模型代码

[1] 数据集文件的构成


  实战项目中数据集文件共6个:

image.png

  其中,reutersNLTK.xlsx是原数据集文件,训练集train.csv、验证集dev.csv、测试集test.csv是之前拆分好的,class.txt是标签目录,label.pkl是压缩存储的标签,方便快速读取用的。

[2] 加载数据集


  加载数据集的目标是:1)把文本数据转化成BERT模型的词序、Mask 码,为输入进BERT作准备;2)把文本标签转化成独热数组。

def build_dataset(config):
    # ## 读取标签
    label_list = pkl.load(open(config.label_path, 'rb'))
    print(f"标签个数======== {len(label_list)}")
    def convert_to_one_hot(Y, C):
        list = [[0 for i in C] for j in Y]
        for i, a in enumerate(Y):
            for b in a:
                if b in C:
                    list[i][C.index(b)] = 1
                else:
                    list[i][len(C) - 1] = 1
        return list
    def load_dataset(path, pad_size=32):
        df = pd.read_csv(path, encoding='utf-8', sep=',')
        data = df['content']
        sentences = data.values
        labels = []
        # 把标签读成数组
        for ls in df['label']:
            labels.append(re.compile(r"'(.*?)'").findall(ls))
        # 把数组转成独热
        labels_id = convert_to_one_hot(labels, label_list)
        contents = []
        count = 0
        for i, content in tqdm(enumerate(sentences)):
            label = labels_id[i]
            encoded_dict = config.tokenizer.encode_plus(
                content,  # 输入文本
                add_special_tokens=True,  # 添加 '[CLS]' 和 '[SEP]'
                max_length=pad_size,  # 填充 & 截断长度
                pad_to_max_length=True,
                padding='max_length',
                truncation='only_first',
                return_attention_mask=True,  # 返回 attn. masks.
                return_tensors='pt'  # 返回 pytorch tensors 格式的数据
            )
            token = config.tokenizer.tokenize(content)
            seq_len = len(token)
            count += seq_len
            contents.append((torch.squeeze(encoded_dict['input_ids'],0), label, seq_len, torch.squeeze(encoded_dict['attention_mask'],0)))
        print(f"数据集地址========{path}")
        print(f"数据集总词数========{count}")
        print(f"数据集文本数========{len(sentences)}")
        print(f"数据集文本平均词数========{count / len(sentences)}")
        return contents
    train = load_dataset(config.train_path, config.pad_size)
    dev = load_dataset(config.dev_path, config.pad_size)
    test = load_dataset(config.test_path, config.pad_size)
    return train, dev, test

  代码如上。

  首先,加载label.pkl文件。对于每一条文本,先提取它的标签,然后转化成独热数组。接下来通过tokenizer.encode_plus编码文本,得到input_idsattention_mask。最后把这些数据都存到数组contents中。

[3] 数据集加载器


  在第二节中,只是把显式的文本数据,转化成了数字化的Tensor格式。如何控制一个batch中有多少文本?如何控制数据的随机性等等?

  这就需要数据集加载器

class DatasetIterater(object):
    def __init__(self, batches, batch_size, device):
        self.batch_size = batch_size
        self.batches = batches
        self.n_batches = len(batches) // batch_size
        self.residue = False  # 记录batch数量是否为整数
        if len(batches) % self.n_batches != 0:
            self.residue = True
        self.index = 0
        self.device = device
    def _to_tensor(self, datas):
        x = torch.LongTensor([_[0].detach().numpy() for _ in datas]).to(self.device)
        y = torch.LongTensor([_[1] for _ in datas]).to(self.device)
        # pad前的长度(超过pad_size的设为pad_size)
        seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device)
        mask = torch.LongTensor([_[3].detach().numpy() for _ in datas]).to(self.device)
        return (x, seq_len, mask), y
    def __next__(self):
        if self.residue and self.index == self.n_batches:
            batches = self.batches[self.index * self.batch_size: len(self.batches)]
            self.index += 1
            batches = self._to_tensor(batches)
            return batches
        elif self.index >= self.n_batches:
            self.index = 0
            raise StopIteration
        else:
            batches = self.batches[self.index * self.batch_size: (self.index + 1) * self.batch_size]
            self.index += 1
            batches = self._to_tensor(batches)
            return batches
    def __iter__(self):
        return self
    def __len__(self):
        if self.residue:
            return self.n_batches + 1
        else:
            return self.n_batches
def build_iterator(dataset, config):
    iter = DatasetIterater(dataset, config.batch_size, config.device)
    return iter

  这个完全是自定义的数据加载器,直接用就可以,不展开介绍。

到这里,数据加载的部分就结束了。我们需要在数字化数据外套一个数据加载器的原因是,回头在调epochbatch_size这些参数的时候,数据加载器能够自动帮我们分配好这些文本数据。

[4] BERT模型代码


  BERT模型代码分为两个文件,一个是BaseConfig.py保存通用配置,一个是bert.py保存实际代码。

  BaseConfig.py

class BaseConfig(object):
    """配置参数"""
    def __init__(self, dataset):
        self.train_path = dataset + '/data/train.csv'                                   # 训练集
        self.dev_path = dataset + '/data/dev.csv'                                       # 验证集
        self.test_path = dataset + '/data/test.csv'                                     # 测试集
        self.label_path = dataset + '/data/label.pkl'                                   # 标签集
        self.vocab_path = dataset + '/data/vocab.pkl'                                   # 词表
        self.class_list = [x.strip() for x in open(
            dataset + '/data/class.txt', encoding='utf-8').readlines()]                 # 类别名单
        self.num_classes = len(self.class_list)                                         # 类别数
        self.n_vocab = 0                                                                # 词表大小,在运行时赋值
        """"""
        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')      # 设备
        """"""
        pretrained_path = './bert-base-uncased'
        self.bert = BertModel.from_pretrained(pretrained_path)
        self.tokenizer = BertTokenizer.from_pretrained(pretrained_path)
        """"""
        self.require_improvement = 1000                                     # 若超过1000batch效果还没提升,则提前结束训练
        self.num_epochs = 100                                               # epoch数
        self.batch_size = 32                                                # mini-batch大小
        self.pad_size = 150                                                 # 每句话处理成的长度(短填长切)
        self.learning_rate = 5e-3                                           # 学习率
        self.embed = 768

  bert.py

class Config(BaseConfig):
    """配置参数"""
    def __init__(self, dataset):
        BaseConfig.__init__(self, dataset)
        self.model_name = 'bert'
        self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt'  # 模型训练结果
        self.log_path = dataset + '/log/' + self.model_name
class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        self.bert = config.bert
        for param in self.bert.parameters():
            param.requires_grad = False
        self.fc = nn.Linear(config.embed, config.num_classes)
    def forward(self, x):
        context = x[0]  # 输入的句子
        mask = x[2]  # 对padding部分进行mask,和句子一个size,padding部分用0表示,如:[1, 1, 1, 1, 0, 0]
        _ = self.bert(context, attention_mask=mask)
        out = self.fc(_[1])  # [batch_size, hidden_size * 2] = [128, 256]
        return out

  这里就是定义了一个bert模型,和一个全连接层。把bert的输出放到fc中做分类。很朴素但是很吊。。。。。效果是真的甩开CNN、RNN系模型一截。

【注意】最终的输出,理解为概率!!

[5] 进行下一篇实战


  【BERT-多标签文本分类实战】之七——训练-评估-测试与运行主程序

相关文章
|
2月前
|
自然语言处理 PyTorch 算法框架/工具
掌握从零到一的进阶攻略:让你轻松成为BERT微调高手——详解模型微调全流程,含实战代码与最佳实践秘籍,助你应对各类NLP挑战!
【10月更文挑战第1天】随着深度学习技术的进步,预训练模型已成为自然语言处理(NLP)领域的常见实践。这些模型通过大规模数据集训练获得通用语言表示,但需进一步微调以适应特定任务。本文通过简化流程和示例代码,介绍了如何选择预训练模型(如BERT),并利用Python库(如Transformers和PyTorch)进行微调。文章详细说明了数据准备、模型初始化、损失函数定义及训练循环等关键步骤,并提供了评估模型性能的方法。希望本文能帮助读者更好地理解和实现模型微调。
88 2
掌握从零到一的进阶攻略:让你轻松成为BERT微调高手——详解模型微调全流程,含实战代码与最佳实践秘籍,助你应对各类NLP挑战!
|
2月前
|
机器学习/深度学习 自然语言处理 知识图谱
|
2月前
|
机器学习/深度学习 自然语言处理 算法
[大语言模型-工程实践] 手把手教你-基于BERT模型提取商品标题关键词及优化改进
[大语言模型-工程实践] 手把手教你-基于BERT模型提取商品标题关键词及优化改进
199 0
|
3月前
|
搜索推荐 算法
模型小,还高效!港大最新推荐系统EasyRec:零样本文本推荐能力超越OpenAI、Bert
【9月更文挑战第21天】香港大学研究者开发了一种名为EasyRec的新推荐系统,利用语言模型的强大文本理解和生成能力,解决了传统推荐算法在零样本学习场景中的局限。EasyRec通过文本-行为对齐框架,结合对比学习和协同语言模型调优,提升了推荐准确性。实验表明,EasyRec在多个真实世界数据集上的表现优于现有模型,但其性能依赖高质量文本数据且计算复杂度较高。论文详见:http://arxiv.org/abs/2408.08821
84 7
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
【AI大模型】BERT模型:揭秘LLM主要类别架构(上)
【AI大模型】BERT模型:揭秘LLM主要类别架构(上)
|
4月前
|
算法 异构计算
自研分布式训练框架EPL问题之帮助加速Bert Large模型的训练如何解决
自研分布式训练框架EPL问题之帮助加速Bert Large模型的训练如何解决
|
7月前
|
机器学习/深度学习 人工智能 开发工具
如何快速部署本地训练的 Bert-VITS2 语音模型到 Hugging Face
Hugging Face是一个机器学习(ML)和数据科学平台和社区,帮助用户构建、部署和训练机器学习模型。它提供基础设施,用于在实时应用中演示、运行和部署人工智能(AI)。用户还可以浏览其他用户上传的模型和数据集。Hugging Face通常被称为机器学习界的GitHub,因为它让开发人员公开分享和测试他们所训练的模型。 本次分享如何快速部署本地训练的 Bert-VITS2 语音模型到 Hugging Face。
如何快速部署本地训练的 Bert-VITS2 语音模型到 Hugging Face
|
7月前
|
PyTorch 算法框架/工具
Bert Pytorch 源码分析:五、模型架构简图 REV1
Bert Pytorch 源码分析:五、模型架构简图 REV1
102 0
|
7月前
|
PyTorch 算法框架/工具
Bert Pytorch 源码分析:五、模型架构简图
Bert Pytorch 源码分析:五、模型架构简图
77 0
|
4月前
|
机器学习/深度学习 存储 自然语言处理
【NLP-新闻文本分类】3 Bert模型的对抗训练
详细介绍了使用BERT模型进行新闻文本分类的过程,包括数据集预处理、使用预处理数据训练BERT语料库、加载语料库和词典后用原始数据训练BERT模型,以及模型测试。
81 1

热门文章

最新文章