基于ERNIE的疫情期间网民情绪识别模型

139 阅读3分钟

本文已参与「新人创作礼」活动.一起开启掘金创作之路。 基于ERNIE的疫情期间网民情绪识别模型

新型冠状病毒(COVID-19)感染的肺炎疫情发生对人们生活生产的方方面面产生了重要影响,并引发国内舆论的广泛关注,众多网民参与疫情相关话题的讨论。此模型能够对网民的疫情相关话题进行一个情绪分类。识别结果分为分别为:1(积极),0(中性)和-1(消极)。

\

训练数据准备 ,数据已csv格式进行存储

  1. 已标注的数据格式 labled.csv
    具体格式为

微博id,格式为整型。
微博发布时间,格式为xx月xx日 xx:xx。
发布人账号,格式为字符串。
微博中文内容,格式为字符串。
微博图片,格式为url超链接,[]代表不含图片。
微博视频,格式为url超链接,[]代表不含视频。
情感倾向,取值为{1,0,-1}。

\

  1. 未标注的数据格式 unlabled.csv
    具体格式为
    微博id,格式为整型。
    微博发布时间,格式为xx月xx日 xx:xx。
    发布人账号,格式为字符串。
    微博中文内容,格式为字符串。
    微博图片,格式为url超链接,[]代表不含图片。
    微博视频,格式为url超链接,[]代表不含视频。

\


代码实现


pip install paddle-ernie
import io
import math, json
import numpy as np
import pandas as pd
from PIL import Image

import matplotlib.pyplot as plt
import paddle

from paddle.io import DataLoader, Dataset

import warnings
warnings.filterwarnings("ignore")

paddle.__version__

# 读取数据 
def re_encode(path):
    with open(path, 'r', encoding='GB2312', errors='ignore') as file:
        lines = file.readlines()
    with open(path, 'w', encoding='utf-8') as file:
        file.write(''.join(lines))
        
re_encode('nCov_10k_test.csv') 
re_encode('nCoV_100k_train.labled.csv')

train_df = pd.read_csv('labled.csv')
train_df = train_df.drop(['微博id', '微博发布时间', '发布人账号', '微博图片'], axis=1)

test_df = pd.read_csv('nCov_10k_test.csv')
train_df = train_df.sample(10000)
train_df.head(5)

# 清洗数据 

train_df = train_df[train_df['情感倾向'].isin(['0', '1', '-1'])]
train_df['情感倾向'] = train_df['情感倾向'].astype(int)
train_df = train_df.dropna()

train_df['情感倾向'] += 1


train_df.head()

# 建模
import sys
import numpy as np
import pandas as pd
from sklearn.metrics import f1_score
import paddle as P

from ernie.tokenizing_ernie import ErnieTokenizer
from ernie.modeling_ernie import ErnieModelForSequenceClassification

BATCH=16
MAX_SEQLEN=50
LR=5e-5
EPOCH=1

ernie = ErnieModelForSequenceClassification.from_pretrained('ernie-1.0', num_labels=3)
optimizer = P.optimizer.Adam(LR,parameters=ernie.parameters())
tokenizer = ErnieTokenizer.from_pretrained('ernie-1.0')
def make_data(df):
    data = []
    for i, row in enumerate(df.iterrows()):
        text, label = row[1].微博中文内容, row[1].情感倾向
        text_id, _ = tokenizer.encode(text) # ErnieTokenizer 会自动添加ERNIE所需要的特殊token,如[CLS], [SEP]
        text_id = text_id[:MAX_SEQLEN]
        text_id = np.pad(text_id, [0, MAX_SEQLEN-len(text_id)], mode='constant')
        data.append((text_id, label))
    return data

train_data = make_data(train_df.iloc[:-2000])
val_data = make_data(train_df.iloc[-2000:])

def get_batch_data(data, i):
    d = data[i*BATCH: (i + 1) * BATCH]
    feature, label = zip(*d)
    feature = np.stack(feature)  # 将BATCH行样本整合在一个numpy.array中
    label = np.stack(list(label))
    feature = P.to_tensor(feature) # 使用to_variable将numpy.array转换为paddle tensor
    label = P.to_tensor(label)
    return feature, label

# 训练与验证 
for i in range(EPOCH):
    np.random.shuffle(train_data) # 每个epoch都shuffle数据以获得最佳训练效果;
    ernie.train()
    for j in range(len(train_data) // BATCH):
        feature, label = get_batch_data(train_data, j)
        loss, _ = ernie(feature, labels=label) 
        loss.backward()
        optimizer.minimize(loss)
        ernie.clear_gradients()
        if j % 50 == 0:
            print('Train %d: loss %.5f' % (j, loss.numpy()))
        
        # evaluate
        if j % 100 == 0:
            all_pred, all_label = [], []
            with P.no_grad():
                ernie.eval()
                for j in range(len(val_data) // BATCH):
                    feature, label = get_batch_data(val_data, j)
                    loss, logits = ernie(feature, labels=label)

                    all_pred.extend(logits.argmax(-1).numpy())
                    all_label.extend(label.numpy())
                ernie.train()
            acc = (np.array(all_label) == np.array(all_pred)).astype(np.float32).mean()
            print('Val acc %.5f' % acc)

预测代码


test_df['情感倾向'] = 0
test_df['微博中文内容'] = test_df['微博中文内容'].fillna('')
test_data = make_data(test_df.iloc[:])


all_pred, all_label = [], []
with P.no_grad():
    ernie.eval()
    for j in range(len(test_data) // BATCH):
        feature, label = get_batch_data(test_data, j)
        loss, logits = ernie(feature, labels=label)

        all_pred.extend(logits.argmax(-1).numpy())
        all_label.extend(label.numpy())

test_df['情感倾向'] = all_pred
test_df['情感倾向'] -= 1
test_df[['微博id', '情感倾向']].to_csv('submit.csv', index=None)