ソースは bazel によって自動的に生成されるため、このソースは見つかりません。ソースからビルドする場合、このファイルはbazel-genfiles
. inspect
モジュールを使用して見つけることができるローカルディストリビューションにも存在します。このファイルには、基になる C++ 実装に対して自動生成された Python ラッパーが含まれているため、基本的には一連の 1 行の関数で構成されています。conv2d_backprop_input
そのような生成された Python op の基になる C++ 実装を見つけるための近道は、スネーク ケースをキャメル ケースに変換することです。Conv2dBackpropInput
# figure out where gen_nn_ops is
print(tf.nn.conv2d_transpose.__globals__['gen_nn_ops'])
from tensorflow.python.ops import gen_nn_ops
import inspect
inspect.getsourcefile('gen_nn_ops.conv2d_backprop_input')
'/Users/yaroslav/anaconda/lib/python3.5/site-packages/tensorflow/python/ops/gen_nn_ops.py'
このファイルが実際にどのように作成されたかを知りたい場合は、ファイル内の bazel 依存関係の跡をたどることができBUILD
ます。それを生成した Bazel ターゲットをテンソルフロー ソース ツリーから見つけます。
fullname=$(bazel query tensorflow/python/ops/gen_nn_ops.py)
bazel query "attr('srcs', $fullname, ${fullname//:*/}:*)"
//tensorflow/python:nn_ops_gen
BUILD
内部のファイルに移動すると、これがここで定義されているtensorflow/python
タイプのターゲットであり、次のように呼び出されることがわかりますtf_gen_op_wrapper_private_py
gen_op_wrapper_py
tensorflow/tensorflow.bzl
def tf_gen_op_wrapper_py(name, out=None, hidden=None, visibility=None, deps=[],
....
native.cc_binary(
name = tool_name,
このnative.cc_binary
コンストラクトは、任意のコマンドの実行を表す Bazel ターゲットを持つ方法です。この場合tool_name
、いくつかの引数を指定して呼び出します。さらにいくつかの手順を実行すると、ここの「ツール」がframework/python_op_gen_main.ccからコンパイルされていることがわかります
この複雑さの理由は、TensorFlow が言語に依存しないように設計されているためです。したがって、理想的な世界では、ops.pbtxtに各 op を記述し、各 op は を使用してハードウェア タイプごとに 1 つの実装を持ちますREGISTER_KERNEL_BUILDER
。したがって、すべての実装は C++/CUDA/Assembly で行われ、すべての言語フロントエンドで自動的に利用可能になります。 . すべての言語に対して「python_op_gen_main」のような同等のトランスレータ op があり、すべてのクライアント ライブラリ コードが自動的に生成されます。しかし、Python が非常に支配的であるため、Python 側に機能を追加するというプレッシャーがありました。そのため、今では 2 種類の op があります。 のようなファイルで見られる純粋な TensorFlow opと、通常は op が自動的に生成されたファイルをラップgen_nn_ops.py
する のようなファイルでの Python のみのop です。nn_ops.py
gen_nn_ops.py
ただし、追加の機能/構文シュガーを追加します。また、元はすべての名前がキャメルケースでしたが、公開リリースはより一般的な Python 構文に準拠した PEP にする必要があると判断されたため、同じ op の C++/Python インターフェース間でキャメルケース/スネークケースの不一致が生じるのはこのためです。