I have read your code:

So the first outerloop(function) is:L148:             def X_prime_class_split_func(j):

What’s the shape and data type of X_prime_class_split[j]? Maybe we could represent it as a tensor
from L162-L166: for k in range(m_class_split):
       # Encode vectors into quantum densities
       X_prime_class_split_each_row = X_prime_class_split_jth[k, :]
       density_each_row = np.dot(X_prime_class_split_each_row.reshape(-1, 1),
                                                   X_prime_class_split_each_row.reshape(1, -1))

You could definetly vectorize this inner loop.
from L171-L174else:
      density_each_row_copy = density_each_row
      for u in range(self.n_copies - 1):
            density_each_row = np.kron(density_each_row, density_each_row_copy)

There is no efficient way to parallelize kronecker product over n_copies since these code are iterative and strongly serial. But you could use the einsum function of pytorch to calculate:def kronecker(A, B):
    return torch.einsum("ab,cd->acbd", A, B).view(A.size(0)*B.size(0),  A.size(1)*B.size(1))


The scale(computation intensity) of your code does not suit process based parallelism, thread based parallelism is not good in your case as well, I suggest you "vectorize’ your code, use tensor operations insead of for loops, it would be at least 10 times more efficient.