На этом шаге мы рассмотрим реализицию этого примера, используя класс Model.
Рассмотрим простой пример: реализуем модель управления заявками в службу поддержки клиентов, создав производный класс от класса Model.
from tensorflow import keras from tensorflow.keras import layers class CustomerTicketModel(keras.Model): def __init__(self, num_departments): # Не забудьте вызвать super() - конструктор родительского класса! super().__init__() # Определите слои в конструкторе self.concat_layer = layers.Concatenate() self.mixing_layer = layers.Dense(64, activation="relu") self.priority_scorer = layers.Dense(1, activation="sigmoid") self.department_classifier = layers.Dense( num_departments, activation="softmax") # Определите порядок выполнения прямого прохода в методе call() def call(self, inputs): title = inputs["title"] text_body = inputs["text_body"] tags = inputs["tags"] features = self.concat_layer([title, text_body, tags]) features = self.mixing_layer(features) priority = self.priority_scorer(features) department = self.department_classifier(features) return priority, department
Определив свой класс моделей, можно создать его экземпляр. Обратите внимание, что веса будут созданы только при первом вызове модели с некоторыми данными, так же как в подклассах Layer:
model = CustomerTicketModel(num_departments=4) priority, department = model( {"title": title_data, "text_body": text_body_data, "tags": tags_data})
Пока не видно никаких отличий от подклассов Layer, которые мы создавали на 82 шаге. В чем же тогда разница между подклассом Layer и подклассом Model? Все просто: слой - это просто блок, используемый при строительстве моделей, а модель - объект более высокого уровня, который вы будете обучать, экспортировать для прогнозирования и т. д. Проще говоря, класс Model имеет методы fit(), evaluate() и predict(), а у слоев этих методов нет. В остальном данные два класса практически идентичны. (Еще одно отличие: модель можно сохранить в файл на диске, о чем мы расскажем позже.)
Компиляция и обучение подкласса Model производятся точно так же, как компиляция последовательных или функциональных моделей:
model.compile(optimizer="rmsprop", # Структура аргументов, передаваемых в параметрах loss и # metrics, должна точно соответствовать тому, что # возвращает call() - в данном случае это списки с # двумя элементами loss=["mean_squared_error", "categorical_crossentropy"], metrics=[["mean_absolute_error"], ["accuracy"]]) # Структура входных данных должна точно соответствовать структуре # параметров метода call() - в данном случае это словарь с ключами # title, text_body и tags model.fit({"title": title_data, "text_body": text_body_data, "tags": tags_data}, # Структура цели должна точно соответствовать тому, # что возвращает метод call(), - в данном случае это # список с двумя элементами [priority_data, department_data], epochs=1) model.evaluate({"title": title_data, "text_body": text_body_data, "tags": tags_data}, [priority_data, department_data]) priority_preds, department_preds = model.predict({"title": title_data, "text_body": text_body_data, "tags": tags_data})
Прием, основанный на создании подклассов класса Model - наиболее гибкий способ построения модели. Он позволяет конструировать модели, которые нельзя выразить в форме ориентированного ациклического графа слоев; представьте, например, модель, в которой метод call() использует слои внутри цикла for или даже вызывает их рекурсивно. В подклассе Model такое возможно - главные здесь вы.
На следующем шаге мы рассмотрим, что не поддерживают подклассы класса Model.