| 299 | # |
| 300 | # Finally, separation_oracle() returns LOSS(idx,Y),PSI(X,Y) |
| 301 | def separation_oracle(self, idx, current_solution): |
| 302 | samp = self.samples[idx] |
| 303 | dims = len(samp) |
| 304 | scores = [0, 0, 0] |
| 305 | # compute scores for each of the three classifiers |
| 306 | scores[0] = dot(current_solution[0:dims], samp) |
| 307 | scores[1] = dot(current_solution[dims:2*dims], samp) |
| 308 | scores[2] = dot(current_solution[2*dims:3*dims], samp) |
| 309 | |
| 310 | # Add in the loss-augmentation. Recall that we maximize |
| 311 | # LOSS(idx,y) + F(X,y) in the separate oracle, not just F(X,y) as we |
| 312 | # normally would in predict_label(). Therefore, we must add in this |
| 313 | # extra amount to account for the loss-augmentation. For our simple |
| 314 | # multi-class classifier, we incur a loss of 1 if we don't predict the |
| 315 | # correct label and a loss of 0 if we get the right label. |
| 316 | if self.labels[idx] != 0: |
| 317 | scores[0] += 1 |
| 318 | if self.labels[idx] != 1: |
| 319 | scores[1] += 1 |
| 320 | if self.labels[idx] != 2: |
| 321 | scores[2] += 1 |
| 322 | |
| 323 | # Now figure out which classifier has the largest loss-augmented score. |
| 324 | max_scoring_label = scores.index(max(scores)) |
| 325 | # And finally record the loss that was associated with that predicted |
| 326 | # label. Again, the loss is 1 if the label is incorrect and 0 otherwise. |
| 327 | if max_scoring_label == self.labels[idx]: |
| 328 | loss = 0 |
| 329 | else: |
| 330 | loss = 1 |
| 331 | |
| 332 | # Finally, return the loss and PSI vector corresponding to the label |
| 333 | # we just found. |
| 334 | psi = self.make_psi(samp, max_scoring_label) |
| 335 | return loss, psi |
| 336 | |
| 337 | |
| 338 | if __name__ == "__main__": |