目次
背景
- いくつかの画像分類の機械学習プロジェクトを経験してきて思ったこと
結論
- 期待値を下げろ
- DNNのモデルなんて先行研究があってもどうなるかはわからない
- サンドボックスの理想的な環境で結果が出ても、Sim2Realに進んだらうまく行かない事が多い
- 人より精度が高かったら導入してもらうように説明するべき
- 機械の期待値を下げて、導入してもらうのが大切
- くれぐれもDNNで何でもできると説明するのはよすべき
- 学習データは絶対に生成する
- 生成データ(synthetic data)が一番大切
- それを確率的に生成するので、入力画像の分布をコントロールする
- 下地を寄せる (例えば、自動生成した画像の背景など)
- ノイズを入れる
- 文字のフォントを合わせる
- 自動運転だって何だって、うまく行くプロジェクトはそうなる
- これができないと、残念ながらPDCAを高速に回せない
- 画像の特徴
- PNGとJPGでは分布が異なる
- Y軸でLog、X軸は0~255のPixelでヒストグラムを作る
- 例えば、文字の中心は黒(0)で輪郭は(1~255)になる
- それがjpgだと0が弱い。他方、pngは非圧縮なので0が強い
- そうすると、二値化したときに変化がでる
- なので、最頻値を二値化するときはthreasholdで見る
- 最頻値の理由
- 白と黒の図面の場合は、最も出現するのが白のため
- 経験的に決めていることもある
- 指標は一つにフォーカスする
- 例えば、取るのがそもそも難しい課題は、最初はRecallにフォーカスするとか
- Recallで間違ってもいいので欲しい画像を取れたら、あとあといらない物を消す前処理を入れる
- Precisionは低くてもやる
- 課題の選択
- 全部の課題に対処することはできない
- エッジケースを除いて、正常系で、さらに簡易的なものを選択する
- 別の言い方だと、分母を絞る
- 90点と50点だと印象が全然違う
- 先にテストの問題を自分で狭めて高いスコアを出せるように調整する
- 特徴
- RGBで特徴量を入れる
- 普通の画像で入れるよりも、RGBで解く超量をまとめる前処理をしてモデルに入れる
- 精度と速度
- 精度を優先したあとに、処理速度を最適化する
- ONNX Runtimeで最適化する
- 失敗時
- エラーについて考察をする(エラーアナリシス)
- 失敗を集めて、hard negative miningする
- $時間軸 \times 課題軸$でReportをまとめる
- 例
- 過去の課題 (past tasks)
- 今週の課題 (present tasks)
- 今週の進捗 (present progress)
- 今週の改善点 (present conclusion)
- 今後のスケジュール (future tasks)
- 課題ベースで話す
- スケジュールベースで話す
- 例
- 定量的と定性的に
- 数量的に判断する
- データが中心
- パターンの整理 (ルールベースの場合は)
- 特に、お客さん自体もルールを完全に把握していない時がある
- 情報を整理して交通整理することは大切
- データの選別の基準
- 事業ドメインやスコープの内・外
- コアユーザー vs. ライトユーザーのデータ
- 標準データ(ISO標準) vs. 非標準データ
- フィージビリティ
- できる所をやる => 費用対効果high
- できない所をやらない => 費用対効果low
- ベースラインを作る
- まずは簡単なやり方でベースラインを作る
- ムーンショットを狙うと、うまく行かなかった時にソフトランディングできない
- そのため、予め安全地帯を確保するのが大切
- 複数の手段を用意して、予め失敗に備える
- アルゴが優先
- 機械学習のDNNよりアルゴを優先するべき
- もしくは、DNNよりLLMを優先
- なぜなら、DNNは未知の変数が多く汎化性能も不明な事が往々にして発生する
- 結果をCherry-pickしたり、一面的に見て精度を判断してしまう事が多い
- はじめから堅く古典的アルゴで攻めて、もしくは万能のLLMで攻める
- それでも要件を満たせないなら、DNNに進む
- DNNの場合はデータが命なので、どれだけデータを集められるかの戦いになる
- 課題もモデルもless is more
- 例えば、XXXの価格予測の問題
- まず価格を簡単なものと難しいものに分ける
- これは誰でもできる
- しかし本質は、モデルを2つに分けた方がいい
- つまり、そもそも混合モデルであるという前提を持つ
- なぜこうするかというと、1つのモデルだと外した時にエラーアナリシスがやりにくいから
- つまり、めんどくさいかもしれないが、予めモデル自体も分解する
- すれば、重み調整やモデルの調整やデバッグもしやすく、本当の課題が見やすくなる
- EdgeではモデルはC++で動かす
- Edgeで早く動かしたいなら、まずはMobileNetとかの軽いモデルを選ぶ
- その上で、軽いランタイムを使ってC++で高速に動かす
- くれぐれも、Pythonで動かさないように
- Server-sideのLLMの場合は
- Prompt Engineeringをする
- 特にFew-shotが絶大
- さらに、CoTで分割統治法的に課題をStepByStepで解くのも大切
- 本質的にはその2つが一番効く
- Context engineeringも大事
- Messageは圧縮するべき
- これをしないと、メッセージが長くなると確実にやり取りがバグる
- Cacheを使う
- 特にAWS BedrockのClaude系のモデルはCacheが強い
- System Promptとかは、経験上9割引になるので有効活用する
- Routerパターンと特化Agentを使う
- 一つのAgentに全部やらせるのは難しいのでAgentを複数用意し、Router Agentに振り分けさせるのがいい
- Promptも最適化する事もできる
- Prompt Engineeringは限界がある
- たとえRouterパターンやStrands-Agentが持つGraph機能やらで分割しても限界がある
- 本質的にはLoRAなどでファインチューニングするべき
- Agentは確率的に間違えるのでPromptのチューニングは限界がある
- SSEやNDJSONでStream処理するのは限界がある
- structured outputをjson一つに対して行えないので、一度Agentが結果を間違えるとめんどくさくなる
- シナリオテストをたくさん実行するのと、fallback用の処理がないと厳しい
- 間違えたらリトライする仕組みを入れる必要がある
- Prompt Engineeringをする
- 先行研究やOSSを真似る
- これは機械学習だけではないが、基本真似が一番速い
- 人類の進化も真似から始まったし、近代の日本も欧州の真似をしただけ
- 真似=学ぶ、学校だって先生を真似るし、武道でも守破離が基本
- 最初は先行者を真似るべき
- TPPした後に、進化させてTPPSする
- つまりは、最初はベースラインを少し改造しただけでOKという事
- ムーンショットは狙うより、実現可能性の検証のため、既存+ちょっと改造で最初はOK
- HDDとSSDとRAMを使い分ける
- データセットは容量の大きいHDDに保存するべき
- しかし、データセットから計算した特徴量は、予め計算してNVMeのSSDに置くべき
- なぜなら、毎回特徴量の計算やEpochごとに大きなIOが発生するため
- 例えば、音系のモデルなら音声を圧縮したMelスペクトルとかは学習の前に計算しておく
- また、data mixingを学習時にやってaugumentationしているなら、それはオンメモリにするべき
- SSDはランダムアクセスに弱く、それをやると無駄なIOが発生して待ち時間が長くなるから
- 学習データの品質について
- データの量は大切だが、なぜ大切かというと多様性のため
- 特に、学習時の $データセットの分布=推論時の分布$ が理想
- そして、その分布のズレ(Distribution Shift)がそのままエラーになる
- 分布ズレの原因は以下が考えられる:
- 共変量シフト:$P(X)$ が変わる (つまり、予測の割合は変わらないけど、入力の割合が変わる)
- ターゲットシフト / ラベルシフト:$P(Y)$ が変わる(入力の割合は変わらないけど、予測の割合が変わる)
- コンセプトシフト:$P(Y|X)$ が変わる
- だからクラスの分布も大事
- データの量と質
- 例えば、音からsilence/speakingの分類をするとする
- 学習後、推論すると環境音でsigmoidの結果が0.5になった
- この理由は、DNNから出力されたlogitが0を出したから
- つまり、どっちか分からないから0.5になった
- 本来はsigmoidの結果は0にならないといけないが、データセットに同じ環境音がないからそうなったということ
- 結局はDNNは巨大な場合分けをする機械なので、その機械にケースにあったデータを渡す必要があるということ
- 学習がうまくいかない時のシンプルなエラーアナリシス
- 学習後にテストデータでうまくいかない => 学習データが間違っている、学習方法の間違い、学習不足やShift、DNNのパラーメター不足など
- 学習後にテストデータでうまくいっている => 学習とデモの分布のズレが原因なので、学習データセットの不足
- Evalが頭打ち => モデルの未学習が多い(つまり、データをしっかり学習して汎化・一般化していない)
- 学習データの蒸留
- 基本的に蒸留してTPPするのが一番てっとり速い
- 特にデータセットが悪いと、いくら量や多様性を増やしてもgarbage in, garbage outになるから
- 質の高いデータセットを作る意味でも、予めteacher-studentモデルでやったほうがいい
- 特に、データセットは用意したのに、意図しない挙動をする時はデータセットの質が低い場合が多い
- Dataのかさ増し
- 画像系では、マージンをいれるなどして汎化性能を高める為data augmentationを行う
- 音声系だと、noise mixing augumentationや、データの前後に無音margenを入れるなどのmixingが過学習を抑えられる
- Data Mixingは既存2つのデータの合成で、Data Aumentationは1つのデータを加工する
まとめ
- 色々なパターンがあるが、失敗しないと学ばなないことが多い
- セルフニューラルネットワークの学習は続くだろう
