stMind

about Tech, Computer vision and Machine learning

データセットをtrain/val/testに分割するコードをnumpyで簡潔に記述する

tl;dr

numpy.splitを使って、aryを3つのsubarrayに分割する。

import numpy as np
train, val, test = 
    np.split(ary, [int(len(ary) * .6), int(len(ary) * .8)])

簡単な説明

データをtrain/testに分割する時、scikit-learnのtrain_test_splitを使うことが多いと思いますが、 train/val/testと分割しようとすると、一度train/testと分けた後でtestに対して再度train_test_splitするなどが必要です。

numpy.split(ary, [a, b])は、第一引数に指定されたaryに対してary[:a], ary[a:b], ary[b:]と分割されるため、一回の処理でデータセットをtrain/val/testに分割することができます。

train/val/testで60/20/20に分割するときは、

np.split(ary, [int(len(ary) * .6), int(len(ary) * .8)])

と指定すればOKです。

ただし、np.splitは単純に分割するだけですので、各セットのラベルの分布を維持するtrain_test_splitのstratifyのような分割をしたい場合には、別途ケアする必要があります。

参照先

以上の内容は、下記stackoverflowの投稿を参照したものです。

stackoverflow.com

Pythonで行列から行と列を取得するコードを簡潔に記述する

tl;dr

アスタリスクによるアンパックとzipを組み合わせる。

for row_vals, col_vals in zip(matrix, zip(*matrix)):
    print(row_vals, col_vals)

簡単な説明

まず、matrixは次のようなリストとする。

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

行は難しいことはなく、問題は列の方。 ここで、アスタリスクでアンパック→アンパックされた各リストに対して、zipで一つずつ要素を取り出してタプルとして返す、という処理をすることで行列の転置と同じことが実現できる。

print(*matrix)
# [1, 2, 3] [4, 5, 6] [7, 8, 9]

for col_vals in zip(*matrix):
    print(col_vals)
# (1, 4, 7)
# (2, 5, 8)
# (3, 6, 9)

従って、最初のコードを実行すると、行と列を一つずつ取り出すことが出来る。

for row_vals, col_vals in zip(matrix, zip(*matrix)):
    print(row_vals, col_vals)
# [1, 2, 3] (1, 4, 7)
# [4, 5, 6] (2, 5, 8)
# [7, 8, 9] (3, 6, 9)

13年かけてApache Solrのコミッターになった人が語る、OSSコミッターになりたい人向けアドバイス

Apache SolrはOSS全文検索システムですが、そのApache Solrのコミッターになった人が、オープンソースプロジェクトのコミッターになりたい人向けにアドバイスをしているブログ記事のメモです。

opensourceconnections.com

最初にパッチを投稿したのが2007年7月12日、4662日後の2020年4月6日にコミッターになったということで、その期間は約13年! ご自身の経験をもとに、コミッターになるためのアドバイスが書いてあります。以下、その内容です。

  1. まず、そのプロジェクトの文化を知ることから始める。どのように意思決定されているのか?どんなツールを使っているのか?様々な頭字語は何を意味するのか?メーリングリストに参加し、すべてのコミットを読もう。
  2. 小さなことから始めて、徐々にやることを増やしていく
    • 既存のパッチを取り込み、テストする。 パッチを最新のコードベースに更新する。 学んだことを文書化する。
    • ドキュメントに新鮮な目を向ける。何かの仕組みについて頭を悩ませることがあったら、その都度、ドキュメントを修正してみる。これは、すぐに貢献できる強力な方法で、プロジェクトに参加するための最も早い方法であり、かつ、認知的な負荷が最も少ない方法。
    • メーリングリストで質問に答える。質問に対する妥当な回答を明確にできれば、どれだけ学んだかが分かる。
    • バグフィックスバグフィックスバグフィックス。 正しい解決法が簡単にわかり、答えが明らかなバグを選ぶ。正しい解決方法が非常に曖昧な場合は、おそらくあまり賛同を得られない。コミッターは、時間があるときに、あなたの修正を適用するということを忘れないように。
  3. コードを書き始める準備はできた?プロジェクトの中核となる基盤をリファクタリングするのはやめよう(少なくとも今は)。その代わりに、パイロットフィッシュのようになって、アクティブに活動しているコアコミッターの人と共に泳ぎましょう(意訳)。プロジェクトのビジョンを受け入れ、彼らが行っている大きなタスクの関連タスクを拾ってみよう。そして、ユニットテストを書いてみる、リファクタリングの機会を探す、複数のプラットフォームで手動テストを行う。あなたが貢献していること(プロジェクトを加速させていること)を彼らが理解したら、自分のチケットをいくつか割り当ててもらえるように働きかける。これが、コミッターに直結しているのを何度も見てきたし、もしこのようにしていたら、もっと早くコミッターになっていたかも。

