Эта модель была создана с использованием Функциональной модели API
В основном это работает так (возможно, если перед тем, как прочесть это, перейдите к «дополнительному вопросу 2» ниже, это может проясниться):
- У вас есть входной тензор (вы также можете видеть его как "входные данные")
- Вы создаете (или повторно используете) слой
- Вы передаете входной тензор слою (вы «называете» слой входом)
- Вы получите тензор вывода
Вы продолжаете работать с этими тензорами, пока не создадите весь график .
Но это еще не создало "модель". (Один вы можете тренировать и использовать другие вещи).
Все, что у вас есть, - это график, показывающий, куда идут тензоры.
Чтобы создать модель, вы определяете ее конечные конечные точки.
В примере.
- Они берут существующую модель:
model = keras.applications.InceptionV3(...)
- Они хотят расширить эту модель, чтобы они получили выходной тензор :
model.output
- Они передают этот тензор как вход
GlobalAveragePooling2D
слоя
- Они получают тензор вывода этого слоя как
new_output
- Они передают это как входные данные еще одному слою:
Dense(N_CLASSES, ....)
- И получить его вывод как
new_output
(этот var был заменен, поскольку они не заинтересованы в сохранении его старого значения ...)
Но поскольку он работает с функциональным API, у нас пока нет модели, только график. Для создания модели мы используем Model
, определяющий входной тензор и выходной тензор:
new_model = Model(old_model.inputs, new_output)
Теперь у вас есть модель.
Если вы используете его в другом var, как я (new_model
), старая модель все еще будет существовать в model
. И эти модели используют одни и те же слои, так что, когда вы тренируете одну из них, другая также обновляется.
Вопрос: откуда он знает, какие еще слои мы хотим добавить между ними?
Когда вы делаете:
outputTensor = SomeLayer(...)(inputTensor)
у вас есть связь между входом и выходом. (Керас будет использовать механизм внутреннего тензорного потока и добавит эти тензоры и узлы на график). Выходной тензор не может существовать без ввода. Вся модель InceptionV3
подключена от начала до конца. Его входной тензор проходит через все слои, чтобы получить выходной тензор. Существует только один возможный путь для данных, и график - путь.
Когда вы получаете выход этой модели и используете его для получения дополнительных выходов, все ваши новые выходы подключаются к этому и, следовательно, к первому входу модели.
Вероятно, атрибут _keras_history
, который добавляется к тензорам, тесно связан с тем, как он отслеживает график.
Таким образом, выполнение Model(old_model.inputs, new_output)
, естественно, будет следовать единственно возможным путем: графиком.
Если вы попытаетесь сделать это с тензорами, которые не подключены, вы получите ошибку.
Дополнительный вопрос 1
Предпочитают импортировать из "keras.models". По сути, этот модуль будет импортировать из другого модуля:
Обратите внимание, что файл keras/models.py
импортирует Model
из keras.engine.training
. Итак, это то же самое.
Дополнительный вопрос 2
Это не new_layer = keras.layers.Dense(...)(prev_layer)
.
Это output_tensor = keras.layers.Dense(...)(input_tensor)
.
Вы делаете две вещи в одной строке:
- Создание слоя - с помощью
keras.layers.Dense(...)
- Вызов слоя с входным тензором для получения выходного тензора
Если вы хотите использовать один и тот же слой с разными входами:
denseLayer = keras.layers.Dense(...) #creating a layer
output1 = denseLayer(input1) #calling a layer with an input and getting an output
output2 = denseLayer(input2) #calling the same layer on another input
output3 = denseLayer(input3) #again
Бонус - Создание функциональной модели, равной последовательной модели
Если вы создадите эту последовательную модель:
model = Sequential()
model.add(Layer1(...., input_shape=some_shape))
model.add(Layer2(...))
model.add(Layer3(...))
Вы делаете точно так же, как:
inputTensor = Input(some_shape)
outputTensor = Layer1(...)(inputTensor)
outputTensor = Layer2(...)(outputTensor)
outputTensor = Layer3(...)(outputTensor)
model = Model(inputTensor,outputTensor)
В чем разница?
Что ж, функциональные модели API абсолютно бесплатны для сборки в любом случае. Вы можете создавать филиалы:
out1 = Layer1(..)(inputTensor)
out2 = Layer2(..)(inputTensor)
Вы можете присоединиться к тензорам:
joinedOut = Concatenate()([out1,out2])
С помощью этого вы можете создать что угодно по вашему желанию со всеми видами причудливых вещей, веток, элементов, конкатенаций, дополнений и т. Д., Что вы не можете сделать с последовательной моделью.
На самом деле модель Sequential
также является Model
, но создана для быстрого использования в моделях без ответвлений.