Search code examples
pythonscipymathematical-optimizationtensor

creating variable dynamically inside optimization function scipy


The below code is for finding the minimum errors in approximating tensor unfold with three matrices a, b, c. Optimization is carried using variables a, b, c.

I am new to optimization case so please help me out in understanding this. My queries are:

  1. inside f, how can we use a, b, c value at each iteration.
  2. How can we create a variable for khatri_rao product using a, b, c for each iteration.
  3. For each iteration, values of params[0]/[1]/[2] are not 2D array values. Not even initial values are seen? My code's error talks about which tuple?

Any help is appreciated. Thank you

import scipy.optimize as optimize
import numpy as np
import sys
sys.path.append("../tensorly-master/")
import tensorly as tl

def f(params, t0, t1, t2):#arguments are tensor unfold
    a, b, c= params[0], params[1], params[2]#multi variables in optimization
    #norm of tensor unfold mode0 minus "a" matrix multiplied with transpose of ' khatri rao product of "c" & "b" '
    value0= t0 - np.matmul(a, tl.tenalg.khatri_rao([c, b], reverse=False).T)
    value1= t1 - np.matmul(b, tl.tenalg.khatri_rao([a, c], reverse=False).T)
    value2= t2 - np.matmul(c, tl.tenalg.khatri_rao([b, a], reverse=False).T)
    #sum of all norms
    values=np.linalg.norm(value0, "fro")+np.linalg.norm(value1, "fro")+np.linalg.norm(value2, "fro")
    #optimizing the sum of all norms be minimum
    return values

#randomly initialinzing tensor , three arrays and unfolding tensor
tn=np.random.uniform(low=0, high=100, size=(3,3,3))
a=np.random.uniform(low=0, high=100, size=(3,2))
b=np.random.uniform(low=0, high=100, size=(3,2))
c=np.random.uniform(low=0, high=100, size=(3,2))
t0=tl.unfold(tn, 0)
t1=tl.unfold(tn, 1)
t2=tl.unfold(tn, 2)
#optimization
result=optimize.minimize(f, [a, b, c], args=(t0, t1, t2))
if result.success:
    fitted_params = result.x
    print(fitted_params)
else:
    raise ValueError(result.message)

the error is:

error:-
Using numpy backend.
Traceback (most recent call last):
  File "stc.py", line 27, in <module>
    result=optimize.minimize(f, [a, b, c], args=(t0, t1, t2))
  File "/home/manish/.local/lib/python2.7/site-packages/scipy/optimize/_minimize.py", line 597, in minimize
    return _minimize_bfgs(fun, x0, args, jac, callback, **options)
  File "/home/manish/.local/lib/python2.7/site-packages/scipy/optimize/optimize.py", line 963, in _minimize_bfgs
    gfk = myfprime(x0)
  File "/home/manish/.local/lib/python2.7/site-packages/scipy/optimize/optimize.py", line 293, in function_wrapper
    return function(*(wrapper_args + args))
  File "/home/manish/.local/lib/python2.7/site-packages/scipy/optimize/optimize.py", line 723, in approx_fprime
    return _approx_fprime_helper(xk, f, epsilon, args=args)
  File "/home/manish/.local/lib/python2.7/site-packages/scipy/optimize/optimize.py", line 657, in _approx_fprime_helper
    f0 = f(*((xk,) + args))
  File "/home/manish/.local/lib/python2.7/site-packages/scipy/optimize/optimize.py", line 293, in function_wrapper
    return function(*(wrapper_args + args))
  File "stc.py", line 10, in f
    value0= t0 - np.matmul(a, tl.tenalg.khatri_rao([c, b], reverse=False).T)
  File "../tensorly-master/tensorly/tenalg/_khatri_rao.py", line 70, in khatri_rao
    n_columns = matrices[0].shape[1]
IndexError: tuple index out of range

Solution

  • optimize calls the f function by passing a 1D array (shape (n,)), even if the given initial guess is not that shape (see for instance in _minimize_bfgs ). You could use reshape and numpy.split to reconstruct the correct 2D arrays a, b and c from the 1D array params:

    import scipy.optimize as optimize
    import numpy as np
    import tensorly as tl
    
    def f(params, t0, t1, t2): # arguments are tensor unfold
        a, b, c = np.split(x0.reshape(3, 6), 3, axis=1)  # unpack the variables
    
        # norm of tensor unfold mode0 minus "a" matrix 
        # multiplied with transpose of ' khatri rao product of "c" & "b" '
        value0= t0 - np.matmul(a, tl.tenalg.khatri_rao([c, b], reverse=False).T)
        value1= t1 - np.matmul(b, tl.tenalg.khatri_rao([a, c], reverse=False).T)
        value2= t2 - np.matmul(c, tl.tenalg.khatri_rao([b, a], reverse=False).T)
        #sum of all norms
        values = np.linalg.norm(value0, "fro") + \
                 np.linalg.norm(value1, "fro") + \
                 np.linalg.norm(value2, "fro")
    
        # optimizing the sum of all norms be minimum
        return values
    
    # randomly initializing tensor, three arrays and unfolding tensor
    tn = np.random.uniform(low=0, high=100, size=(3,3,3))
    t0 = tl.unfold(tn, 0)
    t1 = tl.unfold(tn, 1)
    t2 = tl.unfold(tn, 2)
    
    # Initial guess :
    a = np.random.uniform(low=0, high=100, size=(3,2))
    b = np.random.uniform(low=0, high=100, size=(3,2))
    c = np.random.uniform(low=0, high=100, size=(3,2))
    
    x0 = np.hstack([a, b, c]).ravel()
    
    # optimization
    result = optimize.minimize(f, x0, args=(t0, t1, t2))
    
    if result.success:
        fitted_params = result.x
        print(fitted_params)
    else:
        raise ValueError(result.message)