13年間も貢献し続けたことが単純にすごいことだなと思いますし、そうやってずっと貢献してきた人をコミッターとして迎え入れたApache Solrのプロジェクトも良いコミュニティだなと、偉そうにも読んでいて思いました。

姿勢推定の関節ヒートマップデコードと標準シフト処理の有効性

姿勢推定モデルにおいては、関節毎のヒートマップ表現がよく使われており、OpenPoseを始め、多くの論文で有効性が確認されています。さらに、関節毎のヒートマップから、オリジナル画像における座標へ変換するデコード処理は、これまで十分に考察が行われてこなかったのに対して、DarkPoseと呼ばれる新しいデコード処理を提案する論文がCVPR2020で発表されました。

arxiv.org

論文では、様々な姿勢推定モデルにDarkPoseのデコード処理をアドオンすることで、検出精度が向上したことが報告されていたのですが、注目したのは、デコード処理を比較した以下の結果です。

f:id:satojkovic:20211107180907p:plain

No shiftingは、ヒートマップの最大値の座標をそのまま関節座標とするもので、Standard shiftingは、最大値の座標mと次に大きい値の座標sを求め、mからsへ0.25だけシフトする処理のことで、Stacked Hourglassの論文で使われたものです。このようなサブピクセルレベルのシフト処理は、ダウンサンプリングされたヒートマップ画像における位置が、オリジナル画像の正確な位置とは一致しないことを補うことが目的で、経験的な値として0.25とされた様ですが、大変な効果があることに驚きました。経験的な固定値ではなく、分布を考慮してシフトするのがDarkPoseで、さらに向上が見られているのですが、データセットにおける有効性は確認した上で、シンプルな実装としてStandard shiftingを使っても良いのかもしれません。

TF OD APIのpipeline.configの読み方(概要編)

Tensorflow Object Detection API(TF OD API)では、Protocol Buffersを使用して学習と評価のプロセスを設定しています。学習と評価用のスキーマは、tensorflow/models/research/object_detection/protos/pipeline.configに定義されており、ハイレベルでは5つのパートに分かれています。

  1. 特徴抽出器の指定など、モデルの詳細設定(model)
  2. バッチサイズやデータ拡張オプションなど、モデルの学習用の設定(train_config)
  3. 学習用の入力画像、正解ラベル、正解BoundingBoxなどのテンソルを生成するinput readerの設定(train_input_reader)
  4. バッチサイズやデータ数など、モデルの評価用の設定(eval_config )
  5. train_input_readerと同様で、評価用のinput readerの設定(eval_input_reader)

それぞれの詳細は、別途まとめをするとして、ここでは基本的な設定について触れることにする。

1. model configuration

モデルの詳細設定は、メタアーキテクチャにより異なり、指定可能なアーキテクチャは3種類。

  1. faster_rcnn
  2. ssd
  3. center_net

それぞれのアーキテクチャの中で、feature_extractorや入力画像の前処理のimage_resizerの設定など、細かく指定ができるようになっている。これは、それぞれtensorflow/models/research/object_detection/protosの中に、faster_rcnn.proto、ssd.proto、center_net.protoにて定義されている。

2. train_config

学習の設定で、29種類の項目がある。基本的な項目としては、以下のようなものがある。

  • batch_size
  • num_steps
    • 学習ステップ数。0とすると上限なしとなる。
  • fine_tune_checkpoint
    • リストア対象のチェックポイントへのパス。Tensorflow2 Detection Model Zooからダウンロードしたpretrainedモデルなどを使用。

