このシリーズでは、自然言語処理において主流であるTransformerを中心に、環境構築から学習の方法までまとめます。

今回の記事ではHuggingface Transformersの入門として、概要と基本的なタスクのデモを紹介します。

トークナイザーとモデルによる実装を通じて、タスクの理解を深めましょう。

Google colabを使用して、簡単に最新の自然言語処理モデルを実装することができますので、ぜひ最後までご覧ください。

【前回】

【🔰Huggingface Transformers入門④】 pipelineによるタスク実装紹介

このシリーズでは、自然言語処理において主流であるTransformerを中心に、環境構築から学習の方法までまとめます。 今回の記事ではHuggingface Transformersの入門として…

今回の内容

・Transformerとは

・Huggingfaceとは

・Huggingface Transformersの導入

・tokenizerによるタスクの紹介

(テキスト分類・感情分析・質問応答・マスク言語処理・テキスト生成・固有表現認識・要約・翻訳)

Transformerとは

概要

「Transformer」は2017年にGoogleが「Attention is all you need」で発表した深層学習モデルです。

現在では、自然言語処理に利用する深層学習モデルの主流になっています。

これまでの自然言語処理分野で多く使われていた「RNN」(Recurrent Neural Network)や「CNN」(Convolutional Neural Network)を利用せず、Attentionのみを用いたEncoder-Decoder型のモデルとなっています。

「Transformer」が登場して以降、多くの自然言語処理モデルが再構築され、過去を上回る成果を上げています。

最近では自然言語処理だけでなく、ViTやDETRなどといった画像認識にも応用されています。

詳細は以下の記事をご覧ください。

【🔰Huggingface Transformers入門④】 pipelineによるタスク実装紹介

このシリーズでは、自然言語処理において主流であるTransformerを中心に、環境構築から学習の方法までまとめます。 今回の記事ではHuggingface Transformersの入門として…

Huggingface Transformersとは

概要

「Hugging Face」とは米国のHugging Face社が提供している、自然言語処理に特化したディープラーニングのフレームワークです。

「Huggingface Transformers」は、先ほど紹介したTransformerを実装するためのフレームワークであり、「自然言語理解」と「自然言語生成」の最先端の汎用アーキテクチャ(BERT、GPT-2など)と、何千もの事前学習済みモデルを提供しています。

ソースコードは全てGitHub上で公開されており、誰でも無料で使うことができます。

事前学習済みモデル

Hugging Faceではタスクに応じた様々な事前学習済みモデルが提供されています。

こちらからご確認ください。

Google colabによる導入

ここからはGoogle colabを使用して実装していきます。

今回紹介するコードは以下のボタンからコピーして使用していただくことも可能です。

なお、今回紹介するタスクの概要は公式実装の解説ページから抜粋しています。

Open In Colab

まずはGoogleドライブをマウントして、作業フォルダを作成します。

from google.colab import drive 
drive.mount('/content/drive')
!mkdir -p '/content/drive/My Drive/huggingface_transformers_demo/'
%cd '/content/drive/My Drive/huggingface_transformers_demo/'

次にtransformersをクローンします。

transformersはpipでインストールすることができます。

!git clone https://github.com/huggingface/transformers
%cd transformers
!pip install transformers

トークナイザー

パイプラインとトークナイザー

Huggingface Transformersにおける自然言語処理では「パイプライン」と「トークナイザー」による実装方法があります。

パイプライン ・「タスク種別」と「入力テキスト」を指定するだけで、1行のみで推論を行うシンプル。
・簡単に実行できるが、カスタマイズ性には乏しく、日本語での推論はあまり使えない。
こちらの記事で紹介)
トークナイザー ・「トークナイザー」で入力テキストを深層学習モデルに対応した形式に変換し、その入力データを使って「モデル」を直接操作して、推論を実行する方法
・カスタマイズ性が高く、多くのタスクで日本語での推論にも対応。
(今回紹介する方法)

トークナイザーとは

トークナイザーは自然言語の入力テキストを深層学習モデルの入力データに変換するプログラムのことです。

入力テキストをトークンに分割し、各トークンを「トークンID」に変換し、それをテンソルでラップします。

「トークナイザー」はモデルに関連付けられた「トークナイザークラス」または「AutoTokenizer」で作成することができます。

以下の例のようにトークナイザーを設定します。

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2")

ここからは、トークナイザーによる各タスクの実装方法を紹介していきます。

