Commit ecd8f360 authored by miaecle's avatar miaecle
Browse files

merge master

parents 0b78522e e5475d1c
Loading
Loading
Loading
Loading
+71 −26
Original line number Diff line number Diff line
@@ -7,11 +7,14 @@ from deepchem.metrics import to_one_hot, from_one_hot
from deepchem.models.tensorgraph.graph_layers import WeaveLayer, WeaveGather, \
    Combine_AP, Separate_AP, DTNNEmbedding, DTNNStep, DTNNGather, DAGLayer, DAGGather, DTNNExtract
from deepchem.models.tensorgraph.layers import Dense, Concat, SoftMax, SoftMaxCrossEntropy, GraphConv, BatchNorm, \
    GraphPool, GraphGather, WeightedError, BatchNormalization, Stack
    GraphPool, GraphGather, WeightedError, Dropout, BatchNormalization, Stack
from deepchem.models.tensorgraph.layers import L2Loss, Label, Weights, Feature
from deepchem.models.tensorgraph.tensor_graph import TensorGraph
from deepchem.trans import undo_transforms
from deepchem.utils.evaluate import GeneratorEvaluator
from deepchem.data import NumpyDataset
from deepchem.data.data_loader import featurize_smiles_np
from deepchem.feat.graph_features import ConvMolFeaturizer


