シンプルなファインチューニング例
目次
26. シンプルなファインチューニング例¶
やりたいこと
20 newsgroups text datasetを分類タスクとして学習したい。
方針
fastTextにより「Wikipedia(en)コーパスの一部」を用いて事前学習する。(異なるソースを元に言語モデルを構築する)
なお、ここではfastTextで学習するためにどのようにデータを要ししたら良いのかを確認しやすくするためにWikipediaコーパスから事前学習を行っている。しかし自前でWikipedia事前学習するぐらいなら、最初からFastTextで公開されている事前学習済みモデルをダウンロードして用いるほうが良い。
fastText学習済みモデルを用いて、20 newsgroups textの記事をベクトル化する。
比較対象としてTF-IDFによるベクトル化も用意する。
分類学習にはナイーブベイズ、SVM、NNを用いる。なお、ナイーブベイズは基本的にはカウント情報を想定しているため、fastTextベクトルには適用できないことからTF-IDFのみに適用する。
!date
2022年 3月 9日 水曜日 15時52分25秒 JST
26.1. 事前学習¶
26.1.1. 環境構築¶
fastTextモデルのためにgensimを利用。
#!pip install --upgrade gensim
!conda install -c conda-forge gensim
Collecting package metadata (current_repodata.json): done
Solving environment: failed with initial frozen solve. Retrying with flexible solve.
Collecting package metadata (repodata.json): done
Solving environment: failed with initial frozen solve. Retrying with flexible solve.
PackagesNotFoundError: The following packages are not available from current channels:
- gensim
Current channels:
- https://conda.anaconda.org/conda-forge/osx-arm64
- https://conda.anaconda.org/conda-forge/noarch
- https://repo.anaconda.com/pkgs/main/osx-arm64
- https://repo.anaconda.com/pkgs/main/noarch
- https://repo.anaconda.com/pkgs/r/osx-arm64
- https://repo.anaconda.com/pkgs/r/noarch
To search for alternate channels that may provide the conda package you're
looking for, navigate to
https://anaconda.org
and use the search bar at the top of the page.
26.1.2. データセットの準備¶
英語版Wikipediaのダンプデータをダウンロードし、これを事前学習用コーパスとして利用する。なお、全データを用いると圧縮状態で15GBを超えて待ち時間が長いため、ここでは小規模で提供されているものを指定している。
ダンプデータはbzcatで確認しているように、XML形式で書かれている。
file_url="https://dumps.wikimedia.org/enwiki/latest/enwiki-latest-pages-articles1.xml-p1p41242.bz2"
!curl -O https://dumps.wikimedia.org/enwiki/latest/enwiki-latest-pages-articles1.xml-p1p41242.bz2
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 245M 100 245M 0 0 856k 0 0:04:53 0:04:53 --:--:-- 860kk 0 0 755k 0 0:05:32 0:00:10 0:05:22 871k0 0 798k 0 0:05:14 0:00:18 0:04:56 870k 0 0 821k 0 0:05:05 0:00:31 0:04:34 848k:01:22 0:03:34 867k55 0:02:07 0:02:48 862k4:55 0:02:11 0:02:44 859k0 852k 0 0:04:54 0:02:22 0:02:32 860k52k 0 0:04:54 0:02:31 0:02:23 864k 0 0:04:54 0:02:49 0:02:05 859k 853k0:01:26 863k2 178M 0 0 854k 0 0:04:53 0:03:33 0:01:20 864k 0 0:04:53 0:04:21 0:00:32 864k 855k 0 0:04:53 0:04:23 0:00:30 860k 0 0:04:53 0:04:42 0:00:11 857k
!bzcat enwiki-latest-pages-articles1.xml-p1p41242.bz2 | head
<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en">
<siteinfo>
<sitename>Wikipedia</sitename>
<dbname>enwiki</dbname>
<base>https://en.wikipedia.org/wiki/Main_Page</base>
<generator>MediaWiki 1.38.0-wmf.23</generator>
<case>first-letter</case>
<namespaces>
<namespace key="-2" case="first-letter">Media</namespace>
<namespace key="-1" case="first-letter">Special</namespace>
bzcat: I/O or other error, bailing out. Possible reason follows.
bzcat: Broken pipe
Input file = enwiki-latest-pages-articles1.xml-p1p41242.bz2, output file = (stdout)
26.1.3. 環境構築2¶
multiprocessingは、実行環境におけるCPU数(コア数)を確認するために利用。
gensim.corpora.wikicorpusは、Wikipediaのダンプデータから本文データのみを抽出するために利用。
gensim.models.fasttextは、FastTextモデル。
import multiprocessing
from gensim.corpora.wikicorpus import WikiCorpus
from gensim.models.fasttext import FastText as FT_gensim
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
/var/folders/nc/_3k6g05j2499x9n2cjtmhxl80000gn/T/ipykernel_33837/2467614308.py in <module>
1 import multiprocessing
----> 2 from gensim.corpora.wikicorpus import WikiCorpus
3 from gensim.models.fasttext import FastText as FT_gensim
ModuleNotFoundError: No module named 'gensim'
ダンプデータから本文抽出する様子。sentencesにlatestの全本文があり、文書数は15025件。1件目の文書に含まれる単語数は50単語。
!date
!curl -O https://dumps.wikimedia.org/enwiki/latest/enwiki-latest-pages-articles11.xml-p6899367p7054859.bz2
wikipedia_data = "./enwiki-latest-pages-articles11.xml-p6899367p7054859.bz2"
# expand and extarct
print("get texts from {}".format(wikipedia_data))
wiki = WikiCorpus(wikipedia_data, dictionary={})
sentences = list(wiki.get_texts())
# 出力確認
print(len(sentences))
print(len(sentences[0]))
print(sentences[0][0:5])
!date
26.1.4. fastTextによる事前学習¶
build_vocab() により、まずボキャブラリ(単語一覧)を作成する。
その後、コーパスとそれに対する基本情報、エポック数を指定して学習する。
!date
# faxtText
ft_model = FT_gensim(vector_size=200, window=10, min_count=10, workers=max(1, multiprocessing.cpu_count() - 1))
# build the vocabulary
print("building vocab...")
ft_model.build_vocab(sentences)
# train the model
print("training model...")
ft_model.train(
sentences,
epochs = ft_model.epochs,
total_examples = ft_model.corpus_count,
total_words = ft_model.corpus_total_words
)
print("training done.")
!date
26.1.5. 事前学習により得られたモデルの確認¶
単語でも文章でもベクトル化できる。
“hoge” は元々の文書には存在しない(False)が、ベクトル化できている。(サブワードによる未知語対応)
ベクトル化できたため、類似単語も確認可能。
# 動作確認
print(ft_model.wv['artificial'].shape)
print(ft_model.wv['artificial'][:5])
print(ft_model.wv["more like funchuck,Gave this"][:5])
print("===========")
print("hoge" in ft_model.wv.key_to_index)
print(ft_model.wv["hoge"][:5])
print("===========")
print(ft_model.wv.most_similar("computer"))
print(ft_model.wv.most_similar("programming"))
print(ft_model.wv.most_similar("apple"))
26.2. ファインチューニング¶
fastTextによる事前学習を終えた。これを用いて本当にやりたい 20 news 分類学習に移る。
26.2.1. データセットを用意¶
20 newsのデータセットを用意。
# fine-tuneing stage.
# デーセットの用意
# こちらも時間かかるので、変換したデータセットを指定した場所に保存。
# 既に保存済みデータセットの利用にも対応。
from sklearn.datasets import fetch_20newsgroups
#categories = ['alt.atheism', 'sci.space']
categories = ['comp.os.ms-windows.misc', 'comp.sys.mac.hardware', 'misc.forsale']
newsgroups_train = fetch_20newsgroups(subset='train', categories=categories)
train_text = newsgroups_train.data
train_label = newsgroups_train.target
newsgroups_test = fetch_20newsgroups(subset='test', categories=categories)
test_text = newsgroups_test.data
test_label = newsgroups_test.target
26.2.2. 事前学習モデルによるベクトル化¶
!date
# 事前学習したfastTextにより、文章をベクトルに変換
def sentence2vector(sentences, model):
vectors = []
for sent in sentences:
vectors.append(model.wv[sent])
return vectors
ft_train_vectors = sentence2vector(train_text, ft_model)
ft_test_vectors = sentence2vector(test_text, ft_model)
!date
26.2.3. 分類学習モデルによる学習(fastText版)¶
!date
#from sklearn.naive_bayes import MultinomialNB
from sklearn import svm
from sklearn.neural_network import MLPClassifier
#clf1 = MultinomialNB()
clf2 = svm.SVC(gamma='scale')
clf3 = MLPClassifier(max_iter=500)
clfs = {"SVM":clf2, "NN":clf3}
ft_scores = []
for name, clf in clfs.items():
clf.fit(ft_train_vectors, train_label)
score = clf.score(ft_test_vectors, test_label)
ft_scores.append(score)
print("ft_score = {} by {}".format(score,name))
!date
26.2.4. 分類学習(TF-IDF版)¶
# 比較対象の、事前学習なし実験。
# BoW + TFIDFによるベクトル生成
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer()
tfidf_train_vectors = vectorizer.fit_transform(newsgroups_train.data)
print("train_vectors.shape=", tfidf_train_vectors.shape)
print("len(train_label)=",len(train_label))
tfidf_test_vectors = vectorizer.transform(newsgroups_test.data)
print("test_vectors.shape=", tfidf_test_vectors.shape)
print("len(test_label)=",len(test_label))
!date
from sklearn.naive_bayes import MultinomialNB
from sklearn import svm
from sklearn.neural_network import MLPClassifier
clf1 = MultinomialNB()
clf2 = svm.SVC(gamma='scale')
clf3 = MLPClassifier(max_iter=500)
clfs = {"NB":clf1, "SVM":clf2, "NN":clf3}
tfidf_scores = []
for name, clf in clfs.items():
clf.fit(tfidf_train_vectors, train_label)
score = clf.score(tfidf_test_vectors, test_label)
tfidf_scores.append(score)
print("tfidf_scores = {} by {}".format(score,name))
!date
!date