2020年も終わろうとしているので久々にブログを書こうと思う。
今回はAIセキュリティについて。(異論はあると思うが) いわゆる AI = ニューラルネットな昨今、AI セキュリティ問題といえばほほぼ敵対的攻撃 (Adversarial Attack) の攻防について侃々諤々されている。敵対的攻撃については既にたくさんの記事があり、技術と情報も凄い勢いでアップデートされているので、今回はまったり (比較的マイナーな) 抽出攻撃 (Extraction Attack) について紹介しようと思う。
抽出攻撃
抽出攻撃とは、一言で言うとニューラルネットを盗む攻撃である。まず、クラッカーはある犠牲者モデル (例えばそれはオープンな学習済み推論 API であったり) に画像などを入力して推論結果を得る。そしてその結果をオラクルとして自らのモデルを学習させることで、盗難モデルが完成するというのが一般的な手法である。
犠牲者からすれば、わざわざコストをかけてアノテーションをし、一生懸命モデルを学習したのに、実質何もしてないクラッカーに盗難モデルを作成されては商売あがったりである……。オーソドックスな実験では以下のような、Copycat CNN (Correia-Silva et al. 2018) などがあるが、簡単なモデルであれば造作もなく盗難されている。

他にも Knockoff Nets (Orekondy et al. 2018) のように、強化学習で効率よく盗難のクエリ(入力)を選択する手法などがある。概念だけ見れば、学習してどんどん盗難が上手くなる AI という何ともディストピア的な産物である。
抽出攻撃と一口に言っても、大きく分けて以下の2つが重要な要素となっている。
- Accuracy (盗難モデルの精度の高さ)
- Fidelity (盗難モデルによるパラメータ再現度の忠実さ)
つまり、パラメータはともかく犠牲者モデルをオラクルとして、高精度の分類モデルの学習を目指すのが前者であり、犠牲者モデルを忠実に再現しようとするのが後者ということになる。実際のところ、後者の方がかなり悪質である。パラメータまで含めたネットワーク情報を完全に再現してしまえば、容易に敵対的攻撃を実施できるバックドアとなり、例えば自動運転などで看板を誤認させ重大な事故を引き起す、なーんてこともできてしまうかもしれない。……まあ、そんな簡単にできるわけないのだが。
Accuracy Extraction
今回紹介する論文は、Accuracy と Fidelity の双方を同時に実現しようという試みである。どっちかというと Fidelity を目指す論文である。
“High Accuracy and High Fidelity Extraction of Neural Networks” (Jagielski et al. 2019)
https://arxiv.org/abs/1909.01838
まず高精度 Accuracy Extraction をどう成功させるかのコツが書いてあるのだが、基本的には単純明快である。①とにかく高精度のモデルを攻撃、②とにかく大量のデータセットで攻撃 (Instagram, ImageNet…)。当たり前である。
あと、クエリ選択に能動学習、モデルの高精度化に半教師あり学習を組み合わせるといい。これも順当である。とにかくクラッカーはアノテーションをサボりたいので、半教師あり学習が強い味方となる。論文では、半教師あり学習として Rotation Loss (分類と同時に画像の回転を予測)したり、MixMatch (Berthelot et al. 2019) で検証している。現在だと MixMatch もさらに改善されているが、本旨とはズレるので半教師あり学習の説明は他に任せることにする。ほとんどアノテーションの要らない FixMatch (Shon et al. 2020) なんか相性が良さそうだ。
ところで、Knockoff Nets (Orekondy et al. 2018) に Accuracy Extraction と蒸留のアナロジーが紹介されていた。確かに、犠牲者モデルと盗難モデルの関係は、一度学習したモデルを使って別のモデルを学習するという意味で基本的に蒸留と同じことをしていることになる。

