На этом шаге мы рассмотрим способ доступа к этой информации.
Функциональная модель - это графовая структура данных. Она позволяет исследовать связи между слоями и повторно использовать предыдущие узлы графа (которые являются выходами слоев) в новых моделях. Кроме того, она хорошо соответствует "ментальной модели" (графу слоев), которую используют многие исследователи, рассуждая о глубоких нейронных сетях, а также поддерживает два важных способа использования: визуализацию модели и извлечение признаков.
Давайте отобразим связи в только что созданной модели (ее топологию). Получить изображение функциональной модели в виде графа можно с помощью утилиты plot_model() (рисунок 1).
keras.utils.plot_model(model, "updated_ticket_classifier.png", show_layer_names=True)
Рис.1. Графическое представление модели классификации заявок, сгенерированное функцией plot_model()
В эту диаграмму можно добавить форму входа и выхода каждого слоя в модели, что может пригодиться в процессе отладки (рисунок 2).
keras.utils.plot_model(model, "updated_ticket_classifier.png", show_layer_names=True, show_shapes=True, expand_nested=True)
Рис.2. Графическое представление модели с информацией о форме входов и выходов
Слово None в формах тензоров представляет размер пакета: данная модель может обрабатывать пакеты любого размера.
Доступность информации о связях между слоями также означает возможность исследовать и повторно использовать отдельные узлы (выходы слоев) в графе. Свойство модели model.layers возвращает список слоев в модели, и для каждого слоя в этом списке можно исследовать их свойства layer.input и layer.output.
print(model.layers) print(model.layers[3].input) print(model.layers[3].output) [<InputLayer name=title, built=True>, <InputLayer name=text_body, built=True>, <InputLayer name=tags, built=True>, <Concatenate name=concatenate_1, built=True>, <Dense name=dense_1, built=True>, <Dense name=priority, built=True>, <Dense name=department, built=True>] [<KerasTensor shape=(None, 10000), dtype=float32, sparse=False, name=title>, <KerasTensor shape=(None, 10000), dtype=float32, sparse=False, name=text_body>, <KerasTensor shape=(None, 100), dtype=float32, sparse=False, name=tags>] <KerasTensor shape=(None, 20100), dtype=float32, sparse=False, name=keras_tensor_4>
Это позволяет производить извлечение признаков в моделях, повторно использующих промежуточные признаки из другой модели.
Представьте, что вы решили добавить еще один выход в предыдущую модель - оценку времени, которое потребуется для решения обозначенной в заявке проблемы (своего рода рейтинг сложности). Это можно сделать с помощью слоя классификации по трем категориям: "простая" проблема, "средняя" и "сложная". Причем вам не нужно воссоздавать и повторно обучать модель с нуля: можно начать с промежуточных признаков предыдущей модели, как показано ниже.
# layers[4] - это промежуточный слой Dense features = model.layers[4].output difficulty = layers.Dense(3, activation="softmax", name="difficulty")(features) new_model = keras.Model( inputs=[title, text_body, tags], outputs=[priority, department, difficulty])
Теперь получим графическое представление новой модели (рисунок 3):
keras.utils.plot_model( new_model, "updated_ticket_classifier.png", show_layer_names=True, show_shapes=True, expand_nested=True
Рис.3. Графическое представление новой модели (изображение кликабельно)
На следующем шаге мы рассмотрим создание производных от класса Model.