【ポートフォリオ】Google Colaboratoryで、固有表現抽出データセットの作成、BERTモデルのファインチューニング、Gradio製アプリの作成

# 概要
:::note
ポートフォリオとして、**自作のデータセットでファインチューニングした言語モデルを使ったアプリ**を公開しました。
:::

この記事に関連する一連の記事は、ポートフォリオの解説兼備忘録であり、以下の内容を含みます。
1. **データセットの作成**
1. **言語モデルのファインチューニング**
1. **言語モデルを使用したアプリの作成**

とはいえ、ファインチューニングはTransformersのTrainerを使っただけであり、アプリの作成も、言語モデルが完成したら、ノートブック１つで完結するので、ほとんどの記事はデータセットの作成（と、前処理？）についてになります。

:::note warn
プログラミングと自然言語処理の知識は独学で得たものであり、現場を何も知らないので、本職の方が見られると、「なんでそんなことをしているの？」と思われるようなことばかりかもしれません。
また、可読性を最重視してコーディングしたつもりですが、良いコーディングができているのか分かりません。
何卒ご了承ください。
:::


# 作成物

## アプリ

https://huggingface.co/spaces/wolf4032/japanese-token-classification-search-local-cuisine

入力文の条件をもとに、郷土料理を検索するアプリです。

:::note
Gradioが実行できない場合は、[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/wolf4032/nlp-token-classification/blob/main/local_cuisine_search_app/notebooks/cuisine_search.ipynb)で、Gradioを使わずに固有表現抽出と料理の検索を行えます。
:::

## 言語モデル

https://huggingface.co/wolf4032/bert-japanese-token-classification-search-local-cuisine