class WeaveTensorGraph(TensorGraph):
@@ -481,6 +484,7 @@ class GraphConvTensorGraph(TensorGraph):

    """
    self.n_tasks = n_tasks
    self.error_bars = True if 'error_bars' in kwargs and kwargs['error_bars'] else False
    kwargs['use_queue'] = False
    super(GraphConvTensorGraph, self).__init__(**kwargs)
    self.build_graph()
@@ -512,20 +516,23 @@ class GraphConvTensorGraph(TensorGraph):
    batch_norm2 = BatchNorm(in_layers=[gc2])
    gp2 = GraphPool(in_layers=[batch_norm2, self.degree_slice, self.membership]
                    + self.deg_adjs)
    dense = Dense(out_channels=128, activation_fn=None, in_layers=[gp2])
    dense = Dense(out_channels=128, activation_fn=tf.nn.relu, in_layers=[gp2])
    batch_norm3 = BatchNorm(in_layers=[dense])
    gg1 = GraphGather(
    readout = GraphGather(
        batch_size=self.batch_size,
        activation_fn=tf.nn.tanh,
        in_layers=[batch_norm3, self.degree_slice, self.membership] +
        self.deg_adjs)

    if self.error_bars == True:
      readout = Dropout(in_layers=[readout], dropout_prob=0.2)

    costs = []
    self.my_labels = []
    for task in range(self.n_tasks):
      if self.mode == 'classification':
        classification = Dense(
            out_channels=2, activation_fn=None, in_layers=[gg1])
            out_channels=2, activation_fn=None, in_layers=[readout])

        softmax = SoftMax(in_layers=[classification])
        self.add_output(softmax)
@@ -535,7 +542,8 @@ class GraphConvTensorGraph(TensorGraph):
        cost = SoftMaxCrossEntropy(in_layers=[label, classification])
        costs.append(cost)
      if self.mode == 'regression':
        regression = Dense(out_channels=1, activation_fn=None, in_layers=[gg1])
        regression = Dense(
            out_channels=1, activation_fn=None, in_layers=[readout])
        self.add_output(regression)

        label = Label(shape=(None, 1))
@@ -590,6 +598,7 @@ class GraphConvTensorGraph(TensorGraph):
              self.layers[k.name].out_tensor: v
              for k, v in six.iteritems(feed_dict)
          }
          feed_dict[self._training_placeholder] = 1.0  ##
          result = np.array(sess.run(out_tensors, feed_dict=feed_dict))
          if len(result.shape) == 3:
            result = np.transpose(result, axes=[1, 0, 2])
@@ -607,28 +616,64 @@ class GraphConvTensorGraph(TensorGraph):
        labels=self.my_labels,
        weights=[self.my_task_weights])

  def predict_on_smiles(self, smiles, transformers):
    max_index = len(smiles)
    num_batches = max_index // self.batch_size
  def bayesian_predict(self,
                       dataset,
                       transformers=[],
                       n_passes=4,
                       untransform=False):
    """Generates predictions and confidences on a dataset object
     https://arxiv.org/pdf/1506.02142.pdf

    # Returns:
      mu: numpy ndarray of shape (n_samples, n_tasks)
      sigma: numpy ndarray of shape (n_samples, n_tasks)
    """
    X = dataset.X
    max_index = X.shape[0] - 1
    num_batches = (max_index // self.batch_size) + 1

    y_ = []
    mus = []
    sigmas = []
    for i in range(num_batches):
      smiles_batch = smiles[i * self.batch_size:(i + 1) * self.batch_size]
      y_.append(self.predict_on_smiles_batch(smiles_batch, transformers))
    smiles_batch = smiles[num_batches * self.batch_size:max_index]
    y_.append(self.predict_on_smiles_batch(smiles_batch, transformers))

    return np.concatenate(y_, axis=1)

  def predict_on_smiles_batch(self, smiles, transformers=[]):
    featurizer = ConvMolFeaturizer()
    convmols = featurize_smiles_np(smiles, featurizer)

    n_smiles = convmols.shape[0]
      start = i * self.batch_size
      end = min((i + 1) * self.batch_size, max_index + 1)
      batch = X[start:end]
      mu, sigma = self.bayesian_predict_on_batch(
          batch, transformers=[], n_passes=n_passes)
      mus.append(mu)
      sigmas.append(sigma)
    mu = np.concatenate(mus, axis=0)
    sigma = np.concatenate(sigmas, axis=0) + 0.55

    if untransform:
      mu = undo_transforms(mu, transformers)
      for i in range(sigma.shape[1]):
        sigma[:, i] = sigma[:, i] * transformers[0].y_stds[i]

    return mu[:max_index + 1], sigma[:max_index + 1]

  def predict_on_smiles(self, smiles, transformers=[], untransform=False):
    """Generates predictions on a numpy array of smile strings

    # Returns:
      y_: numpy ndarray of shape (n_samples, n_tasks)
    """
    max_index = len(smiles) - 1
    n_tasks = len(self.outputs)
    num_batches = (max_index // self.batch_size) + 1
    featurizer = ConvMolFeaturizer()

    dataset = NumpyDataset(X=convmols, y=None, n_tasks=n_tasks)
    generator = self.default_generator(dataset, predict=True, pad_batches=False)
    y_ = self.predict_on_generator(generator, transformers)

    return y_.reshape(-1, n_tasks)[:n_smiles]
    y_ = []
    for i in range(num_batches):
      start = i * self.batch_size
      end = min((i + 1) * self.batch_size, max_index + 1)
      smiles_batch = smiles[start:end]
      y_.append(
          self.predict_on_smiles_batch(smiles_batch, featurizer, transformers))
    y_ = np.concatenate(y_, axis=0)[:max_index + 1]
    y_ = y_.reshape(-1, n_tasks)

    if untransform:
      y_ = undo_transforms(y_, transformers)

    return y_
+46 −1
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@ from deepchem.models.models import Model
from deepchem.models.tensorgraph.layers import InputFifoQueue, Label, Feature, Weights
from deepchem.trans import undo_transforms
from deepchem.utils.evaluate import GeneratorEvaluator
from deepchem.feat.graph_features import ConvMolFeaturizer
from deepchem.data.data_loader import featurize_smiles_np


class TensorGraph(Model):
@@ -282,6 +284,40 @@ class TensorGraph(Model):
          results.append(result)
        return np.concatenate(results, axis=0)

  def bayesian_predict_on_batch(self, X, transformers=[], n_passes=4):
    """
    Returns:
      mu: numpy ndarray of shape (n_samples, n_tasks)
      sigma: numpy ndarray of shape (n_samples, n_tasks)
    """
    dataset = NumpyDataset(X=X, y=None, n_tasks=len(self.outputs))
    y_ = []
    for i in range(n_passes):
      generator = self.default_generator(
          dataset, predict=True, pad_batches=True)
      y_.append(self.predict_on_generator(generator, transformers))

    y_ = np.concatenate(y_, axis=2)
    mu = np.mean(y_, axis=2)
    sigma = np.std(y_, axis=2)

    return mu, sigma

  def predict_on_smiles_batch(self,
                              smiles,
                              featurizer,
                              n_tasks,
                              transformers=[]):
    """
    # Returns:
      A numpy ndarray of shape (n_samples, n_tasks)
    """
    convmols = featurize_smiles_np(smiles, featurizer)

    dataset = NumpyDataset(X=convmols, y=None, n_tasks=len(self.outputs))
    generator = self.default_generator(dataset, predict=True, pad_batches=True)
    return self.predict_on_generator(generator, transformers)

  def predict_on_batch(self, X, sess=None, transformers=[]):
    """Generates output predictions for the input samples,
      processing the samples in a batched way.