テキスト分類の実装デモ

概要

テキスト分類は、定義した特定のテキストにラベルまたはクラスを割り当てるタスクです。

主な使用例として、後ほど紹介する感情分析や自然言語推論、文法の正確性の評価などがあります。

以下の例では、3つの文章が与えられたときのクラス分類を実装することで、文章の言い換えが行われているかを判断します。

sequence_0 = "The company HuggingFace is based in New York City"
# HuggingFace 社はニューヨーク市に拠点を置いています。

sequence_1 = "Apples are especially bad for your health"
# りんごは特に健康に悪い

sequence_2 = "HuggingFace's headquarters are situated in Manhattan"
# ハギングフェイスの本社はマンハッタンにあります

sequence_0の文章を基準に考えると、sequence_2は内容を言い換えた文章ですが、sequence_1は全く内容が異なる文章となっています。

これを判定するため、「言い換えである」・「言い換えでない」の2分類モデルを実装してみましょう。

推論

まずはトークナイザーとモデルをインスタンス化します。

今回は学習済みモデルは「bert-base-cased-finetuned-mrpc」を使用します。

モデルは BERT モデルとして識別され、チェックポイントに格納された重みでロードされます。

from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased-finetuned-mrpc")
model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased-finetuned-mrpc")

分類のクラス名を指定します。ここでは「言い換えでない」、「言い換えである」の2種類です。

classes = ["not paraphrase", "is paraphrase"]
# 言い換えでない、言い換えである

正しいモデル固有の区切り文字、トークン タイプ ID、およびアテンション マスク (トークナイザーによって自動的に作成されます) を使用して、2 つの文からシーケンスを作成します。

paraphrase = tokenizer(sequence_0, sequence_2, return_tensors="pt")
not_paraphrase = tokenizer(sequence_0, sequence_1, return_tensors="pt")

このシーケンスをモデルに渡し、使用可能な 2つのクラスのいずれかに分類されるようにします: 0 (言い換えではない) と 1 (言い換えです)。

paraphrase_classification_logits = model(**paraphrase).logits
not_paraphrase_classification_logits = model(**not_paraphrase).logits

結果のソフトマックスを計算して、クラス全体の確率を取得します。

paraphrase_results = torch.softmax(paraphrase_classification_logits, dim=1).tolist()[0]
not_paraphrase_results = torch.softmax(not_paraphrase_classification_logits, dim=1).tolist()[0]

結果出力

最後に結果を出力します。

1つめの「paraphrase_results」は、「sequence_0 = “The company HuggingFace is based in New York City”」と、「sequence_2 = “HuggingFace’s headquarters are situated in Manhattan”」を比較した結果を表示します。

これらの文章はほぼ言い換えであるといえるでしょう。

for i in range(len(classes)):
    print(f"{classes[i]}: {int(round(paraphrase_results[i] * 100))}%")

実行すると以下のように、「not paraphrase: 10%,is paraphrase: 90%」という結果を得ます。

not paraphrase: 10%
is paraphrase: 90%

高確率で言い換えであると判断できていることがわかりました。

2つめの「not_paraphrase_results」は、「sequence_0 = “The company HuggingFace is based in New York City”」と、「sequence_1 = “Apples are especially bad for your health”」を比較した結果を表示します。

これらの文章は全く無関係の内容であるため、言い換えでないといえます。

for i in range(len(classes)):
    print(f"{classes[i]}: {int(round(not_paraphrase_results[i] * 100))}%")

実行すると以下のように、「not paraphrase: 94%,is paraphrase: 6%」という結果を得ます。

not paraphrase: 94%
is paraphrase: 6%

高確率で言い換えでないと判断できていることがわかりました。

どちらのケースでも、文章の内容からクラスに沿った分類ができていることがわかりました。

テキスト分類タスクのまとめ

これまで紹介したように、テキストの内容を把握し、クラス分類を実装しました。

最後に、これまでのコードをまとめると以下のようになります。

from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch

# トークナイザーとモデルをインスタンス化
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased-finetuned-mrpc")
model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased-finetuned-mrpc")

# 分類のクラス名を指定
classes = ["not paraphrase", "is paraphrase"]

# 比較する文章(入力)を定義
sequence_0 = "The company HuggingFace is based in New York City"
sequence_1 = "Apples are especially bad for your health"
sequence_2 = "HuggingFace's headquarters are situated in Manhattan"

