孤独でつらい機械学習データの作成を、ワイワイ楽しくする環境を3日で作る

21世紀でもっともセクシーと言われるデータサイエンスは、18世紀を彷彿とさせる奴隷的な作業によって支えられています(要出典)。その作業とは、データを作る作業(=アノテーション)です。多くの場合、アノテーションは孤独な単調作業の繰り返しです。延々と続けていると、[全ての単語にunkとつけるようになる事例も報告されています](https://twitter.com/AntiBayesian/status/1128666738717970432?s=20)。つまりつらい！のです。

本記事では、「孤独で辛い」アノテーションを「みんなで楽しく」行える環境を作る方法を紹介します。そのポイントは以下3点です。

1. Easy: アノテーションを楽に
2. Feedback: アノテーションした結果がすぐにわかるように
3. Gamification: アノテーション結果をみんなで競い合う

## Overview

アノテーションを行う流れは以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/a122529d-6b56-38d6-a486-21d8de8d3e30.png)

1. **Annotation Tool** for Easy: アノテーションを楽にするためのツールを用意
2. **Infrastructure** for Feedback: アノテーションした結果がすぐわかるようなインフラを整備
3. **Visualization** for Gamification: Leader Boardを見てアノテーションをした結果を競い合う！(Kaggleライク)

アノテーションツールは、オープンソースのdoccanoを使用しました。

[chakki-works/doccano](https://github.com/chakki-works/doccano)
![named_entity_annotation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/f70abc39-3852-7ae3-2cf9-49d74dc9c4e2.gif)

インフラ構成は以下のようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/25062d05-3de9-7506-f975-b5303344e8e4.png)

