code: def coe(
      X,
      k,
      lamda=0.05,
      n_epochs=150,
      learning_rate=0.001,
      batch_size=1000,
      init_params=None,
  ):
      # Data = Dataset(data)
  
      # Initial user factors
      if init_params["U"] is None:
          U = torch.randn(X.shape[0], k, requires_grad=True)
      else:
          U = torch.from_numpy(init_params["U"])
          U.requires_grad = True
  
      # Initial item factors
      if init_params["V"] is None:
          V = torch.randn(X.shape[1], k, requires_grad=True)
      else:
          V = torch.from_numpy(init_params["V"])
          V.requires_grad = True
  
      optimizer = torch.optim.Adam([U, V], lr=learning_rate)
      for epoch in range(n_epochs):
          #        num_steps = int(Data.data.shape[0]/batch_size)
  
          #       for i in range(1, num_steps + 1):
          #          batch_c,_ = Data.next_batch(batch_size)
          sampled_batch = sample_triplet(X, batch_size)
  
          regU = U[sampled_batch[:, 0], :]
          regI = V[sampled_batch[:, 1], :]
          regJ = V[sampled_batch[:, 2], :]
  
          regU_unq = U[np.unique(sampled_batch[:, 0]), :]
          regI_unq = V[np.unique(sampled_batch[:, 1:]), :]
  
          Scorei = torch.norm(regU - regI, dim=1)
          Scorej = torch.norm(regU - regJ, dim=1)
  
          loss = (
              lamda * (regU_unq.norm().pow(2) + regI_unq.norm().pow(2))
              - torch.log(torch.sigmoid(Scorej - Scorei)).sum()
          )
          optimizer.zero_grad()
          loss.backward()
          optimizer.step()
          print("epoch:", epoch, "loss:", loss)
  
      U = U.data.cpu().numpy()
      V = V.data.cpu().numpy()
  
      res = {"U": U, "V": V}
  
      return res
  
imports: import random
  import numpy
  import torch
label_desc: Use image node_id 2 for calling a global function with example usage: coe(X, k, lamda, n_epochs, learning_rate, batch_size, init_params) and returns: res