|
11 | 11 |
|
12 | 12 |
|
13 | 13 | def pairwiseEuclideanGPU(a, b, returnAsGPU=False, squared=False): |
| 14 | + """ |
| 15 | + Compute the pairwise euclidean distance between matrices a and b. |
| 16 | +
|
| 17 | +
|
| 18 | + Parameters |
| 19 | + ---------- |
| 20 | + a : np.ndarray (n, f) |
| 21 | + first matrice |
| 22 | + b : np.ndarray (m, f) |
| 23 | + second matrice |
| 24 | + returnAsGPU : boolean, optional (default False) |
| 25 | + if True, returns cudamat matrix still on GPU, else return np.ndarray |
| 26 | + squared : boolean, optional (default False) |
| 27 | + if True, return squared euclidean distance matrice |
| 28 | +
|
| 29 | +
|
| 30 | + Returns |
| 31 | + ------- |
| 32 | + c : (n x m) np.ndarray or cudamat.CUDAMatrix |
| 33 | + pairwise euclidean distance distance matrix |
| 34 | + """ |
14 | 35 | # a is shape (n, f) and b shape (m, f). Return matrix c of shape (n, m). |
15 | 36 | # First compute in c_GPU the squared euclidean distance. And return its |
16 | 37 | # square root. At each cell [i,j] of c, we want to have |
@@ -46,6 +67,48 @@ def pairwiseEuclideanGPU(a, b, returnAsGPU=False, squared=False): |
46 | 67 | return c_GPU.asarray() |
47 | 68 |
|
48 | 69 |
|
| 70 | +def sinkhorn_lpl1_mm(a, labels_a, b, M_GPU, reg, eta=0.1, numItermax=10, |
| 71 | + numInnerItermax=200, stopInnerThr=1e-9, |
| 72 | + verbose=False, log=False): |
| 73 | + p = 0.5 |
| 74 | + epsilon = 1e-3 |
| 75 | + Nfin = len(b) |
| 76 | + |
| 77 | + indices_labels = [] |
| 78 | + classes = np.unique(labels_a) |
| 79 | + for c in classes: |
| 80 | + idxc, = np.where(labels_a == c) |
| 81 | + indices_labels.append(cudamat.CUDAMatrix(idxc.reshape(1, -1))) |
| 82 | + |
| 83 | + Mreg_GPU = cudamat.empty(M_GPU.shape) |
| 84 | + W_GPU = cudamat.empty(M_GPU.shape).assign(0) |
| 85 | + |
| 86 | + for cpt in range(numItermax): |
| 87 | + Mreg_GPU.assign(M_GPU) |
| 88 | + Mreg_GPU.add_mult(W_GPU, eta) |
| 89 | + transp_GPU = sinkhorn(a, b, Mreg_GPU, reg, numItermax=numInnerItermax, |
| 90 | + stopThr=stopInnerThr, returnAsGPU=True) |
| 91 | + # the transport has been computed. Check if classes are really |
| 92 | + # separated |
| 93 | + W_GPU.assign(1) |
| 94 | + W_GPU = W_GPU.transpose() |
| 95 | + for (i, c) in enumerate(classes): |
| 96 | + (_, nbRow) = indices_labels[i].shape |
| 97 | + tmpC_GPU = cudamat.empty((Nfin, nbRow)).assign(0) |
| 98 | + transp_GPU.transpose().select_columns(indices_labels[i], tmpC_GPU) |
| 99 | + majs_GPU = tmpC_GPU.sum(axis=1).add(epsilon) |
| 100 | + cudamat.pow(majs_GPU, (p-1)) |
| 101 | + majs_GPU.mult(p) |
| 102 | + |
| 103 | + tmpC_GPU.assign(0) |
| 104 | + tmpC_GPU.add_col_vec(majs_GPU) |
| 105 | + W_GPU.set_selected_columns(indices_labels[i], tmpC_GPU) |
| 106 | + |
| 107 | + W_GPU = W_GPU.transpose() |
| 108 | + |
| 109 | + return transp_GPU.asarray() |
| 110 | + |
| 111 | + |
49 | 112 | class OTDA_GPU(OTDA): |
50 | 113 | def normalizeM(self, norm): |
51 | 114 | if norm == "median": |
@@ -84,3 +147,28 @@ def fit(self, xs, xt, reg=1, ws=None, wt=None, norm=None, **kwargs): |
84 | 147 | self.normalizeM(norm) |
85 | 148 | self.G = sinkhorn(ws, wt, self.M_GPU, reg, **kwargs) |
86 | 149 | self.computed = True |
| 150 | + |
| 151 | + |
| 152 | +class OTDA_lpl1(OTDA_GPU): |
| 153 | + def fit(self, xs, ys, xt, reg=1, eta=1, ws=None, wt=None, norm=None, |
| 154 | + **kwargs): |
| 155 | + cudamat.init() |
| 156 | + xs = np.asarray(xs, dtype=np.float64) |
| 157 | + xt = np.asarray(xt, dtype=np.float64) |
| 158 | + |
| 159 | + self.xs = xs |
| 160 | + self.xt = xt |
| 161 | + |
| 162 | + if wt is None: |
| 163 | + wt = unif(xt.shape[0]) |
| 164 | + if ws is None: |
| 165 | + ws = unif(xs.shape[0]) |
| 166 | + |
| 167 | + self.ws = ws |
| 168 | + self.wt = wt |
| 169 | + |
| 170 | + self.M_GPU = pairwiseEuclideanGPU(xs, xt, returnAsGPU=True, |
| 171 | + squared=True) |
| 172 | + self.normalizeM(norm) |
| 173 | + self.G = sinkhorn_lpl1_mm(ws, ys, wt, self.M_GPU, reg, eta, **kwargs) |
| 174 | + self.computed = True |
0 commit comments