首页 > 解决方案 > 使用 reticulate 从 R 导入的函数计算梯度时出错

问题描述

我现在正在解决一个问题,我试图在 Python 中使用 Tensorflow 概率中的优化器来解决我已经在 R 中定义的简单优化问题。

以下是步骤:

第 1 步:定义解决 Rosenbrock 香蕉函数的原始 Python 问题:

import contextlib
import functools
import os
import time

import numpy as np
import pandas as pd
import scipy as sp
from six.moves import urllib
from sklearn import preprocessing

import tensorflow.compat.v2 as tf
tf.enable_v2_behavior()

import tensorflow_probability as tfp


def make_val_and_grad_fn(value_fn):
    @functools.wraps(value_fn)
    def val_and_grad(x):
        return tfp.math.value_and_gradient(value_fn, x)
    return val_and_grad 

@contextlib.contextmanager
def timed_execution():
    t0 = time.time()
    yield
    dt = time.time() - t0
    print('Evaluation took: %f seconds' % dt)

def np_value(tensor):
  """Get numpy value out of possibly nested tuple of tensors."""
  if isinstance(tensor, tuple):
    return type(tensor)(*(np_value(t) for t in tensor))
  else:
    return tensor.numpy()

def run(optimizer):
    optimizer()  # Warmup.
    with timed_execution():
        result = optimizer()
    return np_value(result)
  
  
def run(optimizer):
    optimizer()  # Warmup.
    with timed_execution():
        result = optimizer()
    return np_value(result)
  

@make_val_and_grad_fn
def rosenbrock_test(coord):
    x, y = coord[..., 0], coord[..., 1]
    return((5.0-x)**2 + 10.0 * (y-x**2)**2)
  
optim_results = tfp.optimizer.lbfgs_minimize(
      rosenbrock_test,
      initial_position=rosenbrock_start, 
      tolerance=1e-12)
rosenbrock_start = tf.constant([2.,2.])



optim_results = tfp.optimizer.lbfgs_minimize(
      rosenbrock_test,
      initial_position=rosenbrock_start, 
      tolerance=1e-12)
rosenbrock_start = tf.constant([2.,2.])



print('L-BFGS Results')
print('Converged:', optim_results.converged)
print('Location of the minimum:', optim_results.position)
print('Number of iterations:', optim_results.num_iterations) 

第 2 步:在 R 中定义一个相同的函数:

rosenbrock_for_r <- function(coord){
  x <- coord[1]
  y <- coord[2]
  return(   (5-x)^2 + 10 * (y-x^2)^2       )    }

rosenbrock_for_r(c(2,2))

第 3 步:为 R 函数定义 Python 包装器:

def rosenbrock_R(coord): 
    return(r.rosenbrock_for_r(coord))

错误发生在这一步:

temp = [2.0,2.0] 
tfp.math.value_and_gradient(rosenbrock_R, [2.,2.])

错误是:

类型错误:rosenbrock_R() 接受 1 个位置参数,但给出了 2 个

我尝试调查是否在函数中输入了错误的内容,但实现与我的本机实现相同:

def rosenbrock_alt(coord):
    x, y = coord[..., 0], coord[..., 1]
    return((5.0-x)**2 + 10.0 * (y-x**2)**2)  
  
temp = tf.constant([2.0,2.0])
  
tfp.math.value_and_gradient(rosenbrock_alt,temp)

这会产生预期的输出:

(<tf.Tensor: shape=(), dtype=float32, numpy=49.0>, <tf.Tensor: shape=(2,), dtype=float32, numpy=array([154., -40.], dtype =float32)>)

标签: pythonrtensorflowreticulatetensorflow-probability

解决方案


tfp.math.value_and_gradient会将列表解压缩为多个参数,并对每个参数进行区分。你必须换成np.arrayor tf.convert_to_tensor

此外,目前还不清楚如何获得rosenbrock_for_r. 您可能必须使用类似的东西

@tf.custom_gradient
def f(x):
  def df(df_x):
    return r.grad_rosenbrock(x, df_x)
  return r.rosenbrock_for_r(x), df  # or x.numpy() but that will be eager-only

您可以使用tf.py_function将 eager/r 代码嵌入到 TF 图中。


推荐阅读