# Course

## Docs

- [章末クイズ](https://huggingface.co/learn/course/ja/chapter7/9.md)
- [要約](https://huggingface.co/learn/course/ja/chapter7/5.md)
- [イントロダクション](https://huggingface.co/learn/course/ja/chapter7/1.md)
- [マスク言語モデルの微調整](https://huggingface.co/learn/course/ja/chapter7/3.md)
- [因果言語モデルを一から学習](https://huggingface.co/learn/course/ja/chapter7/6.md)
- [NLPをマスター](https://huggingface.co/learn/course/ja/chapter7/8.md)
- [翻訳](https://huggingface.co/learn/course/ja/chapter7/4.md)
- [質問応答](https://huggingface.co/learn/course/ja/chapter7/7.md)
- [トークン分類](https://huggingface.co/learn/course/ja/chapter7/2.md)
- [パート1終了！](https://huggingface.co/learn/course/ja/chapter4/5.md)
- [ハギングフェイスハブ](https://huggingface.co/learn/course/ja/chapter4/1.md)
- [学習済みモデルを共有する](https://huggingface.co/learn/course/ja/chapter4/3.md)
- [チャプター修了クイズ](https://huggingface.co/learn/course/ja/chapter4/6.md)
- [モデルカードを作成する](https://huggingface.co/learn/course/ja/chapter4/4.md)
- [学習済みモデルを使う](https://huggingface.co/learn/course/ja/chapter4/2.md)
- [イントロダクション](https://huggingface.co/learn/course/ja/chapter8/1.md)
- [パート２終了!](https://huggingface.co/learn/course/ja/chapter8/6.md)
- [エラーを見つけた時に最初にすること](https://huggingface.co/learn/course/ja/chapter8/2.md)
- [パート2公開記念イベント](https://huggingface.co/learn/course/ja/events/2.md)
- [複数系列の処理](https://huggingface.co/learn/course/ja/chapter2/5.md)
- [イントロダクション](https://huggingface.co/learn/course/ja/chapter2/1.md)
- [モデル](https://huggingface.co/learn/course/ja/chapter2/3.md)
- [トークナイザ](https://huggingface.co/learn/course/ja/chapter2/4.md)
- [pipelineの裏側](https://huggingface.co/learn/course/ja/chapter2/2.md)
- [イントロダクション](https://huggingface.co/learn/course/ja/chapter0/1.md)
- [まとめ](https://huggingface.co/learn/course/ja/chapter1/9.md)
- [エンコーダーモデル](https://huggingface.co/learn/course/ja/chapter1/5.md)
- [イントロダクション](https://huggingface.co/learn/course/ja/chapter1/1.md)
- [Transformersで何ができる?](https://huggingface.co/learn/course/ja/chapter1/3.md)
- [デコーダーモデル](https://huggingface.co/learn/course/ja/chapter1/6.md)
- [章末クイズ](https://huggingface.co/learn/course/ja/chapter1/10.md)
- [バイアスと限界](https://huggingface.co/learn/course/ja/chapter1/8.md)
- [Transformersの仕組みについて](https://huggingface.co/learn/course/ja/chapter1/4.md)
- [Sequence-to-sequence モデル](https://huggingface.co/learn/course/ja/chapter1/7.md)
- [自然言語処理 / NLP(Natural Language Processing)](https://huggingface.co/learn/course/ja/chapter1/2.md)

### 章末クイズ
https://huggingface.co/learn/course/ja/chapter7/9.md

# 章末クイズ

<CourseFloatingBanner
    chapter={7}
    classNames="absolute z-10 right-0 top-0"
/>

この章で学んだことをテストしてみましょう！

### 1. 次のタスクのうち、トークン分類問題として組み立てられるものはどれでしょうか？

<Question
	choices={[
		{
			text: "文中の文法的な構成要素を見つける。",
			explain: "正解! あとは各単語に名詞、動詞などのラベルをつければいいです。",
			correct: true
		},
		{
			text: "文が文法的に正しいかどうかを調べる。",
			explain: "いいえ、それはシーケンス分類の問題です。"
		},
		{
			text: "文中で言及されている人物を見つける。",
			explain: "正解! 各単語に人物かそうでないかのラベルをつければよいです。",
            correct: true
		},
        {
			text: "質問の答えとなる単語の塊を文中から見つける。",
			explain: "いいえ、それは質問応答問題でしょう。"
		}
	]}
/>

### 2. トークン分類のための前処理は、他の前処理パイプラインとどの部分が違うのでしょうか？

<Question
	choices={[
		{
			text: "何もする必要はありません。テキストはすでにトークン化されています。",
			explain: "テキストは確かに別々の単語として与えられていますが、それでもサブワード型トークン化モデルを適用する必要があります。"
		},
		{
			text: "テキストは単語として与えられているので、サブワード トークン化を適用するだけです。",
			explain: "正解! これは、トークン化パイプラインをすべて適用する必要がある、通常の前処理とは異なります。他の違いも思いつきますか？",
			correct: true
		},
		{
			text: "特殊なトークンには <code>-100</code> を使ってラベル付けしています。",
			explain: "これはトークン分類に限ったことではありません。損失で無視したいトークンのラベルには、常に<code>-100</code>を使用します。"
		},
		{
			text: "単語を切り捨て/パディングを適用する際に、ラベルも入力と同じサイズに切り捨てるかパディングする必要があります。",
			explain: "確かに! しかし、それだけが違いではありません。",
			correct: true
		}
	]}
/>

### 3.トークン分類問題で単語をトークン化し、そのトークンにラベルを付けたい場合、どのような問題がありますか？

<Question
	choices={[
		{
			text: "トークナイザーは特別なトークンを追加しますが、それに対応するラベルがありません。",
			explain: "損失で無視されるように、これらに<code>-100</code>の特別なラベルを付ける事ができます。"
		},
		{
			text: "各単語は複数のトークンを生成できるため、ラベルの数よりも多くのトークンを持つことになります。",
			explain: "これが主な問題になります。元のラベルとトークンを揃える必要があります。",
			correct: true
		},
		{
			text: "追加されたトークンはラベルを持たないので、問題はありません。",
			explain: "それは正しくありません。トークンと同じ数のラベルが必要です。そうしないと、モデルがエラーになります。"
		}
	]}
/>

### 4. 「ドメイン適応」とはどういう意味ですか？

<Question
	choices={[
		{
			text: "あるデータセットに対してモデルを実行し、そのデータセット内の各サンプルに対する予測値を得ることです。",
			explain: "いいえ、これは推論タスクを実行しているだけです。"
		},
		{
			text: "あるデータセットでモデルを学習することです。",
			explain: "いいえ、これはモデルのトレーニングです。そこに適応がありません。"
		},
		{
			text: "事前に学習したモデルを新しいデータセットを微調整することで、そのデータセットに適応した予測をすることです。",
			explain: "正解! モデルは新しいデータセットに知識を適応させました。",
            correct: true
		},
        {
			text: "モデルをより堅牢にするために、誤分類されたサンプルをデータセットに追加することです。",
			explain: "確かに定期的にモデルを再トレーニングするのであれば行うべきことですが、それはドメイン適応ではありません。"
		}
	]}
/>

### 5. マスク言語モデリング問題におけるラベルとは何ですか？

<Question
	choices={[
		{
			text: "入力文の一部のトークンはランダムにマスクされます。ラベルは元の入力トークンです。",
			explain: "それです！",
            correct: true
		},
		{
			text: "入力文のいくつかのトークンはランダムにマスクされ、ラベルは元の入力トークンを左にシフトしたものです。",
			explain: "いいえ、ラベルを左にず>らすことは次の単語を予測することに相当し、これは因果言語モデリングです。"
		},
		{
			text: "入力文の一部のトークンをランダムにマスクし、その文が肯定的か否定的かをラベルとします。",
			explain: "これはデータ拡張を伴うシーケンス分類の問題で、マスク言語モデリングではありません。"
		},
        {
			text: "2つの入力文のトークンの一部がランダムにマスクされた後、ラベルとは2つの文が類似しているかどうかになります。",
			explain: "これはデータ拡張を伴うシーケンス分類の問題であり>、マスク言語モデリングではありません。"
		}
	]}
/>

### 6. 以下の作業のうち、シーケンス間問題と見なせるものはどれですか？

<Question
	choices={[
		{
			text: "長い文書の短いレビューを書く",
			explain: "はい、それは要約問題です。他の答えも探してみてください！",
            correct: true
		},
		{
			text: "文書に関する質問に答える",
			explain: "これはシーケンス間問題として組み立てられます。しかし、他にも正解はあります。",
            correct: true
		},
		{
			text: "中国語の文章を英語に翻訳する",
			explain: "これは間違いなくシーケンス間問題です。他の正解も見つけられますか？",
            correct: true
		},
        {
			text: "甥っ子/友人が送ってきたメッセージを正しい英語に直す",
			explain: "これは一種の翻訳問題なので、シーケンス間タスクに間違いありません。しかし、これだけが正解ではありません！",
			correct: true
		}
	]}
/>

### 7. シーケンス間問題におけるデータの前処理はどのように行うのが適切でしょうか？

<Question
	choices={[
		{
			text: "入力とターゲットは<code>inputs=...</code>と<code>targets=...</code>で一緒にトークナイザーに送らなければなりません。",
			explain: "これは将来的に>追加するAPIかもしれませんが、今はまだ不可能です。"
		},
		{
			text: "入力とターゲットの両方を前処理する必要があり、トークナイザーを2回別々に呼び出す必要があります。",
			explain: "その通りですが、不完全です。トークナイザーが両方を適切に処理できるようにするために必要なことがあります。"
		},
		{
			text: "いつも通り、入力をトークン化すればいいだけです。",
			explain: "シーケンス分類の問題ではありません。ターゲットも数値に変換する必要があるテキストです！"
		},
        {
			text: "入力はトークナイザーに送られなければなりません。ターゲットもですが、特別なコンテキストマネージャーの下で送らなければなりません。",
			explain: "その通りです。トークナイザは、そのコンテキストマネージャによってターゲットモードにする必要があります。",
			correct: true
		}
	]}
/>

{#if fw === 'pt'}

### 8. なぜシーケンス間問題には `Trainer` の特定のサブクラスが存在するのでしょうか？

<Question
	choices={[
		{
			text: "シーケンス間問題はカスタム損失を使い、<code>-100</code>に設定されたラベルを無視するためです。",
			explain: "それはカスタム損失固有の問題ではなく、損失が計算される際は常にそうなります。"
		},
		{
			text: "シーケンス間問題には特別な評価ループが必要だからです。",
			explain: "その通りです。シーケンス間モデルの予測は <code>generate()</code>メソッドで実行されることが多いです。",
			correct: true
		},
		{
			text: "シーケンス間問題ではターゲットがテキストになるためです。",
			explain: "事前に前処理されているので、<code>Trainer</code>はあまり気にしません。"
		},
        {
			text: "シーケンス間問題では2つのモデルを使用するためです。",
			explain: "ある意味2つのモデルを使用しています。エンコーダーとデコーダーですが、1つのモデルにまとめられています。"
		}
	]}
/>

{:else}

### 9. Transformerモデルで `compile()` を呼び出す際に、損失を指定する必要がないことが多いのはなぜですか？

<Question
	choices={[
		{
			text: "Transformerのモデルは教師なし学習でトレーニングされるからです。",
			explain: "そうではありません。教師なし学習でも損失関数が必要なのです！"
		},
		{
			text: "モデル内部の損失出力がデフォルトで使われるからです。",
			explain: "その通りです！",
			correct: true
		},
		{
			text: "代わりに学習後に指標を計算するからです。",
			explain: "よくやる事ですが、これでは学習時に最適化に使用する損失値をどこから得ているのか説明がつきません。"
		},
        {
			text: "損失は `model.fit()` で代わりに指定されているからです。",
			explain: "いいえ、損失関数は `model.compile()` を実行すると常に固定され、 `model.fit()` で変更することはできません。"
		}
	]}
/>

{/if}

### 10. 新しいモデルの事前学習はいつ行うべきですか？

<Question
	choices={[
		{
			text: "特定の言語で利用できる事前学習済みモデルがない場合",
			explain: "その通りです。",
			correct: true
		},
		{
			text: "たとえ事前学習済みモデルがあったとしても、利用可能なデータがたくさんある場合",
			explain: "この場合、膨大な計算コストを避けるために、事前学習済みのモデルを使用し>て、データ上で微調整を行うべきでしょう。"
		},
		{
			text: "使用している事前学習済みモデルのバイアスに懸念がある場合",
			explain: "その通りですが、学習に使用するデータが本当に良いものであることをよく確認する必要があります。",
			correct: true
		},
        {
			text: "利用できる事前学習済みモデルが十分に良い性能ではない場合",
			explain: "学習時にきちんとデバッグができていますか？"
		}
	]}
/>

### 11. なぜ、たくさんのテキストで言語モデルを事前学習する事は簡単なのですか？

<Question
	choices={[
		{
			text: "インターネット上にたくさんのテキストがあるからです。",
			explain: "確かにそうですが、それでは質問に答えているとは言えません。もう一度試してみてください。"
		},
		{
			text: "事前学習の目的では人間がデータにラベル付けする必要がないからです",
			explain: "その通りです。言語モデリングは自己教師あり問題です。",
			correct: true
		},
		{
			text: "🤗 Transformers は数行のコードで学習を開始することができるからです。",
			explain: "確かにそうですが、それでは質問されたことに答えられません。別の答えを試してみてください！"
		}
	]}
/>

### 12. 質問応答タスクのためにデータを前処理する際の主な課題は何ですか？

<Question
	choices={[
		{
			text: "入力をトークン化する必要があります。",
			explain: "その通りですが、本当に主な課題でしょうか？"
		},
		{
			text: "非常に長い文脈を扱う必要があり、その中には、答えに繋がるかどうかわからないいくつかの学習対象となる特徴があります。",
			explain: "これは間違いなく課題の1つです。",
			correct: true
		},
		{
			text: "入力だけでなく、質問に対する答えもトークン化する必要があります。",
			explain: "いいえ、質問回答の問題をシーケンス間タスクとして組み立てているのでなければ、そうではありません。"
		},
       {
			text: "テキスト内の回答の範囲から、トークン化された入力の開始と終了のトークンを見つけなければなりません。",
			explain: "それは難しい部分の1つです、はい！",
			correct: true
		}
	]}
/>

### 13. 質問応答では通常どのように後処理が行われますか？

<Question
	choices={[
		{
			text: "モデルが回答の開始と終了の位置を与えるので、対応するトークンの範囲をデコードするだけです。",
			explain: "それも一つの方法かもしれませんが、ちょっと単純すぎますね。"
		},
		{
			text: "モデルは、1つの例文から作成した各特徴の開始位置と終了位置を与えるので、最も良いスコアを持つものの中から対応するトークンの範囲を解読すればよいです。",
			explain: "私たちが勉強した後処理に近いですが、完全に正しいわけではありません。"
		},
		{
			text: "このモデルでは、1つの例文から作成した各特徴の答えの開始位置と終了位置を与えるので、ベストスコアを出した方のコンテキストの範囲に合わせればいいだけです。",
			explain: "簡単に言うとそれだけです！",
			correct: true
		},
        {
			text: "モデルが答えを生成するので、あなたはそれを解読すればいいだけです。",
			explain: "いいえ、質問応答問題をシーケンス間タスクとして組み立てているのでなければ、そうではありません。"
		}
	]}
/>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter7/9.mdx" />

### 要約
https://huggingface.co/learn/course/ja/chapter7/5.md

# 要約

{#if fw === 'pt'}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section5_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section5_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section5_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section5_tf.ipynb"},
]} />

{/if}

このセクションでは、Transformerモデルを使用して、長いドキュメントを要約する方法を見ていきます。これは、_文章要約_ として知られるタスクです。 これは、長い文章を理解したり、ドキュメントの主要なトピックを補足する一貫性のあるテキストを生成したりするなど、さまざまな能力を必要とするため、最も困難なNLPタスクの1つです。 ただし、テキストの要約は、うまく行けば、領域の専門家が長いドキュメントを詳細に読む負担を軽減することで、さまざまなビジネスプロセスをスピードアップできる強力なツールになります。

<Youtube id="yHnr5Dk2zCI"/>

[ハギングフェイス ハブ](https://huggingface.co/models?pipeline_tag=summarization&sort=downloads)には、要約用に微調整されたさまざまなモデルがすでに存在しますが、これらのほとんどは英語のドキュメントにのみ適しています。 したがって、このセクションにひねりを加えるために、英語とスペイン語のバイリンガルモデルをトレーニングします。 このセクションの終わりまでに、ここに示すようなカスタマーレビューを要約できる[モデル](https://huggingface.co/huggingface-course/mt5-small-finetuned-amazon-en-es)ができあがります。 

<iframe src="https://course-demos-mt5-small-finetuned-amazon-en-es.hf.space" frameBorder="0" height="400" title="Gradio app" class="block dark:hidden container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

これから説明するように、これらの要約は、顧客が製品レビュー投稿時につけたタイトル文を使って学習されているため、簡潔です。 このタスクに適した多言語コーパスをまとめることから始めましょう。

## 多言語コーパスの準備

[Multilingual Amazon Reviews Corpus](https://huggingface.co/datasets/amazon_reviews_multi)を使用して、多言語要約器を作成します。このコーパスは、6つの言語でのAmazon製品レビューで構成されており、通常、多言語分類子のベンチマークに使用されます。 ただし、各レビューには短いタイトルが付いているため、モデルが学習対象とする要約文としてタイトルを使用できます。 開始するには、ハギングフェイス ハブから英語とスペイン語のサブセットをダウンロードしましょう。

```python
from datasets import load_dataset

spanish_dataset = load_dataset("amazon_reviews_multi", "es")
english_dataset = load_dataset("amazon_reviews_multi", "en")
english_dataset
```

```python out
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
    })
})
```

ご覧の通り、各言語の `train` 分割には 200,000 件のレビューがあり、 `validation` と `test` 分割にはそれぞれ 5,000 件のレビューがあります。私達が内容を知りたいレビュー情報は `review_body` と `review_title` カラムに含まれています。[第5章](/course/ja/chapter5) で学んだ手法で、トレーニングセットからランダムにサンプルを取得する簡単な関数を作成し、いくつかの例を見てみましょう。

```python
def show_samples(dataset, num_samples=3, seed=42):
    sample = dataset["train"].shuffle(seed=seed).select(range(num_samples))
    for example in sample:
        print(f"\n'>> Title: {example['review_title']}'")
        print(f"'>> Review: {example['review_body']}'")


show_samples(english_dataset)
```

```python out
'>> Title: Worked in front position, not rear'
'>> Review: 3 stars because these are not rear brakes as stated in the item description. At least the mount adapter only worked on the front fork of the bike that I got it for.'

'>> Title: meh'
'>> Review: Does it’s job and it’s gorgeous but mine is falling apart, I had to basically put it together again with hot glue'

'>> Title: Can\'t beat these for the money'
'>> Review: Bought this for handling miscellaneous aircraft parts and hanger "stuff" that I needed to organize; it really fit the bill. The unit arrived quickly, was well packaged and arrived intact (always a good sign). There are five wall mounts-- three on the top and two on the bottom. I wanted to mount it on the wall, so all I had to do was to remove the top two layers of plastic drawers, as well as the bottom corner drawers, place it when I wanted and mark it; I then used some of the new plastic screw in wall anchors (the 50 pound variety) and it easily mounted to the wall. Some have remarked that they wanted dividers for the drawers, and that they made those. Good idea. My application was that I needed something that I can see the contents at about eye level, so I wanted the fuller-sized drawers. I also like that these are the new plastic that doesn\'t get brittle and split like my older plastic drawers did. I like the all-plastic construction. It\'s heavy duty enough to hold metal parts, but being made of plastic it\'s not as heavy as a metal frame, so you can easily mount it to the wall and still load it up with heavy stuff, or light stuff. No problem there. For the money, you can\'t beat it. Best one of these I\'ve bought to date-- and I\'ve been using some version of these for over forty years.'
```

<Tip>

✏️ ** あなたの番です！ ** `Dataset.shuffle()` コマンドのランダムシードを変更して、コーパスの他のレビューも調べてみてください。もしあなたがスペイン語を話せるなら、`spanish_dataset` にあるいくつかのレビューを見て、タイトルも妥当な要約に見えるかどうか確かめてみてください。

</Tip>

このサンプルは、肯定的なレビューから否定的なレビューまで（そしてその中間にある全てのレビュー！）、一般的にオンラインで見られるレビューの多様性を示しています。 「meh」というタイトルはあまり有益な情報を示すタイトルではありませんが、他のタイトルはレビュー自体の適切な要約のように見えます。40万件のレビューすべてについて要約モデルをトレーニングすることは、単一のGPUではあまりにも時間がかかりすぎるため、その代わりに、単一製品のドメインについて要約を生成することに焦点を当てます。どのようなドメインから選択できるかを知るために、`english_dataset` を `pandas.DataFrame` に変換して、製品カテゴリごとのレビュー数を計算してみましょう。

```python
english_dataset.set_format("pandas")
english_df = english_dataset["train"][:]
# Show counts for top 20 products
english_df["product_category"].value_counts()[:20]
```

```python out
home                      17679
apparel                   15951
wireless                  15717
other                     13418
beauty                    12091
drugstore                 11730
kitchen                   10382
toy                        8745
sports                     8277
automotive                 7506
lawn_and_garden            7327
home_improvement           7136
pet_products               7082
digital_ebook_purchase     6749
pc                         6401
electronics                6186
office_product             5521
shoes                      5197
grocery                    4730
book                       3756
Name: product_category, dtype: int64
```

英語のデータセットで最も人気のある商品は、家庭用品、衣類、ワイヤレス電子機器に関するものです。しかし、Amazon本来のテーマに沿って、書評の要約に焦点を当てましょう。結局のところ、書籍はこの会社が設立された際の商品なのです! 2つの製品カテゴリ(`book` と `digital_ebook_purchase`) が当てはまるので、これらの製品について両言語でデータセットをフィルタリングしてみましょう。[第5章](/course/ja/chapter5) で見たように、 `Dataset.filter()` 関数を使うと非常に効率的にデータセットをスライスできるので、これを行うための簡単な関数を定義してみましょう。

```python
def filter_books(example):
    return (
        example["product_category"] == "book"
        or example["product_category"] == "digital_ebook_purchase"
    )
```

この関数を `english_dataset` と `spanish_dataset` に適用すると、書籍のカテゴリを含む行だけが結果に含まれるようになります。フィルタを適用する前に、`english_dataset` のフォーマットを `"pandas"` から `"arrow"` に戻してみましょう。

```python
english_dataset.reset_format()
```

次に、フィルター機能を適用し、サニティーチェックとして、レビューのサンプルが本当に本に関するものかどうかを調べてみましょう。

```python
spanish_books = spanish_dataset.filter(filter_books)
english_books = english_dataset.filter(filter_books)
show_samples(english_books)
```

```python out
'>> Title: I\'m dissapointed.'
'>> Review: I guess I had higher expectations for this book from the reviews. I really thought I\'d at least like it. The plot idea was great. I loved Ash but, it just didnt go anywhere. Most of the book was about their radio show and talking to callers. I wanted the author to dig deeper so we could really get to know the characters. All we know about Grace is that she is attractive looking, Latino and is kind of a brat. I\'m dissapointed.'

'>> Title: Good art, good price, poor design'
'>> Review: I had gotten the DC Vintage calendar the past two years, but it was on backorder forever this year and I saw they had shrunk the dimensions for no good reason. This one has good art choices but the design has the fold going through the picture, so it\'s less aesthetically pleasing, especially if you want to keep a picture to hang. For the price, a good calendar'

'>> Title: Helpful'
'>> Review: Nearly all the tips useful and. I consider myself an intermediate to advanced user of OneNote. I would highly recommend.'
```

レビューが厳密に本についてではなく、カレンダーやOneNoteのような電子アプリケーションのようなものを参照している可能性があることがわかります。それでも、このドメインは要約モデルを学習させるのに適していると思われます。このタスクに適した様々なモデルを見る前に、最後のデータ準備として、英語とスペイン語のレビューを1つの `DatasetDict` オブジェクトとして結合する必要があります。🤗 Datasetsには便利な `concatenate_datasets()` 関数があり、（その名の通り）2つの `Dataset` オブジェクトを重ね合わせることができます。つまり、バイリンガル・データセットを作成するために、各分割をループし、その分割データセットを連結し、モデルが単一言語に過剰適合しないように結果をシャッフルします。

```python
from datasets import concatenate_datasets, DatasetDict

books_dataset = DatasetDict()

for split in english_books.keys():
    books_dataset[split] = concatenate_datasets(
        [english_books[split], spanish_books[split]]
    )
    books_dataset[split] = books_dataset[split].shuffle(seed=42)

# Peek at a few examples
show_samples(books_dataset)
```

```python out
'>> Title: Easy to follow!!!!'
'>> Review: I loved The dash diet weight loss Solution. Never hungry. I would recommend this diet. Also the menus are well rounded. Try it. Has lots of the information need thanks.'

'>> Title: PARCIALMENTE DAÑADO'
'>> Review: Me llegó el día que tocaba, junto a otros libros que pedí, pero la caja llegó en mal estado lo cual dañó las esquinas de los libros porque venían sin protección (forro).'

'>> Title: no lo he podido descargar'
'>> Review: igual que el anterior'
```

これは確かに英語とスペイン語のレビューが混在しているように見えますね！
さて、トレーニングコーパスができたので、最後にレビューとそのタイトルに含まれる単語の分布を確認します。これは要約タスクにおいて特に重要で、学習データとして参考にするデータ中に短すぎる要約が多いと、要約生成時に1つか2つの単語しか出力しないようモデルを偏らせる可能性があります。下のプロットは単語の分布を示しており、タイトルが1-2単語だけに大きく偏っていることがわかります。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/review-lengths.svg" alt="Word count distributions for the review titles and texts."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/review-lengths-dark.svg" alt="Word count distributions for the review titles and texts."/>
</div>

この問題に対処し、私達のモデルがより興味深い要約を生成できるように、非常に短いタイトルを持つ例をフィルタリングすることにします。英語とスペイン語のテキストを扱っているので、タイトルを空白で分割する大まかな経験則を元に、信頼できる `Dataset.filter()` メソッドを以下のように使用します。

```python
books_dataset = books_dataset.filter(lambda x: len(x["review_title"].split()) > 2)
```

さて、コーパスができたところで、このコーパスを使って、Transformerのモデルを微調整してみましょう。

## 文章要約用モデル


考えてみれば、文章の要約は機械翻訳と似たような種類のタスクです。レビューのようなテキスト入力があり、それを入力文内の顕著な特徴をとらえた短いバージョンに「翻訳」したいのです。したがって、要約のためのほとんどのTransformerモデルは[第1章](/course/ja/chapter1)で最初に出会ったエンコーダとデコーダのアーキテクチャを採用しています。しかし、GPTモデル群のような例外もあり、少数ショット学習設定で使用することも可能です。以下の表は、要約のために微調整が可能な、よく使われる事前学習済みモデルの一覧です。

| Transformer model | Description                                                                                                                                                                                                    | Multilingual? |
| :---------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----------: |
|    [GPT-2](https://huggingface.co/gpt2-xl)    | Although trained as an auto-regressive language model, you can make GPT-2 generate summaries by appending "TL;DR" at the end of the input text.                                                                          |      ❌       |
|   [PEGASUS](https://huggingface.co/google/pegasus-large)   | Uses a pretraining objective to predict masked sentences in multi-sentence texts. This pretraining objective is closer to summarization than vanilla language modeling and scores highly on popular benchmarks. |      ❌       |
|     [T5](https://huggingface.co/t5-base)      | A universal Transformer architecture that formulates all tasks in a text-to-text framework; e.g., the input format for the model to summarize a document is `summarize: ARTICLE`.                              |      ❌       |
|     [mT5](https://huggingface.co/google/mt5-base)     | A multilingual version of T5, pretrained on the multilingual Common Crawl corpus (mC4), covering 101 languages.                                                                                                |      ✅       |
|    [BART](https://huggingface.co/facebook/bart-base)     | A novel Transformer architecture with both an encoder and a decoder stack trained to reconstruct corrupted input that combines the pretraining schemes of BERT and GPT-2.                                    |      ❌       |
|  [mBART-50](https://huggingface.co/facebook/mbart-large-50)   | A multilingual version of BART, pretrained on 50 languages.                                                                                                                                                     |      ✅       |

この表からわかるように、要約のためのTransformerモデルの大半は（そして実際、ほとんどのNLPタスクも）単言語版です。これはタスクが英語やドイツ語のような利用可能なデータの多い「高リソース」言語である場合は良いのですが、世界中で使われている何千もの他の言語ではそうではありません。幸いなことに、mT5やmBARTのような多言語Transformerモデルもあります。これらのモデルは言語モデリングを使って事前に学習されますが、ひねりが加えられています。1つの言語のコーパスで学習するのではなく、50以上の言語のテキストで一度に共同学習しているのです！

ここでは、T5をベースにテキストからテキストへのフレームワークで事前学習された興味深いアーキテクチャであるmT5に焦点を当てます。T5では、すべての自然言語処理タスクは「要約：」のようなプロンプト接頭辞で定式化され、生成されたテキストをプロンプトに適応させるようモデルに条件付けされます。下図に示すように、T5は非常に汎用性が高く、1つのモデルで多くのタスクを解決することができます！

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/t5.svg" alt="Different tasks performed by the T5 architecture."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/t5-dark.svg" alt="Different tasks performed by the T5 architecture."/>
</div>

mT5は接頭辞を使用しませんが、T5の多用途性を共有し、多言語であるという利点があります。さて、モデルを選んだところで、学習用のデータの準備に取りかかりましょう。

<Tip>

✏️ ** あなたの番です！ ** このセクションを終えたら、同じ手法でmBARTを微調整して、mT5がmBARTと比較してどの程度優れているかを見てみましょう。ボーナスポイントとして、英語のレビューだけでT5を微調整してみることもできます。T5には特別な接頭辞プロンプトがあるので、以下の前処理ステップでは入力例の前に`summarize:`を付ける必要があります。

</Tip>

## データの前処理

<Youtube id="1m7BerpSq8A"/>

次のタスクはレビューとそのタイトルをトークン化しエンコードすることです。いつものように、事前に学習したモデルのチェックポイントに関連付けられたトークナイザーをロードすることから始めます。ここではチェックポイントとして `mt5-small` を使用します。

```python
from transformers import AutoTokenizer

model_checkpoint = "google/mt5-small"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
```

<Tip>

💡 NLPプロジェクトの初期段階では、「小さな」モデルのクラスを少量のデータサンプルで学習させるのがよい方法です。これにより、エンド・ツー・エンドのワークフローに向けたデバッグと反復をより速く行うことができます。結果に自信が持てたら、モデルのチェックポイントを変更するだけで、いつでもモデルをスケールアップすることができます。

</Tip>

少量のサンプルでmT5トークナイザーをテストしてみましょう

```python
inputs = tokenizer("I loved reading the Hunger Games!")
inputs
```

```python out
{'input_ids': [336, 259, 28387, 11807, 287, 62893, 295, 12507, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}
```

ここで、[第3章](/course/ja/chapter3) の最初の微調整の実験で遭遇した、おなじみの `input_ids` と `attention_mask` を見ることができます。これらの入力IDをトークナイザーの `convert_ids_to_tokens()` 関数でデコードして、どのようなトークナイザーなのかを見てみましょう。

```python
tokenizer.convert_ids_to_tokens(inputs.input_ids)
```

```python out
['▁I', '▁', 'loved', '▁reading', '▁the', '▁Hung', 'er', '▁Games', '</s>']
```

Unicodeの特殊文字 `▁` とシーケンスの終わりを意味するトークン `</s>` は、SentencePieceトークナイザーを扱っていることを示しています。これは [第6章](/course/ja/chapter6) で説明したユニグラムセグメント化アルゴリズムに基づいています。ユニグラムは多言語コーパスに特に有効です。ユニグラムによりSentencePieceは口調、句読点、空白などに依存しなくなるので、日本語のように空白文字を持たない多くの言語に対して効果的になります。

このコーパスをトークン化するために、要約に関連する些細な問題に対処する必要があります。ラベルもテキストなので、モデルの最大コンテキストサイズを超える可能性があります。これは、レビューとそのタイトルの両方に切り詰めを適用して、過度に長い入力をモデルに渡さないようにする必要があることを意味します。🤗 Transformers のトークナイザーは、入力と並行してラベルをトークン化することができる便利な `as_target_tokenizer()` 関数を提供します。これは通常、まず入力をエンコードし、次にラベルを別の列としてエンコードする前処理関数の内部で、コンテキストマネージャーを使用して行われます。

以下は、mT5 用のそのような関数の例です。

```python
max_input_length = 512
max_target_length = 30


def preprocess_function(examples):
    model_inputs = tokenizer(
        examples["review_body"], max_length=max_input_length, truncation=True
    )
    # Set up the tokenizer for targets
    with tokenizer.as_target_tokenizer():
        labels = tokenizer(
            examples["review_title"], max_length=max_target_length, truncation=True
        )

    model_inputs["labels"] = labels["input_ids"]
    return model_inputs
```

何が起こっているのか理解するために、このコードを見ていきましょう。まず最初に、`max_input_length`と`max_target_length`の値を定義しました。これはレビューとタイトルの長さの上限を設定するものです。通常、レビューの本文はタイトルよりもはるかに大きいので、これらの値を適宜スケーリングしています。次に、`preprocess_function()` 自身で、レビューが最初にトークン化され、次に `as_target_tokenizer()` でタイトルがトークン化されていることがわかります。

`preprocess_function()` があれば、あとはこのコースで散々使ってきた便利な `Dataset.map()` 関数を使ってコーパス全体をトークン化するのは簡単なことです。

```python
tokenized_datasets = books_dataset.map(preprocess_function, batched=True)
```

さて、コーパスの前処理が終わったところで、要約によく使われるいくつかの指標を見てみましょう。これから見るように、機械が生成した文章の品質を測る際に、万能の手法は存在しません。

<Tip>

💡 上の `Dataset.map()` 関数で `batched=True` を使っていることにお気づきかもしれません。これはサンプルを1,000のバッチ（デフォルト）でエンコードし、🤗 Transformersの高速トークナイザーが持つマルチスレッド機能を利用できるようにするものです。可能であれば、前処理を最大限に活用するために `batched=True` を使ってみてください!

</Tip>


## 文章要約のための指標

<Youtube id="TMshhnrEXlg"/>

このコースで取り上げた他のほとんどのタスクと比較して、要約や翻訳のようなテキスト生成タスクの性能測定はそれほど簡単ではありません。例えば、「ハンガーゲームを読むのが好きだ」というレビューがあったとして、「ハンガーゲームが大好きだ」「ハンガーゲームは素晴らしい読み物だ」など、有効な要約が複数存在します。明らかに、生成された要約とラベルの間にある種の完全な一致を適用することは良い解決策ではありません。私たちは皆、独自の文体を持っているので、そのような測定指標を用いては人間でさえうまくいかないでしょう。

要約のために、最もよく使われる指標の1つが[ROUGE score](https://en.wikipedia.org/wiki/ROUGE_(metric)) (Recall-Oriented Understudy for Gisting Evaluationの略)です。この指標の背後にある基本的な考え方は、生成された要約を、通常人間が作成するした参照要約のセットと比較することです。これをより正確にするために、次の2つの要約を比較したいとします。

```python
generated_summary = "I absolutely loved reading the Hunger Games"
reference_summary = "I loved reading the Hunger Games"
```

比較する一つの方法として、重複している単語の数を数えることが考えられますが、この場合、6個となります。しかし、これは少し粗いので、代わりにROUGEは重なり合った部分の _適合率_ と _再現率_ のスコアを計算することを基本としています。

<Tip>

🙋 もしあなたが適合率や再現率について初めて聞いたとしても心配しないでください。すべてを明らかにするために、いくつかの明確な例を一緒に見ていきましょう。これらの指標は通常分類タスクで遭遇するので、その分類タスクの場合に適合率と再現率がどのように定義されているかを理解したい場合は、 `scikit-learn` [guides](https://scikit-learn.org/stable/auto_examples/model_selection/plot_precision_recall.html) をチェックアウトすることをお勧めします。

</Tip>

ROUGEでは、生成した要約に参照元の要約がどれだけ取り込まれたかを再現率で測定します。単語を比較するだけであれば、以下の式によって再現率を計算することができます。

$$ \mathrm{Recall} = \frac{\mathrm{Number\,of\,overlapping\, words}}{\mathrm{Total\, number\, of\, words\, in\, reference\, summary}} $$

上記の簡単な例では、この式は6/6 = 1の完全な再現率を与えます。つまり、参照要約のすべての単語がモデルによって生成されたことになります。これは素晴らしいことだと思うかもしれませんが、もし私達のモデルが生成した要約が「ハンガーゲームを一晩中読むのが本当に本当に好きだった」であったとしたらどうでしょう。この場合も完璧な再現率が得られますが、冗長であるため、間違いなくより悪い要約となります。このようなシナリオに対処するために、我々は私達は適合率も計算します。これはROUGEの文脈において、生成された要約がどれだけ関連していたかを測定するものです。

$$ \mathrm{Precision} = \frac{\mathrm{Number\,of\,overlapping\, words}}{\mathrm{Total\, number\, of\, words\, in\, generated\, summary}} $$

これを冗長な要約に適用すると、適合率は6/10 = 0.6となり、短い要約で得られた6/7 = 0.86よりもかなり悪くなります。実際には、通常、適合率と再現率の両方が計算され、そして、F1スコア（精度とリコールの調和平均）が報告されます。これは🤗 Datasetsで、まず `rouge_score` パッケージをインストールすることで簡単に行うことができます。

```py
!pip install rouge_score
```

そして、ROUGE指標を読み込みます。

```python
import evaluate

rouge_score = evaluate.load("rouge")
```

そして、`rouge_score.compute()`関数を使って、すべての指標を一度に計算することができます。

```python
scores = rouge_score.compute(
    predictions=[generated_summary], references=[reference_summary]
)
scores
```

```python out
{'rouge1': AggregateScore(low=Score(precision=0.86, recall=1.0, fmeasure=0.92), mid=Score(precision=0.86, recall=1.0, fmeasure=0.92), high=Score(precision=0.86, recall=1.0, fmeasure=0.92)),
 'rouge2': AggregateScore(low=Score(precision=0.67, recall=0.8, fmeasure=0.73), mid=Score(precision=0.67, recall=0.8, fmeasure=0.73), high=Score(precision=0.67, recall=0.8, fmeasure=0.73)),
 'rougeL': AggregateScore(low=Score(precision=0.86, recall=1.0, fmeasure=0.92), mid=Score(precision=0.86, recall=1.0, fmeasure=0.92), high=Score(precision=0.86, recall=1.0, fmeasure=0.92)),
 'rougeLsum': AggregateScore(low=Score(precision=0.86, recall=1.0, fmeasure=0.92), mid=Score(precision=0.86, recall=1.0, fmeasure=0.92), high=Score(precision=0.86, recall=1.0, fmeasure=0.92))}
```

おっと、この出力には多くの情報が含まれていますね。

これは全て何を意味するのでしょうか？まず、🤗 Datasetsは適合率、再現率、F1スコアの信頼区間を計算します。これらはここに表示されている `low`、`mid`、`high` の属性です。さらに、🤗 Datasetsは生成された要約と参照された要約を比較する際に、異なるタイプのテキストの粒度に基づいた様々なROUGEスコアを計算します。`rouge1`のバリエーションはユニグラムの重なり具合です。これは単語のオーバーラップを言い換えただけのもので、まさに上で説明したような指標です。これを確認するために、スコアの `mid` 値を引き出してみましょう。

```python
scores["rouge1"].mid
```

```python out
Score(precision=0.86, recall=1.0, fmeasure=0.92)
```

素晴らしい！適合率と再現率の数値が一致しました。では、他のROUGEスコアについてはどうでしょうか？
`rouge2` はビッグラム（単語のペアの重なり）の重なりを測定し、 `rougeL` と `rougeLsum` は生成されたサマリーと参照サマリーで最も長い共通部分文字列を探して、最も長くマッチする単語列を測定します。`rougeLsum` の "sum" は、 `rougeL` が個々の文の平均値として計算されるのに対し、この指標は要約全体に対して計算されるという事実を表している。

<Tip>

✏️ **あなたの番です！ ** 生成と参照要約の独自の例を作成し、結果のROUGEスコアが精度とリコールの公式を基にした手動計算と一致するかどうかを確認することができます。ボーナスポイントとして、テキストをビッグラムに分割し、`rouge2` 指標の適合率と制限率を比較します。

</Tip>

このROUGEスコアを使ってモデルのパフォーマンスを追跡していきますが、その前に優れたNLP実践者がすべきこと、それは強力かつシンプルなベースラインを作成することです。

### 強力なベースラインの作成

テキスト要約の一般的なベースラインは、単純に記事の最初の3つのセンテンスを取ることで、しばしば _lead-3_ ベースラインと呼ばれます。文の境界を追跡するためにピリオドを使うこともできますが、このやり方は "U.S." や "U.N." のような頭字語では失敗します。そこで、このようなケースを処理するための優れたアルゴリズムを含む `nltk` ライブラリを使用することにします。このパッケージは、以下のように `pip` を用いてインストールすることができます。

```python
!pip install nltk
```

そして、句読点規則をダウンロードしてください。

```python
import nltk

nltk.download("punkt")
```

次に、`nltk`からセンテンストークナイザーをインポートし、レビューの最初の3文を抽出する簡単な関数を作成します。テキストの要約では、各要約を改行で区切るのが慣例なので、これも含めて学習例でテストしてみましょう。

```python
from nltk.tokenize import sent_tokenize


def three_sentence_summary(text):
    return "\n".join(sent_tokenize(text)[:3])


print(three_sentence_summary(books_dataset["train"][1]["review_body"]))
```

```python out
'I grew up reading Koontz, and years ago, I stopped,convinced i had "outgrown" him.'
'Still,when a friend was looking for something suspenseful too read, I suggested Koontz.'
'She found Strangers.'
```

これはうまくいきそうなので、今度はデータセットからこれらの「要約」を抽出し、ベースラインのROUGEスコアを計算する関数を実装してみましょう。

```python
def evaluate_baseline(dataset, metric):
    summaries = [three_sentence_summary(text) for text in dataset["review_body"]]
    return metric.compute(predictions=summaries, references=dataset["review_title"])
```

そして、この関数を使って検証セットのROUGEスコアを計算し、Pandasを使って少しきれいにすることができます。

```python
import pandas as pd

score = evaluate_baseline(books_dataset["validation"], rouge_score)
rouge_names = ["rouge1", "rouge2", "rougeL", "rougeLsum"]
rouge_dict = dict((rn, round(score[rn].mid.fmeasure * 100, 2)) for rn in rouge_names)
rouge_dict
```

```python out
{'rouge1': 16.74, 'rouge2': 8.83, 'rougeL': 15.6, 'rougeLsum': 15.96}
```

rouge2`のスコアが他よりかなり低いことがわかります。これは、レビューのタイトルが一般的に簡潔であるため、lead-3のベースラインが冗長すぎるという事実を反映していると思われます。これでベースラインができたので、次はmT5の微調整を行います！

{#if fw === 'pt'}

## Trainer API を使って mT5 を微調整する

要約のためのモデルの微調整は、この章で取り上げた他のタスクと非常によく似ています。まず最初に行うべきことは、`mt5-small` チェックポイントから事前学習したモデルをロードすることです。要約はシーケンス間タスクなので、`AutoModelForSeq2SeqLM` クラスを使用してモデルをロードすることができます。これは自動的に重みをダウンロードし、キャッシュします。

```python
from transformers import AutoModelForSeq2SeqLM

model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint)
```

{:else}

## KerasでmT5を微調整する

要約のためのモデルの微調整は、この章で取り上げた他のタスクと非常によく似ています。まず最初に行うべきことは、`mt5-small`チェックポイントから事前に学習したモデルをロードすることです。要約はシーケンス間タスクなので、`AutoModelForSeq2SeqLM`クラスでモデルをロードすれば、自動的に重みをダウンロードし、キャッシュすることができます。

```python
from transformers import TFAutoModelForSeq2SeqLM

model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint)
```

{/if}

<Tip>

💡 下流のタスクでモデルを微調整に関する警告が表示されないことを不思議に思うかもしれませんが、それはシーケンス間タスクでは、ネットワークのすべての重みが保持されるからです。これを[第3章](/course/ja/chapter3)のテキスト分類モデルと比較してみましょう。テキスト分類モデルでは、事前学習したモデルの先頭をランダムに初期化したネットワークに置き換えています。

</Tip>

次に必要なのは、ハンギングフェイス ハブにログインすることです。このコードをノートブックで実行する場合は、次のユーティリティ関数で実行できます。

```python
from huggingface_hub import notebook_login

notebook_login()
```

これにより、ウィジェットが表示され、認証情報を入力することができます。または、ターミナルで以下のコマンドを実行し、ログインすることもできます。

```
huggingface-cli login
```

{#if fw === 'pt'}

トレーニング中にROUGEスコアを計算するために、要約を生成する必要があります。幸いなことに、🤗 Transformersは専用の `Seq2SeqTrainingArguments` と `Seq2SeqTrainer` クラスを提供し、私たちのために自動的にこれを行うことができます！
このクラスがどのように機能するかを見てみるために、まず実験用にハイパーパラメータとその他の引数を定義しましょう。

```python
from transformers import Seq2SeqTrainingArguments

batch_size = 8
num_train_epochs = 8
# Show the training loss with every epoch
logging_steps = len(tokenized_datasets["train"]) // batch_size
model_name = model_checkpoint.split("/")[-1]

args = Seq2SeqTrainingArguments(
    output_dir=f"{model_name}-finetuned-amazon-en-es",
    evaluation_strategy="epoch",
    learning_rate=5.6e-5,
    per_device_train_batch_size=batch_size,
    per_device_eval_batch_size=batch_size,
    weight_decay=0.01,
    save_total_limit=3,
    num_train_epochs=num_train_epochs,
    predict_with_generate=True,
    logging_steps=logging_steps,
    push_to_hub=True,
)
```

ここでは、 `predict_with_generate` 引数を設定し、各エポックの ROUGE スコアを計算できるように、評価中に要約を生成するように指示しました。[第1章](/course/ja/chapter1) で説明したように、デコーダはトークンを一つずつ予測して推論を行いますが、これはモデルの `generate()` メソッドによって実装されています。`predict_with_generate=True` を設定すると、 `Seq2SeqTrainer` がそのメソッドを使用して評価を行うようになります。また、学習率、エポック回数、重み減衰などのデフォルトのハイパーパラメータを調整し、 `save_total_limit` オプションを設定して、学習中のチェックポイントを3つまでしか保存しないようにしました。これはmT5の「小さい」バージョンでさえ、ハードディスクの容量を約1GB使用しており、保存するコピーを制限すれば、少し容量を節約することができるからです。

`push_to_hub=True` を指定すると、学習後にモデルを Hub にプッシュすることができます。ユーザープロファイルの下の、 `output_dir` で定義された場所にリポジトリが作成されます。なお、 `hub_model_id` 引数で、プッシュしたいリポジトリの名前を指定することができます。(特に、組織にプッシュする場合はこの引数を使用する必要があります)。例えば、モデルを [`huggingface-course` organization](https://huggingface.co/huggingface-course) にプッシュする場合、`Seq2SeqTrainingArguments` に `hub_model_id="huggingface-course/mt5-finetuned-amazon-en-es"` を追加しています。

次に必要なことは、学習中にモデルを評価できるように、 `compute_metrics()` 関数をトレーナーに提供することです。
要約タスクでは、予測タスクのようにシンプルに `rouge_score.compute()` を呼ぶのと少し異なります。なぜなら、ROUGE スコアを計算する前に、出力とラベルをテキストにデコードする必要があるからです。以下の関数はまさにそれを行うもので、さらに `nltk` の `sent_tokenize()` 関数を利用して、要約文章を改行で区切るようにしています。

```python
import numpy as np


def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    # Decode generated summaries into text
    decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True)
    # Replace -100 in the labels as we can't decode them
    labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
    # Decode reference summaries into text
    decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)
    # ROUGE expects a newline after each sentence
    decoded_preds = ["\n".join(sent_tokenize(pred.strip())) for pred in decoded_preds]
    decoded_labels = ["\n".join(sent_tokenize(label.strip())) for label in decoded_labels]
    # Compute ROUGE scores
    result = rouge_score.compute(
        predictions=decoded_preds, references=decoded_labels, use_stemmer=True
    )
    # Extract the median scores
    result = {key: value.mid.fmeasure * 100 for key, value in result.items()}
    return {k: round(v, 4) for k, v in result.items()}
```

{/if}

次に、シーケンス間タスクのためのデータコレーターを定義する必要があります。mT5はエンコーダ・デコーダのTransformerモデルなので、バッチを準備する際の一つのちょっとした差異は、デコード中にラベルを右に1つシフトする必要があることです。これは、デコーダが以前の真実のラベルしか見ないようにするためで、現在や将来のラベルをモデルに記憶させないようにしうます。これは[因果言語モデリング](/course/ja/chapter7/6)のようなタスクでマスクされた自己注意が入力に適用される方法に似ています。

幸運なことに、🤗 Transformers は `DataCollatorForSeq2Seq` コレーターを提供し、入力とラベルを動的にパディングしてくれます。このコレーターをインスタンス化するには、単に `tokenizer` と `model` を提供する必要があります。

{#if fw === 'pt'}

```python
from transformers import DataCollatorForSeq2Seq

data_collator = DataCollatorForSeq2Seq(tokenizer, model=model)
```

{:else}

```python
from transformers import DataCollatorForSeq2Seq

data_collator = DataCollatorForSeq2Seq(tokenizer, model=model, return_tensors="tf")
```

{/if}

それでは、このコレーターが少量のサンプルをバッチで与えたときに何を生成するかを見てみましょう。まず、文字列を含む列を削除する必要があります。コレーターはこれらの要素をどのようにパディングするかを知らないからです。

```python
tokenized_datasets = tokenized_datasets.remove_columns(
    books_dataset["train"].column_names
)
```

コレーター は `dict` のリストを受け取り、各 `dict` はデータセット内の 1 つの例を表している事を期待しています。したがって、データをコレーターに渡す前に期待通りの形式に変換する必要があります。

```python
features = [tokenized_datasets["train"][i] for i in range(2)]
data_collator(features)
```

```python out
{'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]), 'input_ids': tensor([[  1494,    259,   8622,    390,    259,    262,   2316,   3435,    955,
            772,    281,    772,   1617,    263,    305,  14701,    260,   1385,
           3031,    259,  24146,    332,   1037,    259,  43906,    305,    336,
            260,      1,      0,      0,      0,      0,      0,      0],
        [   259,  27531,  13483,    259,   7505,    260, 112240,  15192,    305,
          53198,    276,    259,  74060,    263,    260,    459,  25640,    776,
           2119,    336,    259,   2220,    259,  18896,    288,   4906,    288,
           1037,   3931,    260,   7083, 101476,   1143,    260,      1]]), 'labels': tensor([[ 7483,   259,  2364, 15695,     1,  -100],
        [  259, 27531, 13483,   259,  7505,     1]]), 'decoder_input_ids': tensor([[    0,  7483,   259,  2364, 15695,     1],
        [    0,   259, 27531, 13483,   259,  7505]])}
```

ここで注目すべきは、最初の例は2番目の例よりも長いので、2番目の例の `input_ids` と `attention_mask` は右側に `[PAD]` トークン (ID は `0`) でパディングされていることです。同様に、`labels` は `-100` でパディングされていることがわかります。これは、パディングトークンが損失関数によって無視されることを確認するためです。そして最後に、新しい `decoder_input_ids` を見ると、最初のエントリに `[PAD]` トークンを挿入してラベルを右にシフトしていることが確認できます。

{#if fw === 'pt'}

これでようやく、トレーニングに必要な材料が揃いました。あとは、標準的な引数でトレーナーを実体化するだけです。

```python
from transformers import Seq2SeqTrainer

trainer = Seq2SeqTrainer(
    model,
    args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    tokenizer=tokenizer,
    compute_metrics=compute_metrics,
)
```

そして、トレーニングランを開始します。

```python
trainer.train()
```

学習中はエポック毎に学習損失が減少し、ROUGE スコアが増加するのが分かるはずです。学習が完了したら、`Trainer.evaluate()`を実行して最終的な ROUGE スコアを確認することができます。

```python
trainer.evaluate()
```

```python out
{'eval_loss': 3.028524398803711,
 'eval_rouge1': 16.9728,
 'eval_rouge2': 8.2969,
 'eval_rougeL': 16.8366,
 'eval_rougeLsum': 16.851,
 'eval_gen_len': 10.1597,
 'eval_runtime': 6.1054,
 'eval_samples_per_second': 38.982,
 'eval_steps_per_second': 4.914}
```

スコアから、私達のモデルがlead-3のベースラインを見事に上回ったことがわかります。いいですね！
最後に、以下のようにモデルの重みをハブにプッシュします。

```
trainer.push_to_hub(commit_message="Training complete", tags="summarization")
```

```python out
'https://huggingface.co/huggingface-course/mt5-finetuned-amazon-en-es/commit/aa0536b829b28e73e1e4b94b8a5aacec420d40e0'
```

これは、ハブにすべてのファイルをアップロードする前に、チェックポイントと設定ファイルを `output_dir` に保存するものです。引数に `tags` を指定することで、Hub 上のウィジェットが mT5 アーキテクチャに関連付けられたデフォルトのテキスト生成用ではなく、要約パイプライン用のものになることも確認できます (モデルタグに関する詳細については、 [🤗 Hub documentation](https://huggingface.co/docs/hub/main#how-is-a-models-type-of-inference-api-and-widget-determined)を参照してください)。
`trainer.push_to_hub()` の出力は Git のコミットハッシュへの URL で、モデルリポジトリに加えられた変更を簡単に確認することができます！

このセクションの最後に、🤗 Accelerate が提供する低レベルの機能を使って mT5 を微調整することもできる方法を見てみましょう。

{:else}

トレーニングの準備はほぼ整いました。あとは上で定義したデータコレーターを使ってデータセットを `tf.data.Dataset`s に変換し、モデルを `compile()` と `fit()` するだけです。まず、データセットです。

```python
tf_train_dataset = tokenized_datasets["train"].to_tf_dataset(
    columns=["input_ids", "attention_mask", "labels"],
    collate_fn=data_collator,
    shuffle=True,
    batch_size=8,
)
tf_eval_dataset = tokenized_datasets["validation"].to_tf_dataset(
    columns=["input_ids", "attention_mask", "labels"],
    collate_fn=data_collator,
    shuffle=False,
    batch_size=8,
)
```

ここで、学習用ハイパーパラメータを定義し、コンパイルします。

```python
from transformers import create_optimizer
import tensorflow as tf

# The number of training steps is the number of samples in the dataset, divided by the batch size then multiplied
# by the total number of epochs. Note that the tf_train_dataset here is a batched tf.data.Dataset,
# not the original Hugging Face Dataset, so its len() is already num_samples // batch_size.
num_train_epochs = 8
num_train_steps = len(tf_train_dataset) * num_train_epochs
model_name = model_checkpoint.split("/")[-1]

optimizer, schedule = create_optimizer(
    init_lr=5.6e-5,
    num_warmup_steps=0,
    num_train_steps=num_train_steps,
    weight_decay_rate=0.01,
)

model.compile(optimizer=optimizer)

# Train in mixed-precision float16
tf.keras.mixed_precision.set_global_policy("mixed_float16")
```

そして最後に、モデルのフィットを行います。`PushToHubCallback`を使用して、各エポック後にモデルをHubに保存し、後で推論に使用できるようにします。

```python
from transformers.keras_callbacks import PushToHubCallback

callback = PushToHubCallback(
    output_dir=f"{model_name}-finetuned-amazon-en-es", tokenizer=tokenizer
)

model.fit(
    tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback], epochs=8
)
```

学習中に損失値を取得しましたが、本当は先ほど計算したROUGE指標を見たいのです。この指標を取得するためには、モデルから出力を生成し、それを文字列に変換する必要があります。ROUGE指標を比較するために、ラベルと予測のリストをいくつか作ってみましょう（このセクション実行時にインポートエラーが発生した場合は、`!pip install tqdm`を実行する必要があるかもしれませんので注意してください）。

```python
from tqdm import tqdm
import numpy as np

all_preds = []
all_labels = []
for batch in tqdm(tf_eval_dataset):
    predictions = model.generate(**batch)
    decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True)
    labels = batch["labels"].numpy()
    labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
    decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)
    decoded_preds = ["\n".join(sent_tokenize(pred.strip())) for pred in decoded_preds]
    decoded_labels = ["\n".join(sent_tokenize(label.strip())) for label in decoded_labels]
    all_preds.extend(decoded_preds)
    all_labels.extend(decoded_labels)
```

ラベルと予測文字列のリストがあれば、ROUGEスコアの計算は簡単です。

```python
result = rouge_score.compute(
    predictions=decoded_preds, references=decoded_labels, use_stemmer=True
)
result = {key: value.mid.fmeasure * 100 for key, value in result.items()}
{k: round(v, 4) for k, v in result.items()}
```

```
{'rouge1': 31.4815, 'rouge2': 25.4386, 'rougeL': 31.4815, 'rougeLsum': 31.4815}
```


{/if}

{#if fw === 'pt'}

## mT5モデルを 🤗 Accelerate を使って微調整する

🤗 Accelerateを使ったモデルの微調整は、[第3章](/course/ja/chapter3)で行ったテキスト分類の例と非常によく似ています。主な違いは、学習時に要約を明示的に生成する必要があることと、ROUGEスコアの計算方法を定義することです（`Seq2SeqTrainer`が生成の面倒をみてくれたことを思い出してください）。では、この2つの要件を🤗 Accelerateでどのように実装するか見てみましょう。

### トレーニングのための準備

まず最初に行うべきことは、各分割に対して `DataLoader` を作成することです。PyTorchのデータローダーはテンソルのバッチを想定しているので、データセットのフォーマットを `"torch"` に設定する必要があります。

```python
tokenized_datasets.set_format("torch")
```

これでテンソルだけのデータセットができたので、次にやることは `DataCollatorForSeq2Seq` を再び実体化することです。そのためには、新しいバージョンのモデルを用意する必要があるので、キャッシュからロードし直しましょう。

```python
model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint)
```

次に、データコレーターを実態化し、これを使用してデータローダーを定義します。

```python
from torch.utils.data import DataLoader

batch_size = 8
train_dataloader = DataLoader(
    tokenized_datasets["train"],
    shuffle=True,
    collate_fn=data_collator,
    batch_size=batch_size,
)
eval_dataloader = DataLoader(
    tokenized_datasets["validation"], collate_fn=data_collator, batch_size=batch_size
)
```

次に行うことは、使用するオプティマイザーを定義することです。他の例と同様に、ほとんどの問題でうまく機能する `AdamW` を使用することにします。

```python
from torch.optim import AdamW

optimizer = AdamW(model.parameters(), lr=2e-5)
```

最後に、モデル、オプティマイザー、データロードを `accelerator.prepare()` メソッドに渡します。

```python
from accelerate import Accelerator

accelerator = Accelerator()
model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare(
    model, optimizer, train_dataloader, eval_dataloader
)
```

<Tip>

🚨 TPUでトレーニングする場合は、上記のコードをすべて専用のトレーニング関数に移動する必要があります。詳しくは[第3章](/course/ja/chapter3)を参照してください。

</Tip>

さて、オブジェクトの準備ができたので、残すは3つです。


* 学習率のスケジュールを定義する。
* 評価用の要約を後処理する関数を実装する。
* ハブ上にモデルをプッシュできるリポジトリを作成する。

学習率のスケジュールには、前節までの標準的な線形なものを使うことにします。

```python
from transformers import get_scheduler

num_train_epochs = 10
num_update_steps_per_epoch = len(train_dataloader)
num_training_steps = num_train_epochs * num_update_steps_per_epoch

lr_scheduler = get_scheduler(
    "linear",
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=num_training_steps,
)
```

後処理として、生成された要約を改行で区切られた文に分割する関数が必要です。これはROUGE指標が期待する形式であり、次のようなコードの断片でこれを実現できます。

```python
def postprocess_text(preds, labels):
    preds = [pred.strip() for pred in preds]
    labels = [label.strip() for label in labels]

    # ROUGE expects a newline after each sentence
    preds = ["\n".join(nltk.sent_tokenize(pred)) for pred in preds]
    labels = ["\n".join(nltk.sent_tokenize(label)) for label in labels]

    return preds, labels
```

これは、 `Seq2SeqTrainer` の `compute_metrics()` 関数をどのように定義したかを思い出せば、見覚えがあるはずです。

最後に、ハギングフェイス ハブにモデルリポジトリを作成する必要があります。これには、適切なタイトルの🤗 ハブ ライブラリを使用します。
私たちは、リポジトリの名前を定義する必要があるだけです。このライブラリには、リポジトリ ID とユーザプロファイルを組み合わせるユーティリティ関数があります。

```python
from huggingface_hub import get_full_repo_name

model_name = "test-bert-finetuned-squad-accelerate"
repo_name = get_full_repo_name(model_name)
repo_name
```

```python out
'lewtun/mt5-finetuned-amazon-en-es-accelerate'
```

このリポジトリ名を使って、resultsディレクトリにローカルバージョンをクローンし、学習用成果物を格納します。

```python
from huggingface_hub import Repository

output_dir = "results-mt5-finetuned-squad-accelerate"
repo = Repository(output_dir, clone_from=repo_name)
```

これにより、トレーニング中に `repo.push_to_hub()` メソッドを呼び出すことで、成果物をハブにプッシュバックすることができます！
それでは、トレーニングループを書き出し、分析を終えましょう。

### 学習ループ

要約のためのトレーニングループは、私たちが遭遇した他の🤗 Accelerateの例と非常によく似ており、大きく4つの主要なステップに分かれています。

1. 各エポックごとに `train_dataloader` にあるすべての例に対して繰り返し処理を行い、モデルを学習させる。
2. 各エポック終了時に、まずトークンを生成し、それをデコードしてテキストにすることでモデルの要約を生成する。(参考要約も)。
3. 先に見たのと同じ手法でROUGEスコアを計算する。
4. チェックポイントを保存し、すべてをハブにプッシュする。ここでは、エポック毎にチェックポイントを _非同期_ にプッシュできるように、`Repository` オブジェクトの `blocking=False` という便利な引数に頼っています。これにより、GBサイズのモデルで発生する遅いアップロードを待つことなく、学習を継続することができるようになりました。

これらの手順は、以下のコードブロックのようになります。

```python
from tqdm.auto import tqdm
import torch
import numpy as np

progress_bar = tqdm(range(num_training_steps))

for epoch in range(num_train_epochs):
    # Training
    model.train()
    for step, batch in enumerate(train_dataloader):
        outputs = model(**batch)
        loss = outputs.loss
        accelerator.backward(loss)

        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        progress_bar.update(1)

    # Evaluation
    model.eval()
    for step, batch in enumerate(eval_dataloader):
        with torch.no_grad():
            generated_tokens = accelerator.unwrap_model(model).generate(
                batch["input_ids"],
                attention_mask=batch["attention_mask"],
            )

            generated_tokens = accelerator.pad_across_processes(
                generated_tokens, dim=1, pad_index=tokenizer.pad_token_id
            )
            labels = batch["labels"]

            # If we did not pad to max length, we need to pad the labels too
            labels = accelerator.pad_across_processes(
                batch["labels"], dim=1, pad_index=tokenizer.pad_token_id
            )

            generated_tokens = accelerator.gather(generated_tokens).cpu().numpy()
            labels = accelerator.gather(labels).cpu().numpy()

            # Replace -100 in the labels as we can't decode them
            labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
            if isinstance(generated_tokens, tuple):
                generated_tokens = generated_tokens[0]
            decoded_preds = tokenizer.batch_decode(
                generated_tokens, skip_special_tokens=True
            )
            decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)

            decoded_preds, decoded_labels = postprocess_text(
                decoded_preds, decoded_labels
            )

            rouge_score.add_batch(predictions=decoded_preds, references=decoded_labels)

    # Compute metrics
    result = rouge_score.compute()
    # Extract the median ROUGE scores
    result = {key: value.mid.fmeasure * 100 for key, value in result.items()}
    result = {k: round(v, 4) for k, v in result.items()}
    print(f"Epoch {epoch}:", result)

    # Save and upload
    accelerator.wait_for_everyone()
    unwrapped_model = accelerator.unwrap_model(model)
    unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save)
    if accelerator.is_main_process:
        tokenizer.save_pretrained(output_dir)
        repo.push_to_hub(
            commit_message=f"Training in progress epoch {epoch}", blocking=False
        )
```

```python out
Epoch 0: {'rouge1': 5.6351, 'rouge2': 1.1625, 'rougeL': 5.4866, 'rougeLsum': 5.5005}
Epoch 1: {'rouge1': 9.8646, 'rouge2': 3.4106, 'rougeL': 9.9439, 'rougeLsum': 9.9306}
Epoch 2: {'rouge1': 11.0872, 'rouge2': 3.3273, 'rougeL': 11.0508, 'rougeLsum': 10.9468}
Epoch 3: {'rouge1': 11.8587, 'rouge2': 4.8167, 'rougeL': 11.7986, 'rougeLsum': 11.7518}
Epoch 4: {'rouge1': 12.9842, 'rouge2': 5.5887, 'rougeL': 12.7546, 'rougeLsum': 12.7029}
Epoch 5: {'rouge1': 13.4628, 'rouge2': 6.4598, 'rougeL': 13.312, 'rougeLsum': 13.2913}
Epoch 6: {'rouge1': 12.9131, 'rouge2': 5.8914, 'rougeL': 12.6896, 'rougeLsum': 12.5701}
Epoch 7: {'rouge1': 13.3079, 'rouge2': 6.2994, 'rougeL': 13.1536, 'rougeLsum': 13.1194}
Epoch 8: {'rouge1': 13.96, 'rouge2': 6.5998, 'rougeL': 13.9123, 'rougeLsum': 13.7744}
Epoch 9: {'rouge1': 14.1192, 'rouge2': 7.0059, 'rougeL': 14.1172, 'rougeLsum': 13.9509}
```

それで終わりです。これを実行すると、`Trainer`で得たものとよく似たモデルと結果が得られます。

{/if}

## あなたの微調整したモデルを使用する

モデルをハブにプッシュしたら、推論ウィジェットか `pipeline` オブジェクトを使って、次のように操作することができます。

```python
from transformers import pipeline

hub_model_id = "huggingface-course/mt5-small-finetuned-amazon-en-es"
summarizer = pipeline("summarization", model=hub_model_id)
```

要約の品質について感触を得るために、テストセット（モデルは見た事がない）からいくつかの例をパイプラインに送り込むことができます。最初に、レビュー、タイトル、生成された要約を一緒に表示する簡単な関数を実装してみましょう。

```python
def print_summary(idx):
    review = books_dataset["test"][idx]["review_body"]
    title = books_dataset["test"][idx]["review_title"]
    summary = summarizer(books_dataset["test"][idx]["review_body"])[0]["summary_text"]
    print(f"'>>> Review: {review}'")
    print(f"\n'>>> Title: {title}'")
    print(f"\n'>>> Summary: {summary}'")
```

英語の例を一つ見てみましょう。

```python
print_summary(100)
```

```python out
'>>> Review: Nothing special at all about this product... the book is too small and stiff and hard to write in. The huge sticker on the back doesn’t come off and looks super tacky. I would not purchase this again. I could have just bought a journal from the dollar store and it would be basically the same thing. It’s also really expensive for what it is.'

'>>> Title: Not impressed at all... buy something else'

'>>> Summary: Nothing special at all about this product'
```

これは悪くありません! 私たちのモデルは実際に新しい単語でレビューの一部を補強することによって、抽象的な要約を行うことができたことがわかります。また、私たちのモデルの最もクールな点は、バイリンガルであることです。したがって、スペイン語のレビューの要約も生成することができます。

```python
print_summary(0)
```

```python out
'>>> Review: Es una trilogia que se hace muy facil de leer. Me ha gustado, no me esperaba el final para nada'

'>>> Title: Buena literatura para adolescentes'

'>>> Summary: Muy facil de leer'
```

要約は英語で「Very easy to read」と訳され、この要約の場合はレビューの文中から直接抽出されたことが分かります。しかし、これはmT5モデルの多用途性を示しており、多言語コーパスを扱うことがどのようなものかを体験していただけたと思います。

次に、もう少し複雑なタスクである、ゼロから言語モデルを学習させる事に目を向けます。


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter7/5.mdx" />

### イントロダクション
https://huggingface.co/learn/course/ja/chapter7/1.md

# イントロダクション

<CourseFloatingBanner
    chapter={7}
    classNames="absolute z-10 right-0 top-0"
/>

[第3章](/course/ja/chapter3)では、テキスト分類のためにモデルを微調整する方法を学びました。この章では、以下のような一般的な自然言語処理タスクに取り組みます。

- トークン分類
- マスク言語モデリング(BERTのような)
- 要約
- 翻訳
- 因果言語モデリング事前学習(GPT-2など)
- 質問応答

{#if fw === 'pt'}

これを行うには、第3章で学んだTrainer APIと🤗 Accelerateライブラリ、5章で学んだ🤗 Datasetsライブラリ、第6章で学んだ🤗 Tokenizersライブラリについて、すべて活用する必要があります。また、第4章で行ったように、結果をModel Hubにアップロードします。したがって、この章は本当にすべてが集約された章です。

各セクションは独立して読むことができ、Trainer APIや🤗 Accelerateを使った独自の学習ループでモデルを学習する方法が紹介されています。どのパートも自由にスキップできるので、最も興味のあるパートに集中してください。Trainer APIは裏で何が起こっているかを気にせずにモデルを微調整したりトレーニングしたりするのに最適です。一方、Accelerateを使ったトレーニングループでは、必要な部分をより簡単にカスタマイズすることができます。

{:else}

これを行うには、第3章のKeras API、第5章の🤗 Datasetsライブラリ、第6章の🤗 Tokenizersライブラリでモデルのトレーニングについて学んだことをすべて活用する必要があります。また、第4章で行ったように、結果をモデルハブにアップロードすることになるので、この章はまさにすべてが集約された章と言えます。

各セクションは独立して読むことができます。

{/if}

<Tip>

各セクションを順番に読んでいくと、共通するコードや文章がかなりあることに気がつくと思います。この繰り返しは意図的なもので、興味のあるタスクに飛び込んで（あるいは後で戻って）、完全な動作例を見つけることができるようにするためのものです。

</Tip>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter7/1.mdx" />

### マスク言語モデルの微調整
https://huggingface.co/learn/course/ja/chapter7/3.md

# マスク言語モデルの微調整

{#if fw === 'pt'}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section3_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section3_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section3_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section3_tf.ipynb"},
]} />

{/if}

Transformerモデルを含む多くのNLPアプリケーションでは、ハギング フェイス ハブから事前学習済みのモデルを取り出し、自分が実行したいタスク用のデータを直接使って微調整を行うだけでよいのです。事前学習に使われたコーパスと微調整に使うコーパスがあまり違わない限り、転移学習は通常良い結果を生み出します。

しかし、モデルのヘッド部だけを対象にタスクに特化したトレーニング行う前に、まずデータを使って言語モデルを微調整したいケースもいくつかあります。例えば、データセットに法的契約や科学論文が含まれている場合、BERTのような素のTransformerモデルは通常、コーパス内のドメイン特有の単語を稀なトークンとして扱うため、結果として満足のいく性能が得られない可能性があります。ドメイン内データで言語モデルを微調整することで、多くの下流タスクのパフォーマンスを向上させることができ、このステップは通常一度だけ行えばよいことになります。

このように、事前に学習した言語モデルをドメイン内データで微調整するプロセスは、通常_ドメイン適応_と呼ばれます。これは2018年に[ULMFiT](https://arxiv.org/abs/1801.06146)によって普及しました。転移学習をNLPで本当に使えるようにした最初のニューラルアーキテクチャ（LSTMがベース）の1つです。ULMFiTによるドメイン適応の例を下の画像に示します。このセクションでは、LSTMの代わりにTransformerを使って、同様のことを行います！


<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/ulmfit.svg" alt="ULMFiT."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/ulmfit-dark.svg" alt="ULMFiT."/>
</div>

このセクションの終わりには、以下のような文章を自動補完できる[マスク言語モデル](https://huggingface.co/huggingface-course/distilbert-base-uncased-finetuned-imdb?text=This+is+a+great+%5BMASK%5D.)がHub上にできていることでしょう。

<iframe src="https://course-demos-distilbert-base-uncased-finetune-7400b54.hf.space" frameBorder="0" height="300" title="Gradio app" class="block dark:hidden container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

それでは始めましょう！

<Youtube id="mqElG5QJWUg"/>

<Tip>

🙋 「マスク言語モデリング」や「事前学習済みモデル」という言葉に聞き覚えがない方は、[第1章](/course/ja/chapter1)でこれらの主要な概念をすべて動画付きで説明していますので、ぜひご覧になってください。

</Tip>

## マスク言語モデリング用の事前学習済みモデルの選択

まず、マスク言語モデリングに適した事前学習済みモデルを選びましょう。以下のスクリーンショットのように、[ハギング フェイス ハブ](https://huggingface.co/models?pipeline_tag=fill-mask&sort=downloads)の "Fill-Mask "フィルタを適用すると、候補のリストが表示されます。

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/mlm-models.png" alt="Hub models." width="80%"/>
</div>

BERT と RoBERTa モデルのファミリーが最もダウンロードされていますが、ここでは [DistilBERT](https://huggingface.co/distilbert-base-uncased) と呼ばれるモデルを使用することにします。このモデルは、下流タスクの性能をほとんど損なうことなく、より高速に学習させることができます。

このモデルは、[_知識蒸留_](https://en.wikipedia.org/wiki/Knowledge_distillation)と呼ばれる特別な技術を使用して訓練されました。この手法は、BERTのような大きな「教師モデル」が、それよりはるかに少ないパラメータを持つ「生徒モデル」の訓練を導くために使用されています。

知識蒸溜の詳細を説明すると、この章の内容から離れすぎてしまいますが、もし興味があれば、[_Natural Language Processing with Transformers_](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/)（通称Transformers教科書）でそれについてすべて読むことができます。

{#if fw === 'pt'}

それでは、`AutoModelForMaskedLM`クラスを使ってDistilBERTをダウンロードしてみましょう。

```python
from transformers import AutoModelForMaskedLM

model_checkpoint = "distilbert-base-uncased"
model = AutoModelForMaskedLM.from_pretrained(model_checkpoint)
```

このモデルがいくつのパラメータを持っているかは、`num_parameters()` メソッドを呼び出すことで確認することができます。

```python
distilbert_num_parameters = model.num_parameters() / 1_000_000
print(f"'>>> DistilBERT number of parameters: {round(distilbert_num_parameters)}M'")
print(f"'>>> BERT number of parameters: 110M'")
```

```python out
'>>> DistilBERT number of parameters: 67M'
'>>> BERT number of parameters: 110M'
```

{:else}

それでは、`AutoModelForMaskedLM`クラスを使ってDistilBERTをダウンロードしてみましょう。

```python
from transformers import TFAutoModelForMaskedLM

model_checkpoint = "distilbert-base-uncased"
model = TFAutoModelForMaskedLM.from_pretrained(model_checkpoint)
```
このモデルがいくつのパラメータを持っているかは、`summary()` メソッドを呼び出すことで確認することができます。

```python
model(model.dummy_inputs)  # Build the model
model.summary()
```

```python out
Model: "tf_distil_bert_for_masked_lm"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
distilbert (TFDistilBertMain multiple                  66362880  
_________________________________________________________________
vocab_transform (Dense)      multiple                  590592    
_________________________________________________________________
vocab_layer_norm (LayerNorma multiple                  1536      
_________________________________________________________________
vocab_projector (TFDistilBer multiple                  23866170  
=================================================================
Total params: 66,985,530
Trainable params: 66,985,530
Non-trainable params: 0
_________________________________________________________________
```

{/if}

約6,700万パラメータを持つDistilBERTは、BERTの基本モデルよりも約2倍小さく、これは、学習時に約2倍のスピードアップに相当します（素晴らしい！）。それでは、このモデルが予測する、小さなテキストサンプルの最も可能性の高い完成形はどのような種類のトークンであるかを見てみましょう。

```python
text = "This is a great [MASK]."
```

人間なら `[MASK]` トークンに対して、"day", "ride", "painting" などの多くの可能性を想像することができます。事前学習済みモデルの場合、予測値はモデルが学習したコーパスに依存します。なぜなら、モデルはデータに存在する統計的パターンを選択するように学習するからです。BERTと同様に、DistilBERTは[English Wikipedia](https://huggingface.co/datasets/wikipedia) と [BookCorpus](https://huggingface.co/datasets/bookcorpus) のデータセットで事前学習されているので、`[MASK]`の予測はこれらのドメインを反映すると予想されます。マスクを予測するためには、モデルの入力生成用にDistilBERTのtokenizerが必要なので、これもHubからダウンロードしましょう。

```python
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
```

tokenizerモデルがあれば、テキストサンプルをモデルに渡し、ロジットを抽出し、上位5つの候補を出力することができます。

{#if fw === 'pt'}

```python
import torch

inputs = tokenizer(text, return_tensors="pt")
token_logits = model(**inputs).logits
# Find the location of [MASK] and extract its logits
mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]
mask_token_logits = token_logits[0, mask_token_index, :]
# Pick the [MASK] candidates with the highest logits
top_5_tokens = torch.topk(mask_token_logits, 5, dim=1).indices[0].tolist()

for token in top_5_tokens:
    print(f"'>>> {text.replace(tokenizer.mask_token, tokenizer.decode([token]))}'")
```

{:else}

```python
import numpy as np
import tensorflow as tf

inputs = tokenizer(text, return_tensors="np")
token_logits = model(**inputs).logits
# Find the location of [MASK] and extract its logits
mask_token_index = np.argwhere(inputs["input_ids"] == tokenizer.mask_token_id)[0, 1]
mask_token_logits = token_logits[0, mask_token_index, :]
# Pick the [MASK] candidates with the highest logits
# We negate the array before argsort to get the largest, not the smallest, logits
top_5_tokens = np.argsort(-mask_token_logits)[:5].tolist()

for token in top_5_tokens:
    print(f">>> {text.replace(tokenizer.mask_token, tokenizer.decode([token]))}")
```

{/if}

```python out
'>>> This is a great deal.'
'>>> This is a great success.'
'>>> This is a great adventure.'
'>>> This is a great idea.'
'>>> This is a great feat.'
```

出力から、モデルの予測は日常的な用語に言及していることがわかりますが、これは英語版ウィキペディアが基盤となっている事を考えれば驚くことではありません。では、この領域をもう少しニッチなもの、つまり、分裂している映画評価データセットに変えてみましょう。

## データセット

ドメイン適応の例を示すために、私たちは有名な[Large Movie Review Dataset](https://huggingface.co/datasets/imdb) (略してIMDb)を使用します。これは、感情分析モデルのベンチマークによく使われる、映画のレビューのコーパスです。このコーパスでDistilBERTを微調整することで、言語モデルが事前学習したWikipediaの事実に基づくデータから、映画レビューのより主観的な要素に語彙を適応させることが期待されます。ハギング フェイス ハブのデータは、🤗 Datasetsの `load_dataset()` 関数で取得することができます。

```python
from datasets import load_dataset

imdb_dataset = load_dataset("imdb")
imdb_dataset
```

```python out
DatasetDict({
    train: Dataset({
        features: ['text', 'label'],
        num_rows: 25000
    })
    test: Dataset({
        features: ['text', 'label'],
        num_rows: 25000
    })
    unsupervised: Dataset({
        features: ['text', 'label'],
        num_rows: 50000
    })
})
```

`train` と `test` 用のデータ分割にはそれぞれ25,000件のレビューから構成され、ラベル付けされていない `unsupervised` という分割には50,000件のレビューが含まれていることがわかります。どのようなテキストを扱っているか知るために、いくつかのサンプルを見てみましょう。このコースの前の章で行ったように、 `Dataset.shuffle()` と `Dataset.select()` 関数を連鎖させて、ランダムなサンプルを作成しましょう。

```python
sample = imdb_dataset["train"].shuffle(seed=42).select(range(3))

for row in sample:
    print(f"\n'>>> Review: {row['text']}'")
    print(f"'>>> Label: {row['label']}'")
```

```python out

'>>> Review: This is your typical Priyadarshan movie--a bunch of loony characters out on some silly mission. His signature climax has the entire cast of the film coming together and fighting each other in some crazy moshpit over hidden money. Whether it is a winning lottery ticket in Malamaal Weekly, black money in Hera Pheri, "kodokoo" in Phir Hera Pheri, etc., etc., the director is becoming ridiculously predictable. Don\'t get me wrong; as clichéd and preposterous his movies may be, I usually end up enjoying the comedy. However, in most his previous movies there has actually been some good humor, (Hungama and Hera Pheri being noteworthy ones). Now, the hilarity of his films is fading as he is using the same formula over and over again.<br /><br />Songs are good. Tanushree Datta looks awesome. Rajpal Yadav is irritating, and Tusshar is not a whole lot better. Kunal Khemu is OK, and Sharman Joshi is the best.'
'>>> Label: 0'

'>>> Review: Okay, the story makes no sense, the characters lack any dimensionally, the best dialogue is ad-libs about the low quality of movie, the cinematography is dismal, and only editing saves a bit of the muddle, but Sam" Peckinpah directed the film. Somehow, his direction is not enough. For those who appreciate Peckinpah and his great work, this movie is a disappointment. Even a great cast cannot redeem the time the viewer wastes with this minimal effort.<br /><br />The proper response to the movie is the contempt that the director San Peckinpah, James Caan, Robert Duvall, Burt Young, Bo Hopkins, Arthur Hill, and even Gig Young bring to their work. Watch the great Peckinpah films. Skip this mess.'
'>>> Label: 0'

'>>> Review: I saw this movie at the theaters when I was about 6 or 7 years old. I loved it then, and have recently come to own a VHS version. <br /><br />My 4 and 6 year old children love this movie and have been asking again and again to watch it. <br /><br />I have enjoyed watching it again too. Though I have to admit it is not as good on a little TV.<br /><br />I do not have older children so I do not know what they would think of it. <br /><br />The songs are very cute. My daughter keeps singing them over and over.<br /><br />Hope this helps.'
'>>> Label: 1'
```

そう、これらは確かに映画のレビューです。もしあなたが十分に年を取っているなら、最後のレビューにあるVHS版を所有しているというコメントさえ理解できるかもしれません😜! 言語モデリングにはラベルは必要ありませんが、`0`は否定的なレビュー、`1`は肯定的なレビューに対応することがもうわかりました。

<Tip>

✏️ **挑戦してみましょう！** `unsupervised` のラベルがついた分割データのランダムサンプルを作成し、ラベルが `0` や `1` でないことを確認してみましょう。また、`train` と `test` 用の分割データのラベルが本当に `0` か `1` のみかを確認することもできます。これはすべての自然言語処理の実践者が新しいプロジェクトの開始時に実行すべき、有用なサニティチェックです!

</Tip>

さて、データをざっと見たところで、マスク言語モデリングのための準備に取りかかりましょう。[第3章](/course/ja/chapter3)で見たシーケンス分類のタスクと比較すると、いくつかの追加ステップが必要であることがわかるでしょう。さあ、始めましょう！

## データの前処理

<Youtube id="8PmhEIXhBvI"/>

自己回帰言語モデリングでもマスク言語モデリングでも、共通の前処理として、すべての用例を連結し、コーパス全体を同じ大きさの断片に分割することが行われます。これは、個々のサンプルを単純にトークン化するという、私達の通常のアプローチとは全く異なるものです。なぜすべてを連結するのでしょうか？それは、個々の例文が長すぎると切り捨てられる可能性があり、言語モデリングタスクに役立つかもしれない情報が失われてしまうからです！

そこで、まずいつものようにコーパスをトークン化します。ただし、トークン化する際に `truncation=True` オプションをtokenizerに_設定しない_ようにします。また、単語IDがあればそれを取得します（[6章](/course/ja/chapter6/3)で説明した高速tokenizerを使用している場合はそうなります）。後で単語全体をマスキングするために必要になるからです。これをシンプルな関数にまとめ、ついでに `text` と `label` カラムも不要になったので削除してしまいましょう。

```python
def tokenize_function(examples):
    result = tokenizer(examples["text"])
    if tokenizer.is_fast:
        result["word_ids"] = [result.word_ids(i) for i in range(len(result["input_ids"]))]
    return result


# Use batched=True to activate fast multithreading!
tokenized_datasets = imdb_dataset.map(
    tokenize_function, batched=True, remove_columns=["text", "label"]
)
tokenized_datasets
```

```python out
DatasetDict({
    train: Dataset({
        features: ['attention_mask', 'input_ids', 'word_ids'],
        num_rows: 25000
    })
    test: Dataset({
        features: ['attention_mask', 'input_ids', 'word_ids'],
        num_rows: 25000
    })
    unsupervised: Dataset({
        features: ['attention_mask', 'input_ids', 'word_ids'],
        num_rows: 50000
    })
})
```

DistilBERTはBERTに似たモデルなので、エンコードされたテキストは、他の章で見た `input_ids` と `attention_mask` に加え、私達が追加した `word_ids` で構成されていることがわかります。

さて、映画のレビューをトークン化したので、次のステップはそれらをすべてグループ化して、結果を断片に分割することです。しかし、この断片の大きさはどの程度にすべきでしょうか？これは最終的には利用可能な GPU メモリの量によって決まりますが、良い出発点はモデルの最大コンテキストサイズが何であるかを見ることです。これはtokenizerの `model_max_length` 属性を調べることで推測することができます。

```python
tokenizer.model_max_length
```

```python out
512
```

この値は、チェックポイントに関連付けられた *tokenizer_config.json* ファイルから取得します。この場合、BERT と同様に、コンテキストサイズが 512 トークンであることが分かります。

<Tip>

✏️ ** あなたの番です！ ** [BigBird](https://huggingface.co/google/bigbird-roberta-base) や [Longformer](hf.co/allenai/longformer-base-4096) などのいくつかの Transformer モデルは、BERT や他の初期の Transformer モデルよりずっと長いコンテキスト長を持っています。これらのチェックポイントのトークナイザーをインスタンス化して、`model_max_length` がそのモデルカード内に記載されているものと一致することを検証してください。

</Tip>

され、Google Colab内で利用可能なGPUで実験を行うために、メモリに収まるような少し小さめのものを選ぶことにします。

```python
chunk_size = 128
```

<Tip warning={true}>

なお、小さな断片サイズを使用すると、実際のシナリオでは不利になることがあるので、モデルを適用するユースケースに対応したサイズを使用する必要があります。

</Tip>

さて、ここからが楽しいところです。連結がどのように機能するかを示すために、トークン化されたトレーニングセットからいくつかのレビューを取り出し、レビュー毎のトークン数を出力してみましょう。

```python
# Slicing produces a list of lists for each feature
tokenized_samples = tokenized_datasets["train"][:3]

for idx, sample in enumerate(tokenized_samples["input_ids"]):
    print(f"'>>> Review {idx} length: {len(sample)}'")
```

```python out
'>>> Review 0 length: 200'
'>>> Review 1 length: 559'
'>>> Review 2 length: 192'
```

そして、これらの例をすべてをシンプルな辞書内包表記を使って連結すると、次のようになります。

```python
concatenated_examples = {
    k: sum(tokenized_samples[k], []) for k in tokenized_samples.keys()
}
total_length = len(concatenated_examples["input_ids"])
print(f"'>>> Concatenated reviews length: {total_length}'")
```

```python out
'>>> Concatenated reviews length: 951'
```

素晴らしい！全体の長さの裏付けがとれました。

では、連結されたレビューを `block_size` で指定されたサイズの断片に分割してみましょう。そのために、 `concatenated_examples` を繰り返し処理し、リスト内包表記を使用して各特徴のスライスを作成します。その結果、断片の辞書ができあがります。

```python
chunks = {
    k: [t[i : i + chunk_size] for i in range(0, total_length, chunk_size)]
    for k, t in concatenated_examples.items()
}

for chunk in chunks["input_ids"]:
    print(f"'>>> Chunk length: {len(chunk)}'")
```

```python out
'>>> Chunk length: 128'
'>>> Chunk length: 128'
'>>> Chunk length: 128'
'>>> Chunk length: 128'
'>>> Chunk length: 128'
'>>> Chunk length: 128'
'>>> Chunk length: 128'
'>>> Chunk length: 55'
```

この例でわかるように、一般的に最後の断片は最大断片サイズより小さくなります。これを扱うには、主に 2 つの方法があります。

* 最後の断片が `chunk_size` よりも小さければ削除する
* 最後の断片の長さが `chunk_size` と等しくなるまで、最後の断片にダミーデータを詰め込む

ここでは、最初のアプローチをとります。上記のロジックをすべてひとつの関数にまとめ、トークン化されたデータセットに適用してみましょう。

```python
def group_texts(examples):
    # Concatenate all texts
    concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
    # Compute length of concatenated texts
    total_length = len(concatenated_examples[list(examples.keys())[0]])
    # We drop the last chunk if it's smaller than chunk_size
    total_length = (total_length // chunk_size) * chunk_size
    # Split by chunks of max_len
    result = {
        k: [t[i : i + chunk_size] for i in range(0, total_length, chunk_size)]
        for k, t in concatenated_examples.items()
    }
    # Create a new labels column
    result["labels"] = result["input_ids"].copy()
    return result
```

`group_texts()` の最後のステップでは、 `input_ids` 列のコピーである新しい `labels` 列を作成していることに注意してください。これから説明するように、マスク言語モデリングでは、入力部に含まれるランダムなマスクトークンを予測することが目的です。 `labels` 列は、言語モデルが学習の際に参考する真実の値を提供するために使用します。

それでは、信頼できる `Dataset.map()` 関数を使って、トークン化されたデータセットに `group_texts()` を適用してみましょう。

```python
lm_datasets = tokenized_datasets.map(group_texts, batched=True)
lm_datasets
```

```python out
DatasetDict({
    train: Dataset({
        features: ['attention_mask', 'input_ids', 'labels', 'word_ids'],
        num_rows: 61289
    })
    test: Dataset({
        features: ['attention_mask', 'input_ids', 'labels', 'word_ids'],
        num_rows: 59905
    })
    unsupervised: Dataset({
        features: ['attention_mask', 'input_ids', 'labels', 'word_ids'],
        num_rows: 122963
    })
})
```

テキストをグループ化し、断片に分けたことで`train`と`test`のデータセットで25,000よりも多くのサンプルが生成されていることがわかります。これは、元のコーパスに複数のレビューを含むものがあるため _連続トークン_ を含むサンプルができたからです。このことは、断片の1つにある特別な `[SEP]` と `[CLS]` トークンを探すことで明確にわかります。

```python
tokenizer.decode(lm_datasets["train"][1]["input_ids"])
```

```python out
".... at.......... high. a classic line : inspector : i'm here to sack one of your teachers. student : welcome to bromwell high. i expect that many adults of my age think that bromwell high is far fetched. what a pity that it isn't! [SEP] [CLS] homelessness ( or houselessness as george carlin stated ) has been an issue for years but never a plan to help those on the street that were once considered human who did everything from going to school, work, or vote for the matter. most people think of the homeless"
```

上の例では、高校に関する映画とホームレスに関する映画のレビューが2つ重複しているのがわかります。また、マスク言語モデリングのラベルがどのように見えるか確認してみましょう。

```python out
tokenizer.decode(lm_datasets["train"][1]["labels"])
```

```python out
".... at.......... high. a classic line : inspector : i'm here to sack one of your teachers. student : welcome to bromwell high. i expect that many adults of my age think that bromwell high is far fetched. what a pity that it isn't! [SEP] [CLS] homelessness ( or houselessness as george carlin stated ) has been an issue for years but never a plan to help those on the street that were once considered human who did everything from going to school, work, or vote for the matter. most people think of the homeless"
```

上の `group_texts()` 関数から予想されるように、これはデコードされた `input_ids` と同じに見えます。しかし、それではこのモデルはどうやって何かを学習するのでしょうか？入力のランダムな位置に `[MASK]` トークンを挿入する、という重要なステップが抜けているのです。それでは、特別なデータコレーターを使って、微調整の際にどのようにこれを行うか見てみましょう。

## DistilBERTを`Trainer`APIで微調整する

マスク言語モデルの微調整は、[第3章](/course/ja/chapter3)で行ったようなシーケンス分類モデルの微調整とほぼ同じです。唯一の違いは、各バッチのテキストに含まれるいくつかのトークンをランダムにマスクすることができる特別なデータコレーターが必要であることです。幸いなことに、🤗 Transformersにはこのタスクのために専用の `DataCollatorForLanguageModeling` が用意されています。私たちはtokenizerと、マスクするトークンの割合を指定する `mlm_probability` 引数を渡すだけでよいのです。ここでは、BERTで使用され、文献上でも一般的な選択である15％を選びます。

```python
from transformers import DataCollatorForLanguageModeling

data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15)
```

ランダムマスクがどのように機能するかを見るために、いくつかの例を data_collator に与えてみましょう。コレーターは辞書型 のリストを想定しており、各 辞書は連続したテキストの塊を表すので、まずデータセットを繰り返し処理してからコレーターにバッチを渡します。このデータコレーターは `"word_ids"` キーを必要としないので、これを削除します。

```python
samples = [lm_datasets["train"][i] for i in range(2)]
for sample in samples:
    _ = sample.pop("word_ids")

for chunk in data_collator(samples)["input_ids"]:
    print(f"\n'>>> {tokenizer.decode(chunk)}'")
```

```python output
'>>> [CLS] bromwell [MASK] is a cartoon comedy. it ran at the same [MASK] as some other [MASK] about school life, [MASK] as " teachers ". [MASK] [MASK] [MASK] in the teaching [MASK] lead [MASK] to believe that bromwell high\'[MASK] satire is much closer to reality than is " teachers ". the scramble [MASK] [MASK] financially, the [MASK]ful students whogn [MASK] right through [MASK] pathetic teachers\'pomp, the pettiness of the whole situation, distinction remind me of the schools i knew and their students. when i saw [MASK] episode in [MASK] a student repeatedly tried to burn down the school, [MASK] immediately recalled. [MASK]...'

'>>> .... at.. [MASK]... [MASK]... high. a classic line plucked inspector : i\'[MASK] here to [MASK] one of your [MASK]. student : welcome to bromwell [MASK]. i expect that many adults of my age think that [MASK]mwell [MASK] is [MASK] fetched. what a pity that it isn\'t! [SEP] [CLS] [MASK]ness ( or [MASK]lessness as george 宇in stated )公 been an issue for years but never [MASK] plan to help those on the street that were once considered human [MASK] did everything from going to school, [MASK], [MASK] vote for the matter. most people think [MASK] the homeless'
```

いいですね、うまくいきました！
`[MASK]`トークンがテキストの様々な場所にランダムに挿入されていることがわかります。

これらが学習中にモデルが予測しなければならないトークンになります。そしてデータコレーターの素晴らしいところは、バッチごとに`[MASK]`の挿入をランダムにすることです! 

<Tip>

✏️ ** あなたの番です！ ** 上のコードを何度か実行して、ランダムなマスキングがあなたの目の前で起こるのを見ましょう! また、`tokenizer.decode()` メソッドを `tokenizer.convert_ids_to_tokens()` に置き換えると、与えた単語内から一つのトークンが選択されてマスクされ、他の単語がマスクされないことを見ることができます。

</Tip>

{#if fw === 'pt'}

ランダムマスキングの副作用として、`Trainer`を使用する場合、評価指標が確定的でなくなることが挙げられます。
これはトレーニングセットとテストセットに同じデータコレーターを使用するためです。後ほど、🤗 Accelerateで微調整を行う際に、カスタム評価ループの柔軟性を利用してランダム性をなくす方法について説明します。

{/if}

マスク言語モデルをトレーニングする場合、個々のトークンではなく、単語全体をマスキングする手法があります。この手法は _whole word masking_ と呼ばれます。単語全体をマスキングする場合、データコレーターを自作する必要があります。データコレーターとは、サンプルのリストを受け取り、それをバッチ変換する関数のことです。

今からやってみましょう！

先ほど計算した単語IDを使って、単語のインデックスと対応するトークンのマップを作る事にします。どの単語をマスクするかをランダムに決めて、そのマスクを入力に適用します。なお、ラベルはマスクする単語を除いて全て`-100`です。

{#if fw === 'pt'}

```py
import collections
import numpy as np

from transformers import default_data_collator

wwm_probability = 0.2


def whole_word_masking_data_collator(features):
    for feature in features:
        word_ids = feature.pop("word_ids")

        # Create a map between words and corresponding token indices
        mapping = collections.defaultdict(list)
        current_word_index = -1
        current_word = None
        for idx, word_id in enumerate(word_ids):
            if word_id is not None:
                if word_id != current_word:
                    current_word = word_id
                    current_word_index += 1
                mapping[current_word_index].append(idx)

        # Randomly mask words
        mask = np.random.binomial(1, wwm_probability, (len(mapping),))
        input_ids = feature["input_ids"]
        labels = feature["labels"]
        new_labels = [-100] * len(labels)
        for word_id in np.where(mask)[0]:
            word_id = word_id.item()
            for idx in mapping[word_id]:
                new_labels[idx] = labels[idx]
                input_ids[idx] = tokenizer.mask_token_id
        feature["labels"] = new_labels

    return default_data_collator(features)
```

{:else}

```py
import collections
import numpy as np

from transformers.data.data_collator import tf_default_data_collator

wwm_probability = 0.2


def whole_word_masking_data_collator(features):
    for feature in features:
        word_ids = feature.pop("word_ids")

        # Create a map between words and corresponding token indices
        mapping = collections.defaultdict(list)
        current_word_index = -1
        current_word = None
        for idx, word_id in enumerate(word_ids):
            if word_id is not None:
                if word_id != current_word:
                    current_word = word_id
                    current_word_index += 1
                mapping[current_word_index].append(idx)

        # Randomly mask words
        mask = np.random.binomial(1, wwm_probability, (len(mapping),))
        input_ids = feature["input_ids"]
        labels = feature["labels"]
        new_labels = [-100] * len(labels)
        for word_id in np.where(mask)[0]:
            word_id = word_id.item()
            for idx in mapping[word_id]:
                new_labels[idx] = labels[idx]
                input_ids[idx] = tokenizer.mask_token_id
        feature["labels"] = new_labels

    return tf_default_data_collator(features)
```

{/if}

次に、先ほどと同じサンプルで試してみます。

```py
samples = [lm_datasets["train"][i] for i in range(2)]
batch = whole_word_masking_data_collator(samples)

for chunk in batch["input_ids"]:
    print(f"\n'>>> {tokenizer.decode(chunk)}'")
```

```python out
'>>> [CLS] bromwell high is a cartoon comedy [MASK] it ran at the same time as some other programs about school life, such as " teachers ". my 35 years in the teaching profession lead me to believe that bromwell high\'s satire is much closer to reality than is " teachers ". the scramble to survive financially, the insightful students who can see right through their pathetic teachers\'pomp, the pettiness of the whole situation, all remind me of the schools i knew and their students. when i saw the episode in which a student repeatedly tried to burn down the school, i immediately recalled.....'

'>>> .... [MASK] [MASK] [MASK] [MASK]....... high. a classic line : inspector : i\'m here to sack one of your teachers. student : welcome to bromwell high. i expect that many adults of my age think that bromwell high is far fetched. what a pity that it isn\'t! [SEP] [CLS] homelessness ( or houselessness as george carlin stated ) has been an issue for years but never a plan to help those on the street that were once considered human who did everything from going to school, work, or vote for the matter. most people think of the homeless'
```

<Tip>

✏️ ** あなたの番です！ ** 上のコードを何度か実行して、ランダムなマスキングがあなたの目の前で起こるのを見ましょう! また、`tokenizer.decode()` メソッドを `tokenizer.convert_ids_to_tokens()` に置き換えると、与えられた単語からのトークンが常に一緒にマスクされることを確認できます。

</Tip>

これで2つのデータコレーターが揃いましたので、残りの微調整ステップは標準的なものです。Google Colabで、神話に出てくるP100 GPUを運良く割り当てられなかった場合、学習に時間がかかることがあります😭そこで、まず学習セットのサイズを数千事例までダウンサンプルします。心配しないでください、それでもかなりまともな言語モデルができますよ。🤗 Datasets 内のデータセットは[第5章](/course/ja/chapter5)で紹介した `Dataset.train_test_split()` 関数で簡単にダウンサンプリングすることができます。

```python
train_size = 10_000
test_size = int(0.1 * train_size)

downsampled_dataset = lm_datasets["train"].train_test_split(
    train_size=train_size, test_size=test_size, seed=42
)
downsampled_dataset
```

```python out
DatasetDict({
    train: Dataset({
        features: ['attention_mask', 'input_ids', 'labels', 'word_ids'],
        num_rows: 10000
    })
    test: Dataset({
        features: ['attention_mask', 'input_ids', 'labels', 'word_ids'],
        num_rows: 1000
    })
})
```

これは自動的に新しい `train` と `test` にデータを分割し、トレーニングセットのサイズを 10,000 事例に、検証セットをその 10%に設定しました。もし強力なGPUをお持ちなら、この値を自由に増やしてください！

次に必要なことは、ハギング フェイス ハブにログインすることです。このコードをnotebookで実行する場合は、次のユーティリティ関数で実行できます。

```python
from huggingface_hub import notebook_login

notebook_login()
```

上記を実行すると、入力ウィジェットが表示され、認証情報を入力することができます。また実行することもできます。

```
huggingface-cli login
```

好みに応じて、ターミナルを起動し、そこからログインしてください。

{#if fw === 'tf'}

一度ログインしたら、`tf.data`データセットを作成する事ができます。ここでは標準的なデータコレーターを使いますが、練習として全単語マスキングのコレーターを試して結果を比較することも可能です。

```python
tf_train_dataset = downsampled_dataset["train"].to_tf_dataset(
    columns=["input_ids", "attention_mask", "labels"],
    collate_fn=data_collator,
    shuffle=True,
    batch_size=32,
)

tf_eval_dataset = downsampled_dataset["test"].to_tf_dataset(
    columns=["input_ids", "attention_mask", "labels"],
    collate_fn=data_collator,
    shuffle=False,
    batch_size=32,
)
```

次に、学習用ハイパーパラメータを設定し、モデルをコンパイルします。Transformersライブラリの `create_optimizer()` 関数を使用し、学習率が線形に減衰する性質を持つ `AdamW` オプティマイザを使用します。また、モデルの組み込みの損失を使用します。これは `compile()` の引数に損失が指定されていない場合のデフォルトであり、学習精度は `"mixed_float16"` に設定されます。Colabで割り当てられたGPUやお使いのGPUがfloat16のサポートをしていない場合は、この行をコメントアウトする必要があります。

さらに、各エポック後にモデルをハブに保存する `PushToHubCallback` をセットアップします。`hub_model_id` 引数で、プッシュしたいリポジトリの名前を指定します。（特に、組織を指定してプッシュする場合はこの引数を使用する必要があります）。例えば、モデルを [`huggingface-course` organization](https://huggingface.co/huggingface-course) にプッシュするには、 `hub_model_id="huggingface-course/distilbert-finetuned-imdb"` を追加しました。デフォルトでは、使用されるリポジトリはあなたの名前空間になり、設定された出力ディレクトリの名前になります。そのため、私達のケースでは`"lewtun/distilbert-finetuned-imdb"` となるでしょう。

```python
from transformers import create_optimizer
from transformers.keras_callbacks import PushToHubCallback
import tensorflow as tf

num_train_steps = len(tf_train_dataset)
optimizer, schedule = create_optimizer(
    init_lr=2e-5,
    num_warmup_steps=1_000,
    num_train_steps=num_train_steps,
    weight_decay_rate=0.01,
)
model.compile(optimizer=optimizer)

# Train in mixed-precision float16
tf.keras.mixed_precision.set_global_policy("mixed_float16")

callback = PushToHubCallback(
    output_dir=f"{model_name}-finetuned-imdb", tokenizer=tokenizer
)
```

これで `model.fit()` を実行する準備ができました。
しかし、これを実行する前に言語モデルの性能を評価する一般的な指標である _パープレキシティ_ について簡単に見ておきましょう。

{:else}

一度ログインしたら、`Trainer` の引数を指定できます。

```python
from transformers import TrainingArguments

batch_size = 64
# Show the training loss with every epoch
logging_steps = len(downsampled_dataset["train"]) // batch_size
model_name = model_checkpoint.split("/")[-1]

training_args = TrainingArguments(
    output_dir=f"{model_name}-finetuned-imdb",
    overwrite_output_dir=True,
    evaluation_strategy="epoch",
    learning_rate=2e-5,
    weight_decay=0.01,
    per_device_train_batch_size=batch_size,
    per_device_eval_batch_size=batch_size,
    push_to_hub=True,
    fp16=True,
    logging_steps=logging_steps,
)
```

ここでは、各エポックでの学習損失を確実に追跡するために `logging_steps` を含むデフォルトのオプションを少し調整しました。また、 `fp16=True` を使用して、混合精度の学習を有効にし、さらに高速化しました。デフォルトでは、 `Trainer` はモデルの `forward()` メソッドに含まれない列をすべて削除します。つまり、全単語マスク用のデータコレーターを使用している場合は、 `remove_unused_columns=False` を設定して、学習時に `word_ids` カラムが失われないようにする必要があります。

なお、 `hub_model_id` 引数でプッシュ先のリポジトリ名を指定することができます (特に、組織にプッシュする場合はこの引数を使用する必要があります)。例えば、モデルを [`huggingface-course` organization](https://huggingface.co/huggingface-course) にプッシュする場合、 `TrainingArguments` に `hub_model_id="huggingface-course/distilbert-finetuned-imdb"` を追加しています。デフォルトでは、使用するリポジトリはあなたの名前空間内にあり、設定した出力ディレクトリにちなんだ名前になるので、私たちの場合は `"lewtun/distilbert-finetuned-imdb"` となります。

これで `Trainer` のインスタンスを作成するための材料が揃いました。ここでは、標準的な `data_collator` を使用しますが、練習として全単語マスキングのデータコレーターを試して、結果を比較することができます。

```python
from transformers import Trainer

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=downsampled_dataset["train"],
    eval_dataset=downsampled_dataset["test"],
    data_collator=data_collator,
    tokenizer=tokenizer,
)
```

これで `trainer.train()` を実行する準備ができました。しかしその前に、言語モデルの性能を評価する一般的な指標である _パープレキシティ_ について簡単に見ておきましょう。

{/if}

### 言語モデルのパープレキシティ

<Youtube id="NURcDHhYe98"/>

テキストの分類や質問応答のように、ラベル付けされたコーパスを用いて学習する他のタスクとは異なり、言語モデリングでは明示的なラベルを一切持ちません。では、何が良い言語モデルなのか、どのように判断すればよいのでしょうか？

携帯電話の自動補正機能のように、文法的に正しい文には高い確率で、無意味な文には低い確率で割り当てることができるものが良い言語モデルです。自動補正の失敗例として、携帯電話に搭載された自動補正モデルが、おかしな（そして往々にして不適切な）文章を生成している例がネット上に多数紹介されています。

{#if fw === 'pt'}

テストセットのほとんどが文法的に正しい文であると仮定すると、言語モデルの品質を測る一つの方法は、テストセットのすべての文において、次に出現する単語を正しく割り当てる確率を計算することです。確率が高いということは、モデルが未知の例文に「驚き」や「当惑」を感じていないことを示し、その言語の文法の基本パターンを学習していることを示唆しています。パープレキシティには様々な数学的定義がありますが、私達が使うのはクロスエントロピー損失の指数として定義するものです。したがって、`Trainer.evaluate()`関数を使ってテスト集合のクロスエントロピー損失を計算し、その結果の指数を取ることで事前学習済みモデルのパープレキシティを計算することができるのです。

```python
import math

eval_results = trainer.evaluate()
print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
```

{:else}
テストセットのほとんどが文法的に正しい文章で構成されていると仮定すると、言語モデルの品質を測定する一つの方法は、テストセットのすべての文章で次の単語が正しく割り当てる確率を計算することです。確率が高いということは、モデルが未見の例文に「驚き」「当惑」していないことを示し、その言語の文法の基本パターンを学習していることを示唆しています。パープレキシティには様々な数学的定義がありますが、私達が使うのはクロスエントロピーの損失の指数として定義するものです。したがって、`model.evaluate()` メソッドを使ってテスト集合のクロスエントロピー損失を計算し、その結果の指数を取ることで事前学習済みモデルのパープレキシティを計算することができるのです。

```python
import math

eval_loss = model.evaluate(tf_eval_dataset)
print(f"Perplexity: {math.exp(eval_loss):.2f}")
```

{/if}

```python out
>>> Perplexity: 21.75
```

パープレキシティスコアが低いほど、良い言語モデルということになります。
私達の開始時のモデルの値はやや大きいことがわかります。
では、微調整によってこの値を下げられるか見てみましょう。そのために、まず学習ループを実行します。


{#if fw === 'pt'}

```python
trainer.train()
```

{:else}

```python
model.fit(tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback])
```

{/if}

それから計算を実行し、その結果得られたテストセットに対するパープレキシティを先ほどと同様に計算します。

{#if fw === 'pt'}

```python
eval_results = trainer.evaluate()
print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
```

{:else}

```python
eval_loss = model.evaluate(tf_eval_dataset)
print(f"Perplexity: {math.exp(eval_loss):.2f}")
```

{/if}

```python out
>>> Perplexity: 11.32
```

素敵！かなりパープレキシティを減らすことができました。
これは、モデルが映画レビューの領域について何かを学んだことを示しています。

{#if fw === 'pt'}

一度、トレーニングが終了したら、トレーニング情報が入ったモデルカードをHubにプッシュする事ができます。（チェックポイントはトレーニングの最中に保存されます）。

```python
trainer.push_to_hub()
```

{/if}

<Tip>

✏️ ** あなたの番です！ ** データコレーターを全単語マスキングコレーターに変えて、上記のトレーニングを実行してみましょう。より良い結果が得られましたか？

</Tip>

{#if fw === 'pt'} 

今回の使用例では、トレーニングループに特別なことをする必要はありませんでしたが、場合によってはカスタムロジックを実装する必要があるかもしれません。そのようなアプリケーションでは、🤗 Accelerateを使用することができます。
見てみましょう!

## DistilBERTを🤗 Accelerateを使って微調整する

`Trainer`で見たように、マスクされた言語モデルの微調整は[第3章](/course/ja/chapter3)のテキスト分類の例と非常によく似ています。実際、唯一のわずかな違いは特別なデータコレーターを使うことで、それはこのセクションの前半ですでに取り上げました! 

しかし、`DataCollatorForLanguageModeling`は評価ごとにランダムなマスキングを行うので、学習実行ごとにパープレキシティスコアに多少の変動が見られることがわかりました。このランダム性を排除する一つの方法は、テストセット全体に _一度だけ_ マスキングを適用し、その後🤗 Transformersのデフォルトのデータコレーターを使用して、評価中にバッチを収集することです。これがどのように機能するかを見るために、`DataCollatorForLanguageModeling` を最初に使った時と同様に、バッチにマスキングを適用する簡単な関数を実装してみましょう。

```python
def insert_random_mask(batch):
    features = [dict(zip(batch, t)) for t in zip(*batch.values())]
    masked_inputs = data_collator(features)
    # Create a new "masked" column for each column in the dataset
    return {"masked_" + k: v.numpy() for k, v in masked_inputs.items()}
```

次に、この関数をテストセットに適用して、マスクされていないカラムを削除し、マスクされたカラムに置き換えることができるようにします。上の `data_collator` を適切なものに置き換えることで、全単語単位でのマスキングを行うことができます。
その場合は、以下の最初の行を削除してください。

```py
downsampled_dataset = downsampled_dataset.remove_columns(["word_ids"])
eval_dataset = downsampled_dataset["test"].map(
    insert_random_mask,
    batched=True,
    remove_columns=downsampled_dataset["test"].column_names,
)
eval_dataset = eval_dataset.rename_columns(
    {
        "masked_input_ids": "input_ids",
        "masked_attention_mask": "attention_mask",
        "masked_labels": "labels",
    }
)
```

あとは通常通りデータローダーをセットアップしますが、ここでは評価セットに 🤗 Transformers の `default_data_collator` を使用します。

```python
from torch.utils.data import DataLoader
from transformers import default_data_collator

batch_size = 64
train_dataloader = DataLoader(
    downsampled_dataset["train"],
    shuffle=True,
    batch_size=batch_size,
    collate_fn=data_collator,
)
eval_dataloader = DataLoader(
    eval_dataset, batch_size=batch_size, collate_fn=default_data_collator
)
```

ここでは、🤗 Accelerateを使った標準的なステップに従います。最初にやる事は、事前学習したモデルの新しいバージョンをロードすることです。

```
model = AutoModelForMaskedLM.from_pretrained(model_checkpoint)
```

次に、オプティマイザを指定します。ここでは、標準的な `AdamW` を使用します。

```python
from torch.optim import AdamW

optimizer = AdamW(model.parameters(), lr=5e-5)
```

これらのオブジェクトがあれば、あとは `Accelerator` オブジェクトを使ってトレーニングのためのすべてを準備することができます。

```python
from accelerate import Accelerator

accelerator = Accelerator()
model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare(
    model, optimizer, train_dataloader, eval_dataloader
)
```

モデル、オプティマイザー、データローダーが設定されたので、学習率スケジューラーを以下のように指定することができます。

```python
from transformers import get_scheduler

num_train_epochs = 3
num_update_steps_per_epoch = len(train_dataloader)
num_training_steps = num_train_epochs * num_update_steps_per_epoch

lr_scheduler = get_scheduler(
    "linear",
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=num_training_steps,
)
```

トレーニングの前に最後にすることがあります。ハギング フェイス ハブにモデルリポジトリを作成することです。🤗 Hub ライブラリを使って、まずレポジトリのフルネームを生成します。

```python
from huggingface_hub import get_full_repo_name

model_name = "distilbert-base-uncased-finetuned-imdb-accelerate"
repo_name = get_full_repo_name(model_name)
repo_name
```

```python out
'lewtun/distilbert-base-uncased-finetuned-imdb-accelerate'
```

それから、🤗 Hub の `Repository` クラスを使用してリポジトリを作成し、クローンします。

```python
from huggingface_hub import Repository

output_dir = model_name
repo = Repository(output_dir, clone_from=repo_name)
```

これができれば、あとはトレーニングと評価のループをすべて書き出すだけです。

```python
from tqdm.auto import tqdm
import torch
import math

progress_bar = tqdm(range(num_training_steps))

for epoch in range(num_train_epochs):
    # Training
    model.train()
    for batch in train_dataloader:
        outputs = model(**batch)
        loss = outputs.loss
        accelerator.backward(loss)

        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        progress_bar.update(1)

    # Evaluation
    model.eval()
    losses = []
    for step, batch in enumerate(eval_dataloader):
        with torch.no_grad():
            outputs = model(**batch)

        loss = outputs.loss
        losses.append(accelerator.gather(loss.repeat(batch_size)))

    losses = torch.cat(losses)
    losses = losses[: len(eval_dataset)]
    try:
        perplexity = math.exp(torch.mean(losses))
    except OverflowError:
        perplexity = float("inf")

    print(f">>> Epoch {epoch}: Perplexity: {perplexity}")

    # Save and upload
    accelerator.wait_for_everyone()
    unwrapped_model = accelerator.unwrap_model(model)
    unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save)
    if accelerator.is_main_process:
        tokenizer.save_pretrained(output_dir)
        repo.push_to_hub(
            commit_message=f"Training in progress epoch {epoch}", blocking=False
        )
```

```python out
>>> Epoch 0: Perplexity: 11.397545307900472
>>> Epoch 1: Perplexity: 10.904909330983092
>>> Epoch 2: Perplexity: 10.729503505340409
```

イケてる！
エポックごとにパープレキシティを評価し、複数回のトレーニングを実行した際の再現性を確保することができました

{/if}

## 微調整したモデルを使う

微調整したモデルは、Hub上のウィジェットを使うか、🤗 Transformersの `pipeline` を使ってローカル環境で操作することができます。それでは後者に挑戦してみましょう。`fill-mask`パイプラインを使用してモデルをダウンロードします。

```python
from transformers import pipeline

mask_filler = pipeline(
    "fill-mask", model="huggingface-course/distilbert-base-uncased-finetuned-imdb"
)
```

そして「これは素晴らしい[MASK]です」というサンプルテキストをパイプラインに送り、上位5つの予測を確認することができます。


```python
preds = mask_filler(text)

for pred in preds:
    print(f">>> {pred['sequence']}")
```

```python out
'>>> this is a great movie.'
'>>> this is a great film.'
'>>> this is a great story.'
'>>> this is a great movies.'
'>>> this is a great character.'
```

すっきりしました。
このモデルは、映画と関連する単語をより強く予測するように、明らかに重みを適応させていますね！

<Youtube id="0Oxphw4Q9fo"/>

これで、言語モデルを学習するための最初の実験を終えました。[セクション6](/course/ja/chapter7/section6)では、GPT-2のような自己回帰モデルをゼロから学習する方法を学びます。もし、あなた自身のTransformerモデルをどうやって事前学習するか見たいなら、そちらに向かってください

<Tip>

✏️ ** あなたの番です！ ** ドメイン適応の利点を定量化するために、IMDbラベルの分類器を、訓練前と微調整したDistilBERTチェックポイントの両方で微調整してください。テキスト分類について復習が必要な場合は、[第3章](/course/ja/chapter3)をチェックしてみてください。

</Tip>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter7/3.mdx" />

### 因果言語モデルを一から学習
https://huggingface.co/learn/course/ja/chapter7/6.md

# 因果言語モデルを一から学習

{#if fw === 'pt'}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section6_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section6_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section6_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section6_tf.ipynb"},
]} />

{/if}

今までは、事前学習したモデルを使い、事前学習時の重みを再利用して新しい用途向けに微調整を行うことがほとんどでした。[第1章](/course/ja/chapter1)で見たように、これは一般的に _転移学習_ と呼ばれ、ラベル付きデータがあまりない実世界のほとんどの用途でTransformerモデルを適用するための非常に成功した戦略です。この章では、別のアプローチで、全く新しいモデルをゼロから学習します。これは多くのデータを持っている場合に取るべき良いアプローチで、利用可能なモデルに使われる事前学習データとは全く異なります。しかし、言語モデルの事前学習には、既存のモデルを微調整するよりも、かなり多くの計算リソースが必要になります。例えば、音符やDNAなどの分子配列、プログラミング言語などのデータセットに新しいモデルを学習させることが有効な場合があります。後者については、OpenAIのCodexモデルを搭載したTabNineやGitHubのCopilotのような、長いコード列を生成できるツールが最近人気を集めています。このテキスト生成のタスクは、GPT-2のような自己回帰型言語モデルや因果関係言語モデルで対応するのが最適です。

このセクションでは、コード生成モデルの縮小版を構築します。Pythonコードのサブセットを使用して、完全な関数やクラスではなく、1行の補完に焦点を当てます。Pythonでデータを扱うとき、`matplotlib`, `seaborn`, `pandas`, `scikit-learn` ライブラリからなるPythonデータサイエンススタックと頻繁に接触することになります。これらのフレームワークを使うとき、特定のコマンドを調べる必要があるのはよくあることです。そこで、これらの呼び出しを補完するためにモデルを使うことができれば素敵です。

<Youtube id="Vpjb1lu0MDk"/>

[第6章](/course/ja/chapter6)では、Pythonソースコードを処理するための効率的なトークナイザーを作成しましたが、モデルを事前学習するためには、やはり大規模なデータセットが必要です。ここでは、GitHub リポジトリから得た Python コードのコーパスにトークナイザを適用します。そして、`Trainer` API と 🤗 Accelerate を使ってモデルを学習します。さあ、始めましょう

<iframe src="https://course-demos-codeparrot-ds.hf.space" frameBorder="0" height="300" title="Gradio app" class="block dark:hidden container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

これは実際に、このセクションで示したコードを使って学習し、ハブにアップロードしたモデルを紹介しているものです。[こちら](https://huggingface.co/huggingface-course/codeparrot-ds?text=plt.imshow%28)をご覧ください。なお、テキスト生成の際にランダム化が行われているので、おそらく少し異なる結果が得られると思います。
 
## データを収集する

PythonのコードはGitHubなどのコードリポジトリから豊富に提供されており、これを利用してPythonのリポジトリごとにスクレイピングすることでデータセットを作成することができます。これは[トランスフォーマーの教科書](https://learning.oreilly.com/library/view/natural-language-processing/9781098103231/)で大規模なGPT-2モデルを事前学習させるために取られたアプローチです。著者らは`codeparrot`と呼ばれる約2000万のPythonファイルを含む約180GBのGitHubダンプを使ってデータセットを作り、それを[ハギング フェイス ハブ](https://huggingface.co/datasets/transformersbook/codeparrot)で共有しました。

しかし、コーパス全体に対する学習は時間と計算がかかるので、Pythonを使用したデータサイエンスに関連するデータだけが必要です。そこで、まず`codeparrot`データセットから、データサイエンスに使われるライブラリのいずれかを含むすべてのファイルをフィルタリングしてみましょう。データセットのサイズが大きいので、ダウンロードは避けたいです。その代わりに、ストリーミング機能を使って、その場でフィルタリングすることにしましょう。先ほど紹介したライブラリを使ったコードサンプルをフィルタリングするために、次の関数を使います。

```py
def any_keyword_in_string(string, keywords):
    for keyword in keywords:
        if keyword in string:
            return True
    return False
```

2つの例でテストしてみましょう。

```py
filters = ["pandas", "sklearn", "matplotlib", "seaborn"]
example_1 = "import numpy as np"
example_2 = "import pandas as pd"

print(
    any_keyword_in_string(example_1, filters), any_keyword_in_string(example_2, filters)
)
```

```python out
False True
```

これを利用して、データセットをストリーミングし、必要な要素をフィルタリングする関数を作成することができます。

```py
from collections import defaultdict
from tqdm import tqdm
from datasets import Dataset


def filter_streaming_dataset(dataset, filters):
    filtered_dict = defaultdict(list)
    total = 0
    for sample in tqdm(iter(dataset)):
        total += 1
        if any_keyword_in_string(sample["content"], filters):
            for k, v in sample.items():
                filtered_dict[k].append(v)
    print(f"{len(filtered_dict['content'])/total:.2%} of data after filtering.")
    return Dataset.from_dict(filtered_dict)
```

そして、この関数をストリーミングデータセットに適用するだけです。

```py
# This cell will take a very long time to execute, so you should skip it and go to
# the next one!
from datasets import load_dataset

split = "train"  # "valid"
filters = ["pandas", "sklearn", "matplotlib", "seaborn"]

data = load_dataset(f"transformersbook/codeparrot-{split}", split=split, streaming=True)
filtered_data = filter_streaming_dataset(data, filters)
```

```python out
3.26% of data after filtering.
```

この結果、元のデータセットの約3%が残されましたが、それでもかなり大きなサイズです。このデータセットは6GBで、60万のPythonスクリプトから構成されています！

データセット全体のフィルタリングには、マシンや帯域幅にもよりますが、2〜3時間かかると思われます。もし、この長いプロセスを自分でやりたくない場合、私達は既にフィルタリングされたデータセットをハブで提供し、ダウンロードできるようにしています。

```py
from datasets import load_dataset, DatasetDict

ds_train = load_dataset("huggingface-course/codeparrot-ds-train", split="train")
ds_valid = load_dataset("huggingface-course/codeparrot-ds-valid", split="validation")

raw_datasets = DatasetDict(
    {
        "train": ds_train,  # .shuffle().select(range(50000)),
        "valid": ds_valid,  # .shuffle().select(range(500))
    }
)

raw_datasets
```

```python out
DatasetDict({
    train: Dataset({
        features: ['repo_name', 'path', 'copies', 'size', 'content', 'license'],
        num_rows: 606720
    })
    valid: Dataset({
        features: ['repo_name', 'path', 'copies', 'size', 'content', 'license'],
        num_rows: 3322
    })
})
```

<Tip>

言語モデルのプリトレーニングにはしばらく時間がかかります。まず、上記の2つのデータセットに関する部分を一旦コメント化し、サンプルデータに対して学習ループを実行し、学習が一通り正常に終了してモデルが保存されたことを確認することをお勧めします。フォルダを作り忘れたり、学習ループの最後にタイプミスがあったりして、最後のステップで学習が失敗してしまうことほど悔しいことはありません！

</Tip>

データセット内の例を見てみましょう。ここでは、各フィールドの最初の200文字だけを表示することにします。

```py
for key in raw_datasets["train"][0]:
    print(f"{key.upper()}: {raw_datasets['train'][0][key][:200]}")
```

```python out
'REPO_NAME: kmike/scikit-learn'
'PATH: sklearn/utils/__init__.py'
'COPIES: 3'
'SIZE: 10094'
'''CONTENT: """
The :mod:`sklearn.utils` module includes various utilites.
"""

from collections import Sequence

import numpy as np
from scipy.sparse import issparse
import warnings

from .murmurhash import murm
LICENSE: bsd-3-clause'''
```

`content` フィールドに、モデルに学習させたいコードが含まれていることがわかります。データセットができたので、テキストを準備し、事前学習に適した形式にする必要があります。

## データセットの準備

<Youtube id="ma1TrR7gE7I"/>

まず最初に、データをトークン化し、学習に利用できるようにします。私達の目標は主に短い関数呼び出しを自動補完することなので、コンテキストのサイズを比較的小さく保つことができます。これにより、モデルをより速く学習させることができ、必要なメモリ量も大幅に少なくなるという利点があります。もしあなたのアプリケーションにとってより多くのコンテキストを持つことが重要であれば(例えば、関数定義を含むファイルに基づいてユニットテストを書くようにモデルをしたい場合)、この数を増やした事を確認してください。GPT-2 のコンテキストサイズは 1,024、GPT-3 では 2,048 ですが、現在のところ、私達のコンテキストサイズは 128 トークンに固定しましょう。

ほとんどの文書は128トークンより多いので、単純に入力を最大長に切り詰めると、データセットの大部分を除去してしまうことになります。その代わりに、[第6章](/course/ja/chapter6/4) で行ったように、 `return_overflowing_tokens` オプションを使って入力全体をトークン化し、いくつかの断片に分割してみます。また、`return_length`オプションを使用して、作成された各断片の長さを自動的に返します。多くの場合、最後の断片はコンテキストのサイズよりも小さくなるので、パディングの問題を避けるためにこれらの断片を取り除きます。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/chunking_texts.svg" alt="Chunking a large texts in several pieces."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/chunking_texts-dark.svg" alt="Chunking a large texts in several pieces."/>
</div>

最初の2つの例で、この仕組みを具体的に見てみましょう。

```py
from transformers import AutoTokenizer

context_length = 128
tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer")

outputs = tokenizer(
    raw_datasets["train"][:2]["content"],
    truncation=True,
    max_length=context_length,
    return_overflowing_tokens=True,
    return_length=True,
)

print(f"Input IDs length: {len(outputs['input_ids'])}")
print(f"Input chunk lengths: {(outputs['length'])}")
print(f"Chunk mapping: {outputs['overflow_to_sample_mapping']}")
```

```python out
Input IDs length: 34
Input chunk lengths: [128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 117, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 41]
Chunk mapping: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
```

これらの 2 つのサンプルから、合計で 34 の断片が得られることがわかります。断片の長さを見ると、両方のドキュメントの末尾にある断片は 128 トークンより短いことがわかります。(それぞれ 117 と 41)これらは全断片のほんの一部なので、安全に捨てることができます。`overflow_to_sample_mapping` フィールドを使うと、どの断片がどの入力サンプルに属していたかを再構築することもできます。

この操作では、🤗 Datasetsの `Dataset.map()` 関数の便利な機能を使っています。それは、一対一の対応を必要としないことです。[セクション 3](/course/ja/chapter7/3) で見たように、入力バッチよりも要素が多いバッチや少ないバッチを作成することが可能です。これは、データ拡張やデータフィルタリングなど、要素数を変更するような操作を行う場合に有用です。私達の場合、各要素を指定されたコンテキストサイズの断片にトークン化する際に、各文書から多くのサンプルを作成します。ただ、既存の列はサイズが競合しているので、必ず削除する必要があります。もしそれらを残しておきたい場合は、 `Dataset.map()` 呼び出しを適切に繰り返して返すことができます。

```py
def tokenize(element):
    outputs = tokenizer(
        element["content"],
        truncation=True,
        max_length=context_length,
        return_overflowing_tokens=True,
        return_length=True,
    )
    input_batch = []
    for length, input_ids in zip(outputs["length"], outputs["input_ids"]):
        if length == context_length:
            input_batch.append(input_ids)
    return {"input_ids": input_batch}


tokenized_datasets = raw_datasets.map(
    tokenize, batched=True, remove_columns=raw_datasets["train"].column_names
)
tokenized_datasets
```

```python out
DatasetDict({
    train: Dataset({
        features: ['input_ids'],
        num_rows: 16702061
    })
    valid: Dataset({
        features: ['input_ids'],
        num_rows: 93164
    })
})
```

現在、各トークンが128個の1670万サンプルがあり、これは合計で約21億トークンに相当します。参考までに、OpenAIのGPT-3とCodexモデルはそれぞれ3000億、1000億のトークンで学習されており、CodexモデルはGPT-3のチェックポイントから初期化されています。このセクションの目的は、長くて一貫性のあるテキストを生成できるこれらのモデルと競合することではなく、データサイエンティストのための迅速な自動補完機能を提供する縮小版を作成することです。

さて、データセットの準備ができたので、モデルをセットアップしてみましょう!

<Tip>

✏️ **あなたの番です！**

コンテキストサイズより小さい断片を全て取り除くことは、今回は小さなコンテキストウィンドウを使っているので大きな問題ではありませんでした。コンテキストサイズを大きくすると（あるいは短いドキュメントのコーパスがある場合）、捨てられる断片の割合も大きくなります。より効率的なデータの準備方法としては、トークン化されたサンプルを `eos_token_id` トークンを挟んで一括で連結し、連結したデータに対して断片分割を実行することです。練習として、その方法を利用するために `tokenize()` 関数を修正してください。トークン ID の完全なシーケンスを取得するために、 `truncation=False` を設定し、トークナイザーの他の引数を削除する必要があることに注意してください。

</Tip>

## 新しいモデルを初期化する

最初のステップは GPT-2 モデルを新しく初期化することです。このモデルには小型のGPT-2モデルと同じ設定を使用します。そのため、事前学習済みの設定をロードし、トークナイザーのサイズがモデルの語彙サイズと一致することを確認し、`bos`と`eos`（シーケンスの開始と終了を意味します）のトークンIDを渡します。

{#if fw === 'pt'}

```py
from transformers import AutoTokenizer, GPT2LMHeadModel, AutoConfig

config = AutoConfig.from_pretrained(
    "gpt2",
    vocab_size=len(tokenizer),
    n_ctx=context_length,
    bos_token_id=tokenizer.bos_token_id,
    eos_token_id=tokenizer.eos_token_id,
)
```

この構成で、新しいモデルをロードすることができます。これは `from_pretrained()` 関数を使わない最初の例であることに注意してください。なぜなら、実際には自分自身でモデルを初期化しているからです。

```py
model = GPT2LMHeadModel(config)
model_size = sum(t.numel() for t in model.parameters())
print(f"GPT-2 size: {model_size/1000**2:.1f}M parameters")
```

```python out
GPT-2 size: 124.2M parameters
```

{:else}

```py
from transformers import AutoTokenizer, TFGPT2LMHeadModel, AutoConfig

config = AutoConfig.from_pretrained(
    "gpt2",
    vocab_size=len(tokenizer),
    n_ctx=context_length,
    bos_token_id=tokenizer.bos_token_id,
    eos_token_id=tokenizer.eos_token_id,
)
```

この構成で、新しいモデルをロードすることができます。これは `from_pretrained()` 関数を使わない最初の例であることに注意してください。なぜなら、実際には自分自身でモデルを初期化しているからです。

```py
model = TFGPT2LMHeadModel(config)
model(model.dummy_inputs)  # Builds the model
model.summary()
```

```python out
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
transformer (TFGPT2MainLayer multiple                  124242432 
=================================================================
Total params: 124,242,432
Trainable params: 124,242,432
Non-trainable params: 0
_________________________________________________________________
```

{/if}

このモデルには1億2400万のパラメータがあり、これを調整する必要があります。トレーニングを開始する前に、バッチを作成するためのデータコレーターをセットアップする必要があります。私達は`DataCollatorForLanguageModeling`を使う事ができます。

これは言語モデリング用に特別に設計されたものです（その名前が示すとおり）。バッチのスタックとパディングの他にまた、言語モデルのラベルを作成することもできます。因果言語モデリングでは、入力もラベルの役割を果たしますが（要素を1つずらすだけです）、このデータコレーターは学習中にラベルを作成するので、 `input_ids` を重複させる必要がありません。

`DataCollatorForLanguageModeling` はマスク言語モデリング (MLM) と因果言語モデリング (CLM) の両方をサポートすることに注意してください。デフォルトでは MLM 用のデータが用意されていますが、引数 `mlm=False` を設定することでCLMに切り替えることができます。

{#if fw === 'pt'}

```py
from transformers import DataCollatorForLanguageModeling

tokenizer.pad_token = tokenizer.eos_token
data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=False)
```

{:else}

```py
from transformers import DataCollatorForLanguageModeling

tokenizer.pad_token = tokenizer.eos_token
data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=False, return_tensors="tf")
```

{/if}

例を見てみましょう。

```py
out = data_collator([tokenized_datasets["train"][i] for i in range(5)])
for key in out:
    print(f"{key} shape: {out[key].shape}")
```

{#if fw === 'pt'}

```python out
input_ids shape: torch.Size([5, 128])
attention_mask shape: torch.Size([5, 128])
labels shape: torch.Size([5, 128])
```

{:else}

```python out
input_ids shape: (5, 128)
attention_mask shape: (5, 128)
labels shape: (5, 128)
```

{/if}

サンプルを重ねてみると、すべてのテンソルが同じ形をしていることがわかります。

{#if fw === 'tf'}

あとは `to_tf_dataset()` メソッドを使って、上で作成したデータコレーターでデータセットをTensorFlowのデータセットに変換すればよいでしょう。

```python
tf_train_dataset = tokenized_dataset["train"].to_tf_dataset(
    columns=["input_ids", "attention_mask", "labels"],
    collate_fn=data_collator,
    shuffle=True,
    batch_size=32,
)
tf_eval_dataset = tokenized_dataset["valid"].to_tf_dataset(
    columns=["input_ids", "attention_mask", "labels"],
    collate_fn=data_collator,
    shuffle=False,
    batch_size=32,
)
```

{/if}

<Tip warning={true}>

⚠️ 入力とラベルの位置をずらすのはモデル内部で行われるので、データコレーターは入力をコピーしてラベルを作成するだけです。

</Tip>

これで、実際にモデルを訓練するための準備が整いました。

結局のところ、それほど大変な作業ではありませんでしたね。トレーニングを始める前に、ハギング フェイスにログインする必要があります。もしノートブックで作業しているなら、次のユーティリティ関数でログインできます。

```python
from huggingface_hub import notebook_login

notebook_login()
```

これにより、ハギング フェイスのログイン情報を入力するウィジェットが表示されます。

ノートブックで作業していない場合は、ターミナルで次の行を入力するだけです。

```bash
huggingface-cli login
```

{#if fw === 'pt'}

あとは学習用の引数を設定し、`Trainer` を起動するだけです。ここでは、いくつかのウォームアップを伴う cosine 学習率のスケジュールと、256 の有効バッチサイズ (`per_device_train_batch_size` * `gradient_accumulation_steps`) を使用することにします。勾配累積は、単一のバッチがメモリに収まらない場合に使用され、いくつかの前進/後退パスを通して勾配を増分的に構築します。これは、🤗 Accelerateで学習ループを作成するときに実際に見ることができます。

```py
from transformers import Trainer, TrainingArguments

args = TrainingArguments(
    output_dir="codeparrot-ds",
    per_device_train_batch_size=32,
    per_device_eval_batch_size=32,
    evaluation_strategy="steps",
    eval_steps=5_000,
    logging_steps=5_000,
    gradient_accumulation_steps=8,
    num_train_epochs=1,
    weight_decay=0.1,
    warmup_steps=1_000,
    lr_scheduler_type="cosine",
    learning_rate=5e-4,
    save_steps=5_000,
    fp16=True,
    push_to_hub=True,
)

trainer = Trainer(
    model=model,
    tokenizer=tokenizer,
    args=args,
    data_collator=data_collator,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["valid"],
)
```

あとは `Trainer` を起動し、学習が終了するのを待つだけです。トレーニングセット全体かその一部分だけかにもよりますが、それぞれ20時間、2時間かかりますので、コーヒーでも飲んでお好きな本をゆっくり読んでください。

```py
trainer.train()
```

学習が完了したら、モデルとトークナイザーをHubにプッシュすることができます。

```py
trainer.push_to_hub()
```

{:else}

あとは学習用ハイパーパラメータを設定し、`compile()`と`fit()`を呼び出すだけです。ここでは、学習の安定性を向上させるために、ウォームアップを伴う学習率スケジュールを使用することにします。

```py
from transformers import create_optimizer
import tensorflow as tf

num_train_steps = len(tf_train_dataset)
optimizer, schedule = create_optimizer(
    init_lr=5e-5,
    num_warmup_steps=1_000,
    num_train_steps=num_train_steps,
    weight_decay_rate=0.01,
)
model.compile(optimizer=optimizer)

# Train in mixed-precision float16
tf.keras.mixed_precision.set_global_policy("mixed_float16")
```
あとは `model.fit()` を呼び出して、学習が終了するのを待つだけです。トレーニングセット全体かその一部分だけかにもよりますが、それぞれ20時間、2時間かかりますので、コーヒーでも飲みながらお好きな本を読んでゆっくり待ちましょう。学習が完了したら、モデルとトークナイザーをハブにプッシュします。

```py
from transformers.keras_callbacks import PushToHubCallback

callback = PushToHubCallback(output_dir="codeparrot-ds", tokenizer=tokenizer)

model.fit(tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback])
```

{/if}

<Tip>

✏️ **あなたの番です！** 生のテキストからGPT-2の学習まで、`TrainingArguments`に加えて、約30行のコードを作成するだけで済みました。あなた自身のデータセットで試してみて、良い結果が得られるかどうか確認してみてください! 

</Tip>

<Tip>

{#if fw === 'pt'}

💡 もし、複数のGPUを搭載したマシンを利用できるのであれば、そこでコードを実行してみてください。トレーナー`は自動的に複数のマシンを管理するため、学習速度が飛躍的に向上します。

{:else}

💡 もし、複数のGPUを搭載したマシンを利用できるのであれば、`MirroredStrategy`コンテキストを使って、学習を大幅にスピードアップさせることができます。そのためには `tf.distribute.MirroredStrategy` オブジェクトを作成し、 `to_tf_dataset` コマンド、モデルの作成、 `fit()` の呼び出しがすべて `scope()` コンテキストで実行されることを確認する必要があります。これに関するドキュメントは[こちら](https://www.tensorflow.org/guide/distributed_training#use_tfdistributestrategy_with_keras_modelfit)で見ることができます。

{/if}

</Tip>

## パイプラインによるコード生成

さて、いよいよ本番です！学習したモデルが実際にどの程度機能するのか見てみましょう。ログを見ると損失が着実に減っていることがわかりますが、モデルをテストするために、いくつかのプロンプトに対してどの程度効果があるのか見てみましょう。そのために、テキスト生成の `pipeline` でモデルをラップし、利用可能であれば高速に生成するために GPU に乗せることにします。

{#if fw === 'pt'}

```py
import torch
from transformers import pipeline

device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
pipe = pipeline(
    "text-generation", model="huggingface-course/codeparrot-ds", device=device
)
```

{:else}

```py
from transformers import pipeline

course_model = TFGPT2LMHeadModel.from_pretrained("huggingface-course/codeparrot-ds")
course_tokenizer = AutoTokenizer.from_pretrained("huggingface-course/codeparrot-ds")
pipe = pipeline(
    "text-generation", model=course_model, tokenizer=course_tokenizer, device=0
)
```

{/if}

まずは散布図を作るという簡単な作業から始めてみましょう。

```py
txt = """\
# create some data
x = np.random.randn(100)
y = np.random.randn(100)

# create scatter plot with x, y
"""
print(pipe(txt, num_return_sequences=1)[0]["generated_text"])
```

```python out
# create some data
x = np.random.randn(100)
y = np.random.randn(100)

# create scatter plot with x, y
plt.scatter(x, y)

# create scatter
```

結果は正しいようです。
これは `pandas` オペレーションでも動作するのでしょうか？2つの配列から `DataFrame` を作成できるかどうか見てみましょう。


```py
txt = """\
# create some data
x = np.random.randn(100)
y = np.random.randn(100)

# create dataframe from x and y
"""
print(pipe(txt, num_return_sequences=1)[0]["generated_text"])
```

```python out
# create some data
x = np.random.randn(100)
y = np.random.randn(100)

# create dataframe from x and y
df = pd.DataFrame({'x': x, 'y': y})
df.insert(0,'x', x)
for
```

いいねですね！それが正解です。

しかし、その後、列 `x` を再び挿入しています。生成されるトークンの数には限りがあるので、次の `for` ループは切り捨てられいます。
もう少し複雑なことをして、モデルに `groupby` 操作を使わせることができるか見てみましょう。

```py
txt = """\
# dataframe with profession, income and name
df = pd.DataFrame({'profession': x, 'income':y, 'name': z})

# calculate the mean income per profession
"""
print(pipe(txt, num_return_sequences=1)[0]["generated_text"])
```

```python out
# dataframe with profession, income and name
df = pd.DataFrame({'profession': x, 'income':y, 'name': z})

# calculate the mean income per profession
profession = df.groupby(['profession']).mean()

# compute the
```

悪くないですね。これは正しいやり方です。
最後に、`scikit-learn`にも使えるかどうか、Random Forestモデルを設定してみましょう。

```py
txt = """
# import random forest regressor from scikit-learn
from sklearn.ensemble import RandomForestRegressor

# fit random forest model with 300 estimators on X, y:
"""
print(pipe(txt, num_return_sequences=1)[0]["generated_text"])
```

```python out
# import random forest regressor from scikit-learn
from sklearn.ensemble import RandomForestRegressor

# fit random forest model with 300 estimators on X, y:
rf = RandomForestRegressor(n_estimators=300, random_state=random_state, max_depth=3)
rf.fit(X, y)
rf
```

{#if fw === 'tf'}

これらのいくつかの例を見ると、このモデルはPythonを使ったデータサイエンス関連の構文の一部を学習したようです。もちろん、このモデルを実世界に展開する前に、もっと徹底的に評価する必要がありますが、それでもこれは印象的なプロトタイプです。

{:else}

これらのいくつかの例を見ると、モデルはPythonデータサイエンス関連の構文の一部を学習したようです（もちろん、実世界にモデルを展開する前にもっと徹底的に評価する必要があるでしょう）。しかし、あるユースケースに必要なパフォーマンスを達成するために、モデルの学習をよりカスタマイズする必要がある場合もあります。例えば、バッチサイズを動的に更新したい場合や、適切でないサンプルをその場でスキップする条件付き学習ループを持ちたい場合はどうすればよいでしょうか。一つの選択肢は `Trainer` をサブクラス化して必要な変更を加えることですが、時には学習ループを一から書いた方がシンプルな場合もあります。そこで🤗 Accelerateの出番です。

{/if}

{#if fw === 'pt'}

## 🤗 Accelerate を使ったトレーニング

これまで `Trainer` を使ってモデルを学習する方法を見てきました。これはある程度カスタマイズすることができますが、時には学習ループを完全に制御したい場合や、派手な変更を加えたい場合があります。この場合、🤗 Accelerateは素晴らしい選択肢です。このセクションでは、それを使ってモデルを訓練する手順を説明します。さらに面白くするために、学習ループに一工夫してみましょう。

<Youtube id="Hm8_PgVTFuc"/>

私達は主にデータサイエンスライブラリの自動補完に興味があるので、これらのライブラリをより多く使用する学習サンプルに重きを置くことは理にかなっています。これらのサンプルは `plt`, `pd`, `sk`, `fit`, `predict` といったキーワードで簡単に識別できます。これらは `matplotlib.pyplot`, `pandas`, `sklearn` で最も頻繁に使用される import 名で、後者の fit/predict のパターンも同様です。これらをそれぞれ1つのトークンとして表現すれば、入力列の中にそれらがあるかどうかを簡単にチェックすることができます。トークンは半角スペースを前に持つことができるので、トークナイザーの語彙の中にそれらのがあるかどうかもチェックすることになります。動作確認のため、複数のトークンに分割されるはずのテストトークンを1つ追加してみます。

```py
keytoken_ids = []
for keyword in [
    "plt",
    "pd",
    "sk",
    "fit",
    "predict",
    " plt",
    " pd",
    " sk",
    " fit",
    " predict",
    "testtest",
]:
    ids = tokenizer([keyword]).input_ids[0]
    if len(ids) == 1:
        keytoken_ids.append(ids[0])
    else:
        print(f"Keyword has not single token: {keyword}")
```

```python out
'Keyword has not single token: testtest'
```

素晴らしい！うまくいったようですね。

入力シーケンス、ロジット、そして先ほど選択したキートークンを入力とするカスタム損失関数を書くことができます。まず、ロジットと入力の位置を合わせる必要があります。入力列を右に1つシフトしたものがラベルとなり、次のトークンが現在のトークンのラベルとなります。これは入力シーケンスの2番目のトークンからラベルを開始することで実現できます。なぜなら、モデルは最初のトークンに対していずれにしても予測を行わないからです。そして、最後のロジットを切り捨てます。なぜなら、全入力シーケンスの後には対応するラベルがないからです。これでサンプルごとの損失を計算し、各サンプルにおける全てのキーワードの出現をカウントすることができます。最後に、出現回数を重みとして、全サンプルの加重平均を計算します。キーワードを持たないサンプルを全て捨てたくないので、重みに1を加えます。

```py
from torch.nn import CrossEntropyLoss
import torch


def keytoken_weighted_loss(inputs, logits, keytoken_ids, alpha=1.0):
    # Shift so that tokens < n predict n
    shift_labels = inputs[..., 1:].contiguous()
    shift_logits = logits[..., :-1, :].contiguous()
    # Calculate per-token loss
    loss_fct = CrossEntropyLoss(reduce=False)
    loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
    # Resize and average loss per sample
    loss_per_sample = loss.view(shift_logits.size(0), shift_logits.size(1)).mean(axis=1)
    # Calculate and scale weighting
    weights = torch.stack([(inputs == kt).float() for kt in keytoken_ids]).sum(
        axis=[0, 2]
    )
    weights = alpha * (1.0 + weights)
    # Calculate weighted average
    weighted_loss = (loss_per_sample * weights).mean()
    return weighted_loss
```

この素晴らしい新しい損失関数を使った学習を始める前に、いくつかのことを準備する必要があります。

- データをロードしてバッチにするためのデータローダーが必要です。
- 重み減衰のパラメータを設定する必要があります。
- 時折、評価を行いたいので、評価コードを関数でラップするのは理にかなっています。

まずはデータローダーから始めましょう。
データセットのフォーマットを `"torch"` に設定するだけで、あとは適切なバッチサイズで PyTorch の `DataLoader` に渡せばいいのです。

```py
from torch.utils.data.dataloader import DataLoader

tokenized_dataset.set_format("torch")
train_dataloader = DataLoader(tokenized_dataset["train"], batch_size=32, shuffle=True)
eval_dataloader = DataLoader(tokenized_dataset["valid"], batch_size=32)
```

次に、パラメータをグループ化し、オプティマイザがどのパラメータが追加の重み減衰を得るかを知ることができるようにします。通常、すべてのバイアスとLayerNormの重み項は、この対象から除外されます。
以下のようになります。

```py
weight_decay = 0.1


def get_grouped_params(model, no_decay=["bias", "LayerNorm.weight"]):
    params_with_wd, params_without_wd = [], []
    for n, p in model.named_parameters():
        if any(nd in n for nd in no_decay):
            params_without_wd.append(p)
        else:
            params_with_wd.append(p)
    return [
        {"params": params_with_wd, "weight_decay": weight_decay},
        {"params": params_without_wd, "weight_decay": 0.0},
    ]
```

トレーニング中に定期的に検証セットでモデルを評価したいので、そのための関数も書いておきましょう。この関数は、評価用データローダを実行し、プロセス間の損失をすべて収集するだけです。

```py
def evaluate():
    model.eval()
    losses = []
    for step, batch in enumerate(eval_dataloader):
        with torch.no_grad():
            outputs = model(batch["input_ids"], labels=batch["input_ids"])

        losses.append(accelerator.gather(outputs.loss))
    loss = torch.mean(torch.cat(losses))
    try:
        perplexity = torch.exp(loss)
    except OverflowError:
        perplexity = float("inf")
    return loss.item(), perplexity.item()
```

`evaluate()`関数により、損失と[パープレキシティ](/course/ja/chapter7/3)を一定時間ごとに報告することができます。次に、もう一度ゼロから学習するために、モデルを再定義します。

```py
model = GPT2LMHeadModel(config)
```

次に、先ほどの関数を使って、重み減衰のパラメータを分割し、オプティマイザを定義します。

```py
from torch.optim import AdamW

optimizer = AdamW(get_grouped_params(model), lr=5e-4)
```

それでは、モデル、オプティマイザ、データローダを準備し、トレーニングを開始しましょう。

```py
from accelerate import Accelerator

accelerator = Accelerator(fp16=True)

model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare(
    model, optimizer, train_dataloader, eval_dataloader
)
```

<Tip>

🚨 TPUでトレーニングする場合は、上記のセルから始まるコードを全て専用のトレーニング関数に移動する必要があります。詳しくは[第3章](/course/ja/chapter3)を参照してください。

</Tip>

これで `train_dataloader` を `accelerator.prepare()` に送ったので、その長さを用いて学習ステップ数を計算することができます。このメソッドはデータローダーの長さを変更するので、常にデータローダーを準備した後に行う必要があることを忘れないでください。ここでは、学習率から0までの古典的な線形スケジュールを使用します。

```py
from transformers import get_scheduler

num_train_epochs = 1
num_update_steps_per_epoch = len(train_dataloader)
num_training_steps = num_train_epochs * num_update_steps_per_epoch

lr_scheduler = get_scheduler(
    name="linear",
    optimizer=optimizer,
    num_warmup_steps=1_000,
    num_training_steps=num_training_steps,
)
```

最後に、私たちのモデルをハブにプッシュするために、作業フォルダに `Repository` オブジェクトを作成する必要があります。まず、ハギング フェイス ハブ にログインしてください（まだログインしていない場合）。モデルに付与したいモデル ID からリポジトリ名を決定します（`repo_name` を自由に置き換えてください。これはユーザー名を含む必要があり、関数 `get_full_repo_name()` が行っている事です)。

```py
from huggingface_hub import Repository, get_full_repo_name

model_name = "codeparrot-ds-accelerate"
repo_name = get_full_repo_name(model_name)
repo_name
```

```python out
'sgugger/codeparrot-ds-accelerate'
```

そして、そのリポジトリをローカルフォルダーにクローンすることができます。すでに存在するのであれば、このローカルフォルダーは作業中のリポジトリの既存のクローンであるべきです。

```py
output_dir = "codeparrot-ds-accelerate"
repo = Repository(output_dir, clone_from=repo_name)
```

これで `repo.push_to_hub()` メソッドを呼び出すことで、`output_dir` に保存したものをアップロードできるようになりました。これにより、各エポック終了時に中間モデルをアップロードすることができます。

学習する前に、評価関数が正しく動作するかどうか、簡単なテストを実行してみましょう。

```py
evaluate()
```

```python out
(10.934126853942871, 56057.14453125)
```

損失とパープレキシティは非常に高い値ですが、まだモデルを訓練していないので驚くことではありません。これで、学習スクリプトの核となる部分、学習ループを書く準備が整いました。学習ループでは、データローダーを繰り返し処理し、そのバッチをモデルに渡します。ロジットを取得することで、独自の損失関数を評価することができます。損失は勾配累積のステップ数でスケーリングし、より多くのステップを集約する際に大きな損失が生じないようにします。また、最適化する前に、収束を良くするために勾配を切り取ります。最後に、数ステップごとに、新しい `evaluate()` 関数を用いて、評価セットでモデルを評価します。

```py
from tqdm.notebook import tqdm

gradient_accumulation_steps = 8
eval_steps = 5_000

model.train()
completed_steps = 0
for epoch in range(num_train_epochs):
    for step, batch in tqdm(
        enumerate(train_dataloader, start=1), total=num_training_steps
    ):
        logits = model(batch["input_ids"]).logits
        loss = keytoken_weighted_loss(batch["input_ids"], logits, keytoken_ids)
        if step % 100 == 0:
            accelerator.print(
                {
                    "lr": get_lr(),
                    "samples": step * samples_per_step,
                    "steps": completed_steps,
                    "loss/train": loss.item() * gradient_accumulation_steps,
                }
            )
        loss = loss / gradient_accumulation_steps
        accelerator.backward(loss)
        if step % gradient_accumulation_steps == 0:
            accelerator.clip_grad_norm_(model.parameters(), 1.0)
            optimizer.step()
            lr_scheduler.step()
            optimizer.zero_grad()
            completed_steps += 1
        if (step % (eval_steps * gradient_accumulation_steps)) == 0:
            eval_loss, perplexity = evaluate()
            accelerator.print({"loss/eval": eval_loss, "perplexity": perplexity})
            model.train()
            accelerator.wait_for_everyone()
            unwrapped_model = accelerator.unwrap_model(model)
            unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save)
            if accelerator.is_main_process:
                tokenizer.save_pretrained(output_dir)
                repo.push_to_hub(
                    commit_message=f"Training in progress step {step}", blocking=False
                )
```

これで完了です。
貴方はGPT-2のような因果言語モデルのためのカスタム学習ループを作成できるようになり、更にニーズに合わせてカスタマイズすることができます。

<Tip>
✏️ **あなたの番です！** 用途に合わせた独自の損失関数を作成するか、トレーニングループに別のカスタムステップを追加してみましょう。
</Tip>

<Tip>

✏️ **あなたの番です！** 長時間に及ぶ学習実験を行う場合、TensorBoardやWeights & Biasesなどのツールを使って重要な指標を記録しておくとよいでしょう。学習ループに適切なログを追加することで、学習がどのように進んでいるかを常に確認することができます。

</Tip>

{/if}

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter7/6.mdx" />

### NLPをマスター
https://huggingface.co/learn/course/ja/chapter7/8.md

# NLPをマスター

<CourseFloatingBanner
    chapter={7}
    classNames="absolute z-10 right-0 top-0"
/>

このコースでここまで進んだなら、おめでとうございます！
あなたは今、🤗トランスフォーマーとハギング フェイス エコシステムを使って（ほとんど）どんなNLPタスクにも取り組むために必要なすべての知識とツールを手にしています。

様々なデータコレーターを見てきましたので、各タスクにどのコレーターを使えばいいのかがわかるように、この小さなビデオを作りました。

<Youtube id="-RPeakdlHYo"/>

このライトニング・ツアーでNLPの主要タスクを学んだ後、次のことを行ってください。
* 各タスクに最適なアーキテクチャ（エンコーダ、デコーダ、またはエンコーダ-デコーダ）を把握する
* 言語モデルの事前トレーニングと微調整の違いを理解する
* フォローしているトラックに応じて、TrainerAPIと分散トレーニング機能の🤗AccelerateまたはTensorFlowとKerasのいずれかを使用してTransformerモデルをトレーニング
する方法を知る
* テキスト生成タスクのROUGEやBLEUなどの指標の意味と制限を理解する
* ハブを使用する場合と🤗Transformersのパイプラインの使用する場合の両方で、微調整されたモデルを使う方法を知る

このすべての知識にもかかわらず、コードで難しいバグに遭遇したり、特定のNLP問題を解決する方法について質問したりするときが来るでしょう。 幸いなことに、ハギング
 フェイスコミュニティがお手伝いします。 コースのこの部分の最後の章では、Transformerモデルをデバッグし、効果的に支援を求める方法を探ります。

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter7/8.mdx" />

### 翻訳
https://huggingface.co/learn/course/ja/chapter7/4.md

# 翻訳

{#if fw === 'pt'}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section4_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section4_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section4_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section4_tf.ipynb"},
]} />

{/if}

では、翻訳タスクに飛び込んでみましょう。これも[シーケンス間タスク](/course/chapter1/ja/7)で、ある配列から別の配列へという定式化が可能な問題ということです。その意味では、この問題は[要約](/course/chapter7/ja/6)にかなり近く、今回得る知識は、以下のような他のシーケンス間問題に適応させることができます。

- **スタイル転送**: あるスタイルで書かれた文章を別のスタイルに*翻訳*するモデルの作成(例：フォーマルな文章からカジュアルな文章、シェイクスピア英語から現代英語など）

- **質問応答生成**: 与えられた文脈に沿って、質問に対する答えを生成するモデルを作成する。

<Youtube id="1JvfrvZgi6c"/>

2言語（またはそれ以上）のテキストの十分な大きさのコーパスがあれば、[因果言語モデリング](/course/chapter7/ja/6)で説明するように、新しい翻訳モデルをゼロから学習させることができます。しかし、mT5やmBARTのような多言語翻訳モデルを特定の言語ペアに合うように微調整したり、ある言語から別の言語への翻訳に特化したモデルを特定のコーパスに合うように微調整する方が、より速く翻訳モデルを作成できます。

このセクションでは、（多くのHugging Face社員は両方の言語を話すため）英語からフランス語に翻訳するように事前に学習したMarianモデルを、[KDE4データセット](https://huggingface.co/datasets/kde4)で微調整します。このデータセットは [KDE apps](https://apps.kde.org/) のローカライズファイルのデータセットです。

私たちが使うモデルは、実際にKDE4データセットを含む[Opus dataset](https://opus.nlpl.eu/) から取得したフランス語と英語のテキストの大規模なコーパスで事前学習されています。しかし、私たちが使う事前学習済みモデルは、事前学習中にそのデータを見ていたとしても、微調整の後、より良いバージョンを得ることができることが分かるでしょう。

これが終われば、以下のような予測が可能なモデルが完成します。

<iframe src="https://course-demos-marian-finetuned-kde4-en-to-fr.hf.space" frameBorder="0" height="350" title="Gradio app" class="block dark:hidden container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

<a class="flex justify-center" href="/huggingface-course/marian-finetuned-kde4-en-to-fr">
<img class="block dark:hidden lg:w-3/5" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/modeleval-marian-finetuned-kde4-en-to-fr.png" alt="One-hot encoded labels for question answering."/>
<img class="hidden dark:block lg:w-3/5" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/modeleval-marian-finetuned-kde4-en-to-fr-dark.png" alt="One-hot encoded labels for question answering."/>
</a>

前のセクションと同様に、以下のコードで学習してハブにアップロードする実際のモデルを[ここ](https://huggingface.co/huggingface-course/marian-finetuned-kde4-en-to-fr?text=This+plugin+allows+you+to+automatically+translate+web+pages+between+several+languages.)で見つけ、その予測結果をダブルチェックする事ができます。

## データの準備

翻訳モデルをゼロから調整・学習するためには、そのタスクに適したデータセットが必要です。前述したように、このセクションでは [KDE4 dataset](https://huggingface.co/datasets/kde4) を使用しますが、翻訳したい2つの言語の文のペアがあれば、自分のデータを使用するようにコードを適応させることは非常に簡単です。カスタムデータを `Dataset` にロードする方法を思い出したい場合は、[5章](/course/ja/chapter5) を参照してください。

### KDE4データセット

いつものように、 `load_dataset()` 関数を使用してデータセットをダウンロードします。

```py
from datasets import load_dataset

raw_datasets = load_dataset("kde4", lang1="en", lang2="fr")
```

異なる言語のペアを扱いたい場合は、そのコードで指定することができます。このデータセットでは、全部で92の言語が利用できます。その[データセットカード](https://huggingface.co/datasets/kde4)の言語タグを展開すると、すべての言語を見ることができます。

<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/language_tags.png" alt="Language available for the KDE4 dataset." width="100%">

それでは、データセットを見てみましょう。

```py
raw_datasets
```

```python out
DatasetDict({
    train: Dataset({
        features: ['id', 'translation'],
        num_rows: 210173
    })
})
```

210,173組の文がありますが、1回の分割で、独自の検証セットを作成する必要があります。[第5章](/course/ja/chapter5) で見たように、 `Dataset` には `train_test_split()` メソッドがあり、これを利用して検証セットの作成を行うことができます。再現性を高めるためにシードを用意します。

```py
split_datasets = raw_datasets["train"].train_test_split(train_size=0.9, seed=20)
split_datasets
```

```python out
DatasetDict({
    train: Dataset({
        features: ['id', 'translation'],
        num_rows: 189155
    })
    test: Dataset({
        features: ['id', 'translation'],
        num_rows: 21018
    })
})
```
以下のように `"test"` キーを `"validation"` に変更することができます。

```py
split_datasets["validation"] = split_datasets.pop("test")
```

では、データセットの1つの要素を見てみましょう。

```py
split_datasets["train"][1]["translation"]
```

```python out
{'en': 'Default to expanded threads',
 'fr': 'Par défaut, développer les fils de discussion'}
```

必要な言語のペアで構成される2つの文の辞書を得ることができました。コンピュータサイエンスの専門用語を集めたこのデータセットの特殊性は、すべてフランス語で完全に翻訳されていることです。しかし、フランスのエンジニアは怠惰なので、コンピュータサイエンス特有の単語はほとんど英語単語のままで会話していることが多いです。例えば、"threads "という単語は、フランス語の文章、特に技術的な会話ではよく出てきますが、このデータセットでは、より正しい "fils de discussion "に翻訳しています。
しかし、このモデルは、より大きなフランス語と英語のコーパスで事前学習されているので、この単語をそのままにしておくという簡単な選択肢をとっています。

```py
from transformers import pipeline

model_checkpoint = "Helsinki-NLP/opus-mt-en-fr"
translator = pipeline("translation", model=model_checkpoint)
translator("Default to expanded threads")
```

```python out
[{'translation_text': 'Par défaut pour les threads élargis'}]
```

この動作のもう一つの例は、「plugin」という単語で見ることができます。これは正式なフランス語の単語ではありませんが、ほとんどのフランス語を母国語とする人が理解でき、わざわざ翻訳する必要はありません。
KDE4データセットでは、この単語はより正式な「module d'extension」とフランス語で翻訳されています。

```py
split_datasets["train"][172]["translation"]
```

```python out
{'en': 'Unable to import %1 using the OFX importer plugin. This file is not the correct format.',
 'fr': "Impossible d'importer %1 en utilisant le module d'extension d'importation OFX. Ce fichier n'a pas un format correct."}
```

しかし、私達の事前学習済みモデルは、コンパクトで親しみやすい英単語に固執します。

```py
translator(
    "Unable to import %1 using the OFX importer plugin. This file is not the correct format."
)
```

```python out
[{'translation_text': "Impossible d'importer %1 en utilisant le plugin d'importateur OFX. Ce fichier n'est pas le bon format."}]
```

このようなデータセットの特殊性を、微調整したモデルが拾い上げてくれるかどうか、興味深いところです。(ネタバレ注意：拾ってくれます)

<Youtube id="0Oxphw4Q9fo"/>

<Tip>

✏️ **あなたの番です！** フランス語でよく使われるもう1つの英単語は "email "です。学習データセットから、この単語を使った最初のサンプルを見つけてください。どのように翻訳されますか？同じ英文を学習済みモデルはどのように翻訳しているでしょうか？

</Tip>

### データを加工する

<Youtube id="XAR8jnZZuUs"/>

もうお分かりだと思いますが、テキストを全てトークンIDのセットに変換し、モデルが意味を理解できるようにする必要があります。このタスクのために、入力とターゲットの両方をトークン化する必要があります。最初のタスクは `tokenizer` オブジェクトを作成することです。

先に述べたように、今回は英語からフランス語に翻訳するように事前学習したMarianモデルを使用します。もしこのコードを他の言語のペアで試す場合は、モデルのチェックポイントを適応させてください。[Helsinki-NLP](https://huggingface.co/Helsinki-NLP) という組織が多言語で1000以上のモデルを提供しています。

```python
from transformers import AutoTokenizer

model_checkpoint = "Helsinki-NLP/opus-mt-en-fr"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint, return_tensors="tf")
```

また、`model_checkpoint` を [Hub](https://huggingface.co/models) にある好きなモデルや、事前学習したモデルやトークナイザーを保存したローカルフォルダに置き換えることができます。

<Tip>

💡 mBART、mBART-50、M2M100 などの多言語トークナイザーを使用している場合は、トークナイザーの `tokenizer.src_lang` と `tokenizer.tgt_lang` に入力元となる言語とターゲットとなる言語の正しい言語コード値を設定する必要があります。

</Tip>

データの準備はとても簡単です。入力言語は通常通り処理しますが、ターゲット言語についてはトークナイザーをコンテキストマネージャー `as_target_tokenizer()` の中にラップする必要があります。

Python のコンテキストマネージャーは `with` 文で導入され、2つの関連する操作をペアで実行するときに便利です。最も一般的な例は、ファイルを書き込んだり読み込んだりするときで、次のような命令の内部で実行されることがよくあります。

```
with open(file_path) as f:
    content = f.read()
```

上の例では、関連する2つの操作をペアとして実行することで、ファイルを開く動作と閉じる動作を実現しています。オープンされたファイル `f` に対応するオブジェクトは、 `with` の下にあるインデントされたブロックの中にのみ存在し、ファイルのオープンはそのブロックの前に、フェイルのクローズはブロックの最後に行われます。

私達のケースでは、コンテキストマネージャー `as_target_tokenizer()` は、インデントされたブロックが実行される前にトークナイザーを出力言語 (ここではフランス語) に設定し、その後、入力言語 (ここでは英語) に設定しなおします。

つまり、サンプルの前処理は次のようになります。

```python
en_sentence = split_datasets["train"][1]["translation"]["en"]
fr_sentence = split_datasets["train"][1]["translation"]["fr"]

inputs = tokenizer(en_sentence)
with tokenizer.as_target_tokenizer():
    targets = tokenizer(fr_sentence)
```

もし、コンテキスト・マネージャの内部でターゲット言語をトークン化する処理を忘れると、入力トークナイザーによってトークン化されてしまい、Marian モデルの場合、全くうまくいきません。

```python
wrong_targets = tokenizer(fr_sentence)
print(tokenizer.convert_ids_to_tokens(wrong_targets["input_ids"]))
print(tokenizer.convert_ids_to_tokens(targets["input_ids"]))
```

```python out
['▁Par', '▁dé', 'f', 'aut', ',', '▁dé', 've', 'lop', 'per', '▁les', '▁fil', 's', '▁de', '▁discussion', '</s>']
['▁Par', '▁défaut', ',', '▁développer', '▁les', '▁fils', '▁de', '▁discussion', '</s>']
```

このように、英語用のトークナイザーを使ってフランス語の文章を前処理すると、トークンの数が多くなります。トークナイザーはフランス語の単語を知らないからです（「discussion」のように英語と共通する単語は除きます）。

`inputs`と`targets`はどちらも通常のキー（入力ID、アテンションマスクなど）を持つ辞書なので、最後のステップは入力の中に `"labels"` キーを設定することです。これはデータセットに適用する前処理関数で行います。

```python
max_input_length = 128
max_target_length = 128


def preprocess_function(examples):
    inputs = [ex["en"] for ex in examples["translation"]]
    targets = [ex["fr"] for ex in examples["translation"]]
    model_inputs = tokenizer(inputs, max_length=max_input_length, truncation=True)

    # Set up the tokenizer for targets
    with tokenizer.as_target_tokenizer():
        labels = tokenizer(targets, max_length=max_target_length, truncation=True)

    model_inputs["labels"] = labels["input_ids"]
    return model_inputs
```

入力と出力に同様な最大長を設定していることに注意してください。扱うテキストはかなり短いと思われるので、128を使用しています。

<Tip>

💡 T5モデル（具体的には `t5-xxx` チェックポイントの1つ）を使用している場合、モデルはテキスト入力にタスクを示すプレフィックス、例えば `translate: English to French:` のような、タスクを示す接頭辞を持つテキスト入力であることを期待します。

</Tip>

<Tip warning={true}>

⚠️私達はターゲット文のアテンションマスクはモデルが期待していないので、注意を払っていません。その代わり、パディングトークンに対応するラベルに`-100`に設定し、損失計算で無視されるようにします。私達は動的パディングを使用するのでこの処理は後でデータコレーターが行います。しかし、ここでパディングを使用する場合は、パディングトークンに対応する全てのラベルを`-100`に設定するように前処理関数を適応させる必要があります。

</Tip>

これで、データセットのすべての分割に対して、この前処理を一度に適用することができるようになりました。

```py
tokenized_datasets = split_datasets.map(
    preprocess_function,
    batched=True,
    remove_columns=split_datasets["train"].column_names,
)
```

データの前処理が終わったので、次は学習済みモデルの微調整を行います！

{#if fw === 'pt'}

## Trainer API を用いてモデルを微調整する


実際に `Trainer` を使用するコードは、これまでと同じですが、1つだけ少し変更点があります。
ここでは [`Seq2SeqTrainer`](https://huggingface.co/transformers/main_classes/trainer.html#seq2seqtrainer) を使用します。
これは `Trainer` のサブクラスであり、評価を適切に処理するためで、`generate()` メソッドを使用して入力から出力を予測します。詳細は、指標計算の話をするときに詳しく掘り下げます。

まず最初に、微調整を行うための実際のモデルが必要です。ここでは、通常の `AutoModel` API を使用します。

```py
from transformers import AutoModelForSeq2SeqLM

model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint)
```

{:else}

## Kerasを使ったモデルの微調整

まず最初に、微調整を行うための実際のモデルが必要です。ここでは、通常の `AutoModel` API を使用します。

```py
from transformers import TFAutoModelForSeq2SeqLM

model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint, from_pt=True)
```

<Tip warning={false}>

💡 `Helsinki-NLP/opus-mt-en-fr`のチェックポイントにはPyTorch用の重みしかありません。
`from_pretrained()` メソッドで `from_pt=True` という引数を指定せずにモデルをロードしようとするとエラーが発生します。

`from_pt=True` を指定すると、ライブラリはPyTorch の重みを自動的にダウンロードし、変換します。
このように、🤗 Transformersではフレームワークの切り替えが非常に簡単です！

</Tip>

{/if}

なお、今回は翻訳タスクで学習したモデルを使用しており、実際にすでに使用することができますので、重みの欠落や新たに初期化されたものについての警告は出ていません。

### データの照合

動的バッチ処理用のパディングを行うために、データコレーターが必要になります。この場合、[第3章](/course/ja/chapter3) のような `DataCollatorWithPadding` を使うわけにはいきません。

なぜなら、それは入力（入力ID、アテンションマスク、トークンタイプID）だけをパディングするものだからです。私たちのラベルも、ラベルで遭遇する最大長にパディングされるべきです。そして、前述したように、これらのパディングされた値が損失計算で無視されるように、ラベルをパディングするために使用されるパディング値は、トークナイザーのパディングトークンではなく、`-100`であるべきです。

これはすべて [`DataCollatorForSeq2Seq`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorforseq2seq) によって行われます。`DataCollatorWithPadding` と同様に、入力の前処理に使用した `tokenizer` を受け取りますが、 `model` も受け取ります。これは、このデータコレーターがデコーダーの入力 ID を準備する役割も担うからです。この ID は、ラベルをシフトしたもので、先頭に特別なトークンが付加されています。このシフトはアーキテクチャによって若干異なるので、 `DataCollatorForSeq2Seq` は `model` オブジェクトを知っている必要があります。

{#if fw === 'pt'}

```py
from transformers import DataCollatorForSeq2Seq

data_collator = DataCollatorForSeq2Seq(tokenizer, model=model)
```

{:else}

```py
from transformers import DataCollatorForSeq2Seq

data_collator = DataCollatorForSeq2Seq(tokenizer, model=model, return_tensors="tf")
```

{/if}

いくつかのサンプルでこれをテストする場合、トークナイザーのトレーニングセットから取得したサンプルのリストに対して呼び出すだけです。

```py
batch = data_collator([tokenized_datasets["train"][i] for i in range(1, 3)])
batch.keys()
```

```python out
dict_keys(['attention_mask', 'input_ids', 'labels', 'decoder_input_ids'])
```

ラベルがバッチの最大長になるように`-100` を使ってパディングされたことを確認できます。

```py
batch["labels"]
```

```python out
tensor([[  577,  5891,     2,  3184,    16,  2542,     5,  1710,     0,  -100,
          -100,  -100,  -100,  -100,  -100,  -100],
        [ 1211,     3,    49,  9409,  1211,     3, 29140,   817,  3124,   817,
           550,  7032,  5821,  7907, 12649,     0]])
```

また、デコーダーの入力IDを見ると、ラベルをシフトさせたものであることがわかります。

```py
batch["decoder_input_ids"]
```

```python out
tensor([[59513,   577,  5891,     2,  3184,    16,  2542,     5,  1710,     0,
         59513, 59513, 59513, 59513, 59513, 59513],
        [59513,  1211,     3,    49,  9409,  1211,     3, 29140,   817,  3124,
           817,   550,  7032,  5821,  7907, 12649]])
```

以下は、データセットの1番目と2番目の要素に対するラベルです。

```py
for i in range(1, 3):
    print(tokenized_datasets["train"][i]["labels"])
```

```python out
[577, 5891, 2, 3184, 16, 2542, 5, 1710, 0]
[1211, 3, 49, 9409, 1211, 3, 29140, 817, 3124, 817, 550, 7032, 5821, 7907, 12649, 0]
```

{#if fw === 'pt'}

この `data_collator` を `Seq2SeqTrainer` に渡します。次に、指標を見てみましょう。

{:else}

この `data_collator` を使って、各データセットを `tf.data.Dataset` に変換し、学習できるようにします。

```python
tf_train_dataset = tokenized_datasets["train"].to_tf_dataset(
    columns=["input_ids", "attention_mask", "labels"],
    collate_fn=data_collator,
    shuffle=True,
    batch_size=32,
)
tf_eval_dataset = tokenized_datasets["validation"].to_tf_dataset(
    columns=["input_ids", "attention_mask", "labels"],
    collate_fn=data_collator,
    shuffle=False,
    batch_size=16,
)
```

{/if}


### 指標

<Youtube id="M05L1DhFqcw"/>

{#if fw === 'pt'}

`Seq2SeqTrainer` がスーパークラス `Trainer` に追加した機能は、評価や予測の際に `generate()` メソッドを使用することです。学習時には、モデルは `decoder_input_ids` を使用し、予測しようとするトークンの後ろのトークンを使用しないようにアテンションマスクをして、学習を高速化することができます。推論実行時には同様にこれらを使用することはできませんので、同じ設定でモデルを評価するのは良いアイデアです。

[第1章](/course/ja/chapter1/6) で見たように、デコーダはトークンを1つずつ予測して推論を行います。🤗 Transformersでは `generate()` メソッドが裏で動いています。`Seq2SeqTrainer` では、 `predict_with_generate=True` を設定すると、この手法を使って評価を行うことができるようになります。

{/if}

翻訳に使われる伝統的な指標は、[BLEU score](https://en.wikipedia.org/wiki/BLEU) です。これはKishore Papineniらによって、[a 2002 article](https://aclanthology.org/P02-1040.pdf) で紹介された指標で、翻訳文がそのラベルにどれだけ近いかを評価するものです。

モデルの生成した出力文の明瞭度や文法的な正しさは測定しませんが、生成した出力に含まれるすべての単語がターゲットにも現れるように、統計的なルールを使用します。また、同じ単語の繰り返しが元文章にない場合はペナルティを与えるルール（モデルが「the the the the」のような文章を出力しないように）や、ターゲットより短い文章を出力するとペナルティを与えるルール（モデルが「the」のような文章を出力しないように）などがあります。

BLEUの弱点は、テキストがすでにトークン化されていることを前提としているため、異なるトークナイザーを使用するモデル間でスコアを比較することが困難な点です。そこで、現在翻訳モデルのベンチマークとして最もよく使われているのが[SacreBLEU](https://github.com/mjpost/sacrebleu)です。トークン化ステップを標準化することで、この弱点（およびその他の弱点）を解決しています。この指標を使うには、まずSacreBLEUライブラリをインストールする必要があります。

```py
!pip install sacrebleu
```

そして、[第3章](/course/ja/chapter3) で行ったように `evaluate.load()` で読み込むことができるようになります。

```py
import evaluate

metric = evaluate.load("sacrebleu")
```

この指標はテキストを入力とターゲットとして受け取ります。同じ文でも複数の翻訳があることが多いので、複数の翻訳を受け入れるように設計されています。私たちが使っているデータセットは1つしか提供していませんが、NLPでは複数の文をラベルとして与えるデータセットが珍しくありません。つまり、予測は文のリストであるべきですが、その参照は文のリストのリストであるべきなのです。

例をやってみましょう。

```py
predictions = [
    "This plugin lets you translate web pages between several languages automatically."
]
references = [
    [
        "This plugin allows you to automatically translate web pages between several languages."
    ]
]
metric.compute(predictions=predictions, references=references)
```

```python out
{'score': 46.750469682990165,
 'counts': [11, 6, 4, 3],
 'totals': [12, 11, 10, 9],
 'precisions': [91.67, 54.54, 40.0, 33.33],
 'bp': 0.9200444146293233,
 'sys_len': 12,
 'ref_len': 13}
```

この結果、BLEUスコアは46.75となりました。これはかなり良い結果です。

参考までに、["Attention Is All You Need" 論文](https://arxiv.org/pdf/1706.03762.pdf) のオリジナルのTransformerモデルは、英語とフランス語間の同様の翻訳タスクでBLEUスコア41.8を達成しました！（`count`や`bp`などの個々の指標の詳細は[SacreBLEUリポジトリ](https://github.com/mjpost/sacrebleu/blob/078c440168c6adc89ba75fe6d63f0d922d42bcfe/sacrebleu/metrics/bleu.py#L74)を参照してください)。

一方、翻訳モデルからよく出てくる2つの悪いタイプの予測（単語の繰り返しが多い、または短すぎる）で試すと、かなり悪いBLEUスコアが得られます。

```py
predictions = ["This This This This"]
references = [
    [
        "This plugin allows you to automatically translate web pages between several languages."
    ]
]
metric.compute(predictions=predictions, references=references)
```

```python out
{'score': 1.683602693167689,
 'counts': [1, 0, 0, 0],
 'totals': [4, 3, 2, 1],
 'precisions': [25.0, 16.67, 12.5, 12.5],
 'bp': 0.10539922456186433,
 'sys_len': 4,
 'ref_len': 13}
```

```py
predictions = ["This plugin"]
references = [
    [
        "This plugin allows you to automatically translate web pages between several languages."
    ]
]
metric.compute(predictions=predictions, references=references)
```

```python out
{'score': 0.0,
 'counts': [2, 1, 0, 0],
 'totals': [2, 1, 0, 0],
 'precisions': [100.0, 100.0, 0.0, 0.0],
 'bp': 0.004086771438464067,
 'sys_len': 2,
 'ref_len': 13}
```

スコアは0から100まであり、高ければ高いほど良いスコアです。

{#if fw === 'tf'}

モデルの出力を指標が使用できるテキストに変換するために、 `tokenizer.batch_decode()` メソッドを使用します。ラベルに含まれる `-100` をすべて削除する必要があります。トークナイザーはパディングトークンに対しても自動的に同じ処理を行います。

モデルとデータセットを受け取り、それに対して指標を計算する関数を定義しましょう。長いシーケンスの生成には時間がかかるので、検証セットをサブサンプリングして、時間がかからないようにします。

```py
import numpy as np


def compute_metrics():
    all_preds = []
    all_labels = []
    sampled_dataset = tokenized_datasets["validation"].shuffle().select(range(200))
    tf_generate_dataset = sampled_dataset.to_tf_dataset(
        columns=["input_ids", "attention_mask", "labels"],
        collate_fn=data_collator,
        shuffle=False,
        batch_size=4,
    )
    for batch in tf_generate_dataset:
        predictions = model.generate(
            input_ids=batch["input_ids"], attention_mask=batch["attention_mask"]
        )
        decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True)
        labels = batch["labels"].numpy()
        labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
        decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)
        decoded_preds = [pred.strip() for pred in decoded_preds]
        decoded_labels = [[label.strip()] for label in decoded_labels]
        all_preds.extend(decoded_preds)
        all_labels.extend(decoded_labels)

    result = metric.compute(predictions=all_preds, references=all_labels)
    return {"bleu": result["score"]}
```

{:else}

モデルの出力を指標が使用できるテキストに変換するために、 `tokenizer.batch_decode()` メソッドを使用することにします。ラベルに含まれるすべての `-100` をクリーンアップする必要があります。（トークンナイザーはパディングトークンに対して自動的に同じことを行います）

```py
import numpy as np


def compute_metrics(eval_preds):
    preds, labels = eval_preds
    # In case the model returns more than the prediction logits
    if isinstance(preds, tuple):
        preds = preds[0]

    decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True)

    # Replace -100s in the labels as we can't decode them
    labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
    decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)

    # Some simple post-processing
    decoded_preds = [pred.strip() for pred in decoded_preds]
    decoded_labels = [[label.strip()] for label in decoded_labels]

    result = metric.compute(predictions=decoded_preds, references=decoded_labels)
    return {"bleu": result["score"]}
```

{/if}

これで、モデルを微調整する準備が整いました！

### モデルの微調整

最初のステップは、ハギング フェイスにログインして、結果をModel Hubにアップロードすることです。そのための便利な機能がノートブックにあります。

```python
from huggingface_hub import notebook_login

notebook_login()
```

これは、ハギング フェイスのログイン情報を入力するウィジェットが表示されます。
ノートブックで作業していない場合は、ターミナルで次の行を入力するだけです。

```bash
huggingface-cli login
```

{#if fw === 'tf'}

その前に、何も学習していないモデルでどのような結果が得られるか見てみましょう。

```py
print(compute_metrics())
```

```
{'bleu': 33.26983701454733}
```

これが完了すると、モデルをコンパイルして学習するために必要なものをすべて準備することができます。

tf.keras.mixed_precision.set_global_policy("mixed_float16")` を使用していることに注意してください。これは、Kerasにfloat16を使用して学習するように指示します。これは、それをサポートするGPU（Nvidia RTX 20xx/V100またはそれ以降）で大幅なスピードアップを得ることができます。

```python
from transformers import create_optimizer
from transformers.keras_callbacks import PushToHubCallback
import tensorflow as tf

# The number of training steps is the number of samples in the dataset, divided by the batch size then multiplied
# by the total number of epochs. Note that the tf_train_dataset here is a batched tf.data.Dataset,
# not the original Hugging Face Dataset, so its len() is already num_samples // batch_size.
num_epochs = 3
num_train_steps = len(tf_train_dataset) * num_epochs

optimizer, schedule = create_optimizer(
    init_lr=5e-5,
    num_warmup_steps=0,
    num_train_steps=num_train_steps,
    weight_decay_rate=0.01,
)
model.compile(optimizer=optimizer)

# Train in mixed-precision float16
tf.keras.mixed_precision.set_global_policy("mixed_float16")
```

次に、[セクション2](/course/ja/chapter7/2)で見たように、学習中にモデルをHubにアップロードするための`PushToHubCallback`を定義し、そのコールバックとしモデルを単純にフィトするようにします。

```python
from transformers.keras_callbacks import PushToHubCallback

callback = PushToHubCallback(
    output_dir="marian-finetuned-kde4-en-to-fr", tokenizer=tokenizer
)

model.fit(
    tf_train_dataset,
    validation_data=tf_eval_dataset,
    callbacks=[callback],
    epochs=num_epochs,
)
```

なお、`hub_model_id` 引数でプッシュ先のリポジトリ名を指定することができます。(特に、組織にプッシュする場合はこの引数を使用する必要があります)。例えば、モデルを [`huggingface-course` organization](https://huggingface.co/huggingface-course) にプッシュする場合、`Seq2SeqTrainingArguments` に `hub_model_id="huggingface-course/marian-finetuned-kde4-en-to-fr"` を追加しています。

デフォルトでは、使用するリポジトリはあなたの名前空間内にあり、設定した出力ディレクトリの名前になります。ここでは `"sgugger/marian-finetuned-kde4-en-to-fr"` (このセクションの最初にリンクしたモデルです)となります。

<Tip>

💡 使用している出力ディレクトリがすでに存在する場合、プッシュしたいリポジトリのローカルクローンである必要があります。そうでない場合は、`model.fit()` を呼び出すときにエラーが発生するので、新しい名前を設定する必要があります。

</Tip>

最後に、トレーニングが終了した後の指標を見てみましょう。

```py
print(compute_metrics())
```

```
{'bleu': 57.334066271545865}
```

この段階で、モデルハブ上の推論ウィジェットを使って、モデルをテストしたり、友人と共有したりすることができます。これで、翻訳タスクのモデルの微調整が完了です。

おめでとうございます！

{:else}

これが完了したら、`Seq2SeqTrainingArguments` を定義することができます。`Trainer` と同様に、いくつかのフィールドを含む `TrainingArguments` のサブクラスを使用します。

```python
from transformers import Seq2SeqTrainingArguments

args = Seq2SeqTrainingArguments(
    f"marian-finetuned-kde4-en-to-fr",
    evaluation_strategy="no",
    save_strategy="epoch",
    learning_rate=2e-5,
    per_device_train_batch_size=32,
    per_device_eval_batch_size=64,
    weight_decay=0.01,
    save_total_limit=3,
    num_train_epochs=3,
    predict_with_generate=True,
    fp16=True,
    push_to_hub=True,
)
```

通常のハイパーパラメータ（学習率、エポック数、バッチサイズ、重み減衰など）とは別に、前のセクションで見たものと比較して、いくつかの変更点があります。

- 評価には時間がかかるので、定期的な評価は設定しません。学習前と学習後に一度だけモデルを評価します。
- fp16=True` を設定し、最新の GPU を使っている際に学習を高速化しました。
- 前述したように predict_with_generate=True` を設定します。
- 各エポック終了時にモデルをハブにアップロードするために、`push_to_hub=True`を使用します。

なお、 `hub_model_id` 引数には、プッシュしたいリポジトリのフルネームを指定できます。(特に、組織にプッシュする場合は、この引数を使用する必要があります)。例えば、モデルを [`huggingface-course` organization`](https://huggingface.co/huggingface-course) にプッシュする場合、`Seq2SeqTrainingArguments` に `hub_model_id="huggingface-course/marian-finetuned-kde4-en-to-fr"` を追加しています。デフォルトでは、使用するリポジトリはあなたの名前空間内にあり、設定した出力ディレクトリにちなんだ名前になります。
この例では `"sgugger/marian-finetuned-kde4-en-to-fr"` となります。(このセクションの冒頭でリンクしたモデルです)

<Tip>

💡 出力先ディレクトリがすでに存在する場合は、プッシュしたいリポジトリのローカルクローンである必要があります。そうでない場合は、`Seq2SeqTrainer` を定義するときにエラーが発生するので、新しい名前を設定する必要があります。

</Tip>

最後に、すべてを `Seq2SeqTrainer` に渡すだけです。

```python
from transformers import Seq2SeqTrainer

trainer = Seq2SeqTrainer(
    model,
    args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    tokenizer=tokenizer,
    compute_metrics=compute_metrics,
)
```

学習する前に、まずモデルが獲得するスコアを確認し、微調整によって事態を悪化させていないか再確認します。このコマンドは少し時間がかかるので、実行中にコーヒーを飲むとよいでしょう。

```python
trainer.evaluate(max_length=max_target_length)
```

```python out
{'eval_loss': 1.6964408159255981,
 'eval_bleu': 39.26865061007616,
 'eval_runtime': 965.8884,
 'eval_samples_per_second': 21.76,
 'eval_steps_per_second': 0.341}
```

BLEUスコアが39というのは悪くない結果で、このモデルがすでに英語の文章をフランス語に翻訳するのが得意であることを反映しています。

次に学習ですが、これにも少し時間がかかります。

```python
trainer.train()
```

学習が行われている間、モデルが保存されるたびに（ここではエポックごとに）バックグラウンドでHubにアップロードされることに注意してください。このようにして、必要に応じて別のマシンで学習を再開することができます。

学習が完了したら、再びモデルを評価します。BLEUスコアに改善が見られることを期待しましょう。

```py
trainer.evaluate(max_length=max_target_length)
```

```python out
{'eval_loss': 0.8558505773544312,
 'eval_bleu': 52.94161337775576,
 'eval_runtime': 714.2576,
 'eval_samples_per_second': 29.426,
 'eval_steps_per_second': 0.461,
 'epoch': 3.0}
```

ほぼ14ポイントの改善です。素晴らしいことです。

最後に、`push_to_hub()` メソッドを使って、最新版のモデルをアップロードしていることを確認します。また、`Trainer`はすべての評価結果を含むモデルカードを起草し、アップロードします。このモデルカードには、モデルハブが推論デモ用のウィジェットを選ぶのに役立つメタデータが含まれています。通常はモデルクラスから正しいウィジェットを推論できるので何も言う必要はありませんが、今回は同じモデルクラスがあらゆるシーケンス間問題に使えるので、翻訳モデルであることを指定しています。

```py
trainer.push_to_hub(tags="translation", commit_message="Training complete")
```

このコマンドは、今行ったコミットの URL を返すので、それを検査したい場合は、このコマンドを使用します。

```python out
'https://huggingface.co/sgugger/marian-finetuned-kde4-en-to-fr/commit/3601d621e3baae2bc63d3311452535f8f58f6ef3'
```

この段階で、モデルハブ上の推論ウィジェットを使って、モデルをテストしたり、友人と共有したりすることができます。これで、翻訳タスクのモデルの微調整が完了しました。おめでとうございます！

もう少し深く学習ループを学びたい場合に、🤗 Accelerateを使って同じことをする方法を紹介します。

{/if}

{#if fw === 'pt'}

## カスタムトレーニングループ

それでは、必要な部分を簡単にカスタマイズできるように、トレーニングループの全体像を見てみましょう。これは、[セクション 2](/course/ja/chapter7/2) と [第3章](/course/chapter3/4) で行ったことと同じように見えます。


### トレーニングのためのすべての準備

何度か見たことがあるはずなので、かなり手短にコードを見ていきましょう。まず、データセットから `DataLoader` を構築します。データセットを `"torch"` フォーマットに設定し、PyTorchテンソルを取得します。

```py
from torch.utils.data import DataLoader

tokenized_datasets.set_format("torch")
train_dataloader = DataLoader(
    tokenized_datasets["train"],
    shuffle=True,
    collate_fn=data_collator,
    batch_size=8,
)
eval_dataloader = DataLoader(
    tokenized_datasets["validation"], collate_fn=data_collator, batch_size=8
)
```

次に、モデルの再定義を行います。これは、以前の微調整を継続するのではなく、再び学習済みモデルから開始することを確認するためです。

```py
model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint)
```

それから、オプティマイザーが必要になります。

```py
from torch.optim import AdamW

optimizer = AdamW(model.parameters(), lr=2e-5)
```

これらのオブジェクトが揃ったら、それらを `accelerator.prepare()` メソッドに送ることができます。もし、ColabノートブックでTPUの学習をしたい場合は、このコードを全てトレーニング関数に移動する必要があります。そしてトレーニング関数は、`Accelerator`をインスタンス化するセルを実行しないようにします。

```py
from accelerate import Accelerator

accelerator = Accelerator()
model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare(
    model, optimizer, train_dataloader, eval_dataloader
)
```

これで `train_dataloader` を `accelerator.prepare()` に送ったので、その長さを使って学習ステップ数を計算することができます。このメソッドは `DataLoader` の長さを変更するので、常にデータローダーを準備した後にこの操作を行う必要があることを忘れないでください。ここでは、学習率を0に近づける古典的な線形スケジュールを使用します。

```py
from transformers import get_scheduler

num_train_epochs = 3
num_update_steps_per_epoch = len(train_dataloader)
num_training_steps = num_train_epochs * num_update_steps_per_epoch

lr_scheduler = get_scheduler(
    "linear",
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=num_training_steps,
)
```

最後に、私たちのモデルをハブにプッシュするために、作業フォルダに `Repository` オブジェクトを作成する必要があります。まず、ハギングフェイスハブにログインしてください（まだログインしていない場合）。モデルに付与したいモデル ID からリポジトリ名を決定します。(`repo_name` は自由に置き換えてください。ユーザー名が含まれていればよく、これは関数 `get_full_repo_name()` が行うことです)

```py
from huggingface_hub import Repository, get_full_repo_name

model_name = "marian-finetuned-kde4-en-to-fr-accelerate"
repo_name = get_full_repo_name(model_name)
repo_name
```

```python out
'sgugger/marian-finetuned-kde4-en-to-fr-accelerate'
```

そして、そのリポジトリをローカルフォルダーにクローンすることができます。すでに存在する場合は、このローカルフォルダーは作業中のリポジトリのクローンである必要があります。

```py
output_dir = "marian-finetuned-kde4-en-to-fr-accelerate"
repo = Repository(output_dir, clone_from=repo_name)
```

これで `repo.push_to_hub()` メソッドを呼び出すことで、`output_dir` に保存したものをアップロードできるようになりました。これにより、各エポック終了時に中間モデルをアップロードすることができます。

### トレーニングループ

これで完全なトレーニングループを書く準備ができました。評価パートを簡略化するため、この`postprocess()`関数は予測値とラベルを受け取って、 `metric` オブジェクトが求める文字列のリストに変換します。

```py
def postprocess(predictions, labels):
    predictions = predictions.cpu().numpy()
    labels = labels.cpu().numpy()

    decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True)

    # Replace -100 in the labels as we can't decode them.
    labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
    decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)

    # Some simple post-processing
    decoded_preds = [pred.strip() for pred in decoded_preds]
    decoded_labels = [[label.strip()] for label in decoded_labels]
    return decoded_preds, decoded_labels
```

学習ループは [セクション 2](/course/ja/chapter7/2) や [第3章](/course/ja/chapter3) のものとよく似ていますが、評価パートで少し違いがあります。では、その部分に注目してみましょう!

まず、予測の計算には `generate()` メソッドを使用していますが、これはベースモデルに対するメソッドです。🤗 Accelerateが`prepare()` メソッドで作成したラップモデルではありません。これがまずモデルをアンラップしてから、このメソッドを呼び出している理由です。

もう一つは、[トークン分類](/course/ja/chapter7/2) のように、2つのプロセスで入力とラベルを異なる形状にパディングしている場合があるので、 `accelerator.pad_across_processes()` で予測値とラベルを同じ形状にしてから `gather()` メソッドを呼び出しています。もしこれを行わなければ、評価はエラーになるか、永遠にハングアップします。

```py
from tqdm.auto import tqdm
import torch

progress_bar = tqdm(range(num_training_steps))

for epoch in range(num_train_epochs):
    # Training
    model.train()
    for batch in train_dataloader:
        outputs = model(**batch)
        loss = outputs.loss
        accelerator.backward(loss)

        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        progress_bar.update(1)

    # Evaluation
    model.eval()
    for batch in tqdm(eval_dataloader):
        with torch.no_grad():
            generated_tokens = accelerator.unwrap_model(model).generate(
                batch["input_ids"],
                attention_mask=batch["attention_mask"],
                max_length=128,
            )
        labels = batch["labels"]

        # Necessary to pad predictions and labels for being gathered
        generated_tokens = accelerator.pad_across_processes(
            generated_tokens, dim=1, pad_index=tokenizer.pad_token_id
        )
        labels = accelerator.pad_across_processes(labels, dim=1, pad_index=-100)

        predictions_gathered = accelerator.gather(generated_tokens)
        labels_gathered = accelerator.gather(labels)

        decoded_preds, decoded_labels = postprocess(predictions_gathered, labels_gathered)
        metric.add_batch(predictions=decoded_preds, references=decoded_labels)

    results = metric.compute()
    print(f"epoch {epoch}, BLEU score: {results['score']:.2f}")

    # Save and upload
    accelerator.wait_for_everyone()
    unwrapped_model = accelerator.unwrap_model(model)
    unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save)
    if accelerator.is_main_process:
        tokenizer.save_pretrained(output_dir)
        repo.push_to_hub(
            commit_message=f"Training in progress epoch {epoch}", blocking=False
        )
```

```python out
epoch 0, BLEU score: 53.47
epoch 1, BLEU score: 54.24
epoch 2, BLEU score: 54.44
```

これが完了すると、`Seq2SeqTrainer`で学習したものとかなり似た結果を持つモデルができるはずです。このコードを使って学習させたものは [*huggingface-course/marian-finetuned-kde4-en-to-fr-accelerate*](https://huggingface.co/huggingface-course/marian-finetuned-kde4-en-to-fr-accelerate) で確認することができます。また、学習ループに手を加えたい場合は、上に示したコードを編集することで、直接実装することができます

{/if}

## 微調整したモデルを使う

モデルハブで微調整したモデルを推論ウィジェットで使用する方法は既に紹介しました。パイプラインで使用する場合は、モデル識別子を指定します。

```py
from transformers import pipeline

# Replace this with your own checkpoint
model_checkpoint = "huggingface-course/marian-finetuned-kde4-en-to-fr"
translator = pipeline("translation", model=model_checkpoint)
translator("Default to expanded threads")
```

```python out
[{'translation_text': 'Par défaut, développer les fils de discussion'}]
```

予想通り、事前学習したモデルは、微調整したコーパスに知識を適応させ、英語の「threads」をそのままにせず、フランス語の正式なバージョンに翻訳するようになったのです。「plugin」についても同じです。

```py
translator(
    "Unable to import %1 using the OFX importer plugin. This file is not the correct format."
)
```

```python out
[{'translation_text': "Impossible d'importer %1 en utilisant le module externe d'importation OFX. Ce fichier n'est pas le bon format."}]
```

ドメイン適応の好例がまた一つ増えましたね！

<Tip>

✏️ **あなたの番です！** 先ほど確認した「email」という単語が入ったサンプルでは、モデルは何を返すでしょうか？

</Tip>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter7/4.mdx" />

### 質問応答
https://huggingface.co/learn/course/ja/chapter7/7.md

# 質問応答

{#if fw === 'pt'}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section7_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section7_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section7_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section7_tf.ipynb"},
]} />

{/if}

質問応答について考える時が来ました。このタスクには多くの種類がありますが、このセクションで取り上げるのは「 *抽出的* な質問応答」です。これは、特定の文書についての質問を投げかけ、文書内の答えの書かれている範囲を特定することを含みます。

<Youtube id="ajPx5LwJD-I"/>

私達は、Wikipediaの記事に対してクラウドワーカーによって作成された質問からなる[SQuADデータセット](https://rajpurkar.github.io/SQuAD-explorer/)のBERTモデルを微調整する予定です。これにより、以下のような予測を実行できるモデルができるでしょう。

<iframe src="https://course-demos-bert-finetuned-squad.hf.space" frameBorder="0" height="450" title="Gradio app" class="block dark:hidden container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

これは実際にこのセクションで示したコードを使って学習し、ハブにアップロードしたモデルを紹介しているものです。
貴方は[ここ](https://huggingface.co/huggingface-course/bert-finetuned-squad?context=%F0%9F%A4%97+Transformers+is+backed+by+the+three+most+popular+deep+learning+libraries+%E2%80%94+Jax%2C+PyTorch+and+TensorFlow+%E2%80%94+with+a+seamless+integration+between+them.+It%27s+straightforward+to+train+your+models+with+one+before+loading+them+for+inference+with+the+other.&question=Which+deep+learning+libraries+back+%F0%9F%A4%97+Transformers%3F)でモデルを見つけて、予測を再確認することができます。

<Tip>

💡 BERTのようなエンコーダのみのモデルは、「トランスフォーマーアーキテクチャを発明したのは誰ですか？」のような事実として受け入れられている解答が存在する質問に対して答えを抽出するのには優れていますが、「なぜ、空は青いのですか？」のような自由形式の質問を与えられたときにはうまくいかない傾向があります。

このような難しいケースでは、T5やBARTのようなエンコーダーデコーダーモデルが、[テキスト要約](/course/ja/chapter7/5)に非常に似た典型的な方法で情報を合成するために使用されます。このタイプの *生成的* な質問回答に興味がある場合は、[ELI5データセット](https://huggingface.co/datasets/eli5)に基づく私たちの[デモ](https://yjernite.github.io/lfqa.html)をチェックすることをお勧めします。

</Tip>

## データの準備

抽出的質問応答の学術的なベンチマークとして最も利用されているデータセットが [SQuAD](https://rajpurkar.github.io/SQuAD-explorer/) ですので、ここでもこれを利用します。また、より難しい[SQuAD v2](https://huggingface.co/datasets/squad_v2)ベンチマークもあり、これは答えのない質問を含んでいます。あなたのデータセットが文脈の列、質問の列、答えの列を含んでいる限り、以下のステップを適用することができるはずです。

### SQuAD データセット

いつものように、`load_dataset()`のおかげで、たった1ステップでデータセットをダウンロードし、キャッシュすることができます。

```py
from datasets import load_dataset

raw_datasets = load_dataset("squad")
```

そして、このオブジェクトを見て、SQuADデータセットについてもっと知ることができます。

```py
raw_datasets
```

```python out
DatasetDict({
    train: Dataset({
        features: ['id', 'title', 'context', 'question', 'answers'],
        num_rows: 87599
    })
    validation: Dataset({
        features: ['id', 'title', 'context', 'question', 'answers'],
        num_rows: 10570
    })
})
```

`context`, `question`, `answers` フィールドで必要なものはすべて揃ったようなので、トレーニングセットの最初の要素に対してこれらを出力してみましょう。

```py
print("Context: ", raw_datasets["train"][0]["context"])
print("Question: ", raw_datasets["train"][0]["question"])
print("Answer: ", raw_datasets["train"][0]["answers"])
```

```python out
Context: 'Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend "Venite Ad Me Omnes". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.'
Question: 'To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?'
Answer: {'text': ['Saint Bernadette Soubirous'], 'answer_start': [515]}
```

`context` と `question` フィールドは非常に簡単に使うことができます。`answers` フィールドは少し手が込んでおり、リストである2つのフィールドを持つ辞書型データを作成します。これは、 `squad` 指標が評価時に期待する形式です。もし、あなた自身のデータを使用しているのであれば、必ずしも同じ形式の答えを置くことを心配する必要はありません。また、 `answer_start` フィールドには、コンテキスト内の各解答の開始文字インデックスが格納されます。

トレーニングの間、可能な答えは1つだけです。このことは `Dataset.filter()` メソッドでダブルチェックすることができます。

```py
raw_datasets["train"].filter(lambda x: len(x["answers"]["text"]) != 1)
```

```python out
Dataset({
    features: ['id', 'title', 'context', 'question', 'answers'],
    num_rows: 0
})
```

ただし、評価については、各サンプルについて、同じ答えもあれば異なる答えもあり、いくつかの可能性があります。

```py
print(raw_datasets["validation"][0]["answers"])
print(raw_datasets["validation"][2]["answers"])
```

```python out
{'text': ['Denver Broncos', 'Denver Broncos', 'Denver Broncos'], 'answer_start': [177, 177, 177]}
{'text': ['Santa Clara, California', "Levi's Stadium", "Levi's Stadium in the San Francisco Bay Area at Santa Clara, California."], 'answer_start': [403, 355, 355]}
```

評価スクリプトは🤗 Datasetsの指標によってまとめられるので、ここでは深入りしませんが、簡単に言うと、いくつかの質問にはいくつかの回答があり、このスクリプトは予測された回答とすべての許容できる回答を比較し、ベストスコアを取るということです。例えばインデックス2のサンプルを見てみると

```py
print(raw_datasets["validation"][2]["context"])
print(raw_datasets["validation"][2]["question"])
```

```python out
'Super Bowl 50 was an American football game to determine the champion of the National Football League (NFL) for the 2015 season. The American Football Conference (AFC) champion Denver Broncos defeated the National Football Conference (NFC) champion Carolina Panthers 24–10 to earn their third Super Bowl title. The game was played on February 7, 2016, at Levi\'s Stadium in the San Francisco Bay Area at Santa Clara, California. As this was the 50th Super Bowl, the league emphasized the "golden anniversary" with various gold-themed initiatives, as well as temporarily suspending the tradition of naming each Super Bowl game with Roman numerals (under which the game would have been known as "Super Bowl L"), so that the logo could prominently feature the Arabic numerals 50.'
'Where did Super Bowl 50 take place?'
```

答えは、3つの可能性のうちの1つであることがわかります。

### 学習データの処理

<Youtube id="qgaM0weJHpA"/>

まず、学習データの前処理から始めましょう。難しいのは質問の答えのラベルを生成することで、これはコンテキスト内の答えに対応するトークンの開始位置と終了位置となります。

しかし、先を急がないようにしましょう。まず、トークナイザーを使って、入力のテキストをモデルが理解できるようなIDに変換する必要があります。

```py
from transformers import AutoTokenizer

model_checkpoint = "bert-base-cased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
```

先に述べたように、私たちは BERT モデルを微調整しますが、高速なトークナイザーが実装されている限り、他のどのようなモデルタイプでも使用することができます。[この大きな表](https://huggingface.co/transformers/#supported-frameworks)で高速版を持つすべてのアーキテクチャを見ることができます。使用している `tokenizer` オブジェクトが本当に 🤗 Tokenizers でバックアップされているかどうかを確認するには、その `is_fast` 属性を見ることができます。

```py
tokenizer.is_fast
```

```python out
True
```

質問とコンテキストを一緒にトークナイザーに渡せば、特殊なトークンを適切に挿入して、次のような文章を形成してくれます。

```
[CLS] question [SEP] context [SEP]
```

2重チェックしてみましょう。

```py
context = raw_datasets["train"][0]["context"]
question = raw_datasets["train"][0]["question"]

inputs = tokenizer(question, context)
tokenizer.decode(inputs["input_ids"])
```

```python out
'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Architecturally, '
'the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin '
'Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms '
'upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred '
'Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a '
'replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette '
'Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 statues '
'and the Gold Dome ), is a simple, modern stone statue of Mary. [SEP]'
```

ラベルは回答の開始と終了のトークンのインデックスとなり、モデルは入力のトークンごとに1つの開始と終了のロジットを予測するよう課され、理論上のラベルは次のようになります。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/qa_labels.svg" alt="One-hot encoded labels for question answering."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/qa_labels-dark.svg" alt="One-hot encoded labels for question answering."/>
</div>

この場合、コンテキストはそれほど長くありませんが、データセットの中には非常に長い文脈を持つ例もあり、設定した最大長（この場合は384）を超えてしまいます。[第6章](/course/ja/chapter6/4)で `質問応答`パイプラインの内部を調べたときに見たように、長いコンテキストに対しては、データセットの1つのサンプルから複数の学習特徴を作成し、それらの間にスライディングウィンドウを設けて対処することになります。

今回の例では、長さを100に制限し、50トークンのスライディングウィンドウを使用することで、どのように動作するかを確認します。注意点として、使用するのは

- 最大長を設定する `max_length` (ここでは100)
- `truncation="only_second"` は、質問とそのコンテキストが長すぎる場合に、(2番目の位置にある)コンテキストを切り詰める
- `stride` は2つの連続した断片間で重複するトークンの数を設定します (ここでは50)
- `return_overflowing_tokens=True` でトークナイザーにオーバーフロー用トークンが必要なことを知らせます。

```py
inputs = tokenizer(
    question,
    context,
    max_length=100,
    truncation="only_second",
    stride=50,
    return_overflowing_tokens=True,
)

for ids in inputs["input_ids"]:
    print(tokenizer.decode(ids))
```

```python out
'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basi [SEP]'
'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin [SEP]'
'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 [SEP]'
'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP]. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 statues and the Gold Dome ), is a simple, modern stone statue of Mary. [SEP]'
```

見てわかるように、この例は4つの入力に分割され、それぞれが質問とコンテキストの一部を含んでいます。質問に対する答え（"Bernadette Soubirous"）は3番目と最後の入力にのみ現れることに注意してください。このように長い文脈を扱うことで、答えが文脈に含まれない学習サンプルをいくつか作成することができます。これらの例では、ラベルは `start_position = end_position = 0` となります（つまり、`[CLS]` トークンを予測することになります）。また、不幸にも答えが切り捨てられ、始まり（または終わり）しかない場合にも、これらのラベルを設定します。答えがコンテキストに完全に含まれている例では、ラベルは答えが始まるトークンのインデックスと答えが終わるトークンのインデックスになります。

データセットからコンテキスト内の答えの開始文字が得られ、答えの長さを追加することで、コンテキスト内の終了文字が見つかります。これらをトークン インデックスにマップするには、[第6章](/course/ja/chapter6/4) で学習したオフセット マッピングを使用する必要があります。`return_offsets_mapping=True` を渡すことで、トークナイザーにこれらを返させることができます。

```py
inputs = tokenizer(
    question,
    context,
    max_length=100,
    truncation="only_second",
    stride=50,
    return_overflowing_tokens=True,
    return_offsets_mapping=True,
)
inputs.keys()
```

```python out
dict_keys(['input_ids', 'token_type_ids', 'attention_mask', 'offset_mapping', 'overflow_to_sample_mapping'])
```

見てのとおり、通常の入力 ID、トークンタイプ ID、アテンションマスクに加え、必要なオフセットマッピング、さらに `overflow_to_sample_mapping` というキーが返されます。この値は、複数のテキストを同時にトークン化するときに役に立ちます (このトークナイザーがRustに支えられているという事実を利用するために、そうする必要があります)。1 つのサンプルは複数の特徴を与えることができるので、各特徴をその元となるサンプルにマップします。ここでは 1 つの例をトークン化しただけなので、`0` のリストが得られます。

```py
inputs["overflow_to_sample_mapping"]
```

```python out
[0, 0, 0, 0]
```

しかし、もっと多くの例をトークン化すれば、これはもっと便利になります。

```py
inputs = tokenizer(
    raw_datasets["train"][2:6]["question"],
    raw_datasets["train"][2:6]["context"],
    max_length=100,
    truncation="only_second",
    stride=50,
    return_overflowing_tokens=True,
    return_offsets_mapping=True,
)

print(f"The 4 examples gave {len(inputs['input_ids'])} features.")
print(f"Here is where each comes from: {inputs['overflow_to_sample_mapping']}.")
```

```python out
'The 4 examples gave 19 features.'
'Here is where each comes from: [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3].'
```

見ての通り、最初の3例（トレーニングセットのインデックス2、3、4）はそれぞれ4つの特徴を与え、最後の例（トレーニングセットのインデックス5）は7つの特徴を与えています。

この情報は、得られた各特徴を対応するラベルに対応付けるために有用です。前述したように、それらのラベルは

- 答えがコンテキストが対応する範囲内にない場合、 `(0, 0)` となります
- `(start_position, end_position)` もし答えがコンテキストの対応する範囲内にあれば、 `start_position` は答えの始まりのトークン（入力IDの中）のインデックス、 `end_position` は答えの終わりのトークン（入力IDの中）のインデックスです

これらのどちらであるか、また関連する場合はトークンの位置を決定するために、まず入力IDの中で文脈を開始するインデックスと終了するインデックスを見つけます。これを行うにはトークンタイプ ID を使用することもできますが、それはすべてのモデルに存在するとは限らないので (例えば DistilBERT はそれを要求しません)、代わりにトークナイザーが返す `BatchEncoding` の `sequence_ids()` メソッドを使用することにします。

トークンのインデックスが得られたら、対応するオフセットを調べます。オフセットとは、元のコンテキスト内の文字の範囲を表す2つの整数の組のことです。このようにして、この特徴におけるコンテキストの断片が、答えが終わった後に始まっているのか、答えが始まる前に終わっているのか（その場合のラベルは `(0, 0)` ） を検出することができるのです。そうでない場合は、答えの最初と最後のトークンを見つけるためにループします。

```py
answers = raw_datasets["train"][2:6]["answers"]
start_positions = []
end_positions = []

for i, offset in enumerate(inputs["offset_mapping"]):
    sample_idx = inputs["overflow_to_sample_mapping"][i]
    answer = answers[sample_idx]
    start_char = answer["answer_start"][0]
    end_char = answer["answer_start"][0] + len(answer["text"][0])
    sequence_ids = inputs.sequence_ids(i)

    # Find the start and end of the context
    idx = 0
    while sequence_ids[idx] != 1:
        idx += 1
    context_start = idx
    while sequence_ids[idx] == 1:
        idx += 1
    context_end = idx - 1

    # If the answer is not fully inside the context, label is (0, 0)
    if offset[context_start][0] > start_char or offset[context_end][1] < end_char:
        start_positions.append(0)
        end_positions.append(0)
    else:
        # Otherwise it's the start and end token positions
        idx = context_start
        while idx <= context_end and offset[idx][0] <= start_char:
            idx += 1
        start_positions.append(idx - 1)

        idx = context_end
        while idx >= context_start and offset[idx][1] >= end_char:
            idx -= 1
        end_positions.append(idx + 1)

start_positions, end_positions
```

```python out
([83, 51, 19, 0, 0, 64, 27, 0, 34, 0, 0, 0, 67, 34, 0, 0, 0, 0, 0],
 [85, 53, 21, 0, 0, 70, 33, 0, 40, 0, 0, 0, 68, 35, 0, 0, 0, 0, 0])
```

私達のアプローチが正しいことを確認するために、いくつかの結果を見てみましょう。最初の特徴量では、ラベルとして `(83, 85)` が見つかったので、理論的な答えと83から85（インデックスに対応するトークンも含む）までのトークンのデコードした範囲を比較してみましょう。

```py
idx = 0
sample_idx = inputs["overflow_to_sample_mapping"][idx]
answer = answers[sample_idx]["text"][0]

start = start_positions[idx]
end = end_positions[idx]
labeled_answer = tokenizer.decode(inputs["input_ids"][idx][start : end + 1])

print(f"Theoretical answer: {answer}, labels give: {labeled_answer}")
```

```python out
'Theoretical answer: the Main Building, labels give: the Main Building'
```

ということで、一致しました ここで、ラベルを `(0, 0)` に設定しました。つまり、答えはその特徴のコンテキストの断片にないことを意味します。

```py
idx = 4
sample_idx = inputs["overflow_to_sample_mapping"][idx]
answer = answers[sample_idx]["text"][0]

decoded_example = tokenizer.decode(inputs["input_ids"][idx])
print(f"Theoretical answer: {answer}, decoded example: {decoded_example}")
```

```python out
'Theoretical answer: a Marian place of prayer and reflection, decoded example: [CLS] What is the Grotto at Notre Dame? [SEP] Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grot [SEP]'
```

確かに、文脈の中に答えが出てきません。

<Tip>

✏️ **あなたの番です！** XLNetアーキテクチャを使用する場合、左側にパディングが適用され、質問とコンテキストが切り替わります。先ほどのコードを全てXLNetアーキテクチャに適応させてください（そして`padding=True`を追加する）。パディングを適用した場合、`[CLS]` トークンが 0 の位置に来ない可能性があることに注意してください。

</Tip>

訓練データの前処理を段階的に見てきましたが、訓練データセット全体に対して適用する関数にまとめることができます。ほとんどのコンテキストは長いので（そして対応するサンプルはいくつかの特徴に分割されます）、ここで動的パディングを適用してもあまり意味がないので、すべての特徴を設定した最大長になるようにパディングします。

```py
max_length = 384
stride = 128


def preprocess_training_examples(examples):
    questions = [q.strip() for q in examples["question"]]
    inputs = tokenizer(
        questions,
        examples["context"],
        max_length=max_length,
        truncation="only_second",
        stride=stride,
        return_overflowing_tokens=True,
        return_offsets_mapping=True,
        padding="max_length",
    )

    offset_mapping = inputs.pop("offset_mapping")
    sample_map = inputs.pop("overflow_to_sample_mapping")
    answers = examples["answers"]
    start_positions = []
    end_positions = []

    for i, offset in enumerate(offset_mapping):
        sample_idx = sample_map[i]
        answer = answers[sample_idx]
        start_char = answer["answer_start"][0]
        end_char = answer["answer_start"][0] + len(answer["text"][0])
        sequence_ids = inputs.sequence_ids(i)

        # Find the start and end of the context
        idx = 0
        while sequence_ids[idx] != 1:
            idx += 1
        context_start = idx
        while sequence_ids[idx] == 1:
            idx += 1
        context_end = idx - 1

        # If the answer is not fully inside the context, label is (0, 0)
        if offset[context_start][0] > start_char or offset[context_end][1] < end_char:
            start_positions.append(0)
            end_positions.append(0)
        else:
            # Otherwise it's the start and end token positions
            idx = context_start
            while idx <= context_end and offset[idx][0] <= start_char:
                idx += 1
            start_positions.append(idx - 1)

            idx = context_end
            while idx >= context_start and offset[idx][1] >= end_char:
                idx -= 1
            end_positions.append(idx + 1)

    inputs["start_positions"] = start_positions
    inputs["end_positions"] = end_positions
    return inputs
```

スライディングウィンドウの長さと最大長を決定するために2つの定数を定義したことと、トークン化の前に小さなクリーンアップを追加したことに注意してください。SQuADデータセットのいくつかの質問には最初と最後に何も追加しない余計なスペース（RoBERTaなどのモデルを使用するとトークン化するときにスペースを取ってしまいます）があるので、それらの余計なスペースを除去しています。

この関数を訓練セット全体に適用するために、 `Dataset.map()` メソッドに `batched=True` フラグを付けて使います。これはデータセットの長さを変更するために必要です（1つの例で複数の学習特徴を与えることができるため）。

```py
train_dataset = raw_datasets["train"].map(
    preprocess_training_examples,
    batched=True,
    remove_columns=raw_datasets["train"].column_names,
)
len(raw_datasets["train"]), len(train_dataset)
```

```python out
(87599, 88729)
```
このように、前処理によって約1,000個の特徴が追加されました。これで訓練セットの準備は整いました。次は検証セットの前処理です。

### 検証セットの処理

検証データの前処理は、ラベルを生成する必要がないため、若干簡単になります。（検証損失を計算したい場合は別ですが、この数値はモデルがどれだけ優れているかを理解するのにあまり役立ちません）。本当の喜びは、モデルの予測を元のコンテキストの範囲として解釈する事にあります。このためには、オフセットマッピングと、作成された各特徴を元の例文とマッチングさせる方法の両方を保存する必要があるだけです。元のデータセットにIDカラムがあるので、そのIDを使用します。

ここで追加するのは、オフセットマッピングのほんの少しのクリーンアップだけです。質問とコンテキストのオフセットが含まれますが、後処理の段階では、入力IDのどの部分がコンテキストに対応し、どの部分が質問であるかを知る方法がありません（私たちが使った `sequence_ids()` メソッドはトークナイザの出力にのみ利用可能です）。そこで、質問に対応するオフセットを `None` に設定することにします。

```py
def preprocess_validation_examples(examples):
    questions = [q.strip() for q in examples["question"]]
    inputs = tokenizer(
        questions,
        examples["context"],
        max_length=max_length,
        truncation="only_second",
        stride=stride,
        return_overflowing_tokens=True,
        return_offsets_mapping=True,
        padding="max_length",
    )

    sample_map = inputs.pop("overflow_to_sample_mapping")
    example_ids = []

    for i in range(len(inputs["input_ids"])):
        sample_idx = sample_map[i]
        example_ids.append(examples["id"][sample_idx])

        sequence_ids = inputs.sequence_ids(i)
        offset = inputs["offset_mapping"][i]
        inputs["offset_mapping"][i] = [
            o if sequence_ids[k] == 1 else None for k, o in enumerate(offset)
        ]

    inputs["example_id"] = example_ids
    return inputs
```

この関数は、先ほどのように検証用データセット全体に適用することができます。

```py
validation_dataset = raw_datasets["validation"].map(
    preprocess_validation_examples,
    batched=True,
    remove_columns=raw_datasets["validation"].column_names,
)
len(raw_datasets["validation"]), len(validation_dataset)
```

```python out
(10570, 10822)
```

この場合、数百サンプルしか追加していないので、検証用データセットのコンテキストは少し短いようです。
さて、全てのデータの前処理が終わったので、いよいよ学習に入ります。

{#if fw === 'pt'}

## Trainer API でモデルの微調整を行う

この例の学習コードは、前のセクションのコードとよく似ています。最も難しいのは `compute_metrics()` 関数を書くことです。すべてのサンプルを設定した最大長になるようにパディングしているので、データコレーターを定義する必要はありません。したがって、この指標の計算だけが本当に心配しなければならないことです。難しいのは、後処理でモデルの予測を元の例文のテキストの範囲にすることです。一旦これを行えば、🤗 Datasetsライブラリの指標が私達のためにほとんどの作業をしてくれるでしょう。

{:else}

## Kerasを使ってモデルの微調整を行う

この例の学習コードは、前のセクションのコードとよく似ていますが、指標の計算に独自の難しさがあります。全てのサンプルを設定した最大長にパディングしたので、定義すべきデータコレーターはなく、この指標の計算だけが本当に心配しなければならないことなのです。難しい事は、後処理として、モデルの予測を元の例のテキストの範囲にすることです。一度それを行えば、🤗 Datasetsライブラリのメトリックが私たちのために仕事の大部分を行ってくれます。

{/if}

### 後処理

{#if fw === 'pt'}

<Youtube id="BNy08iIWVJM"/>

{:else}

<Youtube id="VN67ZpN33Ss"/>

{/if}

このモデルは、[`question-answering` pipeline](/course/ja/chapter6/3b) の探索で見たように、入力IDにおける答えの開始位置と終了位置のロジットを出力することになります。後処理のステップは、その際に行ったことと同じようなものになりますので、以下でやった事を思い出してください。

- コンテキスト外のトークンに対応する開始と終了のロジットをマスクしました。
- 次に、ソフトマックスを使用して開始ロジットと終了ロジットを確率に変換しました。
- 各ペア `(start_token, end_token)` には、対応する二つの確率の積を取ることでスコアを付与しました。
- 私達は有効な答え（例えば、`start_token`が`end_token`より前にある）をもたらす最大のスコアを持つペアを探しました。

ここでは、実際のスコアを計算する必要がないため、このプロセスを少し変更します（予測された答えだけが欲しいのです）。つまり、ソフトマックスのステップをスキップすることができます。また、より高速に処理するために、可能性のある全ての `(start_token, end_token)` ペアをスコアリングせず、最も高い `n_best` ロジットに対応するものだけをスコアリングします（`n_best=20` とします）。ソフトマックスをスキップするので、これらのスコアはlogitスコアとなり、開始と終了のロジットの和を取ることで得られます。\\(\log(ab) = \log(a) + \log(b)\\))の公式があるので積の代わりに和となります)。

これらのことを実証するためには、何らかの予測が必要です。まだモデルを学習していないので、QAパイプラインのデフォルトモデルを使用して、検証セットの一部で予測を生成することにします。この処理関数はグローバル定数 `tokenizer` に依存しているので、このオブジェクトを一時的に使用したいモデルのトークナイザーに変更するだけでよいのです。

```python
small_eval_set = raw_datasets["validation"].select(range(100))
trained_checkpoint = "distilbert-base-cased-distilled-squad"

tokenizer = AutoTokenizer.from_pretrained(trained_checkpoint)
eval_set = small_eval_set.map(
    preprocess_validation_examples,
    batched=True,
    remove_columns=raw_datasets["validation"].column_names,
)
```

前処理が終わったので、トークナイザーを元々選んでいたものに戻します。

```python
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
```

次に、`eval_set`からモデルが期待しない列を取り除き、その小さな検証セットをすべて含むバッチを構築し、それをモデルに渡します。GPUが利用可能であれば、より高速に処理するためにそれを使用します。

{#if fw === 'pt'}

```python
import torch
from transformers import AutoModelForQuestionAnswering

eval_set_for_model = eval_set.remove_columns(["example_id", "offset_mapping"])
eval_set_for_model.set_format("torch")

device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
batch = {k: eval_set_for_model[k].to(device) for k in eval_set_for_model.column_names}
trained_model = AutoModelForQuestionAnswering.from_pretrained(trained_checkpoint).to(
    device
)

with torch.no_grad():
    outputs = trained_model(**batch)
```

`Trainer`は予測値をNumPyの配列として与えるので、開始と終了のロジットを取得し、その形式に変換します。

```python
start_logits = outputs.start_logits.cpu().numpy()
end_logits = outputs.end_logits.cpu().numpy()
```

{:else}

```python
import tensorflow as tf
from transformers import TFAutoModelForQuestionAnswering

eval_set_for_model = eval_set.remove_columns(["example_id", "offset_mapping"])
eval_set_for_model.set_format("numpy")

batch = {k: eval_set_for_model[k] for k in eval_set_for_model.column_names}
trained_model = TFAutoModelForQuestionAnswering.from_pretrained(trained_checkpoint)

outputs = trained_model(**batch)
```

実験を容易にするために、これらの出力をNumPyの配列に変換してみましょう。

```python
start_logits = outputs.start_logits.numpy()
end_logits = outputs.end_logits.numpy()
```

{/if}

さて、`small_eval_set` に含まれる各例に対して、予測される答えを見つける必要があります。一つの例は、`eval_set`の中でいくつかの特徴に分割されている可能性があるので、最初のステップは `small_eval_set` の中の各例を `eval_set` の中の対応する特徴にマッピングすることです。

```python
import collections

example_to_features = collections.defaultdict(list)
for idx, feature in enumerate(eval_set):
    example_to_features[feature["example_id"]].append(idx)
```

これがあれば、すべての例と、それぞれの例について、関連するすべての特徴をループすることで、実際に仕事に取り掛かることができます。前に述べたように、「n_best」な開始ロジットと終了ロジットのロジットスコアを見ますが、以下を除きます。

- コンテキストの中にない答え
- 負の長さを持つ答え
- 長すぎる答え (私達は `max_answer_length=30` で可能性を制限しています)

1つの例に対して採点されたすべての可能な答えがあったら、最高のロジットスコアから1つを選びます。

```python
import numpy as np

n_best = 20
max_answer_length = 30
predicted_answers = []

for example in small_eval_set:
    example_id = example["id"]
    context = example["context"]
    answers = []

    for feature_index in example_to_features[example_id]:
        start_logit = start_logits[feature_index]
        end_logit = end_logits[feature_index]
        offsets = eval_set["offset_mapping"][feature_index]

        start_indexes = np.argsort(start_logit)[-1 : -n_best - 1 : -1].tolist()
        end_indexes = np.argsort(end_logit)[-1 : -n_best - 1 : -1].tolist()
        for start_index in start_indexes:
            for end_index in end_indexes:
                # Skip answers that are not fully in the context
                if offsets[start_index] is None or offsets[end_index] is None:
                    continue
                # Skip answers with a length that is either < 0 or > max_answer_length.
                if (
                    end_index < start_index
                    or end_index - start_index + 1 > max_answer_length
                ):
                    continue

                answers.append(
                    {
                        "text": context[offsets[start_index][0] : offsets[end_index][1]],
                        "logit_score": start_logit[start_index] + end_logit[end_index],
                    }
                )

    best_answer = max(answers, key=lambda x: x["logit_score"])
    predicted_answers.append({"id": example_id, "prediction_text": best_answer["text"]})
```

予測された答えの最終的なフォーマットは、私たちが使用する指標によって期待されるものです。いつものように、🤗 Evaluateライブラリの助けを借りて読み込むことができます。

```python
import evaluate

metric = evaluate.load("squad")
```

この指標は、上で見た形式の予測された答え（サンプルのIDと予測されたテキストの1つのキーを持つ辞書のリスト）と、下の形式の理論的な答え（サンプルのIDと可能な答えの1つのキーを持つ辞書のリスト）を期待するものです。

```python
theoretical_answers = [
    {"id": ex["id"], "answers": ex["answers"]} for ex in small_eval_set
]
```

ここで、両方のリストの最初の要素を見て、賢明な結果が得られることを確認することができます。

```python
print(predicted_answers[0])
print(theoretical_answers[0])
```

```python out
{'id': '56be4db0acb8001400a502ec', 'prediction_text': 'Denver Broncos'}
{'id': '56be4db0acb8001400a502ec', 'answers': {'text': ['Denver Broncos', 'Denver Broncos', 'Denver Broncos'], 'answer_start': [177, 177, 177]}}
```

悪くないですね！では、この指標が示すスコアを見てみましょう。

```python
metric.compute(predictions=predicted_answers, references=theoretical_answers)
```

```python out
{'exact_match': 83.0, 'f1': 88.25}
```

[この論文](https://arxiv.org/abs/1910.01108v2)によると、SQuADで微調整したDistilBERTは、全データセットで79.1点と86.9点を獲得していることを考えると、これはむしろ良いことだと言えます。

{#if fw === 'pt'}

ここで、先ほど行ったことをすべて `compute_metrics()` 関数にまとめて、 `Trainer` で使用することにしましょう。通常、 `compute_metrics()` 関数は logits と labels を含むタプル `eval_preds` を受け取るだけです。

今回はもう少し多くの情報が必要になります。オフセット用の特徴のデータセットと、元のコンテキスト用のデータセットを調べなければならないためです。
そのため、この関数を使って学習中に通常の評価結果を得ることはできません。この関数は学習終了時に結果を確認するためだけに使います。

compute_metrics()` 関数は、前と同じステップをグループ化します。有効な答えが得られなかった場合（その場合は予測を空文字列とします）に備えて、小さなチェックを追加しているだけです。

{:else}

では、今やったことをすべて `compute_metrics()` 関数にまとめてみましょう。この関数はモデルの学習後に使用します。オフセット用の特徴のデータセットと、元の文脈の例文用のデータセットを調べなければならないので、出力のロジットだけでなく、もう少し多くのデータを渡す必要があります。

{/if}

```python
from tqdm.auto import tqdm


def compute_metrics(start_logits, end_logits, features, examples):
    example_to_features = collections.defaultdict(list)
    for idx, feature in enumerate(features):
        example_to_features[feature["example_id"]].append(idx)

    predicted_answers = []
    for example in tqdm(examples):
        example_id = example["id"]
        context = example["context"]
        answers = []

        # Loop through all features associated with that example
        for feature_index in example_to_features[example_id]:
            start_logit = start_logits[feature_index]
            end_logit = end_logits[feature_index]
            offsets = features[feature_index]["offset_mapping"]

            start_indexes = np.argsort(start_logit)[-1 : -n_best - 1 : -1].tolist()
            end_indexes = np.argsort(end_logit)[-1 : -n_best - 1 : -1].tolist()
            for start_index in start_indexes:
                for end_index in end_indexes:
                    # Skip answers that are not fully in the context
                    if offsets[start_index] is None or offsets[end_index] is None:
                        continue
                    # Skip answers with a length that is either < 0 or > max_answer_length
                    if (
                        end_index < start_index
                        or end_index - start_index + 1 > max_answer_length
                    ):
                        continue

                    answer = {
                        "text": context[offsets[start_index][0] : offsets[end_index][1]],
                        "logit_score": start_logit[start_index] + end_logit[end_index],
                    }
                    answers.append(answer)

        # Select the answer with the best score
        if len(answers) > 0:
            best_answer = max(answers, key=lambda x: x["logit_score"])
            predicted_answers.append(
                {"id": example_id, "prediction_text": best_answer["text"]}
            )
        else:
            predicted_answers.append({"id": example_id, "prediction_text": ""})

    theoretical_answers = [{"id": ex["id"], "answers": ex["answers"]} for ex in examples]
    return metric.compute(predictions=predicted_answers, references=theoretical_answers)
```

私達の予測を使って動作確認ができます。

```python
compute_metrics(start_logits, end_logits, eval_set, small_eval_set)
```

```python out
{'exact_match': 83.0, 'f1': 88.25}
```

いい感じです！では、これを使ってモデルを微調整してみましょう。

### モデルの微調整

{#if fw === 'pt'}

これでモデルを学習する準備ができました。先程と同じように `AutoModelForQuestionAnswering` クラスを使用して、まずモデルを作成しましょう。

```python
model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint)
```

{:else}

これでモデルを学習する準備ができました。まず、前と同じように `TFAutoModelForQuestionAnswering` クラスを使用してモデルを作成しましょう。

```python
model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint)
```

{/if}

いつものように、いくつかの重みが使われていない（事前学習時のヘッドのもの）、他のいくつかの重みがランダムに初期化されている（質問応答用ヘッドのもの）という警告が表示されます。もう慣れたと思いますが、これはこのモデルがまだ使える状態ではなく、微調整が必要であることを意味します。

このモデルをHubにプッシュするためには、Hugging Faceにログインする必要があります。もしこのコードをnotebookで実行しているなら、次のユーティリティ関数でログインすることができます。

```python
from huggingface_hub import notebook_login

notebook_login()
```

ノートブックで作業していない場合は、ターミナルで次の行を入力するだけです。

```bash
huggingface-cli login
```

{#if fw === 'pt'}

これが完了したら、`TrainingArguments` を定義します。指標を計算する関数を定義したときに言ったように、 `compute_metrics()` 関数の制限のために、通常の評価ループを持つことができません。これを実現するために、独自の `Trainer` のサブクラスを書くこともできますが (この方法は [質問応答例スクリプト](https://github.com/huggingface/transformers/blob/master/examples/pytorch/question-answering/trainer_qa.py) にあります)、このセクションにはちょっと長すぎますね。その代わり、ここでは学習の最後にモデルを評価することだけを行い、通常の評価の方法は後述の「カスタム学習ループ」で紹介します。

これは `Trainer` API の限界であり、🤗 Accelerate ライブラリが輝くところです。特定の用例に合わせてクラスをカスタマイズするのは大変ですが、完全に公開された学習ループを調整するのは簡単です。

それでは、`TrainingArguments` を見てみましょう。

```python
from transformers import TrainingArguments

args = TrainingArguments(
    "bert-finetuned-squad",
    evaluation_strategy="no",
    save_strategy="epoch",
    learning_rate=2e-5,
    num_train_epochs=3,
    weight_decay=0.01,
    fp16=True,
    push_to_hub=True,
)
```

これらのほとんどは以前にも見たことがあると思います。

ハイパーパラメータ（学習率、学習エポック数、ウェイト減衰など）を設定し、エポック終了ごとにモデルを保存し、評価を省略し、結果をモデルハブにアップロードすることを指定します。また、`fp16=True`で混合精度学習を有効にします。最近のGPUでは、混合精度学習がうまくスピードアップするからです。

{:else}

これで、TFデータセットを作成することができます。今回はシンプルなデフォルトのデータコレーターを使用します。

```python
from transformers import DefaultDataCollator

data_collator = DefaultDataCollator(return_tensors="tf")
```

そして、今度はいつも通りデータセットを作成します。

```python
tf_train_dataset = train_dataset.to_tf_dataset(
    columns=[
        "input_ids",
        "start_positions",
        "end_positions",
        "attention_mask",
        "token_type_ids",
    ],
    collate_fn=data_collator,
    shuffle=True,
    batch_size=16,
)
tf_eval_dataset = validation_dataset.to_tf_dataset(
    columns=["input_ids", "attention_mask", "token_type_ids"],
    collate_fn=data_collator,
    shuffle=False,
    batch_size=16,
)
```

次に、学習用ハイパーパラメータを設定し、モデルをコンパイルします。

```python
from transformers import create_optimizer
from transformers.keras_callbacks import PushToHubCallback
import tensorflow as tf

# The number of training steps is the number of samples in the dataset, divided by the batch size then multiplied
# by the total number of epochs. Note that the tf_train_dataset here is a batched tf.data.Dataset,
# not the original Hugging Face Dataset, so its len() is already num_samples // batch_size.
num_train_epochs = 3
num_train_steps = len(tf_train_dataset) * num_train_epochs
optimizer, schedule = create_optimizer(
    init_lr=2e-5,
    num_warmup_steps=0,
    num_train_steps=num_train_steps,
    weight_decay_rate=0.01,
)
model.compile(optimizer=optimizer)

# Train in mixed-precision float16
tf.keras.mixed_precision.set_global_policy("mixed_float16")
```

最後に、`model.fit()`で学習する準備ができました。`PushToHubCallback`を使用して、各エポック後にモデルをハブにアップロードします。

{/if}

デフォルトでは、使用されるリポジトリはあなたの名前空間にあり、設定した出力ディレクトリの名前になります。
この例では、 `"sgugger/bert-finetuned-squad"` になります。

`hub_model_id` を渡すことで、これを上書きすることができます。例えば、モデルを `huggingface_course` という組織にプッシュするには、 `hub_model_id="huggingface_course/bert-finetuned-squad"`(この章の始めでリンクしたモデルです) を使用します。

{#if fw === 'pt'}

<Tip>

💡 使用する出力ディレクトリが存在する場合は、プッシュしたいリポジトリのローカルクローンである必要があります (したがって、`Trainer` の定義時にエラーが発生した場合は、新しい名前を設定する必要があります)。

</Tip>

最後に、すべてを `Trainer` クラスに渡して、トレーニングを開始するだけです。

```python
from transformers import Trainer

trainer = Trainer(
    model=model,
    args=args,
    train_dataset=train_dataset,
    eval_dataset=validation_dataset,
    tokenizer=tokenizer,
)
trainer.train()
```

{:else}

```python
from transformers.keras_callbacks import PushToHubCallback

callback = PushToHubCallback(output_dir="bert-finetuned-squad", tokenizer=tokenizer)

# We're going to do validation afterwards, so no validation mid-training
model.fit(tf_train_dataset, callbacks=[callback], epochs=num_train_epochs)
```

{/if}

学習が行われている間、モデルが保存されるたびに（ここではエポックごとに）バックグラウンドでハブにアップロードされることに注意してください。こうすることで、必要に応じて別のマシンでトレーニングを再開することができます。トレーニング全体にはしばらく時間がかかるので（Titan RTXで1時間強）、その間コーヒーを飲んだり、コースの難しい部分を読み直したりすることができます。また、最初のエポックが終了するとすぐに、いくつかの重みがハブにアップロードされ、そのページであなたのモデルで遊び始めることができることに留意してください。

{#if fw === 'pt'}

学習が完了したら、最後にモデルを評価することができます（そして、無駄に計算時間を費やさないように祈ることになります）。`Trainer` の `predict()` メソッドはタプルを返し、その最初の要素はモデルの予測値（ここでは開始ロジットと終了ロジットのペア）となります。これを `compute_metrics()` 関数に送ります。

```python
predictions, _, _ = trainer.predict(validation_dataset)
start_logits, end_logits = predictions
compute_metrics(start_logits, end_logits, validation_dataset, raw_datasets["validation"])
```

{:else}

学習が完了したら、最後にモデルを評価することができます（そして、無駄に計算時間を費やしていないことを祈ります）。予測値の取得は `model` の `predict()` メソッドで行います。また、先ほど `compute_metrics()` 関数を定義して苦労したので、1行で結果を得ることができます。

```python
predictions = model.predict(tf_eval_dataset)
compute_metrics(
    predictions["start_logits"],
    predictions["end_logits"],
    validation_dataset,
    raw_datasets["validation"],
)
```

{/if}

```python out
{'exact_match': 81.18259224219489, 'f1': 88.67381321905516}
```

素晴らしい！
比較として、このモデルのBERTの記事で報告されているベースラインのスコアは80.8と88.5なので、ちょうどあるべきところにいることになります。

{#if fw === 'pt'}

最後に、`push_to_hub()`メソッドを使用して、最新バージョンのモデルをアップロードすることを確認します。

```py
trainer.push_to_hub(commit_message="Training complete")
```

これは、今行ったコミットの URL を返します。もしそれを検査したいのであれば、その URL をチェックします。

```python out
'https://huggingface.co/sgugger/bert-finetuned-squad/commit/9dcee1fbc25946a6ed4bb32efb1bd71d5fa90b68'
```

また、`Trainer`は評価結果をまとめたモデルカードを起案し、アップロードします。

{/if}

この段階で、モデルハブ上の推論ウィジェットを使ってモデルをテストし、友人、家族、お気に入りのペットと共有することができます。あなたは、質問応答タスクでモデルの微調整に成功しました。おめでとうございます！

<Tip>

✏️ **あなたの番です！** このタスクでより良いパフォーマンスが得られるかどうか、別のモデルアーキテクチャを試してみてください！

</Tip>

{#if fw === 'pt'}

もう少し深くトレーニングループを極めたい方は、今度は🤗Accelerateを使って同じことをする方法を紹介します。

## カスタムトレーニングループ

それでは、必要な部分を簡単にカスタマイズできるように、トレーニングループの全体像を見てみましょう。[第3章](/course/ja/chapter3/4)の学習ループとほぼ同じですが、評価ループは例外です。もう `Trainer` クラスの制約を受けないので、定期的にモデルを評価することができるようになります。

### トレーニングのためのすべてを準備する

まず、datasetsから `DataLoader` を構築します。それらのdatasetsのフォーマットを `"torch"` に設定し、検証用セットの中からモデルで使用しないカラムを削除します。次に、Transformers が提供する `default_data_collator` を `collate_fn` として使用し、トレーニングセットをシャッフルしますが、検証セットはシャッフルしません。

```py
from torch.utils.data import DataLoader
from transformers import default_data_collator

train_dataset.set_format("torch")
validation_set = validation_dataset.remove_columns(["example_id", "offset_mapping"])
validation_set.set_format("torch")

train_dataloader = DataLoader(
    train_dataset,
    shuffle=True,
    collate_fn=default_data_collator,
    batch_size=8,
)
eval_dataloader = DataLoader(
    validation_set, collate_fn=default_data_collator, batch_size=8
)
```

次に、モデルの再定義を行います。これは、以前の微調整を継続するのではなく、BERTで事前学習したモデルから再び開始することを確認するためです。

```py
model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint)
```

それから、オプティマイザーが必要になります。いつものように、古典的な `AdamW` を使用します。これは Adam のようなものですが、重みの減衰の適用方法を修正したものです。

```py
from torch.optim import AdamW

optimizer = AdamW(model.parameters(), lr=2e-5)
```

これらのオブジェクトが揃ったら、それらを `accelerator.prepare()` メソッドに送ることができます。もし、ColabノートブックでTPUを使ったトレーニングをしたいのであれば、このコードを全てトレーニング関数に移動する必要があることに注意してください。トレーニング関数は`Accelerator`をインスタンス化するセルを実行するべきではありません。`Accelerator`に `fp16=True` を渡すことで、強制的に混合精度のトレーニングを行うことができます (または、コードをスクリプトとして実行する場合は、🤗 Accelerate `config` を適切に埋めてください)。

```py
from accelerate import Accelerator

accelerator = Accelerator(fp16=True)
model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare(
    model, optimizer, train_dataloader, eval_dataloader
)
```

前のセクションで学んだように、`train_dataloader` の長さは `accelerator.prepare()` メソッドを経た後でのみ、トレーニングステップ数を計算するために使用することができます。ここでは、これまでのセクションと同じ線形スケジュールを使用します。

```py
from transformers import get_scheduler

num_train_epochs = 3
num_update_steps_per_epoch = len(train_dataloader)
num_training_steps = num_train_epochs * num_update_steps_per_epoch

lr_scheduler = get_scheduler(
    "linear",
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=num_training_steps,
)
```

モデルをハブにプッシュするには、作業フォルダに `Repository` オブジェクトを作成する必要があります。まず、ハギング フェイス ハブにログインしてください（まだログインしていない場合）。モデルに付与したいモデル ID からリポジトリ名を決定します（`repo_name` を自由に置き換えてください。ユーザー名を含む必要があり、これは関数 `get_full_repo_name()` が行っている事です)。

```py
from huggingface_hub import Repository, get_full_repo_name

model_name = "bert-finetuned-squad-accelerate"
repo_name = get_full_repo_name(model_name)
repo_name
```

```python out
'sgugger/bert-finetuned-squad-accelerate'
```

そして、そのリポジトリをローカルフォルダーにクローンすることができます。すでに存在する場合は、このローカルフォルダーは作業中のリポジトリのクローンである必要があります。

```py
output_dir = "bert-finetuned-squad-accelerate"
repo = Repository(output_dir, clone_from=repo_name)
```

これで `repo.push_to_hub()` メソッドを呼び出すことで、`output_dir` に保存したものをアップロードできるようになりました。これにより、各エポック終了時に中間モデルをアップロードすることができます。

## トレーニングループ

これでトレーニングループの全体を記述する準備が整いました。トレーニングの進捗を確認するためのプログレスバーを定義した後、ループは3つの部分に分かれます。

- 訓練自体は、`train_dataloader`に対する古典的な繰り返しで、モデルを前方に通過させ、後方に通過させ、オプティマイザーのステップを行います。

- 評価では、`start_logits` と `end_logits` の値をすべて収集し、NumPy の配列に変換します。評価ループが終了したら、すべての結果を連結します。各処理で同じ数のサンプルが得られるように、`Accelerator`が最後にいくつかのサンプルを追加している可能性があるため、切り捨てる必要があることに注意してください。

- 保存とアップロードでは、まずモデルとトークナイザーを保存し、次に `repo.push_to_hub()` を呼び出します。前回と同様に、引数 `blocking=False` を使って🤗 Hubライブラリに非同期処理でプッシュするように指示します。こうすることで、トレーニングは通常通り行われ、この（長い時間のかかる）命令はバックグラウンドで実行されます。

以下は、トレーニングループの完全なコードです。

```py
from tqdm.auto import tqdm
import torch

progress_bar = tqdm(range(num_training_steps))

for epoch in range(num_train_epochs):
    # Training
    model.train()
    for step, batch in enumerate(train_dataloader):
        outputs = model(**batch)
        loss = outputs.loss
        accelerator.backward(loss)

        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        progress_bar.update(1)

    # Evaluation
    model.eval()
    start_logits = []
    end_logits = []
    accelerator.print("Evaluation!")
    for batch in tqdm(eval_dataloader):
        with torch.no_grad():
            outputs = model(**batch)

        start_logits.append(accelerator.gather(outputs.start_logits).cpu().numpy())
        end_logits.append(accelerator.gather(outputs.end_logits).cpu().numpy())

    start_logits = np.concatenate(start_logits)
    end_logits = np.concatenate(end_logits)
    start_logits = start_logits[: len(validation_dataset)]
    end_logits = end_logits[: len(validation_dataset)]

    metrics = compute_metrics(
        start_logits, end_logits, validation_dataset, raw_datasets["validation"]
    )
    print(f"epoch {epoch}:", metrics)

    # Save and upload
    accelerator.wait_for_everyone()
    unwrapped_model = accelerator.unwrap_model(model)
    unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save)
    if accelerator.is_main_process:
        tokenizer.save_pretrained(output_dir)
        repo.push_to_hub(
            commit_message=f"Training in progress epoch {epoch}", blocking=False
        )
```

🤗Accelerateで保存されたモデルを初めて表示する場合は、それに付随する3行のコードを調べてみましょう。

```py
accelerator.wait_for_everyone()
unwrapped_model = accelerator.unwrap_model(model)
unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save)
```

最初の行は自明です。すべてのプロセスに、全員がその段階になるまで待ってから続行するように指示します。これは、保存する前に、すべてのプロセスが同じモデルを対象にしている事を確認するためです。次に、定義したベースモデルである`unwrapped_model`を取得します。 `accelerator.prepare（）`メソッドは、分散トレーニングで機能するようにモデルを変更するため、 `save_pretrained（）`メソッドはなくなります。 `accelerator.unwrap_model（）`メソッドはそのステップを元に戻します。最後に、 `save_pretrained（）`を呼び出しますが、そのメソッドに `torch.save（）`の代わりに `accelerator.save（）`を使用するように指示します。

これが完了すると、`Trainer`でトレーニングされたものと非常によく似た結果を生成するモデルができあがります。 このコードを使用してトレーニングしたモデルは、[*huggingface-course/bert-finetuned-squad-accelerate*]（https://huggingface.co/huggingface-course/bert-finetuned-squad-accelerate）で確認できます。 また、トレーニングループの微調整をテストする場合は、上記のコードを編集して直接実装できます！

{/if}

## 微調整したモデルを使用する

モデルハブで微調整したモデルを推論ウィジェットで使用する方法は既に紹介しました。`pipeline`で利用する場合は、モデル識別子を指定します。

```py
from transformers import pipeline

# Replace this with your own checkpoint
model_checkpoint = "huggingface-course/bert-finetuned-squad"
question_answerer = pipeline("question-answering", model=model_checkpoint)

context = """
🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch and TensorFlow — with a seamless integration
between them. It's straightforward to train your models with one before loading them for inference with the other.
"""
question = "Which deep learning libraries back 🤗 Transformers?"
question_answerer(question=question, context=context)
```

```python out
{'score': 0.9979003071784973,
 'start': 78,
 'end': 105,
 'answer': 'Jax, PyTorch and TensorFlow'}
```

素晴らしいです！ 私たちのモデルは、このパイプラインのデフォルトのものと同じように動作しています！

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter7/7.mdx" />

### トークン分類
https://huggingface.co/learn/course/ja/chapter7/2.md

# トークン分類

{#if fw === 'pt'}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section2_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section2_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={7}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter7/section2_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter7/section2_tf.ipynb"},
]} />

{/if}

最初に紹介するアプリケーションは、トークン分類です。この汎用的なタスクは「文中の各トークンにラベルを付ける」と定義可能な、以下のような問題を含みます。

- **固有表現認識(NER)**: 文中に含まれる人名、地名、組織名などの固有のエンティティを検出します。これは、固有エンティティを1クラス、固有エンティティなしを1クラスとして、各トークンにラベルを付与するタスクと定義できます。
- **品詞タグ付け(POS)**: 文中の各単語を特定の品詞（名詞、動詞、形容詞など）に対応するものとしてマークします。
- **チャンキング(chunking)**: 同じエンティティに属するトークンを見つけます。このタスク（POSやNERと組み合わせることができます）は、チャンクの先頭にあるトークンには一つのラベル（通常 `B-`）、チャンクの中にあるトークンには別のラベル（通常 `I-`）、どのチャンクにも属さないトークンには三つ目のラベル（通常 `O`）を付けることと定義できます。。

<Youtube id="wVHdVlPScxA"/>

もちろん、トークン分類問題には他にも多くの問題があり、これらは代表的な例に過ぎません。このセクションでは、NERタスクでモデル（BERT）を微調整し、以下のような予測計算ができるようにします。

<iframe src="https://course-demos-bert-finetuned-ner.hf.space" frameBorder="0" height="350" title="Gradio app" class="block dark:hidden container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

<a class="flex justify-center" href="/huggingface-course/bert-finetuned-ner">
<img class="block dark:hidden lg:w-3/5" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/model-eval-bert-finetuned-ner.png" alt="One-hot encoded labels for question answering."/>
<img class="hidden dark:block lg:w-3/5" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter7/model-eval-bert-finetuned-ner-dark.png" alt="One-hot encoded labels for question answering."/>
</a>

あなたは学習済みモデルをHubで探したり、Hubにアップロードし、その予測値を[ここで](https://huggingface.co/huggingface-course/bert-finetuned-ner?text=My+name+is+Sylvain+and+I+work+at+Hugging+Face+in+Brooklyn)再確認することができます 。

## データの準備

まず最初に、トークン分類に適したデータセットが必要です。このセクションでは、[CoNLL-2003 dataset](https://huggingface.co/datasets/conll2003)を使います。このデータセットはロイターが配信するニュース記事を含みます。 

<Tip>

💡 単語とそれに対応するラベルに分割されたテキストからなるデータセットであれば、ここで説明するデータ処理を自分のデータセットに適用することができます。独自のデータを `Dataset` にロードする方法について復習が必要な場合は、[第5章](/course/ja/chapter5) を参照してください。

</Tip>

### The CoNLL-2003 dataset

CoNLL-2003のデータセットをロードするために、🤗 Datasetsライブラリの `load_dataset()` メソッドを使用します。

```py
from datasets import load_dataset

raw_datasets = load_dataset("conll2003")
```

これはデータセットをダウンロードしキャッシュします。[第3章](/course/ja/chapter3)でGLUE MRPC datasetを扱ったときと同じです。このオブジェクトを調べると、定義された列と、トレーニングセット、検証セット、テストセットの3つに分割されている事がわかります。

```py
raw_datasets
```

```python out
DatasetDict({
    train: Dataset({
        features: ['chunk_tags', 'id', 'ner_tags', 'pos_tags', 'tokens'],
        num_rows: 14041
    })
    validation: Dataset({
        features: ['chunk_tags', 'id', 'ner_tags', 'pos_tags', 'tokens'],
        num_rows: 3250
    })
    test: Dataset({
        features: ['chunk_tags', 'id', 'ner_tags', 'pos_tags', 'tokens'],
        num_rows: 3453
    })
})
```

特に、このデータセットには、先に述べた3つのタスク用のラベル、NER、POS、チャンキングが含まれていることがわかります。他のデータセットとの大きな違いは、入力テキストが文や文書としてではなく、単語のリストとして表示されていることです（最後の列は`tokens`呼ばれていますが、これはトークン化前の入力で、まだサブワード トークン化のためにtokenizer処理する必要があるという意味で単語を含んでいます）。

それでは、学習セットの最初の要素を見てみましょう。

```py
raw_datasets["train"][0]["tokens"]
```

```python out
['EU', 'rejects', 'German', 'call', 'to', 'boycott', 'British', 'lamb', '.']
```

今回は固有表現認識を行いたいので、NERタグを見ることにします。

```py
raw_datasets["train"][0]["ner_tags"]
```

```python out
[3, 0, 7, 0, 0, 0, 7, 0, 0]
```

これは学習時に使われるラベルのため整数値で格納されています。データを調べるときには必ずしも便利ではありません。テキスト分類のように、データセットの `features` 属性を見れば、これらの整数値が何のラベルであるか調べる事ができます。

```py
ner_feature = raw_datasets["train"].features["ner_tags"]
ner_feature
```

```python out
Sequence(feature=ClassLabel(num_classes=9, names=['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC', 'B-MISC', 'I-MISC'], names_file=None, id=None), length=-1, id=None)
```

つまり、このカラムは `ClassLabel` の要素を含んでいます。各要素の型は、この `ner_feature` の `feature` 属性にあり、その `feature` の `names` 属性を見ることで名前のリストを確認する事ができます。


```py
label_names = ner_feature.feature.names
label_names
```

```python out
['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC', 'B-MISC', 'I-MISC']
```

これらのラベルは[第6章](/course/ja/chapter6/3)で、`token-classification`パイプラインを学んだときに掘り下げましたが、簡単に復習しておきましょう。 

- `O` はその単語がどのエンティティにも対応しないことを意味します。
- `B-PER`/`I-PER` は、その単語が *人(person)* エンティティの先頭、または内部であることを意味します。
- `B-ORG`/`I-ORG` は、その単語が *組織(organization)* エンティティの先頭、または内部であることを意味します。 
- `B-LOC`/`I-LOC` は、その単語が *場所(location)* エンティティの先頭、または内部であることを意味します。 
- `B-MISC`/`I-MISC` は、その単語が *その他(miscellaneous)* エンティティの先頭、または内部であることを意味します。

さて、先ほどのラベルをデコードすると、以下のようになります。

```python
words = raw_datasets["train"][0]["tokens"]
labels = raw_datasets["train"][0]["ner_tags"]
line1 = ""
line2 = ""
for word, label in zip(words, labels):
    full_label = label_names[label]
    max_length = max(len(word), len(full_label))
    line1 += word + " " * (max_length - len(word) + 1)
    line2 += full_label + " " * (max_length - len(full_label) + 1)

print(line1)
print(line2)
```

```python out
'EU    rejects German call to boycott British lamb .'
'B-ORG O       B-MISC O    O  O       B-MISC  O    O'
```

また、`B-` と `I-`のラベルを混在させた例として、学習セットの4番目の要素について同じコードを実行すると、以下のようになります。

```python out
'Germany \'s representative to the European Union \'s veterinary committee Werner Zwingmann said on Wednesday consumers should buy sheepmeat from countries other than Britain until the scientific advice was clearer .'
'B-LOC   O  O              O  O   B-ORG    I-ORG O  O          O         B-PER  I-PER     O    O  O         O         O      O   O         O    O         O     O    B-LOC   O     O   O          O      O   O       O'
```

このように、"European Union" と "Werner Zwingmann" のように2つの単語にまたがるエンティティは、最初の単語には `B-` ラベルが、2番目の単語には `I-` ラベルが付与されます。

<Tip>

✏️ **あなたの番です！** 同じ2つの文をPOSラベルまたはチャンキングラベルと一緒に出力してください。

</Tip>

### データの処理

<Youtube id="iY2AZYdZAr0"/>

いつものように、モデルが意味を理解できるようにするために、テキストはトークンIDに変換される必要があります。[第6章](/course/ja/chapter6/)で見たように、トークン分類タスクの場合の大きな違いは、入力があらかじめトークン化されていると言う事です。幸いなことに、tokenizer API はこの点をかなり簡単に処理できます。特別なフラグを指定して `tokenizer` に警告するだけです。

まず最初に、`tokenizer` オブジェクトを作成しましょう。前に述べたように、事前学習済みBERTモデルを使用する予定なので、関連するtokenizerをダウンロードしてキャッシュすることから始めます。

```python
from transformers import AutoTokenizer

model_checkpoint = "bert-base-cased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
```

あなたは`model_checkpoint` を自由に置き換える事ができます。[Hub](https://huggingface.co/models) にある好きなモデルや、自分の端末に保存した事前学習済みモデルやtokenizerをで置き換えることができます。

唯一の制約は、tokenizerが 🤗 Tokenizers ライブラリによってバックアップされる必要があることです。これにより「高速」バージョンが用意されます。[この大きなテーブル](https://huggingface.co/transformers/#supported-frameworks) で高速バージョンを持つ全てのアーキテクチャを見ることができます。使用している `tokenizer` オブジェクトが本当に 🤗 Tokenizers でバックアップされているかどうかを確認するには、`is_fast` 属性を見る事が確認できます。

```py
tokenizer.is_fast
```

```python out
True
```

トークン化前の入力をトークン化するには、普段通り `tokenizer` を使用して、 `is_split_into_words=True` を追加するだけです。

```py
inputs = tokenizer(raw_datasets["train"][0]["tokens"], is_split_into_words=True)
inputs.tokens()
```

```python out
['[CLS]', 'EU', 'rejects', 'German', 'call', 'to', 'boycott', 'British', 'la', '##mb', '.', '[SEP]']
```

見ての通り、トークン化はモデルが使用する特殊なトークン（先頭の `[CLS]` と末尾の `[SEP]` ）を追加し、ほとんどの単語はそのままにしました。しかし、`lamb`という単語は`la`と`##mb`という2つのサブワードにトークン化されました。このため、入力とラベルの間にミスマッチが生じます。ラベルのリストには9つの要素しかありませんが、入力のリストには12のトークンがあります。特殊なトークンを考慮するのは簡単ですが（最初と最後にあることが分かっています）、すべてのラベルを適切な単語に揃えることも必要です。

幸い、高速なtokenizerを使っているので、🤗 Tokenizers のスーパーパワーにアクセスすることができ、それぞれのトークンを対応する単語に簡単にマッピングすることができます (これは [第６章](/course/ja/chapter6/3) で見たとおりです)。

```py
inputs.word_ids()
```

```python out
[None, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, None]
```

ほんの少しの作業で、トークンにマッチするようにラベルリストを拡張することができます。最初に適用するルールは、特殊なトークンには `-100` というラベルを付けるというものです。これはデフォルトで `-100` がこれから使う損失関数（クロスエントロピー）で無視される数だからです。次に、単語内の各トークンは単語の先頭のトークンと同じラベルが付与されます。これは同じエンティティの一部であるためです。単語の内部にあり、かつ先頭にないトークンについては、`B-` を `I-` に置き換えます（そのトークンはエンティティを開始しないためです）。

```python
def align_labels_with_tokens(labels, word_ids):
    new_labels = []
    current_word = None
    for word_id in word_ids:
        if word_id != current_word:
            # Start of a new word!
            current_word = word_id
            label = -100 if word_id is None else labels[word_id]
            new_labels.append(label)
        elif word_id is None:
            # Special token
            new_labels.append(-100)
        else:
            # Same word as previous token
            label = labels[word_id]
            # If the label is B-XXX we change it to I-XXX
            if label % 2 == 1:
                label += 1
            new_labels.append(label)

    return new_labels
```

それでは、最初の文章で試してみましょう。

```py
labels = raw_datasets["train"][0]["ner_tags"]
word_ids = inputs.word_ids()
print(labels)
print(align_labels_with_tokens(labels, word_ids))
```

```python out
[3, 0, 7, 0, 0, 0, 7, 0, 0]
[-100, 3, 0, 7, 0, 0, 0, 7, 0, 0, 0, -100]
```

見てわかるように、この関数は最初と最後の2つの特別なトークンに対して `-100` を追加し、2つのトークンに分割された単語に対して新たに `0` を追加しています。

<Tip>

✏️ **あなたの番です！** 研究者の中には、1つの単語には1つのラベルしか付けず、与えられた単語内の他のサブトークンに`-100`を割り当てることを好む人もいます。これは、多くのサブトークンに分割される長い単語が学習時の損失に大きく寄与するのを避けるためです。このルールに従って、ラベルと入力IDを一致させるように、前の関数を変更してみましょう。

</Tip>

データセット全体の前処理として、すべての入力をトークン化し、すべてのラベルに対して `align_labels_with_tokens()` を適用する必要があります。高速なtokenizerの速度を活かすには、たくさんのテキストを同時にトークン化するのがよいでしょう。そこで、サンプルのリストを処理する関数を書いて、 `Dataset.map()` メソッドに `batched=True` オプションを付けて使用することにしましょう。以前の例と唯一違うのは、tokenizerへの入力がテキストのリスト（この場合は単語のリストのリスト）である場合、 `word_ids()` 関数は単語IDが欲しいリストのインデックスを必要とするので、これも追加します。

```py
def tokenize_and_align_labels(examples):
    tokenized_inputs = tokenizer(
        examples["tokens"], truncation=True, is_split_into_words=True
    )
    all_labels = examples["ner_tags"]
    new_labels = []
    for i, labels in enumerate(all_labels):
        word_ids = tokenized_inputs.word_ids(i)
        new_labels.append(align_labels_with_tokens(labels, word_ids))

    tokenized_inputs["labels"] = new_labels
    return tokenized_inputs
```

まだ、入力をパディングしていないことに注意してください。
これは後でデータ照合ツールでバッチを作成するときにやることにします。

これで、データセットの分割に対して、すべての前処理を一度に適用することができるようになりました。

```py
tokenized_datasets = raw_datasets.map(
    tokenize_and_align_labels,
    batched=True,
    remove_columns=raw_datasets["train"].column_names,
)
```

一番大変なところをやりましたね！
データの前処理が終わったので、実際の学習は[第3章](/course/ja/chapter3)でやったような感じになりますね。

{#if fw === 'pt'}

## Trainer API でモデルを微調整する

実際に `Trainer` を使用するコードは、これまでと同じです。変更点は、データをバッチ化する方法と、指標を計算する関数だけです。

{:else}

## Keras を使ってモデルを微調整する

Kerasを使った実際のコードは、これまでとほとんど同じで、データをバッチ化する方法と、指標計算の関数が変わるだけです。

{/if}


### データ照合

[第3章](/course/ja/chapter3) にあるような `DataCollatorWithPadding` は入力 (入力 ID、アテンションマスク、トークンタイプ ID) のみをパディングするので使えません。ここでは、ラベルのサイズが変わらないように、入力と全く同じ方法でパディングを行います。値として `-100` を使用し、対応する予測値が損失計算で無視されるようにします。

これは全て [`DataCollatorForTokenClassification`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorfortokenclassification) によって行われます。DataCollatorWithPadding` と同様に、入力の前処理に使用される `tokenizer` を受け取ります。

{#if fw === 'pt'}

```py
from transformers import DataCollatorForTokenClassification

data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer)
```

{:else}

```py
from transformers import DataCollatorForTokenClassification

data_collator = DataCollatorForTokenClassification(
    tokenizer=tokenizer, return_tensors="tf"
)
```

{/if}

これをいくつかのサンプルでテストするには、トークン化されたトレーニングセットからサンプルのリストに対して呼び出すだけでよいのです。

```py
batch = data_collator([tokenized_datasets["train"][i] for i in range(2)])
batch["labels"]
```

```python out
tensor([[-100,    3,    0,    7,    0,    0,    0,    7,    0,    0,    0, -100],
        [-100,    1,    2, -100, -100, -100, -100, -100, -100, -100, -100, -100]])
```

これをデータセットの1番目と2番目の要素のラベルと比較してみましょう。

```py
for i in range(2):
    print(tokenized_datasets["train"][i]["labels"])
```

```python out
[-100, 3, 0, 7, 0, 0, 0, 7, 0, 0, 0, -100]
[-100, 1, 2, -100]
```

{#if fw === 'pt'}

見ての通り、2つ目のラベルのセットは最初のラベルの長さに `-100`s を使ってパディングされています．

{:else}

データ照合の準備ができました！
では、これを使って `tf.data.Dataset` を `to_tf_dataset()` メソッドを使って作ってみましょう。

```py
tf_train_dataset = tokenized_datasets["train"].to_tf_dataset(
    columns=["attention_mask", "input_ids", "labels", "token_type_ids"],
    collate_fn=data_collator,
    shuffle=True,
    batch_size=16,
)

tf_eval_dataset = tokenized_datasets["validation"].to_tf_dataset(
    columns=["attention_mask", "input_ids", "labels", "token_type_ids"],
    collate_fn=data_collator,
    shuffle=False,
    batch_size=16,
)
```


次は、モデル本体です。

{/if}

{#if fw === 'tf'}

### モデルの定義

今回はトークン分類の問題を扱うので、 `TFAutoModelForTokenClassification` クラスを使用します。このモデルを定義する際に覚えておくべきことは、ラベルの数に関する情報を渡すことです。最も簡単な方法は `num_labels` 引数でその数を渡すことですが、このセクションの最初に見たような素敵な推論ウィジェットを動作させたい場合は、代わりに正しいラベルの対応関係を設定した方が良いでしょう。

id2label` と `label2id` という 2 つの辞書型データがあり、ID からラベル、ラベルから ID へのマッピングを設定することができます。

```py
id2label = {i: label for i, label in enumerate(label_names)}
label2id = {v: k for k, v in id2label.items()}
```

あとはそれらを `TFAutoModelForTokenClassification.from_pretrained()` メソッドに渡せば、モデルの設定にセットされ、適切に保存されてHubにアップロードされるでしょう。

```py
from transformers import TFAutoModelForTokenClassification

model = TFAutoModelForTokenClassification.from_pretrained(
    model_checkpoint,
    id2label=id2label,
    label2id=label2id,
)
```

[第3章](/course/ja/chapter3) で `TFAutoModelForSequenceClassification` を定義したときのように、モデルを作成すると、いくつかの重みが使われていない（事前学習済みモデルのヘッド部の重み）、他のいくつかの重みがランダムに初期化されている（新しく接続したトークン分類ヘッドの重み）、このモデルはトレーニングする必要があるという警告が表示されます。トレーニングはすぐにでも実行できますが、まずはこのモデルが正しい数のラベルを持つことを再確認しましょう。

```python
model.config.num_labels
```

```python out
9
```

<Tip warning={true}>

⚠️ ラベルの数が間違っているモデルがあると、後で `model.fit()` を呼び出すときによくわからないエラーが発生します。このエラーはデバッグの際に厄介なので、このチェックを必ず行い、期待通りのラベル数であることを確認してください。

</Tip>

### モデルの微調整

これでモデルを学習する準備が整いました！
しかし、その前にもう少しだけやるべきことがあります。Hugging Faceにログインし、学習用ハイパーパラメータを定義する必要があります。もしNotebookで作業しているなら、これを助ける便利な関数があります。

```python
from huggingface_hub import notebook_login

notebook_login()
```

これにより、Hugging Faceのログイン情報を入力するウィジェットが表示されます。

Notebookで作業していない場合は、ターミナルに次の行を入力するだけです。

```bash
huggingface-cli login
```

ログインしたら、モデルをコンパイルするために必要なものをすべて準備します。

🤗 Transformers は便利な `create_optimizer()` 関数を提供しており、重みの減衰と学習率の減衰を適切に設定した `AdamW` オプティマイザが得られます。この2つの設定は、組み込みの `Adam` オプティマイザと比較してあなたのモデルの性能を向上させるでしょう。

```python
from transformers import create_optimizer
import tensorflow as tf

# Train in mixed-precision float16
# Comment this line out if you're using a GPU that will not benefit from this
tf.keras.mixed_precision.set_global_policy("mixed_float16")

# The number of training steps is the number of samples in the dataset, divided by the batch size then multiplied
# by the total number of epochs. Note that the tf_train_dataset here is a batched tf.data.Dataset,
# not the original Hugging Face Dataset, so its len() is already num_samples // batch_size.
num_epochs = 3
num_train_steps = len(tf_train_dataset) * num_epochs

optimizer, schedule = create_optimizer(
    init_lr=2e-5,
    num_warmup_steps=0,
    num_train_steps=num_train_steps,
    weight_decay_rate=0.01,
)
model.compile(optimizer=optimizer)
```

また、`compile()`に `loss`引数を与えないことにも注意してください。これは、モデルが内部的に損失を計算することができるからです。損失なしでコンパイルして、入力辞書にラベルを指定すると（私たちのデータセットで行っているように）、モデルはその内部損失を使用して学習し、それは選んだタスクとモデルタイプに適したものになるでしょう。

次に、学習中にモデルをHubにアップロードするための`PushToHubCallback`を定義し、そのコールバックでモデルをフィットさせます。

```python
from transformers.keras_callbacks import PushToHubCallback

callback = PushToHubCallback(output_dir="bert-finetuned-ner", tokenizer=tokenizer)

model.fit(
    tf_train_dataset,
    validation_data=tf_eval_dataset,
    callbacks=[callback],
    epochs=num_epochs,
)
```

`hub_model_id` 引数には、プッシュしたいリポジトリのフルネームを指定できます。 (特に、特定の組織（organization）にプッシュする場合はこの引数を使用する必要があります)。例えば、モデルを [`huggingface-course` organization](https://huggingface.co/huggingface-course) にプッシュする場合、 `hub_model_id="huggingface-course/bert-finetuned-ner"` を追加します。デフォルトでは、使用されるリポジトリはあなたの名前が使われ、設定した出力ディレクトリにちなんだ名前、例えば `"cool_huggingface_user/bert-finetuned-ner"` となります。

<Tip>

💡 使用している出力ディレクトリがすでに存在する場合は、プッシュしたいリポジトリのローカルクローンである必要があります。そうでない場合は、`model.fit()` を呼び出すときにエラーが発生し、新しい名前を設定する必要があります。

</Tip>

学習が行われている間、モデルが保存されるたびに（今回の例ではエポックごとに）バックグラウンドでHubにアップロードされることに注意してください。このようにしておけば、必要に応じて別のマシンで学習を再開することができます。この段階で、Model Hub上の推論ウィジェットを使ってモデルをテストし、友人と共有することができます。

これでトークン分類タスクのモデル微調整に成功しました。おめでとうございます！

しかし、このモデルの実力はいかほどでしょうか？それを知るために、いくつかの指標を使って評価する必要があります。

{/if}


### 指標

{#if fw === 'pt'}

`Trainer` にエポック毎に指標を計算させるためには、`compute_metrics()` 関数を定義する必要があります。これは予測とラベルの配列を受け取り、指標の名前と値を含む辞書を返す関数です。

トークン分類予測の評価に使われる伝統的な枠組みは[*seqeval*](https://github.com/chakki-works/seqeval)です。この指標を使うには、まず *seqeval* ライブラリをインストールする必要があります。


```py
!pip install seqeval
```

そして、[第3章](/course/ja/chapter3) で行ったように `evaluate.load()` 関数で読み込むことができるようになります。

{:else}

トークン分類予測の評価に使われる伝統的な枠組みは[*seqeval*](https://github.com/chakki-works/seqeval)です。この評価指標を使うには、まず*seqeval*ライブラリをインストールする必要があります。

```py
!pip install seqeval
```

そして、[第3章](/course/ja/chapter3) で行ったように `evaluate.load()` 関数で読み込むことができるようになります。

{/if}

```py
import evaluate

metric = evaluate.load("seqeval")
```

この指標は標準的な精度指標のように動作しません：実際にはラベルのリストを整数ではなく文字列として受け取るので、予測値とラベルを指標に渡す前に完全にデコードする必要があります。

それでは、どのように動作するか見てみましょう。まず、最初の学習サンプルに対するラベルを取得します。

```py
labels = raw_datasets["train"][0]["ner_tags"]
labels = [label_names[i] for i in labels]
labels
```

```python out
['B-ORG', 'O', 'B-MISC', 'O', 'O', 'O', 'B-MISC', 'O', 'O']
```

そして、インデックス2の値を変更するだけで、それらの疑似予測を作成することができます。

```py
predictions = labels.copy()
predictions[2] = "O"
metric.compute(predictions=[predictions], references=[labels])
```

この指標は予測値のリスト（1つだけではない）とラベルのリストを受け取ることに注意してください。以下はその出力です。


```python out
{'MISC': {'precision': 1.0, 'recall': 0.5, 'f1': 0.67, 'number': 2},
 'ORG': {'precision': 1.0, 'recall': 1.0, 'f1': 1.0, 'number': 1},
 'overall_precision': 1.0,
 'overall_recall': 0.67,
 'overall_f1': 0.8,
 'overall_accuracy': 0.89}
```

{#if fw === 'pt'}

とても多くの情報を取得しています！
各エンティティの精度、再現率、F1スコア、そして総合的なスコアです。

私達の指標計算では、総合的なスコアのみを保持することにします。
しかし、お望みなら`compute_metrics()`関数を微調整して、報告させたいすべての指標を返すこともできます。

この `compute_metrics()` 関数は、まず 最終レイヤーが出力するベクトルの最大値を予測値に変換します（最終レイヤーが出力する生の値は通常は確率に変換されますが、最大値は確率に変換しなくとも同じなので、softmax で確率に変換させる必要はありません）。次に、ラベルと予測値の両方を整数から文字列に変換する必要があります。ラベルが `-100` である値をすべて削除し、その結果を `metric.compute()` メソッドに渡します。

```py
import numpy as np


def compute_metrics(eval_preds):
    logits, labels = eval_preds
    predictions = np.argmax(logits, axis=-1)

    # Remove ignored index (special tokens) and convert to labels
    true_labels = [[label_names[l] for l in label if l != -100] for label in labels]
    true_predictions = [
        [label_names[p] for (p, l) in zip(prediction, label) if l != -100]
        for prediction, label in zip(predictions, labels)
    ]
    all_metrics = metric.compute(predictions=true_predictions, references=true_labels)
    return {
        "precision": all_metrics["overall_precision"],
        "recall": all_metrics["overall_recall"],
        "f1": all_metrics["overall_f1"],
        "accuracy": all_metrics["overall_accuracy"],
    }
```

これで、`Trainer` を定義する準備はほぼ整いました。あとは微調整をするための `model` が必要です。

{:else}

とても多くの情報を取得しています！
各エンティティの精度、再現率、F1スコア、そして総合的なスコアです。
では、実際にモデルの予測値を使ってスコアを計算してみるとどうなるか見てみましょう。

TensorFlowは予測値を連結することを好みません。なぜなら、予測値は可変長であるからです。つまり、`model.predict()`をそのまま使うことはできないのです。しかし、だからといってここで止めるつもりはありません。一度にいくつかの予測をバッチで実行して取得し、それらを一つの大きな長いリストに連結し、マスキングやパディングを示す `-100` トークンを削除します。

```py
import numpy as np

all_predictions = []
all_labels = []
for batch in tf_eval_dataset:
    logits = model.predict(batch)["logits"]
    labels = batch["labels"]
    predictions = np.argmax(logits, axis=-1)
    for prediction, label in zip(predictions, labels):
        for predicted_idx, label_idx in zip(prediction, label):
            if label_idx == -100:
                continue
            all_predictions.append(label_names[predicted_idx])
            all_labels.append(label_names[label_idx])
metric.compute(predictions=[all_predictions], references=[all_labels])
```


```python out
{'LOC': {'precision': 0.91, 'recall': 0.92, 'f1': 0.91, 'number': 1668},
 'MISC': {'precision': 0.70, 'recall': 0.79, 'f1': 0.74, 'number': 702},
 'ORG': {'precision': 0.85, 'recall': 0.90, 'f1': 0.88, 'number': 1661},
 'PER': {'precision': 0.95, 'recall': 0.95, 'f1': 0.95, 'number': 1617},
 'overall_precision': 0.87,
 'overall_recall': 0.91,
 'overall_f1': 0.89,
 'overall_accuracy': 0.97}
```

あなたのモデルは、私たちのモデルと比較して、どうでしたか？
もし、同じような数値が出たのなら、トレーニングは成功です。

{/if}

{#if fw === 'pt'}

### モデルを定義

今回はトークン分類の問題を扱うので、 `AutoModelForTokenClassification` クラスを使用します。このモデルを定義する際に覚えておくべきことは、ラベルの数に関する情報を渡すことです。最も簡単な方法は `num_labels` 引数でその数を渡すことですが、このセクションの最初に見たような素敵な推論ウィジェットを動作させたい場合は、代わりに正しいラベルの対応関係を設定した方が良いでしょう。

id2label` と `label2id` という 2 つの辞書型データがあり、ID からラベル、ラベルから ID へのマッピングを設定することができます。

```py
id2label = {i: label for i, label in enumerate(label_names)}
label2id = {v: k for k, v in id2label.items()}
```

あとはそれらを `AutoModelForTokenClassification.from_pretrained()` メソッドに渡せば、モデルの構成に設定され、適切に保存されて Hub にアップロードされます。

```py
from transformers import AutoModelForTokenClassification

model = AutoModelForTokenClassification.from_pretrained(
    model_checkpoint,
    id2label=id2label,
    label2id=label2id,
)
```

[第3章](/course/ja/chapter3) で `AutoModelForSequenceClassification` を定義したときのように、モデルを作成すると、いくつかの重みが使われていない（事前学習済みモデルのヘッド部の重み）、他のいくつかの重みがランダムに初期化されている（新しく接続したトークン分類ヘッドの重み）、このモデルはトレーニングする必要があるという警告が表示されます。トレーニングはすぐにでも実行できますが、まずはこのモデルが正しい数のラベルを持つことを再確認しましょう。

```python
model.config.num_labels
```

```python out
9
```

<Tip warning={true}>

⚠️ ラベルの数が間違っているモデルがあると、後で `model.fit()` を呼び出すときによくわからないエラー（"CUDA error: device-side assert triggered"のようなエラー）が発生します。このようなエラーはユーザーから報告されるバグの原因として一番多いものです。このチェックを必ず行い、期待通りのラベル数であることを確認してください。

</Tip>

### モデルの微調整

これでモデルを学習する準備が整いました！
しかし、`Trainer`を定義する前に、最後に2つのことをする必要があります。

Hugging Faceにログインし、学習用ハイパーパラメータを定義する必要があります。もしNotebookで作業しているなら、これを助ける便利な関数があります。

```python
from huggingface_hub import notebook_login

notebook_login()
```

これにより、Hugging Faceのログイン情報を入力するウィジェットが表示されます。

Notebookで作業していない場合は、ターミナルに次の行を入力するだけです。

```bash
huggingface-cli login
```

完了したら、`TrainingArguments`を定義する事ができるようになります。

```python
from transformers import TrainingArguments

args = TrainingArguments(
    "bert-finetuned-ner",
    evaluation_strategy="epoch",
    save_strategy="epoch",
    learning_rate=2e-5,
    num_train_epochs=3,
    weight_decay=0.01,
    push_to_hub=True,
)
```

これらのパラメータのほとんどは以前に見たことがあると思います。

ハイパーパラメータ（学習率、学習エポック数、ウェイト減衰など）を設定し、`push_to_hub=True` を指定して、モデルを保存して各エポック終了時に評価し、その結果をモデルハブにアップロードすることを指示します。


なお、 `hub_model_id` 引数でプッシュ先のリポジトリ名を指定できます (特に、特定の組織（organization）にプッシュする場合は、この引数を使用する必要があります)。例えば、[`huggingface-course` organization](https://huggingface.co/huggingface-course) にモデルをプッシュする場合、`TrainingArguments` に `hub_model_id="huggingface-course/bert-finetuned-ner"` を追加しました。

デフォルトでは、使用されるリポジトリはあなたの名前が使われ、設定した出力ディレクトリちなんだ名前、例えば今回の例では `"sgugger/bert-finetuned-ner"` となります。

<Tip>
💡 使用する出力ディレクトリが既に存在する場合は、プッシュしたいリポジトリのローカルクローンである必要があります。そうでない場合は、`Trainer` を定義する際にエラーが発生し、新しい名前を設定する必要があります。

</Tip>

最後に、すべてを `Trainer` に渡して、トレーニングを開始するだけです。

```python
from transformers import Trainer

trainer = Trainer(
    model=model,
    args=args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    compute_metrics=compute_metrics,
    tokenizer=tokenizer,
)
trainer.train()
```

学習が行われている間、モデルが保存されるたびに（ここではエポックごとに）バックグラウンドでHubにアップロードされることに注意してください。このようにして、必要に応じて別のマシンで学習を再開することができます。

学習が完了したら、`push_to_hub()` メソッドを使用して、最新バージョンのモデルをアップロードするようにします。

```py
trainer.push_to_hub(commit_message="Training complete")
```

このコマンドは、今行ったコミットの URL を返すので、それを検査したい場合は、このコマンドを使用します。

```python out
'https://huggingface.co/sgugger/bert-finetuned-ner/commit/26ab21e5b1568f9afeccdaed2d8715f571d786ed'
```

また、`Trainer`はすべての評価結果を含むモデルカードを起草し、アップロードします。この段階で、Model Hub上の推論ウィジェットを使ってモデルをテストし、友人と共有することができます。これで、トークン分類タスクのモデル微調整に成功しました。
おめでとうございます！

もう少し深く学習ループについて学びたい場合は、🤗 Accelerate を使って同じことをする方法を紹介します。

## カスタムトレーニングループ

それでは、必要な部分を簡単にカスタマイズできるように、トレーニングループの全体像を見てみましょう。これは、[第3章](/course/ja/chapter3/4) で行ったこととよく似ていますが、評価のために少し変更が加えられています。

### トレーニングのための準備

まず、データセットから `DataLoader` を作成する必要があります。ここでは、`data_collator` を `collate_fn` として再利用し、トレーニングセットをシャッフルします。ただし、検証セットはシャッフルしません。

```py
from torch.utils.data import DataLoader

train_dataloader = DataLoader(
    tokenized_datasets["train"],
    shuffle=True,
    collate_fn=data_collator,
    batch_size=8,
)
eval_dataloader = DataLoader(
    tokenized_datasets["validation"], collate_fn=data_collator, batch_size=8
)
```

次に、モデルの再定義を行います。これは、以前の微調整を継続するのではなく、BERTで事前学習したモデルから再び開始することを確認するためです。

```py
model = AutoModelForTokenClassification.from_pretrained(
    model_checkpoint,
    id2label=id2label,
    label2id=label2id,
)
```

それから、オプティマイザが必要になります。ここでは、古典的な `AdamW` を使用します。これは `Adam` のようなものですが、重みの減衰の適用方法を修正したものです。

```py
from torch.optim import AdamW

optimizer = AdamW(model.parameters(), lr=2e-5)
```

これらのオブジェクトをすべて取得したら、それらを `accelerator.prepare()` メソッドに送ります。

```py
from accelerate import Accelerator

accelerator = Accelerator()
model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare(
    model, optimizer, train_dataloader, eval_dataloader
)
```

<Tip>

🚨 TPUでトレーニングする場合は、上のセルから始まるコードを全て専用のトレーニング関数に移動する必要があります。詳しくは[第3章](/course/ja/chapter3)を参照してください。

</Tip>

これで `train_dataloader` を `accelerator.prepare()` に送ったので、そのデータ長を用いて学習ステップ数を計算することができます。このメソッドはdataloaderの長さを変更するので、常にdataloaderを準備した後に行う必要があることを忘れないでください。ここでは、学習率から0まで古典的な線形スケジュールを使用します。

```py
from transformers import get_scheduler

num_train_epochs = 3
num_update_steps_per_epoch = len(train_dataloader)
num_training_steps = num_train_epochs * num_update_steps_per_epoch

lr_scheduler = get_scheduler(
    "linear",
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=num_training_steps,
)
```

最後に、モデルをHubにプッシュするために、作業フォルダに `Repository` オブジェクトを作業フォルダに作成する必要があります。まず、まだログインしていなければHugging Faceにログインしてください。モデルに付与したいモデルIDからリポジトリ名を決定します。（`repo_name`は自由に置き換えてください；ユーザー名を含む必要があるだけで、これは関数 `get_full_repo_name()` が行っている事です）。

```py
from huggingface_hub import Repository, get_full_repo_name

model_name = "bert-finetuned-ner-accelerate"
repo_name = get_full_repo_name(model_name)
repo_name
```

```python out
'sgugger/bert-finetuned-ner-accelerate'
```

そして、そのリポジトリをローカルフォルダーにクローンすることができます。すでに存在するのであれば、このローカルフォルダーは作業中のリポジトリの既存のクローンであるべきです。

```py
output_dir = "bert-finetuned-ner-accelerate"
repo = Repository(output_dir, clone_from=repo_name)
```

これで `repo.push_to_hub()` メソッドを呼び出すことで、`output_dir` に保存したものをアップロードできるようになりました。これにより、各エポック終了時に中間モデルをアップロードすることができます。

### 学習ループ

これで学習ループを書く準備ができました。
評価部分を簡略化するため、`postprocess()` 関数を簡単に定義します。
この関数は予測値とラベルを受け取って `metric` オブジェクトが期待するような文字列のリストに変換します。

```py
def postprocess(predictions, labels):
    predictions = predictions.detach().cpu().clone().numpy()
    labels = labels.detach().cpu().clone().numpy()

    # Remove ignored index (special tokens) and convert to labels
    true_labels = [[label_names[l] for l in label if l != -100] for label in labels]
    true_predictions = [
        [label_names[p] for (p, l) in zip(prediction, label) if l != -100]
        for prediction, label in zip(predictions, labels)
    ]
    return true_labels, true_predictions
```

次に、トレーニングループを書きます。トレーニングの進捗を確認するためのプログレスバーを定義した後、ループは3つのパートに分かれます。

- 学習そのもの。`train_dataloader`に対する古典的な繰り返しで、モデルを前方に伝播させ、後方に逆伝播させ、最適化のステップを行います。

- 評価。モデルの出力をバッチで取得した後に、新しい事をします。2つのプロセスで入力とラベルを異なる形状にパディングしているかもしれないので、`gather()`メソッドを呼ぶ前に `accelerator.pad_across_processes()` を使って予測値とラベルを同じ形状にする必要があるのです。これを行わないと、評価がエラーになるか、永遠にハングアップします。そして、結果を `metric.add_batch()` に送り、評価ループが終了したら `metric.compute()` を呼び出します。

- 保存とアップロード。まずモデルとtokenizerを保存し、次に `repo.push_to_hub()` を呼び出します。引数 `blocking=False` を使って、🤗 Hub libraryに非同期処理でプッシュするように指示していることに注意してください。この指定をすると、トレーニングは通常通り行われ、この（長い時間のかかる）命令はバックグラウンドで実行されます。

以下は、トレーニングループの完全なコードです。


```py
from tqdm.auto import tqdm
import torch

progress_bar = tqdm(range(num_training_steps))

for epoch in range(num_train_epochs):
    # Training
    model.train()
    for batch in train_dataloader:
        outputs = model(**batch)
        loss = outputs.loss
        accelerator.backward(loss)

        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        progress_bar.update(1)

    # Evaluation
    model.eval()
    for batch in eval_dataloader:
        with torch.no_grad():
            outputs = model(**batch)

        predictions = outputs.logits.argmax(dim=-1)
        labels = batch["labels"]

        # Necessary to pad predictions and labels for being gathered
        predictions = accelerator.pad_across_processes(predictions, dim=1, pad_index=-100)
        labels = accelerator.pad_across_processes(labels, dim=1, pad_index=-100)

        predictions_gathered = accelerator.gather(predictions)
        labels_gathered = accelerator.gather(labels)

        true_predictions, true_labels = postprocess(predictions_gathered, labels_gathered)
        metric.add_batch(predictions=true_predictions, references=true_labels)

    results = metric.compute()
    print(
        f"epoch {epoch}:",
        {
            key: results[f"overall_{key}"]
            for key in ["precision", "recall", "f1", "accuracy"]
        },
    )

    # Save and upload
    accelerator.wait_for_everyone()
    unwrapped_model = accelerator.unwrap_model(model)
    unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save)
    if accelerator.is_main_process:
        tokenizer.save_pretrained(output_dir)
        repo.push_to_hub(
            commit_message=f"Training in progress epoch {epoch}", blocking=False
        )
```

今回初めて🤗 Accelerateで保存されたモデルをご覧になる方のために、それに付随する3行のコードを少し点検してみましょう。

```py
accelerator.wait_for_everyone()
unwrapped_model = accelerator.unwrap_model(model)
unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save)
```

最初の行は明らかです。この行は、すべてのプロセスに、全プロセスがその行に達するまで、処理を待つよう指示します。これは、保存する前に、すべてのプロセスが同じモデルになっている事を確認するためです。次に `unwrapped_model` を取得します。これは定義したベースモデルです。`accelerator.prepare()` メソッドは分散して学習するようにモデルを変更するので、`save_pretrained()` メソッドを持たなくなります。`accelerator.unwrap_model()` メソッドはそのステップを元に戻します。最後に、`save_pretrained()` を呼び出しますが、このメソッドには `torch.save()` の代わりに `accelerator.save()` を使用するように指示します。

これが完了すると、`Trainer` で学習したものとほぼ同じ結果を得ることができるモデルができあがります。このコードを使って学習したモデルは [*huggingface-course/bert-finetuned-ner-accelerate*](https://huggingface.co/huggingface-course/bert-finetuned-ner-accelerate) で確認することができます。また、学習ループの微調整を試したい場合は、上に示したコードを編集することで直接実装することができます!

{/if}

## 微調整したモデルを使う

Model Hubで微調整したモデルを推論ウィジェットで使用する方法は既に紹介しました。ローカル環境の`pipeline`で使用する場合は、モデル識別子を指定します。


```py
from transformers import pipeline

# Replace this with your own checkpoint
model_checkpoint = "huggingface-course/bert-finetuned-ner"
token_classifier = pipeline(
    "token-classification", model=model_checkpoint, aggregation_strategy="simple"
)
token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.")
```

```python out
[{'entity_group': 'PER', 'score': 0.9988506, 'word': 'Sylvain', 'start': 11, 'end': 18},
 {'entity_group': 'ORG', 'score': 0.9647625, 'word': 'Hugging Face', 'start': 33, 'end': 45},
 {'entity_group': 'LOC', 'score': 0.9986118, 'word': 'Brooklyn', 'start': 49, 'end': 57}]
```

素晴らしい！
私たちのモデルは、このパイプラインのデフォルトのものと同じように動作しています！


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter7/2.mdx" />

### パート1終了！
https://huggingface.co/learn/course/ja/chapter4/5.md

# パート1終了！

<CourseFloatingBanner
    chapter={4}
    classNames="absolute z-10 right-0 top-0"
/>

これでコースのパート1は終了です！パート2は11月15日に開催される、大きなコミュニティイベントで公開される予定です。詳しくは[こちら](https://huggingface.co/blog/course-launch-event)をご覧ください。

これで、テキスト分類問題（単一または文のペア）に対する学習済みモデルのファインチューニングを行い、結果をモデルハブにアップロードできるようになりました。この最初のセクションを確実にマスターするためには、自分の興味のある問題（英語でなくてもよい）をきっちりやっておくことが必要です。[Hugging Face forums](https://discuss.huggingface.co/)で助けを求めることもできますし、完成したら[this topic](https://discuss.huggingface.co/t/share-your-projects/6803)でプロジェクトを共有することもできます。

何ができるか楽しみです！


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter4/5.mdx" />

### ハギングフェイスハブ
https://huggingface.co/learn/course/ja/chapter4/1.md

# ハギングフェイスハブ

<CourseFloatingBanner
    chapter={4}
    classNames="absolute z-10 right-0 top-0"
/>

[ハギングフェイスハブ](https://huggingface.co/)（Hugging Face Hub） –- 私たちのメインウェブサイト –- は、誰もが新しい最先端のモデルやデータセットを発見し、利用し、貢献することができるプラットフォームです。様々なモデルをホストしており、10,000以上のモデルが一般に公開されています。この章ではモデルに焦点を当て、第5章ではデータセットについて見ていきます。

ハブにあるモデルは、🤗 Transformersや、そもそもNLPモデルに限りません。例えば、[Flair](https://github.com/flairNLP/flair)や[AllenNLP](https://github.com/allenai/allennlp)からはNLPモデルが、[Asteroid](https://github.com/asteroid-team/asteroid)や[pyannote](https://github.com/pyannote/pyannote-audio)からは音声モデルが、そして[timm](https://github.com/rwightman/pytorch-image-models)からは画像モデルがそれぞれ寄贈されています。

これらのモデルはそれぞれGitリポジトリとしてホストされており、バージョン管理および再現性を担保しています。ハブでモデルを共有することは、モデルをコミュニティに開放し、誰でも簡単に利用できるようにすることであり、その結果、モデルを自分で学習する必要がなくなり、共有と利用が容易になります。

さらに、ハブ上でモデルを共有すると、そのモデルに対する推論APIが自動的にデプロイ・ホストされます。コミュニティの誰もが、カスタム入力と適切なウィジェットを使って、モデルのページで直接自由にテストすることができます。

ハブで公開されているモデルの共有や使用は、完全に無料です！非公開でモデルを共有したい場合は、[有料プラン](https://huggingface.co/pricing)も存在します。

以下のビデオでは、ハブの操作方法を紹介しています。

<Youtube id="XvSGPZFEjDY"/>

ハブでリポジトリの作成と管理を行うため、これ以降はハギングフェイスアカウントが必要になります：[アカウント作成](https://huggingface.co/join)。

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter4/1.mdx" />

### 学習済みモデルを共有する
https://huggingface.co/learn/course/ja/chapter4/3.md

# 学習済みモデルを共有する

{#if fw === 'pt'}

<CourseFloatingBanner chapter={4}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter4/section3_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter4/section3_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={4}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter4/section3_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter4/section3_tf.ipynb"},
]} />

{/if}

以下のステップでは、学習済みモデルを🤗ハブに共有する最も簡単な方法について見ていきます。ハブ上で直接モデルを共有し、更新できるツールやユーティリティが用意されていますので、以下、それを見ていきます。

<Youtube id="9yY3RB_GSPM"/>

たとえ非常に特殊なデータセットで学習させたとしても、モデルをコミュニティに共有することをお勧めします。他のユーザーの時間と計算資源を節約し、有用な学習済みモデルを提供することができるからです。代わりに、他の人の成果物の恩恵を受けることもできます！

新しいモデルリポジトリを作成するには、次の3つの方法があります：

- `push_to_hub` APIを使用する
- `huggingface_hub` Pythonライブラリを使用する
- ウェブインターフェイスを使用する

リポジトリを作成したら、git と git-lfs を使ってリポジトリにファイルをアップロードすることができます。以下のセクションでは、モデルリポジトリを作成し、ファイルをアップロードする方法を説明します。

## `push_to_hub` APIを使用する

{#if fw === 'pt'}

<Youtube id="Zh0FfmVrKX0"/>

{:else}

<Youtube id="pUh5cGmNV8Y"/>

{/if}

ハブにファイルをアップロードする最も簡単な方法は、`push_to_hub` API を使うことです。

先に進む前に、あなたが誰で、どのネームスペースに書き込み権限があるのかを通知するために、認証トークンを生成しましょう。`transformers`がインストールされている環境であることを確認してください（[セットアップ](/course/chapter0)を参照のこと）。ノートブックの場合は、以下の関数を使ってログインすることができます：

```python
from huggingface_hub import notebook_login

notebook_login()
```

ターミナル上では次の通りです:

```bash
huggingface-cli login
```

どちらの場合も、ユーザー名とパスワードの入力を求められますが、これはハブにログインするときに使用するものと同じです。まだハブのプロフィールをお持ちでない方は、[こちら](https://huggingface.co/join)から作成してください。

これで、認証トークンがキャッシュフォルダに保存されました。それでは、リポジトリを作成しましょう！

{#if fw === 'pt'}

`Trainer`API を使ってモデルを学習させたのであれば、 `TrainingArguments`において`push_to_hub=True`と設定することで、最も簡単にハブにアップロードすることができます：

```py
from transformers import TrainingArguments

training_args = TrainingArguments(
    "bert-finetuned-mrpc", save_strategy="epoch", push_to_hub=True
)
```

`trainer.train()`を実行すると、モデルを保存する度に（ここではエポック毎に）`Trainer`はモデルをレポジトリにアップロードします。このリポジトリは出力ディレクトリと同じ名前になりますが（この例では`bert-finetuned-mrpc`）、`hub_model_id = "a_different_name"`とすることで別の名前を指定することができます。

あなたが所属する組織にモデルをアップロードするには、`hub_model_id = "my_organization/my_repo_name"`とすればよいです。

学習が終了したら、最後に `trainer.push_to_hub()` を実行して、モデルの最終版をアップロードしてください。この際、使用したハイパーパラメータと評価結果など、全ての関連するメタデータを含むモデルカードが生成されます！以下に、モデルカードに含まれる内容の例を示します。

<div class="flex justify-center">
  <img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/model_card.png" alt="An example of an auto-generated model card." width="100%"/>
</div>

{:else}

モデルの学習にKerasを使用している場合、最も簡単にアップロードする方法は`PushToHubCallback`を`model.fit()`に渡すことです：

```py
from transformers import PushToHubCallback

callback = PushToHubCallback(
    "bert-finetuned-mrpc", save_strategy="epoch", tokenizer=tokenizer
)
```

そして、`model.fit()`の呼び出しに`callbacks=[callback]`を追加してください。モデルを保存する度に（ここではエポック毎に）コールバックはモデルをリポジトリにアップロードします。このリポジトリは出力ディレクトリと同じ名前になりますが（この例では`bert-finetuned-mrpc`）、`hub_model_id = "a_different_name"`とすることで別の名前を指定することができます。

あなたが所属する組織にモデルをアップロードするには、`hub_model_id = "my_organization/my_repo_name"`とすればよいです。

{/if}

より低いレベルでは、モデル、トークナイザー、および設定オブジェクトの `push_to_hub()` メソッドを通じて、モデルハブへのアクセスを直接行うことができます。このメソッドは、リポジトリの作成と、モデルやトークナイザーのリポジトリへのプッシュの両方を行います。後述するAPIとは異なり、手動で操作する必要はありません。

その仕組みを理解するために、まずモデルとトークナイザーを初期化してみましょう：

{#if fw === 'pt'}
```py
from transformers import AutoModelForMaskedLM, AutoTokenizer

checkpoint = "camembert-base"

model = AutoModelForMaskedLM.from_pretrained(checkpoint)
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
```
{:else}
```py
from transformers import TFAutoModelForMaskedLM, AutoTokenizer

checkpoint = "camembert-base"

model = TFAutoModelForMaskedLM.from_pretrained(checkpoint)
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
```
{/if}

これらを使って、トークナイザーにトークンを追加したり、モデルを学習させたり、微調整したりと、好きなことを自由に行うことができます。出来上がったモデル、重み、トークナイザーに満足したら、`model` オブジェクトから直接利用できる`push_to_hub()`メソッドを活用できます：

```py
model.push_to_hub("dummy-model")
```

これであなたのプロファイルに新しいリポジトリ `dummy-model` が作成され、モデルファイルがそこに格納されます。すべてのファイルがこのリポジトリで利用できるよう、トークナイザーにも同様に実行してください：

```py
tokenizer.push_to_hub("dummy-model")
```

組織に所属している場合、`organization`引数を指定することで当該組織のネームスペースにアップロードできます：

```py
tokenizer.push_to_hub("dummy-model", organization="huggingface")
```

特定のHugging Faceトークンを使うこともできます：

```py
tokenizer.push_to_hub("dummy-model", organization="huggingface", use_auth_token="<TOKEN>")
```

さあ、新しくアップロードしたモデルをモデルハブで見てみましょう：*https://huggingface.co/user-or-organization/dummy-model*.

"Files and versions"タブをクリックすると、これらのファイルが表示されるはずです：

{#if fw === 'pt'}
<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/push_to_hub_dummy_model.png" alt="Dummy model containing both the tokenizer and model files." width="80%"/>
</div>
{:else}
<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/push_to_hub_dummy_model_tf.png" alt="Dummy model containing both the tokenizer and model files." width="80%"/>
</div>
{/if}

<Tip>

✏️ **やってみよう！** `bert-base-cased`チェックポイントに関連付けられたモデルとトークナイザーを、`push_to_hub()`メソッドを使って自分のネームスペースにあるリポジトリにアップロードします。レポジトリを削除する前に、レポジトリがあなたのページに正しく表示されることを確認してください。

</Tip>

これまで見てきたように、`push_to_hub()`メソッドはいくつかの引数をとるので、特定のリポジトリや組織のネームスペースにアップロードしたり、別のAPI トークンを使用したりすることが可能です。詳細については、[🤗 Transformers documentation](https://huggingface.co/transformers/model_sharing.html)で仕様を確認することをお勧めします。

この`push_to_hub()`メソッドは、ハギングフェイスハブに直接アクセスできる[`huggingface_hub`](https://github.com/huggingface/huggingface_hub) Pythonパッケージで実装されており、🤗 Transformersや、[`allenlp`](https://github.com/allenai/allennlp)といった、他の機械学習ライブラリに統合されています。この章では🤗 Transformersに焦点を当てますが、あなた自身のコードやライブラリに統合することは簡単です。

最後のセクションに移動して、新しく作成したリポジトリにファイルをアップロードする方法をご覧ください！

## `huggingface_hub` Pythonライブラリを使用する

`huggingface_hub` Pythonライブラリは、モデルとデータセットのハブのためのツールセットを提供するパッケージです。ハブ上のリポジトリに関する情報を取得し、それらを管理するような一般的なタスクのためのシンプルなメソッドとクラスを提供します。また、これらのリポジトリのコンテンツを管理し、あなたのプロジェクトやライブラリにハブを統合するために、gitの上で動作するシンプルなAPIを提供します。

`push_to_hub` API を使用する場合と同様に、APIトークンをキャッシュに保存しておく必要があります。これを行うには、前のセクションで説明したように、CLI から `login` コマンドを使用する必要があります (Google Colab で実行する場合は、これらのコマンドの前に `!` 文字を付加してください)：

```bash
huggingface-cli login
```

`huggingface_hub` パッケージには、便利なメソッドとクラスがいくつかあります。まず、リポジトリの作成と削除を管理するためのメソッドがいくつかあります：

```python no-format
from huggingface_hub import (
    # ユーザー管理
    login,
    logout,
    whoami,

    # レポジトリの作成と管理
    create_repo,
    delete_repo,
    update_repo_visibility,

    # そして、コンテンツに関する情報を取得／変更するためのいくつかのメソッド
    list_models,
    list_datasets,
    list_metrics,
    list_repo_files,
    upload_file,
    delete_file,
)
```


さらに、ローカルリポジトリを管理するための非常に強力な `Repository` クラスを提供しています。これらのメソッドやクラスをどのように活用するかについては、次のセクションで説明します。

`create_repo` メソッドを使用すると、ハブに新しいリポジトリを作成できます：

```py
from huggingface_hub import create_repo

create_repo("dummy-model")
```

これで、あなたのネームスペースに `dummy-model` というリポジトリが作成されます。もし必要なら、 `organization` 引数で所属する組織を指定することもできます：

```py
from huggingface_hub import create_repo

create_repo("dummy-model", organization="huggingface")
```

あなたがその組織に所属していると仮定して、これで`huggingface`ネームスペースに `dummy-model` リポジトリが作成されます。その他の便利な引数は以下の通りです。

- `private`：リポジトリを他から見えるようにするかどうかを指定します。
- `token`：キャッシュに保存されているトークンではない、別のトークンを指定します。
- `repo_type`：モデルではなく「データセット」や「スペース」のレポジトリを作成します。指定できる値は`"dataset"`と`"space"`です。

レポジトリが作成できたらファイルを追加してみましょう！次のセクションに移動して、3つの方法を見てみましょう。


## ウェブインターフェイスを使う

ウェブインタフェースでは、ハブのリポジトリを直接管理することができます。このインターフェイスを使って、リポジトリの作成、ファイル（大きなものも！）の追加、モデルの検索、差分の可視化など、さまざまなことが簡単にできます。

レポジトリを新しく作るには、[huggingface.co/new](https://huggingface.co/new)にアクセスして下さい：

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/new_model.png" alt="Page showcasing the model used for the creation of a new model repository." width="80%"/>
</div>

まず、リポジトリの所有者を指定します。これはあなた自身か、あなたが所属する組織のいずれかになります。組織を選択した場合、モデルは組織のページで紹介され、組織の全メンバーがリポジトリに貢献することができるようになります。

次に、モデルの名前を入力します。これはリポジトリの名前にもなります。最後に、モデルをパブリックにするかプライベートにするかを指定します。プライベートモデルは、一般公開されないモデルです。

モデルリポジトリを作成すると、このようなページが表示されるはずです：

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/empty_model.png" alt="An empty model page after creating a new repository." width="80%"/>
</div>

これは、あなたのモデルがホストされる場所です。ウェブインターフェースから直接、モデルにREADMEファイルを追加してみましょう。

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/dummy_model.png" alt="The README file showing the Markdown capabilities." width="80%"/>
</div>

READMEファイルはMarkdownで書かれています - どうぞ自由に使ってください。この章の第三部は、モデルカードの作成に専念します。モデルカードはそのモデルができることを他の人に伝える場所であり、あなたのモデルに価値を与えるために最も重要なものです。

"Files and versions"タブを見ると、まだ多くのファイルがないことがわかります。先ほど作成した *README.md* と、大きなファイルを追跡するための *.gitattributes* ファイルがあるだけです。

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/files.png" alt="The 'Files and versions' tab only shows the .gitattributes and README.md files." width="80%"/>
</div>

次は、新しいファイルを追加する方法について見てみましょう。

## モデルファイルのアップロード

ハギングフェイスハブでのファイル管理の仕組みは、通常のファイルはgit、大きなファイルはgit-lfs ([Git Large File Storage](https://git-lfs.github.com/)の略)をベースにしています。

次のセクションでは、ハブにファイルをアップロードする3つの方法について説明します: `huggingface_hub` と git コマンドです。

### `upload_file`を使ったアプローチ

`upload_file` を使用する場合、git や git-lfs がシステムにインストールされている必要はありません。HTTP POST リクエストを使用して、ファイルを直接 🤗 ハブにプッシュします。この方法の制限は、5GB を超えるサイズのファイルを扱えないことです。5GB を超えるファイルを扱う場合は、以下に説明する他の2つの方法に従ってください。

本APIは次のように使用することができます：

```py
from huggingface_hub import upload_file

upload_file(
    "<path_to_file>/config.json",
    path_in_repo="config.json",
    repo_id="<namespace>/dummy-model",
)
```

これは、リポジトリのルートである `<path_to_file>` にある `config.json` というファイルを `dummy-model` リポジトリにアップロードすることになります。
その他便利な引数は次の通りです：

- `token`、キャッシュに保存されているトークンではない、別のトークンを指定します。
- `repo_type`、モデルではなく「データセット」や「スペース」のレポジトリを作成します。指定できる値は`"dataset"`と`"space"`です。


### `Repository`クラス

`Repository` クラスは、gitに似た方法でローカルリポジトリを管理します。このクラスは、gitであれば苦労する点のほとんどを抽象化してくれます。

このクラスを使用するには、git と git-lfs がインストールされている必要があります。そのため、始める前に git-lfs をインストールし（インストール方法は[こちら](https://git-lfs.github.com/)を参照）、セットアップしておく必要があります。

作成したリポジトリでいろいろ試してみるために、リモートリポジトリをクローンしてローカルフォルダに初期化することから始めましょう：

```py
from huggingface_hub import Repository

repo = Repository("<path_to_dummy_folder>", clone_from="<namespace>/dummy-model")
```

作業ディレクトリに `<path_to_dummy_folder>` というフォルダが作成されます。このフォルダには `.gitattributes` というファイルだけが存在しているはずです。これは、`create_repo` でリポジトリを作成する際に作成される唯一のファイルだからです。

これ以降、従来のgitのメソッドのいくつかを使用することができます：

```py
repo.git_pull()
repo.git_add()
repo.git_commit()
repo.git_push()
repo.git_tag()
```

その他にも同様のメソッドがあります！利用可能なすべてのメソッドの概要については、[こちら](https://github.com/huggingface/huggingface_hub/tree/main/src/huggingface_hub#advanced-programmatic-repository-management)にある `Repository` のドキュメントをご覧になることをお勧めします。

現在、私たちはハブにプッシュしたいモデルとトークナイザーを持っていると仮定します。リポジトリのクローンには成功し、そのリポジトリ内にファイルを保存することができるはずです。

まず、ローカルのクローンから最新の変更を取り込み、最新の状態にします：

```py
repo.git_pull()
```

それが終わったら、モデルファイルとトークナイザーファイルを保存します：

```py
model.save_pretrained("<path_to_dummy_folder>")
tokenizer.save_pretrained("<path_to_dummy_folder>")
```

`<path_to_dummy_folder>` には、すべてのモデルファイルとトークナイザーファイルが格納されています。通常の git ワークフローに従って、ファイルをステージング・エリアに追加し、コミットしてハブにプッシュします。

```py
repo.git_add()
repo.git_commit("Add model and tokenizer files")
repo.git_push()
```

おめでとうございます！あなたは今、最初のファイルをハブにプッシュしました。

### gitベースのアプローチ

これは、ファイルをアップロードするための必要最小限なアプローチで、gitとgit-lfsを直接使います。これまでのアプローチでは困難なことのほとんどは抽象化されていますが、このアプローチにはいくつかの注意点があります。より複雑なユースケースで説明していきます。

このクラスを使用するには、git と git-lfs がインストールされている必要があります。そのため、始める前に[git-lfs](https://git-lfs.github.com/)をインストールし（インストール方法はこちらを参照）、セットアップしておいてください。

まず最初に git-lfs を初期化することから始めます：

```bash
git lfs install
```

```bash
Updated git hooks.
Git LFS initialized.
```

それが終わったら、まず最初にモデルリポジトリをクローンします：

```bash
git clone https://huggingface.co/<namespace>/<your-model-id>
```

私のユーザ名は `lysandre` で、モデル名は `dummy` としたので、私の場合、コマンドは以下のようになります：

```
git clone https://huggingface.co/lysandre/dummy
```

作業ディレクトリに*dummy*という名前のフォルダができました。このフォルダに `cd` して、中身を見ることができます：

```bash
cd dummy && ls
```

```bash
README.md
```

ハギングフェイスハブの `create_repo` メソッドを使ってリポジトリを作成したばかりの場合、このフォルダーには `.gitattributes` という隠しファイルだけが存在しているはずです。前のセクションの指示に従ってウェブインターフェースを使用してリポジトリを作成した場合、このフォルダーには、ここに示すように、`.gitattributes` ファイルと一緒に*README.md* ファイルだけが存在しているはずです。

設定ファイルや語彙ファイルなど、基本的に数メガバイト以下の通常サイズのファイルを追加することは、gitベースのシステムで行うのとまったく同じように行われます。しかし、より大きなファイルを *huggingface.co* にプッシュするには、git-lfs を通して登録する必要があります。

Pythonに少し戻って、ダミーリポジトリにコミットするモデルとトークナイザを生成してみましょう：

{#if fw === 'pt'}
```py
from transformers import AutoModelForMaskedLM, AutoTokenizer

checkpoint = "camembert-base"

model = AutoModelForMaskedLM.from_pretrained(checkpoint)
tokenizer = AutoTokenizer.from_pretrained(checkpoint)

# モデルを使って、トレーニングしたり、微調整したり...。

model.save_pretrained("<path_to_dummy_folder>")
tokenizer.save_pretrained("<path_to_dummy_folder>")
```
{:else}
```py
from transformers import TFAutoModelForMaskedLM, AutoTokenizer

checkpoint = "camembert-base"

model = TFAutoModelForMaskedLM.from_pretrained(checkpoint)
tokenizer = AutoTokenizer.from_pretrained(checkpoint)

# モデルを使って、トレーニングしたり、微調整したり...。

model.save_pretrained("<path_to_dummy_folder>")
tokenizer.save_pretrained("<path_to_dummy_folder>")
```
{/if}

さて、モデルとトークナイザーのアーティファクトをいくつか保存したので、*dummy* フォルダーをもう一度見てみましょう。

```bash
ls
```

{#if fw === 'pt'}
```bash
config.json  pytorch_model.bin  README.md  sentencepiece.bpe.model  special_tokens_map.json tokenizer_config.json  tokenizer.json
```

ファイルサイズを見ると（たとえば `ls -lh` で）、モデル状態のディクショナリファイル (*pytorch_model.bin*) が唯一、400 MB 以上あることがわかると思います。

{:else}
```bash
config.json  README.md  sentencepiece.bpe.model  special_tokens_map.json  tf_model.h5  tokenizer_config.json  tokenizer.json
```

ファイルサイズを見ると（たとえば `ls -lh` で）、モデル状態のディクショナリファイル (*t5_model.h5*) が唯一、400 MB 以上あることがわかると思います。

{/if}

<Tip>
✏️ ウェブインターフェースからリポジトリを作成する場合、*.gitattributes* ファイルは自動的に *.bin* や *.h5* などの特定の拡張子を持つファイルを大きなファイルとみなすように設定され、git-lfs がそれらを追跡するようになります。ユーザー側で別途設定を行う必要はありません。
</Tip> 

これで、従来の Git リポジトリと同じように作業を進められるようになりました。すべてのファイルを Git のステージング環境に追加するには、`git add` コマンドを使います：

```bash
git add .
```

そして、現在ステージングされているファイルを見ることができます：

```bash
git status
```

{#if fw === 'pt'}
```bash
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
  modified:   .gitattributes
	new file:   config.json
	new file:   pytorch_model.bin
	new file:   sentencepiece.bpe.model
	new file:   special_tokens_map.json
	new file:   tokenizer.json
	new file:   tokenizer_config.json
```
{:else}
```bash
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
  modified:   .gitattributes
  	new file:   config.json
	new file:   sentencepiece.bpe.model
	new file:   special_tokens_map.json
	new file:   tf_model.h5
	new file:   tokenizer.json
	new file:   tokenizer_config.json
```
{/if}

同様に、git-lfs が正しいファイルを追跡しているかどうかを `status` コマンドで確認することができます：

```bash
git lfs status
```

{#if fw === 'pt'}
```bash
On branch main
Objects to be pushed to origin/main:


Objects to be committed:

	config.json (Git: bc20ff2)
	pytorch_model.bin (LFS: 35686c2)
	sentencepiece.bpe.model (LFS: 988bc5a)
	special_tokens_map.json (Git: cb23931)
	tokenizer.json (Git: 851ff3e)
	tokenizer_config.json (Git: f0f7783)

Objects not staged for commit:


```

`LFS`で処理される*pytorch_model.bin* と *sentencepiece.bpe.model* を除き、すべてのファイルが `Git` で処理されることが分かります。素晴らしい！

{:else}
```bash
On branch main
Objects to be pushed to origin/main:


Objects to be committed:

	config.json (Git: bc20ff2)
	sentencepiece.bpe.model (LFS: 988bc5a)
	special_tokens_map.json (Git: cb23931)
	tf_model.h5 (LFS: 86fce29)
	tokenizer.json (Git: 851ff3e)
	tokenizer_config.json (Git: f0f7783)

Objects not staged for commit:


```

`LFS`で処理される*t5_model.h5*を除き、すべてのファイルが `Git` で処理されることが分かります。素晴らしい！

{/if}

最後のステップ、コミットと*huggingface.co*リモートリポジトリへのプッシュへと進みましょう：

```bash
git commit -m "First model version"
```

{#if fw === 'pt'}
```bash
[main b08aab1] First model version
 7 files changed, 29027 insertions(+)
  6 files changed, 36 insertions(+)
 create mode 100644 config.json
 create mode 100644 pytorch_model.bin
 create mode 100644 sentencepiece.bpe.model
 create mode 100644 special_tokens_map.json
 create mode 100644 tokenizer.json
 create mode 100644 tokenizer_config.json
```
{:else}
```bash
[main b08aab1] First model version
 6 files changed, 36 insertions(+)
 create mode 100644 config.json
 create mode 100644 sentencepiece.bpe.model
 create mode 100644 special_tokens_map.json
 create mode 100644 tf_model.h5
 create mode 100644 tokenizer.json
 create mode 100644 tokenizer_config.json
```
{/if}

プッシュは、インターネットの接続速度やファイルの大きさによって、少し時間がかかることがあります：

```bash
git push
```

```bash
Uploading LFS objects: 100% (1/1), 433 MB | 1.3 MB/s, done.
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 12 threads
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 288.27 KiB | 6.27 MiB/s, done.
Total 9 (delta 1), reused 0 (delta 0), pack-reused 0
To https://huggingface.co/lysandre/dummy
   891b41d..b08aab1  main -> main
```

{#if fw === 'pt'}
これが終了した時点でモデルリポジトリを見てみると、最近追加されたすべてのファイルを見ることができます：

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/full_model.png" alt="The 'Files and versions' tab now contains all the recently uploaded files." width="80%"/>
</div>

このUIでは、モデルファイルやコミットを探索したり、各コミットでの差分を確認することができます：

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/diffs.gif" alt="The diff introduced by the recent commit." width="80%"/>
</div>
{:else}
これが終了した時点でモデルリポジトリを見てみると、最近追加されたすべてのファイルを見ることができます：

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/full_model_tf.png" alt="The 'Files and versions' tab now contains all the recently uploaded files." width="80%"/>
</div>

このUIでは、モデルファイルやコミットを探索したり、各コミットでの差分を確認することができます：

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/diffstf.gif" alt="The diff introduced by the recent commit." width="80%"/>
</div>
{/if}


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter4/3.mdx" />

### チャプター修了クイズ
https://huggingface.co/learn/course/ja/chapter4/6.md

# チャプター修了クイズ

<CourseFloatingBanner
    chapter={4}
    classNames="absolute z-10 right-0 top-0"
/>

この章で学んだことを確認してみましょう！
  
### 1. ハブにアップロードできるモデルには何か制限があるでしょうか？

<Question
	choices={[
		{
			text: "🤗 Transformersライブラリのモデルに制限される。",
			explain: "🤗 Transformersライブラリのモデルはハギングフェイスハブでサポートされていますが、それだけではありません！"
		},
		{
			text: "🤗 Transformersと似たインターフェイスを備えたモデルに制限される。",
			explain: "どんなインターフェイスのモデルでもハギングフェイスハブにアップロードすることができます。"
		},
		{
			text: "制限はありません。",
			explain: "正解です！どんなモデルでもハブにアップロードすることができます。",
            correct: true
		},
        {
			text: "NLPに関連したモデルに制限される。",
			explain: "どんな分野のモデルでも構いません！"
		}
	]}
/>

### 2. ハブではどうやってモデルを管理すればよいでしょうか？

<Question
	choices={[
		{
			text: "GCPアカウントを通じて",
			explain: "Incorrect!"
		},
		{
			text: "P2P配信を通じて",
			explain: "Incorrect!"
		},
		{
			text: "gitとgit-lfsを通じて",
			explain: "正解です！ハブ上のモデルは単にGitのレポジトリで、大きなファイルには<code>git-lfs</code>を活用しています。",
            correct: true
		}
	]}
/>

### 3. ハギングフェイスハブのウェブインターフェイスを使うと何ができるでしょうか？

<Question
	choices={[
		{
			text: "既存のレポジトリをフォークできる。",
			explain: "ハギングフェイスハブではレポジトリのフォークはできません。"
		},
		{
			text: "モデルレポジトリの新規作成ができる。",
			explain: "正解です！でもそれだけではありません。",
            correct: true
		},
		{
			text: "ファイルの管理と編集ができる。",
			explain: "正解です！でもそれだけではありません。",
            correct: true
		},
        {
			text: "ファイルのアップロードができる。",
			explain: "正解です！でもそれだけではありません。",
            correct: true
		},
        {
			text: "バージョン間の差異を確認できる。",
			explain: "正解です！でもそれだけではありません。",
            correct: true
		}
	]}
/>

### 4. モデルカードとは何でしょう？

<Question
	choices={[
		{
			text: "モデルの概要なので、モデルやトークナイザーのファイルよりは重要ではない。",
			explain: "確かにモデルの説明ですが、とても重要な情報です。もし不完全であったり、なかったりすると、モデルの有用性が激減してしまいます。"
		},
		{
			text: "再現性、再利用性、公平性を確保するための方法です。",
			explain: "正解です！モデルカードで正しい情報を共有することで、ユーザーはモデルを活用し、その限界と偏りを認識することができます。",
            correct: true
		},
		{
			text: "モデルの情報を取得するためのPythonファイルです。",
			explain: "モデルカードは単純なマークダウンファイルです。"
		}
	]}
/>

### 5. これらの🤗 Transformersライブラリのオブジェクトのうち、 `push_to_hub()` を使ってハブ上で直接共有できるものはどれでしょうか？

{#if fw === 'pt'}
<Question
	choices={[
		{
			text: "トークナイザー",
			explain: "正解です！全てのトークナイザーは<code>push_to_hub</code>メソッドを備えており、全てのトークナイザーファイル（ボキャブラリー、トークナイザーのアーキテクチャ、等々）をレポジトリにプッシュすることができます。でもこれだけが正解ではありません。",
            correct: true
		},
		{
			text: "モデルの設定",
			explain: "正解です！全てのモデル設定は<code>push_to_hub</code>メソッドを備えており、レポジトリにプッシュすることができます。その他に共有できるものは何でしょうか？",
            correct: true
		},
		{
			text: "モデル",
			explain: "正解です！全てのモデルは<code>push_to_hub</code>メソッドを備えており、モデルとその設定ファイルをレポジトリにプッシュすることができます。でも他にも共有できるものがあります。",
            correct: true
		},
        {
			text: "トレーナー",
			explain: "正解です！<code>Trainer</code>も<code>push_to_hub</code>メソッドを備えており、モデル、モデル設定、トークナイザー、モデルカードの下書きを、レポジトリにプッシュすることができます。その他の正解も当ててみましょう！",
            correct: true
		}
	]}
/>
{:else}
<Question
	choices={[
		{
			text: "トークナイザー",
			explain: "正解です！全てのトークナイザーは<code>push_to_hub</code>メソッドを備えており、全てのトークナイザーファイル（ボキャブラリー、トークナイザーのアーキテクチャ、等々）をレポジトリにプッシュすることができます。でもこれだけが正解ではありません。",
            correct: true
		},
		{
			text: "モデルの設定",
			explain: "正解です！全てのモデル設定は<code>push_to_hub</code>メソッドを備えており、レポジトリにプッシュすることができます。その他に共有できるものは何でしょうか？",
            correct: true
		},
		{
			text: "モデル",
			explain: "正解です！<code>Trainer</code>も<code>push_to_hub</code>メソッドを備えており、モデル、モデル設定、トークナイザー、モデルカードの下書きを、レポジトリにプッシュすることができます。その他の正解も当ててみましょう！",
            correct: true
		},
		{
			text: "専用のコールバックを備えた上記の全て",
			explain: "正解です！<code>PushToHubCallback</code>は学習中、定期的にこれらのオブジェクトをレポジトリに送信します。",
            correct: true
		}
	]}
/>
{/if}

### 6. `push_to_hub()`メソッドやCLIツールを使用する際の最初のステップは何でしょうか？

<Question
	choices={[
		{
			text: "ウェブサイトにログインする。",
			explain: "これはローカルマシンでは役に立ちません。"
		},
		{
			text: "ターミナル上で'huggingface-cli login'と実行する。",
			explain: "正解です。これでパーソナルトークンをダウンロードし、キャッシュします。",
            correct: true
		},
		{
			text: "ノートブック上で'notebook_login()'と実行する。",
			explain: "正解です。これで認証画面を表示します。",
            correct: true
		},
	]}
/>

### 7. モデルとトークナイザーはどうやってハブにアップロードすればよいですか？

<Question
	choices={[
		{
			text: "モデルとトークナイザーの`push_to_hub`メソッドを直接実行する。",
			explain: "正解です！",
            correct: true
		},
		{
			text: "Pythonランタイム上で、これらを<code>huggingface_hub</code>ユーティリティでラップする。",
			explain: "モデルとトークナイザーは既に<code>huggingface_hub</code>ユーティリティの恩恵を受けています。追加のラッピングは必要はありません。"
		},
		{
			text: "ディスクに保存して、<code>transformers-cli upload-model</code>を実行する。",
			explain: "<code>upload-model</code>というコマンドは存在しません。"
		}
	]}
/>

### 8. `Repository`クラスでできる git 操作はなんでしょう？

<Question
	choices={[
		{
			text: "コミット",
			explain: "正解です。<code>git_commit()</code>メソッドはそのためにあります。",
            correct: true
		},
		{
			text: "プル",
			explain: "それが<code>git_pull()</code>メソッドの目的です。",
            correct: true
		},
		{
			text: "プッシュ",
			explain: "これを行うのが<code>git_push()</code>メソッドです。",
            correct: true
		},
		{
			text: "マージ",
			explain: "このAPIを通してのマージは、未来永劫絶対にできません。"
		}
	]}
/>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter4/6.mdx" />

### モデルカードを作成する
https://huggingface.co/learn/course/ja/chapter4/4.md

# モデルカードを作成する

<CourseFloatingBanner
    chapter={4}
    classNames="absolute z-10 right-0 top-0"
/>

モデルカードは、モデルリポジトリにおいて、モデルファイルやトークナイザーファイルと同じくらい重要なファイルです。モデルの主要な定義であり、コミュニティメンバーによる再利用と結果の再現性を保証し、さらには他のメンバーが成果物を構築するためのプラットフォームを提供します。

また、使用したデータや前処理・後処理に関する十分な情報を提供することで、モデルの限界、バイアス、有用となる場面の特定及び理解が可能になります。

そのため、モデルを明確に定義したモデルカードを作成することは、非常に重要なステップとなります。ここでは、これに役立ついくつかのヒントを提供します。モデルカードの作成は、先ほど見た*README.md*ファイル、つまりMarkdownファイルを通して行います。

「モデルカード」のコンセプトは、Googleの研究方針に端を発し、Margaret Mitchellらの論文["Model Cards for Model Reporting"](https://arxiv.org/abs/1810.03993)で初めて公開されました。ここに含まれる多くの情報は、その論文に基づいており、再現性、再利用性、公平性を重視する世界において、なぜモデルカードが重要であるかを理解するには、この論文をご覧になることをお勧めします。

モデルカードは通常、何のためのモデルなのかという非常に簡潔でハイレベルな概要から始まり、これらの追加の詳細が説明されます：

- モデル概要
- 使用目的・制限
- 使用方法
- 制限とバイアス
- 学習データ
- 学習手順
- 評価結果

それでは、それぞれのセクションの内容について見ていきましょう。

### モデル概要

モデルの概要では、モデルに関する基本的な詳細を説明します。これには、アーキテクチャ、バージョン、論文で紹介されたかどうか、オリジナルの実装があるかどうか、作者、モデルに関する一般的な情報などが含まれます。著作権についてはここに記載すべきです。学習方法、パラメータ、重要な免責事項に関する一般的な情報もこのセクションに記載することができます。

### 使用目的・制限

ここでは、モデルが適用される言語、フィールド、ドメインなど、そのモデルが想定するユースケースを記述します。モデルカードのこのセクションは、モデルの適用範囲外であることが分かっている領域や、最適でない性能を発揮する可能性がある領域も記述することができます。

### 使用方法

このセクションでは、モデルの使い方の例をいくつか紹介します。これは`pipeline()`関数の使い方、モデルクラスとトークナイザークラスの使い方、そしてその他に役立つコードを紹介することができます。

### 学習データ

この部分は、モデルがどのデータセットで学習されたかを示す必要があります。データセットの簡単な説明でも大丈夫です。

### 学習手順

このセクションでは、再現性の観点から有用となる、学習に関する全てを記述する必要があります。これには、データに対して行われた前処理や後処理、モデルの学習エポック数、バッチサイズ、学習レートなどの詳細が含まれます。

### 変数とメトリクス

ここでは、評価のために使用したメトリクスと、測定しているさまざまな要因を記述します。どのデータセットで、どのデータセットを分割して、どのメトリクスを使用したかを記述することで、他のモデルの性能と比較することが容易になります。これらの情報は、前のセクション（想定されるユーザーやユースケースなど）から得たものであるべきです。

### 評価結果

最後に、評価用データセットにおいて、モデルがどの程度うまく機能するかの指標を提供します。モデルが閾値を使用する場合、評価に使用した閾値を提供するか、または想定する用途に応じた異なる閾値での評価に関する詳細を提供します。

## 例

よくできたモデルカードの例として、これらをご覧ください：

- [`bert-base-cased`](https://huggingface.co/bert-base-cased)
- [`gpt2`](https://huggingface.co/gpt2)
- [`distilbert`](https://huggingface.co/distilbert-base-uncased)

さまざまな組織や企業によるその他の事例は、[こちら](https://github.com/huggingface/model_card/blob/master/examples.md)からご覧いただけます。

## 注釈

モデルカードはモデルを公開する際の必須条件ではありませんし、モデルを作成する際に上記のセクションをすべて含める必要はありません。しかし、モデルを明確に文書化することは、必ず将来のユーザーのためになるので、できるだけ多くのセクションを埋めることをお勧めします。

## モデルカードメタデータ

ハギングフェイスハブを少しみてみると、いくつかのモデルが特定のカテゴリに属していることがわかるはずです：タスク、言語、ライブラリなどでフィルタリングすることができます。モデルが属するカテゴリーは、モデルカードのヘッダーに追加されたメタデータによって識別されます。

例えば、[`camembert-base`モデルカード](https://huggingface.co/camembert-base/blob/main/README.md)を見てみると、モデルカードのヘッダに以下のような行があるはずです：

```
---
language: fr
license: mit
datasets:
- oscar
---
```

このメタデータはハギングフェイスハブによって解析され、このモデルがOscarデータセットで学習されたMITライセンスのフランス語のモデルであることが特定されます。

[モデルカード全仕様](https://github.com/huggingface/hub-docs/blame/main/modelcard.md)では、言語、ライセンス、タグ、データセット、メトリクス、および学習時にモデルが得た評価結果を記述することができます。


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter4/4.mdx" />

### 学習済みモデルを使う
https://huggingface.co/learn/course/ja/chapter4/2.md

# 学習済みモデルを使う

{#if fw === 'pt'}

<CourseFloatingBanner chapter={4}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter4/section2_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter4/section2_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={4}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter4/section2_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter4/section2_tf.ipynb"},
]} />

{/if}

モデルハブは適切なモデルを簡単に選択できるようにし、どのライブラリからでも数行のコードで使用できるようにします。では、実際にこれらのモデルをどのように使用し、どのようにコミュニティに貢献するかを見ていきましょう。

例えば、マスクフィルを行えるフランス語のモデルを探しているとします。

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/camembert.gif" alt="Selecting the Camembert model." width="80%"/>
</div>

試しに`camembert-base`チェックポイントを選択してみましょう。camembert-base`という識別子があれば、すぐに使い始めることができます。これまでの章で見てきたように、 `pipeline()` 関数を使用してインスタンスを作成することができます：

```py
from transformers import pipeline

camembert_fill_mask = pipeline("fill-mask", model="camembert-base")
results = camembert_fill_mask("Le camembert est <mask> :)")
```

```python out
[
  {'sequence': 'Le camembert est délicieux :)', 'score': 0.49091005325317383, 'token': 7200, 'token_str': 'délicieux'}, 
  {'sequence': 'Le camembert est excellent :)', 'score': 0.1055697426199913, 'token': 2183, 'token_str': 'excellent'}, 
  {'sequence': 'Le camembert est succulent :)', 'score': 0.03453313186764717, 'token': 26202, 'token_str': 'succulent'}, 
  {'sequence': 'Le camembert est meilleur :)', 'score': 0.0330314114689827, 'token': 528, 'token_str': 'meilleur'}, 
  {'sequence': 'Le camembert est parfait :)', 'score': 0.03007650189101696, 'token': 1654, 'token_str': 'parfait'}
]
```

ご覧の通り、パイプライン内でのモデルのロードは非常に簡単です。唯一気をつけなければならないのは、選択したチェックポイントが使用するタスクに適しているかということです。例えば、ここでは`camembert-base`というチェックポイントを`fill-mask`というパイプラインでロードしていますが、これは全く問題ありません。しかし、このチェックポイントを`text-classification`パイプラインでロードしたとすると、`camembert-base`の「ヘッド」がこのタスクに適していないため、結果が意味をなさないことになります！適切なチェックポイントを選択するために、ハギングフェイスハブインタフェースにあるタスクセレクタを使用することをお勧めします：

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/tasks.png" alt="The task selector on the web interface." width="80%"/>
</div>

また、モデル・アーキテクチャを直接使用して、チェックポイントをインスタンス化することもできます：

{#if fw === 'pt'}
```py
from transformers import CamembertTokenizer, CamembertForMaskedLM

tokenizer = CamembertTokenizer.from_pretrained("camembert-base")
model = CamembertForMaskedLM.from_pretrained("camembert-base")
```

しかし、代わりに[`Auto*` classes](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes)を使用することをお勧めします。これらは設計上、（モデル）アーキテクチャに依存しないためです。先ほどのコードサンプルでは、CamemBERT アーキテクチャでロード可能なチェックポイントに限定していましたが、 `Auto*`クラスを使用すると、チェックポイントを簡単に切り替えることができます：

```py
from transformers import AutoTokenizer, AutoModelForMaskedLM

tokenizer = AutoTokenizer.from_pretrained("camembert-base")
model = AutoModelForMaskedLM.from_pretrained("camembert-base")
```
{:else}
```py
from transformers import CamembertTokenizer, TFCamembertForMaskedLM

tokenizer = CamembertTokenizer.from_pretrained("camembert-base")
model = TFCamembertForMaskedLM.from_pretrained("camembert-base")
```

しかし、代わりに[`TFAuto*` classes](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes)を使用することをお勧めします。これらは設計上、アーキテクチャに依存しないためです。先ほどのコードサンプルでは、CamemBERT アーキテクチャでロード可能なチェックポイントに限定していましたが、 `TFAuto*`クラスを使用すると、チェックポイントを簡単に切り替えることができます：

```py
from transformers import AutoTokenizer, TFAutoModelForMaskedLM

tokenizer = AutoTokenizer.from_pretrained("camembert-base")
model = TFAutoModelForMaskedLM.from_pretrained("camembert-base")
```
{/if}

<Tip>
学習済みのモデルを使う場合は、どのように学習したのか、どのデータセットで学習したのか、その限界と偏りを必ず確認すること。これらの情報はすべて、モデルカードに記載されています。
</Tip>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter4/2.mdx" />

### イントロダクション
https://huggingface.co/learn/course/ja/chapter8/1.md

# イントロダクション

<CourseFloatingBanner
    chapter={8}
    classNames="absolute z-10 right-0 top-0"
/>

🤗 Transformers　を使いながらNLPタスクに取り組む方法がわかった後、自分自身のプロジェクトを簡単に始めることができます!　この章では、エラーにぶつかったときにどうすればよいかを深く探ります。自分のコードやトレーニングを正確にデバッグする方法、そして自分でエラーを解決できない場合にコミュニティに助けを求める方法を一緒に学びましょう。また、HuggingFace (ハギングフェイス) ライブラリのひとつにバグを見つけたと思ったら、その問題をできるだけ早く解決するため報告する方法を紹介します。

この章では、一緒に次のことを学びます：

-　エラーを見つけた時に最初にすること
-　[ハギングフェイス フォーラム](https://discuss.huggingface.co/)の中で助けの求め方
-　トレーニングパイプラインのデバグ方法
-　良いGitHubイシューの書き方

もちろん、このどれもが🤗 Transformersやハギングフェイスのエコシステムと特別な関係はありません。この章から得られる教訓は、ほとんどのオープンソースプロジェクトに適用可能です

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter8/1.mdx" />

### パート２終了!
https://huggingface.co/learn/course/ja/chapter8/6.md

# パート２終了!

<CourseFloatingBanner
    chapter={8}
    classNames="absolute z-10 right-0 top-0"
/>

お疲れ様でした。第２部を無事に完了しました！今は第３部について働いてるので情報を見逃せないように我々の[ニュースレター](https://huggingface.curated.co/)に応募して下さい！

今は、様々なNLPタスクに取り組み、その上でモデルを微調整またはプリトレーニングできるようになったはずです！その結果を [モデルハブ] (https://huggingface.co/models) でコミュニティと共有することを忘れないでください。

皆さんがコースのお陰に得た知識で何を作るのか、楽しみです！

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter8/6.mdx" />

### エラーを見つけた時に最初にすること
https://huggingface.co/learn/course/ja/chapter8/2.md

# エラーを見つけた時に最初にすること

<CourseFloatingBanner chapter={8}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/ja/chapter8/section2.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/ja/chapter8/section2.ipynb"},
]} />

このセクションでは、新しくチューニングされたTransformerモデルから予測を生成しようとするときに起こる事ができる、いくつかの一般的なエラーについて見ていきましょう。これは[セクション4](/course/chapter8/section4)の準備となり、学習段階をデバッグする方法を見ていきましょう。

<Youtube id="DQ-CpJn6Rc4"/>

この章の為に[テンプレートレポジトリー](https://huggingface.co/lewtun/distilbert-base-uncased-finetuned-squad-d5716d28)を用意しました。この章のコードを実行したい場合は、まずモデルを[ハギングフェイスハブ（Hugging Face Hub）](https://huggingface.co)のアカウントにコピーする必要があります。まずJupyterNotebookでログインしましょう

```python
from huggingface_hub import notebook_login

notebook_login()
```

それとも、ターミナルを使いながら:

```bash
huggingface-cli login
```

ユーザー名とパスワードを入力する画面が表示されます。Authentification token が *~/.cache/huggingface/*の中にセーブされます。ログインした後に以下の機能でテンプレートリポジトリをコピーすることができます

```python
from distutils.dir_util import copy_tree
from huggingface_hub import Repository, snapshot_download, create_repo, get_full_repo_name


def copy_repository_template():
    # Clone the repo and extract the local path
    template_repo_id = "lewtun/distilbert-base-uncased-finetuned-squad-d5716d28"
    commit_hash = "be3eaffc28669d7932492681cd5f3e8905e358b4"
    template_repo_dir = snapshot_download(template_repo_id, revision=commit_hash)
    # Create an empty repo on the Hub
    model_name = template_repo_id.split("/")[1]
    create_repo(model_name, exist_ok=True)
    # Clone the empty repo
    new_repo_id = get_full_repo_name(model_name)
    new_repo_dir = model_name
    repo = Repository(local_dir=new_repo_dir, clone_from=new_repo_id)
    # Copy files
    copy_tree(template_repo_dir, new_repo_dir)
    # Push to Hub
    repo.push_to_hub()
```

`copy_repository_template()`機能はテンプレートレポジトリーをアカウントにコピーします。

## 🤗 Transformers　パイプラインのデバグ

Transformerモデルとパイプラインのデバッグという素晴らしい世界への旅を始めるにあたり、次のようなシナリオを考えてみましょう。あなたは同僚と一緒に、あるeコマースサイトに関するお客さんの答えを見つけられるように、'Question Answering'のプロジェクトに取り組んでいます。あなたの同僚はこんなメッセージを送りました。

> どうも! 先ほど、【第7章】(/course/chapter7/7)　のテクニックを使って実験をしたところ、SQuADデータセットで素晴らしい結果が得られました!Hub上のモデルIDは"lewtun/distilbert-base-uncased-finetuned-squad-d5716d28"です。このモデルをぜひテストしてみましょう!

さて、🤗 Transformers でモデルをロードするために　 `pipeline` を使いましょう！

```python
from transformers import pipeline

model_checkpoint = get_full_repo_name("distillbert-base-uncased-finetuned-squad-d5716d28")
reader = pipeline("question-answering", model=model_checkpoint)
```

```python out
"""
OSError: Can't load config for 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28'. Make sure that:

- 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is a correct model identifier listed on 'https://huggingface.co/models'

- or 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is the correct path to a directory containing a config.json file
"""
```

残念！どうしてもエラーが発生しました。プログラミングが初めての方はこんなメッセージは怖そうに見えます。(`OSError`は何？)。このようなエラーは、_Python traceback_ と呼ばれる、より大きなエラーレポートの最後の部分です。このエラーは、Google Colabで実行した場合には、次のような画像が表示されます。

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/traceback.png" alt="A Python traceback." width="100%"/>
</div>

このレポートには多くの情報が含まれているので、主要な部分を一緒に見ていきましょう。まず注意すべきは、トレースバックは下から上へ読むということです（日本語の逆の読み方ですね！）。これは、エラートレースバックが、モデルとトークナイザーをダウンロードするときに `pipeline` が行う一連の関数呼び出しを反映していますいます（詳しくは[第２章](/course/chapter2)）をご覧下さい。

<Tip>

🚨 Google Colabのトレースバックで、「6frames」のあたりに青い枠があるのが見えますか？これはColabの特別な機能で、トレースバックを "フレーム "に圧縮しているのです。もしエラーの原因が詳しく見つからないようであれば、この2つの小さな矢印をクリックして、トレースバックの全容を拡大してみてください。

</Tip>

これは、トレースバックの最後の行が、発生したエラーの名前を与えることをします。エラーのタイプは `OSError` で、これはシステム関連のエラーを示しています。付属のエラーメッセージを読むと、モデルの *config.json* ファイルに問題があるようで、それを修正するための2つの提案を与えられています。
```python out
"""
Make sure that:

- 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is a correct model identifier listed on 'https://huggingface.co/models'

- or 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is the correct path to a directory containing a config.json file
"""
```

<Tip>

💡 理解しがたいエラーメッセージが表示された場合は、そのメッセージをコピーしてGoogle または [Stack Overflow](https://stackoverflow.com/) の検索バーに貼り付けてください！　そのエラーに遭遇したのはあなたが初めてではない可能性が高いですし、コミュニティの他の人が投稿した解決策を見つける良い方法です。例えば、`OSError: Can't load config for` を Stack Overflow で検索すると、いくつかの [ヒント](https://stackoverflow.com/search?q=OSError%3A+Can%27t+load+config+for+) が見付けられます。これは、問題解決の出発点として使うことができます。
</Tip>

最初の提案は、モデルIDが実際に正しいかどうかを確認するよう求めているので、まず、識別子をコピーしてHubの検索バーに貼り付けましょう。

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/wrong-model-id.png" alt="The wrong model name." width="100%"/>
</div>

うーん、確かに同僚のモデルはハブにないようだ...しかし、モデルの名前にタイプミスがある! DistilBERTの名前には「l」が1つしかないので、それを直して、代わりに「lewtun/distilbert-base-uncased-finetuned-squad-d5716d28」を探そう！
<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/true-model-id.png" alt="The right model name." width="100%"/>
</div>

さて、これでヒットしました。では、正しいモデルIDで再度ダウンロードをしてみましょう。

```python
model_checkpoint = get_full_repo_name("distilbert-base-uncased-finetuned-squad-d5716d28")
reader = pipeline("question-answering", model=model_checkpoint)
```

```python out
"""
OSError: Can't load config for 'lewtun/distilbert-base-uncased-finetuned-squad-d5716d28'. Make sure that:

- 'lewtun/distilbert-base-uncased-finetuned-squad-d5716d28' is a correct model identifier listed on 'https://huggingface.co/models'

- or 'lewtun/distilbert-base-uncased-finetuned-squad-d5716d28' is the correct path to a directory containing a config.json file
"""
```

ああ、また失敗だ。機械学習エンジニアの日常へようこそ！ モデルIDは修正できたので、問題はリポジトリ自体にあるはずです。🤗 Hub上のリポジトリの内容にアクセスする簡単な方法は、`huggingface_hub`ライブラリの `list_repo_files()` 関数を使用することです。

```python
from huggingface_hub import list_repo_files

list_repo_files(repo_id=model_checkpoint)
```

```python out
['.gitattributes', 'README.md', 'pytorch_model.bin', 'special_tokens_map.json', 'tokenizer_config.json', 'training_args.bin', 'vocab.txt']
```

リポジトリには *config.json* ファイルがないようです! どうりで `pipeline` がモデルを読み込めないわけです。同僚がこのファイルをHubにプッシュするのを忘れたに違いありません。この場合、問題を解決するのは簡単です。ファイルを追加するように依頼するか、モデルIDから使用された事前学習済みモデルが[`distilbert-base-uncased`](https://huggingface.co/distilbert-base-uncased)であることがわかるので、そのモデルのconfig（設定）をダウンロードし、我々のリポジトリにプッシュして問題が解決するか確認することができます。それでは試してみましょう。[第2章](/course/chapter2)で学んだテクニックを使って、`AutoConfig`クラスでモデルの設定をダウンロードすることができます。

```python
from transformers import AutoConfig

pretrained_checkpoint = "distilbert-base-uncased"
config = AutoConfig.from_pretrained(pretrained_checkpoint)
```

<Tip warning={true}>

🚨 同僚は `distilbert-base-uncased` の設定を間違えていじったかもしれないです。実際のところ、私たちはまず彼らに確認したいところですが、このセクションの目的では、彼らがデフォルトの設定を使用したと仮定することにします。
</Tip>


それで`push_to_hub()`　機能でモデルの設定をリポジトリにプッシュすることができます。


```python
config.push_to_hub(model_checkpoint, commit_message="Add config.json")
```

そしては、最新のコミットを `main` ブランチから読み込こんでみましょう。

```python
reader = pipeline("question-answering", model=model_checkpoint, revision="main")

context = r"""
Extractive Question Answering is the task of extracting an answer from a text
given a question. An example of a question answering dataset is the SQuAD
dataset, which is entirely based on that task. If you would like to fine-tune a
model on a SQuAD task, you may leverage the
examples/pytorch/question-answering/run_squad.py script.

🤗 Transformers is interoperable with the PyTorch, TensorFlow, and JAX
frameworks, so you can use your favourite tools for a wide variety of tasks!
"""

question = "What is extractive question answering?"
reader(question=question, context=context)
```

```python out
{'score': 0.38669535517692566,
 'start': 34,
 'end': 95,
 'answer': 'the task of extracting an answer from a text given a question'}
```

やったね！ これで、お疲れ様でした。今までのことを一緒に振り返ってみましょう。

- Pythonのエラーメッセージは　__traceback__　と呼ばれ、下から上へと読み上げられます。エラーメッセージの最後の行は一番必要な情報を含んでいます。
- エラーメッセージが複雑な場合は、__traceback__　を読み上げながらエラーが発生したソースコードファイル名や行番号を指定して、エラーの原因を読み取ることができます。
- その場合でもデバグすることができないなら、インターネット上にを検索してみましょう。
- `huggingface_hub` ライブラリは、Hubのリポジトリを使用するため一連のツールを提供します。デバッグするために使用できるのツールも含めています。

パイプラインのデバッグ方法がわかったところで、モデルのフォワードパスで難しい例を見てみましょう。

## モデルのフォワードパスをデバッグ

時にはモデルのロジットにアクセスする必要があります（例えば、カスタムなパイプラインを使いたい場合で）。このような場合、何が問題になるかを知るために、まず `pipeline` からモデルとトークナイザーを取得してみましょう。

```python
tokenizer = reader.tokenizer
model = reader.model
```

次に必要なのは、お気に入りのフレームワークがサポートされているかどうかという質問です。

```python
question = "Which frameworks can I use?"
```

[第7章](/course/chapter7)で見たように、通常必要なステップは、入力のトークン、開始と終了トークンのロジット、そして解答スパンのデコードです。

```python
import torch

inputs = tokenizer(question, context, add_special_tokens=True)
input_ids = inputs["input_ids"][0]
outputs = model(**inputs)
answer_start_scores = outputs.start_logits
answer_end_scores = outputs.end_logits
# Get the most likely beginning of answer with the argmax of the score
answer_start = torch.argmax(answer_start_scores)
# Get the most likely end of answer with the argmax of the score
answer_end = torch.argmax(answer_end_scores) + 1
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}")
```

```python out
"""
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/var/folders/28/k4cy5q7s2hs92xq7_h89_vgm0000gn/T/ipykernel_75743/2725838073.py in <module>
      1 inputs = tokenizer(question, text, add_special_tokens=True)
      2 input_ids = inputs["input_ids"]
----> 3 outputs = model(**inputs)
      4 answer_start_scores = outputs.start_logits
      5 answer_end_scores = outputs.end_logits

~/miniconda3/envs/huggingface/lib/python3.8/site-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
   1049         if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1050                 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1051             return forward_call(*input, **kwargs)
   1052         # Do not call functions when jit is used
   1053         full_backward_hooks, non_full_backward_hooks = [], []

~/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/models/distilbert/modeling_distilbert.py in forward(self, input_ids, attention_mask, head_mask, inputs_embeds, start_positions, end_positions, output_attentions, output_hidden_states, return_dict)
    723         return_dict = return_dict if return_dict is not None else self.config.use_return_dict
    724
--> 725         distilbert_output = self.distilbert(
    726             input_ids=input_ids,
    727             attention_mask=attention_mask,

~/miniconda3/envs/huggingface/lib/python3.8/site-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
   1049         if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1050                 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1051             return forward_call(*input, **kwargs)
   1052         # Do not call functions when jit is used
   1053         full_backward_hooks, non_full_backward_hooks = [], []

~/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/models/distilbert/modeling_distilbert.py in forward(self, input_ids, attention_mask, head_mask, inputs_embeds, output_attentions, output_hidden_states, return_dict)
    471             raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
    472         elif input_ids is not None:
--> 473             input_shape = input_ids.size()
    474         elif inputs_embeds is not None:
    475             input_shape = inputs_embeds.size()[:-1]

AttributeError: 'list' object has no attribute 'size'
"""
```

おやおや、どうやらコードにバグがあるようですね。でも、ちょっとしたデバッグは怖くありません。Pythonのデバッガをノートブックで使うことができるのです。

<Youtube id="rSPyvPw0p9k"/>

それとも、ターミナルでデバッグを行うことができます:

<Youtube id="5PkZ4rbHL6c"/>

エラーメッセージを読むと、 `'list' object has no attribute 'size'` と、 `-->` 矢印が `model(**inputs)` の中で問題が発生した行を指していることが分かります。Pythonデバッガを使ってインタラクティブにデバッグできますが、今は単に `inputs` のスライスを表示して何があるか見てみましょう。

```python
inputs["input_ids"][:5]
```

```python out
[101, 2029, 7705, 2015, 2064]
```

これは確かに普通のPythonの `list` のように見えますが、再確認してみましょう。
```python
type(inputs["input_ids"])
```

```python out
list
```

これは確かにPythonの`list`ですね。では何がいけなかったのか？[第2章](/course/chapter2)で、🤗 Transformersの `AutoModelForXxx` クラスは _tensor_ (PyTorch または TensorFlow のいずれか)を使いながら、例えばPyTorchの `Tensor.size()`機能を呼び出しています。トレースバックをもう一度見て、どの行で例外が発生したかを確認しましょう。

```
~/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/models/distilbert/modeling_distilbert.py in forward(self, input_ids, attention_mask, head_mask, inputs_embeds, output_attentions, output_hidden_states, return_dict)
    471             raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
    472         elif input_ids is not None:
--> 473             input_shape = input_ids.size()
    474         elif inputs_embeds is not None:
    475             input_shape = inputs_embeds.size()[:-1]

AttributeError: 'list' object has no attribute 'size'
```

私たちのコードは `input_ids.size()` を呼び出そうとしたようですが、これは明らかにPythonの `list` に対して動作しません。どうすればこの問題を解決できるでしょうか？Stack Overflowでエラーメッセージを検索すると、関連する[ヒント](https://stackoverflow.com/search?q=AttributeError%3A+%27list%27+object+has+no+attribute+%27size%27&s=c15ec54c-63cb-481d-a749-408920073e8f) がかなり見つかります。

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/stack-overflow.png" alt="An answer from Stack Overflow." width="100%"/>
</div>

回答では、トークナイザーに `return_tensors='pt'` を追加することが推奨されているので、これがうまくいくかどうか見てみましょう。

```python out
inputs = tokenizer(question, context, add_special_tokens=True, return_tensors="pt")
input_ids = inputs["input_ids"][0]
outputs = model(**inputs)
answer_start_scores = outputs.start_logits
answer_end_scores = outputs.end_logits
# Get the most likely beginning of answer with the argmax of the score
answer_start = torch.argmax(answer_start_scores)
# Get the most likely end of answer with the argmax of the score
answer_end = torch.argmax(answer_end_scores) + 1
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}")
```

```python out
"""
Question: Which frameworks can I use?
Answer: pytorch, tensorflow, and jax
"""
```

Stack Overflowがいかに有用であるかを示す素晴らしい例です。同様の問題を特定することで、コミュニティの他の人々の経験から恩恵を受けることができました。しかし、このような検索では、常に適切な回答が得られるとは限りません。では、このような場合、どうすればいいのでしょうか？幸い、[ハギングフェイスフォーラム（Hugging Face forums）](https://discuss.huggingface.co/)には、開発者たちの歓迎するコミュニティがあり、あなたを助けてくれるでしょう。次のセクションでは、回答が得られる可能性の高い、良いフォーラムの質問を作成する方法を見ていきます。

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter8/2.mdx" />

### パート2公開記念イベント
https://huggingface.co/learn/course/ja/events/2.md

# パート2公開記念イベント

パート2のコース公開後、Fine-tuningのスプリントの前に、2日間のトークライブイベントが開催されました。
詳細については以下のページから見ることが出来ます。


## 1日目: Transformersライブラリとその学習方法を俯瞰する

**Thomas Wolf:** *転移学習とTransformersライブラリの誕生*

<div class="flex justify-center">
<Youtube id="wCYVeahJES0"/>
</div>

<p align="center">
<img src="https://i.imgur.com/9eq8oUi.png" alt="Thomasによるトークの概要図" width="80%"/>
</p>

Thomas Wolfは、Hugging Faceの共同設立者であり、主任研究員です。
彼とHugging Faceチームが作成したツールは、Facebook人工知能研究所、Googleリサーチ、DeepMind、Amazonリサーチ、Apple、アレン人工知能研究所、および多くの大学を含む5,000以上の研究機関に使用されています。
Thomas Wolfは人工知能の分野における最大の研究機関の創始者であり、[BigScience](https://bigscience.huggingface.co)をはじめとする、世界で広く利用されている[ライブラリやツール](https://github.com/huggingface/)の開発者です。
加えて、人工知能と自然言語処理の分野におけるリーダーであり、世界中のカンファレンスに定期的に招待されるスピーカーです。[https://thomwolf.io](https://thomwolf.io).


**Jay Alammar:** *Transformersモデルの学習方法の可視化*

<div class="flex justify-center">
<Youtube id="VzvG23gmcYU"/>
</div>

<p align="center">
<img src="https://i.imgur.com/rOZAuE9.png" alt="Jayによるトークの概要図" width="80%"/>
</p>

Jay Alammarは機械学習ツールやコンセプトを基本的なもの（NumPyやPandasのドキュメント）から最先端のもの（Transformers、BERT、GPT-3）まで視覚的に理解できるようなブログを書いています。

**Margaret Mitchell:** *機械学習開発における価値観*

<div class="flex justify-center">
<Youtube id="8j9HRMjh_s8"/>
</div>

<p align="center">
<img src="https://i.imgur.com/NuIsnY3.png" alt="Margaretによるトークの概要図" width="80%"/>
</p>

Margaret Mitchellは、Ethical AIの研究者であり、現在、企業におけるAI開発の倫理的な観点に焦点をあてて研究しています。
彼女は自然言語生成、支援技術、コンピュータビジョン、およびAI倫理に関する50以上の論文を発表し、会話生成と感情分類の分野で複数の特許を保有しています。
以前はGoogle AIにリサーチサイエンティストとして勤務しており、Google&#39;s Ethical AIグループを設立、リーダーとしてAI倫理の基礎研究およびGoogle内部でのAI倫理の運用に注力していました。
Google入社以前は、Microsoft Researchで画像からの言語生成に焦点を当てた研究員、ジョンズ・ホプキンズ大学でベイズモデリングと情報抽出に焦点を当てたポスドクを務めていました。
アバディーン大学でコンピュータサイエンスの博士号を、ワシントン大学で計算言語学の修士号を取得しています。
学位を取得する傍ら、2005年から2012年まで、オレゴン健康科学大学で機械学習、神経障害、支援技術に関する研究に従事していました。
彼女は多様性やコンピュータサイエンス、倫理などの多くの分野でワークショップや活動を率先して行ってきました。
彼女の研究は、アッシュ・カーター国防長官や米国盲人財団から表彰され、複数のテクノロジー企業で導入されています。
ちなみに彼女はガーデニングと犬、猫が好きです。

**Matthew Watson and Chen Qian:** *Kerasによる自然言語処理のワークフロー*

<div class="flex justify-center">
<Youtube id="gZIP-_2XYMM"/>
</div>

<p align="center">
<img src="https://i.imgur.com/1vD2az8.png" alt="MatthewとChenによるトークの概要図" width="80%"/>
</p>

Matthew Watsonは、Kerasチームの機械学習エンジニアで、ハイレベルのモデリングAPIの開発を行っています。
スタンフォード大学でコンピュータグラフィックスを専攻し、修士号を取得しました。
彼はもともと英語を専攻していましたが、コンピュータサイエンスに転向ました。
分野を超えて仕事をし、より多くの人が自然言語処理にアクセスできるようにすることに情熱を傾けています。

Chen QianはKerasチームのソフトウェアエンジニアで、彼もハイレベルのモデリングAPIの開発を行っています。
スタンフォード大学で電気工学の修士号を取得しました。
機械学習タスクのコード実装の簡素化と大規模機械学習に特に興味を持っています。

**Mark Saroufim:** *Pytorchでモデルを学習させる方法*

<div class="flex justify-center">
<Youtube id="KmvPlW2cbIo"/>
</div>

<p align="center">
<img src="https://i.imgur.com/TPmlkm8.png" alt="Markによるトークの概要図" width="80%"/>
</p>

Mark SaroufimはPytorchのパートナーエンジニアで、TorchServeやPytorch Enterpriseを含むOSSの開発に携わっています。
以前はGraphcore、[yuri.ai](http://yuri.ai/)、Microsoft、NASAのジェット推進研究所で応用科学者、プロダクトマネージャーを務めていました。
プログラミングをもっと楽しくすることに情熱を注いでいます。


**Jakob Uszkoreit:** *壊れてないものは<del>直すな</del>壊そう*

<div class="flex justify-center">
<Youtube id="C6jweXYFHSA"/>
</div>

<p align="center">
<img src="https://i.imgur.com/5dWQeNB.png" alt="Jakobによるトークの概要図" width="80%"/>
</p>

Jakob Uszkoreitは、ディープラーニングを用いてワクチンや治療薬のためのRNA分子を設計している機関であるInceptiveの共同創設者です。
InceptiveはRNAベースの医薬品をより入手しやすく、より効果的で、より広く適用できるようにすることを目標にしています。
以前はGoogleに10年以上勤務し、Google Brain、 Research and Searchの研究開発チームを率いて、ディープラーニングの基礎、コンピュータビジョン、言語理解、機械翻訳に取り組んでいました。


## 2日目: 使用するツールの紹介

**Lewis Tunstall:** *🤗 TransformersのTrainerを使ったシンプルな学習*

<div class="flex justify-center">
<Youtube id="u--UVvH-LIQ"/>
</div>

Lewis TunstallはHugging Faceの機械学習エンジニアで、オープンソースのツールを開発し、より広いコミュニティで利用できるようにすることに注力しています。
また、オライリーの書籍[Natural Language Processing with Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/)の共著者でもあります。
Twitter (@_lewtun) では、自然言語処理に関するtipsを紹介しています.


**Matthew Carrigan:** *TensorFlowの新機能として追加された🤗 Transformersと🤗 Datasets*

<div class="flex justify-center">
<Youtube id="gQUlXp1691w"/>
</div>

Matthew CarriganはTransformersでTensorFlowのメンテナンスを担当しています。
彼はいずれTwitterアカウント@carrigmatを通じて、PyTorch派に対するTensorflow派のリーダーとなるでしょう。

**Lysandre Debut:** *機械学習プロジェクトのコラボレーションと共有の手段としてのHugging Face Hub*

<div class="flex justify-center">
<Youtube id="RBw1TmdEZp0"/>
</div>

<p align="center">
<img src="https://i.imgur.com/TarIPCz.png" alt="Lysandreによるトークの概要図" width="80%"/>
</p>

Lysandre DebutはHugging Faceの機械学習エンジニアで、多くのオープンソースプロジェクトに携わっています。
彼の目的は、非常にシンプルなAPIを持つ強力なツールを開発することで、機械学習を誰にでもアクセスできるようにすることです。

**Lucile Saulnier:** *🤗 Transformersと🤗 Tokenizersで自分だけのトークナイザーを手に入れる*

<div class="flex justify-center">
<Youtube id="UkNmyTFKriI"/>
</div>

Lucile SaulnierはHugging Faceの機械学習エンジニアで、オープンソースツールの開発および使用支援を行っています。
彼女は協調学習やBigScienceなど、自然言語処理分野の多くの研究プロジェクトにも積極的に参加しています。

**Sylvain Gugger:** *PyTorchの学習効率を高める🤗 Accelerate*

<div class="flex justify-center">
<Youtube id="t8Krzu-nSeY"/>
</div>

Sylvain GuggerはHugging Faceのリサーチエンジニアで、🤗 Transformersのコアメンテナーの一人であり、🤗 Accelerateの開発者でもあります。
彼はモデルの学習をより身近なものにすることが好きです。

**Merve Noyan:** *モデルのデモを展示する🤗 Spaces*

<div class="flex justify-center">
<Youtube id="vbaKOa4UXoM"/>
</div>

Merve NoyanはHugging FaceのDeveloper Advocateで、誰もが機械学習を使うことが出来るように、ツールの開発とその周辺のコンテンツ構築に取り組んでいます。


**Abubakar Abid:** *機械学習アプリケーションを素早く構築する*

<div class="flex justify-center">
<Youtube id="c7mle2yYpwQ"/>
</div>

<p align="center">
<img src="https://i.imgur.com/qWIFeiF.png" alt="Abubakarによるトークの概要図" width="80%"/>
</p>

Abubakar Abidは[Gradio](www.gradio.app)のCEOです。
2015年にMITで電気工学とコンピュータサイエンスの理学士号を取得し、2021年にスタンフォードで応用機械学習の博士号を取得しました。
Gradioでは機械学習モデルのデモ、デバッグ、デプロイを容易にすることに取り組んでいます。

**Mathieu Desvé:** *AWSの機械学習のビジョン: すべての顧客が機械学習にアクセスできるようにする*

<div class="flex justify-center">
<Youtube id="O2e3pXO4aRE"/>
</div>

<p align="center">
<img src="https://i.imgur.com/oLdZTKy.png" alt="Mathieuによるトークの概要図" width="80%"/>
</p>

Mathieu Desvéはテクノロジー好きで、暇さえあればものづくりをしています。
クライアントとユーザーの問題解決に取り組むことが好きで、日々学び続けています。
2004年以来、フロントエンド、バックエンド、インフラストラクチャー、オペレーション、マネジメントなど、さまざまなポジションを経験してきました。
技術的、経営的に共通する問題を機敏に解決することを心がけています。

**Philipp Schmid:** *Amazon SageMakerと🤗 Transformersを使った学習管理*

<div class="flex justify-center">
<Youtube id="yG6J2Zfo8iw"/>
</div>

Philipp Schmidは、Hugging Faceの機械学習エンジニア兼テックリードで、Amazon SageMakerチームとの協業をリードしています。
最先端の自然言語処理モデルを誰もが使えるように製品化し、ディープラーニングの使いやすさを向上することに情熱を注いでいます。


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/events/2.mdx" />

### 複数系列の処理
https://huggingface.co/learn/course/ja/chapter2/5.md

# 複数系列の処理

{#if fw === 'pt'}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_tf.ipynb"},
]} />

{/if}

{#if fw === 'pt'}
<Youtube id="M6adb1j2jPI"/>
{:else}
<Youtube id="ROxrFOEbsQE"/>
{/if}

前のセクションでは、最も単純な使用例である、単一の短い系列（テキスト）に対して推論を行う方法を見てきました。しかし、これについて以下のような疑問をお持ちの方もいるかもしれません。

- 複数の系列をどのように処理するのか？
- 長さの異なる複数の系列をどのように処理するのか？
- モデルがうまく機能するためには、単語のインデックスだけが入力として必要なのか？
- 系列が長すぎてしまうということはあるのか？

これらの疑問について、実際はどのような問題があるのか、そして🤗 Transformers APIを使ってどのように解決できるのかを見ていきましょう。

## モデルへのバッチ入力

以前のエクササイズで、系列が数値のリストに変換される方法を見てきました。この数値列をテンソルに変換し、モデルに入力してみましょう。

{#if fw === 'pt'}
```py
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)
input_ids = torch.tensor(ids)
# This line will fail.
model(input_ids)
```

```python out
IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)
```
{:else}
```py
import tensorflow as tf
from transformers import AutoTokenizer, TFAutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)
input_ids = tf.constant(ids)
# This line will fail.
model(input_ids)
```

```py out
InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape]
```
{/if}

おっと！「セクション2のパイプラインの手順に従ったのに、なぜ失敗したのか？」と思われるかもしれません。

この問題はモデルに単一の系列を入力しようとしたために発生しました。🤗 Transformersモデルは、デフォルトでは複数の系列を入力として受け付けます。ここでは、`sequence`に対してトークナイザを適用したときに、トークナイザがその背後で行ったすべての処理を行おうとしました。しかし、もう少し詳しく見てみると、トークナイザは入力IDのリストをテンソルに変換するだけでなく、それに対して次元を追加していることがわかります。


{#if fw === 'pt'}
```py
tokenized_inputs = tokenizer(sequence, return_tensors="pt")
print(tokenized_inputs["input_ids"])
```

```python out
tensor([[  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,
          2607,  2026,  2878,  2166,  1012,   102]])
```
{:else}
```py
tokenized_inputs = tokenizer(sequence, return_tensors="tf")
print(tokenized_inputs["input_ids"])
```

```py out
<tf.Tensor: shape=(1, 16), dtype=int32, numpy=
array([[  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662,
        12172,  2607,  2026,  2878,  2166,  1012,   102]], dtype=int32)>
```
{/if}

それでは次元を追加して再度試してみましょう。

{#if fw === 'pt'}
```py
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)

input_ids = torch.tensor([ids])
print("Input IDs:", input_ids)

output = model(input_ids)
print("Logits:", output.logits)
```
{:else}
```py
import tensorflow as tf
from transformers import AutoTokenizer, TFAutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)

input_ids = tf.constant([ids])
print("Input IDs:", input_ids)

output = model(input_ids)
print("Logits:", output.logits)
```
{/if}

ここで入力IDと結果のロジット（モデルの出力）を見てみましょう。

{#if fw === 'pt'}
```python out
Input IDs: [[ 1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,  2607, 2026,  2878,  2166,  1012]]
Logits: [[-2.7276,  2.8789]]
```
{:else}
```py out
Input IDs: tf.Tensor(
[[ 1045  1005  2310  2042  3403  2005  1037 17662 12172  2607  2026  2878
   2166  1012]], shape=(1, 14), dtype=int32)
Logits: tf.Tensor([[-2.7276208  2.8789377]], shape=(1, 2), dtype=float32)
```
{/if}

*バッチ処理*とは、複数の系列をまとめてモデルに入力することです。系列が1つしかない場合でも、バッチを構築することができます。

```
batched_ids = [ids, ids]
```

これは2つの同じ系列からなるバッチとなっています。

<Tip>

✏️ **試してみよう！** この `batch_ids` をテンソルに変換し、モデルに入力してみましょう。前と同じロジット（モデル出力）が得られることを確認してください（ただし、二重になっていることに注意してください）。 

</Tip>

バッチ処理により、複数の系列をモデルに入力できるようになります。単一の系列でバッチを構築するのと同じように、簡単に複数の系列を使用することができます。ただし、ここで1つ問題があります。2つ以上の系列をバッチ処理する場合、系列の長さがそれぞれ異なる場合があります。これまでテンソルを扱ったことがある場合は、テンソルの形状は長方形である必要があることをご存知なのではないでしょうか。従って、異なる長さの系列の入力IDリストを直接テンソルに変換することはできません。この問題を回避するための方法として、入力を*パディング*することが一般的です。

## 入力のパディング

以下の二重のリストはテンソルには変換できません。

```py no-format
batched_ids = [
    [200, 200, 200],
    [200, 200]
]
```

この問題を回避するために、*パディング*を使用して、テンソルの形状を長方形にしてみましょう。パディングは、*パディングトークン*と呼ばれる特別な単語を短い系列に対して追加することで、すべての系列の長さを同じにします。例えば、10語の系列が10個、20語の系列が1個ある場合、パディングにより、すべての系列の長さが20語になります。上記の例では、結果として得られるテンソルは次のようになります。

```py no-format
padding_id = 100

batched_ids = [
    [200, 200, 200],
    [200, 200, padding_id],
]
```

パティングトークンのIDは `tokenizer.pad_token_id` で見つけることができます。それでは、これを使って2つの系列を個別にモデルに入力する場合と、バッチ処理した場合の結果を比較してみましょう。

{#if fw === 'pt'}
```py no-format
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence1_ids = [[200, 200, 200]]
sequence2_ids = [[200, 200]]
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

print(model(torch.tensor(sequence1_ids)).logits)
print(model(torch.tensor(sequence2_ids)).logits)
print(model(torch.tensor(batched_ids)).logits)
```

```python out
tensor([[ 1.5694, -1.3895]], grad_fn=<AddmmBackward>)
tensor([[ 0.5803, -0.4125]], grad_fn=<AddmmBackward>)
tensor([[ 1.5694, -1.3895],
        [ 1.3373, -1.2163]], grad_fn=<AddmmBackward>)
```
{:else}
```py no-format
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence1_ids = [[200, 200, 200]]
sequence2_ids = [[200, 200]]
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

print(model(tf.constant(sequence1_ids)).logits)
print(model(tf.constant(sequence2_ids)).logits)
print(model(tf.constant(batched_ids)).logits)
```

```py out
tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32)
tf.Tensor([[ 0.5803005  -0.41252428]], shape=(1, 2), dtype=float32)
tf.Tensor(
[[ 1.5693681 -1.3894582]
 [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32)
```
{/if}

バッチ処理した予測のロジットについて何か違いがあるようです。2行目は2つ目の系列のロジットと同じであるべきですが、完全に異なる値となってしまっています！

これは、Transformerモデルの代表的な特徴であるアテンション層が、それぞれのトークンに対して*コンテクスト化*を行っていることに起因します。アテンション層は、系列のすべてのトークンに注意（アテンション）を向けるため、パディングトークンも考慮の対象として扱います。異なる長さの系列を個別にモデルに入力する場合と、同じ系列をバッチ処理した場合の両方で同じ結果を得るためには、アテンション層にパディングトークンを無視するように指示する必要があります。これは、アテンションマスクを使用することで実現できます。

## アテンションマスク

*アテンションマスク*とは入力IDのテンソルと全く同じ形をしたテンソルのことで、0と1で構成されています。1は対応するトークンに注意を向けることを示し、0は対応するトークンに注意を向けないこと（つまり、アテンション層に無視されること）を示します。

前の例に対して、アテンションマスクを追加してみましょう。

{#if fw === 'pt'}
```py no-format
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

attention_mask = [
    [1, 1, 1],
    [1, 1, 0],
]

outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask))
print(outputs.logits)
```

```python out
tensor([[ 1.5694, -1.3895],
        [ 0.5803, -0.4125]], grad_fn=<AddmmBackward>)
```
{:else}
```py no-format
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

attention_mask = [
    [1, 1, 1],
    [1, 1, 0],
]

outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask))
print(outputs.logits)
```

```py out
tf.Tensor(
[[ 1.5693681  -1.3894582 ]
 [ 0.5803021  -0.41252586]], shape=(2, 2), dtype=float32)
```
{/if}

これで、バッチ内の2つ目の系列について同じロジットが得られました。

2つ目の系列の最後の値がパディングIDであることに注目してください。これは、アテンションマスクの0の値となっています。

<Tip>

✏️ **試してみよう！** セクション2で使用した2つの文 ("I've been waiting for a HuggingFace course my whole life." と "I hate this so much!") を手動でトークン化してみましょう。そしてこれらをモデルに入力し、セクション2で得られたロジットと同じ結果となることを確認してみましょう。次に、パディングトークンを使用してこれらをバッチ処理し、適切なアテンションマスクを作成してみましょう。また同様にモデルに入力した際、セクション2で得られた結果と同じものになることを確認してみましょう。

</Tip>

## より長い系列

トランスフォーマーモデルでは、モデルに入力できる系列の長さに制限があります。ほとんどのモデルは512トークンまたは1024トークンの系列を処理できますが、これより長い系列を処理しようとするとクラッシュしてしまいます。この問題に対しては、2つの解決策があります。

- 長い系列を処理できるモデルを使用する
- 系列を途中で区切って短くする

処理できる系列長はモデルによって異なり、非常に長い系列の処理に特化したモデルも存在します。[Longformer](https://huggingface.co/transformers/model_doc/longformer.html) はその一例です。また、[LED](https://huggingface.co/transformers/model_doc/led.html) も長い系列を処理できるモデルです。非常に長い系列を処理する必要があるタスクに取り組んでいる場合は、これらのモデルを見てみて下さい。

もう1つの手法として、`max_sequence_length` パラメータを指定して系列を途中で区切ることをお勧めします。

```py
sequence = sequence[:max_sequence_length]
```


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter2/5.mdx" />

### イントロダクション
https://huggingface.co/learn/course/ja/chapter2/1.md

# イントロダクション

<CourseFloatingBanner
    chapter={2}
    classNames="absolute z-10 right-0 top-0"
/>

[第1章](/course/chapter1)で見たように、Transformerのモデルは通常、非常に大きなものです。数百万から数百億のパラメータを持つこれらのモデルをトレーニングし、デプロイすることは複雑な仕事です。さらに、ほぼ毎日新しいモデルがリリースされ、それぞれが独自の実装を持っているため、それらをすべて試すことは簡単なことではありません。

🤗 Transformersライブラリはこの問題を解決するために作成されました。その目的は、どんなTransformerモデルでもロード、学習、保存ができる単一のAPIを提供することです。このライブラリの主な機能は以下の通りです。

- **使いやすさ**: 推論のためには、2行のコードで最先端のNLPモデルをダウンロードして使用できます！
- **柔軟さ**: 実装のコアでは、すべてのモデルが単純なPyTorchの`nn.Module`またはTensorFlowの`tf.keras.Model`クラスであり、それぞれの機械学習（ML）フレームワークの他のモデルと同様に扱うことができます！
- **単純さ**: ライブラリ全体でほとんど抽象化は行われていません。"All in one file"がコアコンセプトです。例えば、モデルの順伝播は1つのファイルで完全に定義されているため、コードそのものが理解しやすく、変更しやすいです！

この最後の特徴が🤗 Transformersを他のMLライブラリとは全く違うものにしています。モデルはファイル間で共有されるモジュールで構築されるのではなく、その代わり、各モデルはそれ自身のレイヤーを持っています。モデルをより親しみやすく理解しやすくすることに加えて、これにより、他のモデルに影響を与えることなく、一つのモデルで簡単に実験することができます。

この章ではまず、[第１章](/course/chapter1) で紹介した `pipeline()` 関数を再現するために、モデルとトークナイザを一緒に使ったエンドツーエンドの例を紹介します。次に、モデルAPIについて説明します。モデルとコンフィギュレーションについて詳しく説明し、モデルをロードする方法と、モデルがどのように数値入力を処理して予測を出力するかを説明します。

次に、`pipeline()`関数のもう一つの主要な構成要素であるトークナイザーAPIについて見ていきます。トークナイザは、テキストからニューラルネットワークの数値入力への変換を処理し、必要に応じてテキストに戻す、最初と最後の処理ステップを担います。最後に、複数の文章をバッチ処理でモデルに送る方法を紹介し、`tokenizer()` 関数を詳しく見て、まとめに移ります。

<Tip>
⚠️ Model Hubと🤗 Transformersで利用可能なすべての機能を活用するには、<a href="https://huggingface.co/join">アカウントを作成する</a>ことをお勧めします。
</Tip>



<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter2/1.mdx" />

### モデル
https://huggingface.co/learn/course/ja/chapter2/3.md

# モデル

{#if fw === 'pt'}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section3_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section3_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section3_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section3_tf.ipynb"},
]} />

{/if}

{#if fw === 'pt'}
<Youtube id="AhChOFRegn4"/>
{:else}
<Youtube id="d3JVgghSOew"/>
{/if}

{#if fw === 'pt'}

このセクションでは、モデルの作成と使用について詳しく見ていきます。ここでは、チェックポイントから任意のモデルをインスタンス化する際に便利な `AutoModel` クラスを使用します。

`AutoModel` クラスとその関連クラスは、実際にはライブラリで利用可能な様々なモデルを覆うシンプルなラッパーです。このクラスは、チェックポイントに適したモデルのアーキテクチャを自動的に推測し、そのアーキテクチャを持つモデルをインスタンス化することができる賢いラッパーです。

{:else}

このセクションでは、モデルの作成と使用について詳しく見ていきます。ここでは、チェックポイントから任意のモデルをインスタンス化する際に便利な `TFAutoModel` クラスを使用します。

`TFAutoModel` クラスとその関連クラスは、実際にはライブラリで利用可能な様々なモデルに対する単純なラッパーです。このクラスは、チェックポイントに適したモデルのアーキテクチャを自動的に推測し、そのアーキテクチャを持つモデルをインスタンス化することができる賢いラッパーです。

{/if}

しかし、使用したいモデルの種類がわかっている場合は、そのアーキテクチャを定義するクラスを直接使用することができます。BERTモデルでこれがどのように機能するかを見てみましょう。

## トランスフォーマーモデルを作成する

BERTモデルを初期化するために最初にしなければならないことは、コンフィギュレーションオブジェクトをロードすることです。

{#if fw === 'pt'}
```py
from transformers import BertConfig, BertModel

# Building the config
config = BertConfig()

# Building the model from the config
model = BertModel(config)
```
{:else}
```py
from transformers import BertConfig, TFBertModel

# Building the config
config = BertConfig()

# Building the model from the config
model = TFBertModel(config)
```
{/if}

コンフィギュレーションには、モデルを構築するために使用される多くの属性が含まれています。

```py
print(config)
```

```python out
BertConfig {
  [...]
  "hidden_size": 768,
  "intermediate_size": 3072,
  "max_position_embeddings": 512,
  "num_attention_heads": 12,
  "num_hidden_layers": 12,
  [...]
}
```

我々は、これらの属性のすべてが何をするかまだ見ていませんが、そのうちのいくつかを認識する必要があります: `hidden_​​size` 属性は `hidden_​​states` ベクトルのサイズを定義し、`num_hidden_​​layers` は Transformer モデルが持つレイヤーの数を定義します。

### さまざまなローディング方法

デフォルトのコンフィギュレーション(設定)からモデルを作成すると、ランダムな値で初期化されます。

{#if fw === 'pt'}
```py
from transformers import BertConfig, BertModel

config = BertConfig()
model = BertModel(config)

# Model is randomly initialized!
```
{:else}
```py
from transformers import BertConfig, TFBertModel

config = BertConfig()
model = TFBertModel(config)

# Model is randomly initialized!
```
{/if}

この状態でもモデルは使えますが、意味不明な出力になってしまうので、まず学習させる必要があります。手元のタスクに対して一からモデルを学習させることもできますが、[第1章](/course/chapter1)で見たように、長い時間と多くのデータを必要とし、環境負荷も無視できないものになるでしょう。無駄な努力や重複を避けるためには、既に学習済みのモデルを共有・再利用できることが必須です。

既に学習済みのTransformerモデルをロードするのは簡単です。`from_pretrained()` メソッドを使ってこれを行うことができます。

{#if fw === 'pt'}
```py
from transformers import BertModel

model = BertModel.from_pretrained("bert-base-cased")
```

先ほど見たように、 `BertModel` を同等のクラスである `AutoModel` に置き換えることができます。チェックポイントに依存しないコードを生成するため、今後はこの方法をとります。あるチェックポイントで動作するコードは、別のチェックポイントでもシームレスに動作するはずです。これはアーキテクチャが異なっていても、チェックポイントが同様のタスク (例えばセンチメント分析タスク) に対して学習されたものである限り、当てはまります。

{:else}
```py
from transformers import TFBertModel

model = TFBertModel.from_pretrained("bert-base-cased")
```

先ほど見たように、 `TFBertModel` を同等のクラスである `TFAutoModel` に置き換えることができます。チェックポイントに依存しないコードを生成するため、今後はこの方法をとります。あるチェックポイントで動作するコードは、別のチェックポイントでもシームレスに動作するはずです。これはアーキテクチャが異なっていても、チェックポイントが同様のタスク (例えばセンチメント分析タスク) に対して学習されたものである限り、当てはまります。

{/if}

上記のコードサンプルでは `BertConfig` を使用せず、代わりに `bert-base-cased` を介して事前に学習されたモデルをロードしています。これはBERTの作者自身によって学習されたモデルのチェックポイントです。これについての詳細はその[モデルカード](https://huggingface.co/bert-base-cased)に記載されています。

このモデルは現在、チェックポイントのすべての重みで初期化されています。これは訓練されたタスクの推論に直接使用することができ、また、新しいタスクでファインチューニングすることができます。ゼロからではなく、事前に学習させた重みを用いて学習させることで、迅速に良い結果を得ることができます。

重みはダウンロードされ、キャッシュフォルダ（デフォルトは *~/.cache/huggingface/transformers* ）に保存されます（将来 `from_pretrained()` メソッドを呼び出したときに再ダウンロードされないようにするため）。環境変数 `HF_HOME` を設定することで、キャッシュフォルダをカスタマイズすることができます。

モデルをロードするために使用される識別子は、BERTアーキテクチャと互換性がある限り、モデルハブ上の任意のモデルの識別子を使用することができます。利用可能なBERTチェックポイントの全リストは、[ここ](https://huggingface.co/models?filter=bert)で確認できます。

### 保存方法

モデルの保存はロードするのと同じくらい簡単で、`from_pretrained()` メソッドに類似した `save_pretrained()` メソッドを使用します。

```py
model.save_pretrained("directory_on_my_computer")
```

これにより、2つのファイルがディスクに保存されます。

{#if fw === 'pt'}
```
ls directory_on_my_computer

config.json model.safetensors
```
{:else}
```
ls directory_on_my_computer

config.json tf_model.h5
```
{/if}

*config.json* ファイルを見てみると、モデルアーキテクチャを構築するために必要な属性がわかると思います。このファイルには、チェックポイントがどこで発生したのか、最後にチェックポイントを保存したときに使用していた🤗 Transformersのバージョンなどのメタデータも含まれています。

{#if fw === 'pt'}
*model.safetensors* ファイルは *state dictionary* として知られており、モデルのすべての重みが含まれています。この2つのファイルは密接に関係しています。コンフィギュレーションはモデルのアーキテクチャを知るために必要であり、モデルの重みはモデルのパラメータです。

{:else}
*tf_model.h5*ファイルは*state dictionary*として知られており、すべてのモデルの重みが含まれています。この2つのファイルは密接に関係しています。設定はモデルのアーキテクチャを知るために必要であり、モデルの重みはモデルのパラメータです。

{/if}

## 推論のためのトランスフォーマーモデルの使用

さて、モデルをロードして保存する方法がわかったので、それを使って予測をしてみましょう。トランスフォーマーモデルは数値、つまりトークナイザが生成する数値だけを処理することができます。しかし、トークナイザについて説明する前に、モデルがどのような入力を受け入れるかを探ってみましょう。

トークナイザは入力を適切なフレームワークのテンソルにキャストすることを引き受けてくれますが、何が起こっているかを理解するために、入力をモデルに送る前に行わなければならないことを簡単に見てみましょう。

例えば、いくつかの文があるとします。

```py
sequences = ["Hello!", "Cool.", "Nice!"]
```

トークナイザはこれらを一般に*入力ID*と呼ばれる語彙のインデックスに変換します。各文は今は数字の羅列です。その結果、出力は次のようになります。

```py no-format
encoded_sequences = [
    [101, 7592, 999, 102],
    [101, 4658, 1012, 102],
    [101, 3835, 999, 102],
]
```

これはエンコードされた文のリストであり、リストのリストです。テンソルは長方形の形しか受け付けません（行列を考えてみましょう）。この「配列」はすでに矩形であるので、テンソルに変換するのは簡単です。

{#if fw === 'pt'}
```py
import torch

model_inputs = torch.tensor(encoded_sequences)
```
{:else}
```py
import tensorflow as tf

model_inputs = tf.constant(encoded_sequences)
```
{/if}

### モデルの入力としてのテンソルの使用

モデルでテンソルを使うのは非常に簡単で、モデルの呼び出し時に入力として渡すだけです。

```py
output = model(model_inputs)
```

このモデルは多くの異なる引数を受け付けますが、必要なのは入力IDだけです。他の引数が何をするのか、いつ必要なのかは後で説明します。
しかし、まずはTransformerモデルが理解できる入力を構築するトークナイザを詳しく見る必要があります。


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter2/3.mdx" />

### トークナイザ
https://huggingface.co/learn/course/ja/chapter2/4.md

# トークナイザ

{#if fw === 'pt'}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section4_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section4_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section4_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section4_tf.ipynb"},
]} />

{/if}

<Youtube id="VFp38yj8h3A"/>

トークナイザはNLPパイプラインの重要な構成要素の1つです。トークナイザの目的は1つで、テキストをモデルが処理できるデータに変換することです。モデルが処理できるのは数値のみなので、トークナイザは入力されたテキストを数値データに変換する必要があります。このセクションでは、トークン化パイプラインで何が起きているのかを具体的に説明します。

NLPのタスクにおいて、一般的に処理されるデータは生文で、以下はその例です。

```
Jim Henson was a puppeteer （Jim Hensonは人形師でした）
```

しかしながらモデルが処理できるのは数値のみなので、生文を数値に変換する方法を考える必要があります。トークナイザはまさにこの役割を担っているものであり、変換にはさまざまな方法があります。目的はモデルにとって最も意味のある表現を見つけることです。そして可能な限り、コンパクトな表現を見つけることも目的としています。

ここではトークン化アルゴリズムの例をいくつか見ながら、トークン化に関する疑問を解消していきます。

## 単語ベース

<Youtube id="nhJxYji1aho"/>

最初に思い浮かぶトークナイズ方法は、_単語ベース_ のものです。一般に、いくつかのルールを設定するだけで非常に簡単に使用でき、そして多くの場合において適切な結果を得ることができます。例えば、以下の画像のように生のテキストを単語に分割し、それぞれの数値表現を見つけることが目的です。

<div class="flex justify-center">
  <img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/word_based_tokenization.svg" alt="An example of word-based tokenization."/>
  <img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/word_based_tokenization-dark.svg" alt="An example of word-based tokenization."/>
</div>

テキストの分け方にはさまざまな種類があります。例えば、Pythonの `split()` 関数を適用して、テキストを空白で区切ることで単語に分割することができます。

```py
tokenized_text = "Jim Henson was a puppeteer".split()
print(tokenized_text)
```

```python out
['Jim', 'Henson', 'was', 'a', 'puppeteer']
```

また、単語トークン化には句読点に関する特別なルールを持つものもあります。この種のトークナイザを使用すると、かなり大きな「語彙」が作成されることになります。語彙は、コーパスに含まれるトークンの総数で定義されます。

各単語には個別のID（0〜語彙のサイズの数値）が割り当てられます。モデルはこれらのIDを使用して各単語を識別します。

単語ベースのトークナイザで言語を完全にカバーしようとすると、その言語の各単語に対応する識別子（ID）が必要になり、膨大な量のトークンが生成されることになります。例えば、英語には50万語以上の単語があるので、各単語から入力IDへのマップ（対応表）を作るには、それだけのIDを記録しておく必要があります。また、「dog」のような単語と「dogs」のような単語は表現が異なるため、モデルは初め "dog" と "dogs" が似ていることを知ることができず、無関係な単語として認識してしまいます。また、"run" と "running" のような類似した単語についても同様で、モデルは初期状態では類似しているとは認識できません。

最後に、語彙にない単語 （未知語）を表すためのトークンが必要です。これは "unknown" トークンと呼ばれ、"[UNK]" や "&lt;unk&gt;" として表されます。トークナイザが多くの unknown トークンを生成している場合、単語の適切な表現を取得できず、情報が失われていると解釈できます。語彙を作成する際の目標は、unknownトークンにトークン化されてしまう単語（未知語）がより少なくなるようにすることです。

unknown トークンの総数を減らす方法の1つは、_文字ベース_ のトークナイザを使用することです。

## 文字ベース

<Youtube id="ssLq_EK2jLE"/>

_文字ベース_ トークナイザはテキストを単語単位ではなく文字単位で分割します。これには2つの主な利点があります。

- 語彙サイズがはるかに小さくなります
- すべての単語は文字で構成されるため、語彙外のトークン（未知語）がはるかに少なくなります

しかし、ここでも空白と句読点に関する問題が発生します。

<div class="flex justify-center">
  <img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/character_based_tokenization.svg" alt="An example of character-based tokenization."/>
  <img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/character_based_tokenization-dark.svg" alt="An example of character-based tokenization."/>
</div>

このアプローチも先と同様、完璧なものではありません。ここでは、表現が単語ではなく文字に基づいているので、直感的にはテキストの意味をうまく汲み取れないとも考えられます。各文字は単独ではあまり意味を持たないのに対し、単語はそのようなことはありません。しかし、言語によってはここでも違いがあります。例えば中国語の各文字は、ラテン語の文字よりも情報を持っています。（漢字1文字とアルファベット1文字では、表現している情報量が異なる場合がありますね。）

考慮すべきもう1つの点としては、モデルが処理する必要があるトークンの数が非常に多くなってしまうことです。単語ベースのトークナイザでは、単語は1つのトークンになりますが、文字ベースのトークナイザでは、単語は10個以上のトークンに変換される可能性があります。

両者のいいとこ取りをするために、これらのアプローチを組み合わせた第3の手法を使用することができます。それが *サブワードトークン化* です。

## サブワードトークン化

<Youtube id="zHvTiHr506c"/>

サーブワードトークン化アルゴリズムは、「出現頻度の高い単語は小さなサブワードに分割されるべきではないが、出現頻度の低い単語は、意味を持ったサブワードに分割されるべきである」という原理に基づいています。

例えば "annoyingly" は出現頻度の低い単語として扱われ、"annoying" と "ly" に分割されることがあります。これら2つのサブワードは、それぞれ単独で頻繁に出現する可能性がありますが、一方で "annoyingly" は稀な単語なので、その意味を "annoying" と "ly" の合成語として表現しようという考え方になります。

それではここで、サブワードトークン化アルゴリズムが "Let's do tokenization!" という系列をトークン化する様子を見てみましょう。

<div class="flex justify-center">
  <img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/bpe_subword.svg" alt="A subword tokenization algorithm."/>
  <img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/bpe_subword-dark.svg" alt="A subword tokenization algorithm."/>
</div>

これらのサブワードは最終的に、うまく意味を表現したものとして機能します。例えば上の例では "tokenization" は "token" と "ization" に分割されていましたが、これら2つのトークンは、空間効率が良く（2つのトークンだけで長い単語を表現できている）、意味論的にも有意なものとなっています。これにより、比較的小さな語彙で多くの単語をカバーすることができ、未知語がほとんど出ないようになります。

このアプローチはトルコ語などの膠着語（機能語が自立語にくっついて文が構成される言語）において特に有効です。トルコ語では、サブワードを繋げることで（ほぼ）任意の長さの合成語を作ることができます。

### さらなるトークン化手法！

実は他にも多くのトークン化手法が存在し、例えば以下のようなものがあります。

- Byte-level BPE: GPT-2で使用される手法
- WordPiece: BERTで使用される手法
- SentencePiece もしくは Unigram: いくつかの多言語モデルで使用される手法

ここまで読めば、APIを使ってトークナイザを使い始めるために必要な知識は十分に身についていると思います！

## 読み込みと保存

トークナイザの読み込みと保存は、モデルと同様に簡単です。実際、これらは同じ2つのメソッド `from_pretrained()` と `save_pretrained()` に基づいています。これらのメソッドは、トークナイザが使用するアルゴリズム（モデルでいう *アーキテクチャ*）と、語彙（モデルでいう *重み*）を読み込むか保存するかを決定します。

BERTと同じチェックポイントで学習されたBERTトークナイザを読み込む方法は、モデルでの読み込み方法と同じです。ただし、`BertTokenizer` クラスを使う点だけが異なります。

```py
from transformers import BertTokenizer

tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
```

{#if fw === 'pt'}
`AutoModel` と同様に、`AutoTokenizer` クラスはチェックポイント名に基づいてライブラリ内の適切なトークナイザクラスを取得し、任意のチェックポイントを直接使用することができます。

{:else}
`TFAutoModel` と同様に、`AutoTokenizer` クラスはチェックポイント名に基づいてライブラリ内の適切なトークナイザクラスを取得し、任意のチェックポイントを直接使用することができます。

{/if}

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
```

そして、前のセクションで見たようにトークナイザを使用することができます。

```python
tokenizer("Using a Transformer network is simple")
```

```python out
{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102],
 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],
 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}
```

トークナイザの保存は、モデルの保存と同じ方法でできます。

```py
tokenizer.save_pretrained("directory_on_my_computer")
```

`token_type_ids` については[Chapter3](/course/chapter3)で詳しく説明し、`attention_mask` についても後ほど説明します。まずは `input_ids` がどのように生成されるかを見てみましょう。

## エンコーディング

<Youtube id="Yffk5aydLzg"/>

テキストを数値に変換することを _エンコード_ と呼びます。エンコードはトークン化とその後の入力IDへの変換の2段階のプロセスで行われます。

ここまで見てきたように、最初のステップはテキストをトークン（単語や単語の一部、句読点など）に分割することです。このプロセスを管理するためのルールがいくつか存在します。まずは、モデルの名前を使ってトークナイザをインスタンス化する必要があります。これにより、モデルが事前学習されたときに使用されたものと同じルールを使用することができます。

2番目のステップはトークンを数値に変換することです。これにより、テンソルを構築し、モデルに入力することができます。これを行うために、トークナイザは *語彙* を有しています。これは、`from_pretrained()` メソッドでインスタンス化するときにダウンロードされる部分です。繰り返しになりますが、モデルの事前学習で使用された語彙と同じものを使用する必要があることに注意してください。

この2つの理解を深めるために、それぞれのステップを別々に見ていきます。ステップの中間結果を表示するために、トークン化パイプラインの一部を別々に実行するメソッドを使用しますが、実際には（セクション2で見たように）入力に対して直接トークナイザを呼び出す必要があります。

### トークン化

トークン化のプロセスは `tokenize()` メソッドによって行われます。

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

sequence = "Using a Transformer network is simple"
tokens = tokenizer.tokenize(sequence)

print(tokens)
```

このメソッドの出力はトークンもしくは文字のリストです。

```python out
['Using', 'a', 'transform', '##er', 'network', 'is', 'simple']
```

ここではサブワードトークナイザを使用しているので、単語を語彙に含まれるトークンになるまで分割していきます。具体的には `transformer` が `transform` と `##er` に分割されているのがわかります。

### トークンからIDへの変換

トークンからIDへの変換は `convert_tokens_to_ids()` のトークナイザメソッドによって行われます。

```py
ids = tokenizer.convert_tokens_to_ids(tokens)

print(ids)
```

```python out
[7993, 170, 11303, 1200, 2443, 1110, 3014]
```

これらの出力は、適切なフレームワークのテンソルに変換された後、前述のようにモデルの入力として使用できます。

<Tip>

✏️ **試してみよう！** 最後の2つのステップ（トークン化と入力IDへの変換）を、セクション2で使った入力文（"I've been waiting for a HuggingFace course my whole life." と "I hate this so much!"）に対して再現してみましょう。先ほどと同じ入力IDが得られるかどうかを確認してみてください。

</Tip>

## デコーディング

*デコーディング* はエンコーディングとは逆の処理になります。`decode()` メソッドを使うことで、語彙のインデックスから文字列を取得することができます。

```py
decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])
print(decoded_string)
```

```python out
'Using a Transformer network is simple'
```

`decode` メソッドは語彙のインデックスをトークンに戻すだけでなく、同じ単語の一部であったトークンをまとめて、読みやすい文章に変換するところも担っています。この挙動は、プロンプトから生成されたテキストや、翻訳や要約などの系列から系列への変換などの問題を解くモデルを使うときに非常に役に立ちます。

ここまでで、トークナイザでできる基本的な処理（トークン化、IDへの変換、IDから文字列への変換）を理解できたのではないでしょうか。しかし、これは氷山の一角に過ぎません。次のセクションでは、これらの処理を限界まで拡張していき、その限界を超える方法を見ていきましょう。


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter2/4.mdx" />

### pipelineの裏側
https://huggingface.co/learn/course/ja/chapter2/2.md

# pipelineの裏側

{#if fw === 'pt'}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section2_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section2_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section2_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section2_tf.ipynb"},
]} />

{/if}

<Tip>
ここは、PyTorchとTensorFlowのどちらを使うかによって内容が少し異なる最初のセクションです。タイトルの上にあるスイッチを切り替えて、好きなプラットフォームを選んでください！
</Tip>

{#if fw === 'pt'}
<Youtube id="1pedAIvTWXk"/>
{:else}
<Youtube id="wVN12smEvqg"/>
{/if}

まずは例として、[Chapter1](/course/chapter1)で次のコードを実行したときに、その裏で何が起こったかを見てみましょう。

```python
from transformers import pipeline

classifier = pipeline("sentiment-analysis")
classifier(
    [
        "I've been waiting for a HuggingFace course my whole life.",
        "I hate this so much!",
    ]
)
```

そして、その出力は以下のようになります。

```python out
[{'label': 'POSITIVE', 'score': 0.9598047137260437},
 {'label': 'NEGATIVE', 'score': 0.9994558095932007}]
```

[第1章](/course/chapter1)で見たように、このpipelineは、前処理、モデルへの入力、後処理の3つのステップをグループ化したものです。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/full_nlp_pipeline.svg" alt="The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/full_nlp_pipeline-dark.svg" alt="The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head."/>
</div>

早速、それぞれを確認してみましょう。


## トークナイザを用いた前処理

他のニューラルネットワークのように、Transformerのモデルは生のテキストを直接処理できないので、今回のpipelineの最初のステップは、テキストの入力をモデルが理解できる数値に変換することです。これを行うために我々は*トークナイザ* を使用します。*トークナイザ* は、以下の処理を担います。

- 入力を単語、サブワード、記号（句読点など）に分割する。それらを*トークン*と呼ぶ。
- 各トークンを整数にマッピングする。
- モデルにとって有用な追加の入力を付け足す。

この前処理はモデルが事前学習されたときと全く同じ方法で行われる必要があるので、まず[Model Hub](https://huggingface.co/models)から情報をダウンロードする必要があります。これを行うには、`AutoTokenizer` クラスとその `from_pretrained()` メソッドを使用します。モデルのチェックポイント名を使って、モデルのトークナイザに関連するデータを自動的に取得し、キャッシュします (従って、以下のコードを最初に実行したときにのみダウンロードされます)。

`sentiment-analysis` のpipelineのデフォルトのチェックポイントは、`distilbert-base-uncased-finetuned-sst-2-english` なので (そのモデルカードは [ここ](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english) で見られます)、次のように実行します。

```python
from transformers import AutoTokenizer

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
```

トークナイザがあれば、文章を直接トークナイザに渡し、モデルに与える準備ができた辞書データに変換することができます! あとは入力IDのリストをテンソルに変換するだけです。

🤗 Transformerは、どのMLフレームワークをバックエンドとして使うかを気にせず使うことができます。PyTorchやTensorFlow、モデルによってはFlaxかもしれません。しかし、Transformerのモデルは、入力として*テンソル*しか受け付けません。もしテンソルに聞き馴染みがない場合は、NumPy配列を代わりに考えてもらうと良いかもしれません。NumPyの配列はスカラー（0次元）、ベクトル（1次元）、行列（2次元）、あるいはもっと多くの次元を持つことができます。これは事実上テンソルです。他のMLフレームワークのテンソルも同様な振る舞いをし、通常はNumPy配列と同じくらい簡単にインスタンス化することができます。

返したいテンソルの種類（PyTorch、TensorFlow、あるいは素のNumPy）を指定するには、`return_tensors` 引数を用います。

{#if fw === 'pt'}
```python
raw_inputs = [
    "I've been waiting for a HuggingFace course my whole life.",
    "I hate this so much!",
]
inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt")
print(inputs)
```
{:else}
```python
raw_inputs = [
    "I've been waiting for a HuggingFace course my whole life.",
    "I hate this so much!",
]
inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="tf")
print(inputs)
```
{/if}

パディングや切り捨てなどの処理についてはまだ心配しなくて大丈夫です。これらは後で説明します。ここで覚えておくべきことは、1つの文か文のリストを渡せることと、返したいテンソルの型を指定することです（型を渡さなければ、結果としてリストのリストを得ることになります）。

{#if fw === 'pt'}

PyTorchのテンソルとしての結果は、以下のようになります。


```python out
{
    'input_ids': tensor([
        [  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172, 2607,  2026,  2878,  2166,  1012,   102],
        [  101,  1045,  5223,  2023,  2061,  2172,   999,   102,     0,     0,     0,     0,     0,     0,     0,     0]
    ]), 
    'attention_mask': tensor([
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    ])
}
```
{:else}

TensorFlowのテンソルとしての結果は、以下のようになります。

```python out
{
    'input_ids': <tf.Tensor: shape=(2, 16), dtype=int32, numpy=
        array([
            [  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,  2607,  2026,  2878,  2166,  1012,   102],
            [  101,  1045,  5223,  2023,  2061,  2172,   999,   102,     0,     0,     0,     0,     0,     0,     0,     0]
        ], dtype=int32)>, 
    'attention_mask': <tf.Tensor: shape=(2, 16), dtype=int32, numpy=
        array([
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        ], dtype=int32)>
}
```
{/if}

出力自体は、`input_ids` と `attention_mask` という2つのキーを持つ辞書です。`input_ids` には2行の整数値（各文章に1つずつ）が含まれており、各文章に含まれるトークンを一意に識別することができます。`attention_mask` が何であるかは、この章の後半で説明します。

## モデルの使い方

{#if fw === 'pt'}

トークナイザで行ったのと同じ方法で事前学習したモデルをダウンロードすることができます。🤗 Transformersは `AutoModel` クラスを提供しており、このクラスは `from_pretrained()` メソッドも持っています。

```python
from transformers import AutoModel

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModel.from_pretrained(checkpoint)
```
{:else}

トークナイザで行ったのと同じ方法で事前学習したモデルをダウンロードすることができます。🤗 Transformers は `TFAutoModel` クラスを提供しており、このクラスは `from_pretrained` メソッドも持っています。


```python
from transformers import TFAutoModel

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = TFAutoModel.from_pretrained(checkpoint)
```
{/if}

このコードスニペットでは、以前pipelineで使用したのと同じチェックポイントをダウンロードし（実際には既にキャッシュされているはずです）、それを使ってモデルをインスタンス化しています。

このアーキテクチャには基本的なTransformerモジュールだけが含まれており、いくつかの入力が与えられると、*隠れ状態(hidden states)*（*特徴量*とも呼ばれます）と呼ばれるものを出力します。各モデルの入力に対して、我々は**Transformerモデルによるその入力の文脈的理解**を表す高次元ベクトルを取り出します。

もしこれが理解できなくても、心配しないでください。後ですべて説明します。

これらの隠れ状態はそれ自体で役に立つこともありますが、通常は*head*と呼ばれるモデルの別の部分への入力となります。[第１章](/course/chapter1) では、異なるタスクでも同じアーキテクチャで実行されたかもしれませんが、これらのタスクにはそれぞれ異なるヘッドが使用されています。

### 高次元ベクトル?

Transformerモジュールが出力するベクトルは通常大きなものです。一般的に3つの次元を持ちます。

- **Batch size**: 一度に処理する系列の数（この例では2）。
- **Sequence length**: 系列の数値表現の長さ（この例では16）。
- **Hidden size**: 各モデル入力のベクトル次元。

Hidden sizeが大きいと「高次元」と言われます。Hidden sizeは非常に大きくすることができます（小さいモデルでは768が一般的で、大きいモデルでは3072以上に達することがあります）。

前処理をした入力をモデルに与えてみると、このことがわかります。

{#if fw === 'pt'}
```python
outputs = model(**inputs)
print(outputs.last_hidden_state.shape)
```

```python out
torch.Size([2, 16, 768])
```
{:else}
```py
outputs = model(inputs)
print(outputs.last_hidden_state.shape)
```

```python out
(2, 16, 768)
```
{/if}

🤗 Transformersモデルの出力は `namedtuple` や辞書のように動作することに注意してください。（私たちが行った）属性や（`outputs["last_hidden_state"]`のような）キー、あるいは探しているものがどこにあるか正確に知っていれば（`outputs[0]`のような）インデックスによって要素にアクセスすることが可能です。

### モデルヘッド(Model heads): 数値の意味を理解する

モデルヘッドは高次元の隠れ状態ベクトルを入力として受け取り、それを異なる次元に射影します。モデルヘッドは、通常、1つまたはいくつかの線形層で構成されます。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/transformer_and_head.svg" alt="A Transformer network alongside its head."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/transformer_and_head-dark.svg" alt="A Transformer network alongside its head."/>
</div>

Transformerモデルの出力は直接モデルヘッドに送られ、処理されます。

この図では、モデルはその埋め込み層とそれに続く層で表現されています。埋め込み層は、トークン化された入力の各入力IDを、紐付いたトークンを表すベクトルに変換します。後続の層はアテンション機構を用いてそれらのベクトルを操作し、最終的な文の表現を生成します。

🤗 Transformers には多くの異なるアーキテクチャがあり、それぞれが特定のタスクに取り組むために設計されています。以下はその一部のリストです。

- `*Model` (隠れ状態を取り出す)
- `*ForCausalLM`
- `*ForMaskedLM`
- `*ForMultipleChoice`
- `*ForQuestionAnswering`
- `*ForSequenceClassification`
- `*ForTokenClassification`

{#if fw === 'pt'}

今回の例では、文章分類のヘッドを持つモデルが必要になります（文章をポジティブかネガティブかに分類できるようにするため）。そのため、実際には `AutoModel` クラスではなく、 `AutoModelForSequenceClassification` クラスを使用することになります。

```python
from transformers import AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(**inputs)
```
{:else}

今回の例では、文章分類のヘッドを持つモデルが必要になります（文章をポジティブかネガティブかに分類することができます）。そこで、実際には `TFAutoModel` クラスではなく、 `TFAutoModelForSequenceClassification` クラスを利用することになります。

```python
from transformers import TFAutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(inputs)
```
{/if}

ここで、入力の形を見ると、次元がかなり小さくなっています。モデルヘッドは、先ほどの高次元ベクトルを入力とし、2つの値（1ラベルにつき1つ）を含むベクトルを出力します。

```python
print(outputs.logits.shape)
```

{#if fw === 'pt'}
```python out
torch.Size([2, 2])
```
{:else}
```python out
(2, 2)
```
{/if}

2つの文と2つのラベルがあるので、このモデルから得られる結果は2x2の形状です。

## 出力の後処理

モデルから出力される値は、それ自体では必ずしも意味をなしません。その例を見てみましょう。

```python
print(outputs.logits)
```

{#if fw === 'pt'}
```python out
tensor([[-1.5607,  1.6123],
        [ 4.1692, -3.3464]], grad_fn=<AddmmBackward>)
```
{:else}
```python out
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
    array([[-1.5606991,  1.6122842],
           [ 4.169231 , -3.3464472]], dtype=float32)>
```
{/if}

我々のモデルは最初の文を`[-1.5607, 1.6123]`、2番目の文を`[ 4.1692, -3.3464]`と予測しました。これは確率ではなく*logits*であり、モデルの最終層が出力した正規化されていない生のスコアです。確率に変換するためには、[SoftMax](https://en.wikipedia.org/wiki/Softmax_function)層を通る必要があります（すべての🤗 Transformersモデルはlogitsを出力します。学習用の損失関数は通常、SoftMaxなどの最後の活性化関数とクロスエントロピーのような実際の損失関数が融合されるためです）。

{#if fw === 'pt'}
```py
import torch

predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
print(predictions)
```
{:else}
```py
import tensorflow as tf

predictions = tf.math.softmax(outputs.logits, axis=-1)
print(predictions)
```
{/if}

{#if fw === 'pt'}
```python out
tensor([[4.0195e-02, 9.5980e-01],
        [9.9946e-01, 5.4418e-04]], grad_fn=<SoftmaxBackward>)
```
{:else}
```python out
tf.Tensor(
[[4.01951671e-02 9.59804833e-01]
 [9.9945587e-01 5.4418424e-04]], shape=(2, 2), dtype=float32)
```
{/if}

このモデルは、最初の文は`[0.0402, 0.9598]`、2番目の文は`[0.9995,  0.0005]`と予測したことがわかるでしょう。これらは確率のスコアです。

以下では、各ポジションに対応するラベルを得るには、モデル設定の `id2label` 属性を調べます（これについては次のセクションで詳しく説明します）。

```python
model.config.id2label
```

```python out
{0: 'NEGATIVE', 1: 'POSITIVE'}
```

これで、このモデルは次のように予測したと結論づけることができます。
 
- 最初の文: ネガティブ: 0.0402、ポジティブ: 0.9598
- 第二文: ネガティブ: 0.9995、 ポジティブ: 0.0005

これで、pipelineの3つのステップ、すなわち、トークナイザによる前処理、モデルへの入力、そして後処理がうまく再現できました。この先では、それぞれのステップをより深く掘り下げていきましょう。

<Tip>

✏️ **試してみよう!** 自分でテキストを2つ（またはそれ以上）用意し、`sentiment-analysis` pipelineで実行します。そして、ここで見た手順を自分で再現して、同様な結果が得られるかどうか確認してみましょう!

</Tip>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter2/2.mdx" />

### イントロダクション
https://huggingface.co/learn/course/ja/chapter0/1.md

# イントロダクション

Hugging Faceコースへようこそ！このページでは、実行環境のセットアップ方法についてご案内します。もし、このコースを始めたばかりでしたら、ますは[第１章](/course/chapter1)を見てからここに戻ってきて、コードをご自身で試せるように環境をセットアップすることをお勧めします。

このコースで使用するライブラリは全てPythonパッケージとして提供されているため、ここではPython環境の構築と必要なライブラリのインストール方法について説明します。

実行環境をセットアップする方法として、Colabノートブックを使用する方法とPythonの仮想環境を使用する方法の2つを取り上げます。ご自身で好みの方法をご自由にお選びください。初心者の方には、Colabノートブックを使う方法から始めることを強くお勧めします。

なお、Windowsシステムは取り扱わない点についてご了承ください。もしWindowsで実行される場合は、Colabノートブックを使用することをお勧めします。LinuxやmacOSで実行される場合は、ここで説明するどちらの方法をお選びいただいても構いません。

このコースの大半の場面では、Hugging Faceアカウントをお持ちであることが前提となっています。お持ちでない場合、今すぐ作成することをお勧めします: [アカウント作成](https://huggingface.co/join).

## Google Colabノートブックを使用する場合

Colabノートブックを使用してセットアップを行うのが、一番シンプルな方法です。ブラウザでノートブックを起動し、すぐにコーディングを始めることができます！ 

Colabに馴染みのない方は、まず[Colabのイントロダクション](https://colab.research.google.com/notebooks/intro.ipynb)をご覧いただくことをお勧めします。Colabでは、GPUやTPUのようなアクセラレーターを使用することができ、小規模な作業であれば無料で使用することができます。

Colabでの操作に慣れたら、新しいノートブックを作成してセットアップを始めましょう。

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter0/new_colab.png" alt="An empty colab notebook" width="80%"/>
</div>

次のステップとして、このコースで使用するライブラリのインストールを行います。インストールには、Pythonのパッケージマネージャーである`pip`を使用します。ノートブック内では、システムコマンドの前に`!`をつけることで実行が可能となるため、次のようにして🤗 Transformersライブラリをインストールすることができます。

```
!pip install transformers
```

パッケージが正常にインストールされたかどうかは、Pythonランタイム内でインポートすることで確認できます。

```
import transformers
```

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter0/install.gif" alt="A gif showing the result of the two commands above: installation and import" width="80%"/>
</div>

上記の方法では、非常に軽量なバージョンの🤗 Transformersをインストールしています。特に、特定の機械学習フレームワーク（PyTorchやTensorFlowなど）はインストールしていません。このコースでは、transformersの多くの機能を使うことになるため、想定しているユースケースで必要な依存関係が全て含まれている開発バージョンをインストールすることをお勧めします。

```
!pip install transformers[sentencepiece]
```

このインストールには少し時間がかかりますが、これで残りのコースを問題なく進めることができます！

## Pythonの仮想環境を使用する場合

Pythonの仮想環境を使用したい場合は、まず手元のシステムにPythonをインストールしておく必要があります。このコースでは、[このガイド](https://realpython.com/installing-python/)に従って始めることをお勧めします.

Pythonのインストールが完了すると、ターミナルでPythonコマンドが実行できるようになるはずです。まずは`python --version`を実行して、正常にインストールされていることを確認してから次のステップに進んでください。このコマンドを実行すると、システムで現在利用可能なPythonのバージョンが出力されます。

ターミナルで`python --version`のようなPythonコマンドを実行する場合、コマンドを実行するプログラムはシステムのメインのPythonと考えるべきです。このメインのPythonにはパッケージが存在しない状態を維持し、取り組むそれぞれの内容ごとに個別の環境を作成するのに使用することをお勧めします。この方法では、それぞれの環境が依存関係とパッケージを独立して持つことができ、他の取り組みとの互換性の問題を気にする必要がなくなります。

これはPythonでは、[仮想環境](https://docs.python.org/3/tutorial/venv.html)によって行われます。仮想環境とは、必要な全てのパッケージとともに特定のバージョンのPythonをインストールした自己完結型のディレクトリツリーのことです。仮想環境の作成は多くのツールで行うことが可能ですが、このコースでは[`venv`](https://docs.python.org/3/library/venv.html#module-venv)と呼ばれるPythonの公式パッケージを使用します。

まずは、作業を行うディレクトリを作成します。例として、ホームディレクトリのルートに*transformers-course*という新しいディレクトリを作成するとよいでしょう。

```
mkdir ~/transformers-course
cd ~/transformers-course
```

このディレクトリの中で、Pythonの`venv`モジュールを用いて仮想環境を作成します。

```
python -m venv .env
```

これで、何も入っていなかったディレクトリに*.env*というディレクトリができたはずです。

```
ls -a
```

```out
.      ..    .env
```

仮想環境は、`activate`と`deactivate`というスクリプトで有効化したり、無効化することが可能です。

```
# Activate the virtual environment
source .env/bin/activate

# Deactivate the virtual environment
deactivate
```

仮想環境が有効になっているかどうかは、`which python`というコマンドを実行することで確認することができます。もし以下のように仮想環境であることを示していれば、正常に有効化できています！

```
which python
```

```out
/home/<user>/transformers-course/.env/bin/python
```

### 依存関係のインストール

前のセクションで扱ったGoogle Colabのインスタンスを使用する場合と同様に、この先で必要となるパッケージをインストールする必要があります。ここでも、`pip`というパッケージマネージャーを使用して🤗 Transformersの開発バージョンをインストールすることが可能です。

```
pip install "transformers[sentencepiece]"
```

これでセットアップは完了です！


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter0/1.mdx" />

### まとめ
https://huggingface.co/learn/course/ja/chapter1/9.md

# まとめ

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

この章では、🤗 Transformersが提供する高レベルな`pipeline()` 関数を用いて、異なるNLPタスクにアプローチする方法を学びました。また、同様にHubを用いてモデルを探す方法や、推論APIを使ってブラウザ上でモデルを直接テストする方法も学びました。

さらに、Transformerモデルがどのように動作するかを高いレベルで議論し、さらに転移学習やファインチューニングの重要性について話しました。一つの重要な観点は、解きたいタスクに応じてアーキテクチャ全体を用いることや、エンコーダーやデコーダーの一方だけを用いることができるという点です。以下の表はそのまとめです。

| モデル           | 例                                          | タスク                                                                            |
|-----------------|--------------------------------------------|----------------------------------------------------------------------------------|
| Encoder         | ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa |文章分類, 固有表現抽出, 抽出型質問応答                                                  |
| Decoder         | CTRL, GPT, GPT-2, Transformer XL           | 文章生成                                                                          |
| Encoder-decoder | BART, T5, Marian, mBART                    | 文章要約, 翻訳, 生成型質問応答　                                                      |


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter1/9.mdx" />

### エンコーダーモデル
https://huggingface.co/learn/course/ja/chapter1/5.md

# エンコーダーモデル

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

<Youtube id="MUqNwgPjJvQ" />

エンコーダーモデルとは、Transformerモデルのエンコーダーのみを使用したモデルを指します。 処理の各段階で、attention層は最初の文の全ての単語にアクセスすることができます。 これらのモデルは "bi-directional"（双方向）のattentionを持つものとして特徴付けられ、*オートエンコーダーモデル*と呼ばれます。

これらのモデルの事前学習は、何らかの方法で（例えば文中の単語をランダムにマスクするなどで）文を壊し、この文の再構築をタスクとして解くことを中心に展開されます。

エンコーダーモデルは、文の分類 ・ 固有表現認識（より一般的には単語の分類） ・ 抽出的質問応答など、文全体の理解を必要とするタスクに最も適しています。

エンコーダーモデルでは以下のものが代表的です：

- [ALBERT](https://huggingface.co/transformers/model_doc/albert.html)
- [BERT](https://huggingface.co/transformers/model_doc/bert.html)
- [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html)
- [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html)
- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html)


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter1/5.mdx" />

### イントロダクション
https://huggingface.co/learn/course/ja/chapter1/1.md

# イントロダクション

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

## 🤗 コースへようこそ!

<Youtube id="00GKzGyWFEs" />

このコースでは、[Hugging Face](https://huggingface.co/)のエコシステムを形成するライブラリである[🤗 Transformers](https://github.com/huggingface/transformers)、[🤗 Datasets](https://github.com/huggingface/datasets)、[🤗 Tokenizers](https://github.com/huggingface/tokenizers)、[🤗 Accelerate](https://github.com/huggingface/accelerate)、そして[Hugging Face Hub](https://huggingface.co/models)を使って自然言語処理（NLP）について学習することができます。このコースは、完全に無料で取り組むことができ、広告もありません。


## 何を学ぶことができるのか？

こちらがこのコースの概要になります:

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/summary.svg" alt="Brief overview of the chapters of the course.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/summary-dark.svg" alt="Brief overview of the chapters of the course.">
</div>

- 第１章から第４章では、🤗 Transformersライブラリのメインコンセプトを紹介します。このパートを終える頃には、Transformerモデルがどのように機能するかを理解し、[Hugging Face Hub](https://huggingface.co/models)にあるモデルを利用し、データセットでfine-tuningを行い、その成果をHub上で共有する方法を身につけることができるでしょう！
- 第５章から第８章では、代表的なNLPタスクに取り掛かる前に、🤗 Datasetsと🤗 Tokenizersの基礎を学びます。このパートを終える頃には、大半のNLPの課題に自分で取り組むことができるようになります。
- 第９章から第１２章では、NLPの範囲にとどまらず、音声処理とコンピュータビジョンのタスクにTransformerモデルをどのように適用できるかを検討します。その過程で、モデルのデモを作成して共有することや本番環境用にモデルを最適化する方法を学ぶことができます。このパートを終える頃には、🤗 Transformersを（ほとんど）全ての機械学習の問題に適用する知識が身についていることでしょう！

このコースでは:

* Pythonの知識が必要です
* コースに取り組む前に、深層学習の入門コースである[fast.ai](https://www.fast.ai/)による [Practical Deep Learning for Coders](https://course.fast.ai/)や[DeepLearning.AI](https://www.deeplearning.ai/)が開発したプログラムなどを受講した方がよいでしょう
* [PyTorch](https://pytorch.org/)や[TensorFlow](https://www.tensorflow.org/)の事前知識は必須ではありませんが、どちらかに精通していると理解がより促進されるでしょう

このコースを修了した後は、DeepLearning.AIの[Natural Language Processing Specialization](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh)をご覧いただくことをお勧めします。ナイーブベイズやLSTMなどの従来のNLPモデルを幅広くカバーしており、これらも理解しておいて損はありませんよ！

## 私たちについて

筆者のプロフィール:

**Matthew Carrigan**はHugging Faceの機械学習エンジニアです。アイルランドのダブリンに住んでおり、以前はParse.lyで機械学習エンジニアとして、それ以前はトリニティ・カレッジ・ダブリンでポスドク研究員として働いていました。彼は、既存のアーキテクチャを拡張することでAGI（汎用人工知能）に到達できるとは思っていませんが、ロボットによる不死には大きな期待を寄せています。

**Lysandre Debut**はHugging Faceの機械学習エンジニアで、かなり初期の開発段階から🤗 Transformersライブラリに携わってきました。彼の目標は、非常にシンプルなAPIのツールを開発することによって、誰もがNLPにアクセスできるようにすることです。

**Sylvain Gugger**はHugging Faceのリサーチエンジニアで、🤗 Transformersライブラリのコアメンテナーの1人です。以前は、fast.aiのリサーチサイエンティストで、Jeremy Howard氏と[Deep Learning for Coders with fastai and PyTorch](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/)を共同執筆しています。限られたリソースでモデルを高速に学習させる技術を設計・改善することで、深層学習をより身近なものにすることに研究の焦点を置いています。

**Merve Noyan**はHugging Faceのデベロッパーアドボケイトであり、誰もが機械学習に取り組めるようなツールの開発とその周辺のコンテンツ作成に取り組んでいます。

**Lucile Saulnier**はHugging Faceの機械学習エンジニアで、オープンソースツールの開発および利用のサポートを行っています。また、共同でのモデルの学習やBigScienceなど、自然言語処理の分野で多くの研究プロジェクトに積極的に参加しています。

**Lewis Tunstall**はHugging Faceの機械学習エンジニアで、オープンソースツールの開発とより広いコミュニティで利用されるようにすることに注力しています。また、[オライリー出版のTransformersに関する本](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/)の著者の1人です。

**Leandro von Werra**はHugging Faceのオープンソースチームの機械学習エンジニアであり、[オライリー出版のTransformersに関する本](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/)の著者の1人です。機械学習全般に関わり、NLPプロジェクトを実運用に移行する経験をこの業界で数年積んでいます。

準備はできていますか？この章では、以下のことを学びます:
* `pipeline()`機能を使ったテキスト生成や分類などNLPタスクの取り組み方
* Transformerのアーキテクチャについて
* エンコーダ、デコーダ、エンコーダ・デコーダのアーキテクチャとユースケースの見分け方

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter1/1.mdx" />

### Transformersで何ができる?
https://huggingface.co/learn/course/ja/chapter1/3.md

# Transformersで何ができる?

<CourseFloatingBanner chapter={1}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter1/section3.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter1/section3.ipynb"},
]} />


このセクションでは、Transformerモデルができることを見ていき、🤗 Transformersライブラリの最初のツールとして `pipeline()` 関数を使ってみましょう。

<Tip>
👀 右上に<em>Open in Colab</em>というボタンがありますよね？それをクリックすると、このセクションのすべてのコードサンプルを含むGoogle Colabノートブックが開きます。このボタンは、コードサンプルを含むどのセクションにも存在します。

ローカルでサンプルを実行したい場合は、<a href="/course/chapter0">セットアップ</a>を参照することをお勧めします。
</Tip>

## Transformersは至るところに!

Transformerモデルは前節で述べたようなあらゆる種類のNLPタスクを解決するために使用されています。ここでは、Hugging FaceとTransformerモデルを使用している企業や組織を紹介します。それらの組織はまた、モデルを共有することでコミュニティに還元しています。

<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/companies.PNG" alt="Companies using Hugging Face" width="100%">

[🤗 Transformers library](https://github.com/huggingface/transformers)は、それらの共有モデルを作成し、使用するための機能を提供します。[Model Hub](https://huggingface.co/models)には、誰でもダウンロードして使用できる何千もの事前学習済みモデルが含まれています。また、あなた自身のモデルをModel Hubにアップロードすることも可能です。

<Tip>
⚠️Hugging Face Hubはトランスフォーマーモデルに限定されるものではありません。誰でも好きな種類のモデルやデータセットを共有することができます!すべての利用可能な機能の恩恵を受けるために<a href="https://huggingface.co/join">huggingface.coのアカウントを作成</a>しましょう!
</Tip>  

<br>

Transformerのモデルがどのように機能するのかを知る前に、いくつかの興味深いNLPの問題を解決するため、Transformerがどのように使われるのか、いくつかの例で見ていきましょう。

## pipelineを使ってタスクを実行する

<Youtube id="tiZFewofSLM" />

🤗 Transformers ライブラリの中で最も基本的なオブジェクトは `pipeline()` 関数です。これはモデルを必要な前処理と後処理のステップに接続し、任意のテキストを直接入力して理解しやすい答えを得ることを可能にします。

```python
from transformers import pipeline

classifier = pipeline("sentiment-analysis")
classifier("I've been waiting for a HuggingFace course my whole life.")
```

```python out
[{'label': 'POSITIVE', 'score': 0.9598047137260437}]
```

複数の文章を入力することも可能です。

```python
classifier(
    ["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"]
)
```

```python out
[{'label': 'POSITIVE', 'score': 0.9598047137260437},
 {'label': 'NEGATIVE', 'score': 0.9994558095932007}]
```

デフォルトでは、このpipelineは英語の感情分析用にファインチューニングされた特定の事前学習モデルを使用します。このモデルは `classifier` オブジェクトを作成する際にダウンロードされ、キャッシュされます。コマンドを再実行すると、キャッシュされたモデルが代わりに使用され、モデルを再度ダウンロードする必要はありません。

pipelineにテキストを渡す場合、主に3つのステップがあります。

1. テキストはモデルが理解できる形式に前処理される。
2. 前処理された入力がモデルに渡される。
3. 予測結果を理解できるように、モデルの後処理が行われる。

現在[利用可能なpipeline](https://huggingface.co/transformers/main_classes/pipelines.html)の一部を紹介します。

- `feature-extraction` (テキストのベクトル表現を取得)
- `fill-mask`
- `ner` (固有表現認識)
- `question-answering`
- `sentiment-analysis`
- `summarization`
- `text-generation`
- `translation`
- `zero-shot-classification`

では、いくつか見ていきましょう！

## ゼロショット分類

まず、ラベル付けされていないテキストを分類する必要があるような、より困難なタスクに取り組むことから始めます。これは実際のプロジェクトでよくあるシナリオです。なぜなら、テキストにアノテーションをつけるのは通常時間がかかり、専門知識が必要だからです。このような場合、`zero-shot-classification` pipelineは非常に強力です。分類に使用するラベルを指定できるので、事前に学習したモデルのラベルに依存する必要がありません。肯定的か否定的かの2つのラベルを使って、モデルがどのようにテキストを分類するかは既に見たとおりです。しかし、他の任意のラベルセットを使ってテキストを分類することもできます。


```python
from transformers import pipeline

classifier = pipeline("zero-shot-classification")
classifier(
    "This is a course about the Transformers library",
    candidate_labels=["education", "politics", "business"],
)
```

```python out
{'sequence': 'This is a course about the Transformers library',
 'labels': ['education', 'business', 'politics'],
 'scores': [0.8445963859558105, 0.111976258456707, 0.043427448719739914]}
```

このpipelineは _zero-shot_ と呼ばれます。なぜなら、これを使うために自前のデータセットでモデルのファインチューニングをする必要がないからです。任意のラベルのリストに対して直接確率スコアを返すことができます。

<Tip>

✏️ **試してみよう!** 独自の入力とラベルで遊んでみて、モデルがどのように振る舞うか見てみましょう。

</Tip>

## 文章生成

では、pipelineを使ってテキストを生成する方法を見てみましょう。主なアイデアは、プロンプトを与えると、モデルが残りのテキストを生成してそれを補完することです。これは、多くの携帯電話に搭載されている予測入力機能に類似しています。テキスト生成にはランダム性が含まれるため、以下と同様な結果が得られないのが通常です。

```python
from transformers import pipeline

generator = pipeline("text-generation")
generator("In this course, we will teach you how to")
```

```python out
[{'generated_text': 'In this course, we will teach you how to understand and use '
                    'data flow and data interchange when handling user data. We '
                    'will be working with one or more of the most commonly used '
                    'data flows — data flows of various types, as seen by the '
                    'HTTP'}]
```

引数`num_return_sequences`で異なるシーケンスの生成数を、引数`max_length`で出力テキストの合計の長さを制御することができます。

<Tip>


✏️ **試してみよう!** `num_return_sequences` と `max_length` 引数を用いて、15語ずつの2つの文を生成してみましょう！

</Tip>


## pipelineでHubから任意のモデルを使用する

これまでの例では、タスクに応じたデフォルトのモデルを使用しましたが、特定のタスク（例えばテキスト生成）のpipelineで使用するモデルをHubから選択することも可能です。[Model Hub](https://huggingface.co/models)にアクセスし、左側の対応するタグをクリックすると、そのタスクでサポートされているモデルのみが表示されます。[このようなページ](https://huggingface.co/models?pipeline_tag=text-generation)が表示されるはずです。

それでは、[`distilgpt2`](https://huggingface.co/distilgpt2)モデルを試してみましょう! 先ほどと同じpipelineでロードする方法を説明します。

```python
from transformers import pipeline

generator = pipeline("text-generation", model="distilgpt2")
generator(
    "In this course, we will teach you how to",
    max_length=30,
    num_return_sequences=2,
)
```

```python out
[{'generated_text': 'In this course, we will teach you how to manipulate the world and '
                    'move your mental and physical capabilities to your advantage.'},
 {'generated_text': 'In this course, we will teach you how to become an expert and '
                    'practice realtime, and with a hands on experience on both real '
                    'time and real'}]
```

言語タグをクリックして検索するモデルを絞り込み、他の言語でテキストを生成するモデルを選ぶことができます。Model Hubには、複数の言語をサポートする多言語モデルのチェックポイントもあります。

モデルをクリックで選択すると、オンラインで直接試用できるウィジェットが表示されます。このようにして、ダウンロードする前にモデルの機能をすばやくテストすることができます。

<Tip>

✏️ **試してみよう!** フィルターを使って、他の言語のテキスト生成モデルを探してみましょう。ウィジェットで自由に遊んだり、pipelineで使ってみてください！

</Tip>


### 推論API

すべてのモデルは、Hugging Face [ウェブサイト](https://huggingface.co/)で公開されているInference APIを使って、ブラウザから直接テストすることが可能です。このページでは、任意の文字列を入力し、モデルが入力データを処理する様子を見ることで、直接モデルで遊ぶことができます。

このウィジェットを動かすInference APIは、有料製品としても提供されており、ワークフローに必要な場合は便利です。詳しくは[価格ページ](https://huggingface.co/pricing)をご覧ください。

## 空所穴埋め

次に試すpipelineは`fill-mask`です。このタスクのアイデアは、与えられたテキストの空白を埋めることです。

```python
from transformers import pipeline

unmasker = pipeline("fill-mask")
unmasker("This course will teach you all about <mask> models.", top_k=2)
```

```python out
[{'sequence': 'This course will teach you all about mathematical models.',
  'score': 0.19619831442832947,
  'token': 30412,
  'token_str': ' mathematical'},
 {'sequence': 'This course will teach you all about computational models.',
  'score': 0.04052725434303284,
  'token': 38163,
  'token_str': ' computational'}]
```

`top_k` 引数は、いくつの可能性を表示させたいかをコントロールします。ここでは、モデルが特別な `<mask>` という単語を埋めていることに注意してください。これはしばしば *mask token* と呼ばれます。他の空所穴埋めモデルは異なるマスクトークンを持つかもしれないので、他のモデルを探索するときには常に適切なマスクワードを確認するのが良いでしょう。それを確認する1つの方法は、ウィジェットで使用されているマスクワードを見ることです。

<Tip>

✏️ **試してみよう!** Hub で `bert-base-cased` モデルを検索し、推論API ウィジェットでそのマスクワードを特定します。このモデルは上記の `pipeline` の例文に対して何を予測するでしょうか？

</Tip>

## 固有表現認識

固有表現認識（NER）は、入力されたテキストのどの部分が人物、場所、組織などの固有表現に対応するかをモデルが見つけ出すタスクです。例を見てみましょう。

```python
from transformers import pipeline

ner = pipeline("ner", grouped_entities=True)
ner("My name is Sylvain and I work at Hugging Face in Brooklyn.")
```

```python out
[{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18}, 
 {'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45}, 
 {'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57}
]
```

ここでは、モデルはSylvainが人（PER）、Hugging Faceが組織（ORG）、Brooklynが場所（LOC）であることを正しく識別しています。

pipelineの作成機能でオプション `grouped_entities=True` を渡すと、同じエンティティに対応する文の部分を再グループ化するようpipelineに指示します。ここでは、名前が複数の単語で構成されていても、モデルは "Hugging" と "Face" を一つの組織として正しくグループ化しています。実際、次の章で説明するように、前処理ではいくつかの単語をより小さなパーツに分割することさえあります。例えば、`Sylvain`は4つの部分に分割されます。`S`, `##yl`, `##va`, and `##in`.です。後処理の段階で、pipelineはこれらの断片をうまく再グループ化しました。

<Tip>

✏️ **試してみよう!** Model Hubで英語の品詞タグ付け（通常POSと略される）を行えるモデルを検索してください。このモデルは、上の例の文に対して何を予測するでしょうか？

</Tip>

## 質問応答

質問応答pipelineは、与えられた文脈から得た情報を使って質問に答えます。

```python
from transformers import pipeline

question_answerer = pipeline("question-answering")
question_answerer(
    question="Where do I work?",
    context="My name is Sylvain and I work at Hugging Face in Brooklyn",
)
```

```python out
{'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'}
```

このpipelineは、提供されたコンテキストから情報を抽出することで動作し、答えを生成するわけではないことに注意してください。

## 要約

要約とは、文章中の重要な部分をすべて（あるいはほとんど）維持したまま、より短い文章にするタスクです。以下はその例です。

```python
from transformers import pipeline

summarizer = pipeline("summarization")
summarizer(
    """
    America has changed dramatically during recent years. Not only has the number of 
    graduates in traditional engineering disciplines such as mechanical, civil, 
    electrical, chemical, and aeronautical engineering declined, but in most of 
    the premier American universities engineering curricula now concentrate on 
    and encourage largely the study of engineering science. As a result, there 
    are declining offerings in engineering subjects dealing with infrastructure, 
    the environment, and related issues, and greater concentration on high 
    technology subjects, largely supporting increasingly complex scientific 
    developments. While the latter is important, it should not be at the expense 
    of more traditional engineering.
    Rapidly developing economies such as China and India, as well as other 
    industrial countries in Europe and Asia, continue to encourage and advance 
    the teaching of engineering. Both China and India, respectively, graduate 
    six and eight times as many traditional engineers as does the United States. 
    Other industrial countries at minimum maintain their output, while America 
    suffers an increasingly serious decline in the number of engineering graduates 
    and a lack of well-educated engineers.
"""
)
```

```python out
[{'summary_text': ' America has changed dramatically during recent years . The '
                  'number of engineering graduates in the U.S. has declined in '
                  'traditional engineering disciplines such as mechanical, civil '
                  ', electrical, chemical, and aeronautical engineering . Rapidly '
                  'developing economies such as China and India, as well as other '
                  'industrial countries in Europe and Asia, continue to encourage '
                  'and advance engineering .'}]
```

テキスト生成と同様に、結果に対して `max_length` や `min_length` を指定することができます。


## 翻訳

翻訳の場合、タスク名に言語ペアを指定すれば（`"translation_en_to_fr"`など）デフォルトのモデルを使うこともできますが、一番簡単なのは [Model Hub](https://huggingface.co/models) で使いたいモデルを選ぶことです。ここでは、フランス語から英語への翻訳を試してみます。

```python
from transformers import pipeline

translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en")
translator("Ce cours est produit par Hugging Face.")
```

```python out
[{'translation_text': 'This course is produced by Hugging Face.'}]
```

テキスト生成や要約と同様に、結果に対して `max_length` や `min_length` を指定することができます。

<Tip>

✏️ **試してみよう!** 他言語の翻訳モデルを検索して、前の文章をいくつかの異なる言語に翻訳してみましょう。

</Tip>

これまで紹介したpipelineは、ほとんどがデモンストレーションのためのものです。これらは特定のタスクのためにプログラムされたものであり、それらのバリエーションを実行することはできません。次の章では、`pipeline()`関数の中身と、その動作をカスタマイズする方法を学びます。


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter1/3.mdx" />

### デコーダーモデル
https://huggingface.co/learn/course/ja/chapter1/6.md

# デコーダーモデル

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

<Youtube id="d_ixlCubqQw" />

デコーダーモデルとは、Transformerモデルのデコーダーのみを使用したモデルを指します。 処理の各段階で、処理対象の単語について、attention層はその単語より前に出現した単語にのみアクセスすることができます。 このようなモデルは*自己回帰モデル*と呼ばれます。

　デコーダーモデルの事前学習は、次に続く単語を予測するタスクを解くことを中心に展開されます。

これらのモデルは、文を生成するタスクに最も適しています。


デコーダーモデルでは以下のものが代表的です：

- [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html)
- [GPT](https://huggingface.co/docs/transformers/model_doc/openai-gpt)
- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html)
- [Transformer XL](https://huggingface.co/transformers/model_doc/transfo-xl.html)


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter1/6.mdx" />

### 章末クイズ
https://huggingface.co/learn/course/ja/chapter1/10.md

# 章末クイズ

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

この章では多くの物事を学びました！詳細を把握できなくても安心してください。次の章はどのようにこれらのツールが動いているか理解する上で役に立ちます。

まずは、この章で学んだことを確かめましょう！


### 1.Hubを探索して`roberta-large-mnli`チェックポイントを見つけましょう。 このモデルはどのタスクに適していますか?

<Question
	choices={[
		{
			text: "文章要約",
			explain: "もう一度roberta-large-mnliの<a href=\"https://huggingface.co/roberta-large-mnli\">ページ</a>を見てみましょう。"
		},
		{
			text: "文章分類",
			explain: "より正確には2つの文が論理的にどのような関係を持つか、３つのラベル（矛盾、中立、含意）について分類します。このタスクは<em>自然言語推論</em>とも呼ばれます。",
			correct: true
		},
		{
			text: "文章生成",
			explain: "もう一度roberta-large-mnliの<a href=\"https://huggingface.co/roberta-large-mnli\">ページ</a>を見てみましょう。"
		}
	]}
/>

### 2.次のコードは何を返しますか?

```py
from transformers import pipeline

ner = pipeline("ner", grouped_entities=True)
ner("My name is Sylvain and I work at Hugging Face in Brooklyn.")
```

<Question
	choices={[
		{
            text: "この文章の分類スコアを\"positive\"または\"negative\"のラベルとともに返します。",
            explain: "間違いです。それは<code>sentiment-analysis</code> パイプラインを用いたときの動作です。"
		},
		{
            text: "この文章を完結させるための生成された文を返します。",
            explain: "間違いです。それは <code>text-generation</code> パイプラインを用いたときの動作です。"
		},
		{
            text: "この文中の人物、団体、場所を表す単語を返します。",
            explain: "さらに、<code>grouped_entities=True</code>を用いると、同じエンティティに属する単語をグループ化します。",
			correct: true
		}
	]}
/>

### 3. このサンプルコードでは...をどのように置き換えればよいでしょうか?

```py
from transformers import pipeline

filler = pipeline("fill-mask", model="bert-base-cased")
result = filler("...")
```

<Question
	choices={[
		{
			text: "This \<mask\> has been waiting for you.",
			explain: "間違いです。<code>bert-base-cased</code>のモデルカードをチェックして、あなたの間違いを見つけましょう。"
		},
		{
			text: "This [MASK] has been waiting for you.",
			explain: "正解！このモデルのマスクトークンは[MASK]です。",
			correct: true
		},
		{
			text: "This man has been waiting for you.",
			explain: "間違いです。このパイプラインはマスクされた単語を埋めるので、どこかにマスクトークンが必要です。"
		}
	]}
/>

### 4. なぜこのコードは動かないのでしょうか？

```py
from transformers import pipeline

classifier = pipeline("zero-shot-classification")
result = classifier("This is a course about the Transformers library")
```

<Question
	choices={[
		{
            text: "このパイプラインには、テキストを分類するためのラベルを与える必要があります。",
            explain: "正解です。正しいコードには<code>candidate_labels=[...]</code>を含める必要があります。",
			correct: true
		},
		{
			text: "このパイプラインには、一つの文だけでなく複数の文が必要です。",
            explain: "これは間違いです。しかし、適切に使用すれば、このパイプラインは処理する文のリストを受け取ることができます（他のパイプラインも同様です）。"
		},
		{
			text: "いつもどおり、この🤗Transformersライブラリは壊れています。",
            explain: "ノーコメント！"
		},
		{
            text: "このパイプラインはもっと長い入力が必要です。この入力は短すぎます。",
            explain: "これは間違いです。ただし、とても長い文をこのパイプラインで処理すると、切り捨てられることに注意してください。"
		}
	]}
/>

### 5. 転移学習とはどのような意味ですか？


<Question
	choices={[
		{
			text: "同じデータセットで学習することで、事前学習モデルが持つ知識を新しいモデルに転移させること。",
			explain: "間違いです。それは、2つのバージョンの同じモデルになります。"
		},
		{
			text: "事前学習モデルの重みを用いて、2つ目の新しいモデルを初期化することで、事前学習モデルの知識を転移させること。",
            explain: "正解です。2つ目のモデルを新しいタスクで学習する場合、それは最初のモデルが知識を*転移*したことになります。",
			correct: true
		},
		{
            text: "事前学習モデルと同じアーキテクチャを持つ新しいモデルを構築することで、事前学習モデルの知識を転移させること。",
			explain: "アーキテクチャはあくまでもモデルの作り方であるため、この場合には知識の共有、転移は行われません。"
		}
	]}
/>

### 6. マルバツクイズ、言語モデルの事前学習にラベルは通常は必要ない？


<Question
	choices={[
		{
			text: "マル",
            explain: "事前学習は通常、<em>自己教師あり学習</em>で行われます。つまり、ラベルは入力から自動的に作成されます（例えば、次の単語を予測したり、マスクされた単語を埋めたりといったように）。",
			correct: true
		},
		{
			text: "バツ",
			explain: "これは正しい回答ではありません。"
		}
	]}
/>

### 7.「モデル」、「アーキテクチャ」、「重み」という用語を最も適切に説明している文を選んでください。

<Question
	choices={[
		{
			text: "モデルが建物であるとすれば、アーキテクチャはその設計図で、重みは中に住んでいる人です。",
			explain: "このたとえに従うなら、重みはレンガなどビルを構成する材料になります。"
		},
		{
			text: "アーキテクチャはモデルを構築するための地図であり、その重みは地図上に表される都市です。",
			explain: "このたとえの問題は、通常地図は一つの実在する現実を表していることにあります（フランスにはパリという都市は一つしかない）。一方で、あるアーキテクチャに対して複数の重みを考えることができます。"
		},
		{
			text: "アーキテクチャはモデルを構築する一連の数学的な関数であり、重みはそれらの関数のパラメータです。",
			explain: "同じ数学的な関数の集合（アーキテクチャ）に対して、異なるパラメーター（重み）を用いることで、異なるモデルを作ることができます。",
			correct: true
		}
	]}
/>


### 8. 生成された文でプロンプトを完成させるために使うモデルはどれでしょうか？


<Question
	choices={[
		{
			text: "エンコーダーモデル",
			explain: "エンコーダーモデルは文章全体の埋め込み表現を生成するので、文章分類のようなタスクにより適しています。"
		},
		{
			text: "デコーダーモデル",
			explain: "デコーダーモデルはプロンプトから文章を生成するために、完璧に適したモデルです。",
			correct: true
		},
		{
			text: "sequence-to-sequenceモデル",
			explain: "Sequence-to-sequenceモデルは、与えられたプロンプトではなく入力文と関連のある文章を生成したいときにより適したモデルです。"
		}
	]}
/>

### 9. 文章要約タスクに使うモデルはどれでしょうか?

<Question
	choices={[
		{
			text: "エンコーダーモデル",
			explain: "エンコーダーモデルは文章全体の埋め込み表現を生成するので、文章分類のようなタスクにより適しています。"
		},
		{
			text: "デコーダーモデル",
			explain: "デコーダーモデルは出力文を生成する上で良いモデルです（たとえば要約のように）。しかし、要約対象の文章全体のような文脈を利用する能力はありません。"
		},
		{
			text: "sequence-to-sequenceモデル",
			explain: "Sequence-to-sequenceモデルは要約タスクに完璧に適したモデルです。",
			correct: true
		}
	]}
/>

### 10. 入力された文を特定のラベルに分類したいときに使うモデルはどれでしょうか？


<Question
	choices={[
		{
			text: "エンコーダーモデル",
			explain: "エンコーダーモデルは文章全体の埋め込み表現を生成するので、文章分類のようなタスクに完璧に適しています。",
			correct: true
		},
		{
			text: "デコーダーモデル",
			explain: "デコーダーモデルは出力文を生成する上で良いモデルですが、文からラベルを抽出するモデルではありません。"
		},
		{
			text: "sequence-to-sequenceモデル",
			explain: "Sequence-to-sequenceモデルは、入力文に基づいて文を生成するときにより適したモデルで、ラベルを出力するモデルではありません。",
		}
	]}
/>

### 11. モデルが持つバイアスはどのような要因で生じますか?


<Question
	choices={[
		{
			text: "モデルが事前学習モデルをファインチューニングしたバージョンであり、そのモデルが元のモデルよりバイアスを受け継いだとき。",
			explain: "転移学習が適用されるとき、事前学習モデルのバイアスがファインチューニングされたモデルに発現します。",
			correct: true
		},
		{
			text: "モデルを訓練するデータに偏りがある時。",
			explain: "これは最も顕著なバイアスの要因です。しかし、要因はこれだけではありません。",
			correct: true
		},
		{
			text: "モデルを最適化するための指標に偏りがある時",
            explain: "バイアスの要因としてあまり知られていないのはモデルの学習方法です。モデルはあなたが選んだどんな指標に対しても、やみくもに最適化します。",
			correct: true
		}
	]}
/>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter1/10.mdx" />

### バイアスと限界
https://huggingface.co/learn/course/ja/chapter1/8.md

# バイアスと限界

<CourseFloatingBanner chapter={1}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter1/section8.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter1/section8.ipynb"},
]} />

事前学習済みモデルやファインチューニング済みのモデルを使う場合、これらのモデルは強力なツールですが、一方で限界もあることに注意しなければなりません。
その代表例は、大量のデータによる事前学習を行うために、研究者はインターネット上にある利用可能なデータを良いものから悪いものまで手当たりしだいに集めてしまうことです。

簡単に説明するために、BERTによる`fill-mask`パイプラインの例に戻りましょう:


```python
from transformers import pipeline

unmasker = pipeline("fill-mask", model="bert-base-uncased")
result = unmasker("This man works as a [MASK].")
print([r["token_str"] for r in result])

result = unmasker("This woman works as a [MASK].")
print([r["token_str"] for r in result])
```

```python out
['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic']
['nurse', 'waitress', 'teacher', 'maid', 'prostitute']
```

これらの２つの文の欠落した単語を埋めさせたときに、モデルはジェンダーフリーの回答を一つだけしか与えません(waiter/waitress)。他はたいていの場合、特定の性別と関連付けられる職業です。そして、モデルは「女性」と「仕事」から連想される可能性のある職業としてトップ５に「売春婦（prostitute）」を上げています。
BERTはインターネット上のあらゆるところからデータをかき集めて構築されたのではなく、中立的なデータ([English Wikipedia](https://huggingface.co/datasets/wikipedia)と[BookCorpus](https://huggingface.co/datasets/bookcorpus)を用いて学習されています) を用いて構築されためずらしいTransformerモデルであるにも関わらず、このような現象が発生してしまいます。

したがって、これらのツールを使用する際は、オリジナルのモデルがとても簡単に性的、差別的、あるいは同性愛嫌悪のコンテンツを生成してしまうことを念頭に置く必要があります。この本質的なバイアスは、あるデータでファインチューニングしても消えることはありません。

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter1/8.mdx" />

### Transformersの仕組みについて
https://huggingface.co/learn/course/ja/chapter1/4.md

# Transformersの仕組みについて

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

このセクションでは、Transformerモデルのアーキテクチャをざっくりと見ていきます。

## Transformerの歴史を簡単に

Transformerモデルの（短い）歴史の中で、参考となるポイントをいくつか紹介します。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers_chrono.svg" alt="A brief chronology of Transformers models.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers_chrono-dark.svg" alt="A brief chronology of Transformers models.">
</div>

[Transformerのアーキテクチャ](https://arxiv.org/abs/1706.03762)は2017年6月に登場しました。 当初の研究は翻訳タスクに焦点を置いていましたが、これに続くようにして以下のような影響力のあるモデルがいくつか登場します。

- **2018/6** [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf): 様々な自然言語処理タスクに対してfine-tuningすることでSoTAを達成した、史上初の事前学習済みモデルです。

- **2018/10** [BERT](https://arxiv.org/abs/1810.04805): これも大規模な事前学習済みモデルで、文についてのより良い要約を生成するように設計されています。（こちらについては次の章で詳しく説明します！）

- **2019/2** [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf): これはGPTを改良 & 大規模化したものですが、倫理的な問題から一般公開までには時間がかかったモデルです。

- **2019/10** [DistilBERT](https://arxiv.org/abs/1910.01108): これはBERTを60%高速化し40%のメモリ軽量化をしながら、97%の性能を維持した蒸留モデルです。

- **2019/10** [BART](https://arxiv.org/abs/1910.13461), [T5](https://arxiv.org/abs/1910.10683): オリジナルのTransformerモデルと同じアーキテクチャを採用した大規模な事前学習済みモデルです。

- **2020/5** [GPT-3](https://arxiv.org/abs/2005.14165): GPT-2をさらに大規模化したもので、fine-tuningなし（_zero-shot学習_）で様々なタスクを解くことができるようにしたモデルです。

このリストは決して包括的なものではなく、Transformerのモデルの種類をざっくり分けることを意図しています。種類については大きく以下の3つのカテゴリーに分類することができます。

- GPT型 (_auto-regressive_ Transformerモデルとも呼ばれます)
- BERT型 (_auto-encoding_ Transformerモデルとも呼ばれます) 
- BART/T5型 (_sequence-to-sequence_ Transformerモデルとも呼ばれます)

これらの種類についてこれから深掘りしていきます。

## Transformers = 言語モデル

GPT、BERT、T5などの上記の全てのモデルは*言語モデル*として学習されています。これは大量の生文に対して自己教師あり学習を行ったことを意味しています。自己教師あり学習は、学習の目的となるものを、モデルに入力するデータから自動で算出する学習方法です。つまりデータに対する人手のラベル付が必要ないことを意味します。

このタイプのモデルは、学習させた言語に対する統計的な理解を深めることができますが、特定のタスクにはあまり役に立ちません。従って、一般的な事前学習済みモデルは、この後に*転移学習*と呼ばれるプロセスを経ます。このプロセスでは人手でラベル付されたデータを用いた教師あり学習を行なって、特定のタスクに対してfine-tuningされます。

タスク例の1つに、前のいくつかの単語を読んで、それに続く次の単語を予測するものがあります。これは出力が過去と現在の入力にのみ依存し、将来の入力には依存しないため、 *Causal Language Modeling (CLM)* と呼ばれます。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/causal_modeling.svg" alt="Example of causal language modeling in which the next word from a sentence is predicted.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/causal_modeling-dark.svg" alt="Example of causal language modeling in which the next word from a sentence is predicted.">
</div>

他の例としては *Masked Language Modeling (MLM)* があり、これは文中のマスクされた（隠された）単語が何かを予測するタスクになっています。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/masked_modeling.svg" alt="Example of masked language modeling in which a masked word from a sentence is predicted.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/masked_modeling-dark.svg" alt="Example of masked language modeling in which a masked word from a sentence is predicted.">
</div>

## Transformers = 大規模モデル

前述のDistilBERTなどの例外を除けば、より良いパフォーマンスを達成するための一般的な戦略として、モデルサイズと学習データ量を大きくするというものがあります。

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/model_parameters.png" alt="Number of parameters of recent Transformers models" width="90%">
</div>

残念ながらモデルの学習（特に大規模なモデルの学習）には大量のデータが必要になります。これは時間と計算資源の面で非常にコストがかかります。また、以下のグラフから分かるように、環境にも影響を及ぼすものになります。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/carbon_footprint.svg" alt="The carbon footprint of a large language model.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/carbon_footprint-dark.svg" alt="The carbon footprint of a large language model.">
</div>

<Youtube id="ftWlj4FBHTg"/>

そしてこの図は、事前学習の環境負荷を意識的に減らすことを目的とするチームが率いる、（超大規模）モデルのプロジェクトを示しています。最適なハイパーパラメータを得るための多くの試行による環境負荷は、より大きなものになると考えられます。

もし研究チームや学生団体、企業がその度にモデルを一から学習していたらどうでしょうか。これでは膨大で不必要なコストがかかってしまいます。

従って、学習済み言語モデルの重みを共有しそれを利用することで、コミュニティ全体の計算コストや環境負荷を削減することができるのです。

## 転移学習

<Youtube id="BqqfQnyjmgg" />

*事前学習*とはモデルを一から学習することです。重みはランダムに初期化され、事前知識なしに学習が開始されます。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/pretraining.svg" alt="The pretraining of a language model is costly in both time and money.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/pretraining-dark.svg" alt="The pretraining of a language model is costly in both time and money.">
</div>

事前学習は大量のデータを使って行われます。よって、非常に大きなデータコーパスを必要とし、学習には数週間かかることがあります。

一方で*ファインチューニング*は事前学習の**後に**行われるものです。ファインチューニングを行うには、まず最初に事前学習済みモデルを取得し、次にタスクに応じたデータセットを用いて追加の学習を行います。ここで、「（事前学習を行わずに）初めからこのタスクに対して学習を行えば良いのでは？」と思った方がいるかもしれませんが、これにはいくつかの理由があります。

*  事前学習済みモデルは、ファインチューニング用のデータセットと何らかの類似性を持ったデータで既に学習が行われています。このため、ファインチューニングの過程において、事前学習済みモデルが既に獲得した知識を利用することができます。（例えば自然言語処理の問題では、事前学習済みのモデルは言語に対する何らかの統計的な理解をしているはずです。）
*  また事前学習済みモデルは大量のデータを使って学習されているので、ファインチューニングでははるかに少ないデータで適切な結果を得ることが可能になります。
*  これと同じ理由で、良い結果を得るために必要な時間や資源を大きく削減することができます。

例えば、英語で訓練された事前学習済みモデルをarXivコーパスでファインチューニングすることで、科学/研究ベースのモデルを作ることができます。ファインチューニングは少ないデータで実施できます。これは事前学習済みモデルが獲得していた知識が「転移」しているためで、この特徴から「*転移学習*」と呼ばれているという訳です。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/finetuning.svg" alt="The fine-tuning of a language model is cheaper than pretraining in both time and money.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/finetuning-dark.svg" alt="The fine-tuning of a language model is cheaper than pretraining in both time and money.">
</div>

従って、モデルのファインチューニングに必要な時間、データ、経済的/環境的コストは少なく済みます。また事前学習よりも制約が少ないため、様々なファインチューニングのスキームを素早く簡単に試すことができます。

このプロセスは（大量のデータがある場合を除いて）ゼロから学習するよりも良い結果をもたらします。だからこそ（目的のタスクにできるだけ近い）事前学習済みモデルを活用し、それをファインチューニングするべきだと言えます。

## 一般的なアーキテクチャ

このセクションでは、Transformerモデルの一般的なアーキテクチャについて見ていきます。各構成要素については後ほど詳しく説明するので、理解できない部分があっても心配ありません！

<Youtube id="H39Z_720T5s" />

## イントロダクション

モデルは主に2つの要素で構成されます。

* **エンコーダー （左）**: エンコーダーは入力を受け取り、その特徴量を生成します。これは入力から理解を得るためにモデルが最適化されることを意味します。
* **デコーダー　（右）**: デコーダーではエンコーダーが生成した特徴量とその他の入力を受け取って、目的の系列を生成します。これは出力を生成するためにモデルが最適化されることを意味します。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers_blocks.svg" alt="Architecture of a Transformers models">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers_blocks-dark.svg" alt="Architecture of a Transformers models">
</div>

これらの構成要素はタスクに応じてそれぞれ別々に使用することができます。

* **Encoder-only モデル**: 文章分類や固有表現抽出など入力に対する理解が必要となるタスクに適しています。
* **Decoder-only モデル**: 文生成などの生成タスクに適しています。
* **Encoder-Decoder(sequence-to-sequence) モデル**: 翻訳や要約など、入力を要する生成タスクに適しています。

これらのアーキテクチャについてはのちのセクションで個別に紹介します。


## アテンション層

Transformerモデルは*アテンション層*と呼ばれる特殊な層で構築されていることが大きな特徴となっています。実際にTransformerが登場した論文のタイトルも["Attention Is All You Need"](https://arxiv.org/abs/1706.03762)というものでした！ アテンション層については後ほど詳しく説明します。現段階においては、モデルが各単語の特徴量を扱う際に、入力されたテキストのどの単語に注目すべきかをアテンション層が指示してくれる（多かれ少なかれその他の単語は無視される）ということだけ知っておいてもらえれば十分です。

このことを理解するために、英語からフランス語への翻訳タスクを考えてみます。"You like this course" という入力があるとき、翻訳モデルは "like" という単語を適切に翻訳するために "You" という隣接する単語に注目する必要があります。これはフランス語の動詞 "like" は主語によって異なる活用がされるためです。ただこのとき、"like" の翻訳に他の単語の情報は役に立ちません。同じように、モデルは "this" という単語を翻訳する際に "course" という単語に注意を払う必要があり、これは "this" という単語の翻訳が関連する名詞が男性か女性かによって変化するためです。この場合においてもその他の単語は "this" の翻訳には関係ありません。より複雑な文（および文法規則）では、モデルは各単語を適切に翻訳するために、文中のより離れた位置に出現する可能性のある単語に対して特別な注意を払う必要があります。

単語はそれ自体で意味を持ちますが、その意味は文脈（前後に現れるその他の単語）に大きな影響を受けます。このため、翻訳タスクと同じ考え方が自然言語に関する色々なタスクに対して当てはまります。

さて、アテンション層がどのようなものかを理解頂いた上で、Transformerのアーキテクチャをより詳しく見ていきましょう！

## オリジナルのアーキテクチャ

Transformerのアーキテクチャは翻訳用に設計されました。学習過程において、エンコーダーはある言語の入力（文章）を受け取り、デコーダーは別言語で書かれた同じ文章を受け取ります。エンコーダーのアテンション層は文中の全ての単語を使うことができます。（先ほど見たように、、ある単語を翻訳するためにはその前後の単語に注意を払う必要があるためです。）一方でデコーダーは逐次的に動作します。このため既に翻訳して生成した単語にしか注意を向けることができません。（言い換えればこれから翻訳して生成される単語に対しては注意が張られないということです。）例えば、翻訳対象の最初の3単語を予測したらそれをデコーダーに渡すことで、デコーダーはエンコーダーに入力された情報を全て使いながら4単語目を予測します。

モデルの学習中、学習速度を上げるためにデコーダーには答えとなる翻訳文（ターゲット文）全体が与えられていますが、処理対象となる単語の後に続く単語を使うことは許されていません。例えば、4番目の単語を予測する際、アテンション層はターゲット文の1〜3番目の位置にある単語にしかアクセスすることができません。

Transformerのオリジナルのアーキテクチャの概観は、このように左側のエンコーダーと右側のデコーダーからなります。

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers.svg" alt="Architecture of a Transformers models">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers-dark.svg" alt="Architecture of a Transformers models">
</div>

デコーダーブロックの最初のアテンション層は、デコーダーに対する全ての入力を使うことができますが、2番目のアテンション層はエンコーダーの出力を利用します。従って、入力文全体にアクセスすることで現在の単語の最適な予測が可能になるという訳です。これは言語によって単語の登場順が異なるような文法規則があったり、文の後半で提供される文脈情報が、現在の単語の翻訳に役立つ場合があるので、非常に便利なものとなっています。

*attentionマスク*はエンコーダー・デコーダーで、ある特別な単語に注目しないようにするために使用されます。（例えば、文をまとめて入力するときに、全ての文を同じ長さに揃えるために使われるpadding tokenなどです。）

##  アーキテクチャ vs. チェックポイント

このコースでTransformerモデルについて掘り下げていくと、*モデル*と同様に*アーキテクチャ*や*チェックポイント*という単語についても言及されていることがわかります。これらの用語はそれぞれ少しずつ異なる意味を持っています。


* **アーキテクチャ**: これはモデルの骨格を意味し、モデル内の各層と内部で起こる操作を定義したものになります。
* **チェックポイント**: これは与えられたアーキテクチャに対して読み込まれる重みを意味します。
* **モデル**: これは「アーキテクチャ」や「チェックポイント」ほど正確ではない、より包括的な用語で両方を意味することがあります。このコースでは曖昧さを回避するために、重要な場合は*アーキテクチャ*や*チェックポイント*を使うことにします。

例えばBERTはアーキテクチャを指し、`bert-base-cased`はGoogleの開発チームがBERTの最初のリリースのために用意した重みを指したチェックポイントとなります。しかしながら"BERTモデル"や"`bert-base-cased`モデル"と呼ぶこともできます。


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter1/4.mdx" />

### Sequence-to-sequence モデル
https://huggingface.co/learn/course/ja/chapter1/7.md

# Sequence-to-sequence モデル

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

<Youtube id="0_4KEb08xrE" />

Encoder-decoderモデル（*sequence-to-sequence models*とも呼ばれる）はTransformerアーキテクチャのエンコーダーとデコーダーの両方を使用します。
それぞれのステージにおいて、エンコーダーのアテンション層は入力文のすべての単語にアクセスできるのに対して、デコーダーのアテンション層は入力中のある単語の前に位置する単語にのみアクセスできます。

これらのモデルの事前学習は、エンコーダー、またはデコーダーの学習と同じように行われますが、通常はより複雑な方法を含みます。
例えば、[T5](https://huggingface.co/t5-base) は、特殊な単語で文中のスパン（複数の単語を含むことができる）をランダムにマスクしたときに、そのマスクされた文を予測する事を目的として事前学習されています。

Sequence-to-sequenceモデルは、要約、翻訳、質問応答生成などのように、与えられた入力文に対して新しい文を生成するタスクにとても適しています。

これらの系統のモデルの代表は次のとおりです:

- [BART](https://huggingface.co/transformers/model_doc/bart.html)
- [mBART](https://huggingface.co/transformers/model_doc/mbart.html)
- [Marian](https://huggingface.co/transformers/model_doc/marian.html)
- [T5](https://huggingface.co/transformers/model_doc/t5.html)


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter1/7.mdx" />

### 自然言語処理 / NLP(Natural Language Processing)
https://huggingface.co/learn/course/ja/chapter1/2.md

# 自然言語処理 / NLP(Natural Language Processing)

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

Transformerモデルの詳細に飛び込んでいく前に、自然言語処理とはどんなもので、かつ、なぜ我々が注目する必要があるのかの大まかな概要を知っていきましょう。

## 自然言語処理とはどんなもの？

自然言語処理とは、人の言語に関連した全てのことへの理解に焦点を当てた、言語学と機械学習の分野です。自然言語処理タスクの目標は、文章を個別に一単語ずつ理解するだけでなく、それらの単語で構成された文章の文脈を理解することです。

以下のリストで、具体例付きで一般的な自然言語処理タスクを紹介します。

- **文章の分類**：レビューの評価、スパムメールの検出、文法的に正しいかどうかの判断、2つの文が論理的に関連しているかどうかの判断
- **文の中の単語分類**：品詞（名詞、動詞、形容詞）や、固有表現（人、場所、組織）の識別
- **文章内容の生成**：自動生成されたテキストによる入力テキストの補完、文章の穴埋め
- **文章からの情報抽出**：質問と文脈が与えられたときの、文脈からの情報に基づいた質問に対する答えの抽出
- **文章の変換**：ある文章の他の言語への翻訳、文章の要約

さらに、自然言語処理は文章に限ったものではありません。音声認識やコンピュータビジョンの分野でも、音声サンプルの書き起こしや画像の説明文の生成など、複雑な課題に取り組んでいます。

## なぜ自然言語処理は困難なのか？

コンピュータは人間と同じように情報を処理するわけではありません。例えば、「私はお腹が空いています。」という文章を読むと、人間はその意味を簡単に理解することができます。同様に、「私はお腹が空いています。」と「私は悲しいです。」という2つの文章があれば、その類似性を人間は簡単に判断することができます。しかし、機械学習(ML)モデルにおいては、このようなタスクはより困難です。機械学習モデルが学習できるように、テキストを処理する必要があります。また、言語は複雑なため、どのように処理すべきかを慎重に考える必要があります。テキストをどのように表現するかについては多くの研究がなされており、次の章ではいくつかの方法について見ていきます。


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ja/chapter1/2.mdx" />