# トークナイザーを使用して、2 つの文からシーケンスを作成します。
paraphrase = tokenizer(sequence_0, sequence_2, return_tensors="pt")
not_paraphrase = tokenizer(sequence_0, sequence_1, return_tensors="pt")

# シーケンスをモデルに渡す
paraphrase_classification_logits = model(**paraphrase).logits
not_paraphrase_classification_logits = model(**not_paraphrase).logits

# クラス全体の確率を取得
paraphrase_results = torch.softmax(paraphrase_classification_logits, dim=1).tolist()[0]
not_paraphrase_results = torch.softmax(not_paraphrase_classification_logits, dim=1).tolist()[0]

# sequence_0とsequence_2の比較結果を出力
print('--sequence_0,sequence_2--')
for i in range(len(classes)):
    print(f"{classes[i]}: {int(round(paraphrase_results[i] * 100))}%")

# sequence_0とsequence_1の比較結果を出力
print('--sequence_0,sequence_1--')
for i in range(len(classes)):
    print(f"{classes[i]}: {int(round(not_paraphrase_results[i] * 100))}%")

以下のような出力結果を得ます。

--sequence_0,sequence_2--
not paraphrase: 10%
is paraphrase: 90%
--sequence_0,sequence_1--
not paraphrase: 94%
is paraphrase: 6%

質問応答の実装デモ

概要

質問応答は、入力した文章に関する質問について解答を抽出するタスクです。

下の例のように、元の文章に関する質問に対して、解答を出力することができます。

元の文章
Transformers (以前は pytorch-transformers および pytorch-pretrained-bert と呼ばれていた) は、汎用の自然言語理解 (NLU) および Natural 用のアーキテクチャー (BERT、GPT-2、RoBERTa、XLM、DistilBert、XLNet など)、100 以上の言語で 32 以上の事前トレーニング済みモデルを備えた言語生成 (NLG) 性能と、TensorFlow 2.0 と PyTorchとの間での深い相互運用性を有する。
質問解答
Transformers で使用できる事前トレーニング済みのモデルは
いくつありますか?
???
Transformers は何を提供しますか????
Transformers は、どのフレームワーク間の相互運用性を提供しますか????

推論

以下のような手順で処理を進めていきます。

チェックポイント名からトークナイザーとモデルをインスタンス化します。
元のテキストと質問文を定義します。
質問を反復処理し、テキストと現在の質問からシーケンスを構築します。
このシーケンスをモデルに渡して、開始位置と終了位置の両方について、シーケンストークン全体 (質問とテキスト) のスコアの範囲を出力します。
top_kメソッドを使用して上位 5 つのトークンを取得します。
マスク トークンをトークンに置き換えて、結果を出力します。

順番に実行していきましょう。

①チェックポイント名からトークナイザーとモデルをインスタンス化します。

from transformers import AutoTokenizer, AutoModelForQuestionAnswering
import torch

# トークナイザーとモデルをインスタンス化
tokenizer = AutoTokenizer.from_pretrained("bert-large-uncased-whole-word-masking-finetuned-squad")
model = AutoModelForQuestionAnswering.from_pretrained("bert-large-uncased-whole-word-masking-finetuned-squad")

②元のテキストと質問文を定義します。

# 元の文章(入力)を定義します。
text = r"""
🤗 Transformers (formerly known as pytorch-transformers and pytorch-pretrained-bert) provides general-purpose
architectures (BERT, GPT-2, RoBERTa, XLM, DistilBert, XLNet…) for Natural Language Understanding (NLU) and Natural
Language Generation (NLG) with over 32+ pretrained models in 100+ languages and deep interoperability between
TensorFlow 2.0 and PyTorch.
"""
# 質問を定義します。
questions = [
    "How many pretrained models are available in 🤗 Transformers?",
    "What does 🤗 Transformers provide?",
    "🤗 Transformers provides interoperability between which frameworks?",
]

③〜⑥以下の通り、処理を進めます。

