Commit eab4109d authored by Bharath Ramsundar's avatar Bharath Ramsundar Committed by GitHub
Browse files

Merge pull request #244 from rbharath/graph_conv_changes

Fixes prediction for rigid-batch models
parents 8956bc7a 6c30d262
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -277,7 +277,7 @@ class NumpyDataset(Dataset):
      for j in range(len(interval_points)-1):
        indices = range(interval_points[j], interval_points[j+1])
        perm_indices = sample_perm[indices]
        X_batch = dataset._X[perm_indices, :]
        X_batch = dataset._X[perm_indices]
        y_batch = dataset._y[perm_indices]
        w_batch = dataset._w[perm_indices]
        ids_batch = dataset._ids[perm_indices]
@@ -535,7 +535,7 @@ class DiskDataset(Dataset):
        for j in range(len(interval_points)-1):
          indices = range(interval_points[j], interval_points[j+1])
          perm_indices = sample_perm[indices]
          X_batch = X[perm_indices, :]
          X_batch = X[perm_indices]
          y_batch = y[perm_indices]
          w_batch = w[perm_indices]
          ids_batch = ids[perm_indices]
@@ -875,9 +875,15 @@ class DiskDataset(Dataset):
  def X(self):
    """Get the X vector for this dataset as a single numpy array."""
    Xs = []
    one_dimensional = False
    for (X_b, _, _, _) in self.itershards():
      Xs.append(X_b)
      if len(X_b.shape) == 1:
        one_dimensional = True
    if not one_dimensional:
      return np.vstack(Xs)
    else:
      return np.concatenate(Xs)

  @property
  def y(self):
+26 −11
Original line number Diff line number Diff line
@@ -54,16 +54,32 @@ class Model(object):
    raise NotImplementedError(
        "Each model is responsible for its own fit_on_batch method.")

  def predict_on_batch(self, X):
  def predict_on_batch(self, X, pad_batch=False):
    """
    Makes predictions on given batch of new data.

    Parameters
    ----------
    X: np.ndarray
      Features
    pad_batch: bool, optional
      Ignored for Sklearn Model. Only used for Tensorflow models
      with rigid batch-size requirements.
    """
    raise NotImplementedError(
        "Each model is responsible for its own predict_on_batch method.")

  def predict_proba_on_batch(self, X):
  def predict_proba_on_batch(self, X, pad_batch=False):
    """
    Makes predictions of class probabilities on given batch of new data.

    Parameters
    ----------
    X: np.ndarray
      Features
    pad_batch: bool, optional
      Ignored for Sklearn Model. Only used for Tensorflow models
      with rigid batch-size requirements.
    """
    raise NotImplementedError(
        "Each model is responsible for its own predict_on_batch method.")
@@ -142,10 +158,8 @@ class Model(object):
    for (X_batch, y_batch, w_batch, ids_batch) in dataset.iterbatches(
        batch_size, deterministic=True):
      n_samples = len(X_batch)
      if pad_batches:
        X_batch = pad_features(batch_size, X_batch)
      y_pred_batch = self.predict_on_batch(X_batch)
      if pad_batches:
      y_pred_batch = self.predict_on_batch(X_batch, pad_batch=pad_batches)
      # Discard any padded predictions
      y_pred_batch = y_pred_batch[:n_samples]
      y_pred_batch = np.reshape(y_pred_batch, (n_samples, n_tasks))
      y_pred_batch = undo_transforms(y_pred_batch, transformers)
