Apache MXNet - KVStore e Visualização

Este capítulo trata dos pacotes Python KVStore e visualização.

Pacote KVStore

Lojas KV significa armazenamento de valor-chave. É um componente crítico usado para treinamento em vários dispositivos. É importante porque a comunicação de parâmetros entre dispositivos em uma única máquina ou em várias máquinas é transmitida por meio de um ou mais servidores com um KVStore para os parâmetros.

Vamos entender o funcionamento da KVStore com a ajuda dos seguintes pontos:

  • Cada valor em KVStore é representado por um key e um value.

  • Cada array de parâmetros na rede é atribuído a um key e os pesos dessa matriz de parâmetro são referidos por value.

  • Depois disso, os nós de trabalho pushgradientes após o processamento de um lote. Eles tambémpull pesos atualizados antes de processar um novo lote.

Em palavras simples, podemos dizer que KVStore é um lugar para compartilhamento de dados onde, cada dispositivo pode enviar e retirar dados.

Data Push-In e Pull-Out

O KVStore pode ser considerado como um único objeto compartilhado por diferentes dispositivos, como GPUs e computadores, onde cada dispositivo é capaz de inserir e extrair dados.

A seguir estão as etapas de implementação que precisam ser seguidas por dispositivos para inserir e retirar dados:

Etapas de implementação

Initialisation- O primeiro passo é inicializar os valores. Aqui, para nosso exemplo, estaremos inicializando um par (int, NDArray) em KVStrore e depois retirando os valores -

import mxnet as mx
kv = mx.kv.create('local') # create a local KVStore.
shape = (3,3)
kv.init(3, mx.nd.ones(shape)*2)
a = mx.nd.zeros(shape)
kv.pull(3, out = a)
print(a.asnumpy())

Output

Isso produz a seguinte saída -

[[2. 2. 2.]
[2. 2. 2.]
[2. 2. 2.]]

Push, Aggregate, and Update - Uma vez inicializado, podemos colocar um novo valor no KVStore com a mesma forma para a chave -

kv.push(3, mx.nd.ones(shape)*8)
kv.pull(3, out = a)
print(a.asnumpy())

Output

O resultado é dado abaixo -

[[8. 8. 8.]
 [8. 8. 8.]
 [8. 8. 8.]]

Os dados usados ​​para envio podem ser armazenados em qualquer dispositivo, como GPUs ou computadores. Também podemos inserir vários valores na mesma chave. Nesse caso, o KVStore primeiro soma todos esses valores e, em seguida, envia o valor agregado da seguinte forma -

contexts = [mx.cpu(i) for i in range(4)]
b = [mx.nd.ones(shape, ctx) for ctx in contexts]
kv.push(3, b)
kv.pull(3, out = a)
print(a.asnumpy())

Output

Você verá a seguinte saída -

[[4. 4. 4.]
 [4. 4. 4.]
 [4. 4. 4.]]

Para cada push que você aplicou, o KVStore combinará o valor enviado com o valor já armazenado. Isso será feito com a ajuda de um atualizador. Aqui, o atualizador padrão é ASSIGN.

def update(key, input, stored):
   print("update on key: %d" % key)
   
   stored += input * 2
kv.set_updater(update)
kv.pull(3, out=a)
print(a.asnumpy())

Output

Ao executar o código acima, você verá a seguinte saída -

[[4. 4. 4.]
 [4. 4. 4.]
 [4. 4. 4.]]

Example

kv.push(3, mx.nd.ones(shape))
kv.pull(3, out=a)
print(a.asnumpy())

Output

A seguir está a saída do código -

update on key: 3
[[6. 6. 6.]
 [6. 6. 6.]
 [6. 6. 6.]]

Pull - Assim como Push, também podemos extrair o valor de vários dispositivos com uma única chamada, da seguinte maneira -

b = [mx.nd.ones(shape, ctx) for ctx in contexts]
kv.pull(3, out = b)
print(b[1].asnumpy())

