Apache MXNet - KVStore i wizualizacja

W tym rozdziale omówiono pakiety KVStore w języku Python oraz wizualizację.

Pakiet KVStore

Sklepy KV to skrót od Key-Value store. Jest to krytyczny komponent używany do treningu na wielu urządzeniach. Jest to ważne, ponieważ komunikacja parametrów między urządzeniami na jednym, a także na wielu maszynach jest przesyłana przez jeden lub więcej serwerów z KVStore dla parametrów.

Pozwól nam zrozumieć działanie KVStore za pomocą następujących punktów:

  • Każda wartość w KVStore jest reprezentowana przez key i a value.

  • Każda tablica parametrów w sieci ma przypisany plik key a wagi tej tablicy parametrów są określane przez value.

  • Następnie węzły robocze pushgradienty po przetworzeniu partii. Oni teżpull zaktualizowane wagi przed przetworzeniem nowej partii.

Krótko mówiąc, możemy powiedzieć, że KVStore to miejsce do udostępniania danych, w którym każde urządzenie może przesyłać i pobierać dane.

Dane push-in i pull-out

KVStore można traktować jako pojedynczy obiekt współużytkowany przez różne urządzenia, takie jak GPU i komputery, w których każde urządzenie może wprowadzać i pobierać dane.

Poniżej przedstawiono kroki implementacji, które muszą wykonać urządzenia, aby wypychać i pobierać dane:

Etapy wdrażania

Initialisation- Pierwszym krokiem jest zainicjowanie wartości. Tutaj, dla naszego przykładu, zainicjujemy parę (int, NDArray) w KVStrore, a następnie wyciągniemy wartości -

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

Daje to następujący wynik -

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

Push, Aggregate, and Update - Po zainicjowaniu możemy przesłać nową wartość do KVStore o tym samym kształcie do klucza -

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

Output

Dane wyjściowe podano poniżej -

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

Dane używane do wypychania mogą być przechowywane na dowolnym urządzeniu, takim jak GPU lub komputery. Możemy również wprowadzić wiele wartości do tego samego klucza. W takim przypadku KVStore najpierw zsumuje wszystkie te wartości, a następnie przekaże zagregowaną wartość w następujący sposób -

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

Zobaczysz następujący wynik -

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

Dla każdego zastosowanego wypchnięcia KVStore połączy przekazaną wartość z wartością już zapisaną. Zostanie to zrobione za pomocą aktualizatora. Tutaj domyślnym aktualizatorem jest 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

Po wykonaniu powyższego kodu powinieneś zobaczyć następujące dane wyjściowe -

[[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

Poniżej podano wynik kodu -

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

Pull - Podobnie jak w przypadku Push, możemy również przeciągnąć wartość na kilka urządzeń za pomocą jednego wywołania w następujący sposób -

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

Output

Dane wyjściowe podano poniżej -

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

Pełny przykład implementacji

Poniżej podano pełny przykład wdrożenia -

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())

Obsługa par klucz-wartość

Wszystkie operacje, które zaimplementowaliśmy powyżej, dotyczą jednego klucza, ale KVStore zapewnia również interfejs dla a list of key-value pairs -

Dla jednego urządzenia

Poniżej znajduje się przykład pokazujący interfejs KVStore dla listy par klucz-wartość dla jednego urządzenia -

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

Otrzymasz następujący wynik -

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

Dla wielu urządzeń

Poniżej znajduje się przykład pokazujący interfejs KVStore dla listy par klucz-wartość dla wielu urządzeń -

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

Zobaczysz następujący wynik -

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

Pakiet wizualizacji

Pakiet wizualizacji to pakiet Apache MXNet używany do reprezentowania sieci neuronowej (NN) jako grafu obliczeniowego składającego się z węzłów i krawędzi.

Wizualizuj sieć neuronową

W poniższym przykładzie użyjemy mx.viz.plot_networkwizualizacja sieci neuronowej. Następujące warunki są do tego niezbędne -

Prerequisites

  • Notatnik Jupyter

  • Biblioteka Graphviz

Przykład implementacji

W poniższym przykładzie zwizualizujemy próbkę NN dla liniowej faktoryzacji macierzy -

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)