---
title: '第4章: ニューラルネットワークのトレーニング'
description:
  "この章では、ユースケースに合わせて機械学習モデルを更新する方法を学びます。例えば、オンラインのコメントを使って新しい固有表現タイプを予測する、などです。
  ゼロからモデルを学習させていき、トレーングの基礎を理解し、NLPプロジェクトをより成功させるためのヒントやコツを学んでいきます。"
prev: /chapter3
next: null
type: chapter
id: 4
---

<exercise id="1" title="モデルのトレーニングと更新" type="slides">

<slides source="chapter4_01_training-updating-models">
</slides>

</exercise>

<exercise id="2" title="学習データと検証データ">

モデルを学習させるには、通常「学習データ」（または「訓練データ」）と検証データが必要です。この「検証データ」はなぜ必要でしょうか。

<choice>

<opt text="学習データが足りない場合、予備データとして使われる">

訓練中、モデルは学習データのみに基づいて更新されます。
モデルを評価するために、検証データをモデルに与え、未見のデータに対しての予測を正解と比較し、モデルの精度を計算します。

</opt>

<opt text="モデルを未見のデータに対して評価し、精度を計算するため" correct="true">

モデルを評価するために、検証データをモデルに与え、未見のデータに対しての予測を正解と比較し、モデルの精度を計算します。

</opt>

<opt text="アノテーションなしのデータを訓練で使うため">

訓練中、モデルは学習データのみに基づいて更新されます。
モデルを評価するために、検証データをモデルに与え、未見のデータに対しての予測を正解と比較し、モデルの精度を計算します。

</opt>

</choice>

</exercise>

<exercise id="3" title="学習データを作る(1)">

spaCyのルールベースの `Matcher` は、固有表現抽出の学習データを素早く作成するのに最適な方法です。
文章のリストが変数 `TEXTS` として用意されており、プリントすると、中身を見ることができます。
iPhoneのモデルが言及されている箇所を見つけるため、それらを `"GADGET"` として認識するようにモデルに教えるための学習データを作成します。

- 小文字が `"iphone"` にマッチするトークン、小文字が `"x"` にマッチするトークン、合計2つのトークンのパターンを書きます。
- 小文字が `"iphone"` にマッチするトークン、数字のトークン、合計2つのトークンのパターンを書きます。

<codeblock id="04_03">

- トークンの小文字を一致させるには、`"LOWER"`属性を使用します。例えば、`{"LOWER": "apple"}`のようにします。
- 数字のトークンを見つけるには、`"IS_DIGIT"` フラグを用います。例えば、 `{"IS_DIGIT": True}`のようになります。

</codeblock>

</exercise>

<exercise id="4" title="学習データを作る(2)">

前の演習で作成したマッチパターンを使って、学習データを作っていきましょう。
spaCyで学習データを使うためには `.spacy` ファイルを作成する必要があります。

- `docs`のリストを使って`DocBin`を作成します
- `DocBin`を`train.spacy`というファイルに保存します

<codeblock id="04_04">

- `DocBin`を初期化するとき、`Doc`のリストを`docs`キーワード引数で指定できます
- `DocBin`の`to_disk`メソッドは出力ファイル名を引数として取ります。
  ファイル名の拡張子は`.spacy`にしましょう。

</codeblock>

</exercise>

<exercise id="5" title="トレーニングの設定と実行" type="slides">

<slides source="chapter4_02_running-training">
</slides>

</exercise>

<exercise id="6" title="設定ファイル">

`config.cfg`の設定ファイルはパイプラインにとって「信頼できる唯一の情報源」です。
以下の選択肢のうち、どれが正しくないでしょうか。

<choice>

<opt text="学習の詳細設定やハイパーパラメータを設定できる">

設定ファイルにはハイパーパラメータを含め、トレーニングの全ての設定が記載されています。

</opt>

<opt text="学習の再現性を向上させる">

設定ファイルに全ての設定が含まれているため、隠れデフォルトなどはなく、実験の再現性を高めます。
他人に設定ファイルを共有するだけで同じ実験を再現できます。

</opt>

<opt text="インストールできるパッケージを生成する" correct="true">

設定ファイルにトレーニングに関する全ての設定は記載されていますが、パイプラインをパッケージ化することは別の機能です。
パッケージを作成することは`spacy package`コマンドでできます。

</opt>

<opt text="パイプラインのコンポネントとその設定を定義する">

設定ファイルの`[components]`ブロックでは、モデルのバージョンを含め、コンポネントに関する全ての設定が記述されています。

</opt>

</choice>

</exercise>

<exercise id="7" title="設定ファイルの生成">

