本文主要介紹論文Adapt or Get Left Behind: Domain Adaptation through BERT Language Model Finetuning for Aspect-Target Sentiment Classification[1]及其代碼實現(文中代碼塊可左右滑動噢)。
python
關於更多情感分析任務解讀關注文末『往期推薦』
linux
論文解讀
Introduction
最先的情感分析只是判斷文本(能夠是一句話或者一段長文本)的情感傾向,可是不少實際應用須要更細粒度的分析,這就出現了Aspect Based Sentiment Analysis (ABSA)任務,不瞭解的讀者能夠先參考情感分析簡介[2]。ABSA任務有兩種方法:ACD+ACSC和ATE+ATSC。git
ACD是Aspect Category Detection的縮寫,ACSC是Aspect Category Sentiment Classifica- tion的縮寫。ACD是一個多標籤(multi-label)分類問題,一個句子能夠同時說多個aspect category。以句子」I love their dumplings」爲例,ACD會把它分類爲food這個category,而ACSC會把這個aspect的情感分類爲正面。github
ATE是Aspect Target Extraction的縮寫,而ATSC是Aspect Target Sentiment Classification的縮寫。仍是以」I love their dumplings」爲例,ATE抽取的是dumplings,ATSC會把對於dumplings的情感分類爲正面。web
本文解決的就是ATSC的問題,也就是給定一個句子和Aspect Target(好比dumplings),判斷它的情感分類。注意:一個句子可能包括多個Aspect Target,好比」這個酒店的位置很好可是服務通常」,則它有」位置」和」服務」兩個Aspect Target,它們的情感分類分別是正面和負面。對於這個句子,會進行兩次預測,首先的輸入是」這個酒店的位置很好可是服務通常」+」位置」,輸出應該是正面;接着輸入是」這個酒店的位置很好可是服務通常」+」服務」,輸出是負面。json
方法
本文的方法很是簡單,就是使用BERT來進行分類,對BERT不熟悉的讀者能夠先參考BERT課程[3]。由於有句子和Target兩個輸入,因此在fine-tuning是會把它們拼接起來。假設句子是s,Target是t,則BERT在fine-tuning時的輸入是」[CLS] s [SEP] t [SEP]」。另外本文能取得很好結果的緣由就是使用了大量領域數據來pretraining BERT,由於Wiki等語料庫和評論的差異仍是比較大的。好比在wiki裏,」The touchscreen is an [MASK] device」,[MASK]極可能是」input」這樣的詞,而在評論裏,[MASK]更多是」amazing」這樣的詞。微信
論文使用了Yelp的酒店評論數據和Amazon的電子產品的評論數據來對BERT模型進行pretraining(初始爲Google模型),在酒店的ATSC任務上取得裏很好的成績,下圖是實驗結果。app
這篇文章的方法在酒店的數據集上效果很好,可是在筆記本電腦上並無取得最好的結果。dom
代碼
下載代碼
git clone https://github.com/deepopinion/domain-adapted-atsc.git
安裝
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python -m spacy download en_core_web_sm
mkdir -p data/raw/semeval2014 # creates directories for data
mkdir -p data/transformed
mkdir -p data/models
爲了進行fine-tuning,須要安裝pytorch、pytorch-transformers和apex。咱們首先安裝pytorch和pytorch-transformer:編輯器
pip install scipy sckit-learn
pip install https://download.pytorch.org/whl/cu100/torch-1.1.0-cp36-cp36m-linux_x86_64.whl
pip install pytorch-transformers tensorboardX
注意:上面安裝的是pytorch-1.1.0的GPU版本,它須要CUDA-10.0。
接着須要安裝apex:
cd ..
git clone https://github.com/NVIDIA/apex
cd apex
pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" ./
做者執行最後的pip install時碰到了一些小困難。它會提示nvcc的版本和編譯pytorch的不一致(由於pytorch是用pip而不是從源代碼安裝的),所以須要修改setup.py去掉下面的檢查的代碼:
check_cuda_torch_binary_vs_bare_metal(torch.utils.cpp_extension.CUDA_HOME)
去掉以後就能夠用最後pip install 安裝apex了。
準備fine-tuning BERT語言模型的數據
這個步驟是準備fine-tuning(實際上是在BERT基礎模型的基礎上繼續pretraining)語言模型的數據,做者也提供了他fine-tuning以後的模型,若是讀者不想本身fine-tuning語言模型能夠跳過這一步。
做者用來fine-tuning laptop任務的數據來自Amazon的電子產品的數據,參考這個連接[4],你們能夠發郵件給julian.mcauley@gmail.com來申請這個數據集。mcauley的郵件會給出下載的連接,讀者也須要下載的是reviews_Electronics.json.gz和meta_Electronics.json.gz兩個文件,注意別下載錯了。這兩個文件分別爲1.7GB和178MB。
而fine-tuning restaurant的數據集來自yelp,你們能夠點擊這裏[5]下載,下載獲得一個yelp_dataset.tar.gz。解壓它能夠獲得一個review.json文件,這個文件的大小是5.0GB。
把這些文件都放到data/raw下,相似:
meta_Electronics.json.gz review.json reviews_Electronics.json.gz
數據預處理:
python prepare_laptop_reviews.py
python prepare_restaurant_reviews.py
python prepare_restaurant_reviews.py --large # takes some time to finish
處理後在data/transformed/下會獲得laptop_corpus_1019917.txt這樣的文件,這是BERT pretraining須要的數據格式,咱們能夠看幾行:
$ head laptop_corpus_1019917.txt
This product has proven to be a communication breakthrough for my brother who has gone deaf in his elder years.
He is not computer literate and cannot type.
However, he quickly picked up on how to use this machine which plugs into the phone line.
I love it!
It has ended our one way conversations for he can now read whatever I send him and either respond by email or by calling (I can hear him just fine).
I think this is a very useful product!
I gave this product 1 star based on problems I have encountered with one I bought for my in-laws.
(See previous review).
文檔之間用一個空行分割開,每行表示一個句子,這是BERT須要的。
由於論文還把兩個數據集混合在一塊兒訓練,因此還有一個步驟是把兩個數據cat到一塊兒:
cd data/transformed
cat laptop_corpus_1011255.txt restaurant_corpus_1000004.txt > mixed_corpus.txt
下載SemEval 2014數據
請讀者去這裏[6]全部SemEval 2014的數據,下載後相似這樣:
.
├── SemEval-2014 ABSA Test Data - Gold Annotations
│ ├── ABSA_Gold_TestData
│ │ ├── Laptops_Test_Gold.xml
│ │ └── Restaurants_Test_Gold.xml
│ └── Laptops_Test_Gold.xml
└── SemEval-2014 ABSA Train Data v2.0 & Annotation Guidelines
├── Laptop_Train_v2.xml
└── Restaurants_Train_v2.xml
請參考上面的目錄結構放置解壓後的文件(若是是Windows的話可能文件名不能用&,那麼須要重命名,代碼也須要修改)。
咱們看一下SemEval-2014 ABSA Train Data v2.0 & Annotation Guidelines/Restaurants_Train_v2.xml這個文件:
1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 <sentences>
3 <sentence id="3121">
4 <text>But the staff was so horrible to us.</text>
5 <aspectTerms>
6 <aspectTerm term="staff" polarity="negative" from="8" to="13"/>
7 </aspectTerms>
8 <aspectCategories>
9 <aspectCategory category="service" polarity="negative"/>
10 </aspectCategories>
11 </sentence>
12 <sentence id="2777">
13 <text>To be completely fair, the only redeeming factor was the food, which was above average, but co uldn't make up for all the other deficiencies of Teodora.</text>
14 <aspectTerms>
15 <aspectTerm term="food" polarity="positive" from="57" to="61"/>
16 </aspectTerms>
17 <aspectCategories>
18 <aspectCategory category="food" polarity="positive"/>
19 <aspectCategory category="anecdotes/miscellaneous" polarity="negative"/>
20 </aspectCategories>
21 </sentence>
對於ATSC這個任務,輸入是」But the staff was so horrible to us.」和」staff」,輸出是negative這個分類。
由於SemEval 2014分類包括衝突(conflict),做者把衝突的數據去掉了。下面的腳本就是處理掉這些數據,首先是laptop的數據:
# laptops
# laptops without conflict label
python prepare_semeval_datasets.py \
--files "data/raw/semeval2014/SemEval-2014 ABSA Train Data v2.0 & Annotation Guidelines/Laptop_Train_v2.xml" \
--output_dir data/transformed/laptops_noconfl \
--istrain \
--noconfl
python prepare_semeval_datasets.py \
--files "data/raw/semeval2014/SemEval-2014 ABSA Test Data - Gold Annotations/ABSA_Gold_TestData/Laptops_Test_Gold.xml" \
--output_dir data/transformed/laptops_noconfl \
--noconfl
而後是restaurant:
# restaurants without conflict label
python prepare_semeval_datasets.py \
--files "data/raw/semeval2014/SemEval-2014 ABSA Train Data v2.0 & Annotation Guidelines/Restaurants_Train_v2.xml" \
--output_dir data/transformed/restaurants_noconfl \
--istrain \
--noconfl
python prepare_semeval_datasets.py \
--files "data/raw/semeval2014/SemEval-2014 ABSA Test Data - Gold Annotations/ABSA_Gold_TestData/Restaurants_Test_Gold.xml" \
--output_dir data/transformed/restaurants_noconfl \
--noconfl
最後是混合的訓練數據:
# mixed without conflict label
python prepare_semeval_datasets.py \
--files "data/raw/semeval2014/SemEval-2014 ABSA Train Data v2.0 & Annotation Guidelines/Restaurants_Train_v2.xml" \
"data/raw/semeval2014/SemEval-2014 ABSA Train Data v2.0 & Annotation Guidelines/Laptop_Train_v2.xml" \
--output_dir data/transformed/mixed_noconfl \
--istrain --noconfl
python prepare_semeval_datasets.py \
--files "data/raw/semeval2014/SemEval-2014 ABSA Test Data - Gold Annotations/ABSA_Gold_TestData/Restaurants_Test_Gold.xml" \
"data/raw/semeval2014/SemEval-2014 ABSA Test Data - Gold Annotations/ABSA_Gold_TestData/Laptops_Test_Gold.xml" \
--output_dir data/transformed/mixed_noconfl --noconfl
使用做者pretraining好的BERT語言模型來fine-tuning ATSC restaurant任務
咱們這裏只嘗試restaurant數據集,首先在這裏[7]下載做者pretraining好的BERT模型。下載後放到data/models下:
├── added_tokens.json
├── config.json
├── pytorch_model.bin
├── special_tokens_map.json
└── vocab.txt
而後基於這個模型進行監督的fine-tuning:
cd finetuning_and_classification
python run_glue.py \
--model_type bert \
--model_name_or_path ../data/models/restaurants_10mio_ep3 \
--do_train --evaluate_during_training --do_eval \
--logging_steps 100 --save_steps 1200 --task_name=semeval2014-atsc \
--seed 42 --do_lower_case \
--data_dir=../data/transformed/restaurants_noconfl \
--output_dir=../data/models/semeval2014-atsc-bert-ada-restaurants-restaurants \
--max_seq_length=128 --learning_rate 3e-5 --per_gpu_eval_batch_size=8 --per_gpu_train_batch_size=8 \
--gradient_accumulation_steps=1 --max_steps=800 --overwrite_output_dir --overwrite_cache --warmup_steps=120 --fp16
請根據GPU的內存修改per_gpu_eval_batch_size和per_gpu_train_batch_size兩個參數,我這裏使用是8。
最終做者獲得的結果爲:
10/21/2019 09:41:51 - INFO - __main__ - ***** Eval results *****
10/21/2019 09:41:51 - INFO - __main__ - acc = 0.8723214285714286
10/21/2019 09:41:51 - INFO - __main__ - f1_macro = 0.7945154951637271
基本和論文裏的87%的準確率以及80%的F1得分是差很少的。
本身使用Yelp來pretrainng語言模型
由於訓練1000萬的語料太費時間,我這裏只使用裏100萬的數據進行了3個epoch。
首先須要生成BERT須要的訓練數據,這可使用下面的腳本:
python pregenerate_training_data.py \
--train_corpus \
../data/transformed/restaurant_corpus_1000000.txt \
--bert_model \
bert-base-uncased \
--do_lower_case \
--output_dir \
dev_corpus_prepared/ \
--epochs_to_generate \
3 \
--max_seq_len \
256
接着進行pretraining:
python finetune_on_pregenerated.py \
--pregenerated_data dev_corpus_prepared/ \
--bert_model bert-base-uncased \
--do_lower_case \
--output_dir dev_corpus_finetuned/ \
--epochs 2 \
--train_batch_size 4 \
而後用本身pretraining的模型再進行fine-tuning:
python run_glue.py \
--model_type bert \
--model_name_or_path dev_corpus_finetuned/ \
--do_train --evaluate_during_training --do_eval \
--logging_steps 100 --save_steps 1200 --task_name=semeval2014-atsc \
--seed 42 --do_lower_case \
--data_dir=../data/transformed/restaurants_noconfl \
--output_dir=../data/models/semeval2014-atsc-bert-ada-restaurants-restaurants \
--max_seq_length=128 --learning_rate 3e-5 --per_gpu_eval_batch_size=8 --per_gpu_train_batch_size=8 \
--gradient_accumulation_steps=1 --max_steps=800 --overwrite_output_dir --overwrite_cache --warmup_steps=120 --fp16
這個和前面的惟一區別就是--model_name_or_path使用了咱們本身的模型。由於沒有使用大量的數據,最終的效果比做者pretraining的要差一些。從這裏也能看出,若是讀者要對本身領域的數據進行情感分析的話,最好仍是找大量未標註的語料庫pretraining以後在用監督數據進行fine-tuning效果會更好。
本文參考資料
Adapt or Get Left Behind: Domain Adaptation through BERT Language Model Finetuning for Aspect-Target Sentiment Classification: https://arxiv.org/abs/1908.11860
[2]情感分析簡介: /2019/09/25/sentiment-analysis-survey/
[3]BERT課程: /2019/03/05/bert-prerequisites/
[4]這個連接: http://jmcauley.ucsd.edu/data/amazon/amazon_readme.txt
[5]這裏: https://www.yelp.com/dataset/download
[6]這裏: http://metashare.ilsp.gr:8080/repository/search/?q=semeval+2014
[7]這裏: https://drive.google.com/file/d/1DmVrhKQx74p1U5c7oq6qCTVxGIpgvp1c/view?usp=sharing
- END -
![](http://static.javashuo.com/static/loading.gif)
記得把NewBeeNLP設爲星標哦
等你在看
本文分享自微信公衆號 - NewBeeNLP(NewBeeNLP)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。