web-dev-qa-db-ja.com

TensorflowモデルをCaffeモデルに変換

TensorflowモデルをCaffeモデルに変換できるようにしたいと思います。

Googleで検索しましたが、caffeからtensorflowへのコンバーターのみを見つけることができましたが、その逆は見つかりませんでした。

誰もそれを行う方法についてアイデアを持っていますか?

ありがとう、エヴィ

26
Evi

私は同じ問題を抱えていて、解決策を見つけました。コードはこちら( 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リポジトリにあります。役に立てば幸いです。 :)


乾杯、
致命的

6
Fatality

@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レイヤーで分離されています上記。また、gammameanおよびvarianceは、バッチ正規化レイヤーで分離されます。

3
Jayant Agrawal