[自作のファインチューニング用データセット](https://huggingface.co/datasets/wolf4032/token-classification-japanese-search-local-cuisine)に含まれない表現に対する予測精度は未検証です。
（自分で思いつけなかった表現が使われている文章に対する、予測精度の検証方法が思いつきませんでした。）

:::note warn
何かしらの課題解決のための言語モデルではなく、**自然言語処理のエンジニアになるためのポートフォリオを作る**という目的のために作成したものです。
（それなりの手間はかかるかと思いますが、）辞書と正規表現をうまく組み合わせれば、モデルの出力に近しい抽出を行えそうな気がします。
:::

## データセット

https://huggingface.co/datasets/wolf4032/token-classification-japanese-search-local-cuisine

[アプリ](https://huggingface.co/spaces/wolf4032/japanese-token-classification-search-local-cuisine)へ入力されるであろう文章を、自分一人の拙い語彙と表現をもとに作成しました。
入力文を使用するシチュエーションが限定的すぎるうえ、表現の幅も狭いため、必ずしも言語モデルを使う必要がないと思えるほどに、似通った文章だけで構成されています。

# GitHub

https://github.com/wolf4032/nlp-token-classification/tree/main


# プロジェクトに使用したノートブックの解説
この記事では、ポートフォリオとして固有表現抽出モデルを使ったアプリを作ることにした理由を説明しています。
データセット、言語モデル、アプリの作成方法以外興味がなければ、この記事を読む必要はないので、以下のリンクから、目的のノートブックの解説記事を読んでください。

1. **データセットの作成**
[＃０　導入](https://qiita.com/wolf4032/private/df5522799f3d6b30aaff)
[＃１　基本的な文頭表現の作成](https://qiita.com/wolf4032/private/5fea8539cdb42335e055)
[＃２　文頭表現の分類](https://qiita.com/wolf4032/private/06bdbc09ae72a228867f)
[＃３　似た文頭表現の追加](https://qiita.com/wolf4032/private/ad5cdf11199111e312e7)
[＃４　文頭表現へのカンマと並列表現の追加](https://qiita.com/wolf4032/private/67d8aee0d87d4f1d83de)
[＃５　文末表現の作成](https://qiita.com/wolf4032/private/cc7b8ee77639e328af75)
[＃６　テンプレートの作成](https://qiita.com/wolf4032/private/8071f68c13cfeb561b3a)
[＃７　トークン化前のデータセットの作成](https://qiita.com/wolf4032/private/8c0fadc274a7188a921e)
[＃８　エンコード済みデータセットの作成](https://qiita.com/wolf4032/private/38e6ca2452773f2a5a43)
　
1. **言語モデルのファインチューニング**
[固有表現抽出用BERTモデルのファインチューニング](https://qiita.com/wolf4032/private/08b4f868397ef6d44da9)
　
1. **言語モデルを使用したアプリの作成**
[固有表現抽出用BERTモデルとGradioで、郷土料理検索アプリの作成](https://qiita.com/wolf4032/private/8ad3124c15fb08c127fe)


# プロジェクトの背景

自然言語処理のエンジニアとして適切なポートフォリオなのか分かりませんでしたが、悩んでいても仕方がないので、とりあえず思いついたことをやってみました。

## 自然言語処理のエンジニアを目指す理由

他人や社会を恐れていたり、自分に自信が無かったり、生きることに苦しさを感じている人に寄り添い、自分らしく生きるための足掛かりとなるAIを開発したいからです。

**「人」と話すのは怖いけど、「誰か」に話を聞いてほしい**

そんな「**誰か**」を作りたいです。

## 言語モデルを自作した理由

自然言語処理を学んだことがなく、どのようなスキルが求められるのか分からなかったため、とりあえず言語モデルを自作することにしました。

## アプリとして公開した理由

作成したポートフォリオの機能を、分かりやすく伝える必要があると思ったからです。

## 言語モデルのタスクのうち、固有表現抽出を選んだ理由

パラメータ数の大きな言語モデルを使ったアプリをHugging Face Spacesで公開するには、ハードウェアのアップグレードが必要になるため、要求スペックの少ないタスクとして、固有表現抽出を採用しました。

## 言語モデルのうち、BERTモデルを選んだ理由

固有表現抽出を学習させることができる大規模言語モデルの中でも、パラメータ数が少ないうえ、[BERTモデルによる固有表現抽出の参考資料](https://qiita.com/age884/items/7b8d5c583e59e755aaf0)を見つけることができたためです。

## データセットを自作した理由

個人が利用できる日本語の固有表現抽出のデータセットは、Wikipedia由来のものしか見つけられず、Wikipediaのデータセットを使った固有表現抽出言語モデルのファインチューニングはすでに[前例](https://qiita.com/age884/items/7b8d5c583e59e755aaf0)がありました。
前例と同じデータセット、同じ方針で、コードを自分で書きなおすのも、自然言語処理を学ぶには有効だと思いましたが、ポートフォリオとしては今一つだろうと感じました。
そこで、データセットを自作することにしました。

機械学習で重要と思われる、本来の前処理とは異なることになるだろうし、ポートフォリオとしての価値は無いに等しいのかもしれませんが、いずれにせよ、言語モデルの作成には必要なので、やらざるを得ませんでした。
（一応、作成の過程で、データセットに使用する入力文の作成を一部人力で行ったり、データセットに使うべきではなさそうなデータを省いたり、トークン化とラベル付けをしたりしましたが、それらは前処理にあたるのかもしれません。）
ただ、基本的には、思いついた文章の構成要素を機械的につなぎ合わせただけのデータセットなので、やはり自然言語処理の現場では不要な工程かもしれませんが、”前例の模倣”よりは意義があるだろうと考えました。

## 郷土料理検索機能を付けた理由

固有表現の抽出結果を出力するだけのアプリだと味気ない気がしたため、抽出結果をもとに何かしらの処理を行うアプリを作成しようと考えました。
抽出結果をキーワードとして資料を検索するアプリなら作成しやすいと考え、農林水産省が公開している[うちの郷土料理](https://www.maff.go.jp/j/keikaku/syokubunka/k_ryouri/)を検索対象としました。

## GUIライブラリのうち、Gradioを選んだ理由

Hugging Face Spacesでは、Streamlitか、Gradioのどちらかでアプリを作成することを想定されているようです。
加えて、[こちらの記事](https://qiita.com/NoriakiOshita/items/9cefe65477b9919b8f2e)で、StreamlitをHugging Face Spacesで実行すると、読み込みに時間がかかるという記述を目にしたので、Gradioを使うことにしました。


# 開発環境
Google Colaboratory
（ファインチューニングにGPUを使いたかったため。）


# 補足事項
Gradioのコードをオブジェクト指向で書けるように、`my_gradio.py`というモジュールを作成しましたが、本筋ではないため、解説しません。


# 参考資料

[BERTによる日本語固有表現抽出](https://qiita.com/age884/items/7b8d5c583e59e755aaf0)
[AIアプリをさくっと作るなら、HuggingFace Spaceがおすすめ](https://qiita.com/NoriakiOshita/items/9cefe65477b9919b8f2e)
[Gradio](https://www.gradio.app/)

郷土料理の情報
出典:農林水産省Webサイト(https://www.maff.go.jp/j/keikaku/syokubunka/k_ryouri/)