[`init config`コマンド](https://spacy.io/api/cli#init-config)を使うと、デフォルト設定の設定ファイルを自動に生成できます。
この演習では、固有表現抽出器を学習させるためのパイプラインを作るため、`ner`コンポネントを含む設定ファイルを作成します。
この演習はJupyter Notebookで実行されているため、コマンドラインのコマンドは`!`で始まるように書きます。
手元のコマンドラインで実行する場合、`!`を入れる必要はありません。

### パート1

- spaCyの`init config`コマンドを使って、日本語の設定ファイルを生成してください
- 設定ファイルを`config.cfg`に保存してください
- `--pipeline`の引数を使って`ner`コンポネントを指定してください

<codeblock id="04_07_01">

- パイプラインの言語クラスは`--lang`で指定できます。日本語は`ja`となります。

</codeblock>

### パート2

今生成された設定ファイルの内容を確認しましょう。
下記のコマンドでファイルの中身を表示できます。

<codeblock id="04_07_02"></codeblock>

</exercise>

<exercise id="8" title="トレーニングCLIの使い方">

今までの演習で作った設定ファイルを使って固有表現抽出器を学習させましょう！

[`train`](https://spacy.io/api/cli#train)コマンドを使うことで設定ファイルからパイプラインを学習させることができます。
`exercises/ja`に`config_gadget.cfg`の設定ファイル、そして学習データの`train_gadget.spacy`と検証データの`dev_gadget.spacy`は既に用意されています。
この演習はJupyter Notebookで実行されているため、コマンドラインのコマンドは`!`で始まるように書きます。
手元のコマンドラインで実行する場合、`!`を入れる必要はありません。

- `exercises/ja/config_gadget.cfg`の設定ファイルを使って`train`コマンドを実行してください
- 学習されたパイプラインを`output`ディレクトリーに出力してください
- `exercises/ja/train_gadget.spacy`と`exercises/ja/dev_gadget.spacy`のパスを指定してください

<codeblock id="04_08">

`spacy train`コマンドの1つ目の引数は設定ファイルのパスです。

</codeblock>

</exercise>

<exercise id="9" title="モデルの探索">

見たことのないデータに対してモデルがどのように動作するか見てみましょう! 
少しスピードを上げるために、パイプラインをすでにいくつかのテキストに対して実行しています。以下に結果の一部を示します。

| Text                                                                                                              | Entities               |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------- |
| アップルはiPhone 8とiPhone Xの性能を制限している - 回避方法はこちら                                               | `(iPhone 8, iPhone X)` |
| iPhone Xの“ノッチ”の役割をようやく理解した                                                                        | `(iPhone X,)`          |
| Samsung Galaxy S9について知っておく必要があるすべて                                                               | `(Samsung Galaxy,)`    |
| iPadのモデル比較？これが2018年モデルのラインナップだ！                                                            | `(iPad,)`              |
| iPhone 8とiPhone 8 Plusは、Appleが設計、開発、販売しているスマートフォンです                                      | `(iPhone 8, iPhone 8)` |
| 一番安いipad、特にipad pro、はどれですか？                                                                        | `(ipad, ipad)`         |
| Samsung Galaxyは、サムスン電子が設計、製造、販売しているモバイルコンピューティングデバイスのシリーズです          | `(Samsung Galaxy,)`    |

文章中のすべての固有表現の中で、**モデルの予測の正解数はいくつでしょう**？
スパンの間違いも、誤りとしてカウントとします！
ヒント：モデルが予測すべき固有表現の数をカウントします。そして、実際にモデルが正しく予測できた数を求め、それを先程のカウントで割ります。

<choice>

<opt text="45%">

モデルが正しく予測した固有表現の数を数え、それをモデルが正しく予測すべきだった固有表現の数で割ってください。

</opt>

<opt text="60%">

モデルが正しく予測した固有表現の数を数え、それをモデルが正しく予測すべきだった固有表現の数で割ってください。

</opt>

<opt text="70%" correct="true">

テストデータに対し、モデルの精度は70%でした。

</opt>

<opt text="90%">

モデルが正しく予測した固有表現の数を数え、それをモデルが正しく予測すべきだった固有表現の数で割ってください。

</opt>

</choice>

</exercise>

<exercise id="10" title="トレーニングのベストプラクティス" type="slides">

<slides source="chapter4_03_training-best-practices">
</slides>

</exercise>

<exercise id="11" title="良いデータ vs. 悪いデータ">

旅行者のレビューについて、固有表現タイプ`TOURIST_DESTINATION` のラベルをつけるトレーニングセットからの抜粋です。

```python
doc1 = nlp("去年アスムテルダムに行った。運河がきれいだった。")
doc1.ents = [Span(doc1, 1, 2, label="TOURIST_DESTINATION")]

doc2 = nlp("人生で一度はパリに行くべきだけど、エッフェル塔はちょっとつまらないな。")
doc2.ents = [Span(doc2, 4, 5, label="TOURIST_DESTINATION")]

doc3 = nlp("アーカンソーにもパリはあるｗ")
doc3.ents = []

doc4 = nlp("ベルリンは夏が最高！公園がたくさんあって、夜遊びが充実していて、ビールが安い！")
doc4.ents = [Span(doc4, 0, 1, label="TOURIST_DESTINATION")]
```

### パート1

なぜこのデータとラベル定義には問題があるでしょうか？

<choice>

<opt text="ある場所が観光地かどうかは主観的な判断であり、確定的なカテゴリーではないので、固有表現抽出器が学習するのは非常に難しいから" correct="true">

より良いアプローチは、`"GPE"`(地政学的実体)または`"LOCATION"`というラベルだけを付け、ルールベースのシステムを使って、その実体が観光地であるかどうかを判断することです。
例えば、知識ベースを用いたり、トラベルウィキで調べたりすることができます。

</opt>

<opt text="一貫性を保つためにもパリは観光地と表記すべきであるから。そうしないとモデルが混乱してしまいます">

米アーカンソー州のパリは観光地である可能性もありますが、これはラベルスキームがいかに主観的であり、ラベルを付けるかどうかを判断することがいかに難しいかを浮き彫りにするだけです。
結果として、この区別を固有表現抽出器が学習するのは非常に困難になります。

</opt>

<opt text="スペルミスのある「アスムテルダム」のような（正しくは「アムステルダム」）、珍しい単語を固有表現としてラベル付けすべきでないから">

非常に珍しい単語やスペルミスであっても、固有表現としてラベル付けすることができます。
実際、文脈に基づいてスペルミスのあるテキストのカテゴリを予測できることは、機械学習ベースの固有表現抽出器の強みの一つです。

</opt>

</choice>

### パート2

- `doc.ents`を書き換えて、`"TOURIST_DESTINATION"`ではなく、`"GPE"`(都市、州、国)というラベルだけを使うようにしてください。
- もとのデータではラベルが付いていなかった `"GPE"` 固有表現のスパンを追加することを忘れないようにしてください。

<codeblock id="04_11">

- 既にラベル付けされているスパンについては、ラベル名を `"TOURIST_DESTINATION"` から `"GPE"` に変更するだけです。
- 1つのテキストには、まだラベル付けされていない都市と州が含まれています。固有表現スパンを追加するには、トークン数を数えて、スパンがどこから始まり、どこで終わるかを調べます。そして、`Span(doc, start, end, label)`でスパンを作り、固有表現のリストに追加します。
- トークンの境目が分からない場合、`list(doc)`で確認できます

</codeblock>

</exercise>

<exercise id="12" title="複数ラベルでのトレーニング">

ここに、新しい固有表現タイプを学習するために作成されたデータセットの一部があります。元のデータセットには数千文が含まれています。
この演習では、ラベル付けを手作業で行います。
実際には、おそらくこれを自動化してアノテーションツールを使用したいと思うでしょう。
例えば、[Brat](http://brat.nlplab.org/)という人気のあるオープンソースのソリューションや、[Prodigy](https://prodi.gy)というspaCyと統合できる、私達が作ったアノテーションツールなどです。

### パート1

- データにある`"WEBSITE"`の固有表現のオフセットを計算してください。
  手動で文字数をカウントしたくないときは、`len(doc1)`を使ってください。

<codeblock id="04_12_01">

- 終了オフセット終了オフセットは、その位置の文字を含まないことに注意してください。
  例えば、2の位置から3の位置までの固有表現の場合、開始オフセットは2で、終了オフセットは4となります。

</codeblock>

### パート2

先ほどラベルを付けたデータに加えて、数千の類似した例を加えてモデルを学習しました。
学習後、`"WEBSITE"`ではうまくいっていますが、`"PERSON"`を抽出しなくなってしまいました。なぜこのようなことが起こるのでしょうか?

<choice>

<opt text='モデルにとって、<code>"PERSON"</code>と<code>"WEBSITE"</code>のように異なるカテゴリを学習するのは難しいから'>

モデルが全く異なる複数のカテゴリを学習することは可能です。
たとえば、spaCyの事前学習の英語モデルは、人と組織とパーセンテージを認識することができます。

</opt>

<opt text='学習データには<code>"PERSON"</code>の例が含まれていなかったため、モデルはこのラベルが正しくないと学習したから' correct="true">

もし`"PERSON"`固有表現がトレーニングに含まれているにも関わらずラベル付けされていなかったら、モデルはこのスパンを出力すべきでないというように学習してしまいます。
同様に、今まであったラベルがトレーニングデータに含まれていない場合、モデルはそのラベルのことを忘れてしまい、予測しなくなってしまうことがあります。
</opt>

<opt text="両方の固有表現タイプを認識できるように、ハイパーパラメータを再調整する必要があるから">

ハイパーパラメータはモデルの精度に影響を与える可能性がありますが、ここでは問題ではないでしょう。

</opt>

</choice>

### パート3

- `"PERSON"`の固有表現「ピューディパイ」と「アレクシス・オハニアン」のアノテーションを含むように学習データを更新します。

<codeblock id="04_11_02">

- もっと固有表現を追加するには、さらにスパンをリストに追加します。
- 終了オフセット終了オフセットは、その位置の文字を含まないことに注意してください。
  例えば、2の位置から3の位置までの固有表現の場合、開始オフセットは2で、終了オフセットは4となります。

</codeblock>

</exercise>

<exercise id="13" title="まとめ" type="slides">

<slides source="chapter4_04_wrapping-up">
</slides>

</exercise>