for question in questions:
    # 質問を反復処理し、テキストと現在の質問からシーケンスを構築
    inputs = tokenizer(question, text, add_special_tokens=True, return_tensors="pt")
    input_ids = inputs["input_ids"].tolist()[0]
    # このシーケンスをモデルに渡して、開始位置と終了位置の両方について、シーケンストークン全体 (質問とテキスト) のスコアの範囲を出力
    outputs = model(**inputs)
    answer_start_scores = outputs.start_logits
    answer_end_scores = outputs.end_logits

    # スコアのargmaxで最も可能性の高い解答の先頭を取得する
    answer_start = torch.argmax(answer_start_scores)

    # スコアのargmaxで最も可能性の高い解答の末尾を取得する
    answer_end = torch.argmax(answer_end_scores) + 1
    
    # top_kメソッドを使用して上位 5 つのトークンを取得
    answer = tokenizer.convert_tokens_to_string(
        tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end])
    )

    print(f"Question: {question}")
    print(f"Answer: {answer}")

実行すると、以下のような結果が出力されます。

Question: How many pretrained models are available in 🤗 Transformers?
Answer: over 32 +
Question: What does 🤗 Transformers provide?
Answer: general - purpose architectures
Question: 🤗 Transformers provides interoperability between which frameworks?
Answer: tensorflow 2. 0 and pytorch

質問と解答を整理してみましょう。

元の文章
Transformers (以前は pytorch-transformers および pytorch-pretrained-bert と呼ばれていた) は、汎用の自然言語理解 (NLU) および Natural 用のアーキテクチャー (BERT、GPT-2、RoBERTa、XLM、DistilBert、XLNet など)、100 以上の言語で 32 以上の事前トレーニング済みモデルを備えた言語生成 (NLG) 性能と、TensorFlow 2.0 と PyTorchとの間での深い相互運用性を有する。
質問解答
Transformers で使用できる事前トレーニング済みのモデルは
いくつありますか?
32以上
Transformers は何を提供しますか?汎用アーキテクチャー
Transformers は、どのフレームワーク間の相互運用性を提供しますか?TensorFlow 2.0 と Pytorch

文章の内容から必要な情報を取得して、与えられた質問に対して適切な回答をしていることがわかりました。

質問応答タスクのまとめ

これまで紹介したように、質問応答タスクを実装しました。

最後にこれまでのコードをまとめると以下のようになります。

from transformers import AutoTokenizer, AutoModelForQuestionAnswering
import torch

# トークナイザーとモデルをインスタンス化
tokenizer = AutoTokenizer.from_pretrained("bert-large-uncased-whole-word-masking-finetuned-squad")
model = AutoModelForQuestionAnswering.from_pretrained("bert-large-uncased-whole-word-masking-finetuned-squad")

# 元の文章(入力)を定義します。
text = r"""
🤗 Transformers (formerly known as pytorch-transformers and pytorch-pretrained-bert) provides general-purpose
architectures (BERT, GPT-2, RoBERTa, XLM, DistilBert, XLNet…) for Natural Language Understanding (NLU) and Natural
Language Generation (NLG) with over 32+ pretrained models in 100+ languages and deep interoperability between
TensorFlow 2.0 and PyTorch.
"""
# 質問を定義します。
questions = [
    "How many pretrained models are available in 🤗 Transformers?",
    "What does 🤗 Transformers provide?",
    "🤗 Transformers provides interoperability between which frameworks?",
]

for question in questions:
    # 質問を反復処理し、テキストと現在の質問からシーケンスを構築
    inputs = tokenizer(question, text, add_special_tokens=True, return_tensors="pt")
    input_ids = inputs["input_ids"].tolist()[0]
    # このシーケンスをモデルに渡して、開始位置と終了位置の両方について、シーケンストークン全体 (質問とテキスト) のスコアの範囲を出力
    outputs = model(**inputs)
    answer_start_scores = outputs.start_logits
    answer_end_scores = outputs.end_logits

    # スコアのargmaxで最も可能性の高い解答の先頭を取得する
    answer_start = torch.argmax(answer_start_scores)

    # スコアのargmaxで最も可能性の高い解答の末尾を取得する
    answer_end = torch.argmax(answer_end_scores) + 1
    
    # top_kメソッドを使用して上位 5 つのトークンを取得
    answer = tokenizer.convert_tokens_to_string(
        tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end])
    )

    print(f"Question: {question}")
    print(f"Answer: {answer}")

実行すると、以下のような結果が出力されます。

Question: How many pretrained models are available in 🤗 Transformers?
Answer: over 32 +
Question: What does 🤗 Transformers provide?
Answer: general - purpose architectures
Question: 🤗 Transformers provides interoperability between which frameworks?
Answer: tensorflow 2. 0 and pytorch

マスク言語モデリングの実装デモ

概要