@@ -439,6 +475,8 @@ class TensorGraph(Model):
      for node in self.topsort():
        node_layer = self.layers[node]
        out_tensors.append(node_layer.none_tensors())
      optimizer = self.optimizer
      self.optimizer = None
      training_placeholder = self._training_placeholder
      self._training_placeholder = None
      self.built = False
@@ -458,6 +496,7 @@ class TensorGraph(Model):
        node_layer = self.layers[node]
        node_layer.set_tensors(out_tensors[index])
      self._training_placeholder = training_placeholder
      self.optimizer = optimizer
      self.built = True
    self.tensor_objects = tensor_objects
    self.rnn_initial_states = rnn_initial_states
@@ -502,6 +541,9 @@ class TensorGraph(Model):
      return tf.get_collection(
          tf.GraphKeys.GLOBAL_VARIABLES, scope=layer.variable_scope)

  def get_global_step(self):
    return self._get_tf("GlobalStep")

  def _get_tf(self, obj):
    """
    TODO(LESWING) REALLY NEED TO DOCUMENT THIS
@@ -525,10 +567,13 @@ class TensorGraph(Model):
      self.tensor_objects['Optimizer'] = self.optimizer()
    elif obj == 'train_op':
      self.tensor_objects['train_op'] = self._get_tf('Optimizer').minimize(
          self.loss.out_tensor)
          self.loss.out_tensor, global_step=self._get_tf('GlobalStep'))
    elif obj == 'summary_op':
      self.tensor_objects['summary_op'] = tf.summary.merge_all(
          key=tf.GraphKeys.SUMMARIES)
    elif obj == 'GlobalStep':
      with self._get_tf("Graph").as_default():
        self.tensor_objects['GlobalStep'] = tf.Variable(0, trainable=False)
    return self._get_tf(obj)

  def _initialize_weights(self, sess, saver):
+35 −1
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import numpy as np
import os
from nose.tools import assert_true
from flaky import flaky
import tensorflow as tf

import deepchem as dc
from deepchem.data import NumpyDataset
@@ -11,7 +12,7 @@ from deepchem.data.datasets import Databag
from deepchem.models.tensorgraph.layers import Dense, SoftMaxCrossEntropy, ReduceMean, SoftMax
from deepchem.models.tensorgraph.layers import Feature, Label
from deepchem.models.tensorgraph.layers import ReduceSquareDifference
from deepchem.models.tensorgraph.tensor_graph import TensorGraph
from deepchem.models.tensorgraph.tensor_graph import TensorGraph, TFWrapper


class TestTensorGraph(unittest.TestCase):
@@ -161,6 +162,39 @@ class TestTensorGraph(unittest.TestCase):
    prediction = np.squeeze(tg.predict_proba_on_batch(X))
    assert_true(np.all(np.isclose(prediction, y, atol=0.4)))

  @flaky
  def test_set_optimizer(self):
    n_data_points = 20
    n_features = 2
    X = np.random.rand(n_data_points, n_features)
    y = [[0, 1] for x in range(n_data_points)]
    dataset = NumpyDataset(X, y)
    features = Feature(shape=(None, n_features))
    dense = Dense(out_channels=2, in_layers=[features])
    output = SoftMax(in_layers=[dense])
    label = Label(shape=(None, 2))
    smce = SoftMaxCrossEntropy(in_layers=[label, dense])
    loss = ReduceMean(in_layers=[smce])
    tg = dc.models.TensorGraph(learning_rate=0.01, use_queue=False)
    tg.add_output(output)
    tg.set_loss(loss)
    global_step = tg.get_global_step()

    def optimizer_function():
      starter_learning_rate = 0.1
      learning_rate = tf.train.exponential_decay(
          starter_learning_rate, global_step, 100000, 0.96, staircase=True)
      return tf.train.GradientDescentOptimizer(learning_rate)

    tg.set_optimizer(TFWrapper(optimizer_function))
    tg.fit(dataset, nb_epoch=1000)
    prediction = np.squeeze(tg.predict_proba_on_batch(X))
    tg.save()

    tg1 = TensorGraph.load_from_dir(tg.model_dir)
    prediction2 = np.squeeze(tg1.predict_proba_on_batch(X))
    assert_true(np.all(np.isclose(prediction, prediction2, atol=0.01)))

  def test_tensorboard(self):
    n_data_points = 20
    n_features = 2
+14 −14
Original line number Diff line number Diff line
@@ -6,12 +6,12 @@ from deepchem.rl.a3c import A3C
class Environment(object):
  """An environment in which an actor performs actions to accomplish a task.

  An environment has a current state, which is represented as a list of NumPy
  arrays.  When an action is taken, that causes the state to be updated.  Exactly
  what is meant by an "action" is defined by each subclass.  As far as this interface
  is concerned, it is simply an arbitrary object.  The environment also computes
  a reward for each action, and reports when the task has been terminated
  (meaning that no more actions may be taken).
  An environment has a current state, which is represented as either a single NumPy
  array, or optionally a list of NumPy arrays.  When an action is taken, that causes
  the state to be updated.  Exactly what is meant by an "action" is defined by each
  subclass.  As far as this interface is concerned, it is simply an arbitrary object.
  The environment also computes a reward for each action, and reports when the task
  has been terminated (meaning that no more actions may be taken).

  Environment objects should be written to support pickle and deepcopy operations.
  Many algorithms involve creating multiple copies of the Environment, possibly