3. train_input_reader

学習用の入力データ生成に関する設定。基本は、検出対象クラス名とインデックスの対応を記述したlabel mapと、学習データを記録したtfrecordを使った学習をすることが多いので、それらを指定するところとなる。その他、30種類ほど指定可能な項目がある。

  • label_map_path
    • label mapファイルのパス
  • tf_record_input_reader もしくは external_input_reader
    • tfrecordの場合は、tf_record_input_readerの中で、input_pathとして指定する。

4. eval_config

evaluationのmetricsなど、評価用の設定(35種類)。

5. eval_input_reader

3のtrain_input_readerと同じで、こちらはevaluation用。こちらもtfrecordを使うことが多いので、3と同じ様にlabel_map_pathとtf_record_input_readerを指定する。加えて、データの処理順序をshuffleしないようにする(shuffle: false)、num_epochsは1回だけ(num_epochs: 1)、などもよく使う。

最後に

見てみると、それぞれの大項目には結構な数の設定項目があり、基本的にはmodel zooの設定をそのまま使うことが多いけれど、自分のデータセットでチューニングする時には知っておくと良さそうなので、それぞれまた詳しく調べてみることにする。

TF OD APIにおいてどのモデルを使うのかは、どのように判断されるのか?

tl;dr

pipeline configに含まれるmodelのアーキテクチャ名から判断され、アーキテクチャに応じたbuildメソッドが使われる。 例えば、以下はfaster_rcnn_resnet50_v1_640x640_coco17_tpu-8のpipeline.configファイル。 f:id:satojkovic:20211010212331p:plain

具体的なところ

configはobject_detection/protos/pipeline.protoに定義され、model以外に5つのフィールドがある。

f:id:satojkovic:20211010211715p:plain

また、modelは対応している有効なmeta architectureとしてfaster_rcnn、ssd、center_netの三種類がobject_detection/protos/model.protoに定義されている。 f:id:satojkovic:20211010212524p:plain

そして、model_main_tf2.pyを使って、引数のpipeline_config_pathで使いたいモデルのpipeline configファイルを指定して実行すると、model_lib_v2.pyのeval_continuously()からmodel_builder.pyのbuild()が呼ばれて、アーキテクチャ名に応じたbuildメソッドを実行するようになっている。 f:id:satojkovic:20211010213240p:plain

Composed Image Retrieval on Real-life images(CIRR)

cuberick-orion.github.io

https://arxiv.org/pdf/2108.04024.pdf

Composed Image RetrievalもしくはImage Retrieval conditioned on Language Feedbackは、従来の単一のモダリティを用いた画像検索と異なり、画像とテキストのペアを与えて検索を行うComposed Image Retrievalのタスクです。ICCV2021でコードとデータセットが公開されました。

f:id:satojkovic:20210829144304p:plain

上図のように、参照画像と修正文をペアとして与えて、ターゲット画像が得られるようにするためには、画像中のどこに着目し、どこは無視していいのか、またどの属性を維持し、どれを変更すべきかに関して、モデルが推論し、視覚的かつ言語的にユーザが合意できる結果を返すようにしなければなりません。

従来のデータセットでは、ファッション画像に限定されていたり、人工的に生成された比較的シンプルな画像であったため、上記のような研究には不十分であり、NLVRデータセットをベースにしたCIRRデータセットが提案されました。

また、大規模なVision and Language(V&L)モデルを利用したCIRPLANT(Composed Image Retrieval using Pretrained LANguage Transformers)という手法も提案しています。著者によると、これまでにもV&Lモデルが様々な視覚言語系タスクに適用され有効性が確認されているが、Composed Image Retrievalのタスクに適用された例はありませんでした。

CIRRデータセットでは、TIRG以前ブログにまとめたもの)やMAAFを超えるスコアを実現し、従来のファッションのデータセットではスコアは劣るものの、MAAFはCIRRデータセットで大幅な性能低下が見られ、汎用的なモデルとなっていると結論づけています。

データセットとコードはGithubで公開されています。

github.com

github.com