マスク言語モデリングは、文中の単語の一部をマスクし、それらのマスクを置き換える単語を予測するタスクです。

マスキング トークンを使用してシーケンス内のトークンをマスキングし、そのマスクを適切なトークンで埋めるようにモデルに指示することで、モデルは右側のコンテキスト (マスクの右側のトークン) と左側のコンテキスト (マスクの左側のトークン) の両方に対応できます。

例として、「Distilled models are smaller than the models they mimic. Using them instead of the large versions would help ◯◯◯ our carbon footprint」という文章の、「◯◯◯」部分の穴埋めの候補を出力します。

推論

以下のような手順で処理を進めていきます。

チェックポイント名からトークナイザーとモデルをインスタンス化します。
マスクされた単語の代わりに「tokenizer.mask_token」を置き、マスクされたトークンを持つシーケンスを定義します。
そのシーケンスをIDのリストにエンコードし、そのリストにおけるマスクされたトークンの位置を見つけます。
マスクトークンのインデックスで予測値を取得します。文脈で可能性が高いと思われるトークンに対して高いスコアを与えます。
topkメソッドを用いて上位5つのトークンを取得する。
マスクトークンをトークンで置き換え、結果を表示する。

順番に実行していきましょう。

①チェックポイント名からトークナイザーとモデルをインスタンス化します。

from transformers import AutoModelForMaskedLM, AutoTokenizer
import torch

# チェックポイント名からトークナイザーとモデルをインスタンス化します。
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-cased")
model = AutoModelForMaskedLM.from_pretrained("distilbert-base-cased")

②マスクされた単語の代わりに「tokenizer.mask_token」を置き、マスクされたトークンを持つシーケンスを定義します。

文章の穴埋めをしたい空白部分に「tokenizer.mask_token」と記述することで、穴埋め箇所を指定することができます。

以下の例では、「Distilled models are smaller than the models they mimic. Using them instead of the large versions would help ◯◯◯ our carbon footprint」という文章の◯◯◯部分の穴埋めの候補を出力します。

# マスクされた単語の代わりに「tokenizer.mask_token」を置き、マスクされたトークンを持つシーケンスを定義します。
sequence = (
    "Distilled models are smaller than the models they mimic. Using them instead of the large "
    f"versions would help {tokenizer.mask_token} our carbon footprint."
)

③〜⑥以下の通り、処理を進めます。

# そのシーケンスをIDのリストにエンコードし、そのリストにおけるマスクされたトークンの位置を見つけます。
inputs = tokenizer(sequence, return_tensors="pt")
mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]

# マスクトークンのインデックスで予測値を取得します。
token_logits = model(**inputs).logits
mask_token_logits = token_logits[0, mask_token_index, :]

# topkメソッドを用いて上位5つのトークンを取得する。
top_5_tokens = torch.topk(mask_token_logits, 5, dim=1).indices[0].tolist()

# マスクトークンをトークンで置き換え、結果を表示する。
for token in top_5_tokens:
    print(sequence.replace(tokenizer.mask_token, tokenizer.decode([token])))

実行すると、以下のような結果が出力されます。

Distilled models are smaller than the models they mimic. Using them instead of the large versions would help reduce our carbon footprint.
Distilled models are smaller than the models they mimic. Using them instead of the large versions would help increase our carbon footprint.
Distilled models are smaller than the models they mimic. Using them instead of the large versions would help decrease our carbon footprint.
Distilled models are smaller than the models they mimic. Using them instead of the large versions would help offset our carbon footprint.
Distilled models are smaller than the models they mimic. Using them instead of the large versions would help improve our carbon footprint.

モデルによって予測された、上位5つのトークンを含む5つのシーケンスを表示しています。

最も上位の候補の結果で、穴埋めの前後を比較すると以下のようになります。

穴埋め前
(入力)
Distilled models are smaller than the models they mimic. Using them instead of the large versions would help ◯◯◯ our carbon footprint
穴埋め後
(出力)
Distilled models are smaller than the models they mimic. Using them instead of the large versions would help reduce our carbon footprint.

自然な文章として成立する結果が得られることがわかりました。

マスク言語モデルタスクのまとめ

これまで紹介したように、質問応答タスクを実装しました。

最後にこれまでのコードをまとめると以下のようになります。

from transformers import AutoModelForMaskedLM, AutoTokenizer
import torch

