Open9

🤗 Transformers 事始め

d3d3

🤗 Transformers を使って、テキスト分類ができるようになるまでの過程

d3d3

Pipeline を使う

最も簡単なのは pipeline を使う方法。

!pip install transformers
from transformers import pipeline

classifier = pipeline("text-classification")
No model was supplied, defaulted to distilbert-base-uncased-finetuned-sst-2-english

デフォルトだと distilbert-base-uncased-finetuned-sst-2-english というモデルが利用される。このモデルは感情分析用に学習されたものと言うことで、 Pipeline を使って推論を行うと勝手に Negative / Positive を判定してくれる。

適当に高評価、低評価なレビューから推論させてみる。

import pandas as pd

text = """This book is a comprehensive, wide-ranging detailed, book that covers a huge range of different topic areas in great detail.
Make no mistake this book is big - 700+ pages of in-depth content, and much, nay, most of it not aimed at the casual beginner.
Across 19 chapters the authors go through topic such as building good training sets, dimension reduction techniques, best practices, ensembles, PyTorch, Scikit-Learn, CNNs, RNNs, transformers, GANs and much much much more.
I, personally, have not read any other books by these authors, but I have bought and read many Packt books previously so I knew potentially what I would be getting."""

outputs = classifier(text)

pd.DataFrame(outputs)
label score
0 POSITIVE 0.990525
text = """Content is undoubtedly good as we all know but here book received is Black & White printed with cheap quality pages.
It looks like a Xerox.
Do not buy from Epitome Books."""

outputs = classifier(text)

pd.DataFrame(outputs)
label score
0 NEGATIVE 0.997563
d3d3

事前学習済みのモデルを Fine-tuning する

事前学習済みのモデルに、特定のデータセットを学習させてテキスト分類ができるようにする。

今回は Hugging Face で利用できる amazon_reviews_multi/ja を学習データとして利用する:

!pip install datasets
from datasets import load_dataset

dataset = load_dataset("amazon_reviews_multi", name="ja")

dataset
DatasetDict({
    train: Dataset({
        features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'],
        num_rows: 200000
    })
    validation: Dataset({
        features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'],
        num_rows: 5000
    })
    test: Dataset({
        features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'],
        num_rows: 5000
    })
})
d3d3

以下のようなデータが入ってる

dataset["train"][0]
{'language': 'ja',
 'product_category': 'shoes',
 'product_id': 'product_ja_0270003',
 'review_body': '普段使いとバイクに乗るときのブーツ兼用として購入しました。見た目や履き心地は良いです。 しかし、2ヶ月履いたらゴム底が削れて無くなりました。また、バイクのシフトペダルとの摩擦で表皮が剥がれ、本革でないことが露呈しました。ちなみに防水とも書いていますが、雨の日は内部に水が染みます。 安くて見た目も良く、履きやすかったのですが、耐久性のなさ、本革でも防水でも無かったことが残念です。結局、本革の防水ブーツを買い直しました。',
 'review_id': 'ja_0388536',
 'review_title': '本革でも防水でもない',
 'reviewer_id': 'reviewer_ja_0454098',
 'stars': 1}
d3d3

今回はテキストがどの製品カテゴリに対してのものなのかを推論させたいので、カラムをreview_bodyproduct_category に絞りたい

dataset = dataset.remove_columns(["review_id", "product_id", "reviewer_id", "stars", "review_title", "language"])
dataset = dataset.rename_column("review_body", "text")
dataset = dataset.rename_column("product_category", "label_name")
dataset["train"][0]
{'label_name': 'shoes',
 'text': '普段使いとバイクに乗るときのブーツ兼用として購入しました。見た目や履き心地は良いです。 しかし、2ヶ月履いたらゴム底が削れて無くなりました。また、バイクのシフトペダルとの摩擦で表皮が剥がれ、本革でないことが露呈しました。ちなみに防水とも書いていますが、雨の日は内部に水が染みます。 安くて見た目も良く、履きやすかったのですが、耐久性のなさ、本革でも防水でも無かったことが残念です。結局、本革の防水ブーツを買い直しました。'}
d3d3

Dataset を Pandas の DataFrame 形式にしておく

import pandas as pd

dataset.set_format(type="pandas")

df_train = dataset["train"][:]
df_validation = dataset["validation"][:]
df_test = dataset["test"][:]

