Apache MXNet - KVStore y visualización

Este capítulo trata sobre la visualización y los paquetes de Python KVStore.

Paquete KVStore

KV stores significa tienda de valor clave. Es un componente crítico que se utiliza para el entrenamiento con múltiples dispositivos. Es importante porque la comunicación de parámetros a través de dispositivos en una o varias máquinas se transmite a través de uno o más servidores con un KVStore para los parámetros.

Comprendamos el funcionamiento de KVStore con la ayuda de los siguientes puntos:

  • Cada valor en KVStore está representado por un key y un value.

  • A cada matriz de parámetros de la red se le asigna un key y los pesos de esa matriz de parámetros se refieren a value.

  • Después de eso, los nodos trabajadores pushgradientes después de procesar un lote. Ellos tambiénpull pesos actualizados antes de procesar un nuevo lote.

En palabras simples, podemos decir que KVStore es un lugar para compartir datos donde, cada dispositivo puede insertar y extraer datos.

Inserción y extracción de datos

KVStore se puede considerar como un único objeto compartido entre diferentes dispositivos, como GPU y computadoras, donde cada dispositivo puede ingresar y extraer datos.

Los siguientes son los pasos de implementación que deben seguir los dispositivos para insertar y extraer datos:

Pasos de implementación

Initialisation- El primer paso es inicializar los valores. Aquí, para nuestro ejemplo, inicializaremos un par (int, NDArray) en KVStrore y luego sacaremos los 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

Esto produce la siguiente salida:

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

Push, Aggregate, and Update - Una vez inicializado, podemos insertar un nuevo valor en KVStore con la misma forma que la clave -

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

Output

La salida se da a continuación:

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

Los datos utilizados para empujar se pueden almacenar en cualquier dispositivo, como GPU o computadoras. También podemos insertar varios valores en la misma clave. En este caso, KVStore primero sumará todos estos valores y luego enviará el valor agregado de la siguiente manera:

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

Verá la siguiente salida:

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

Para cada envío que haya aplicado, KVStore combinará el valor enviado con el valor ya almacenado. Se hará con la ayuda de un actualizador. Aquí, el actualizador predeterminado es ASIGNAR.

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

Cuando ejecute el código anterior, debería ver el siguiente resultado:

[[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 continuación se muestra la salida del código:

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

Pull - Al igual que Push, también podemos extraer el valor en varios dispositivos con una sola llamada de la siguiente manera:

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

Output

La salida se indica a continuación:

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

Ejemplo de implementación completo

A continuación se muestra el ejemplo de implementación 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())

Manejo de pares clave-valor

Todas las operaciones que hemos implementado anteriormente implican una sola clave, pero KVStore también proporciona una interfaz para a list of key-value pairs -

Para un solo dispositivo

A continuación, se muestra un ejemplo para mostrar una interfaz KVStore para una lista de pares clave-valor para un solo 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

Recibirá el siguiente resultado:

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

Para varios dispositivos

A continuación se muestra un ejemplo para mostrar una interfaz de KVStore para una lista de pares clave-valor para varios 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

Verá la siguiente salida:

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

Paquete de visualización

El paquete de visualización es el paquete Apache MXNet que se utiliza para representar la red neuronal (NN) como un gráfico de cálculo que consta de nodos y bordes.

Visualice la red neuronal

En el siguiente ejemplo usaremos mx.viz.plot_networkpara visualizar la red neuronal. Los siguientes son los requisitos previos para esto:

Prerequisites

  • Cuaderno Jupyter

  • Biblioteca Graphviz

Ejemplo de implementación

En el siguiente ejemplo, visualizaremos una muestra NN para la factorización de matriz lineal:

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)