## 玉山 NLP 應用挑戰賽
<center>
3rd. BlackBox Operator
</center>
<img style="border:0px" src="https://i.imgur.com/S7NY0GM.png">
----
### We OPEN the BOX!
所有的 code 都已經放在 [GitHub](https://github.com/BlackBoxOperator/GotchaTheNames) 上了,
不過因為訓練資料是主辦單位提供,故不能釋出。
這部份可能要讀者自行爬取並標記。
接著就來介紹一下這個比賽吧!
----
### Objective
```python
if classify(news) == AML then extract(news) else []
```
----
### limitation
由於是學期末看到的比賽,
比賽已經**開始快一個月**了。
----
### 趕趕趕
----
估計學期結束才能開始。
算一算 **7/6** 才可以開始做,
距離測試賽估計只有**兩個禮拜**,
之後離正式賽也只有**一個禮拜**可以調整模型。
###### (不過有之前做過的東西,可以偷懶一下。)
---
## 爬蟲 Crawling
-----
有了先前的基礎,
基本上只花了一個晚上就把資料都爬回來了。
爬蟲是相對容易,但是需要重複性勞動的工作,
以下介紹我是怎麼爬新聞的。
----
### Basic crawling
新聞網站大部份是動態網頁,
```
Server => template(content from database)
```
只要是同個網站的新聞,
大多會遵照一定的排版。
----
#### pandas & the domains
第一步就先來看看有哪些網站的排版要抓
```python
import re
import pandas as pd
from pprint import pprint
csv = pd.read_csv('tbrain_train_final_0610.csv')
webs = set(re.findall(r'(https?://)?([^/]+)', l)[0][1]
for l in csv['hyperlink'])
pprint(webs)
```
----
可以得到這 39 個 domain:
```python
{'ccc.technews.tw', 'domestic.judicial.gov.tw',
'ec.ltn.com.tw', 'ent.ltn.com.tw', 'estate.ltn.com.tw',
'finance.technews.tw', 'hk.on.cc', 'house.ettoday.net',
'm.ctee.com.tw', 'm.ltn.com.tw', 'money.udn.com',
'mops.twse.com.tw', 'news.cnyes.com', 'news.ebc.net.tw',
'news.ltn.com.tw', 'news.mingpao.com', 'news.tvbs.com.tw',
'ol.mingpao.com', 'sina.com.hk', 'technews.tw',
'tw.news.yahoo.com', 'www.bnext.com.tw',
'www.businesstoday.com.tw', 'www.chinatimes.com',
'www.cna.com.tw', 'www.coolloud.org.tw', 'www.cw.com.tw',
'www.ettoday.net', 'www.fsc.gov.tw', 'www.hbrtaiwan.com',
'www.hk01.com', 'www.managertoday.com.tw', 'udn.com',
'www.mirrormedia.mg', 'www.nextmag.com.tw', 'www.storm.mg',
'www.nownews.com', 'www.setn.com', 'www.wealth.com.tw'}
```
----
#### beautiful soup 4 & the selector
有了 domain 之後就是重複性的工作了。
----
農
----
舉個例子:http://finance.technews.tw/2019/09/06/palo-alto-networks-intends-to-acquire-zingbox/
按下 f12 後可以看到,
此網頁的 article tag 可以涵蓋所有內文,
之後我再把他 p tag 的內容抓出來就好。
----
<img src="https://i.imgur.com/2Jibg8j.png" width="60%">
----
把 39 個 domain 抓出來大概長這樣:
```python
fetch_table = {
'www.mirrormedia.mg': ['article', {}],
'www.coolloud.org.tw': ['div', {'class':'field-items'}],
'm.ctee.com.tw': ['div', {'class': 'entry-main'}],
# ...
'www.storm.mg': ['article', {}],
}
def find_article_args_by(url):
for domain in fetch_table:
if domain in url:
tag, attr = fetch_table[domain]
return { 'name': tag, 'attrs': attr }
print("cannot find domain pattern in", url)
```
----
```python
import re
import requests as rq
from functools import reduce
from operator import add
from bs4 import BeautifulSoup
url = 'https://www.storm.mg/article/1625523'
artics = BeautifulSoup(
rq.get(url, timeout = 10).text, "html.parser"
).findAll(**find_article_args_by(url))
dataBy = lambda f: reduce(add, [f(a) for a in artics])
ext1 = lambda a: a.findChildren("p")
ext2 = lambda a: a.find_all(r'^h[1-6]$')
print(' '.join([s for s in [p.get_text().strip()
for p in dataBy(ext1) + dataBy(ext2)]]))
```
----
抓到的文章為:
```
國安局特勤走私菸案今(23)日偵查終結,其中,最先被羈押禁見的總統府侍衛室少校吳宗憲雖只有訂1條790元的大衛杜夫(Davidoff),但由於他是本案主要的訂購及聯繫人,故北檢仍依違反《貪污治罪條例》及違反《稅捐稽徵法》等罪起訴吳宗憲。 據國安局調查報告,本案買菸者共76人,含國安局25人、侍衛室49人、憲兵警衛大隊2人,今日起訴吳宗憲、張恒嘉、前華航副總邱彰信等13人;另外,據北檢統計,本案總計下訂9441條菸,總金額為680萬2330元。(延伸閱讀:國安局私菸案今偵結 北檢起訴吳宗憲邱彰信等13人) 在涉案的國安特勤中,購買最多的為少校徐兆峰,一共購買1037條,但其中有792條是受妻子高中同學祁明昕所託下訂,其餘則為自用。徐、祁2人今日皆依違反《稅捐稽徵法》予以緩起訴,分別需繳交處分金60萬元及50萬元。
```
----
### Advenced crawling
#### wayback machine & the missing pages (404)
對於一些 404 的網頁,
我們可以想辦法把他找回來,
比方說 wayback machine 就是一個不錯的選擇。
----
我是用別人寫好的這個 [waybackpack](https://github.com/jsvine/waybackpack),
也是 python 寫的小工具,
他只依賴 requests 這個額外的套件。
裝起來也很簡單:
```shell
pip install waybackpack
```
----
使用範例就大概是這樣:
```shell
waybackpack -d wayback \
https://udn.com/news/story/7321/3845624
```
`-d` ,創一個你指定名字的資料夾,然後存進去。
----
```shell
waybackpack -d wayback \
https://udn.com/news/story/7321/3845624
waybackpack -d wayback \
https://udn.com/news/story/7321/3833161
```
```shell
$ tree -ifF wayback | grep -v '/$'
wayback
wayback/20190524225425/udn.com/news/story/7321/3833161
wayback/20190608120835/udn.com/news/story/7321/3845624
wayback/20190609133509/udn.com/news/story/7321/3845624
wayback/20190827225620/udn.com/news/story/7321/3845624
20 directories, 4 files
```
----
之後就是開個檔,
然後一樣餵給剛剛寫的 crawler 即可。
```
requests.get(url) => open(path)
.text => .read()
```
wayback machine 都沒有 => 搜尋引擎吧!
<!--
ignore
----
#### requests-html & the dynamic pages (ajax)
此次比賽給的網頁似乎沒有此種頁面,
但這邊還是提一下。
例如自由時報娛樂版是採動態生成內文,
這部份可以使用 [requests-html](https://github.com/oldani/requests-html) 這個 library。
只用方法不難,
只要照著他的 `README.md` 就可以了,
在此就不贅述了。 -->
---
## 模型雛型 Naive Model
-----
模型大概可以分成兩個部份。
1. classifier 用來辨別是否為 AML 新聞。
2. extractor 用來提取目標人名。
以下就來介紹一下一開始是怎麼實作的。
----
### Document Classification
同一類的東西 => 相似度會比較高,
出現過的詞想成向量。
----
比如這裡有三句話,我們把他當成三篇文章,
為一個 corpus,並且已經做好斷詞。
```
1. 太平洋/有/颱風/生成/,/請/民眾/關注/天氣/,/嚴防/大雨/。
2. 天氣/預報/:/氣流/影響/,/天氣/仍舊/不穩/,/留意/瞬間/大雨/。
3. 台灣/座落/於/西/太平洋/。
```
斷詞在實作上我們是使用 [jieba](https://github.com/fxsjy/jieba) 的 `search_mode`。
```python
import jieba
text = '台灣座落於西太平洋。'
print(jieba.lcut_for_search(text)) # 搜尋引擎模式
#['台灣', '座落', '於', '太平', '太平洋', '西太平洋', '。']
print(jieba.lcut(text, cut_all = True)) # 全模式
#['台', '灣', '座落', '於', '西太平洋', '太平', '太平洋', '', '']
print(jieba.lcut(text, cut_all = False)) # 精確模式
#['台灣', '座落', '於', '西太平洋', '。']
```
----
把停用詞 (stopword) 等一些常用的詞去掉,
例如 `請`,`於`, `仍舊`, `瞬間` 一類的詞,
所有詞可以表示成一個 vector。
```python
[太平洋, 颱風, 生成, 民眾, 關注, 天氣, 嚴防, 大雨,
預報, 氣流, 影響, 不穩, 留意, 台灣, 座落]
```
去掉停用詞的新文章為:
```
1. 太平洋/颱風/生成/民眾/關注/天氣/嚴防/大雨
2. 天氣/預報/氣流/影響/天氣/不穩/留意/大雨
3. 台灣/座落/太平洋
```
----
#### TF
不難想到,一個詞如果在一篇文章中出現多次,
那這個詞和這篇文章的關聯度就會越高,
這個就是 TF (term frequency) 的概念,
一般可以計算為:
```python
該詞出現在該文章的次數 / 該篇文章的詞數
```
----
```python
[太平洋, 颱風, 生成, 民眾, 關注, 天氣, 嚴防, 大雨, 預報, 氣流, ...]
[ 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 0, 0, ...]
[ 0, 0, 0, 0, 0, 2/8, 0, 1/8, 1/8, 1/8, ...]
[ 1/3, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...]
```
用 TF 的直覺大概就是
> 如果兩篇文章擁有相同的詞越多,相似度可能就越高。
----
我們用 cosine similarity 來計算文章相似度:
$$\cos (t,e)= {t e \over \|t\| \| e\|} \\ = \frac{ \sum_{i=1}^{n}{t_i e_i} }{ \sqrt{\sum_{i=1}^{n}{(t_i)^2} } \sqrt{\sum_{i=1}^{n}{(e_i)^2} } }$$
----
```python
from sklearn.metrics.pairwise import cosine_similarity
vecA = [1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 0, ...]
vecB = [ 0, 0, 0, 0, 0, 2/8, 0, 1/8, 1/8, ...]
vecC = [1/3, 0, 0, 0, 0, 0, 0, 0, 0, ...]
print(cosine_similarity(
[vecA, vecB, vecC], [vecA, vecB, vecC]))
# a b c
[[1. 0.3354102 0.20412415] # a
[0.3354102 1. 0. ] # b
[0.20412415 0. 1. ]] # c
```
----
#### IDF
inverse document frequency,逆向文件頻率
一個詞只出現在某幾篇新聞中(比如 "洗錢"),
一個詞幾乎每篇都有(比如 "記者"),
那前者的重要性和獨特性應該會比後者高。
一般可計算為:
```python
log(所有的文章數目 / (出現該詞的文章數 + 1))
```
```python
log(3 / (2)) = 0.4 #因為 corpus 小,而且詞都有出現,所以就不做 +1
log(3 / (1)) = 1.1
[太平洋, 颱風, 生成, 民眾, 關注, 天氣, 嚴防, 大雨, 預報, 氣流, ...]
[ 0.4, 1.1, 1.1, 1.1, 1.1, 0.4, 1.1, 0.4, 1.1, 1.1, ...]
```
----
IDF 可以表達出一個詞的特徵值,
我們把他與 TF 相乘,
便可得到更有意義的特徵值。
```python
[太平洋, 颱風, 生成, 民眾, 關注, 天氣, 嚴防, 大雨, 預報, 氣流, ...]
[ 0.05, 0.21,0.21,0.21,0.21, 0.05,0.21, 0.05, 0.0, 0.0, ...]
[ 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.0, 0.05,0.21,0.21, ...]
[ 0.13, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...]
```
----
我們一樣計算 cosine similarity 可得:
```python
# a b c
[[1. 0.03368042 0.01800272] # a
[0.03368042 1. 0. ] # b
[0.01800272 0. 1. ]] # c
```
----
#### BM25 + w2v + IR model as classifier
IR model 應用上述概念所做的搜尋引擎。
把關聯度高的文章排到前面。
而我們之前所作的 model 使用了:
[bm25](https://kknews.cc/zh-tw/news/z2gkr4g.html) + [word2vector](https://kknews.cc/zh-tw/code/nkjvlm2.html) + [Relevance Feedback](https://zh.wikipedia.org/wiki/%E5%85%B3%E8%81%94%E5%8F%8D%E9%A6%88) 。
----
IR model 當 classifier?
1. 三百篇 bm25 + w2v 分數加起來看相似度
2. 抽三百篇看 recall
----
```python
[ x 0 / 300 score = 0.0 ] Qry29: 【2019理財大事5】跌破...
[ x 11 / 300 score = 5.5 ] Qry30: 公開資訊觀測站...
[ v 223 / 300 score = 195.9 ] Qry31: 涉貪圖利 東檢聲押前台...
[ x 0 / 300 score = 0.0 ] Qry32: 昂山素姬明出席國際法 ...
[ x 0 / 300 score = 0.0 ] Qry33: 繼思想改造集中營之後 ...
[ x 0 / 300 score = 0.0 ] Qry34: 山頂纜車機件故障暫停 ...
[ v 251 / 300 score = 215.4 ] Qry35: 直銷妹誆「1年帶你住帝...
[ v 262 / 300 score = 224.4 ] Qry36: 潤寅詐貸案延燒 上市公...
[ v 206 / 300 score = 179.1 ] Qry37: 花蓮縣3議員涉收賄 貪 ...
[ x 0 / 300 score = 0.0 ] Qry38: 週三晚起東北季風增強 ...
[ x 0 / 300 score = 0.0 ] Qry39: 「灰天鵝」拉警報 | An...
[ x 1 / 300 score = 0.6 ] Qry40: 柯媽爆料:柯文哲絕對 ...
[ x 0 / 300 score = 0.0 ] Qry41: 媒體:特朗普涉嫌威脅 ...
[ x 0 / 300 score = 0.0 ] Qry42: 國銀海外投資豐收 8月O...
```
```pyhthon
[ x 155 / 300 score = 63.6 ] Qry148: 12/3 今彩539頭獎 ...
[ x 155 / 300 score = 63.8 ] Qry797: 12/7 雙贏彩、今彩539 ...
```
----
### Named Entity Recognition
人名提取是本次比賽的重點。
NER 可以識別出特殊的名詞,
例如人物、組織和地點等。
----
#### NN model (ckip) + rule based as extractor (NER)
去年九月,
中研院的 ckip 開源了斷詞系統 [ckiptagger](https://github.com/ckiplab/ckiptagger)。
```python
"""
word embedding + BiLSTM => 斷詞系統
word embedding + BiLSTM + 斷詞 => 詞性標注
word embedding + BiLSTM + 斷詞 + 詞性標注 => 精確、多類別 的 NER
"""
[name for name in NER(news)
if name.type == PEOPLE and not match ["*嫌", "*婦"]]
# ex: 張嫌 陳婦
```
----
<!--
ckiptagger 的版本需求:
```markdown
- python>=3.6
- tensorflow[-gpu] >=1.13.1 , <2
- gdown (optional, for downloading from google drive)
```
記得要先載他 train 好的 model 才可以使用,
你可以用上面的 gdown 或者直接從載點下載,
詳情請參照 [ckiptagger](https://github.com/ckiplab/ckiptagger)。
我們這邊使用的配置如下:
```python
ckiptagger==0.1.1
tensorflow-gpu==1.15
```
----
-->
一個簡單的範例片段:
```python
from ckiptagger import WS, POS, NER
ckipDir = 'ckip' # ckip pre-training path
doc = '重判12年又加保3億,法官怕中電前董周麗真逃亡。'
ws, pos, ner = [f(ckipDir) for f in [WS, POS, NER]]
word_s = ws([doc], sentence_segmentation=True,
segment_delimiter_set=set('??!!。,,;:、'))
names = set([e[3] \
for e in ner(word_s, pos(word_s))[0] \
if e[2] == 'PERSON'])
print(names) # {'周麗真'}
```
----
另一個範例片段:
```python
from pprint import pprint
from ckiptagger import WS, POS, NER
docs = ['東太平洋漁場時價分析師兼操盤手暨洋流講師海龍王彼得。',
'浪漫Duke帶你找到屬於你的浪漫。','卑鄙源之助已經遲到一個小時了欸。',
'惡魔貓男,你今晚的惡夢','我台北暴徒,天不怕地不怕,aka 黑魔王']
ws, pos, ner = WS('ckip'), POS('ckip'), NER('ckip')
word_s = ws(docs, sentence_segmentation=True,
segment_delimiter_set=set('??!!。,,;:、'))
pprint([set([(e[3], e[2]) for e in doc]) \
for doc in ner(word_s, pos(word_s))])
```
```python
[{('海龍王', 'PERSON'),
('東太平洋', 'LOC'),
('彼得', 'PERSON')},
set(),
{('一個小時', 'TIME')},
{('今晚', 'TIME')},
{('台北', 'GPE')}]
```
----
至此,一個不太精確的標記系統已經完成了,
此比賽模型也已經有了一個雛型。
接下來就講講如何把他接上 API,
提供服務給外界使用。
---
## 服務建置 Service
-----
主辦單位提供了 Azure 雲端給我們使用,
主要有用的東西除了一個 Ubuntu 可以使用外,
還有 K80 的 GPU 及一個 IP。
不過原則上還是自己配的環境好用些。
----
<!--
### flask
主辦單位提供了一個簡易的 flask 模板給我們使用。
回傳的 encoding 必須為 UTF-8,
在 `app.run` 前更改一下 flask 的 config 即可:
```python
app.config['JSON_AS_ASCII'] = False
```
----
-->
API call 分作兩個部份 health check 和 inference,
health check 主要在確認 service availability,
而 inference 主要是負責答案的判定。
----
health check:
```python
@app.route('/healthcheck', methods=['POST'])
def healthcheck(): # API for health check
data = request.get_json(force=True)
print(data)
t = datetime.datetime.now()
ts = str(int(t.utcnow().timestamp()))
server_uuid = generate_server_uuid(CAPTAIN_EMAIL+ts)
server_timestamp = t.strftime("%Y-%m-%d %H:%M:%S")
return jsonify({
'esun_uuid': data['esun_uuid'],
'server_uuid': server_uuid,
'captain_email': CAPTAIN_EMAIL,
'server_timestamp': server_timestamp
})
```
----
inference:
```python
answer_cache = {}
@app.route('/inference', methods=['POST'])
def inference():
data = request.get_json(force=True)
esun_timestamp = data['esun_timestamp']
now = datetime.datetime.now()
server_timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
ts = str(int(now.utcnow().timestamp()))
server_uuid = generate_server_uuid(CAPTAIN_EMAIL+ts)
```
```python
template = lambda ans: jsonify({
'esun_timestamp': data['esun_timestamp'],
'server_uuid': server_uuid,
'answer': ans,
'server_timestamp': server_timestamp,
'esun_uuid': data['esun_uuid']
})
```
----
```python
if data['esun_uuid'] in cache_answer:
if cache_answer[data['esun_uuid']] != None:
return template(cache_answer[data['esun_uuid']])
else:
while cache_answer[data['esun_uuid']] == None:
sleep(4)
return template(cache_answer[data['esun_uuid']])
```
```python
else:
cache_answer[data['esun_uuid']] = None
try:
log(data['news'])
answer = predict(data['news'])
log(answer)
except:
log('model error')
raise ValueError('Model error.')
cache_answer[data['esun_uuid']] = answer
return answer_template(answer)
```
----
inference 做了 cache,
原因是一個 inference 時間上限為五秒,
逾時就會重新發 request 過來,次數上限為三次。
為了避免逾時而重複 inference,
所以我們做了 cache。
不過 inference 通常滿快的,
一兩秒內就可以算完了。
----
### static IP
Azure 對外不開放 80 和 443 以外的 port,
所以原則上把服務開在其中一個 port 即可。
----
那如果手上有比較好的顯卡,覺得 K80 跑得太慢,但該電腦又沒有固定 IP 的話怎麼辦呢?
----
反向代理
----
我們把 flask 開在 8080 port 上,
forward 到伺服器的 80 port 上,
http protocol 瀏覽伺服器的 IP 位置即可。
----
```shell
# /etc/ssh/sshd_config
AllowTcpForwarding yes
```
```shell
systemctl restart sshd.service
```
這邊使用 autossh 讓他自動重連比較穩定。
```shell
autossh -M 20000 -i ~/.ssh/id_rsa -NfR \
:8080:localhost:8080 user@azure
# foward local 8080 to remote 8080
```
----
遠端的 80 port 需要 root 權限,
ssh 會關掉 root 遠端登入。
所以這邊可以透過 [python-port-forward](https://github.com/vinodpandey/python-port-forward):
```shell
sudo python2.7 port-forward.py 80:localhost:8080
```
----
### slack
前置作業都完成後,
只要把 web hook 掛給官方提供的 slack bot 即可。
之後比賽他就會去戳你給的 IP address 了。
![](https://i.imgur.com/0cjPF0C.png)
----
到這邊,
已經可以開始拿做好的東西打一場比賽了。
接下來讓我們繼續把 model 調得更好!
---
## 基本模型 Basic Model
-----
Logistic Regression, SVM and XGBoost
從 sklearn 裡拿分類器,
用 bm25 + w2v feature 分類。
詳細教學可以參考 [這篇文章](https://zhuanlan.zhihu.com/p/50657430)。
----
我們嘗試了三種分類器:
LogisticRegression,SVC 和 XGBoost。
```python
clf = LogisticRegression(
C=1.0,solver='lbfgs', multi_class='multinomial')
clf.fit(xtrain_tfv, ytrain)
predictions = clf.predict_proba(xvalid_tfv)
clf = SVC(C=1.0, probability=True)
clf.fit(xtrain_svd_scl, ytrain)
predictions = clf.predict_proba(xvalid_svd_scl)
clf = xgb.XGBClassifier(
max_depth=7, n_estimators=200, colsample_bytree=0.8,
subsample=0.8, nthread=10, learning_rate=0.1)
clf.fit(xtrain_tfv.tocsc(), ytrain)
predictions = clf.predict_proba(xvalid_tfv.tocsc())
```
這裡 classifier 的準確率來到了 88% 到 90% ,
大樂透類的新聞也被準確歸類了。
----
#### BM25 + XGBoost as classifier
經由測試,XGBoost 的效果是最好的,
於是我們就把 classifier 換成 XGBoost。
----
#### NN model (ckip) + XGBoost <br>+ rule based as extractor (NER)
人名前後 5 token 的 BM25
=> XGBoost
=> rule based filter
----
### Neural Network
----
#### BERT
![](https://i.imgur.com/1GygX2N.png)
----
BERT 比較適合小文本的任務,
這次的比賽就是一個非常好的發揮空間。
----
利用 word embedding
unsupervised (特徵提取) + supervised (下游任務)
- ELMo
- OpenAI 的 GPT
- Google 的 BERT 及一堆他的變形
- CMU 的 XLNet
我們在測試賽前嘗試使用 BERT 建立新 classifier,準確度有大幅的提昇。
----
#### NN model (BERT) as classifier
BERT from `transformers` (BERT, XLNet...)
- [進擊的 BERT:NLP 界的巨人之力與遷移學習](https://leemeng.tw/attack_on_bert_transfer_learning_in_nlp.html)
- 李宏毅教授的 [BERT 的教學影片](https://www.youtube.com/watch?v=UYPa347-DdE)
pre-training from [hugface 的網站](https://huggingface.co/models)
因為此次是中文的比賽,所以我們使用了最基本款
`bert-base-chinese` 即可。
----
BERT 四大下游任務
- BertForSequenceClassification:分類。
- BertForMultipleChoice:選擇題。
- BertForQuestionAnswering:文章問答。
- BertForTokenClassification:NER。
----
<img src="https://pic2.zhimg.com/80/v2-c101ddc3b2f4dbd3dc20999f900c71ba_720w.jpg" width="60%">
----
BERT 512 的 token size 限制,
我們取了文章最後的 510 個 token 丟進 model 。
分類準確度從剛才的 90% => 99% 。
時間來到了測試賽。
----
> 測試賽開始:
> 僅測試伺服器的穩定度,
> 並沒有提供題目正確答案和分數。
---
## 進階模型 Advenced Model
-----
BERT 也有提供 NER 的任務訓練,
而 ckip 的 NER 是用在廣泛用途的,
那何不用 BERT 自己也 train 一個呢?
----
### Make our NER
<a href="https://en.wikipedia.org/wiki/Inside%E2%80%93outside%E2%80%93beginning_(tagging)">IOB format</a>
用 `bert-base-chinese`,做 tokenization。
接著根據幫匹配的人名標上標記。
```python
"法官怕周麗真逃亡", ["周麗真"]
['法', '官', '怕', '周', '麗', '真','逃', '亡']
['O', 'O', 'O', 'B-PER', 'I-PER', 'I-PER', 'O', 'O']
```
只要寫個小小的 script 轉換完資料,
用 BertForTokenClassification 開始 NER 囉!
----
#### NN model (BERT) as extractor (NER)
NER 似乎就有簡單的分類能力,
可以避開一些非 AML 相關的人名。
到這裡,基本的模型已經構建完畢,
這就是我們進行正式賽的 Model。
----
> 正式賽分作兩週,共八天。
> 正式賽第一周開始:
> 我們在這週的排名第一天在第四,
> 之後又掉到了五和六。
----
### Extend The DataSet
----
#### Reuse The IR Model
第一周結束的假日,
300 AML news + IR model => new classifier data
----
> 正式賽第二周開始:
> 爬回了四而隔天又掉回了五,
> 加入新資料似乎有一點提昇。
> 不過 model 似乎還要再加強,
> => 決定嘗試其他 Model。
----
### Try other NN Model
XLNet, RoBERTa, Albert 沒有很大的提昇。
RoBERTa 在 classifier 表現上有好些。
----
#### NN model (RoBERTa) as classifier
`Cinese-roberta-wwm-ext`
前幾天的 query 當作 validation set,
RoBERTa 的準確度從 96% 上到 97%,
RoBERTa 的 classifier 似乎有變好,
於是我們將 classifier 換成 RoBERTa。
----
下圖是我們的最終架構圖:
![](https://i.imgur.com/4durE7N.png)
----
> 第七天的 query 送成前一天的,
> 故第七天沒有列入計算。
> 最後我們跑到了第三名。
> 至此,整個賽程結束。
---
## 其他 Others
-----
不過礙於時間關係,我們沒來得及做這些嘗試。
----
### evoluationary computation
我們在嘗試前面的 Model 時,
有嘗試用演化計算來調整參數。
不過後來 Model 都轉移到 NN 上,
我們在傳統機器學習方法上就沒再做更多嘗試了。
其實演化計算的應用很廣,
或許可以應用在現在 Model 的參數微調上。
----
### other models
model 用法錯誤?更棒的 model?
----
### improve the pre-training model
pre-training + news => domain specific ability
----
### expand the data
NER 的部份,也可以將一千五百篇的人名做標記,
如此 NER 的效果可能會提昇一些。
----
### data augmentation
跟圖片一樣,
NLP 的分類也可以使用 augmentation,
這似乎也是一個研究的方向:
[一個中文數據增強的實現](https://github.com/zhanlaoban/EDA_NLP_for_Chinese)。
----
開箱結束,謝謝收看。
{"metaMigratedAt":"2023-06-15T11:39:23.209Z","metaMigratedFrom":"YAML","title":"玉山 NLP 應用挑戰賽","breaks":true,"contributors":"[{\"id\":\"0237d1e4-0096-4101-a312-f08ec9751f08\",\"add\":57424,\"del\":39177}]"}