Commit e74a5d43 authored by Bharath Ramsundar's avatar Bharath Ramsundar
Browse files

Finished adding basic overfit tests. Need to clean up.

parent ae8739f2
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ class Metric(object):
    assert mode in ["classification", "regression"]
    self.mode = mode

  def compute_metric(self, y_true, y_pred, w):
  def compute_metric(self, y_true, y_pred, w, n_classes=2):
    """Compute a performance metric for each task.

    Args:
@@ -140,7 +140,10 @@ class Metric(object):
    computed_metrics = []
    for task in xrange(num_tasks):
      y_task = y_true[:, task]
      if self.mode == "regression":
        y_pred_task = y_pred[:, task]
      else:
        y_pred_task = y_pred[:, task*n_classes:(task+1)*n_classes]
      w_task = w[:, task]
    
      try:
@@ -172,14 +175,22 @@ class Metric(object):
    Raises:
      NotImplementedError: If metric_str is not in METRICS.
    """
    y_true = y_true[w != 0]
    y_pred = y_pred[w != 0]
    y_true = np.squeeze(y_true[w != 0])
    y_pred = np.squeeze(y_pred[w != 0])
    # If there are no nonzero examples, metric is ill-defined.
    if not len(y_true):
      return np.nan
    print("y_pred")
    print(y_pred)
    if self.mode == "classification":
      if self.name == "roc_auc_score":
        y_true = to_one_hot(y_true).astype(int)
      y_pred = y_pred[:, np.newaxis]
      else:
        y_true = y_true.astype(int)
        y_pred = from_one_hot(y_pred)
      #y_pred = from_one_hot(y_pred[:, np.newaxis])
    print("y_pred")
    print(y_pred)
    if self.threshold is not None:
      y_pred = np.greater(y_pred, threshold)
    try:
+4 −0
Original line number Diff line number Diff line
@@ -138,6 +138,10 @@ class Model(object):
    y_preds = []
    batch_size = self.model_params["batch_size"]
    for (X_batch, y_batch, w_batch, ids_batch) in dataset.iterbatches(batch_size):
      print("y_batch.shape")
      print(y_batch.shape)
      print("self.predict_on_batch(X_batch).shape")
      print(self.predict_on_batch(X_batch).shape)
      y_pred_batch = np.reshape(self.predict_on_batch(X_batch), y_batch.shape)
      y_pred_batch = undo_transforms(y_pred_batch, transformers)
      y_preds.append(y_pred_batch)
+17 −0
Original line number Diff line number Diff line
@@ -133,6 +133,23 @@ class MultiTaskDNN(KerasModel):
    y_pred = np.squeeze(y_pred)
    return y_pred

  def predict_proba_on_batch(self, X, n_classes=2):
    """
    Makes predictions on given batch of new data.
    """
    data = self.get_data_dict(X)
    y_pred_dict = self.raw_model.predict_on_batch(data)
    nb_samples = np.shape(X)[0]
    nb_tasks = len(self.tasks)
    y_pred = np.zeros((nb_samples, n_classes*nb_tasks))
    for ind, task in enumerate(self.tasks):
      task_type = self.task_types[task]
      taskname = "task%d" % ind
      y_pred_task = np.squeeze(y_pred_dict[taskname])
      y_pred[:, ind:ind+n_classes] = y_pred_task
    y_pred = np.squeeze(y_pred)
    return y_pred

class SingleTaskDNN(MultiTaskDNN):
  """
  Abstract base class for different ML models.
+38 −16
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ class TensorflowGraph(object):
    This function constructs the computational graph for the model. It relies
    subclassed methods (build/cost) to construct specific graphs.
    """
    print("TensorflowGraph.__init__()")
    self.graph = tf.Graph() 
    self.model_params = model_params
    self.logdir = logdir
@@ -136,6 +137,7 @@ class TensorflowGraph(object):

  def setup(self):
    """Add ops common to training/eval to the graph."""
    print("TensorflowGraph.setup()")
    with self.graph.as_default():
      with tf.name_scope('core_model'):
        self.build()
