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

Expose all netstate options (for all-in-one nets) #3863

Merged
merged 3 commits into from
Jul 11, 2016

Conversation

lukeyeager
Copy link
Contributor

@lukeyeager lukeyeager commented Mar 21, 2016

Was #3736

There are 3 configurable dimensions to a network's NetState: phase (TRAIN or TEST), level and stage. Currently, only phase is exposed through common interfaces. This PR exposes level and stage to the user, further enabling all-in-one nets (#1245)

New CLI:

build/tools/caffe time -model network.prototxt -level 1 -stage deploy

New pycaffe interface:

net = caffe.Net('network.prototxt', weights='weights.caffemodel',
  phase=caffe.TEST, level=1, stages=['deploy'])

EDIT: PR has been updated not to break old code

This is a breaking change (see #1790 (comment) for an explanation). Users will need to transform pycaffe code like:

# old
net = caffe.Net('network.prototxt', 'weights.caffemodel', caffe.TEST)

to:

# new
net = caffe.Net('network.prototxt', weights='weights.caffemodel', phase=caffe.TEST)
# or
net = caffe.Net('network.prototxt', caffe.TEST, weights='weights.caffemodel')

With some effort, this could probably be done without breaking the interface (but I'd need some help with the Boost.Python code). However, I am actually in favor of breaking the interface in order to make it simpler and more "Pythonic".

@seanbell
Copy link

While I agree that the new interface is more Pythonic, I personally think that the old interface can be maintained with a little bit of massaging. All that needs to be edited is the Net.__init__ function, which can be done in the same style as the rest of the _Net_X functions.

Modify the end of pycaffe.py by adding:

# Original Boost.Python Net.__init__ function
_Net_init_boost = Net.__init__


def _Net_init(self, *args, **kwargs):
    """ Construct a caffe.Net """
    # Transform the arguments to handle the legacy API
    if len(args) == 2 and not kwargs:
        # Handle case: Net(param_file, phase)
        _Net_init_boost(self, args[0], weights_file=None, phase=args[1])
    elif len(args) == 3 and not kwargs:
        # Handle case: Net(param_file, weights_file, phase)
        _Net_init_boost(self, args[0], weights_file=args[1], phase=args[2])
    else:
        # Handle new API:
        # Net('net.prototxt', weights_file='weights.caffemodel', phase=caffe.TEST, level=1, stages=['deploy'])
        _Net_init_boost(self, *args, **kwargs)


# Attach methods to Net.
Net.__init__ = _Net_init
...

The above code makes make pytest pass, but I haven't tested it thoroughly.

One other note: It seems that if you wanted to use a kwarg for every argument, then in some place it's named param_file and in others it's named network_file. Maybe this should be harmonized to use the same name?

@@ -25,6 +25,7 @@ class Net {
public:
explicit Net(const NetParameter& param, const Net* root_net = NULL);
explicit Net(const string& param_file, Phase phase,
const int level = 0, const vector<string>* stages = NULL,
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you also insert the new arguments (level, stages) after root_net? Otherwise, this breaks calling code that instantiates Net with root_net non-null:

Net(param_file, phase, root_net);

I'm not sure how common this is, but it's pretty trivial to avoid it by just inserting the new optional arguments at the end of the declaration?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, that seems like the safer choice. I wonder why no tests failed? Seems like a test hole.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does anyone use the root_net parameter? I'd like to keep the phase, level and stages parameters next to each other since they're naturally grouped. If anything, I'd prefer to move root_net before phase, but that would definitely break existing code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As per Evan's comments below, I reverted back to the original behavior of moving root_net to the end.

@lukeyeager
Copy link
Contributor Author

lukeyeager commented Apr 18, 2016

One other note: It seems that if you wanted to use a kwarg for every argument, then in some place it's named param_file and in others it's named network_file. Maybe this should be harmonized to use the same name?

I agree, the naming change is annoying. network_file and weights_file seem more meaningful to me than param_file and pretrained_param_file. They do a better job of conveying the fact that the first file is a textual representation of the network, while the second file is a binary file containing numerical weights.

I thought it might be appropriate to rename them here since this is the transition from internal code to external interface. Other common interfaces use words like solver.net=... and caffe -weights=....

EDIT - Oh, I see what you were pointing out. I was being internally inconsistent with my own code. Whoops!

@lukeyeager lukeyeager force-pushed the bvlc/expose-all-netstate-options branch 2 times, most recently from a8d1c46 to 7a162bf Compare April 18, 2016 23:48
@lukeyeager
Copy link
Contributor Author

While I agree that the new interface is more Pythonic, I personally think that the old interface can be maintained with a little bit of massaging. All that needs to be edited is the Net.__init__ function, which can be done in the same style as the rest of the _Net_X functions.

@seanbell I think I've found a nice compromise between our solutions. I've left the old Net_Init_Load() function in place, and I'm using Boost.Python's pattern matching to distinguish between Net(string, string, int) and Net(string, int, int).

Now all of these constructors work as expected:

### Legacy style
net = caffe.Net('network.prototxt', caffe.TRAIN)
net = caffe.Net('network.prototxt', 'weights.caffemodel', caffe.TEST)
  # pattern matches to Net(network_file, weights_file, phase)
  # prints deprecation warning

### New style
net = caffe.Net('network.prototxt', phase=caffe.TRAIN)
net = caffe.Net('network.prototxt', weights_file='weights.caffemodel', phase=caffe.TEST)
net = caffe.Net('network.prototxt', phase=caffe.TEST, weights_file='weights.caffemodel')
net = caffe.Net('network.prototxt', caffe.TRAIN, 0)
  # pattern matches to Net(network_file, phase, level)
net = caffe.Net('network.prototxt', caffe.TEST, 0, [], 'weights.caffemodel')

Made changes and rebased to address merge conflict from #3982.

@lukeyeager lukeyeager force-pushed the bvlc/expose-all-netstate-options branch from 7a162bf to 0daee4a Compare April 19, 2016 00:09
@lukeyeager
Copy link
Contributor Author

Is there anything in particular holding back this PR?

Does the re-arranging of the root_net parameter break any of the @BVLC team's crazy [cool] workflows?

Is my Python constructor compromise not satisfactory?

@lukeyeager lukeyeager force-pushed the bvlc/expose-all-netstate-options branch from 0daee4a to 8397212 Compare May 13, 2016 22:08
@lukeyeager
Copy link
Contributor Author

  • Updated Net constructor to not switch order of arguments - good idea @ajtulloch
  • Added -phase flag to tools/caffe so that you can time the TEST phase
  • Rebased to master

@ajtulloch
Copy link
Contributor

LGTM. Cool stuff @lukeyeager!

@shelhamer
Copy link
Member

Will review after NIPS deadline 05/20. Thanks for this @lukeyeager and thanks for review @ajtulloch!

bp::default_call_policies(), (bp::arg("network_file"), "phase",
bp::arg("level")=0, bp::arg("stages")=bp::object(),
bp::arg("weights_file")=bp::object())))
// XXX Legacy constructor
Copy link
Member

@shelhamer shelhamer May 25, 2016

Choose a reason for hiding this comment

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

No need for XXX -- the comment is clear as it is.

@lukeyeager lukeyeager force-pushed the bvlc/expose-all-netstate-options branch from 8397212 to dab822c Compare May 25, 2016 22:05
@shelhamer
Copy link
Member

Re: root_net in #3863 (comment) and #3863 (comment), this is a pretty obscure arg that should never really be used outside of the framework itself. Furthermore I hope it can be eventually refactored out through further work on the parallel implementation. With that in mind, I think it is reasonable to keep it as the last, optional arg as to not complicate the normal instantiation of Nets. Thoughts?

@shelhamer
Copy link
Member

shelhamer commented May 25, 2016

Although I originally voted for net states and these varied ways of expressing them, I'm now of two minds. On one hand phase, level, and stage states make all-in-one definitions possible and potentially make variations easier to express, but on the other these are just more special cases in the definition of nets. That said, they do seem to address a need in practice and since they are in the library they should at least be properly exposed to its interfaces. Thoughts @jeffdonahue @longjon?

While I now use and suggest net spec, net states have their purposes so thanks for extending them throughout the interfaces @lukeyeager.

For merge:

  • consider arg name weights_file vs. weights
  • extend caffe train to accept level, stage or decide not to and warn/die if they are given
  • migrate net state tests to C++ side of testing, or at least add a basic test there to not rely on Python
  • switch order of args with root_net?

Let me know if there are other concerns.

@lukeyeager
Copy link
Contributor Author

I've addressed (1) and (2).

(3) Gulp. Time to dive into gtest ...

(4) Don't care

@lukeyeager
Copy link
Contributor Author

make sure to update solver.cpp accordingly:

None of those invocations need updating - they use a different constructor which expects a NetParameter object instead of a filename.

@lukeyeager
Copy link
Contributor Author

I'd rather switch the order of root_net

Done

It would be best to have a C++ test that checks that the layers for do in fact exist

Done

@shelhamer
Copy link
Member

#3863 (comment) Right, sorry about that.

With #3863 (comment) this looks good to me. @longjon will double-check for merge.

This internal functionality will be exposed through the various
interfaces in subsequent commits
Also adds C++ tests for all-in-one nets
Adds command-line flags for phase, level and stage

train -- override level and stages for test_state from solver
test -- set level and stages
time -- set phase, level and stages
Uses Boost.Python's pattern matching to differentiate between
constructors
Also adds Python tests for all-in-one nets
@lukeyeager lukeyeager force-pushed the bvlc/expose-all-netstate-options branch from 56c316e to 19adc7a Compare June 3, 2016 22:36
@lukeyeager
Copy link
Contributor Author

Rebased after conflict from #4227

@lukeyeager
Copy link
Contributor Author

this looks good to me. @longjon will double-check for merge.

ping @longjon

@shelhamer
Copy link
Member

Merging after offline discussion. Thanks @lukeyeager!

p.s. @jeffdonahue noted that this not strictly necessary since the NetState of the NetParameter can be set before instantiating a Net. However, this PR contributes a one-step interface to instantiating any state and enables exposing the different states to languages lacking protobuf bindings (such as matlab, as far as I know).

@shelhamer shelhamer merged commit 3e94c0e into BVLC:master Jul 11, 2016
@lukeyeager
Copy link
Contributor Author

this not strictly necessary since the NetState of the NetParameter can be set before instantiating a Net.

Sure, but it's nice to be able to change it without editing .prototxt.

Merging after offline discussion.

Thanks!

@lukeyeager lukeyeager deleted the bvlc/expose-all-netstate-options branch July 11, 2016 16:45
fxbit pushed a commit to Yodigram/caffe that referenced this pull request Sep 1, 2016
…-options

Expose all netstate options (for all-in-one nets)
timofey-retailnext pushed a commit to retailnext/caffe that referenced this pull request Jun 5, 2018
…ukeyeager/bvlc/expose-all-netstate-options"

This reverts commit 3e94c0e, reversing
changes made to f28f5ae.
timofey-retailnext pushed a commit to retailnext/caffe that referenced this pull request Jun 13, 2018
…ukeyeager/bvlc/expose-all-netstate-options"

This reverts commit 3e94c0e, reversing
changes made to f28f5ae.
timofey-retailnext pushed a commit to retailnext/caffe that referenced this pull request Jun 13, 2018
…ukeyeager/bvlc/expose-all-netstate-options"

This reverts commit 3e94c0e, reversing
changes made to f28f5ae.
timofey-retailnext pushed a commit to retailnext/caffe that referenced this pull request Jun 13, 2018
…ukeyeager/bvlc/expose-all-netstate-options"

This reverts commit 3e94c0e, reversing
changes made to f28f5ae.
timofey-retailnext pushed a commit to retailnext/caffe that referenced this pull request Jun 13, 2018
…ukeyeager/bvlc/expose-all-netstate-options"

This reverts commit 3e94c0e, reversing
changes made to f28f5ae.
timofey-retailnext pushed a commit to retailnext/caffe that referenced this pull request Jun 13, 2018
…ukeyeager/bvlc/expose-all-netstate-options"

This reverts commit 3e94c0e, reversing
changes made to f28f5ae.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants