Шаг 82.
Глубокое обучение на Python. ... . Анатомия нейронной сети: знакомство с основами Keras. Слои: строительные блоки глубокого обучения. Базовый класс Layer в Keras

    На этом шаге мы рассмотрим роль этого класса в построении нейронной сети.

    Простой прикладной интерфейс (API) должен иметь единую абстракцию, лежащую в основе всего. В Keras такой абстракцией служит класс слоев Layer. Все в Keras является либо слоем Layer, либо чем-то еще, что тесно взаимодействует со слоем Layer.

    Слой - это объект, инкапсулирующий некоторое состояние (веса) и некоторые вычисления (прямой проход). Веса обычно определяются с помощью метода build() (но также могут инициализироваться в конструкторе __init__()), а вычисления определяются в методе call(). На 57 шаге мы реализовали класс NaiveDense, содержавший два веса, W и b, и применили вычисления output = activation(dot(input, W) + b). Вот как тот же слой выглядел бы в Keras.


Пример 3.22. Слой Dense, реализованный как подкласс класса Layer
import tensorflow as tf
from tensorflow import keras

#  Все классы слоев в Keras наследуют базовый класс Layer
class SimpleDense(keras.layers.Layer): 
  def __init__(self, units, activation=None): 
    super().__init__() 
    self.units = units 
    self.activation = activation 
    
  #  Веса создаются в методе build()
  def  build(self, input_shape): 
    input_dim = input_shape[-1] 
    #  add_weight() - это вспомогательный метод для создания весов. 
    #  Также имеется возможность создать отдельные
    #  переменные и связать их с атрибутами слоя, например:
    #  self.W = tf.Variable(tf.random.uniform(w_shape))
    self.W = self.add_weight(shape=(input_dim, self.units), 
                             initializer="random_normal") 
    self.b = self.add_weight(shape=(self.units,), 
                             initializer="zeros") 
    
  #  Вычисления, выполняемые во время прямого прохода, 
  #  определяются в методе call()
  def call(self, inputs): 
    y = tf.matmul(inputs, self.W) + self.b 
    if self.activation is not None: 
      y = self.activation(y) 
    return y

    Мы еще вернемся к методам build() и call() в следующих шагах и рассмотрим их подробнее.

    Создав такой слой, его можно использовать как функцию, принимающую на входе тензор TensorFlow:


#  Создать экземпляр слоя, который мы определили выше
my_dense = SimpleDense(units=32, activation=tf.nn.relu)
#  Сформировать некоторые входные данные
input_tensor = tf.ones(shape=(2, 784))
#  Вызвать слой подобно функции и передать ему входные данные
output_tensor = my_dense(input_tensor)
print(output_tensor.shape)

Блокнот с приведенными на этом шаге примерами можно взять здесь.

    Вам, наверное, интересно узнать, зачем нужно было реализовать методы call() и build(), если в итоге мы использовали наш слой, просто вызвав его как функцию, то есть с помощью его метода __call__()? Причина проста: нам нужно, чтобы состояние создавалось динамически, на лету. Давайте посмотрим, как это работает.

    На следующем шаге мы рассмотрим построение слоев на лету.




Предыдущий шаг Содержание Следующий шаг