@@ -160,13 +162,15 @@ class TensorflowGraph(object):
    return tf.name_scope(self._name_scopes[name])

  def add_training_cost(self):
    print("TensorflowGraph.add_training_cost()")
    print("self.output")
    print(self.output)
    with self.graph.as_default():
      self.require_attributes(['output', 'labels', 'weights'])
      epsilon = 1e-3  # small float to avoid dividing by zero
      model_params = self.model_params
      weighted_costs = []  # weighted costs for each example
      gradient_costs = []  # costs used for gradient calculation
      old_costs = []  # old-style cost

      with self._shared_name_scope('costs'):
        for task in xrange(self.num_tasks):
@@ -182,28 +186,23 @@ class TensorflowGraph(object):
              # non-zero weight examples in the batch.  Also, instead of using
              # tf.reduce_mean (which can put ops on the CPU) we explicitly
              # calculate with div/sum so it stays on the GPU.
              print("model_params['batch_size']")
              print(model_params['batch_size'])
              print("weighted_cost")
              print(weighted_cost)
              gradient_cost = tf.div(tf.reduce_sum(weighted_cost),
                                     model_params["batch_size"])
              gradient_costs.append(gradient_cost)

            with tf.name_scope('old_cost'):
              old_cost = tf.div(
                  tf.reduce_sum(weighted_cost),
                  tf.reduce_sum(self.weights[task]) + epsilon)
              old_costs.append(old_cost)

        # aggregated costs
        with self._shared_name_scope('aggregated'):
          with tf.name_scope('gradient'):
            loss = tf.add_n(gradient_costs)
          with tf.name_scope('old_cost'):
            old_loss = tf.add_n(old_costs)

          # weight decay
          if model_params["penalty"] != 0.0:
            penalty = model_ops.WeightDecay(model_params)
            loss += penalty
            old_loss += penalty

        # loss used for gradient calculation
        self.loss = loss