df_train.head()
index text label_name
0 普段使いとバイクに乗るときのブーツ兼用として購入しました。見た目や履き心地は良いです。 しかし、2ヶ月履いたらゴム底が削れて無くなりました。また、バイクのシフトペダルとの摩擦で表皮が剥がれ、本革でないことが露呈しました。ちなみに防水とも書いていますが、雨の日は内部に水が染みます。 安くて見た目も良く、履きやすかったのですが、耐久性のなさ、本革でも防水でも無かったことが残念です。結局、本革の防水ブーツを買い直しました。 shoes
1 十分な在庫を用意できない販売元も悪いですが、Amazonやら楽⚪︎が転売を認めちゃってるのが結果的に転売の後押しになっちゃってるんだよなぁ… Amazonもここぞとばかりに抱き合わせ販売しまくるし… それを恥ずかしいと思えなくなったら動物と同じですよ、最大手さん。 video_games
2 見た目はかなりおしゃれで気に入りました。2、3回持ち歩いた後いつも通りゼンマイを巻いていたら突然空回り。 針の調整はできるけど、つまみをあげても下げてもゼンマイを巻くことができず。 時計屋に持って行って中を開けてもらったら、中のケースと外側の規格がそもそも合っていないため、固定されず、一度ズレると噛み合わなくなるんだそう。 返品して交換した方がいいと言われましたが、保証書付いてないし、 クーリングオフ期間もとっくに過ぎています。 アンティーク感覚で家で放置するならおススメですが、 本来の用途としては全く使えません。 ご注意を。 watch
3 よくある部分での断線はしませんでした ただiphoneとの接続部で接触不良、折れました iphoneの中に残されてしまい摘出に苦労しました pc
4 プラモデルの塗装剥離に使う為に購入 届いて早速使ってみた 結果 1ヶ月経っても未だに剥離出来ない 何じゃこら! home_improvement
d3d3

学習時はラベルを数値にしておく必要があるので、ラベルを数値にした列を追加する。

まず、すべてのラベルを列挙

labels = [
  *df_train["label_name"],
  *df_test["label_name"],
  *df_validation["label_name"]
]

labels = sorted(list(set(labels)))

各ラベルをナンバリングしたマップを作る

from functools import reduce

label_map = reduce(lambda acc, x: { **acc, x: labels.index(x) }, labels, {})
label_map
{'apparel': 0,
 'automotive': 1,
 'baby_product': 2,
 'beauty': 3,
 'book': 4,
 'camera': 5,
 'digital_ebook_purchase': 6,
 'digital_video_download': 7,
 'drugstore': 8,
 'electronics': 9,
 'furniture': 10,
 'grocery': 11,
 'home': 12,
 'home_improvement': 13,
 'industrial_supplies': 14,
 'jewelry': 15,
 'kitchen': 16,
 'lawn_and_garden': 17,
 'luggage': 18,
 'musical_instruments': 19,
 'office_product': 20,
 'other': 21,
 'pc': 22,
 'pet_products': 23,
 'shoes': 24,
 'sports': 25,
 'toy': 26,
 'video_games': 27,
 'watch': 28,
 'wireless': 29}
d3d3

データにラベルに対応した数値の列を足していく。

label_mapper = lambda x: label_map[x]

df_train["label"] = df_train["label_name"].apply(label_mapper)
df_test["label"] = df_test["label_name"].apply(label_mapper)
df_validation["label"] = df_validation["label_name"].apply(label_mapper)
df_train.head()
index text label_name label
0 普段使いとバイクに乗るときのブーツ兼用として購入しました。見た目や履き心地は良いです。 しかし、2ヶ月履いたらゴム底が削れて無くなりました。また、バイクのシフトペダルとの摩擦で表皮が剥がれ、本革でないことが露呈しました。ちなみに防水とも書いていますが、雨の日は内部に水が染みます。 安くて見た目も良く、履きやすかったのですが、耐久性のなさ、本革でも防水でも無かったことが残念です。結局、本革の防水ブーツを買い直しました。 shoes 24
1 十分な在庫を用意できない販売元も悪いですが、Amazonやら楽⚪︎が転売を認めちゃってるのが結果的に転売の後押しになっちゃってるんだよなぁ… Amazonもここぞとばかりに抱き合わせ販売しまくるし… それを恥ずかしいと思えなくなったら動物と同じですよ、最大手さん。 video_games 27
2 見た目はかなりおしゃれで気に入りました。2、3回持ち歩いた後いつも通りゼンマイを巻いていたら突然空回り。 針の調整はできるけど、つまみをあげても下げてもゼンマイを巻くことができず。 時計屋に持って行って中を開けてもらったら、中のケースと外側の規格がそもそも合っていないため、固定されず、一度ズレると噛み合わなくなるんだそう。 返品して交換した方がいいと言われましたが、保証書付いてないし、 クーリングオフ期間もとっくに過ぎています。 アンティーク感覚で家で放置するならおススメですが、 本来の用途としては全く使えません。 ご注意を。 watch 28
3 よくある部分での断線はしませんでした ただiphoneとの接続部で接触不良、折れました iphoneの中に残されてしまい摘出に苦労しました pc 22
4 プラモデルの塗装剥離に使う為に購入 届いて早速使ってみた 結果 1ヶ月経っても未だに剥離出来ない 何じゃこら! home_improvement 13
d3d3

ラベルの分布を見ておく

import matplotlib.pyplot as plt

xs = df_train["label_name"].value_counts().plot.barh(figsize=(9, 7))
plt.show()