* [Slack](https://slack.com/intl/ja-jp/)でアップロードしたデータを、
* [Integromat](https://www.integromat.com/en/)でS3に転送し、
* [Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html)で[ECS](https://aws.amazon.com/jp/ecs/)の学習タスクをキックする。結果は、
* [Google Spread Sheet](https://www.google.com/intl/ja_jp/sheets/about/)に書き込み[Google DataStudio](https://datastudio.google.com/navigation/reporting?hl=ja)でダッシュボードとして表示する。
  * こちらが実際のダッシュボードです: [YANS ANNOTATION HACKATHON](https://datastudio.google.com/u/0/reporting/1nrzE6eXPYiT_fz4dYwp6W1QLcz6iUUKG/page/WgVy)

実装は[yans-2019-annotation-hackathon](https://github.com/icoxfog417/yans-2019-annotation-hackathon)で公開しています(Starいただければ励みになります！)。構築の詳細については後述します。

今回の試みは、[自然言語処理若手の会(YANS 2019)](http://yans.anlp.jp/entry/yans2019)にて「アノテーションハッカソン」として実際に行いました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">モデル作りではなく「データ作り」で競い合うハッカソン「アノテーションハッカソン」をやります！<br><br>これを機にアノテーションを経験してみたい方、アノテーションツールを使ってみたい方、退屈なアノテーションをもっと面白くしたい方、ぜひご参加を！<a href="https://twitter.com/hashtag/yans2019?src=hash&amp;ref_src=twsrc%5Etfw">#yans2019</a> <a href="https://t.co/MTuGfEqmNG">pic.twitter.com/MTuGfEqmNG</a></p>&mdash; ymym@やむやむ (@ymym3412) <a href="https://twitter.com/ymym3412/status/1165886121219223552?ref_src=twsrc%5Etfw">August 26, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

いろいろトラブルはあったのですが(主にマシンリソース関係)、なかなか楽しくできたと思います！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/5c2d7dc8-311f-d099-4069-c8247460ac8e.png)

こうした仕組みで、一人でも多くのアノテーターが21世紀の人権を獲得できれば幸いです。

以下では、インフラ構築の過程(夜間 x 3日)と詳細をリアルタイム形式で解説します。

## Detail

### Day1

イベント(YANS2019)にて「アノテーションで何か企画をやりたい」という話はあったが、実際どうするかは未決であった。アノテーションは孤独でつらい作業なので何かモチベーションがないと人が集まらないと思案。Kaggleみたいにコンペ形式でできればいいね、というアイデアが出る。この時点で開催まであと数日だったが、多分なんとかなるという楽観的な見込みのもと作業を開始。

アノテーションツール自体はすでに開発していたので([doccano](https://github.com/chakki-works/doccano))、アノテーション済みファイル~リーダーボードに表示までのインフラ構築に集中する。ファイル提出~結果表示Webアプリケーションの開発&ホスティングとなると18世紀ではすまないハードワークが待っているので、外部サービスをフル活用することにする(自作だとリーダーボードがしょぼくなる懸念もあった)。

リーダーボードは、Google Data Studioがいい感じに表示できそうと目星をつける。同じGoogleだからインフラも[GCP](https://console.cloud.google.com/?hl=ja)で揃えようかな(ついでにいろいろ触っておきたい)という誘惑が心に芽生えるが、このタイミングでそんなことをしていると18世紀では(以下略)になるので、慣れたAWSで構築することにする。

1. ファイルをなんらかの方法でS3に転送
2. 転送イベントをLambdaでトリガして学習処理を実行
3. 結果をGoogle Spread Sheetに書き込んでData Studioで表示する

ここまでの流れを確定。

### Day2

肝心の学習をどうするか。それが問題だ。
アノテーションのタスクはNERと決まっていたが、日本語のNERが学習できるライブラリはそう簡単に転がっていない。spaCyの日本語対応はWatchしていて、そこでNERを学習していることを思い出す。

* [Add ja_core_web_md-2.1.0](https://github.com/explosion/spacy-models/pull/16)

こちらにあったデータと学習スクリプトを参考に手元で実行してみる。spaCyは[日本語対応済みのspaCy(まだマージされていない)](https://github.com/explosion/spaCy/pull/3945)を使用。うまく動くことを確認。

ただ、この学習はNER以外にPOSタギングなども含んでいる。今回はNERのモデルだけ学習したいので、[spaCyのexample(train_ner.py)](https://github.com/explosion/spaCy/blob/master/examples/training/train_ner.py)を参考に学習スクリプトを実装。doccanoでアノテーションしたデータでNERが学習できることを確認。

学習スクリプトが完成すれば、あとはDockerfileを作れば[ECS](https://aws.amazon.com/jp/ecs/)で走らせることができる(Lambdaはタイムアウトとランタイムの構築が手間なので却下)。Dockerfileを作成するが、spaCy & Sudachiのインストールがとても重い(pip installが長い)。docker buildとdocker pushで夜がふける。

### Day3

Dockerfileの修正が開発速度のボトルネックになっていたので、この点を修正できないか検討。[multi-stage build](https://docs.docker.com/develop/develop-images/multistage-build/)を使って、環境構築とアプリケーション(学習の実行)を分ける。これで問題となっていたbuildのスピードを上げることができた。ただspaCy単独にこだわらず[GiNZA](https://github.com/megagonlabs/ginza)を使えば済む話ではあったので、最終的にこの工夫はあんまりいらなかった。

あとは「ファイルをなんらかの方法でS3に転送」のみ。Slack Appを開発するとなるとBotをホスティングする必要があり、そんな時間はもちろんない。IFTTTとかでなんとかいけないのか・・・と探したところ、[Integromat](https://www.integromat.com/en/)でいけそうだという情報を掴む。ただファイルの直接送信はできなかったので、ファイルのリンクだけ送りLambda側でダウンロード&S3へ保存するようにする。Lambdaではこの後ECSのタスクをキックして学習を実行。学習スクリプトには結果書き込みまで入れたので、ECSのタスクが終わればダッシュボードも更新される。

最後にファイル転送~学習実行~リーダーボード更新の疎通確認テストを実施。Integromatは結果も見やすく(↓)いい仕事をしてくれた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/ac1495e8-98d0-5234-9ccb-4c279fd4fd42.png)

そして北海道(会場)へと旅立ったのだった(完)。

## In fact

ここまではアノテーションを過酷な人手作業として描写しましたが、初手人手でやることはほぼありません。まずルールや辞書を使ってアノテーションを行い、それを修正するのが定石です。学習済みモデルによる事前のラベルづけやアノテーションサポートも検討します。全件人手でアノテーションを行うのは18世紀型の発想と言わざるを得ません。

イベント中、私自身も辞書/正規表現(ルール)でアノテーションをしてみました。↓ぐらいまでには自動でアノテーションすることが可能です。いくつか間違いや重複がありますが、間違いを修正するだけ vs 最初から全部人手、では作業負荷に雲泥の差があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/d11fce21-93c9-bc76-1b46-308aac7acc27.png)

(実装は[yans-2019-annotation-hackathon](https://github.com/icoxfog417/yans-2019-annotation-hackathon/tree/master/yans/annotation)で行っています)

実際、ハッカソンに参加したチームはルールを効果的に使用しています。使った手法について記事を書いてくださるとの連絡も受けているので、楽しみに待ちましょう！

以上、構築の過程まで含めて参考になれば幸いです。人権のあるアノテーションライフを送りましょう！