# チェックポイント名からトークナイザーとモデルをインスタンス化。
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-cased")
model = AutoModelForMaskedLM.from_pretrained("distilbert-base-cased")

# マスクされた単語の代わりに「tokenizer.mask_token」を置き、マスクされたトークンを持つシーケンスを定義。
sequence = (
    "Distilled models are smaller than the models they mimic. Using them instead of the large "
    f"versions would help {tokenizer.mask_token} our carbon footprint."
)

# そのシーケンスをIDのリストにエンコードし、そのリストにおけるマスクされたトークンの位置を見つける。
inputs = tokenizer(sequence, return_tensors="pt")
mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]

# マスクトークンのインデックスで予測値を取得。
token_logits = model(**inputs).logits
mask_token_logits = token_logits[0, mask_token_index, :]

# topkメソッドを用いて上位5つのトークンを取得。
top_5_tokens = torch.topk(mask_token_logits, 5, dim=1).indices[0].tolist()

# マスクトークンをトークンで置き換え、結果を表示。
for token in top_5_tokens:
    print(sequence.replace(tokenizer.mask_token, tokenizer.decode([token])))

実行すると、以下のような結果が出力されます。

Distilled models are smaller than the models they mimic. Using them instead of the large versions would help reduce our carbon footprint.
Distilled models are smaller than the models they mimic. Using them instead of the large versions would help increase our carbon footprint.
Distilled models are smaller than the models they mimic. Using them instead of the large versions would help decrease our carbon footprint.
Distilled models are smaller than the models they mimic. Using them instead of the large versions would help offset our carbon footprint.
Distilled models are smaller than the models they mimic. Using them instead of the large versions would help improve our carbon footprint.

因果関係言語モデリングの実装デモ

概要

因果関係言語モデリングは、一連のトークンの後に続くトークンを予測するタスクです。

モデルは左の文脈(マスクの左側にあるトークン)のみに注目し、次のトークンはモデルが入力シーケンスから生成した最後の隠れ状態のロジットからサンプリングして予測します。

これにより、元のシーケンスに続く首尾一貫した次のトークンが出力されます。

以下の例では、「Hugging Face is based in DUMBO, New York City, and ◯◯◯」 に続く、◯◯◯に来る単語を出力します。

推論

from transformers import AutoModelForCausalLM, AutoTokenizer, top_k_top_p_filtering
import torch
from torch import nn

# チェックポイント名からトークナイザーとモデルをインスタンス化します。
tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2")

# シーケンスを定義します。
sequence = f"Hugging Face is based in DUMBO, New York City, and"

# そのシーケンスをIDのリストにエンコードします。
inputs = tokenizer(sequence, return_tensors="pt")
input_ids = inputs["input_ids"]

# ロジットを取得します。
next_token_logits = model(**inputs).logits[:, -1, :]

# ftop_k_top_p_filtering()によるフィルター
filtered_next_token_logits = top_k_top_p_filtering(next_token_logits, top_k=50, top_p=1.0)

# サンプルを出力
probs = nn.functional.softmax(filtered_next_token_logits, dim=-1)
next_token = torch.multinomial(probs, num_samples=1)

generated = torch.cat([input_ids, next_token], dim=-1)

resulting_string = tokenizer.decode(generated.tolist()[0])
print(resulting_string)

実行すると、以下のような結果が出力されます。

Hugging Face is based in DUMBO, New York City, and is

結果をまとめると以下のようになります。

(入力) Hugging Face is based in DUMBO, New York City, and ◯◯◯
(出力) Hugging Face is based in DUMBO, New York City, and is

「and」の次に来る単語の例として、「 is」を挙げています。

この文脈から次に来る単語としては妥当であるといえます。

テキスト生成の実装デモ

概要

テキスト生成 (オープンエンド テキスト生成とも呼ば れます) の目標は、特定のコンテキストからの継続であるテキストの一貫した部分を作成することです。

以下の例は、GPT2を使用してテキストを生成する方法を示しています。

「Today I believe we can finally 〜」という文章の続きの文章を出力します。

推論

from transformers import AutoTokenizer, AutoModelForCausalLM

# チェックポイント名からトークナイザーとモデルをインスタンス化。
tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2")

# エンコード
prompt = "Today I believe we can finally"
input_ids = tokenizer(prompt, return_tensors="pt").input_ids

# 最大 30 個のトークンを生成
outputs = model.generate(input_ids, do_sample=False, max_length=30)
tokenizer.batch_decode(outputs, skip_special_tokens=True)

