TT Lab
ブログ

한국어 English 日本語 中文

はじめる
ブログ

ブログ

オプティカルフローとRAFT:動きをピクセルで読み解く — すべてのペアを一度に比較し、同じ更新を繰り返す

ステータス: ドラフト (2026-10-13)、一部実測。 論文の数値は原文を開いて条件とともに確認しました。自分で試したものはノートPCのCPUによるnumpyのサンプル(code/05_flow_toy.py, 1秒未満)です。卓球動画のオプティカルフロー実測(Farneback)はリポジトリ docs/tt/PERFORMANCE.md 2.9.7の値であり、RAFTは私たちの動画では実行していません(未実測)。 シリーズ「ビジョンモデルを読む 2」第5編。ここからは「動き」です。次回: 動画モデル.

目次

1. 直感:ピクセルごとに1つの矢印

動画の2フレームを重ねてみると、動いたものはズレており、止まっているものは重なります。 オプティカルフローは、最初のフレームのピクセル一つひとつに「次のフレームのどこへ行ったか」を示す矢印(水平移動u、垂直移動v)を1つずつ付与したマップです。1080pのフレームであれば、矢印は200万個ほどになります。

オプティカルフローは「何が」動いたのかは告げず、「どこがどれだけ」動いたのかだけを伝えます。そのため、対象物を知らなくても使用できます。卓球動画では、選手が大きく動く区間(ラリー中)とうろうろしている区間(ラリーの間)が、オプティカルフローの大きさだけでもかなり区別できます。

2. 古典的手法の仮定とその限界

古典的手法は2つの仮定から出発します。

  1. 明るさは一定である。 点が1つ動いても、その点の明るさは変化しない: I₁(x, y) = I₂(x+u, y+v)。
  2. 動きは小さい。 そのため、右辺を1次テーラー展開できる: I_x·u + I_y·v + I_t ≈ 0。

式は1つですが未知数は2つ(u, v)あります。Lucas–Kanade(1981)は「小さなウィンドウ内のピクセルは一緒に動く」と仮定し、ウィンドウ内の式を集めて最小二乗法で解きます。

この方法が破綻する箇所が3つあります。

3. 学習モデルは正解をどこから得るのか

写真においてピクセルごとに正解の矢印を手動で付与することはできません。そのため、学習型のオプティカルフローは 合成データから始まりました。FlowNet(2015)は写真の背景上に3Dの椅子モデル809種類をレンダリングして貼り付け、アフィン変換で動かした Flying Chairs(22,872ペア)を作成しました。動きを直接作成しているため、正解が正確に分かっています(論文)。以降、よりリアルなFlyingThings3D、アニメ映画から抽出したSintel、自動車の公道KITTIへと続く学習の順序が標準となりました。

損失はたいてい エンドポイント誤差(EPE, End-Point Error) です。予測された矢印の終点と正解の矢印の終点の間の距離(ピクセル)を平均します。

4. 図解:RAFT

RAFT: 모든 짝을 한 번 비교, 같은 갱신을 반복 프레임 1 프레임 2 특징 인코더 ⅛ 해상도 두 프레임 공유 상관 부피(4차원) 4단 반복(학습 12번, 평가 24–32번) 지금 추정 둘레 반경 4칸 조회 4단 모두 합성곱 GRU 가중치 공유 추정 += Δ ⅛ 해상도 흐름 손실: 매 반복의 추정을 정답과 L1 로 비교 뒤 반복일수록 무겁게, 가중 0.8^(N−i) 마지막: 볼록 결합 업샘플링 이웃 3×3 의 가중 평균(가중치도 학습)으로 원래 해상도로
図:RAFT:特徴量抽出 → 4次元相関ボリューム → 半径によるルックアップ → 重みを共有するGRUの反復

RAFT(Teed & Deng, ECCV 2020)は3つのコンポーネントで構成されています。

  1. 特徴量エンコーダ。 2つのフレームを同じCNNに入力し、⅛解像度の特徴量(256次元)を抽出します。明るさではなく特徴量を比較するため、「明るさは一定」という仮定が緩やかになります。
  2. すべてのペアの相関ボリューム(all-pairs correlation volume)。 最初のフレームのすべての位置と2番目のフレームのすべての位置の間の内積を一度に計算し、4次元テーブル(H×W×H×W)として保持します。そして後ろの2つの次元を1・2・4・8ステップでプーリングし、4段階のピラミッドを作成します。一度計算すれば終わりです。
  3. 反復更新器。 現在のフロー推定が指し示す場所の周囲半径4ピクセル分を、4段階のピラミッドからすべてルックアップし、その値を畳み込みGRUに入力して「推定をどれだけ修正するか」(Δ)を出力します。同じ重みのGRUを学習時は12回、評価時はSintelで32回、KITTIで24回繰り返します。200回まで回しても発散しなかったと記載されています(論文)。

ピラミッドを「粗い解像度で解いて細かい解像度に降りていく」段階的な構造として用いていた従来の手法(PWC-Netなど)とは異なり、RAFTは ⅛解像度という単一の解像度ですべての距離のペアをすでに把握しているため、素早く大きく移動したオブジェクトも最初から捉えることができます。

5. どのように学習させるのか

L = Σᵢ γ^(N−i) · ‖ fᵢ − f_정답 ‖₁,   γ = 0.8,  N = 반복 횟수

すべての反復の出力に対して損失を課しますが、後の反復ほど重みを大きくします(論文)。序盤の反復では大きく外れても構いませんが、徐々に正解に近づくべきであることを意味します。この損失のおかげで、GRUは「一発で当てる」のではなく「少しずつ修正する」ことを学習します。