Output

O resultado é declarado abaixo -

[[6. 6. 6.]
 [6. 6. 6.]
 [6. 6. 6.]]

Exemplo de implementação completo

A seguir está o exemplo de implementação completo -

import mxnet as mx
kv = mx.kv.create('local')
shape = (3,3)
kv.init(3, mx.nd.ones(shape)*2)
a = mx.nd.zeros(shape)
kv.pull(3, out = a)
print(a.asnumpy())
kv.push(3, mx.nd.ones(shape)*8)
kv.pull(3, out = a) # pull out the value
print(a.asnumpy())
contexts = [mx.cpu(i) for i in range(4)]
b = [mx.nd.ones(shape, ctx) for ctx in contexts]
kv.push(3, b)
kv.pull(3, out = a)
print(a.asnumpy())
def update(key, input, stored):
   print("update on key: %d" % key)
   stored += input * 2
kv._set_updater(update)
kv.pull(3, out=a)
print(a.asnumpy())
kv.push(3, mx.nd.ones(shape))
kv.pull(3, out=a)
print(a.asnumpy())
b = [mx.nd.ones(shape, ctx) for ctx in contexts]
kv.pull(3, out = b)
print(b[1].asnumpy())

Lidando com pares de valores-chave

Todas as operações que implementamos acima envolvem uma única chave, mas KVStore também fornece uma interface para a list of key-value pairs -

Para um único dispositivo

A seguir está um exemplo para mostrar uma interface KVStore para uma lista de pares chave-valor para um único dispositivo -

keys = [5, 7, 9]
kv.init(keys, [mx.nd.ones(shape)]*len(keys))
kv.push(keys, [mx.nd.ones(shape)]*len(keys))
b = [mx.nd.zeros(shape)]*len(keys)
kv.pull(keys, out = b)
print(b[1].asnumpy())

Output

Você receberá a seguinte saída -

update on key: 5
update on key: 7
update on key: 9
[[3. 3. 3.]
 [3. 3. 3.]
 [3. 3. 3.]]

Para vários dispositivos

A seguir está um exemplo para mostrar uma interface KVStore para uma lista de pares de valores-chave para vários dispositivos -

b = [[mx.nd.ones(shape, ctx) for ctx in contexts]] * len(keys)
kv.push(keys, b)
kv.pull(keys, out = b)
print(b[1][1].asnumpy())

Output

Você verá a seguinte saída -

update on key: 5
update on key: 7
update on key: 9
[[11. 11. 11.]
 [11. 11. 11.]
 [11. 11. 11.]]

Pacote de visualização

O pacote de visualização é o pacote Apache MXNet usado para representar a rede neural (NN) como um gráfico de computação que consiste em nós e arestas.

Visualize a rede neural

No exemplo abaixo, usaremos mx.viz.plot_networkpara visualizar a rede neural. A seguir são os pré-requisitos para isso -

Prerequisites

  • Caderno Jupyter

  • Biblioteca Graphviz

Exemplo de Implementação

No exemplo abaixo, iremos visualizar um NN de amostra para fatoração de matriz linear -

import mxnet as mx
user = mx.symbol.Variable('user')
item = mx.symbol.Variable('item')
score = mx.symbol.Variable('score')

# Set the dummy dimensions
k = 64
max_user = 100
max_item = 50

# The user feature lookup
user = mx.symbol.Embedding(data = user, input_dim = max_user, output_dim = k)

# The item feature lookup
item = mx.symbol.Embedding(data = item, input_dim = max_item, output_dim = k)

# predict by the inner product and then do sum
N_net = user * item
N_net = mx.symbol.sum_axis(data = N_net, axis = 1)
N_net = mx.symbol.Flatten(data = N_net)

# Defining the loss layer
N_net = mx.symbol.LinearRegressionOutput(data = N_net, label = score)

# Visualize the network
mx.viz.plot_network(N_net)