Commit 7db1a9a0 authored by peastman's avatar peastman
Browse files

Merge branch 'torchmodel' of https://github.com/peastman/deepchem into torchmodel

parents 13d0bf88 0334729e
Loading
Loading
Loading
Loading
+36 −8
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ class L1Loss(Loss):

  def _compute_tf_loss(self, output, labels):
    import tensorflow as tf
    output, labels = _make_shapes_consistent(output, labels)
    output, labels = _make_tf_shapes_consistent(output, labels)
    output, labels = _ensure_float(output, labels)
    return tf.abs(output - labels)

@@ -46,7 +46,7 @@ class L2Loss(Loss):

  def _compute_tf_loss(self, output, labels):
    import tensorflow as tf
    output, labels = _make_shapes_consistent(output, labels)
    output, labels = _make_tf_shapes_consistent(output, labels)
    output, labels = _ensure_float(output, labels)
    return tf.square(output - labels)

@@ -64,13 +64,14 @@ class HingeLoss(Loss):

  def _compute_tf_loss(self, output, labels):
    import tensorflow as tf
    output, labels = _make_shapes_consistent(output, labels)
    output, labels = _make_tf_shapes_consistent(output, labels)
    return tf.keras.losses.hinge(labels, output)

  def _create_pytorch_loss(self):
    import torch

    def loss(output, labels):
      output, labels = _make_pytorch_shapes_consistent(output, labels)
      return torch.mean(torch.clamp(1 - labels * output, min=0), dim=-1)

    return loss
@@ -85,7 +86,7 @@ class BinaryCrossEntropy(Loss):

  def _compute_tf_loss(self, output, labels):
    import tensorflow as tf
    output, labels = _make_shapes_consistent(output, labels)
    output, labels = _make_tf_shapes_consistent(output, labels)
    output, labels = _ensure_float(output, labels)
    return tf.keras.losses.binary_crossentropy(labels, output)

@@ -94,6 +95,7 @@ class BinaryCrossEntropy(Loss):
    bce = torch.nn.BCELoss(reduction='none')

    def loss(output, labels):
      output, labels = _make_pytorch_shapes_consistent(output, labels)
      return torch.mean(bce(output, labels), dim=-1)

    return loss
@@ -109,7 +111,7 @@ class CategoricalCrossEntropy(Loss):

  def _compute_tf_loss(self, output, labels):
    import tensorflow as tf
    output, labels = _make_shapes_consistent(output, labels)
    output, labels = _make_tf_shapes_consistent(output, labels)
    output, labels = _ensure_float(output, labels)
    return tf.keras.losses.categorical_crossentropy(labels, output)

@@ -117,6 +119,7 @@ class CategoricalCrossEntropy(Loss):
    import torch

    def loss(output, labels):
      output, labels = _make_pytorch_shapes_consistent(output, labels)
      return -torch.sum(labels * torch.log(output), dim=-1)

    return loss
@@ -132,7 +135,7 @@ class SigmoidCrossEntropy(Loss):

  def _compute_tf_loss(self, output, labels):
    import tensorflow as tf
    output, labels = _make_shapes_consistent(output, labels)
    output, labels = _make_tf_shapes_consistent(output, labels)
    output, labels = _ensure_float(output, labels)
    return tf.nn.sigmoid_cross_entropy_with_logits(labels, output)

@@ -141,6 +144,7 @@ class SigmoidCrossEntropy(Loss):
    bce = torch.nn.BCEWithLogitsLoss(reduction='none')

    def loss(output, labels):
      output, labels = _make_pytorch_shapes_consistent(output, labels)
      return bce(output, labels)

    return loss
@@ -157,7 +161,7 @@ class SoftmaxCrossEntropy(Loss):

  def _compute_tf_loss(self, output, labels):
    import tensorflow as tf
    output, labels = _make_shapes_consistent(output, labels)
    output, labels = _make_tf_shapes_consistent(output, labels)
    output, labels = _ensure_float(output, labels)
    return tf.nn.softmax_cross_entropy_with_logits(labels, output)

@@ -166,6 +170,7 @@ class SoftmaxCrossEntropy(Loss):
    ls = torch.nn.LogSoftmax(dim=1)

    def loss(output, labels):
      output, labels = _make_pytorch_shapes_consistent(output, labels)
      return -torch.sum(labels * ls(output), dim=-1)

    return loss
@@ -190,7 +195,7 @@ class SparseSoftmaxCrossEntropy(Loss):
    return torch.nn.CrossEntropyLoss(reduction='none')


def _make_shapes_consistent(output, labels):
def _make_tf_shapes_consistent(output, labels):
  """Try to make inputs have the same shape by adding dimensions of size 1."""
  import tensorflow as tf
  shape1 = output.shape
@@ -215,6 +220,29 @@ def _make_shapes_consistent(output, labels):
                   (str(shape1), str(shape2)))


