def network_karcher_mean_armijo(CList, pList, maxIter=50): # performing backtracking line search CBase = CList[0] pBase = pList[0] Delta = 1000 counter = 0 loss_init = frechet_loss(CBase, CList, pBase, pList) Frechet_Loss = [loss_init] #Delta = loss_init print('Iter', 'Frechet_Loss') print(counter, loss_init) #while counter < maxIter: # This is a pretty arbitrary stopping condition while Delta > 1e-10 * loss_init and counter < maxIter: # This is a pretty arbitrary stopping condition C0, pBase, gradient = frechet_gradient(CList, pList, CBase, pBase) # perform backtracking line search with following parameters: # currently at C0, descent direction = gradient, # actual gradient = -gradient, loss function = frechet_loss f_val = frechet_loss(C0, CList, pBase, pList) def frechet_loss_at(Y): return frechet_loss(Y, CList, pBase, pList) # Optionally normalize descent direction. Our gradient is minus the # true gradient pk = np.divide(gradient, np.linalg.norm(gradient)) # Can replace gradient below by pk alpha, fc, f_val = line_search_armijo(frechet_loss_at, C0, gradient, -gradient, f_val) CBase = exp_map(C0, alpha * gradient) #step size satisfying Armijo condition Frechet_Loss.append(f_val) Delta = abs(Frechet_Loss[-1] - Frechet_Loss[-2]) counter = counter + 1 print(counter, f_val) print('Initial Loss: ' + str(Frechet_Loss[0])) print('Loss for Minimizer: ' + str(Frechet_Loss[-1])) return CBase, pBase, Frechet_Loss
def network_karcher_mean_armijo_sched_compress(CBase, pBase, CList,pList,budget,exploreIter = 20, maxIter = 50): # Take exploreIter full gradient steps at first, # then do backtracking line search up to maxIter Delta = 1000 counter = 0 loss_init = frechet_loss(CBase,CList,pBase,pList) Frechet_Loss = [loss_init] #Delta = loss_init print('Iter','Frechet_Loss') print(counter, loss_init) tmpC = [CBase] tmpP = [pBase] # Do full gradient steps while counter < exploreIter: CBase, pBase, gradient = frechet_gradient_compressed(CList,pList,CBase,pBase,budget) print('current size ', CBase.shape) CBase = exp_map(CBase,gradient) tmpC.append(CBase) tmpP.append(pBase) f_val = frechet_loss(CBase, CList, pBase, pList) Frechet_Loss.append(f_val) counter = counter + 1 print(counter, f_val, ' full gradient step') # Set CBase to be the best seed point idx = Frechet_Loss.index(min(Frechet_Loss)) CBase = tmpC[idx] pBase = tmpP[idx] print('setting seed at ', idx) f_val = frechet_loss(CBase, CList, pBase, pList) print('seed loss is', f_val) #while counter < maxIter: # This is a pretty arbitrary stopping condition while Delta > 1e-10*loss_init and counter < maxIter: # This is a pretty arbitrary stopping condition C0, pBase, gradient = frechet_gradient_compressed(CList,pList,CBase,pBase,budget) # perform backtracking line search with following parameters: # currently at CBase, descent direction = gradient, # actual gradient = -gradient, loss function = frechet_loss def frechet_loss_at(Y): return frechet_loss(Y,CList,pBase,pList) # Optionally normalize descent direction. Our gradient is minus the # true gradient # gradSz = np.linalg.norm(gradient) #if gradSz > 0: # pk = np.divide(gradient,np.linalg.norm(gradient)) try: alpha, fc, f_val = line_search_armijo(frechet_loss_at, C0, gradient, -gradient, f_val) except: print('exception at iteration ', counter) f_val = frechet_loss_at(C0) print('error at current center is ', f_val) return C0, pBase, Frechet_Loss CBase = exp_map(CBase, alpha*gradient) #step size satisfying Armijo condition Frechet_Loss.append(f_val) Delta = abs(Frechet_Loss[-1]-Frechet_Loss[-2]) counter = counter + 1 print(counter, f_val, 'step scale',alpha) print('Initial Loss: '+str(Frechet_Loss[0])) print('Loss for Minimizer: '+str(Frechet_Loss[-1])) return CBase, pBase, Frechet_Loss
def gwa_cg(a, b, M, reg, f, df, G0=None, numItermax=200, stopThr=1e-9, verbose=False, log=False): # Please refer to cg function in pot package for documentation loop = 1 if log: log = {'loss': []} if G0 is None: G = np.outer(a, b) else: G = G0 def cost(G): return np.sum(M * G) + reg * f(G) f_val = cost(G) if log: log['loss'].append(f_val) it = 0 if verbose: print('{:5s}|{:12s}|{:8s}'.format( 'It.', 'Loss', 'Delta loss') + '\n' + '-' * 32) print('{:5d}|{:8e}|{:8e}'.format(it, f_val, 0)) while loop: it += 1 old_fval = f_val # problem linearization Mi = M + reg * df(G) # set M positive Mi += Mi.min() # solve linear program Gc = ot.emd(a, b, Mi) deltaG = Gc - G # line search alpha, fc, f_val = line_search_armijo(cost, G, deltaG, Mi, f_val) # added May 19, 2020 to avoid multiplication between NoneType and Float if alpha is not None: G = G + alpha * deltaG # test convergence if it >= numItermax: loop = 0 # extra stopping condition in gwa_cg # to avoid dividing by zero if f_val == 0: loop = 0 delta_fval = (f_val - old_fval) / abs(f_val) if abs(delta_fval) < stopThr: loop = 0 if log: log['loss'].append(f_val) if verbose: if it % 20 == 0: print('{:5s}|{:12s}|{:8s}'.format( 'It.', 'Loss', 'Delta loss') + '\n' + '-' * 32) print('{:5d}|{:8e}|{:8e}'.format(it, f_val, delta_fval)) if log: return G, log else: return G
def generalized_conditional_gradient(self, source, target, source_labels): ''' Algoritmo GCG: gradiente condicional generalizado. Calcula la matriz de transporte gamma. Argumentos -------------------------------- source: numpy.ndarray shape(m, k). datos del dominio fuente. target: numpy.ndarray shape(n, k). datos del dominio objetivo. source_labels: numpy.ndarray shape(m, ) etiquetas del dominio fuente. Retorno ----------------------------------- G: numpy.ndarray shape(m, n) Matriz gamma de transporte. ''' loop = True a, b = self.compute_probs(source), self.compute_probs(target) G = np.outer(a, b) M = self.cost_transport_matrix(source, target) cost, cost_gradient, f, df = self.computation_graph( source, target, source_labels ) f_val = cost(G) it = 0 while loop: it += 1 old_fval = f_val # problem linearization Mi = M + self.eta * df(G) # solve linear program with Sinkhorn Gc = sinkhorn( a, b, Mi, self.labda, numItermax=self.num_iters_sinkhorn ) deltaG = Gc - G # line search # Que yo sepa la evaluación de la función se hace con G, no con # Gc dcost = cost_gradient(G) alpha, fc, f_val = line_search_armijo( cost, G, deltaG, dcost, f_val ) if alpha is None: # No se si esto es lo correcto return G G = G + alpha * deltaG # test convergence if it >= self.num_iters_sinkhorn: loop = False # delta_fval = (f_val - old_fval) / abs(f_val) delta_fval = (f_val - old_fval) # print('fval:', f_val, 'delta_fval:', delta_fval) if abs(delta_fval) < self.convergence_threshold: loop = False return G