第一學習在情緒分析比賽中使用Paddlehub

這篇博客主要是記錄一下第一次學習使用Paddlehub來進行情感分析。(備註:這裏的代碼是參考一個比賽大佬的baseline,如果有侵權的話,可以聯繫我,我會刪除引用的code的。)

1.數據處理

該比賽原本的數據是採用GB2312編碼,如果用平常的讀.csv文件的方法可能行不通,所以我們可以先通過將數據文件的編碼格式轉換爲通常的utf-8格式。通過寫一個函數,函數的功能無非是讀文件,然後寫文件,具體代碼如下所示。這裏要注意一下,數據文件經過一次數據轉化就可以了,不然重複轉化,因爲文件本身已經是utf-8編碼格式,如果再用其他編碼格式讀取內容在,重新寫會,文件數據就會被破壞。

# 轉換編碼
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('data/data22724/nCov_10k_test.csv')
re_encode('data/data22724/nCoV_100k_train.labled.csv')

當數據文件的編碼格式修改位utf-8之後,我們就可以用平常習慣的方式進行讀取數據了。


# 讀取數據
import pandas as pd
train_labled = pd.read_csv('data/data22724/nCoV_100k_train.labled.csv', encoding='utf-8')
test = pd.read_csv('data/data22724/nCov_10k_test.csv', encoding='utf-8')

得到數據之後,查看一下數據的shape,以及查看數據的columns。

print(train_labled.shape)
print(test.shape)
print(train_labled.columns)

然後觀察訓練集和測試集的部分數據情況。

train_labled.head(3)
test.head(3)

該比賽是對文本數據進行情感傾向分類的,共有三個類別:-1(消極),0(中性),1(積極)。所以我們要觀察一下數據label的分佈情況。

# 標籤分佈
%matplotlib inline
train_labled['情感傾向'].value_counts(normalize=True).plot(kind='bar');

經觀察圖形可知,訓練集數據的label裏面有一些異常異常label數據,然後就需要將異常數據進行剔除。

# 清除異常標籤數據
train_labled = train_labled[train_labled['情感傾向'].isin(['-1','0','1'])]

然後對文本內容的長度進行信息分析。

train_labled['微博中文內容'].str.len().describe()

2.構建模型

2.1paddlehub簡介

(引用內容來源:https://yunyaniu.blog.csdn.net/article/details/104404833)
此次不使用通常使用的機器學習模型或者是tensorflow等深度學習模型,而使用一種新接觸的Paddlehub進行構建模型,下面先簡單介紹一下什麼是Paddlehub。

PaddleHub是飛槳預訓練模型管理和遷移學習工具,通過PaddleHub開發者可以使用高質量的預訓練模型結合Fine-tune API快速完成遷移學習到應用部署的全流程工作。其提供了飛槳生態下的高質量預訓練模型,涵蓋了圖像分類、目標檢測、詞法分析、語義模型、情感分析、視頻分類、圖像生成、圖像分割、文本審覈、關鍵點檢測等主流模型。更多模型詳情請查看官網:https://www.paddlepaddle.org.cn/hub

基於預訓練模型,PaddleHub支持以下功能:
1)模型即軟件,通過Python API或命令行實現快速預測,更方便地使用PaddlePaddle模型庫。
2)遷移學習,用戶通過Fine-tune API,只需要少量代碼即可完成自然語言處理和計算機視覺場景的深度遷移學習。
3)服務化部署,簡單一行命令即可搭建屬於自己的模型的API服務。
4)超參優化,自動搜索最優超參,得到更好的模型效果。
GitHub地址:PaddleHub發佈最新版本1.5.0,https://github.com/PaddlePaddle/PaddleHub

PaddlePaddle 出品的預訓練模型管理和遷移學習工具,便捷地獲取PaddlePaddle生態下的預訓練模型,完成模型的管理和一鍵預測。配合使用Fine-tune API,可以基於大規模預訓練模型快速完成遷移學習,讓預訓練模型能更好地服務於用戶特定場景的應用。

其使用流程如下:
1)將數據整理成特定格式
2)定義Dataset數據類
3)加載模型
4)構建reader數據讀取接口
5)確定finetune訓練策略
6)配置finetune參數
7)確定任務,開始finetune(訓練)
8)預測

以上流程每個步驟只需一兩句代碼即可完成,使得我們可以快速得到解決方案。

2.2具體構建模型

首先,我們需要安裝Paddlehub庫,根據我之前的安裝經驗,我建議,按照如下安裝順序可能比較容易安裝成功。

!pip install paddlepaddle
!pip install PaddlePaddle
!pip install paddlehub

然後測試一下paddlehub是否安裝成功。

import paddlehub as hub

paddlehub構建的模型的文本任務輸入黨的數據格式如下所示:
在這裏插入圖片描述
我們將數據劃分爲訓練集和驗證集,比例爲8:2, 然後保存爲文本文件,兩列需用tab分隔符隔開。

# 劃分驗證集,保存格式  text[\t]label
from sklearn.model_selection import train_test_split

train_labled = train_labled[['微博中文內容', '情感傾向']]
train, valid = train_test_split(train_labled, test_size=0.2, random_state=2020)
train.to_csv('/home/aistudio/data/data22724/train.txt', index=False, header=False, sep='\t')
valid.to_csv('/home/aistudio/data/data22724/valid.txt', index=False, header=False, sep='\t')

加載文本類自定義數據集,用戶僅需要繼承基類BaseNLPDatast,修改數據集存放地址以及類別即可。這裏我們沒有帶標籤的測試集,所以test_file直接用驗證集代替 “valid.txt” 。