@@ -255,9 +254,22 @@ class TensorflowGraph(object):
          for (X_b, y_b, w_b, ids_b) in dataset.iterbatches(batch_size):
            # Run training op and compute summaries.
            feed_dict = self.construct_feed_dict(X_b, y_b, w_b, ids_b)
            step, loss, _ = sess.run(
                [train_op.values()[0], self.loss, self.updates],
            #step, loss, _ = sess.run(
            #    [train_op.values()[0], self.loss, self.updates],
            #    feed_dict=feed_dict)
            output, step, loss, _ = sess.run(
                self.output + [train_op.values()[0], self.loss, self.updates],
                feed_dict=feed_dict)
            #print("loss")
            #print(loss)
            y_pred = np.squeeze(np.array(output))
            #print("y_pred")
            #print(y_pred)
            y_b = y_b.flatten()
            #print("y_b")
            #print(y_b)
            #print(".5*np.sum((y_b - y_pred)**2)/len(y_b)")
            #print(.5*np.sum((y_b - y_pred)**2)/len(y_b))
          # Save model checkpoints at end of epoch
          saver.save(sess, self._save_path, global_step=self.global_step)
          log('Ending epoch %d: loss %g' % (epoch, loss), self.verbosity)
@@ -333,10 +345,13 @@ class TensorflowGraph(object):

        #labels = np.array(from_one_hot(
        #    np.squeeze(np.concatenate(labels)), axis=-1))
        labels = np.squeeze(np.concatenate(labels)) 
        labels = np.array(labels)[:, 1]
        #labels = np.squeeze(np.concatenate(labels)) 
        outputs = np.array(from_one_hot(
            np.squeeze(np.concatenate(output)), axis=-1))
        #labels = np.array(labels)[:, 1]

    return np.copy(labels)
    #return np.copy(labels)
    return np.copy(outputs)

  def add_output_ops(self):
    """Replace logits with softmax outputs."""
@@ -658,7 +673,7 @@ class TensorflowRegressor(TensorflowGraph):
      A tensor with shape batch_size containing the weighted cost for each
      example.
    """
    #return tf.mul(0.5 * tf.square(output - labels), weights)
    return tf.mul(0.5 * tf.square(output - labels), weights)

  def example_counts(self, y_true):
    """Get counts of examples in each class.
@@ -734,6 +749,13 @@ class TensorflowModel(Model):
    """
    return self.eval_model.predict_on_batch(X)

  def predict_proba_on_batch(self, X):
    """
    Makes predictions on batch of data.
    """
    return self.eval_model.predict_proba_on_batch(X)


  def save(self):
    """
    No-op since tf models save themselves during fit()
+117 −36
Original line number Diff line number Diff line
@@ -62,11 +62,22 @@ import numpy as np
import tensorflow as tf
from tensorflow.python.platform import logging

from deepchem.metrics import from_one_hot
from deepchem.models.tensorflow_models import TensorflowClassifier
from deepchem.models.tensorflow_models import TensorflowRegressor
from deepchem.models.tensorflow_models import model_ops
from deepchem.metrics import to_one_hot

def softmax(x):
    """Simple numpy softmax implementation
    """
    tmp = np.max(x, axis = 1)
    x -= tmp.reshape((x.shape[0], 1))
    x = np.exp(x)
    tmp = np.sum(x, axis = 1)
    x /= tmp.reshape((x.shape[0], 1))
    return x

class TensorflowMultiTaskClassifier(TensorflowClassifier):
  """Implements an icml model as configured in a model_config.proto."""

@@ -148,6 +159,92 @@ class TensorflowMultiTaskClassifier(TensorflowClassifier):
    orig_dict["valid"] = np.ones((self.model_params["batch_size"],), dtype=bool)
    return self._get_feed_dict(orig_dict)

  def predict_proba_on_batch(self, X):
    """Return model output for the provided input.

    Restore(checkpoint) must have previously been called on this object.

    Args:
      dataset: deepchem.datasets.dataset object.

    Returns:
      Tuple of three numpy arrays with shape num_examples x num_tasks (x ...):
        output: Model outputs.
        labels: True labels.
        weights: Example weights.
      Note that the output and labels arrays may be more than 2D, e.g. for
      classifier models that return class probabilities.

    Raises:
      AssertionError: If model is not in evaluation mode.
      ValueError: If output and labels are not both 3D or both 2D.
    """
    if not self._restored_model:
      self.restore()
    with self.graph.as_default():
      assert not model_ops.is_training()
      self.require_attributes(['output', 'labels', 'weights'])

      # run eval data through the model
      num_tasks = self.num_tasks
      outputs, labels, weights = [], [], []
      start = time.time()
      with self._get_shared_session().as_default():
        batch_count = -1.0

        feed_dict = self.construct_feed_dict(X)
        batch_start = time.time()
        batch_count += 1
        data = self._get_shared_session().run(
            self.output + self.labels + self.weights,
            feed_dict=feed_dict)
        batch_outputs = np.asarray(data[:num_tasks], dtype=float)
        batch_labels = np.asarray(data[num_tasks:num_tasks * 2], dtype=float)
        batch_weights = np.asarray(data[num_tasks * 2:num_tasks * 3],
                                   dtype=float)
        # reshape to batch_size x num_tasks x ...
        if batch_outputs.ndim == 3 and batch_labels.ndim == 3:
          batch_outputs = batch_outputs.transpose((1, 0, 2))
          batch_labels = batch_labels.transpose((1, 0, 2))
        elif batch_outputs.ndim == 2 and batch_labels.ndim == 2:
          batch_outputs = batch_outputs.transpose((1, 0))
          batch_labels = batch_labels.transpose((1, 0))
        else:
          raise ValueError(
              'Unrecognized rank combination for output and labels: %s %s' %
              (batch_outputs.shape, batch_labels.shape))
        batch_weights = batch_weights.transpose((1, 0))
        valid = feed_dict[self.valid.name]
        # only take valid outputs
        if np.count_nonzero(~valid):
          batch_outputs = batch_outputs[valid]
          batch_labels = batch_labels[valid]
          batch_weights = batch_weights[valid]
        outputs.append(batch_outputs)
        labels.append(batch_labels)
        weights.append(batch_weights)

        print("predict_proba_on_batch()")
        print("batch_outputs")
        print(batch_outputs)
        print("batch_labels")
        print(batch_labels)
        logging.info('Eval batch took %g seconds', time.time() - start)

        #labels = np.array(from_one_hot(
        #    np.squeeze(np.concatenate(labels)), axis=-1))
        ##labels = np.squeeze(np.concatenate(labels)) 
        #labels = np.array(labels)[:, 1]

        # We apply softmax to predictions to get class probabilities.
        #outputs = np.array(from_one_hot(softmax(np.squeeze(np.concatenate(outputs)))))
        outputs = softmax(np.squeeze(np.concatenate(outputs)))
        print("outputs")
        print(outputs)

    #return np.copy(labels)
    return np.copy(outputs)

class TensorflowMultiTaskRegressor(TensorflowRegressor):
  """Implements an icml model as configured in a model_config.proto."""

@@ -158,6 +255,7 @@ class TensorflowMultiTaskRegressor(TensorflowRegressor):
      mol_features: Molecule descriptor (e.g. fingerprint) tensor with shape
        batch_size x num_features.
    """
    print("ENTERING TensorflowMultiTaskRegressor.build")
    assert len(self.model_params["data_shape"]) == 1
    num_features = self.model_params["data_shape"][0]
    with self.graph.as_default():
@@ -197,14 +295,17 @@ class TensorflowMultiTaskRegressor(TensorflowRegressor):
        prev_layer = layer
        prev_layer_size = layer_sizes[i]

      self.output = [tf.squeeze(model_ops.FullyConnectedLayer(
      self.output = []
      for task in range(self.num_tasks):
        self.output.append(tf.squeeze(
            model_ops.FullyConnectedLayer(
                tensor=prev_layer,
                size=layer_sizes[i],
                weight_init=tf.truncated_normal(
                    shape=[prev_layer_size, 1],
                    stddev=weight_init_stddevs[i]),
                bias_init=tf.constant(value=bias_init_consts[i],
                                shape=[1])))]
                                      shape=[1]))))

  def construct_feed_dict(self, X_b, y_b=None, w_b=None, ids_b=None):
    """Construct a feed dictionary from minibatch data.
@@ -259,52 +360,32 @@ class TensorflowMultiTaskRegressor(TensorflowRegressor):
      self.restore()
    with self.graph.as_default():
      assert not model_ops.is_training()
      self.require_attributes(['output', 'labels', 'weights'])
      self.require_attributes(['output'])

      # run eval data through the model
      num_tasks = self.num_tasks
      output, labels, weights = [], [], []
      start = time.time()
      outputs = []
      with self._get_shared_session().as_default():
        batch_count = -1.0

        feed_dict = self.construct_feed_dict(X)
        batch_start = time.time()
        batch_count += 1
        data = self._get_shared_session().run(
            self.output + self.labels + self.weights,
            feed_dict=feed_dict)
        batch_output = np.asarray(data[:num_tasks], dtype=float)
        batch_labels = np.asarray(data[num_tasks:num_tasks * 2], dtype=float)
        batch_weights = np.asarray(data[num_tasks * 2:num_tasks * 3],
                                   dtype=float)
            self.output, feed_dict=feed_dict)
        batch_outputs = np.asarray(data[:num_tasks], dtype=float)
        # reshape to batch_size x num_tasks x ...
        if batch_output.ndim == 3 and batch_labels.ndim == 3:
          batch_output = batch_output.transpose((1, 0, 2))
          batch_labels = batch_labels.transpose((1, 0, 2))
        elif batch_output.ndim == 2 and batch_labels.ndim == 2:
          batch_output = batch_output.transpose((1, 0))
          batch_labels = batch_labels.transpose((1, 0))
        if batch_outputs.ndim == 3:
          batch_outputs = batch_outputs.transpose((1, 0, 2))
        elif batch_outputs.ndim == 2:
          batch_outputs = batch_outputs.transpose((1, 0))
        else:
          raise ValueError(
              'Unrecognized rank combination for output and labels: %s %s' %
              (batch_output.shape, batch_labels.shape))
        batch_weights = batch_weights.transpose((1, 0))
              'Unrecognized rank combination for output: %s' %
              (batch_outputs.shape))
        valid = feed_dict[self.valid.name]
        # only take valid outputs
        if np.count_nonzero(~valid):
          batch_output = batch_output[valid]
          batch_labels = batch_labels[valid]
          batch_weights = batch_weights[valid]
        output.append(batch_output)
        labels.append(batch_labels)
        weights.append(batch_weights)

        logging.info('Eval batch took %g seconds', time.time() - start)
          batch_outputs = batch_outputs[valid]
        outputs.append(batch_outputs)

        #labels = np.array(from_one_hot(
        #    np.squeeze(np.concatenate(labels)), axis=-1))
        labels = np.squeeze(np.concatenate(labels)) 
        outputs = np.squeeze(np.concatenate(outputs)) 

    return np.copy(labels)
    return np.copy(outputs)
Loading