2023年5月10日水曜日

C++でトップダウン型自動微分をする

C++で書かれたAIの学習プログラムが少ない理由に、トップダウン型の自動微分ができないからというのがあります。

自動微分ができないと、バックプロパゲーションするときに偏微分値を手動で計算してさらにそれをコーディングしないと求められなくて、学習やレイヤー設計が簡単にできないようです。

この問題クリアしないと、組み込みやスパコンでC++で学習させたりできないじゃん。

みんなどうやって自動微分しているのか調べてみました。



・FB


https://pytorch.org/tutorials/advanced/cpp_autograd.html

PytorchってC++で自動微分ができるんですね。すげー。

Pytorchは自動ベクトル化もできるのでC++とかもでもきるんだろうか?


・Google

TensorFlow2じゃないと自動微分できないし、PythonのautogradやJAXライブラ使っているのでC++で自動微分できません。力わざとお金の力で解決?

なんとGoogleが負けている。なんという過酷な開発競争


・PFN

https://www.preferred.jp/ja/news/pr20181203-1/

PFNもC++で自動微分するの大変だったのね。

でも撤退。県外。


・OpenAI


https://github.com/oneapi-src/oneDNN

OneDNNというC++自動微分できるライブラリを自分たちで作っている!

そりゃそうだよね。そうしないとChatGPTとか計算できないよね。



色々調べてみると、どうやらFBのPytorchとOpenAIのOneDNNくらいしかC++で自動微分できないのね。

しかもカスタムのベクトル関数をC++で自動微分できるのはPytorchしかない・・・

悲しい。


ボトムアップ型の自動微分ならば二重数で計算するだけなんですが、トップダウン型のベクトルの自動微分ってそんなに実装するの大変なの?


自動微分をC++で簡単に使うことができる様にしました。

https://github.com/takahiro1127/AutomaticDifferentiation


トップダウン型の自動微分を実装する

https://olanleed.hatenablog.com/entry/2023/04/16/203423


自動微分(Automatic differentiation)のSurvey論文の参照

https://lib-arts.hatenablog.com/entry/diff_implement2



どうやらスカラー型の自動微分のライブラリしか簡単に試せる実装はないらしいです。

任意のベクトル関数の自動微分をするってけっこう大変なのね。

勉強になるねぇ。

自動微分できないと、自動ベクトル化や最適化とかもできなさそうで、負の連鎖になるように思うんですが、どうなんでしょう?


ということで、誰も日本人でC++でベクトルのトップダウン型自動微分をやっている人がいないので、以前Windowsでカスタムビルドできるようにした、pytorchのC++で自動微分してみました。


----------------------

#include <iostream>

#include <torch_torch.h>



int main()

{


auto model = torch::nn::Linear(4, 3);


auto input = torch::randn({ 3, 4 }).requires_grad_(true);

auto output = model(input);


// Calculate loss

auto target = torch::randn({ 3, 3 });

auto loss = torch::nn::MSELoss()(output, target);


// Use norm of gradients as penalty

auto grad_output = torch::ones_like(output);

auto gradient = torch::autograd::grad({ output }, { input }, /*grad_outputs=*/{ grad_output }, /*create_graph=*/true)[0];

auto gradient_penalty = torch::pow((gradient.norm(2, /*dim=*/1) - 1), 2).mean();


// Add gradient penalty to loss

auto combined_loss = loss + gradient_penalty;

combined_loss.backward();


std::cout << input.grad() << std::endl;


return 0;

}



----------------------



----------------------

-0.0678 -0.1252  0.0566  0.0149

 0.2211 -0.0657  0.0009 -0.0186

-0.0982  0.0493  0.0301  0.0358

[ CPUFloatType{3,4} ]

----------------------


できた。

これでおじさんもC++でディープラーニングのレイヤ設計やモデル設計ができるようになりました。


0 件のコメント:

コメントを投稿