⅛解像度のフローをもとの解像度に拡大する際は、単純な補間の代わりに、近傍3×3ピクセルの加重平均をネットワークが学習した重みで計算します(凸結合アップサンプリング)。オブジェクトの境界でフローがぼやけないようにするためです。

学習の順序はゼロから(事前学習なしで)Flying Chairsで10万ステップ → FlyingThingsで10万ステップ → SintelやKITTIなどを混ぜて10万ステップ → KITTIで5万ステップであり、デスクトップ向けのGPU2枚で学習を行いました(論文)。

6. 実際に動かしてみる

code/05_flow_toy.py はnumpyだけでもRAFTの2つの発想を模倣しています。

  1. 滑らかな模様のある64×64の画像を(3.4, −2.2)ピクセル分だけ平行移動させて2番目のフレームを作成します(フーリエシフトを用いているため、小数点の移動も正確です)。
  2. ピクセルごとに周囲5×5のパッチを特徴量とし、2つのフレームの すべてのピクセルペアの類似度を4,096×4,096 = 1,680万エントリのテーブルとして一度に計算します(相関ボリューム)。
  3. 出発点(0, 0)の周囲半径8ピクセルの範囲内で最も類似している場所を選択します(ルックアップ)。整数単位までしか一致しません。
  4. その推定値を出発点として、「現在の推定通りに2番目のフレームを巻き戻し、残った明るさの差分を勾配で割って修正する」という処理を繰り返します。RAFTのGRUが 学習によって 行うことを、ここではLucas–Kanadeの式をベースにした 手動で記述した ルールで代用しました。
[무늬 있는 그림] 상관 부피 4,096×4,096 = 16.8M 칸
  반경 안 argmax(정수) 추정: EPE 평균 0.6546px · 중앙 0.4472px, 가장 흔한 값 (3, -2)
  갱신 1회: EPE 평균 0.1649px · 중앙 0.0414px
  갱신 2회: EPE 평균 0.1726px · 중앙 0.0602px
  갱신 5회: EPE 평균 0.1593px · 중앙 0.0499px

すべてのペアの比較だけでは整数(3, −2)までしか捉えられず、誤差の中央値は0.45px(真の値3.4, −2.2と整数との間の距離)となります。1回の更新で0.04pxに減少しました。それ以降さらに減少しなかったのは、手動で記述したルールの限界(巻き戻し時に用いる双一次補間の誤差)によるものです。RAFTがGRUを学習させる理由はここにあります。「どれだけ修正するか」をルールではなくデータから学習すれば、補間誤差やオクルージョンといった状況も考慮することができます。

同じことを縦縞模様に対して試してみました。

[세로줄(구경 문제)]
  반경 안 argmax(정수) 추정: EPE 평균 7.5758px, 가장 흔한 값 (-4, 0)
  갱신 1–5회: 변화 없음 (식이 풀리지 않는 화소 100.0%)
  → 가로 움직임 중앙값 -4.00(참값 3.4), 세로 움직임은 17가지 값으로 흩어짐

縦縞は上下に動いても同じように見えるため、縦方向の動きを知る術はありません(17通りの値に分散する)。横方向の動きも、縞の間隔が8ピクセルであるため3.4と3.4−8 = −4.6の区がつきません(最も近い整数である−4が選ばれました)。更新式はそもそも解けません。アパーチャ問題を数値として確認したことになります。学習モデルもこの場合には、周囲のコンテキスト(オブジェクトの境界、他の部分の動き)から推測するほかありません。

7. 論文の数値

モデル 数値(論文) 条件
FlowNetS / FlowNetC(2015) Sintel final test EPE 7.42 / 7.28 Flying Chairsで学習。デスクトップ向けGPUで0.08 / 0.15秒
PWC-Net(2018) Sintel final 5.04, KITTI-15 Fl-all 9.60%, パラメータ数875万 1024×436で約35fps(デスクトップ向けGPU)
RAFT(2020) Sintel clean/final 1.94/3.18(2フレーム)、1.61/2.86(前方のフローから開始)、KITTI-15 Fl-all 5.10% パラメータ数530万(小型版100万)。1088×436で10回反復0.10秒(デスクトップ向けGPU)、1080pで12回反復550ms
RAFT、合成データのみで学習 Sintel学習セット clean 1.43 · final 2.71、KITTI-15 EPE 5.04 · Fl-all 17.4% Chairs → Thingsのみ学習し、他のデータへ直接適用
SEA-RAFT(2024) Springベンチマーク 1pxエラー率 3.686、EPE 0.363 反復4回(学習)・4〜12回(推論)、540×960でRAFTの140.7msに対して70.96ms(デスクトップ向けGPU)

Fl-allは、エンドポイント誤差が3ピクセルおよび正解の大きさの5%の双方を超えるピクセルの割合です。低いほど優れています。

SEA-RAFTは、RAFTの損失を「2つのラプラス分布を混合した負対数尤度」に変更しました。当てやすいピクセルに対してはL1のように、本来あいまいなピクセル(オクルージョン、アパーチャ問題)に対しては誤差を過剰にペナルティしないよう、ネットワーク自身が不確実性を同時に出力するようにしたものです。初期推定値を0の代わりに直接回帰することで反復回数を削減しています(論文)。

8. 限界

9. 我々のプロジェクトとのつながり

TT の一言。 ストライプのシャツが上下に動いても、コンピュータにはそれが動いたかどうかわかりません。本当です、例を使って自分で確認しました。だから光流は「大体どこがどれくらい動いているか」に使い、ボールは別に見つけます。

参考文献

ログインするといいねできます

コメント

まだコメントはありません。

ログインするとコメントできます