# 自定義數據集
import os
import codecs #codecs專門用作編碼轉換
import csv

from paddlehub.dataset.base_nlp_dataset import BaseNLPDataset

class MyDataset(BaseNLPDataset):
    """DemoDataset"""
    def __init__(self):
        # 數據集存放位置
        self.dataset_dir = "/home/aistudio/data/data22724"
        super(MyDataset, self).__init__(
            base_path=self.dataset_dir,
            train_file="train.txt",
            dev_file="valid.txt",
            test_file="valid.txt",
            train_file_with_header=False,
            dev_file_with_header=False,
            test_file_with_header=False,
            # 數據集類別集合
            label_list=["-1", "0", "1"])

dataset = MyDataset()
for e in dataset.get_train_examples()[:3]:
    print("{}\t{}\t{}".format(e.guid, e.text_a, e.label))

這裏我們選擇加載ERNIE1.0的中文預訓練模型。ERNIE 1.0 通過建模海量數據中的詞、實體及實體關係,學習真實世界的語義知識。相較於 BERT 學習原始語言信號,ERNIE 直接對先驗語義知識單元進行建模,增強了模型語義表示能力。

其他模型見:https://github.com/PaddlePaddle/PaddleHub
只需修改name=‘xxx’ 就可以切換不同的模型

# 加載模型
import paddlehub as hub
module = hub.Module(name="ernie")

構建一個文本分類的reader,reader負責將dataset的數據進行預處理,首先對文本進行切詞,接着以特定格式組織並輸入給模型進行訓練。

通過max_seq_len可以修改最大序列長度,若序列長度不足,會通過padding方式補到max_seq_len, 若序列長度大於該值,則會以截斷方式讓序列長度爲max_seq_len, 這裏我們設置爲128。

# 構建Reader
reader = hub.reader.ClassifyReader(
    dataset=dataset,
    vocab_path=module.get_vocab_path(),
    sp_model_path=module.get_spm_path(),
    word_dict_path=module.get_word_dict_path(),
    max_seq_len=128)

選擇遷移優化策略。詳見 Strategy

此處我們設置最大學習率爲 learning_rate=5e-5。

權重衰減設置爲 weight_decay=0.01,其避免模型overfitting。

訓練預熱的比例設置爲 warmup_proportion=0.1, 這樣前10%的訓練step中學習率會逐步提升到learning_rate

# finetune策略
strategy = hub.AdamWeightDecayStrategy(
    weight_decay=0.01,
    warmup_proportion=0.1,
    learning_rate=5e-5)

設置配置,設置訓練時的epoch,batch_size,模型儲存路徑等參數。
這裏我們設置訓練輪數 num_epoch = 1,模型保存路徑 checkpoint_dir=“model”, 每100輪(eval_interval)對驗證集驗證一次評分,並保存最優模型。需要注意的是,use_cuda參數表示是否用GPU進行運行,如果不想用GPU的話,可以將use_cuda改爲False即可,

# 運行配置
config = hub.RunConfig(
    use_cuda=True,
    num_epoch=1,
    checkpoint_dir="model",
    batch_size=32,
    eval_interval=100,
    strategy=strategy)

組建Finetune Task
對於文本分類任務,我們需要獲取模型的池化層輸出,並在後面接上全連接層實現分類。

因此,我們先獲取module的上下文環境,包括輸入和輸出的變量,並從中獲取池化層輸出作爲文本特徵。再接入一個全連接層,生成Task。

比賽評價指標爲F1,因此設置metrics_choices=[“f1”]

# Finetune Task
inputs, outputs, program = module.context(
    trainable=True, max_seq_len=128)

# Use "pooled_output" for classification tasks on an entire sentence.
pooled_output = outputs["pooled_output"]

feed_list = [
    inputs["input_ids"].name,
    inputs["position_ids"].name,
    inputs["segment_ids"].name,
    inputs["input_mask"].name,
]

cls_task = hub.TextClassifierTask(
        data_reader=reader,
        feature=pooled_output,
        feed_list=feed_list,
        num_classes=dataset.num_labels,
        config=config,
        metrics_choices=["f1"])

開始finetune
我們使用finetune_and_eval接口就可以開始模型訓練,finetune過程中,會週期性的進行模型效果的評估。

# finetune
run_states = cls_task.finetune_and_eval()

模型訓練結束之後,進行測試集預測。
預測數據格式爲二維的list:

[[‘第一條文本’], [‘第二條文本’], […], …]

# 預測
import numpy as np
    
inv_label_map = {val: key for key, val in reader.label_map.items()}

# Data to be prdicted
data = test[['微博中文內容']].fillna(' ').values.tolist()

run_states = cls_task.predict(data=data)
results = [run_state.run_results for run_state in run_states]

生成預測結果

# 生成預測結果
proba = np.vstack([r[0] for r in results])
prediction = list(np.argmax(proba, axis=1))
prediction = [inv_label_map[p] for p in prediction]
        
submission = pd.DataFrame()
submission['id'] = test['微博id'].values
submission['id'] = submission['id'].astype(str) + ' '
submission['y'] = prediction
np.save('proba.npy', proba)
submission.to_csv('result.csv', index=False)
submission.head()

在這裏插入圖片描述
查看預測的具體結果

submission['text'] = test[['微博中文內容']].fillna(' ').values
submission['label'] = submission['y'].map({-1: '消極', 0: '中性', 1: '積極'})
display(submission[['text', 'label']][176:181])

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章