以下のような出力結果を得ます。

[Today I believe we can finally get to the point where we can make a difference in the lives of the people of the United States of America.]
# 私たちはついにアメリカ合衆国の人々の生活に変化をもたらすことができると信じています。

結果をまとめると以下のようになります。

(入力) Today I believe we can finally 〜
(出力) Today I believe we can finally get to the point where we can make a difference in the lives of the people of the United States of America

「Today I believe we can finally 〜」に続く文章が生成されました。

要約の実装デモ

概要

要約は、重要な情報を保持しながらドキュメントや記事を短いテキストに要約するタスクです。

元の入力からテキストを抽出できるモデルもあれば、まったく新しいテキストを生成できるモデルもあります。

以下は、ニュース記事の要約を行う例です。

推論

from transformers import AutoModelForSeq2SeqLM, AutoTokenizer

# チェックポイント名からトークナイザーとモデルをインスタンス化。
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
tokenizer = AutoTokenizer.from_pretrained("t5-base")

# 入力する記事を定義。
ARTICLE = """ New York (CNN)When Liana Barrientos was 23 years old, she got married in Westchester County, New York.
A year later, she got married again in Westchester County, but to a different man and without divorcing her first husband.
Only 18 days after that marriage, she got hitched yet again. Then, Barrientos declared "I do" five more times, sometimes only within two weeks of each other.
In 2010, she married once more, this time in the Bronx. In an application for a marriage license, she stated it was her "first and only" marriage.
Barrientos, now 39, is facing two criminal counts of "offering a false instrument for filing in the first degree," referring to her false statements on the
2010 marriage license application, according to court documents.
Prosecutors said the marriages were part of an immigration scam.
On Friday, she pleaded not guilty at State Supreme Court in the Bronx, according to her attorney, Christopher Wright, who declined to comment further.
After leaving court, Barrientos was arrested and charged with theft of service and criminal trespass for allegedly sneaking into the New York subway through an emergency exit, said Detective
Annette Markowski, a police spokeswoman. In total, Barrientos has been married 10 times, with nine of her marriages occurring between 1999 and 2002.
All occurred either in Westchester County, Long Island, New Jersey or the Bronx. She is believed to still be married to four men, and at one time, she was married to eight men at once, prosecutors say.
Prosecutors said the immigration scam involved some of her husbands, who filed for permanent residence status shortly after the marriages.
Any divorces happened only after such filings were approved. It was unclear whether any of the men will be prosecuted.
The case was referred to the Bronx District Attorney\'s Office by Immigration and Customs Enforcement and the Department of Homeland Security\'s
Investigation Division. Seven of the men are from so-called "red-flagged" countries, including Egypt, Turkey, Georgia, Pakistan and Mali.
Her eighth husband, Rashid Rajput, was deported in 2006 to his native Pakistan after an investigation by the Joint Terrorism Task Force.
If convicted, Barrientos faces up to four years in prison.  Her next court appearance is scheduled for May 18.
"""

# T5ではmax_lengthが512なので、記事を512トークンに切り詰める。
inputs = tokenizer("summarize: " + ARTICLE, return_tensors="pt", max_length=512, truncation=True)

# 結果を出力
outputs = model.generate(
    inputs["input_ids"], max_length=150, min_length=40, length_penalty=2.0, num_beams=4, early_stopping=True
)

print(tokenizer.decode(outputs[0], skip_special_tokens=True))

以下のような出力結果を得ます。

prosecutors say the marriages were part of an immigration scam. if convicted, barrientos faces two criminal counts of "offering a false instrument for filing in the first degree" she has been married 10 times, nine of them between 1999 and 2002.

結果をまとめると以下のようになります。