@@ -342,7 +356,7 @@ class Model(object):


  def predict_proba(self, dataset, transformers=[], batch_size=None,
                    n_classes=2):
                    n_classes=2, pad_batches=False):
    """
    TODO: Do transformers even make sense here?

@@ -353,9 +367,10 @@ class Model(object):
    n_tasks = self.get_num_tasks()
    for (X_batch, y_batch, w_batch, ids_batch) in dataset.iterbatches(
        batch_size, deterministic=True):
      y_pred_batch = self.predict_proba_on_batch(X_batch)
      batch_size = len(y_batch)
      y_pred_batch = np.reshape(y_pred_batch, (batch_size, n_tasks, n_classes))
      n_samples = len(X_batch)
      y_pred_batch = self.predict_proba_on_batch(X_batch, pad_batch=pad_batches)
      y_pred_batch = y_pred_batch[:n_samples]
      y_pred_batch = np.reshape(y_pred_batch, (n_samples, n_tasks, n_classes))
      y_pred_batch = undo_transforms(y_pred_batch, transformers)
      y_preds.append(y_pred_batch)
    y_pred = np.vstack(y_preds)
+41 −4
Original line number Diff line number Diff line
@@ -55,8 +55,24 @@ class KerasModel(Model):
    model.load_weights(h5_filename)
    self.model_instance = model

  def predict_on_batch(self, X):
    return self.model_instance.predict_on_batch(X)
  def predict_on_batch(self, X, pad_batch=False):
    """
    Makes predictions on given batch of new data.

    Parameters
    ----------
    X: np.ndarray
      Features
    pad_batch: bool, optional
      Used for Tensorflow models with rigid batch-size requirements.
    """
    n_samples = len(X) 
    n_tasks = self.get_num_tasks()
    if pad_batch:
      X = pad_features(self.batch_size, X)
    y_pred = self.model_instance.predict_on_batch(X)
    y_pred = np.reshape(y_pred, (n_samples, n_tasks))
    return y_pred

  # TODO(rbharath): The methods below aren't extensible and depend on
  # implementation details of fcnet. Better way to expose this information?
@@ -67,5 +83,26 @@ class KerasModel(Model):
  def get_num_tasks(self):
    return self.model_instance.n_tasks
  
  def predict_proba_on_batch(self, X, n_classes=2):
    return self.model_instance.predict_proba_on_batch(X, n_classes)
  def predict_proba_on_batch(self, X, pad_batch=False, n_classes=2):
    """
    Makes predictions of class probabilities on given batch of new data.

    Parameters
    ----------
    X: np.ndarray
      Features
    pad_batch: bool, optional
      Ignored for Sklearn Model. Only used for Tensorflow models
      with rigid batch-size requirements.
    n_classes: int
      Number of classifier classes
    """
    n_samples = len(X) 
    n_tasks = self.get_num_tasks()
    
    if pad_batch:
      X = pad_features(self.batch_size, X)
    y_pred_proba = self.model_instance.predict_proba_on_batch(X,
        n_classes)
    y_pred_proba = np.reshape(y_pred_proba, (n_samples, n_tasks, n_classes))
    return y_pred_proba
+18 −2
Original line number Diff line number Diff line
@@ -33,15 +33,31 @@ class SklearnModel(Model):
      self.model_instance.fit(X, y)
    y_pred_raw = self.model_instance.predict(X)

  def predict_on_batch(self, X):
  def predict_on_batch(self, X, pad_batch=False):
    """
    Makes predictions on batch of data.

    Parameters
    ----------
    X: np.ndarray
      Features
    pad_batch: bool, optional
      Ignored for Sklearn Model. Only used for Tensorflow models
      with rigid batch-size requirements.
    """
    return self.model_instance.predict(X)

  def predict_proba_on_batch(self, X):
  def predict_proba_on_batch(self, X, pad_batch=False):
    """
    Makes per-class predictions on batch of data.

    Parameters
    ----------
    X: np.ndarray
      Features
    pad_batch: bool, optional
      Ignored for Sklearn Model. Only used for Tensorflow models
      with rigid batch-size requirements.
    """
    return self.model_instance.predict_proba(X)

+17 −13
Original line number Diff line number Diff line
@@ -277,7 +277,7 @@ class TensorflowGraphModel(object):
          self.verbosity)
    ############################################################## TIMING

  def predict_on_batch(self, X):
  def predict_on_batch(self, X, pad_batch=False):
    """Return model output for the provided input.

    Restore(checkpoint) must have previously been called on this object.
@@ -297,6 +297,8 @@ class TensorflowGraphModel(object):
      AssertionError: If model is not in evaluation mode.
      ValueError: If output and labels are not both 3D or both 2D.
    """
    if pad_batch:
      X = pad_features(self.batch_size, X)
    
    if not self._restored_model:
      self.restore()
@@ -514,7 +516,7 @@ class TensorflowClassifier(TensorflowGraphModel):
                             name='labels_%d' % task)))
      return labels

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

    Restore(checkpoint) must have previously been called on this object.
@@ -532,13 +534,13 @@ class TensorflowClassifier(TensorflowGraphModel):
      AssertionError: If model is not in evaluation mode.
      ValueError: If output and labels are not both 3D or both 2D.
    """
    if pad_batch:
      X = pad_features(self.batch_size, X)
    if not self._restored_model:
      self.restore()
    with self.eval_graph.graph.as_default():

      # run eval data through the model
      n_tasks = self.n_tasks
      outputs = []
      with self._get_shared_session(train=False).as_default():
        feed_dict = self.construct_feed_dict(X)
        data = self._get_shared_session(train=False).run(
@@ -553,10 +555,9 @@ class TensorflowClassifier(TensorflowGraphModel):
          raise ValueError(
              'Unrecognized rank combination for output: %s ' %
              (batch_outputs.shape,))
        outputs.append(batch_outputs)

        # We apply softmax to predictions to get class probabilities.
        outputs = softmax(np.squeeze(np.hstack(outputs)))
      # Note that softmax is already applied in construct_grpah
      outputs = batch_outputs

    return np.copy(outputs)

@@ -707,13 +708,16 @@ class TensorflowModel(Model):
    """
    return Model.predict(self, dataset, transformers, self.model_instance.batch_size, True)

  def predict_on_batch(self, X):
  def predict_on_batch(self, X, pad_batch=True):
    """
    Makes predictions on batch of data.
    """
    if pad_batch:
      len_unpadded = len(X)
      Xpad = pad_features(self.model_instance.batch_size, X)
      return self.model_instance.predict_on_batch(Xpad)[:len_unpadded]
    else:
      return self.model_instance.predict_on_batch(X)

  def predict_grad_on_batch(self, X):
    """
@@ -721,11 +725,11 @@ class TensorflowModel(Model):
    """
    return self.model_instance.predict_grad_on_batch(X)

  def predict_proba_on_batch(self, X):
  def predict_proba_on_batch(self, X, pad_batch=False):
    """
    Makes predictions on batch of data.
    """
    return self.model_instance.predict_proba_on_batch(X)
    return self.model_instance.predict_proba_on_batch(X, pad_batch=pad_batch)

  def save(self):
    """
Loading