NNの神髄は目標関数を微分で極値に到達させる(これでback propagationの形でweightの最適化を行う)ことだと思います。
その微分の実現法として『自動微分』法が良く紹介されています。
しかし、『自動微分』の方法を調べても[例えば↓]、関数が数式(解析式,symbolic format)である例を説明されたばかりですが(これで"forward and reverse accumulation"を論ずる)、現実の関数は皆programming言語で定義されるわけですから、内容や形式が様々で、if文やloop文さえ入れている事もあり、解析的な数式表現とは全然異なりますね!
結局、どうやって、『自動微分』が実装されたの?という質問がずーと分かっていません。
この辺明るい方是非ご教授お願い申し上げます。
[例えば↑] <<Automatic differentiation>>
===================
【面白いidea 1】
What is Automatic Differentiation?
Automatic differentiation is really just a jumped-up chain rule.
When you implement a function on a computer, you only have a small number of primitive operations available (e.g. addition, multiplication, logarithm). Any complicated function, like log(x^2)/x.
is just a combination of these simple functions.
In other words, any complicated function f can be rewritten as the composition of a sequence of primitive functions fk:
f = f0∘f1∘f2∘…∘fn
Because each primitive function fk
has a simple derivative, we can use the chain rule to find df/dx pretty easily.
Although I've used a single-variable function f:R→R
as my example here, it's straightforward to extend this idea to multivariate functions f:Rn→Rm.
【面白いidea 2】
Automatic differentiation computes derivatives based on computational functions (which in turn are broken down into basic operations such as addition/subtraction and multipliation/division).
Since TensorFlow does differentiation based on a computation graph of operations, I'd intuitively say that it's automatic differentiation (I don't know of any other technique that would be appropriate here; I think the possibility that TensorFlow is converting the computation graph into a mathematical equation that is then parsed to compute the derivative of that equation is prob. out of question). The authors say "symbolic differentiation" in the TensorFlow whitepaper though -- however, I think this may be a misnomer similar to "Tensor" instead of "(multi-dimensional) data array" if you'd ask a mathematician.
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+3
人がキーボード叩いて実装されてはいると思います。
結局微分は一般的な形式が存在するので難しくはなさそうですが。
自動微分が普通では書けないと思う理由はなんですか?
http://ailaby.com/chainer_foward_backward/
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/cc/gradients/math_grad.cc
ちなみに微分できないと自動微分できません。
define-and-runだとif文を挟んだ際にif文の分岐分だけグラフのパターンが分かれてしまうため、一般に論理構造を含む実装は困難です。
TensorflowのEagerモードなど、define-by-runで動的にグラフを形成する場合は実装が少々簡単になります。
グラフを計算するときは具体的に入力値が定まっているときなので常にグラフは分岐しない一本道になります。
以下コメント欄を転記。
http://tensorflow.classcat.com/2018/07/17/tensorflow-tutorials-automatic-differentiation/
https://www.tensorflow.org/guide/eager#computing_gradients
上の2つのリンクをたどってみてください。
Eagerの場合逐次実行できるのでGradientTapeというもので計算のフローをたどることができます。
遅延評価されるので、入力を実際に与えたときに初めてフローが形成されます。
なので、実は途中でif文を大量に挟んでも問題ありません。
if文があっても、特別な入力に対しては一つのフローにならなければならないからです。
これは動的にグラフ形成を許すEagerモードならではの実装だと思われます。
結論としては、
①シンボリックには計算していません
②特定の値に対して計算フローを形成するので、必ず一本道になり、単純な自動微分に帰結します
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.34%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2018/08/18 14:09 編集
有難うございます。
>自動微分が普通では書けないと思う理由はなんですか?
純粋に数式の形で表現されている関数(数学意味上の関数)なら、勿論その導関数が簡単に利用できると思いますが、
ところが、予め予約していないユーザ定義の任意数学関数を計算機言語で表現しようとすると、特定の計算機言語においての『関数』になり、即ちコードになりますね。その中にsin,cos expが含まれても、分岐文やループ文によって相当複雑の『数式・関数式』になるわけですから、そのようなコードで表現している数学関数の導関数をLIBはどうやって自動的に導出してくれるの? という質問です。
(『自動微分』は数値微分ではないことにご注意いただきたいのです。)
2018/08/18 18:48 編集
要はユーザがコードで計算機言語の『関数』の形で任意の"数学関数"を定義し、そしてユーザ定義の計算機言語の『関数』の名前をTensorFlowの導関数を求める関数に渡せば、(自動微分で)ユーザ定義関数の導関数を返してくれます。確かに、TensorFlowの導関数を求める関数はどうやってユーザ定義の関数の微分を計算するのはなぞですね。{この場合、解析式(symbol)の形での微分ではない同時に「数値微分」でもないですから}
2018/08/18 22:53
多層ニューラルネットワークにおいて、各層において逐次微分されることを考えると、チェーンルールが適応できることをたいそれた言葉で表現しているだけです。
「それぞれの基本的な関数に対する導関数を予め用意」しておけば、「基本的な関数によって構成された複雑なネットワークの微分を自動的にできる」、ということになります。
tensorflowのリンクのコードを読めばわかりますが、単純関数の導関数は人の手で定義されます。
独自の関数を使いたいのであれば、導関数を自分で書く必要があります。
wikipediaを引用すると
> 自動微分は複雑なプログラムであっても加減乗除などの基本的な算術演算や基本的な関数(指数関数・対数関数・三角関数など)のような基本的な演算の組み合わせで構成されていることを利用し、これらの演算に対して連鎖律を繰り返し適用することによって実現される。自動微分を用いることで偏導関数値を少ない計算量で自動的に求めることができる。
---
複雑ものの場合、ものによっては微分が定義されていません。
そのような関数を使うと、損失関数を処理できず、エラーを吐きます。
top-kを独自実装しようとすると過去にそのようになっていましたが、今はもしかしたら実装されてできるようになっているかもしれません。
難しい関数、特に論理構造があると微分をうまく定義できないことは珍しくありません。
そのような場合には、スコアは難しい関数で順方向だけ計算して、誤差伝搬するときに解析的となる近似表現を用いてネットワークを最適化します。
2018/08/19 10:32 編集
本当にお世話になっております。
仰った事良く理解できます。
ただ、現にユーザ自作の関数(プログラミング言語のコードで表現されているやつ)も簡単に導関数を得られるらしいですね。これこそ理解に困ります。
実例:<<https://github.com/tensorflow/tensorflow/issues/15418>
import tensorflow as tf
import tensorflow.contrib.eager as tfe
tfe.enable_eager_execution()
#↓自作関数で、人間なら、symbolic数式に変換できるが、マシンにとって相当難しいはず。("・・"は space)
def loss(w):
・・ prediction = 2 * w + 1
・・ true_value = 11
・・ return tf.cast((true_value - prediction)**2, tf.float32)
tfe.gradients_function(loss)(0.1) # ← loss関数の導関数を得る!
↑lossはユーザ定義の関数で(内容的に限定されてないようです)、それにlossの導関数をユーザが定義していません。
このgradients_functionはどうやってlossの導関数を算出可能になっているでしょうか。
2018/08/19 12:58
ので、調べてみました。
なかなかにおもしろい話でした。ありがとうございます。
---
http://tensorflow.classcat.com/2018/07/17/tensorflow-tutorials-automatic-differentiation/
https://www.tensorflow.org/guide/eager#computing_gradients
上の2つのリンクをたどってみてください。
Eagerの場合逐次実行できるのでGradientTapeというもので計算のフローをたどることができます。
遅延評価されるので、入力を実際に与えたときに初めてフローが形成されます。
なので、実は途中でif文を大量に挟んでも問題ありません。
if文があっても、特別な入力に対しては一つのフローにならなければならないからです。
これは動的にグラフ形成を許すEagerモードならではの実装だと思われます。
結論としては、
①シンボリックには計算していません
②特定の値に対して計算フローを形成するので、必ず一本道になり、単純な自動微分に帰結します
実装については下の2つです。
https://www.tensorflow.org/api_docs/python/tf/contrib/eager/gradients_function
https://github.com/tensorflow/tensorflow/blob/r1.9/tensorflow/python/eager/backprop.py