機械学習のためのデータを収集する各段階の考え方

[機械学習のデータの集め方](https://qiita.com/nonbiri15/items/f5c5c4357458bfeb03bb)　を先に書いた。

ただ、その中では書き足りないことに気づいたので、ここに書く。
機械学習の書籍やチュートリアルは多数あって、機械学習をとても始めやすくなっている。
代表的な問題に対しては、良質のデータベースが既に作られていて、代表的なフレームワークによっては、簡単に大規模な学習をトレースできる状況にもなっている。

でも、あなたは、機械学習をしなきゃいけない状況なんですよね。

なにかしら、既存の機械学習結果では満足できない理由があって、自分達で機械学習を推進しなければならないときに役に立つであろう考え方を述べたいと思う。


## 何を実現したいのかを明確にしよう

- 何を実現したいのかを、表現してみましょう。
- 実現したいこと自体が実は違っているということが得てしてあるものなのです。
- それを実現するためにどんなやり方がありうるのかを、たくさんの人と語り合ってみましょう。
- 実は機械学習など必要としない手法が既にあるかもしれません。
    - 例：玄関を開けて人が中に入ったら照明をつけるのに、可視のカメラで人を検出する必要はまったくありません。

- その技術を使用する条件によっては、条件をコントロールすることで、簡単な問題に置き換えられる場合があります。

画像認識の分野で機械学習をする場合には、
入力画像の見え方を避けて通ることができない。


- 入力画像はどのようなカメラで、対象物はどの程度の大きさで見えるのか？
- カメラと対象物の位置関係はどうであるのか？
- カメラで検出をしたい最小限のフレームレートはどれくらいなのか？
- システムはどれくらいの遅延をゆるすのか？

こういったことも、次の段階に移る前に考えなくてはならない。




以下の説明では、それらの検討を終えた後でも、機械学習を使うことが価値があると判断したとします。


## そもそも学習をする必要があるのか
機械学習結果は多数公開されています。
それを使うことで十分な場合が相当あるはずです。

OpenVino のretrained-models などを調べてみてください。
~~https://software.intel.com/en-us/openvino-toolkit/documentation/pretrained-models~~

https://docs.openvino.ai/archive/2023.0/omz_models_group_intel.html

人検出でも、以下のようにそれぞれの学習済みモデルが利用可能になっています。

Human Detection

- Eye-Level Detection
- High-Angle Detection
- Detect People, Vehicles, & Bikes
- Pedestrian Detection
- Pedestrian & Vehicle Detection

まず、既存の学習結果で、要件を満足する学習結果がないかを調べること。

HaarCascade 検出器でさえ、ネコの顔検出がある。

https://github.com/opencv/opencv/tree/master/data/haarcascades

github cat detector などを調べると多数の実装例を見つけるだろう。

まず、それらの中に、ライセンス上利用できて、しかも十分な性能を満たすものがあるかを調べてください。

勉強のための機械学習ではなく、何か実用上の機械学習を開発しようとするならば、データを集めて学習させるというのは、それなりの手間がかかるものだということを念頭においてください。


## 可能性を模索するためのデータ収集
ある種の機械学習を実現するという目標を実現可能な目標に設定するかどうかのデータの収集だ。
この段階では、典型的にうまくいきやすいはずのデータを用意して、うまくいくこともあることを確認する。

学習用のデータと評価用のデータを別々に準備することがまだできていないこともあるだろう。
この段階では、それでもいいから、学習したデータで識別することを確認する。
それで、うまくいく場合があることを確かめる。

用意したデータの中の特徴量が、機械学習の識別（例えば検出）に有効なものを含んでいることがわかります。

- この段階では、学習データのアノテーションの数を抑えて結果を出したい.
- できるだけラフなアプローチを目指します。
- 顔検出だったとしたら、マスクをしている顔や顔の一部が隠れている画像は除外して、検出しやすい顔画像だけを対象にします。

その結果をふまえて次の段階に移行します。

## 可能性を確信するためのデータ収集
先の検討では、検出できるかもしれないというレベルのものでした。
それをもっと確信するするためのデータの収集と実験を行います。

- 前回よりも学習データの範囲を広くします。
- 学習がうまくいきやすいアノテーションルールを考えます。
    - 例：学習データのポジティブサンプルに共通な要素で共通性の高い範囲に検出枠をつけます。
    - 例：明確なネガティブサンプルを学習用のネガティブに含めます。
    - 例：判別が難しい部分を無理やり判別しようとかしない。どっちに分類されても大丈夫な部分を最初は広めにしておく。
- それらの学習データとアノテーションルールとで何がどうなりそうか予想する。
- 学習を実行し、評価を行います。

評価結果のチェックポイント

- 例：うまくいった例が前回よりも増えたか。
- 例：どういうので改善して、どういうので難しいのだろうという事前の予想がどうだったか？
- 例：事前の予想が外れた点はなんだったか？
- 例：事前の予想が外れた理由はなんだろうか考える。
    - データを増やせばなんとかなるたぐいのものか？
    - 最初のデータの分類に無理があったか？
    - 画像データ中の対象物の大きさが小さすぎる？
    - 画像データ中の対象物がボケている？
    - 画像データに加えた検出枠の位置に無理がありすぎたか？
  
- 例：学習データでは分離できて、テストデータでは分離できていない場合
- その分離できていない程度に応じて問題への理解を深める。
- それらの理解にもとづいて、次の目標を定める。

## 初期の目標の達成をするためのデータ収集

初期の目標を明確にします。
初期の目標では、どのようにビジネスのうえで価値を生じるのかを明確にします。
不完全な度合いがあっても、ビジネス上に価値を生じるような使い方を考えます。
どういう部分で失敗しやすいかも考えます。

判定処理が、どれくらいの時間に終わって、実際の使い方の中で許容されるかどうかも検討します。

初期も目標での達成するべき再現率・適合率はどれくらいかを仮置きしてみます。

この段階では断念することも明確にします。
断念することがあるので、ポジティブサンプルとネガティブサンプルとの区別が簡単になります。
その状況の中で、正解データを与えるためのアノテーションルールを明確にします。

アノテーション作業で必要になる工数を見積ります。
その工数を確保するために、チームに説明をします。
あとはデータを増やせばうまくいくのだという見通しを説明します。
会社の場合には、その必要な工数を捻出するための予算を確保します。

そして、アノテーションを誰でも行えるように十分に明確にします。
アノテーションルールは運用するのが楽なような一貫性をあたえることです。

また、そのアノテーションを行うのに適したツールを確保します。

そして、アノテーションのチームで作業を進めます。

機械学習のデータをきちんとバージョン管理します。

- データを失うことのないようにバックアップをとること、
- データに改変を加えていったときに、いつどのような改変をしたのか、間違った改変を加えてしまったときには、その前に戻せること、
- 複数の人間がネットワーク越しに協力してデータを育て利用することができること、

このようにして作り上げたデータを利用して機械学習を行います。

この結果は、満足のいくものだったでしょうか。

満足のいくものだった場合には、それ以上の作業は不要です。


## 初期の改善をするためのデータ収集

この結果を改良したいという組織的な動機を持つ場合には、改善をすることができます。

改善をするためのデータを収集するのはただではありません。
何をどう改良すれば、ユースケースの中で利点となるのかをふまえて初期の改善を計画します。


例：パスポートの照合用の顔検出の場合、サングラスの人や横向きの顔を検出してもユースケースの中でメリットはない。

顔検出自体の検出率は、あまり問題になりません。既存のオープン・ソースの顔検出の学習結果で、かなり十分な水準の顔検出になっているはずです。パスポートの顔検出では、サングラスをかけた人やマスクをして顔照合にのぞむ人はいないのですから。パスポートでの顔照合の場合、ある程度以上の好条件で顔検出ができればいいので、過度に難しい条件の顔を検出してもメリットがありません。


ユースケースにおいて改善の恩恵にあずかれる部分を優先的に取り組もう。


難易度とユースケース上の価値の2軸で問題を考えます。

まず取り組むべきは、ユースケース上の価値があって、難易度が高くない領域です。
ユースケース上の価値がある部分を解決することで、機械学習を改善することに価値があると判断してもらうことです。

ユースケース上で最大の価値があっても、難易度が高すぎるものは、最初の改善のためのターゲットに設定してはいけません。
難易度が高すぎるものは、機械学習を失敗に導きやすいものです。

人検出も[HOG-SVMの検出器](https://www.pyimagesearch.com/2015/11/09/pedestrian-detection-opencv/)の時代には、理由があってそのデータがあります。この時期の人画像の学習データは、直立した人に限って学習し、検出していました。そのため、直立した人を正規化した画像で学習させるという割り切りをしています。
（まだこの時点では、深層学習はなかったのです。）

難易度の高いものが扱えるだけの状況になるまでは、ユースケース上の価値があって、難易度が高くない領域と考えます。

学習データとしては、その領域のデータを集中的に集めます。
データの出現頻度に忠実にデータを与えても、既に検出できる領域のデータを増やすばかりで、改善したい領域のデータは増えません。


学習データの領域を集中することは、どの領域のデータで学習が改善したのかどうかを判断しやすくするという利点もあります。


追加する学習データが十分に多ければ、ポジティブサンプルとネガティブサンプルを分ける分離面の精度を出しやすくなります。

そのことも、改善する領域を絞り込むべきだと考える理由です。


学習データをそろえた後に、機械学習を実施します。

あなたの結果はどうだったでしょうか。

追加した領域のデータで、再現率・適合率はどうなったでしょうか。

追加した領域で、再現率・適合率が改善していることを確かめられたでしょうか。

成功していれば、機械学習の改善の作戦はうまくいったことがわかります。

### 学習結果が思った改善になっていない場合

機械学習が失敗する理由はいくらでもある。

#### 例：検出の学習の場合
　物体ではなく背景を学習してしまうことはよく起こりがちだ。
　サッカーをしている人を検出する人検出を学習させたときには、
　えてして芝生の上で競技している人の画像を学習してしまい、
　クレイのグラウンドで練習している人を検出しないなどということが起こりうるのだ。

#### 例：医療用画像の場合
　医療用画像の場合、ある症例に該当するかどうかの2値判定をする場合を考えよう。
　機械学習では、画像中のどの特徴量を使って分類するかを、システムに任せてしまう部分がある。
　そのため、病院Aと病院Bとで利用している医療画像機器の特性の違いをポジティブサンプルとネガティブサンプルの違いとして学習してしまう危険がある。病院Aの画像は定期健康診断の画像でポジティブサンプルの数は少なく、圧倒的に多数がネガティブサンプル。病院Bの場合には、症状に疑いがある人が集中的に集まる病院。そういう状況だと、病院Bの医療画像機器の特性が見つかるとポジティブサンプルに違いないと判断されてしまうということが起こりうる。

このようなことが起こりうるのだということに注意をはらってほしい。

##### 医療用画像では、色が重要なことが多い。
- 一般物体検出の場合には、物体の色によらず検出が成功するように、学習時に色を変動させる仕組みを取り入れているのが多い。
- しかし、医療用画像での判定・検出では、色が重要な場合が多い。
- だから、医療用の機械学習では、学習時に色を変動させることは無効化しておいたほうが良い。

### 適合率と再現率で学習状況を分析してみよう

適合率が低いとき
　誤検出パターンが多いということ。
　ネガティブサンプルの学習が足りていないことを意味している可能性が高い。
　ネガティブサンプルが足りないから、ポジティブサンプルとの境界がネガティブサンプル側に偏っていているのではなかろうか。



再現率が低い時
　その１：ポジティブサンプルのデータが不足している。

　その２：ポジティブサンプルが本来あるべき分散を持っていない。
　例：人検出の学習データを１つの環境で撮影したデータだけで済まそうとすると起こる。
　ある環境でだけはうまくいくが、別の環境では性能が全く出ない。
　例：小型犬だけでイヌ検出の学習データとして大型犬を検出できるか？


　その３：不適切なデータがネガティブサンプルに混入している。
　例：背景画像の中に検出すべき対象の画像が紛れ込んでいる。
　人検出器を作ろうとするときに、ラベリングを見逃した人の画像が残っている。
　人検出器を作ろうとするときに、マネキンの映像が紛れ込んでいる。
　人とマネキンとを区別しようとすると学習は極めて難しくなってしまう。
　


対策：
　ポジティブサンプルの実データを収集する。
　ポジティブサンプルを収集するには、収集を効率よくする工夫をすること

 - 例：動き差分をもとに動きのあるときだけ、画像を収集する。
 - 例：精度はないが、ある程度絞り込めるレベルの検出器を作ってデータを収集しやくする。
 - 例：不足しているポジティブデータをもとに加工したデータを増やし、それをポジティブデータに加えて機械学習を実施する。
    - 画像に変形を加える。
    - 画像の輝度分布を変える。
    - 画像の対象物ではない領域を書き変える。
- 例：そのようにして水増ししたポジティブデータを使って検出器を作り直し、その検出器を元にさらに、ポジティブサンプルの候補を自動で拾い上げ、手作業で絞りこんで、本当のポジティブデータを見つけ出す。
    - その作業を繰り返すことで、ポジティブサンプルを効率的に収集できるようになっていく。


適合率も再現率も低い時：
　ポジティブサンプルとネガティブサンプルとが十分に分離しやすくなっていない。
　ポジティブサンプルをよくばりすぎていて、そのためにポジティブサンプルとネガティブサンプル間の距離が狭くなりすぎている。
　そのため、分離する境界の精度が出ないので、適合率・再現率の両方が低くなっている。
　
　ネガティブサンプルとの区別がつきにくいポジティブサンプルの検出を諦めて学習をさせた方が結果として適合率・再現率を向上させることができる場合がある。

 ネガティブサンプルの中にターゲットのポジティブデータが残ってしまっていることもえてしてありがちだ。学習に用いたネガティブサンプルに対して検出をかけて、間違ってポジティブサンプルが混入しているかどうか確認してみよう。
　また、ポジティブサンプルではないのだが、とても紛らわしいものがあることもある。
学習上の戦略として、その紛らわしいデータをネガティブサンプルから除外するという選択もある。
（そのやり方が妥当かどうかは適用する技術の分野によるだろう。）

　

## 継続的な改善をするためのデータ収集

### 機械学習を利用して、機械学習を加速しよう。

ある程度の検出器ができた時点で、今までよりも学習データの収集が楽にできるはずです。
仮に、自転車検出器を作ると仮定しましょう。
最初は、自転車画像を収集（もしくは撮影）して、自転車の検出ができるようにしようとするはずです。
それが、所定の使用条件で、十分な性能のある検出器かどうかが気になるところです。
膨大な動画画像の中で、自転車が写っているのを全数きちんと検出できているかをチェックしようなんてことは、大変すぎることです。
全数きちんと検出できているかを、人力ですべてアノテーションをしてから評価する。
そういうのは、従来からよくある考え方です。
しかし、それは、貴重な開発者の時間と体力を奪ってしまうやりかたです。

提案する手法は次のとおりです。
・まず、ほどほどの検出器を元に、検出結果を拾い上げよう。
・拾い上げた画像と検出位置を、必要に応じて修正します。
・そして、その結果を追加して学習を更新します。
・更新した検出器を使って、従来未検出だったものが検出になったものを拾います。
・その拾った画像と検出位置とを必要に応じて修正します。
・そして、その結果を追加して学習を更新します。


このように繰り返すことで、未検出は減らしていけるはずです。
このようなやり方に対しては、「それじゃ、元の学習と後の学習で性能がどれだけ改善したか、ちゃんとしたことがわからないじゃないか。
検出できたものをベースに考えるなんて、評価方法としてまっとうじゃない。」　そう判断される方もいると思います。


開発の初期の段階で、完璧な評価方法を作ろうとすること、完璧な評価をしようとすることは、どだい無茶な話だと思っています。
ですから、このように積み上げて開発していったものを、一連の動画に対して、自転車検出をした結果、どのように未検出・誤検出をするのかを評価すればいいのです。最初の段階で評価しても、性能が不足していることはわかりきっているのですから。機械学習の検出結果を元にすれば、長時間の動画データに対して、優先順序が高い画像に着目して処理をすすめることができるのです。学習を打ち切る最後の段階で、これだけ性能が出ていることが確かめられればいいのです。







(執筆予定)
----

## 学習の改善が見えるようにしよう
- 隠れがない判定しやすい画像
- 姿勢の変動でやや難しい画像
- 隠れが生じているので判定が難しいめの画像


改善していることをその都度示し続けることです。
すでに達成した内容で十分利用に耐えるかもしれないのです。
それ以上の改善は、不要かもしれないのです。

### 学習結果の評価項目例
#### 検出対象物の大きさによって検出率の低下がどう起こるのかを確認しよう。
- ある評価用の画像セットがあったら、それらを一律の倍率で縮小して、CNNの推論エンジンに入る時の入力画像中での対象物の大きさが小さくなるようにして検出率を評価しよう。
- このとき、同じ画像セットを用いて縮小することで、縮小だけの効果を見ることができる。
- 検出対象物の大きさが小さくなると検出率が下がる。
- これは、画像中の対象物が小さくなることで、画像中の特徴量がなくなって検出できなくなるということに起因している。
- しかし、たいがいの場合は、学習画像中に小さな対象物が含まれていないことによって起こっている。
- 対象物の大きさが小さくなるように、学習用画像群を一律に縮小したものを学習画像に加えて学習をやり直してみよう。
- 期待される効果としては、前回よりも、縮小サイズでの検出率の低下が減っていないだろうか。

#### 回転画像での検出率
その検出を行うユースケースの中で、対象物がどのような見え方をするだろうか。
landscapeの向きで、人物画像をとるだろうか？　それともportraitの向きで人物画像をとるだろうか。
そこまで極端ではないものの、多くの場合３０度程度の回転を加えても、同じように検出できることを期待していることはないだろうか。
そういう場合には、回転を加えた画像で検出率が保たれているか試してみよう。

データのaugmentation の状況によっては、学習時にいくらかの回転を加えた画像での学習が加わっているかもしれない。
しかし、３０度程度の回転を加えたの検出率がどうなっているのかは、確かめたおいた方が無難だ。






## ポジティブサンプルの共通性を高める手法
ネコがいるかどうかを検出したいときに、２つの考え方がある。

- bounding box をつけるのに、尻尾も含めるか。
- bounding box をつけるのに、尻尾を除外するか。

ポジティブサンプルの共通性を高めるためならば、尻尾を含めないという流儀がお勧めだろう。
尻尾を含めなければ、bounding box に対して胴体の部分の共通性が高まる。
胴体部分の共通性が高まれば、ポジティブサンプルの画像特徴の共通性が高まる。
そのことで、ポジティブサンプルとネガティブサンプルの分離性が向上すると推測する。

ネコを検出するのに、ネコの特徴である長い尻尾を検出枠の外にしてしまうのは違和感もあるだろう。

既存のアノテーション済みのデータベースでも、ネコのbounding box は尻尾を含めているのがふつうだからだ。

自分の解決しようとする課題は何なのか、それに対してどう取り組むのか、あなた自身で考えてください。

----


## ネガティブサンプルの収集
### ネガティブサンプルへの加工
ネガティブサンプルは、加工してもネガティブサンプルだ。
- 画像への歪みの付与
- ノイズの付与
- ヒストグラムの改変
- 画像の回転
- 画像へのボケの付与
- 色相の変更

こういった方法でネガティブサンプルは増やすことができる。
---
追記
ある程度の検出器ができ始めたときには、
半教師あり学習(semi-supervised learning) の手法を調査してみることだ。

[出現頻度のまま学習データの比率にするのは得策ではない。](https://qiita.com/nonbiri15/items/49bdd34c01b084d7cfac)


SSII2020 [OS2: 限られたデータからの深層学習](
https://confit.atlas.jp/guide/event/ssii2020/static/lecturenotes#TS)