TensorflowモデルをCaffeモデルに変換できるようにしたいと思います。
Googleで検索しましたが、caffeからtensorflowへのコンバーターのみを見つけることができましたが、その逆は見つかりませんでした。
誰もそれを行う方法についてアイデアを持っていますか?
ありがとう、エヴィ
私は同じ問題を抱えていて、解決策を見つけました。コードはこちら( https://github.com/lFatality/tensorflow2caffe )にあります。また、一部のYoutubeビデオでもコードを文書化しています。
パート1 はCaffeの VGG-19 のアーキテクチャの作成をカバーし、 tflearn (TensorFlowの高レベルAPI、コードにいくつかの変更を加えたもの)ネイティブTensorFlowも動作するはずです)。
パート2 TensorFlowモデルからnumpyファイルへの重みとバイアスのエクスポートについて説明します。 tflearnでは、次のようなレイヤーの重みを取得できます。
_#get parameters of a certain layer
conv2d_vars = tflearn.variables.get_layer_variables_by_name(layer_name)
#get weights out of the parameters
weights = model.get_weights(conv2d_vars[0])
#get biases out of the parameters
biases = model.get_weights(conv2d_vars[1])
_
たたみ込み層の場合、layer_nameは_Conv_2D
_です。完全に接続されたレイヤーはFullyConnected
と呼ばれます。特定のタイプの複数のレイヤーを使用する場合、前にアンダースコアを付けた整数を使用します(たとえば、2番目のconvレイヤーは_Conv_2D_1
_と呼ばれます)。 TensorBoardのグラフでこれらの名前を見つけました。アーキテクチャー定義でレイヤーに名前を付けると、これらのlayer_namesは定義した名前に変わる可能性があります。
ネイティブのTensorFlowでは、エクスポートに異なるコードが必要になりますが、パラメーターの形式は同じである必要があるため、後続の手順は引き続き適用可能です。
パート は実際の変換をカバーします。重要なのは、カフェモデルを作成するときの重みの変換です(バイアスは変更なしで引き継がれます)。 TensorFlowとCaffeは、フィルターを保存するときに異なる形式を使用します。 TensorFlowは_[height, width, depth, number of filters]
_を使用しますが( 下部のTensorFlow docs )、Caffeは_[number of filters, depth, height, width]
_を使用します( Caffe docs、章 'Blob storage and communication' ) 。形式間で変換するには、transpose
関数を使用できます(例:weights_of_first_conv_layer.transpose((3,2,0,1))
。3,2,0,1シーケンスは、TensorFlow形式(Origin)を列挙してから取得できます。数値を特定の変数に保ちながら、Caffe形式(ターゲット形式)に切り替えます。
テンソル出力を完全に接続されたレイヤーに接続する場合、少し注意が必要です。 112x112の入力サイズでVGG-19を使用すると、次のようになります。
_fc1_weights = data_file[16][0].reshape((4,4,512,4096))
fc1_weights = fc1_w.transpose((3,2,0,1))
fc1_weights = fc1_w.reshape((4096,8192))
_
テンソルと完全に接続されたレイヤー間の接続でパラメーターをエクスポートした場合、TensorFlowから得られるのは、形状_[entries in the tensor, units in the fc-layer]
_(ここでは_[8192, 4096]
_)の配列です。出力テンソルの形状が何であるかを確認してから、TensorFlow形式に合うように配列を再形成する必要があります(上記の_number of filters
_は_number of units in the fc-layer
_を参照)。その後、前に使用したトランスポーズ変換を使用してから、配列を再度整形しますが、逆の場合も同様です。 TensorFlowはfcレイヤーの重みを_[number of inputs, number of outputs]
_として保存しますが、Caffeはその逆を行います。
2つのfcレイヤーを相互に接続する場合、前述の複雑なプロセスを実行する必要はありませんが、転置して別のfcレイヤー形式を考慮する必要があります(fc_layer_weights.transpose((1,0))
)
その後、ネットワークのパラメータを設定できます
_net.params['layer_name_in_prototxt'][0].data[...] = weights
net.params['layer_name_in_prototxt'][1].data[...] = biases
_
これは簡単な概要でした。すべてのコードが必要な場合は、私のgithubリポジトリにあります。役に立てば幸いです。 :)
乾杯、
致命的
@Patwieのコメントで示唆されているように、レイヤーごとにウェイトをコピーして手動で行う必要があります。たとえば、最初のconvレイヤーの重みをtensorflowチェックポイントからcaffemodelにコピーするには、次のようにする必要があります。
sess = tf.Session()
new_saver = tf.train.import_meta_graph("/path/to/checkpoint.meta")
what = new_saver.restore(sess, "/path/to/checkpoint")
all_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)
conv1 = all_vars[0]
bias1 = all_vars[1]
conv_w1, bias_1 = sess.run([conv1,bias1])
net = caffe.Net('path/to/conv.prototxt', caffe.TEST)
net.params['conv_1'][0].data[...] = conv_w1
net.params['conv_1'][1].data[...] = bias_1
...
net.save('modelfromtf.caffemodel')
注1:このコードには[〜#〜] not [〜#〜]がテストされています。これがうまくいくかどうかはわかりませんが、そうすべきだと思います。また、これは1つのconvレイヤーのみです。実際には、最初にテンソルフローチェックポイントを分析して、どのレイヤーの重みがどのインデックスにあるかを確認する必要があります(printall_vars)、次に各レイヤーの重みを個別にコピーする必要があります。
注2:一部の自動化は、通常、設定されたパターン(conv1-> bn1-> relu1-> conv2-> bn2-> relu2 ...)に従って初期のconvレイヤーを反復処理することで実行できます。
注3:Tensorflowは、各レイヤーの重みを個別のインデックスにさらに分割する場合があります。例:weightsおよびbiasesは、示されているように、convレイヤーで分離されています上記。また、gamma、meanおよびvarianceは、バッチ正規化レイヤーで分離されます。