入力
ニューヨーク(CNN)リアナ・バリエントスさんは23歳のとき、ニューヨーク州ウエストチェスター郡で結婚した。
1年後、彼女はウエストチェスター郡で再婚したが、相手は別の男性で、最初の夫とは離婚せずに結婚した。
その結婚からわずか18日後、彼女はまたもや結婚した。その後、バリェントスはさらに5回「I do」と宣言し、時には2週間以内に結婚した。
2010年、彼女はもう一度、今度はブロンクスで結婚した。結婚許可証の申請書には、「最初で最後の」結婚であると書かれていた。
現在39歳のバリェントスは、「第一級虚偽提出物提供」の2つの刑事訴追を受けており、これは2010年の結婚許可申請における彼女の虚偽記載に言及している。
裁判資料によると、2010年の結婚許可証の申請書に虚偽の記載をしたことが原因だ。
検察は、結婚が移民詐欺の一部であると述べている。
金曜日にブロンクスの州最高裁判所で無罪を主張したと、彼女の弁護士であるクリストファー・ライトは述べた。
法廷を出た後、バリェントスは、非常口からニューヨークの地下鉄に忍び込んだという理由で、サービスの窃盗と不法侵入で逮捕・起訴されたと、アネット・マコウスキー刑事は語った。
警察の広報担当者であるアネット・マーコウスキー刑事は、次のように述べています。バリェントスさんは合計で10回結婚しており、そのうち9回は1999年から2002年にかけて結婚している。
いずれもウエストチェスター郡、ロングアイランド、ニュージャージー、ブロンクスのいずれかで行われた。彼女は現在も4人の男性と結婚していると思われ、一時期は8人の男性と同時に結婚していたと検察は述べている。
検察によると、移民詐欺には、結婚後すぐに永住権を申請した夫たちも含まれていた。
離婚は、その申請が承認された後に行われた。この中の誰かが起訴されるかどうかは不明である。
この事件は、移民税関捜査局と国土安全保障省捜査局によってブロンクス地方検事局に付託された。
捜査部門から照会があった このうち7人は、エジプト、トルコ、グルジア、パキスタン、マリなど、いわゆる「レッドフラッグ国」の出身です。
8番目の夫であるRashid Rajputは、Joint Terrorism Task Forceによる調査の後、2006年に母国パキスタンに強制送還されました。
有罪判決を受けた場合、Barrientosは最高4年の禁固刑に直面することになります。 次回の出廷は5月18日に予定されています。
出力(要約結果)
検察は、結婚は移民詐欺の一部であったと述べています。もし有罪になれば、Barrientosは「第一級虚偽申告書提供」の2つの刑事訴追を受けることになります。彼女は10回結婚し、そのうち9回は1999年から2002年の間に結婚しています。

入力したニュース記事の内容を、要約して出力することができました。

翻訳の実装デモ

概要

翻訳とは、テキストをある言語から別の言語に翻訳する作業です。

推論

以下のような手順で処理を進めていきます。

チェックポイント名からトークナイザーとモデルをインスタンス化します。要約は通常、Bart や T5 のようなエンコーダ・デコーダモデルを用いて行われます。
要約する記事を定義します。
T5特有のプレフィックス “translate English to German: ” を追加します。
PreTrainedModel.generate()メソッドを使用して翻訳を実行します。

翻訳とは、テキストをある言語から別の言語に翻訳する作業です。

翻訳データセットの例として、WMT の英語からドイツ語へのデータセットがあります。

このデータセットには、英語の文が入力データとして含まれ、対応するドイツ語の文がターゲット データとして含まれています。

以下は、パイプラインを使用して英語からドイツ語へ翻訳を行う例です。

from transformers import AutoModelForSeq2SeqLM, AutoTokenizer

# チェックポイント名からトークナイザーとモデルをインスタンス化
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
tokenizer = AutoTokenizer.from_pretrained("t5-base")

# T5特有のプレフィックス「translate English to German:」を追加
inputs = tokenizer(
    "translate English to German: Hugging Face is a technology company based in New York and Paris",
    return_tensors="pt",
)

# PreTrainedModel.generate()メソッドを使用して翻訳を実行
outputs = model.generate(inputs["input_ids"], max_length=40, num_beams=4, early_stopping=True)

print(tokenizer.decode(outputs[0], skip_special_tokens=True))

以下のような出力結果を得ます。

Hugging Face ist ein Technologieunternehmen mit Sitz in New York und Paris.

英語からドイツ語への変換ができました。

まとめ

最後までご覧いただきありがとうございました。

今回の記事ではHuggingface Transformersの入門として、概要とトークナイザーによる基本的なタスクのデモを紹介しました。

次回からは文章分類の学習の実装を紹介します。

是非ご覧ください。

【🔰Huggingface Transformers入門⑥】文章分類モデルを作成する(1) 〜CSVからデータセットを作成する〜

このシリーズでは、自然言語処理において主流であるTransformerを中心に、環境構築から学習の方法までまとめます。 今回の記事ではHuggingface Transformersの入門として…