Как построить модель в MXNet с использованием матриц и матричных операций?

Я могу создать модель, используя предварительно построенные высокоуровневые функции, такие как FullyConnected. Например:

X = mx.sym.Variable('data')
P  = mx.sym.FullyConnected(data = X, name = 'fc1', num_hidden = 2)

Таким образом, я получаю символическую переменную P, которая зависит от символической переменной X. Другими словами, у меня есть вычислительный граф, который можно использовать для определения модели и выполнения таких операций, как fit и predict.

Теперь я хотел бы выразить P через X по-другому. Более подробно, вместо использования высокоуровневой функциональности (например, FullyConnected), я хотел бы явно указать отношения между P и X ", используя низкоуровневые тензорные операции (например, матричное умножение) и символические переменные, представляющие параметры модели (матрица веса озера).

Например, чтобы достичь того же, что и выше, я попробовал followig:

W = mx.sym.Variable('W')
B = mx.sym.Variable('B')
P = mx.sym.broadcast_plus(mx.sym.dot(X, W), B)

Однако полученный таким образом P не эквивалентен ранее полученному P. Я не могу использовать его таким же образом. В частности, насколько я понимаю, MXNet жалуется, что W и B не имеют значений (что имеет смысл).

Я также попытался объявить W и B другим способом (чтобы они имели значения):

w = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
b = np.array([7.0, 8.0])

W = mx.nd.array(w)
B = mx.nd.array(b)

Это не работает. Я предполагаю, что MXNet жалуется, потому что он ожидает символическую переменную, но вместо этого получает nd-массивы.

Итак, мой вопрос заключается в том, как построить модель с использованием низкоуровневых тензорных операций (например, матричное умножение) и явных объектов, представляющих параметры модели (например, матричные весы).

Ответ 1

Возможно, вы захотите взглянуть на API Gluon. Например, здесь приведено руководство по созданию MLP с нуля, включая выделение параметров:

#######################
#  Allocate parameters for the first hidden layer
#######################
W1 = nd.random_normal(shape=(num_inputs, num_hidden), scale=weight_scale, ctx=model_ctx)
b1 = nd.random_normal(shape=num_hidden, scale=weight_scale, ctx=model_ctx)

params = [W1, b1, ...]

Прикрепление их к автоматическому градиенту

for param in params:
    param.attach_grad()

Определите модель:

def net(X):
    #######################
    #  Compute the first hidden layer
    #######################
    h1_linear = nd.dot(X, W1) + b1
    ...

и выполнить его

epochs = 10
learning_rate = .001
smoothing_constant = .01

for e in range(epochs):
    ...
    for i, (data, label) in enumerate(train_data):
        data = data.as_in_context(model_ctx).reshape((-1, 784))
        label = label.as_in_context(model_ctx)
        ...
        with autograd.record():
            output = net(data)
            loss = softmax_cross_entropy(output, label_one_hot)
        loss.backward()
        SGD(params, learning_rate)

Вы можете увидеть полный пример в прямом допинге:

http://gluon.mxnet.io/chapter03_deep-neural-networks/mlp-scratch.html