Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sequential API for Model Construction #925

Merged
merged 18 commits into from Dec 21, 2017
Merged

Conversation

rbharath
Copy link
Member

@rbharath rbharath commented Nov 6, 2017

This PR adds a new API for constructing sequential models (those that are a linear stack of models) based on the Keras Sequential API. For simple networks, this new API allows users to skip explicitly specifying Feature, Label, loss inputs, outputs, and in_layers. For example, here's a simple classifier in Sequential:

X = np.random.rand(20, 2)                     
y = [[0, 1] for x in range(20)]
dataset = dc.data.NumpyDataset(X, y)                              
model = dc.models.Sequential(learning_rate=0.01)                  
model.add(Dense(out_channels=2))                                  
model.add(SoftMax())
model.fit(dataset, loss="binary_crossentropy", nb_epoch=1000)     
prediction = np.squeeze(model.predict_on_batch(X)) 

For comparison, here's the same model in the TensorGraph API

X = np.random.rand(20, 2)                     
y = [[0, 1] for x in range(20)]                        
dataset = NumpyDataset(X, y)                                      
features = Feature(shape=(None, 20))                      
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)                    
tg.add_output(output)
tg.set_loss(loss) 
tg.fit(dataset, nb_epoch=1000)                                    
prediction = np.squeeze(tg.predict_on_batch(X))                   

Underneath the hood, Sequential inherits from TensorGraph and simply constructs the explicit TensorGraph as needed. For now, losses are explicitly specified as strings passed into Sequential.fit(). The initial implementation will support the same string arguments as the Keras Sequential API. The PR also removes an old (non-functional) version of Sequential that was not based on TensorGraph.

This PR isn't quite ready to merge (will need to add in losses beyond binary_crossentropy and mse), but I wanted to put it out for feedback on the API design.

@coveralls
Copy link

coveralls commented Nov 6, 2017

Coverage Status

Coverage increased (+0.08%) to 80.499% when pulling 5246f2c on rbharath:sequential into 401d669 on deepchem:master.

@rbharath rbharath changed the title [WIP] Sequential API for Model Construction Sequential API for Model Construction Nov 8, 2017
@coveralls
Copy link

coveralls commented Nov 8, 2017

Coverage Status

Coverage increased (+0.08%) to 80.499% when pulling 7453a90 on rbharath:sequential into 401d669 on deepchem:master.

if not len(layer.in_layers) == 0:
raise ValueError("Cannot specify in_layers for Sequential.")
layer.in_layers += [prev_layer]
self._add_layer(layer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need this? When you set loss this should go through the tree and call already?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, will remove.


if loss == "binary_crossentropy":
smce = SoftMaxCrossEntropy(in_layers=[labels, prev_layer])
self._add_layer(smce)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto for this _add_layer

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will remove.

else:
# TODO(rbharath): Add in support for additional losses.
raise ValueError("Unsupported loss.")
self._built = True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? super().fit() should call build and will also install the queue for faster training/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Will remove.

@peastman
Copy link
Contributor

peastman commented Nov 8, 2017

This class is kind of strange, in that the model isn't fully defined until you call fit(). But what if it never gets called? What if instead the user calls restore() to reload a previously fit model? It won't work.

@rbharath
Copy link
Member Author

rbharath commented Dec 21, 2017

@peastman You raise a good point about restore(). For now, I raise a ValueError if restore() is called. In a future PR, we should figure out a more general mechanism. The issue is that Sequential allows users to avoid specifying placeholders and imputes placeholder shapes from the provided dataset in fit(). This means that the full TensorFlow graph can't be built until fit() is called.

A more general solution would probably be to write placeholder shapes in metadata and add placeholders if necessary in restore(). Will do this in a future PR.

@rbharath rbharath mentioned this pull request Dec 21, 2017
@coveralls
Copy link

Coverage Status

Coverage increased (+0.01%) to 80.749% when pulling c6b7c64 on rbharath:sequential into fbf8b79 on deepchem:master.

@coveralls
Copy link

coveralls commented Dec 21, 2017

Coverage Status

Coverage increased (+0.07%) to 80.806% when pulling 046c8e8 on rbharath:sequential into f6e75cf on deepchem:master.

@rbharath
Copy link
Member Author

Going to go ahead and merge in this PR. Will address any outstanding issues in a follow-on PR.

LGTM

@rbharath rbharath merged commit ae75476 into deepchem:master Dec 21, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants