2017-12-01 17 views
0

TensorFlowのCNN-LSTMネットワークをCNTKにキャプションする作業イメージを変換しようとしていますが、私は正しく訓練されたモデルだと思っていますが、最終的に訓練されたCNTKモデルから予測を抽出する方法がわかりません。CNTK:LSTM非表示状態を初期化するにはどうすればよいですか?

これは、私が働いている一般的なアーキテクチャである:これは私のCNTKモデルです enter image description here

def create_lstm_model(image_features, text_features): 
    embedding_dim = 512 
    hidden_dim = 512 
    cell_dim = 512 
    vocab_dim = 77 

    image_embedding = Embedding(embedding_dim) 
    text_embedding = Embedding(embedding_dim) 
    lstm_classifier = Sequential([Stabilizer(), 
            Recurrence(LSTM(hidden_dim)), 
            Recurrence(LSTM(hidden_dim)), 
            Stabilizer(), 
            Dense(vocab_dim)]) 

    embedded_images = BatchNormalization()(image_embedding(image_features)) 
    embedded_text = text_embedding(text_features) 
    lstm_input = C.plus(embedded_images, embedded_text) 
    lstm_input = C.dropout(lstm_input, 0.5) 
    output = lstm_classifier(lstm_input)  

    return output 

私は、40の固定キャプションシーケンスの大きさで、CTF形式で自分のデータを提供し使用していますこのような構造:別に

def create_reader(path, is_training): 
    return MinibatchSource(CTFDeserializer(path, StreamDefs(
     target_tokens = StreamDef(field='target_tokens', shape=vocab_len, is_sparse=True), 
     input_tokens = StreamDef(field='input_tokens', shape=vocab_len, is_sparse=True), 
     image_features = StreamDef(field='image_features', shape=image_features_dim, is_sparse=False) 
    )), randomize = is_training, max_sweeps = INFINITELY_REPEAT if is_training else 1) 

:3つのデータストリームのための理由は、 - Iは、入力された画像特徴ベクトル(事前訓練ResNetの最後2048 DIM層)、入力されたテキスト・トークンの配列を有し、そしてのシーケンスutputテキストトークン。そこで、基本的シーケンスの面で私のCTFファイルは、次のようになります。

基本的に
0 | target_token_0 | input_token_0 | input_image_feature_vector (2048-dim) 
0 | target_token_1 | input_token_1 | empty array of 2048 zeros 
0 | target_token_2 | input_token_2 | empty array of 2048 zeros 
... 
0 | target_token_40 | input_token_40 | empty array of 2048 zeros 
1 | target_token_0 | input_token_0 | input_image_feature_vector (2048-dim) 
1 | target_token_1 | input_token_1 | empty array of 2048 zeros 
1 | target_token_2 | input_token_2 | empty array of 2048 zeros 
... 
1 | target_token_40 | input_token_40 | empty array of 2048 zeros 

、私は(あなたが簡単に2つのテンソルをスプライスすることができていても)CNTKで一緒に&スプライス二つの配列をスライスする方法を見つけ出すことができませんでした、シーケンスの最初の要素だけを入力2048次元の画像の特徴ベクトルで、シーケンスの残りの要素を空の2048次元の0のベクトルに設定することでハッキングしています。

C.plus(embedded_images, embedded_text)

上記のモデルでは、目標は基本的に最初の要素を取ることです40 画像埋め込みのシーケンスと、ハックスプライス(TM)のシーケンスの最後の39個のエレメントの前に、4[vocab_dim]->[512]ワードの埋め込みのシーケンスがある。空の画像ベクトル(2048のゼロ)のためにかなりの空きの[2048]->[512]画像埋め込みがあるので、埋め込まれた画像シーケンスと要素的に埋め込みテキストシーケンスにLSTMに入る前に追加していきます。基本的に、これは:

image embedding sequence: [-1, 40, 512] (e.g., [-1, 0, 512]) 
text embedding sequence: [-1, 40, 512] (e.g., [-1, 1:40, 512) 
+ 
--------------------------------------- 
lstm input sequence:  [-1, 40, 512] 

私の実際の質問に私をもたらします。今、私はちゃんとうまく訓練したモデルを持っていることを、私は基本的に(このPyTorch image captioning tutorialから)このような何かをやって、モデルからキャプション予測を抽出したいと思います:

def sample(self, features, states=None): 
    """Samples captions for given image features (Greedy search).""" 
    sampled_ids = [] 
    inputs = features.unsqueeze(1) 
    for i in range(20):          # maximum sampling length 
     hiddens, states = self.lstm(inputs, states)   # (batch_size, 1, hidden_size), 
     outputs = self.linear(hiddens.squeeze(1))   # (batch_size, vocab_size) 
     predicted = outputs.max(1)[1] 
     sampled_ids.append(predicted) 
     inputs = self.embed(predicted) 
     inputs = inputs.unsqueeze(1)       # (batch_size, 1, embed_size) 
    sampled_ids = torch.cat(sampled_ids, 1)     # (batch_size, 20) 
    return sampled_ids.squeeze() 

の問題は、私は理解できないですLSTMの外に隠れ状態を取得し、次の時間ステップに戻ってそれをポンピングするためCNTK相当アウト:

hiddens, states = self.lstm(inputs, states) 

どのようにしてCNTKで、この作品?

答えて

0

あなたが探している機能はRecurrenceFrom()だと思います。そのドキュメントには次の例が含まれています:

Example: 
>>> from cntk.layers import * 
>>> from cntk.layers.typing import * 

>>> # a plain sequence-to-sequence model in training (where label length is known) 
>>> en = C.input_variable(**SequenceOver[Axis('m')][SparseTensor[20000]]) # English input sentence 
>>> fr = C.input_variable(**SequenceOver[Axis('n')][SparseTensor[30000]]) # French target sentence 

>>> embed = Embedding(300) 
>>> encoder = Recurrence(LSTM(500), return_full_state=True) 
>>> decoder = RecurrenceFrom(LSTM(500))  # decoder starts from a data-dependent initial state, hence -From() 
>>> emit = Dense(30000) 
>>> h, c = encoder(embed(en)).outputs   # LSTM encoder has two outputs (h, c) 
>>> z = emit(decoder(h, c, sequence.past_value(fr))) # decoder takes encoder outputs as initial state 
>>> loss = C.cross_entropy_with_softmax(z, fr) 
0

私は最近同じ問題に直面しました。以下では、RecurrenceRNNStepオブジェクトを使用して予測を取得する方法を理解するために作成したサンプルコードを提供しています。ここでは、予測は決して次の期間の状態であり、これは決して変換されないためです。私はRNNStepを使用しました。これはパラメータが少なく、簡単な例を簡単に作成できるためです。同じロジックがLSTMに適用されます。そして

process_dim = 1 
n_periods = 100 
np.random.seed(0) 
x_data = np.random.multivariate_normal(mean=np.array([0.0], dtype=np.float32), 
             cov=np.matrix([[0.1]], dtype=np.float32), 
             size=n_periods).astype(np.float32) 

IがRNN構築し、それが容易であるように、そのパラメータを設定:

例の最初の部分は、(それは、任意のプロセスであってもよい)で再生するホワイトノイズプロセスを構築しますその内部計算を理解する。

x = cntk.sequence.input_variable(shape=process_dim) 
initial_state = 10 
W = 1 
H = 1 
b = 1 
with cntk.layers.default_options(initial_state=initial_state): 
    model = cntk.layers.Recurrence(cntk.layers.RNNStep(shape=process_dim, 
                 activation=lambda x_: x_, 
                 init=W, 
                 init_bias=b))(x) 

注1:引数initセットHおよびW.両方 注2:あなたはwithステートメントを使用していない場合は、初期状態が0に設定されている、あまりにも動作します。

RNNを評価する方法、つまり前の期間の状態(私たちの場合は初期状態)と現在の期間の外部入力(x_dataの項目)を組み合わせて次の状態を取得する方法を見てみましょう。以下のスクリプトでは、入力によってはmodel.eval()を呼び出し、実際のRNN計算を手動で実行して出力を検証しています。

x0 = np.array(x_data[0]).reshape((1, 1)) 
x1 = np.array(x_data[1]).reshape((1, 1)) 
x2 = np.array(x_data[2]).reshape((1, 1)) 

h00 = model.eval({x: x0}) 
h01 = model.eval({x: x1}) 
h02 = model.eval({x: x2}) 

print("x0: {}, h00: {}".format(x0, h00)) 
print("x1: {}, h01: {}".format(x1, h01)) 
print("x2: {}, h02: {}".format(x2, h02)) 

# validation 
h00_m = initial_state * H + x0[0, 0] * W + b 
h01_m = initial_state * H + x1[0, 0] * W + b 
h02_m = initial_state * H + x2[0, 0] * W + b 

print("validation of state computed manually") 
print("x0: {}, h00_m: {}".format(x0[0, 0], h00_m)) 
print("x1: {}, h01_m: {}".format(x1[0, 0], h01_m)) 
print("x2: {}, h02_m: {}".format(x2[0, 0], h02_m)) 

さんは今見通し先に複数の期間を取得するためにmodel.eval()を使用する方法を見てみましょう。繰り返しますが、以下のスクリプトはそれを行い、出力を検証します。

# x0 now contains multiple entries 
x0 = np.array(x_data[0:4]).reshape((4, 1)) 
h1234 = model.eval({x: x0}) 
print("forecasts obtained by model automatically") 
print(h1234) 

h01_m = initial_state * H + x0[0, 0] * W + b 
h12_m = h01_m * H + x0[1, 0] * W + b 
h23_m = h12_m * H + x0[2, 0] * W + b 
h34_m = h23_m * H + x0[3, 0] * W + b 

print("forecasts computed manually") 
print(h01_m) 
print(h12_m) 
print(h23_m) 
print(h34_m) 

RNNStepRecurrence内部で使用されているので、だから、それは自動的にあなたがモデル関数に提供し、入力の数(複数可)によるRNNStepを呼び出します。 RNNStepが呼び出されるたびに、前の期間の状態と、model.eval()に与えられた配列の項目を受け取ります。これは、トレーニングで何が起こるかと一致しています。ここで

がLSTMsとのRNNのいくつかの有用なドキュメントです: https://docs.microsoft.com/en-us/python/api/cntk.layers.blocks?view=cntk-py-2.2 その内容はまさにhttps://cntk.ai/pythondocs/index.htmlと同じではありませんし、この場合には、より便利です。

ご迷惑をおかけして申し訳ございませんが、私はこのことに関する知識が限られており、これにはまだ回答がありません。

関連する問題