def _make_pytorch_shapes_consistent(output, labels):
  """Try to make inputs have the same shape by adding dimensions of size 1."""
  import torch
  shape1 = output.shape
  shape2 = labels.shape
  len1 = len(shape1)
  len2 = len(shape2)
  if len1 == len2:
    return (output, labels)
  shape1 = tuple(shape1)
  shape2 = tuple(shape2)
  if len1 > len2 and all(i == 1 for i in shape1[len2:]):
    for i in range(len1 - len2):
      labels = torch.unsqueeze(labels, -1)
    return (output, labels)
  if len2 > len1 and all(i == 1 for i in shape2[len1:]):
    for i in range(len2 - len1):
      output = torch.unsqueeze(output, -1)
    return (output, labels)
  raise ValueError("Incompatible shapes for outputs and labels: %s versus %s" %
                   (str(shape1), str(shape2)))


def _ensure_float(output, labels):
  """Make sure the outputs and labels are both floating point types."""
  import tensorflow as tf
+2 −2
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ def test_overfit_subclass_model():
        x = layer(x)
        if i < len(self.layers) - 1:
          x = F.relu(x)
      return F.sigmoid(x), x
      return torch.sigmoid(x), x

  pytorch_model = ExampleModel([10, 1])
  model = dc.models.TorchModel(
@@ -318,7 +318,7 @@ def test_tensorboard():
  y = [[0.0, 1.0] for x in range(n_data_points)]
  dataset = dc.data.NumpyDataset(X, y)
  pytorch_model = torch.nn.Sequential(
      torch.nn.Linear(n_features, 2), torch.nn.Softmax())
      torch.nn.Linear(n_features, 2), torch.nn.Softmax(dim=1))
  model = dc.models.TorchModel(
      pytorch_model,
      dc.models.losses.CategoricalCrossEntropy(),
+22 −8
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ class TorchModel(Model):
               tensorboard: bool = False,
               wandb: bool = False,
               log_frequency: int = 100,
               device: Optional[torch.device] = None,
               **kwargs) -> None:
    """Create a new TorchModel.

@@ -156,6 +157,9 @@ class TorchModel(Model):
      a global step corresponds to one batch of training. If you'd
      like a printout every 10 batch steps, you'd set
      `log_frequency=10` for example.
    device: torch.device
      the device on which to run computations.  If None, a device is
      chosen automatically.
    """
    super(TorchModel, self).__init__(
        model_instance=model, model_dir=model_dir, **kwargs)
@@ -171,6 +175,16 @@ class TorchModel(Model):
      self.optimizer = optimizer
    self.tensorboard = tensorboard

    # Select a device.

    if device is None:
      if torch.cuda.is_available():
        device = torch.device('cuda')
      else:
        device = torch.device('cpu')
    self.device = device
    model.to(device)

    # W&B logging
    if wandb and not is_wandb_available():
      logger.warning(
@@ -522,7 +536,7 @@ class TorchModel(Model):
      output_values = self.model(inputs)
      if isinstance(output_values, torch.Tensor):
        output_values = [output_values]
      output_values = [t.detach().numpy() for t in output_values]
      output_values = [t.detach().cpu().numpy() for t in output_values]

      # Apply tranformers and record results.
      if uncertainty:
@@ -810,7 +824,7 @@ class TorchModel(Model):
      output_shape = tuple(output.shape[1:])
      output = output.reshape([-1])
      result = []
      grad_output = torch.zeros(output.shape[0])
      grad_output = torch.zeros(output.shape[0], device=self.device)
      for i in range(output.shape[0]):
        grad_output.zero_()
        grad_output[i] = 1
@@ -819,7 +833,7 @@ class TorchModel(Model):
        X.grad.zero_()
      final_result.append(
          torch.reshape(torch.stack(result),
                        output_shape + input_shape).numpy())
                        output_shape + input_shape).cpu().numpy())
    if len(final_result) == 1:
      return final_result[0]
    return final_result
@@ -834,13 +848,13 @@ class TorchModel(Model):
      labels = [
          x.astype(np.float32) if x.dtype == np.float64 else x for x in labels
      ]
      labels = [torch.as_tensor(x) for x in labels]
      labels = [torch.as_tensor(x, device=self.device) for x in labels]
    if weights is not None:
      weights = [
          x.astype(np.float32) if x.dtype == np.float64 else x for x in weights
      ]
      weights = [torch.as_tensor(x) for x in weights]
    inputs = [torch.as_tensor(x) for x in inputs]
      weights = [torch.as_tensor(x, device=self.device) for x in weights]
    inputs = [torch.as_tensor(x, device=self.device) for x in inputs]

    return (inputs, labels, weights)

@@ -1024,7 +1038,7 @@ class TorchModel(Model):
    source_vars = list(source_model.model.parameters())

    for source_var in source_vars:
      value_map[source_var] = source_var.detach().numpy()
      value_map[source_var] = source_var.detach().cpu().numpy()

    return value_map

@@ -1094,7 +1108,7 @@ class TorchModel(Model):

    for source_var, dest_var in assignment_map.items():
      assert source_var.shape == dest_var.shape
      dest_var.data = torch.as_tensor(value_map[source_var])
      dest_var.data = torch.as_tensor(value_map[source_var], device=self.device)


class _StandardLoss(object):