elichika
elichikaのコードリーディング
forwardメソッド内をASTに変換
再帰的に内部表現であるGraphを構築
Graphとは
計算グラフのこと?
ふぉーまっとがわからん
どこ?mrsekut.icon
Chainerの計算グラフをトレースするわけではない
ここに関数呼び出しの対応について「おもしろい」とあるがどの辺が特殊なのかを読みたいmrsekut.icon gast
PythonのASTを返す
Pythonのバージョンが異なっていても互換性を保つ
code:py
>> tree = ast.parse(code)
>> gtree = gast.ast_to_gast(tree)
>> tree = gast.gast_to_ast(gtree) # astと相互に変換できる
0知識でコードリーディングするなら
pydepsを使ってchainer_compiler/elichikaの依存関係をvisualizeした
うへぇ~、結構でかいね..mrsekut.icon
canonicalizerdir
「canonicalization」=正規化
ファイル名のHoge_test.pyはその名の通りhoge句に対するテスト
ディレクトリ構成
__init__.py
chainer2onnx.py
rootっぽい
compile_model()
dictを作成
Graph?→ONNXmodel
compile_modelの最初にテーブルを作成。ここに登録したOpをサポート
CallNodeはchainerのインスタンスも保持しているのでそれでテーブルを引く
functions_builtin.py
links_builtin.py
ONNXGraphにNodeを追加
onnx_converters.py
ONNXGenerator
generate_graph()
GraphのNodeの種類ごとに分岐しONNXのNodeに変換していく
generate_model()
modelとgraphからModelProtoを返す
このModleProtoのことを「ONNXGraph」と呼んでる(?
GraphのNodeを繰り返しONNXの対応するOpに変換
convert_node_call()
NodeCallは、FunctionやLinkは予め登録したテーブルから引いて変換 #?? 関数の種類に応じて分岐
parser
__init__.py
canonicalizer.py
config.py
core.py
★
convert_model()
args: chainer.Chain, inputs
この引数のmodelがどういうフォーマットのものなのかがわかっていない
return: inputs, outputs, Graphクラスのインスタンス
forwardメソッドのソースコードを取得、ASTに変換
ASTを1命令ずつ、Nodeに変換しGraphに追加していく
シンボルテーブル(Module、Field)による変数や関数の解決
どこのことだ?mrsekut.icon
スライドの図と、説明的には、この関数内でPythonコード→AST→Graphになってる感じだが、引数の「model」というのは、どういうフォーマットなの?pythonコードではなさそうに見えるが。 node_input = nodes.NodeInput('input')
この辺でASTに変換
後にこれをGraphに変換
後半では、作ったGraphに値を追加している
add_chainer_function()では、本来のF.relu()などを参照しないようにシンボルテーブルを上書きしている
なんで参照したらダメなの?
functions.py
このファイルだけではないが、Function系のクラスにはvcall()メソッドが定義されている
コンストラクタ内でinspect.getmembers()を読んで、スコープのメンバを取得してシンボルテーブルを作る
UserDefinedFunction
ユーザーが定義した関数群
vacall()の中で、AstContextを作り、またveval_ast()に戻る
つまり、再帰的にASTをNodeへ変換していく(?
functions_builtin.py
Chainerのbuiltinの関数
ChanerFunction
vcall()内でNodeCallを作成し、Graphに追加
functions_ndarray.py
graphs.py
links_builtin.py
nodes.py
Nodeクラス
ASTの一つのノード の起点
utils.py
values.py
ここで、シンボルテーブルを作るメソッドやクラスを定義してるのかな
ValueRef
Nodeを表す ???
Field
ローカルのテーブル
get_attribute()
再帰的に親スコープへ遡っていき、属性を得る
veval_bin.py
veval_multiary.py
veval_unary.py
vevaluator.py
valueのevaluator ?
veval_ast_call()
関数呼び出しのastの評価
シンボルテーブルから参照を解決
Nodeを作成して返す
なんのNode?
ちなみに型はValueRef
veval_ast()
astをevalして返す
visualizer.py
testtools
__init__.py
canonicalizer_tools.py
initializer.py
test_args.py
testcasegen.py
あ、ここから読めばよかったのか、、今気づいた。。mrsekut.icon
generate_testcase()を読むとelichikaの大体の流れが読める
generate_testcase()
chainer.Chainのを継承したChainerモデルを引数にとる
流れ
一つのChainerモデルをインスタンス化する
例えば、組み込み関数だったり、演算子だったり。
それの、パラメータや、勾配をメモる
そのモデルをコンパイルして、ONNXモデルに変換する
Pythonで言語処理系を書くとなると、classを使って型を作るからinstance(obejct, model)はめっちゃ多用されることになるんだな
F.reluなどのビルトイン関数と、ユーザー定義の関数で処理を分けている
F.relu → ONNXのreluのようにONNXのOpと対応する関数
range → NodeGenerate→ ChainerSequenceRange のように特別なOpにしたい
ユーザー定義は、ResBlockなどブロック単位でクラスや関数に分けたいモデルで有効 ref テストコード
__init__.py
canonicalizer
Break_test.py
Continue_test.py
UnaryOpSub_test.py
model
Alex.py
EspNet_AttDot.py
EspNet_AttLoc.py
EspNet_BLSTM.py
EspNet_Decoder.py
EspNet_E2E.py
EspNet_VGG2L.py
MLP.py
MyLSTM.py
Resnet_with_loss.py
StatelessLSTM.py
node
AddMul.py
AveragePool2d.py
BatchNorm.py
ChainList.py
Convolution2D.py
Functions
BroadcastTo.py
Concat.py
Dropout.py
ExpandDims.py
Hstack.py
Matmul.py
MaxPool2d.py
Mean.py
Reshape.py
ResizeImages.py
Roi.py
Separate.py
Sigmoid.py
SplitAxis.py
Squeeze.py
Stack.py
Sum.py
SwapAxes.py
Tanh.py
Vstack.py
Id.py
LRN.py
Len.py
Linear.py
Links
EmbedID.py
NStepBiLSTM.py
NStepLSTM.py
PadSequence.py
Relu.py
Softmax.py
SoftmaxCrossEntropy.py
Unpooling2D.py
Variable.py
ndarray
Ceil.py
Cumsum.py
NpArray.py
NpFull.py
NpZeros.py
Shape.py
Size.py
syntax
Alias.py
BoolOp.py
Break.py
Cmp.py
Continue.py
For.py
ForAndIf.py
If.py
LinkInFor.py
ListComp.py
MultiClass.py
MultiFunction.py
Range.py
Sequence.py
Slice.py
Tuple.py
UserDefinedFunc.py
UserDefinedFuncSub1.py
UserDefinedFuncSub2.py
utils
sequence_utils.py
参考