Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

5.3 Отложенная инициализация

До сих пор при построении сети мы оставляли без внимания следующие моменты:

  • мы определили архитектуру сети, но не задали размерность входа;
  • мы добавляли слои, не указывая выходную размерность предыдущего слоя;
  • при инициализации параметров у нас даже нет достаточной информации, чтобы определить, сколько параметров должна содержать модель.

Некоторые читатели могут удивиться тому, что наш код вообще работает. Ведь фреймворк глубокого обучения не может знать, какой будет размерность входа сети. Секрет в том, что фреймворк использует отложенную инициализацию (defers initialization): он откладывает инициализацию и определяет размер каждого слоя динамически — только тогда, когда данные впервые проходят через модель.

Позднее, при работе со свёрточными нейронными сетями, эта техника окажется ещё удобнее, поскольку входная размерность (то есть разрешение изображения) будет влиять на размерность каждого последующего слоя. Уже сейчас мы можем задавать параметры, не зная заранее их размерностей, и такая возможность существенно упрощает определение и изменение моделей. Далее мы подробнее рассмотрим механизм инициализации.

5.3.1 Создание экземпляра сети

Сначала создадим экземпляр многослойного перцептрона.

MXNet:

from mxnet import np, npx
from mxnet.gluon import nn
npx.set_np()

def get_net():
    net = nn.Sequential()
    net.add(nn.Dense(256, activation='relu'))
    net.add(nn.Dense(10))
    return net

net = get_net()

TensorFlow:

import tensorflow as tf

net = tf.keras.models.Sequential([
    tf.keras.layers.Dense(256, activation=tf.nn.relu),
    tf.keras.layers.Dense(10),
])

Поскольку размерность входа пока неизвестна, сеть не может знать размерность весов входного слоя. Поэтому фреймворк пока не инициализировал ни один параметр, что мы проверим, попытавшись получить доступ к параметрам.

MXNet:

print(net.collect_params)
print(net.collect_params())

TensorFlow:

[net.layers[i].get_weights() for i in range(len(net.layers))]

MXNet: Обратите внимание, что при существующих объектах параметров входная размерность каждого слоя равна -1. MXNet использует специальное значение -1, чтобы обозначить, что размерность параметра пока неизвестна. В этот момент попытка обратиться к net[0].weight.data() вызовет ошибку времени выполнения, которая сообщит, что сначала нужно инициализировать сеть и только потом получать доступ к параметрам. Теперь посмотрим, что происходит, когда мы пытаемся инициализировать параметры с помощью функции initialize.

TensorFlow: Обратите внимание, что объекты всех слоёв существуют, но веса пусты. Вызов net.get_weights() приведёт к ошибке, потому что веса ещё не инициализированы.

MXNet:

net.initialize()
net.collect_params()

MXNet: Как видно, ничего не изменилось. Когда входная размерность неизвестна, вызов initialize не инициализирует параметры по-настоящему. Вместо этого MXNet запоминает, что параметры нужно инициализировать, и при этом может задать распределение для инициализации.

Далее пропустим данные через сеть, чтобы фреймворк наконец инициализировал параметры.

MXNet:

X = np.random.uniform(size=(2, 20))
net(X)

net.collect_params()

TensorFlow:

X = tf.random.uniform((2, 20))
net(X)
[w.shape for w in net.get_weights()]

Как только мы узнаём, что размерность входа равна 20, фреймворк может определить форму матрицы весов первого слоя, подставив значение 20. Определив форму первого слоя, фреймворк переходит ко второму слою и так далее, пока не станут известны все формы. Заметьте, что в данном случае отложенной инициализации требует только первый слой, но фреймворк всё равно инициализирует слои последовательно. Когда все формы параметров известны, фреймворк может инициализировать параметры.

Резюме

  • Отложенная инициализация позволяет фреймворку автоматически определять формы параметров, что упрощает изменение архитектуры модели и помогает избежать некоторых распространённых ошибок.
  • Мы можем пропустить данные через модель, чтобы фреймворк в конце концов инициализировал параметры.

Упражнения

  1. Что произойдёт, если задать входную размерность первого слоя, но не задавать размерности последующих слоёв? Происходит ли инициализация сразу?
  2. Что будет, если задать несовпадающие размерности?
  3. Что нужно сделать, если входные данные имеют разную размерность? Подсказка: обратитесь к разделу о связывании параметров.

MXNet: Обсуждение

PyTorch: Обсуждение

TensorFlow: Обсуждение

PaddlePaddle: Обсуждение