Нелинейная оптимизация с Tensorflow-вероятностью - PullRequest
6 голосов
/ 18 октября 2019

Я пытаюсь реализовать гауссову подгонку с помощью оптимизатора Nelder-Mead TensorFlow-вероятность: tfp.optimizer.nelder_mead_minimize(). Он не сходится, в то время как scipy.optimizer.minimize() обеспечивает хороший результат менее чем за 1 секунду времени вычислений. Я, вероятно, делаю что-то не так, но я не могу понять, что? Может ли кто-нибудь помочь мне в этом?

Я использую:

python                    3.7.3
tensorflow-probability    0.8
tensorflow                2.0

Вот мой код:

import tensorflow as tf
import tensorflow_probability as tfp
import numpy as np
import matplotlib as plt

# Define the gaussian model : y = 1/(sigma * sqrt(2 pi)) * exp(- (x-mu)²/(2*sigma²))
pi = np.pi
def model(x, theta):
    y = 1/(theta[1]*tf.sqrt(2*pi)) * tf.exp(-(x-theta[0])**2 /(2*theta[1]**2))
    return y


# Define the loss (least mean square)
def loss_function(theta, y, x, callback=False, n_iterations=1):
    global n_epochs_cb
    loss = tf.losses.mean_squared_error(y, model(x, theta))
    if callback:
        if n_epochs_cb % (n_iterations/10.) == 0:
            print('{0:4d}   {1:}   {2: 3.6f}'.format(n_epochs_cb, theta, loss))
    n_epochs_cb = n_epochs_cb + 1
    return loss


# Generate some data
theta_true = [3, 2]
X = np.arange(-10, 10, 0.5) 
Y = model(X, theta_true) 
# fig, ax = plt.subplots(1, 1, figsize = [20, 10])
# ax.scatter(X, Y, label='data', alpha=0.5)

# initialize parameters 
theta = tf.constant(tf.random.uniform([2], 0, 10), dtype=tf.float32, name='theta')
n_iterations = 100
n_epochs_cb = 1

# minimization
print('{0:4s}   {1:9s}               {2:9s}'.format('Iter', 'theta', 'loss'))
optim_results = tfp.optimizer.nelder_mead_minimize(lambda theta: loss_function(theta, X, Y, True, n_iterations),
                                                   initial_vertex=theta,
                                                   func_tolerance=1e-8,
                                                   position_tolerance=1e-8,
                                                   max_iterations=n_iterations)   

print("theta_true", theta_true)
print("theta_est", optim_results.position.numpy())
print("convergenced:", optim_results.converged.numpy())
print("number of function evaluation", optim_results.num_objective_evaluations.numpy())
print("number of iterations", optim_results.num_iterations.numpy())
print("objective value", optim_results.objective_value.numpy())

Остановка оптимизации около 50 итераций и возврат:

Iter   theta                   loss     
  10   [0.1448533 6.7525005]    33.408031
  20   [-0.2385819 28.76061  ]    33.382130
  30   [ -4.1879644 260.84622  ]    33.375771
  40   [ -34.722183 2053.5083  ]    33.375099
  50   [ -418.6432 24589.836 ]    33.375008
theta_true [3, 2]
theta_est [ -488.44122 28687.352  ]
convergenced: True
number of function evaluation 55
number of iterations 35
objective value 33.375008

Я запускаю ту же проблему, используя minimize() из scipy.optimize с методом 'Nelder-Mead', и он дает:

Iter   theta                                          loss     
  10   [4.61612335 4.40795762]    0.007583
  20   [3.19502416 2.09290338]    0.001023
  30   [3.01845636 1.99504269]    0.000091
  40   [2.99843397 2.00065615]    0.000010
Optimization terminated successfully.
         Current function value: 0.000010
         Iterations: 44
         Function evaluations: 96
computation time 0.046 seconds

Я ожидаю, что та же производительность будет при использовании Нельдера с вероятностью тензора-Mead Optimizer и оптимизатор Nelder-mead Scipy.optimize.

Что я делаю не так?

Редактировать: Нашли ошибку в определении функции потерь. следующий код теперь сходится:

import tensorflow as tf
import tensorflow_probability as tfp
import numpy as np
import matplotlib as plt

# Define the gaussian model : y = 1/(sigma * sqrt(2 pi)) * exp(- (x-mu)²/(2*sigma²))
pi = np.pi
def model(x, theta):
    y =  1/(theta[1]*tf.sqrt(2*pi)) * tf.exp(-(x-theta[0])**2 /(2*theta[1]**2))
    return y


# Define the loss (least mean square)
def loss_function(theta, y, x, callback=False, n_iterations=1):
    global n_epochs_cb
    loss = tf.losses.mean_squared_error(y, model(x, theta))
    if callback:
        if n_epochs_cb % (n_iterations/10.) == 0:
            print('{0:4d}   {1:}   {2: 3.6f}'.format(n_epochs_cb, theta, loss))
    n_epochs_cb = n_epochs_cb + 1
    return loss

# Generate some data
theta_true = [3, 2]
X = np.arange(-10, 10, 0.5, dtype=np.float32) 
Y = model(X, theta_true) 
# fig, ax = plt.subplots(1, 1, figsize = [20, 10])
# ax.scatter(X, Y, label='data', alpha=0.5)

# initialize parameters 
theta = tf.constant(tf.random.uniform([2], 0, 10), dtype=tf.float32, name='theta')

print("theta_true", theta_true)
print("theta_init", theta.numpy())

n_iterations = 100
n_epochs_cb = 1

# minimization
print('{0:4s}   {1:9s}               {2:9s}'.format('Iter', 'theta', 'loss'))
optim_results = tfp.optimizer.nelder_mead_minimize(lambda theta: loss_function(theta, Y, X, True, n_iterations),
                                                   initial_vertex=theta,
                                                   func_tolerance=1e-8,
                                                   position_tolerance=1e-8,
                                                   max_iterations=n_iterations)   


print("theta_est", optim_results.position.numpy())
print("convergenced:", optim_results.converged.numpy())
print("number of function evaluation", optim_results.num_objective_evaluations.numpy())
print("number of iterations", optim_results.num_iterations.numpy())
print("objective value", optim_results.objective_value.numpy())
...