@@ -27,7 +27,7 @@ class Environment(object):

  @property
  def state(self):
    """The current state of the environment, represented as a list of NumPy arrays.
    """The current state of the environment, represented as either a NumPy array or list of arrays.

    If reset() has not yet been called at least once, this is undefined.
    """
@@ -45,7 +45,9 @@ class Environment(object):
  def state_shape(self):
    """The shape of the arrays that describe a state.

    This returns a list of tuples, where each tuple is the shape of one array.
    If the state is a single array, this returns a tuple giving the shape of that array.
    If the state is a list of arrays, this returns a list of tuples where each tuple is
    the shape of one array.
    """
    return self._state_shape

@@ -74,7 +76,7 @@ class Environment(object):

    Returns
    -------
    the reward earned by taking the action, represented as a float point number
    the reward earned by taking the action, represented as a floating point number
    (higher values are better)
    """
    raise NotImplemented("Subclasses must implement this")
@@ -88,17 +90,15 @@ class GymEnvironment(Environment):
    import gym
    self.env = gym.make(name)
    self.name = name
    super(GymEnvironment, self).__init__([self.env.observation_space.shape],
    super(GymEnvironment, self).__init__(self.env.observation_space.shape,
                                         self.env.action_space.n)

  def reset(self):
    state = self.env.reset()
    self._state = [state]
    self._state = self.env.reset()
    self._terminated = False

  def step(self, action):
    state, reward, self._terminated, info = self.env.step(action)
    self._state = [state]
    self._state, reward, self._terminated, info = self.env.step(action)
    return reward

  def __deepcopy__(self, memo):
+29 −11
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ from deepchem.models.tensorgraph import TFWrapper
from deepchem.models.tensorgraph.layers import Feature, Weights, Label, Layer
import numpy as np
import tensorflow as tf
import collections
import copy
import multiprocessing
import os
@@ -119,6 +120,7 @@ class A3C(object):
    self.value_weight = value_weight
    self.entropy_weight = entropy_weight
    self.use_hindsight = use_hindsight
    self._state_is_list = isinstance(env.state_shape[0], collections.Sequence)
    if optimizer is None:
      self._optimizer = TFWrapper(
          tf.train.AdamOptimizer, learning_rate=0.001, beta1=0.9, beta2=0.999)
@@ -133,7 +135,10 @@ class A3C(object):

  def _build_graph(self, tf_graph, scope, model_dir):
    """Construct a TensorGraph containing the policy and loss calculations."""
    features = [Feature(shape=[None] + list(s)) for s in self._env.state_shape]
    state_shape = self._env.state_shape
    if not self._state_is_list:
      state_shape = [state_shape]
    features = [Feature(shape=[None] + list(s)) for s in state_shape]
    policy_layers = self._policy.create_layers(features)
    action_prob = policy_layers['action_prob']
    value = policy_layers['value']
@@ -235,6 +240,8 @@ class A3C(object):
    -------
    the array of action probabilities, and the estimated value function
    """
    if not self._state_is_list:
      state = [state]
    with self._graph._get_tf("Graph").as_default():
      feed_dict = self._create_feed_dict(state, use_saved_states)
      tensors = [self._action_prob.out_tensor, self._value.out_tensor]
@@ -277,6 +284,8 @@ class A3C(object):
    -------
    the index of the selected action
    """
    if not self._state_is_list:
      state = [state]
    with self._graph._get_tf("Graph").as_default():
      feed_dict = self._create_feed_dict(state, use_saved_states)
      tensors = [self._action_prob.out_tensor]
@@ -424,10 +433,13 @@ class _Worker(object):

    # Rearrange the states into the proper set of arrays.

    if self.a3c._state_is_list:
      state_arrays = [[] for i in range(len(self.features))]
      for state in states:
        for j in range(len(state)):
          state_arrays[j].append(state[j])
    else:
      state_arrays = [states]

    # Build the feed dict and apply gradients.

@@ -446,23 +458,29 @@ class _Worker(object):
    """Create a new rollout by applying hindsight to an existing one, then train the network."""
    hindsight_states, rewards = self.env.apply_hindsight(
        states, actions, states[-1])
    rnn_states = initial_rnn_states
    values = []
    session = self.a3c._session
    if self.a3c._state_is_list:
      state_arrays = [[] for i in range(len(self.features))]
      for state in hindsight_states:
      feed_dict = self.create_feed_dict(state)
      results = session.run(
          [self.value.out_tensor] + self.graph.rnn_final_states,
          feed_dict=feed_dict)
      values.append(float(results[0]))
      rnn_states = results[1:]
    values.append(0.0)
        for j in range(len(state)):
          state_arrays[j].append(state[j])
    else:
      state_arrays = [hindsight_states]
    feed_dict = {}
    for placeholder, value in zip(self.graph.rnn_initial_states,
                                  initial_rnn_states):
      feed_dict[placeholder] = value
    for f, s in zip(self.features, state_arrays):
      feed_dict[f.out_tensor] = s
    values = self.a3c._session.run(self.value.out_tensor, feed_dict=feed_dict)
    values = np.append(values.flatten(), 0.0)
    self.process_rollout(hindsight_states, actions,
                         np.array(rewards), np.array(values),
                         initial_rnn_states)

  def create_feed_dict(self, state):
    """Create a feed dict for use during a rollout."""
    if not self.a3c._state_is_list:
      state = [state]
    feed_dict = dict((f.out_tensor, np.expand_dims(s, axis=0))
                     for f, s in zip(self.features, state))
    for (placeholder, value) in zip(self.graph.rnn_initial_states,
Loading