前言:

    首先容我絮叨一下,哈哈哈哈。这算是我第一次正式的参加数学建模竞赛吧!大一上期的时候,搞过一次,但当时啥也不懂,于是就GG了。

    这次参加了一下数维杯数学建模竞赛练练手,好巧不巧发现D题竟然是和自然语言处理(NLP)相关,于是瞬间想到了PaddleNLP,想着可以用一下。下面是比赛时候的内容稍加注释与修改,然后分享一下。

    也是借鉴了一些其他大佬的开源项目,然后东拼西凑凑出来的,呜呜呜~~

    整理的时候可能会有些疏漏,如果发现可及时联系,大家一起交流,还望各位海涵。

一、解压影评数据集:

%cd /home/aistudio/data/data32015/
!mv Dataset /home/aistudio/work/

二、配置NLP环境:

需要注意的是,由于数据集为自定义数据集,在“制作”Dataloader的时候由于某些原因,需要使用某些版本的paddlenlp。
这里需要稍微特别注意一下。

!pip install --upgrade paddlenlp==2.0.0b4 

三、数据处理与Dataset:

%cd /home/aistudio/work/
def get_data_list(file_path):
    data_list = []
    tf = open('infer_test.txt', 'w')
    with open(file_path) as f:
        for line in f.readlines():
            result = line.strip().split("	")
            if result[0] != '':
                sque = result[1].strip().split(' ')
                sentence = ''
                for i in range(len(sque)):
                    sentence += sque[i]
                tf.write('{}\n'.format(sentence))
                data_list.append([sentence, result[0]])
    return data_list
/home/aistudio/work
import paddle
import paddlenlp as ppnlp

class SelfDefinedDataset(paddle.io.Dataset):
    def __init__(self, data):
        super(SelfDefinedDataset, self).__init__()
        self.data = data

    def __getitem__(self, idx):
        return self.data[idx]

    def __len__(self):
        return len(self.data)
        
    def get_labels(self):
        return ['0','1']

train_list = get_data_list('Dataset/train.txt')
test_list = get_data_list('Dataset/test.txt')
val_list = get_data_list('Dataset/validation.txt')
print(train_list[1])

#train_ds, dev_ds, test_ds = ppnlp.datasets.ChnSentiCorp.get_datasets(['train', 'dev', 'test'])
train_ds, dev_ds, test_ds = SelfDefinedDataset.get_datasets([train_list, val_list, test_list])
print(train_ds[1])
['其实我对锦衣卫爱情很萌因为很言情小说可惜女主角我要不是这样被乔花去偷令牌青龙吃醋想出箭那里萌到让我想起雏菊里郑大叔徐子珊吴尊真是可怕他们完全不是电影料还有脱脱这个名字想要雷死观众导演到底想什么剧情混乱老套无趣对白更是白痴失望', '1']
['其实我对锦衣卫爱情很萌因为很言情小说可惜女主角我要不是这样被乔花去偷令牌青龙吃醋想出箭那里萌到让我想起雏菊里郑大叔徐子珊吴尊真是可怕他们完全不是电影料还有脱脱这个名字想要雷死观众导演到底想什么剧情混乱老套无趣对白更是白痴失望', '1']
%cd /home/aistudio/work/
# 下载词汇表文件word_dict.txt,用于构造词-id映射关系。

from utils import load_vocab, convert_example

# 加载词表
vocab = load_vocab('./senta_word_dict.txt')

for k, v in vocab.items():
    print(k, v)
    break
/home/aistudio/work
[PAD] 0

四、Dataloader数据加载:

import numpy as np
from functools import partial

import paddle.nn as nn
import paddle.nn.functional as F
import paddlenlp as ppnlp
from paddlenlp.data import Pad, Stack, Tuple
from paddlenlp.datasets import MapDatasetWrapper

from utils import load_vocab, convert_example
# Reads data and generates mini-batches.
def create_dataloader(dataset,
                      trans_function=None,
                      mode='train',
                      batch_size=1,
                      pad_token_id=0,
                      batchify_fn=None):
    if trans_function:
        dataset = dataset.apply(trans_function, lazy=True)

    # return_list 数据是否以list形式返回
    # collate_fn  指定如何将样本列表组合为mini-batch数据。传给它参数需要是一个callable对象,需要实现对组建的batch的处理逻辑,并返回每个batch的数据。在这里传入的是`prepare_input`函数,对产生的数据进行pad操作,并返回实际长度等。
    dataloader = paddle.io.DataLoader(
        dataset,
        return_list=True,
        batch_size=batch_size,
        collate_fn=batchify_fn)
        
    return dataloader

# python中的偏函数partial,把一个函数的某些参数固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
trans_function = partial(
    convert_example,
    vocab=vocab,
    unk_token_id=vocab.get('[UNK]', 1),
    is_test=False)

# 将读入的数据batch化处理,便于模型batch化运算。
# batch中的每个句子将会padding到这个batch中的文本最大长度batch_max_seq_len。
# 当文本长度大于batch_max_seq时,将会截断到batch_max_seq_len;当文本长度小于batch_max_seq时,将会padding补齐到batch_max_seq_len.
batchify_fn = lambda samples, fn=Tuple(
    Pad(axis=0, pad_val=vocab['[PAD]']),  # input_ids
    Stack(dtype="int64"),  # seq len
    Stack(dtype="int64")  # label
): [data for data in fn(samples)]


train_loader = create_dataloader(
    train_ds,
    trans_function=trans_function,
    batch_size=128,
    mode='train',
    batchify_fn=batchify_fn)
dev_loader = create_dataloader(
    dev_ds,
    trans_function=trans_function,
    batch_size=128,
    mode='validation',
    batchify_fn=batchify_fn)
test_loader = create_dataloader(
    test_ds,
    trans_function=trans_function,
    batch_size=128,
    mode='test',
    batchify_fn=batchify_fn)

五、LSTMODEL网络搭建:

from LSTMmodel import LSTMModel
import paddle

model= LSTMModel(
        len(vocab),
        2,
        direction='bidirectional',
        padding_idx=vocab['[PAD]'])
lstmmodel = paddle.Model(model)

六、训练配置与网络训练:

optimizer = paddle.optimizer.Adam(
        parameters=model.parameters(), learning_rate=5e-5)

loss = paddle.nn.CrossEntropyLoss()
metric = paddle.metric.Accuracy()

lstmmodel.prepare(optimizer, loss, metric)

# 设置visualdl路径
log_dir = './visualdl'
callback = paddle.callbacks.VisualDL(log_dir=log_dir)

lstmmodel.fit(train_loader, dev_loader, epochs=30, save_dir='./checkpoints', save_freq=30, callbacks=callback)

七、模型推理:

label_map={0:"negtive", 1:"positive"}
results = lstmmodel.predict(test_loader, batch_size=128)[0]
predictions = []

for batch_probs in results:
    # 映射分类label
    idx = np.argmax(batch_probs, axis=-1)
    idx = idx.tolist()
    labels = [label_map[i] for i in idx]
    predictions.extend(labels)

# 看看预测数据前5个样例分类结果
for idx, data in enumerate(test_ds.data[30:]):
    print('Data: {} \t Label: {}'.format(data[0], predictions[idx]))

Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