2017-09-02 122 views
1

該腳本使用小嵌套模型理解Keras模型體系結構(嵌套模型的節點索引)

from keras.layers import Input, Dense 
from keras.models import Model 
import keras 

input_inner = Input(shape=(4,), name='input_inner') 
output_inner = Dense(3, name='inner_dense')(input_inner) 
inner_model = Model(inputs=input_inner, outputs=output_inner) 

input = Input(shape=(5,), name='input') 
x = Dense(4, name='dense_1')(input) 
x = inner_model(x) 
x = Dense(2, name='dense_2')(x) 

output = keras.layers.concatenate([x, x], name='concat_1') 
model = Model(inputs=input, outputs=output) 

print(model.summary()) 

產生以下輸出限定假人模型

Layer (type)      Output Shape   Param #  Connected to      
==================================================================================================== 
input (InputLayer)    (None, 5)    0            
____________________________________________________________________________________________________ 
dense_1 (Dense)     (None, 4)    24   input[0][0]      
____________________________________________________________________________________________________ 
model_1 (Model)     (None, 3)    15   dense_1[0][0]      
____________________________________________________________________________________________________ 
dense_2 (Dense)     (None, 2)    8   model_1[1][0]      
____________________________________________________________________________________________________ 
concat_1 (Concatenate)   (None, 4)    0   dense_2[0][0]      
                    dense_2[0][0]      

我的問題涉及到內容的Connected to列。我知道a layer can have multiple nodes

本專欄的註釋編號爲layer_name[node_index][tensor_index]

如果我們認爲inner_model作爲一個層,我期望它只有一個節點,所以我期望dense_2連接到model_1[0][0]。但實際上它連接到model_1[1][0]。爲什麼會這樣?

回答

5

1.背景

當你說:

If we regard inner_model as a layer I would expect it to have only one node

這是在這個意義上真正的,它只有一個節點是網絡的一部分。

考慮model.summary函數的github repository。打印連接的功能是print_layer_summary_with_connections(第76行),它只考慮來自relevant_nodes陣列的節點。所有不在此陣列中的節點都被認爲是不是網絡的一部分,因此該功能會跳過它們。相關的線是線88-90:

if relevant_nodes and node not in relevant_nodes: 
    # node is not part of the current network 
    continue 

2.您的模型

現在讓我們看看與您的特定模式會發生什麼。首先讓我們定義relevant_nodes

relevant_nodes = [] 
for v in model.nodes_by_depth.values(): 
    relevant_nodes += v 

數組relevant_nodes的樣子:

[<keras.engine.topology.Node at 0x9dfa518>, 
<keras.engine.topology.Node at 0x9dfa278>, 
<keras.engine.topology.Node at 0x9d8bac8>, 
<keras.engine.topology.Node at 0x9d8ba58>, 
<keras.engine.topology.Node at 0x9d74518>] 

然而,當我們在每一層打印入站節點,我們將得到:

for i in model.layers: 
    print(i.inbound_nodes) 

[<keras.engine.topology.Node object at 0x0000000009D74518>] 
[<keras.engine.topology.Node object at 0x0000000009D8BA58>] 
[<keras.engine.topology.Node object at 0x0000000009D743C8>, <keras.engine.topology.Node object at 0x0000000009D8BAC8>] 
[<keras.engine.topology.Node object at 0x0000000009DFA278>] 
[<keras.engine.topology.Node object at 0x0000000009DFA518>] 

你可以看到上面列表中只有一個節點沒有出現在relevant_nodes中。這是在位置0中的第三陣列中的節點:

<keras.engine.topology.Node object at 0x0000000009D743C8> 

它不被認爲是模型的一部分,並且因此沒有出現在relevant_nodes。此陣列中位置1的節點確實出現在relevant_nodes中,這就是爲什麼您將其看作model_1[1][0]

3。原因

原因是基本上行x=inner_model(input)。即使您運行小得多模型,如下一個:

input_inner = Input(shape=(4,), name='input_inner') 
output_inner = Dense(3, name='inner_dense')(input_inner) 
inner_model = Model(inputs=input_inner, outputs=output_inner) 

input = Input(shape=(5,), name='input') 
output = inner_model(input) 

model = Model(inputs=input, outputs=output) 

你會看到relevant_nodes包含兩個元素,同時通過

for i in model.layers: 
     print(i.inbound_nodes) 

你會得到三個節點。

這是因爲第1層(上面的較小模型)有兩個節點,但只有第二個節點被認爲是模型的一部分。特別是,如果你在第1層與layer.get_input_at(node_index)打印在節點中的每一個輸入,你會得到:

print(model.layers[1].get_input_at(0)) 
print(model.layers[1].get_input_at(1)) 

#prints 
/input_inner 
/input 

4.Answers的問題在評論

1) Do you also know what this non-relevant node is good for/where it comes from?

該節點似乎是在應用inner_model期間創建的「內部節點」。特別是,如果您打印在三個節點中的每一個輸入和輸出形狀(在上面的小模型),您可以:

nodes=[model.layers[0].inbound_nodes[0],model.layers[1].inbound_nodes[0],model.layers[1].inbound_nodes[1]] 
for i in nodes: 
    print(i.input_shapes) 
    print(i.output_shapes) 
    print(" ") 

#prints 
[(None, 5)] 
[(None, 5)] 

[(None, 4)] 
[(None, 3)] 

[(None, 5)] 
[(None, 3)] 

,所以你可以看到,中間節點的形狀(一沒有出現在相關節點列表中)對應於inner_model中的形狀。

2) Will an inner model with n output nodes always present them with node indices 1 to n instead of 0 to n-1?

我不知道,如果總是因爲我想有各種可能性有多個輸出節點的節點,但如果我認爲上方的小模型的下面很自然的推廣,這的確是這樣的:

input_inner = Input(shape=(4,), name='input_inner') 
output_inner = Dense(3, name='inner_dense')(input_inner) 
inner_model = Model(inputs=input_inner, outputs=output_inner) 

input = Input(shape=(5,), name='input') 
output = inner_model(input) 
output = inner_model(output) 

model = Model(inputs=input, outputs=output) 

print(model.summary()) 

在這裏,我只是加了output = inner_model(output)小模型。相關節點的名單

[<keras.engine.topology.Node at 0xd10c390>, 
<keras.engine.topology.Node at 0xd10c9b0>, 
<keras.engine.topology.Node at 0xd10ca20>] 

和所有入站節點列表是

[<keras.engine.topology.Node object at 0x000000000D10CA20>] 
[<keras.engine.topology.Node object at 0x000000000D10C588>, <keras.engine.topology.Node object at 0x000000000D10C9B0>, <keras.engine.topology.Node object at 0x000000000D10C390>] 

節點的確指數爲1和2,當你在註釋中。如果我添加另一個output = inner_model(output),節點索引爲1,2,3等,它將繼續類似。

+0

謝謝你非常深思熟慮的答案。你是否也知道這個不相關的節點對它來自哪裏有好處,或者如果具有'n'輸出節點的內部模型總是將它們以節點索引'1'到'n'而不是'0'呈現給'正1'? –

+0

@TobiasHermann請參閱我在答案中添加的「評論中的問題的答案」部分。 –

+0

太棒了,非常感謝。一個小問題:您的[最小化示例](https://ideone.com/JPD0sy)會產生一個錯誤:'ValueError:尺寸必須相同,但對於'model_1/inner_dense/MatMul'爲5和4(op:'MatMul '),輸入形狀爲:[?,5],[4,3]。' –