Fidelity Extraction
ここからが本題である。未知のブラックボックスのニューラルネットに対して、入力と出力を見るだけでパラメータを忠実に再現できるのか? 答えは無理である(少なくとも今は)。
しかし、かなり限定的なモデルについてはほぼ解くことができるのが、この手法の面白い(かなり語弊があるが)ところである。ターゲットモデルは、全結合 (活性化関数 ReLU ) の2層ニューラルネットである。現実問題、ImageNet 学習済みモデルにこいつをファインチューニングすれば、たいがいの分類問題を実用的な精度で解けると思うので、あぐらかいてモデル構築している人は冷や汗をかいてほしい (俺だ)。
ターゲットモデルのパラメータをまとめると次のようになる。それにしても Keynote でニューラルネット書くのクソめんどくさいな……。それは別にいいや。中間層の次元数 \(h\) が、入力次元 \(d\) より多いと解が見つからなくなるので注意(普通中間ノードを入力より多くしないとは思うが)。

入力を \( \vec{x} \)、ここでは出力をオラクルと呼び、\( O_L (\vec{x}) \) とすれば、このモデルの計算は次のようになる。ここでのノーテーションはわかりやすいように、矢印はベクトル、太字は行列を表すことにする。
さて、この手法では、おおまかに次のようなステップでモデルを盗んでいく。
- 変化点探索
- 特徴抽出パラメータ (\(\boldsymbol{A}^{(0)}, \vec{B}^{(0)}\)) の推定
- 線形変換パラメータ (\(\boldsymbol{A}^{(1)}, \vec{B}^{(1)}\)) の導出
一つずつ説明する。
変化点探索
まずは、中間層の ReLU に対応する変化点 ( \( h \) 個あるはず) を求めていく。ReLU を使ったニューラルネットの基本性質として、連続的に入力を変化させた時の関数の応答は、ReLU が活性化する変化点ごとに区分線形になっている。区分線形とは、入力の微小な変化に対して出力は常に線形であることを意味する。そもそも活性化関数の無いニューラルネットは、どれだけ深くしてもただの線形回帰だ。
ここで、\( \vec{x} \) に対して任意のベクトル \(\vec{u}, \vec{v}\) とスカラー値 \(t\) を使って、\(\vec{x} = \vec{u} + t \vec{v}\) と分解する。(ベクトルは一応何でもいいが、ゼロベクトルなど変なものや直交してたりするとダメだろう)。

すると、ある中間ノード \(i \in \{1 \ldots h \} \) に対して、\(\mathrm{ReLU} \left[ \left( \vec{A}{i} \cdot \vec{u} \right) t + \vec{A}{i} \cdot \vec{v} + B_i \right] \) なので、\(t\) をスイープさせれば、いい感じで ReLU の区分線形区間を横切ることになる。というわけで、出力 \(O_L (x)\) の \(t\) 微分について、MNIST でやると以下のようなって、区分線形区間を横切る時に出力の傾きが変わっていることが分かる。

闇雲に変化点を探すのは大変だが、応答は線形なので2つの \(t_1, t_2\) をとって、外挿した値と出力が一致すればそこが変化点、違うなら他の変化点があることになるだろう。最終的に \(h\) 個見つかれば終了する。\( t \in [-h^2, h^2]\) ぐらいをスイープすればいいらしい。

