{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## senti_c: 基於Transformer的繁體中文情感分析工具\n",
"\n",
"senti_c為一個基於Transformer模型Bidirectional Encoder Representations from Transformers (BERT)所提供的預訓練模型bert-base-chinese精進開發的繁體中文情感分析工具。\n",
"\n",
"senti_c的主要功能包含:\n",
"1. 句子層級的情感分類 (i.e., sentence-level sentiment classification)。\n",
"2. 屬性情感分析,包含屬性術語提取(Aspect Extraction)與屬性術語情感分類(Aspect-based Sentiment Analysis)功能。\n",
"\n",
"\n",
"為了能對繁體中文文本提供良好的性能,我們採用順序遷移學習技術、且以BERT作為模型架構,藉由設計預訓練策略和微調(Pre-training and fine-tuning)架構建構模型。\n",
"在順序遷移學習中的預訓練階段,我們採用繼續預訓練,並使用連續多任務學習模式,於每階段加入不同任務、利用所蒐集的資料集實際訓練,預訓練任務包含三個啟發自其他學者的任務:Masked Language Model (MLM)、Sentence Order Prediction (SOP)、與Aspect Category Sentiment Analysis (ACSA),這些任務能幫助模型更好的學習文本中的知識。\n",
"\n",
"另一方面,對於順序遷移學習中的微調階段,我們建構了五千句餐廳領域與一千句飯店領域的訓練資料,每句包含整句的正負面,以及屬性層級的標註。我們的最終模型模型比起現有的模型性能更加優良,尤其相對使用簡體情感分析工具更有明顯的優勢。相信對有繁體中文情感分析需求的使用者有一定的效用與價值。\n",
"\n",
"以下的說明假設你是在自己的機器上執行。另有[Google Colab](https://colab.research.google.com/drive/1OTs4xIueHt53vCd-SN52QOOJE0mcgizv?usp=sharing)版本供大眾參考。\n",
"\n",
"下面提供本工具的簡要說明。如果你使用本工具,請引用以下參考文獻:
\n",
"凃育婷(2020)。基於順序遷移學習開發繁體中文情感分析工具。國立臺灣大學資訊管理學研究所碩士論文,台北市。\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 執行環境\n",
"\n",
"senti_c目前在Python 3.7與3.8環境中測試過。需要[transformers](https://pypi.org/project/transformers/) Version 2.11.0,而transformers需要Pytorch 1.x與tensorflow 2.2.0。使用senti_c不一定要有GPU,但有GPU會讓執行速度加快許多。\n",
"\n",
"由於各種工具可能會造成的版本衝突問題,建議在[Python Virtual Environment](https://docs.python.org/3/tutorial/venv.html)下安裝與使用senti_c。\n",
"\n",
"以下的範例的執行環境為Ubuntu 20.04.2 LTS。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 不使用GPU,或GPU環境(包含Pytorch與Transformer)已經設置妥當的安裝方式\n",
"\n",
"如果不使用GPU (或不理會GPU驅動程式與函式庫相關問題),那安裝的過程大致上分為兩步驟: (1) 設定Python Virtual Environment, (2) 在Virtual Environment中安裝senti_c。\n",
"\n",
"### (1) 建立Python Virtual Environment\n",
"\n",
"以下的工作需在一個Terminal中執行。這個Terminal可以是在Jupyter Lab中開啟的Terminal,或是SSH連線至使用主機的Terminal。\n",
"\n",
"要建立Virtual Environment,首先選擇(或建立)一個工作目錄,如`/service/redstar/senti_c`,切換至此工作目錄。\n",
"```console\n",
"cd /service/redstar/senti_c\n",
"```\n",
"\n",
"設立名叫vm4sentic的Virtual Environment。這會建立一個叫vm4sentic的目錄:\n",
"```console\n",
"python3 -m venv vm4sentic\n",
"```\n",
"\n",
"啟動這個Virtual Environment:\n",
"```console\n",
"source vm4sentic/bin/activate\n",
"```\n",
"\n",
"### (2) 安裝senti_c\n",
"```console\n",
"pip3 install senti_c --no-binary=wrapt,termcolor,sacremoses\n",
"```\n",
"\n",
"其中`--no-binary=wrapt,termcolor,sacremoses`的目的是不使用**bdist_wheel**方式安裝wrapt,termcolor,sacremoses這三個套件(我認為這三個套件無法使用這個方式安裝)。如果你不介意看到一些錯誤訊息,可以直接使用`pip3 install senti_c`安裝senti_c。\n",
"\n",
"安裝完成後,Virtual Environment中應該會有所有senti_c會用到的套件。也就是說,我們可以開始使用senti_c了。\n",
"\n",
"以上的程序適用在沒有GPU的系統、不使用GPU的系統、或是GPU驅動程式與函式庫已經安裝完成,且合適的pytorch (需要Version 1.x)與tensorflow(需要Version 2.2.0)版本已經安裝完成的系統。\n",
"\n",
"安裝GPU驅動程式、函式庫、tensorflow、與pytorch是一個繁複的過程。網路上有許多相關的資訊。但如果你是第一次嘗試,失敗數次是很正常的。希望你越挫越勇。下面提供確認GPU驅動程式已經安裝完成的方式。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### GPU相關驅動程式\n",
"\n",
"如果你沒有GPU請跳過本步驟。如果你準備使用GPU(假設使用nvidia產品線),必須先確認相關的驅動程式與函式庫已經安裝妥當。如果一切都好,執行`nvidia-smi`指令應該會看到類似下面的輸出。\n",
"\n",
"```\n",
"Thu Apr 1 16:17:02 2021\n",
"+-----------------------------------------------------------------------------+\n",
"| NVIDIA-SMI 450.102.04 Driver Version: 450.102.04 CUDA Version: 11.0 |\n",
"|-------------------------------+----------------------+----------------------+\n",
"| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
"| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |\n",
"| | | MIG M. |\n",
"|===============================+======================+======================|\n",
"| 0 GeForce GTX 1080 Off | 00000000:01:00.0 Off | N/A |\n",
"| 29% 62C P5 23W / 210W | 0MiB / 8117MiB | 0% Default |\n",
"| | | N/A |\n",
"+-------------------------------+----------------------+----------------------+\n",
"| 1 GeForce GTX 1080 Off | 00000000:03:00.0 Off | N/A |\n",
"| 27% 62C P5 19W / 210W | 0MiB / 8119MiB | 0% Default |\n",
"| | | N/A |\n",
"+-------------------------------+----------------------+----------------------+\n",
"\n",
"+-----------------------------------------------------------------------------+\n",
"| Processes: |\n",
"| GPU GI CI PID Type Process name GPU Memory |\n",
"| ID ID Usage |\n",
"|=============================================================================|\n",
"| No running processes found |\n",
"+-----------------------------------------------------------------------------+\n",
"```\n",
"\n",
"如果執行`nvidia-smi`後是看到錯誤訊息,那就表示GPU驅動程式與函式庫的安裝有問題。這個部分請自行搜尋相關的說明文件。特別強調的是,沒有GPU也是可以使用senti_c的。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 使用句子層級的情感分類\n",
"\n",
"以下提供一個簡單的範例進行句子層級的情感分類。\n",
"建立一個名叫`sent_pred.py`的檔案,內容如下:\n",
"```python\n",
"from senti_c import SentenceSentimentClassification\n",
"\n",
"sentence_classifier = SentenceSentimentClassification(logging_level = \"warning\")\n",
"test_data = [\"我很喜歡這家店!超級無敵棒!\",\n",
" \"這個服務生很不親切...\",\n",
" \"這間Fridays的空間不大,座位安排略顯擁擠,尤其是有隔板的兩人桌,真的超級小。\",\n",
" \"唯一印象深刻的事... 蛤蜊好大顆,大蝦毛毛蟲好吃!\"]\n",
"result = sentence_classifier.predict(test_data, run_split = True, aggregate_strategy = False)\n",
"print(result.iloc[:, 1:])\n",
"```\n",
"\n",
"執行這個程式 (指令: `python3 sent_pred.py`)。結果如下:\n",
"```console\n",
" Sentences Preds\n",
"0 我很喜歡這家店! 正面\n",
"1 超級無敵棒! 正面\n",
"2 這個服務生很不親切... 負面\n",
"3 這間Fridays的空間不大,座位安排略顯擁擠,尤其是有隔板的兩人桌,真的超級小。 負面\n",
"4 唯一印象深刻的事... 蛤蜊好大顆,大蝦毛毛蟲好吃! 正面\n",
"```\n",
"*sentence_classifier*回傳的是一個Pandas DataFrame。我們取後面兩個Column,也就是每個句子與其正負面。值得一提的是,*sentence_classifier*回傳四種可能的結果: 正面、負面、中性、衝突。其中衝突指的是句子中同時有正面與負面情感。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 屬性情感分析\n",
"\n",
"以下提供一個簡單的範例進行句子層級的情感分類。 建立一個名叫aspect_pred.py的檔案,內容如下:\n",
"```python\n",
"from senti_c import AspectSentimentAnalysis\n",
"aspect_classifier = AspectSentimentAnalysis(logging_level = \"warning\")\n",
"test_data = [\"\"\"這間Fridays的空間不大,座位安排略顯擁擠,尤其是有隔板的兩人桌,真的超級小。服務人員態度很好,只是因為客人太多,感覺人手不足,要求東西常常要等好一陣子才來。如果希望有好一點的服務品質,建議避開週末用餐時段。\"\"\", \n",
" \"\"\"每次經過都會被台灣炒飯給吸引,決定給它一個機會踏進去嚐鮮!有點失望,因為炒飯一般般,飯糰好難吃,冷氣超冷,串燒不推薦! 唯一印象深刻的事... 蛤蜊好大顆,大蝦毛毛蟲好吃! 整體環境不差,服務也可以,但餐點很一般\"\"\"]\n",
"result = aspect_classifier.predict(test_data, output_result = \"all\")\n",
"\n",
"print(\"Extracted aspect terms and their polarity:\")\n",
"for i, aterms in enumerate(result['AspectTermAndSentimentExtraction']):\n",
" print(f\"Sentence {i}: {aterms}\")\n",
"\n",
"print(\"\\n ---\\nLabels for individual tokens:\")\n",
"nseg = len(result['InputWords'])\n",
"# result['AspectTermTags']\n",
"for seg in range(nseg):\n",
" print(f\"\\n* Sentence {seg}:\")\n",
" a1 = result['InputWords'][seg]\n",
" a2 = result['AspectTermAndSentimentTags'][seg]\n",
" for x1, x2 in zip(a1, a2):\n",
" print(f\"{x1}({x2}) \", end = \"\")\n",
"\n",
"print(\"\")\n",
"\n",
"```\n",
"\n",
"執行這個程式 (指令: python3 aspect_pred.py)。結果如下:\n",
"\n",
"\n",
"```console\n",
"Extracted aspect terms and their polarity:\n",
"Sentence 0: [('空間', 'NEG'), ('座位安排', 'NEG'), ('服務人員態度', 'POS'), ('人', 'NEG'), ('服務品質', 'NEG')]\n",
"Sentence 1: [('炒飯', 'POS'), ('炒飯', 'NEG'), ('飯糰', 'NEG'), ('串燒', 'NEG'), ('蛤蜊', 'POS'), ('環境', 'POS'), ('服\n",
"務', 'POS'), ('餐點', 'NEG')]\n",
"\n",
" ---\n",
"Labels for individual tokens:\n",
"\n",
"* Sentence 0:\n",
"這(O-O) 間(O-O) F(O-O) r(O-O) i(O-O) d(O-O) a(O-O) y(O-O) s(O-O) 的(O-O) 空(B-NEG) 間(I-NEG) 不(O-O) 大(O-O) ,(O-O) 座(B-NEG) 位(I-NEG) 安(I-NEG) 排(I-NEG) 略(O-O) 顯(O-O) 擁(O-O) 擠(O-O) ,(O-O) 尤(O-O) 其(O-O) 是(O-O) 有(O-O) 隔(O-O) 板(O-O) 的(O-O) 兩(O-O) 人(O-O) 桌(O-O) ,(O-O) 真(O-O) 的(O-O) 超(O-O) 級(O-O) 小(O-O) 。(O-O) 服(B-POS) 務(I-POS) 人(I-POS) 員(I-POS) 態(I-POS) 度(I-POS) 很(O-O) 好(O-O) ,(O-O) 只(O-O) 是(O-O) 因(O-O) 為(O-O) 客(O-O) 人(O-O) 太(O-O) 多(O-O) ,(O-O) 感(O-O) 覺(O-O) 人(B-NEG) 手(O-NEG) 不(O-O) 足(O-O) ,(O-O) 要(O-O) 求(O-O) 東(O-O) 西(O-O) 常(O-O) 常(O-O) 要(O-O) 等(O-O) 好(O-O) 一(O-O) 陣(O-O) 子(O-O) 才(O-O) 來(O-O) 。(O-O) 如(O-O) 果(O-O) 希(O-O) 望(O-O) 有(O-O) 好(O-O) 一(O-O) 點(O-O) 的(O-O) 服(B-NEG) 務(I-NEG) 品(I-NEG) 質(I-NEG) ,(O-O) 建(O-O) 議(O-O) 避(O-O) 開(O-O) 週(O-O) 末(O-O) 用(O-O) 餐(O-O) 時(O-O) 段(O-O) 。(O-O)\n",
"* Sentence 1:\n",
"每(O-O) 次(O-O) 經(O-O) 過(O-O) 都(O-O) 會(O-O) 被(O-O) 台(O-O) 灣(O-O) 炒(B-POS) 飯(I-POS) 給(O-O) 吸(O-O) 引(O-O) ,(O-O) 決(O-O) 定(O-O) 給(O-O) 它(O-O) 一(O-O) 個(O-O) 機(O-O) 會(O-O) 踏(O-O) 進(O-O) 去(O-O) 嚐(O-O) 鮮(O-O) !(O-O) 有(O-O) 點(O-O) 失(O-O) 望(O-O) ,(O-O) 因(O-O) 為(O-O) 炒(B-NEG) 飯(I-NEG) 一(O-O) 般(O-O) 般(O-O) ,(O-O) 飯(B-NEG) 糰(I-NEG) 好(O-O) 難(O-O) 吃(O-O) ,(O-O) 冷(O-O) 氣(O-O) 超(O-O) 冷(O-O) ,(O-O) 串(B-NEG) 燒(I-NEG) 不(O-O) 推(O-O) 薦(O-O)\n",
"!(O-O) 唯(O-O) 一(O-O) 印(O-O) 象(O-O) 深(O-O) 刻(O-O) 的(O-O) 事(O-O) .(O-O) .(O-O) .(O-O) 蛤(B-POS) 蜊(I-POS) 好(O-O) 大(O-O) 顆(O-O) ,(O-O) 大(O-POS) 蝦(I-POS) 毛(O-O) 毛(O-O) 蟲(O-O) 好(O-O) 吃(O-O) !(O-O) 整(O-O) 體(O-O) 環(B-POS)\n",
"境(I-POS) 不(O-O) 差(O-O) ,(O-O) 服(B-POS) 務(I-POS) 也(O-O) 可(O-O) 以(O-O) ,(O-O) 但(O-O) 餐(B-NEG) 點(I-NEG) 很(O-O) 一(O-O) 般(O-O)\n",
"```\n",
"\n",
"*aspect_classifier*可以抓取輸入文本中的面向以及其對應的正負面情緒。如在第一個輸入中,空間為負面,座位安排為負面,服務人員態度為正面...等。當然,如果有需要,也可以將每個字元對應到其Label。這裡使用的Tags是Begin (B)、Inside (I)、Outside (O)搭配Positive (POS)與Negative (NEG)。\n",
"\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}