|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
Can NOT be differentiated through. |
|
""" |
|
|
|
from __future__ import absolute_import |
|
from __future__ import division |
|
from __future__ import print_function |
|
|
|
import collections |
|
import numpy as np |
|
import sonnet as snt |
|
import tensorflow as tf |
|
from tensorflow.python.framework import function |
|
|
|
from learning_unsupervised_learning import utils |
|
|
|
from learning_unsupervised_learning.meta_objective import utils as meta_obj_utils |
|
|
|
from sklearn import svm |
|
from sklearn import linear_model |
|
|
|
|
|
def build_fit(device, model_fn, num_classes, probs=True): |
|
|
|
def _py_fit_predict(trX, trY, teX): |
|
assert len(np.unique(trY)) == num_classes |
|
model = model_fn() |
|
model.fit(trX, trY) |
|
trP = model.predict(trX) |
|
teP = model.predict(teX) |
|
if probs: |
|
teP_probs = model.predict_log_proba(teX) |
|
return trP.astype(np.int64), teP.astype(np.int64), teP_probs.astype( |
|
np.float32) |
|
else: |
|
teP = model.predict(teX) |
|
return trP.astype(np.int64), teP.astype(np.int64) |
|
|
|
def return_fn(trX, trY, teX): |
|
with tf.device(device): |
|
with tf.device("/cpu:0"): |
|
if probs: |
|
return tf.py_func( |
|
_py_fit_predict, |
|
[tf.identity(trX), |
|
tf.identity(trY), |
|
tf.identity(teX)], [tf.int64, tf.int64, tf.float32]) |
|
else: |
|
return tf.py_func( |
|
_py_fit_predict, |
|
[tf.identity(trX), |
|
tf.identity(trY), |
|
tf.identity(teX)], [tf.int64, tf.int64]) |
|
|
|
return return_fn |
|
|
|
|
|
class SKLearn(meta_obj_utils.MultiTrialMetaObjective): |
|
|
|
def __init__( |
|
self, |
|
local_device=None, |
|
remote_device=None, |
|
averages=1, |
|
samples_per_class=10, |
|
probs=False, |
|
stddev=0.01, |
|
n_samples=10, |
|
name="SKLearn", |
|
): |
|
self._local_device = local_device |
|
self._remote_device = remote_device |
|
self.name = name |
|
self.probs = probs |
|
self.n_samples = n_samples |
|
self.stddev = stddev |
|
|
|
super(SKLearn, self).__init__( |
|
name=name, samples_per_class=samples_per_class, averages=averages) |
|
|
|
def _get_model(self): |
|
raise NotImplemented() |
|
|
|
def _build_once(self, dataset, feature_transformer): |
|
with tf.device(self._local_device): |
|
tr_batch = dataset() |
|
te_batch = dataset() |
|
num_classes = tr_batch.label_onehot.shape.as_list()[1] |
|
all_batch = utils.structure_map_multi(lambda x: tf.concat(x, 0), |
|
[tr_batch, te_batch]) |
|
features = feature_transformer(all_batch) |
|
trX, teX = utils.structure_map_split(lambda x: tf.split(x, 2, axis=0), |
|
features) |
|
trY = tf.to_int64(tr_batch.label) |
|
trY_onehot = tf.to_int32(tr_batch.label_onehot) |
|
teY = tf.to_int64(te_batch.label) |
|
teY_shape = teY.shape.as_list() |
|
|
|
def blackbox((trX, trY, teX, teY)): |
|
trY = tf.to_int32(tf.rint(trY)) |
|
teY = tf.to_int32(tf.rint(teY)) |
|
tf_fn = build_fit( |
|
self._local_device, |
|
self._get_model, |
|
num_classes=num_classes, |
|
probs=self.probs) |
|
if self.probs: |
|
trP, teP, teP_probs = tf_fn(trX, trY, teX) |
|
else: |
|
trP, teP = tf_fn(trX, trY, teX) |
|
|
|
teY.set_shape(teY_shape) |
|
if self.probs: |
|
onehot = tf.one_hot(teY, num_classes) |
|
crossent = -tf.reduce_sum(onehot * teP_probs, [1]) |
|
return tf.reduce_mean(crossent) |
|
else: |
|
|
|
return 1 - tf.reduce_mean( |
|
tf.to_float(tf.equal(teY, tf.to_int32(teP)))) |
|
|
|
test_loss = blackbox((trX, tf.to_float(trY), teX, tf.to_float(teY))) |
|
|
|
stats = {} |
|
|
|
tf_fn = build_fit( |
|
self._local_device, |
|
self._get_model, |
|
num_classes=num_classes, |
|
probs=self.probs) |
|
if self.probs: |
|
trP, teP, teP_probs = tf_fn(trX, trY, teX) |
|
else: |
|
trP, teP = tf_fn(trX, trY, teX) |
|
stats["%s/accuracy_train" % self.name] = tf.reduce_mean( |
|
tf.to_float(tf.equal(tf.to_int32(trY), tf.to_int32(trP)))) |
|
stats["%s/accuracy_test" % self.name] = tf.reduce_mean( |
|
tf.to_float(tf.equal(tf.to_int32(teY), tf.to_int32(teP)))) |
|
stats["%s/test_loss" % self.name] = test_loss |
|
return test_loss, stats |
|
|
|
|
|
class LogisticRegression(SKLearn): |
|
|
|
def __init__(self, C=1.0, name="LogisticRegression", probs=True, **kwargs): |
|
self.C = C |
|
super(LogisticRegression, self).__init__(name=name, probs=probs, **kwargs) |
|
|
|
def _get_model(self): |
|
return linear_model.LogisticRegression(C=self.C) |
|
|