モデルパラメータの決定
特徴抽出パラメータ \(\boldsymbol{A}^{(0)}, \vec{B}^{(0)}\)、つまり1層目のモデルパラメータを先程の変化点を使って求めていく。そのために、出力 \(O_L (\vec{x})\) の二階微分を使う。
各中間ノードに対応した変化点入力 \(x_i\) (\(i \in { 1…h }\)) に対する要素の変位 \(x_i + c \cdot e_j\) (\(j \in \{ 1…d \}\)) を考える。すると、\(c\) を十分に小さくとれば、独立に各変化点を観測できる。
1層目で抽出される特徴量を \(f_k (x) = \mathrm{ReLU} \left[ \vec{A}{k}^{(0)} \cdot \vec{x} + B_k^{(0)} \right]\) (\(k \in \{ 1…h \}\)) と書き、\( \delta(\cdot) \) を条件を満たす時1、満たさない時0となる関数とすると、
\end{align} $$
3行目、十分小さい \(c\) の範囲で、変化点 (\(k = i\)) 以外のノードは引き算でゼロになる。また4行目、変化点の項のみが残ったが、符号、つまり変化点の近傍で傾きが正負どちらに変化するかまでは分からない。
つまりまとめると、特徴抽出パラメータは、
絶対値は分からない……のだが、比は分かる。\(| A_{ij}^{(0)} / A_{i1}^{(0)} |\) は求まるので、\( |A_{i1}^{(0)}| = 1 \) だと思うことにして、特徴抽出パラメータを決定する。高々定数倍なので ReLU の変化点は変わらないし、線形変換で帳尻を合わせれば一応気にしなくてもよいはず。
符号はどう決めるか? これは、先程の式を \(e_j + e_k\) の方向に変位させる。すると以下のようになる。
値を見ると符号の一致不一致が確認できることが分かる。ただ、やはり \(A_{i1}^{(0)}\) の符号は分からない……泥臭い。ちなみに \(\vec{A}_i^{(0)} \cdot \vec{x}_i + B^{(0)} = 0\) なので、符号さえ決まればバイアスは分かる。
もう後は、重みの値(ベクトル内の相対値)と、ベクトル内の正負が分かったので、あとは、特徴量 \(i\) に対する線形変換のベクトル \(\vec{A}_{i}^{(0)}\) の符号を確定すればよい。
ここまで来ると執念を感じるが、2種類のベクトル \( \vec{z}, \vec{v}_i \) を探索して求めることで最後の足がかりとする。これは、すべてのノードをゼロにするベクトル \(\boldsymbol{A}^{(0)} \cdot \vec{z} = 0\) と、特定ノード \(i\) だけ変化させる \(\boldsymbol{A}^{(0)} \cdot \vec{v}_i = e_i\) である。頑張れば求まる(雑)。
あとは、これらのベクトル \(\vec{z}, \vec{v}_i\) を使って、犠牲者モデルを攻撃する \(O_L (\vec{z}), O_L (\vec{z} + \vec{v}_i), O_L (\vec{z}- \vec{v}_i)\) と、\(\vec{A}_i^{(0)}\) の符号が確定することになる。
あとは、単純な線形変換なので、これまで攻撃してきた結果から連立方程式で \( \boldsymbol{A}^{(1)}, \vec{B}^{(1)} \) が確定する。
実験
導出した Fidelity Extraction について MNIST と CIFAR10 で実験している。ぶっちゃけかなり手堅く、どんなデータを使おうが変わらないので問題はパラメータ数だけであったようだ。以下の通り、5万パラメータ程度の予測であれば 100% 言い当ててしまっている。

10万パラメータの結果を見れば分かるように、どうも考察によると二階微分の計算で誤差が発生し、10,000回に1回ぐらいの割合で失敗するらしい。抽出層の重みの誤差自体は気にならないが、そのバイアス、分類層の重み、バイアスへと伝搬することで無視できない誤差となっていくようだ。なので、その誤差をオラクルからの学習ベースで補正してしまうという方法を使う。

99% の精度で、補正無しの4倍のパラメータまでカバーしており、80% の精度向上となっている。また、恐ろしいことに予測されたパラメータで作成した敵対的攻撃は100% 成功したとのこと。
最後に
今回はちょっと抽出攻撃について紹介した。そんなものもあるんだなぁと思ってもらえればいいが、AIがもっと普及した頃にこの記事も日の目を見るかもしれない。モデル隠しておけばいいやと思って出力を垂れ流しにしていると、思わぬ攻撃に見舞われるという話である。
Fidelity Extraction も色々と説明してきたが、モデルパラメータを忠実に再現できるにしても、層が増えた瞬間に変化点がどこの層だか分からなくなるし、そもそもオラクル丸見えってどういう状況設定だよという話である。いわんや複雑なモデルをや。ただ、ニューラルネットの特性を使った式展開はなかなか興味深く、もしかしたら何かの研究に役立つかもしれない。
今日はこのへんで。また気が向いたらブログを書こう。