2017-06-28 3 views
4

J'essaie d'utiliser les optimiseurs de descente de gradient de MXNet pour minimiser une fonction. L'exemple équivalent dans Tensorflow serait:Descente en dégradé simple avec mxnet

import tensorflow as tf 

x = tf.Variable(2, name='x', dtype=tf.float32) 
log_x = tf.log(x) 
log_x_squared = tf.square(log_x) 

optimizer = tf.train.GradientDescentOptimizer(0.5) 
train = optimizer.minimize(log_x_squared) 

init = tf.initialize_all_variables() 

def optimize(): 
    with tf.Session() as session: 
    session.run(init) 
    print("starting at", "x:", session.run(x), "log(x)^2:", session.run(log_x_squared)) 
    for step in range(10): 
     session.run(train) 
     print("step", step, "x:", session.run(x), "log(x)^2:", session.run(log_x_squared)) 

Je ne suis pas sûr de savoir comment faire la même chose dans MXNet. L'API de l'optimiseur documentation ne semble pas avoir une méthode équivalente. Voici ce que j'ai essayé jusqu'ici. La principale confusion a été autour de la nécessité de transmettre des données de formation:

import mxnet as mx 

x = mx.sym.Variable('data') 
log_x = mx.sym.log(x) 
log_x_squared = mx.sym.square(log_x) 

mod = mx.mod.Module(log_x_squared) # Create a module where the loss function 
            # is the one we want to optimize 
mod.bind(data_shapes=[('data', (1,1))]) # ?? not sure if this is correct - we 
             # are saying our input is a scalar 
mod.init_params() 
mod.init_optimizer() # SGD is default 

mod.fit() # ?? must pass data_iter to fit 

Il semble que la variable x doit être alimenté en quelque sorte de retour en tant que data_iter mais je ne sais pas comment accomplir cela.

Mise à jour: grâce à kevinthesun pour leur excellente réponse! Voici une routine de minimisation de travail construit sur un seul réseau de neurones couche cachée:

import mxnet as mx 
import numpy as np 


def minimize(objective_function, 
      initial_params, 
      max_iters=1000, 
      optimizer='sgd', 
      optimizer_params=(('learning_rate', 0.1),), 
      tol=1e-8): 

    class InitialParam(mx.init.Initializer): 

     def __init__(self, vals): 
      super(InitialParam, self).__init__() 
      self._vals = vals 

     def _init_weight(self, _, arr): 
      arr[:] = self._vals.asnumpy()[:, np.newaxis] 


    x = mx.sym.Variable('data') 
    params_len = initial_params.shape[0] 
    fc = mx.sym.FullyConnected(data=x, name='fc1', 
           num_hidden=params_len, 
           no_bias=True) 

    # Passing the FullyConnected layer into the objective function 
    # is difficult to manipulate. If the fully connected layer represents 
    # [x, y] for optimizing a 2 dimensional function f(x, y) it is easier 
    # to work with x, and y. So we split the fully connected layer into a 
    # number of symbols for each parameter: 
    param_syms = [] 
    for i in range(params_len): 
     ps = mx.sym.slice(fc, begin=(0, i), end=(1, i + 1)) 
     param_syms.append(ps) 

    # The loss function for the network is our objective function. 
    loss = mx.sym.MakeLoss(objective_function(param_syms)) 
    mod = mx.mod.Module(loss) 

    mod.bind(data_shapes=[('data', (1,))]) 
    mod.init_params(InitialParam(initial_params)) 
    mod.init_optimizer(optimizer=optimizer, 
         optimizer_params=optimizer_params) 

    (o_name, o_shape), = mod.output_shapes 

    i = 0 
    params = initial_params 
    old_val = np.full(o_shape, np.nan) 
    while i < max_iters: 
     mod.forward_backward(mx.io.DataBatch(
      data=[mx.nd.ones((1,))])) 
     mod.update() 
     params = mod.get_params()[0]['fc1_weight'] 
     val = mod.get_outputs()[0].asnumpy() 
     if np.allclose(old_val, val, atol=tol): 
      print 'Function value: {}'.format(val) 
      print 'Iterations: {}'.format(i) 
      return params 

     old_val = val 
     i += 1 

    return params 

et en l'utilisant:

def my_func(x): 
    return (x[0] + 1) ** 2 

p = minimize(my_func, mx.nd.array([1.0])) 
p.asnumpy() 

>>> array([[-0.99999988]], dtype=float32) 

et un autre:

def my_func(x): 
    return (x[0] + 1) ** 2 + (x[1] - 2) ** 2 + (x[2] + 3) ** 2 

p = minimize(my_func, mx.nd.array([1.0, 1.5, 2.0])) 
p.asnumpy() 

>>> array([[-0.99996436], 
      [ 1.99999106], 
      [-2.99991083]], dtype=float32) 

Répondre

4

Actuellement, il n'est pas aussi facile que tensorflow d'optimiser une fonction simple en utilisant MXNet, en raison du manque de support en frontend.

D'abord vous avez besoin d'une fonction de perte en tant que dernière couche de votre réseau. Ici, il s'agit de log_x_squared. Utilisez MakeLoss pour créer une fonction de perte.

La deuxième est l'entrée et les poids. Comme actuellement dans MXNet Variable n'est pas comptabilisé comme poids entraînable, vous devez définir x comme poids. Voici une solution de contournement: Définir une variable d'entrée «fausse» qui doit toujours être 1. Après cela, ajoutez un calque entièrement connecté avec 1 unité cachée et aucun biais. Cela nous donne "1 * x". Maintenant, notre x est un poids.

Troisièmement, si vous souhaitez optimiser plusieurs fois un échantillon de données unique, module.fit n'est peut-être pas le meilleur choix. Après l'initialisation de l'optimiseur. Vous avez juste besoin d'appeler module.forward_backward() et module.update() plusieurs fois. Pour la fonction forward_backward, vous devez passer un databatch, qui est une interface plus simple comparée à dataiter. Ici, nous avons juste besoin de passer un ndarray constant de 1 à chaque fois.

En fait, nous construisons un graphe de calcul de log (1 * x)^2 et x devient un poids au lieu de variable. Quoi qu'il en soit, nous devrions envisager de fournir une interface similaire de tensorflow pour optimiser la variable.

Espérons que ce soit utile!

0

mxnet est différent de tensorflow. Vous devez lire ceci tutorial