-
-
Notifications
You must be signed in to change notification settings - Fork 26k
[MRG] Fixing label clamping for LabelPropagation #6727
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
Conversation
The previous way was breaking the test sklearn.tests.test_common.test_all_estimators
Based on the original paper.
Sorry for not reviewing this so far. I think it's an important fix. The maintainers are pretty busy :( |
No worries, I understand. ;-) |
This needs some love soon. |
Can you elaborate on the directed graph issue? The construction creates a symmetric graph matrix, right? |
@amueller I don't think the default implementation of I corrected by making the connectivity matrix symmetric explicitly: https://github.com/musically-ut/semi_supervised/blob/master/semi_supervised/label_propagation.py#L136 Does this answer your question? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add the test suggested in #5774 (at least)?
@@ -291,7 +292,7 @@ class LabelPropagation(BaseLabelPropagation): | |||
Parameter for knn kernel | |||
|
|||
alpha : float | |||
Clamping factor | |||
DEPRECATED: It's internally fixed to zero and it'll be removed in 0.19 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deprecated in 0.19 and removed in 0.21. You should raise a deprecation warning if it is set.
alpha=.0, max_iter=30, tol=1e-3, n_jobs=1): | ||
# alpha is deprecated for LabelPropagation because it doesn't have any | ||
# theoretical meaning (from the reference paper). | ||
alpha = .0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can just put alpha=0
in the line below, and set alpha above to None
and if alpha is not None
raise a DeprecationWarning
.
@musically-ut yeah, sorry, of course. I was thinking about distance graphs... getting late over here... |
We might want to think about renaming |
@amueller, no worries. Great to see progress on this though! |
@amueller I'm not inclined to change the name of the parameter, it is called |
@musically-ut we should have fixed this a looong long time ago. Do you want to open a separate issue about symmetry? |
@amueller Sure, I can do that. IIRC, I wasn't sure what the option |
We usually try to avoid Greek letter parameters and prefer natural language parameters, though not everywhere (if I'd rewrite the linear models, I'd call alpha "regularization"). I don't have a strong opinion though. The question is whether the parameters is called |
@amueller |
Deprecating parameters is not really tricky, but I'm fine with keeping alpha. I was also thinking about the docs, which currently say "clamping factor" which is bad. |
I'm going to apply the suggestions regarding the deprecation of |
Now that the tests are failing, I remember why I didn't use Suggestions? |
"Deprecated in 0.19 and it's going to be removed in 0.21.", | ||
DeprecationWarning | ||
) | ||
alpha = .0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't put this here. Put it where it's used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll set the alpha
of the line below to .0
.
But what about the alpha
of the constructor above? You said it should be set to None
, but the tests fail because the two constructors have different default values (None
and 0
).
What am I missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shouldn't be changed in the constructor, it should be replaced in fit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the fit
function behave differently for LabelPropagation
and LabelSpreading
? I mean, should they have different implementations of fit
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit unfortunate but it looks like LabelPropagation
needs to get it's own fit
which calls
super(LabelPropagation, self).fit
. But before, it checks whether alpha is set and raises a deprecation warning.
Then in BaseLabelPropagation
you need to introduce a local variable alpha
that has the right value. One way to do this is to check isinstance(self, LabelSpreading)
- which is not great.
The other would be so set self._alpha = 0
in LabelPropagation.fit
and do alpha = getattr(self, "_alpha", self.alpha)
in BaseLabelPropagation.fit
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you have a nicer way, that's also fine ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering the testing restrictions, I can't see a any better solution. I chose to adopt your second suggestion.
This solution isn't great, but it sets the correct value for alpha without violating the restrictions imposed by the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, we would have a test that the DeprecationWarning fires when it is meant to and when not.
Please add a bug fix entry to what's new.
@@ -291,7 +295,7 @@ class LabelPropagation(BaseLabelPropagation): | |||
Parameter for knn kernel | |||
|
|||
alpha : float | |||
Clamping factor | |||
DEPRECATED: Deprecated in 0.19 and it's going to be removed in 0.21. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can use sphinx's .. deprecated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I'll check it out.
# theoretical meaning (from the reference paper). Look at PR 6727. | ||
if self.alpha is not None: | ||
warnings.warn( | ||
"Deprecated in 0.19 and it's going to be removed in 0.21.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
State "Parameter alpha was ... and will be ..."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree.
warnings.warn( | ||
"Deprecated in 0.19 and it's going to be removed in 0.21.", | ||
DeprecationWarning | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be setting _alpha to the user-provided alpha until deprecation is compeleted? Otherwise our deprecation warning should state that alpha is being ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the case of LabelPropagation
, setting a different alpha
value is not something supported by the algorithm's description in the cited references.
def fit(self, X, y): | ||
# alpha is deprecated for LabelPropagation because it doesn't have any | ||
# theoretical meaning (from the reference paper). Look at PR 6727. | ||
if self.alpha is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you need to implement __init__
such that alpha=None
by default and this message only appears when a non-default value is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To follow your suggestion and pass the tests, I would need to change the __init__
of BaseLabelPropagation
, which is probably not what we want since LabelSpreading
can really use different alpha
values.
This problem was discussed with @amueller before, in his code review.
Do you have another suggestion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how. I have no problem putting a new __init__
in LabelPropagation
which passes alpha=None to BaseLabelPropagation.__init__
, while still passing the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see this merged in the coming release!
def fit(self, X, y): | ||
# alpha is deprecated for LabelPropagation because it doesn't have any | ||
# theoretical meaning (from the reference paper). Look at PR 6727. | ||
if self.alpha is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how. I have no problem putting a new __init__
in LabelPropagation
which passes alpha=None to BaseLabelPropagation.__init__
, while still passing the tests.
@@ -381,7 +402,10 @@ class LabelSpreading(BaseLabelPropagation): | |||
parameter for knn kernel | |||
|
|||
alpha : float | |||
clamping factor | |||
Clamping factor [0, 1], it specifies the relative amount of the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit more verbose for clarity: "Clamping factor, in [0, 1], specifies the extent to which a sample's label should derive from its neighbors in preference to its initial label."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By a new __init__
do you mean something like this?
What should be the default value for alpha
in BaseLabelPropagation.__init__
? What about LabelPropagation.__init__
? The tests were failing because I ended up with alpha=1
in BaseLabelPropagation.__init__
and alpha=None
in LabelPropagation.__init__
, i.e., this constructor set a different default value for alpha
than the former.
I've not yet looked at test failures or otherwise, but I'd leave alpha=None
until fit, or even just remove it from base's init if it's not relevant to
all subclasses
…On 29 May 2017 8:53 pm, "Andre Boechat" ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In sklearn/semi_supervised/label_propagation.py
<#6727 (comment)>
:
> @@ -381,7 +402,10 @@ class LabelSpreading(BaseLabelPropagation):
parameter for knn kernel
alpha : float
- clamping factor
+ Clamping factor [0, 1], it specifies the relative amount of the
By a new __init__ do you mean something like this
<f609105>
?
What should be the default value for alpha in
BaseLabelPropagation.__init__? What about LabelPropagation.__init__? The
tests were failing because I ended up with alpha=1 in
BaseLabelPropagation.__init__ and alpha=None in LabelPropagation.__init__,
i.e., this constructor set a different default value for alpha than the
former.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#6727 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAEz6_f4VqVwRMB0AHMXG9HOe0Yxuhq-ks5r-qOogaJpZM4IRT8O>
.
|
The point is that you should still not have to modify anything in init, and leave warning until fit. |
If I don't modify |
i was suggesting you do modify init but don't modify the parameter before
setting the attribute
…On 30 May 2017 2:51 pm, "Andre Boechat" ***@***.***> wrote:
If I don't modify __init__, the warning on LabelPropagation.fit will be
echoed by default. Is this what you meant?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#6727 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAEz6-jkNQC4VcQZUwnP5v6yjGMkog-eks5r-6AygaJpZM4IRT8O>
.
|
Changes to fixing scikit-learn#5774 (label clamping)
It seems you'll need to resolve a merge conflict. I've now patched this to my liking. Could we get at least one other review? @amueller? |
Yes, I noticed. I'm gonna fix it. |
X, y = make_classification(n_samples=100) | ||
y[::3] = -1 | ||
lp_default = label_propagation.LabelPropagation() | ||
lp_default_y = assert_no_warnings(lp_default.fit, X, y).transduction_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is getting a warning (although not the one we're concerned about) and the assertion fails:
======================================================================
FAIL: sklearn.semi_supervised.tests.test_label_propagation.test_alpha_deprecation
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/travis/miniconda/envs/testenv/lib/python3.6/site-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
File "/home/travis/build/scikit-learn/scikit-learn/sklearn/semi_supervised/tests/test_label_propagation.py", line 71, in test_alpha_deprecation
lp_default_y = assert_no_warnings(lp_default.fit, X, y).transduction_
File "/home/travis/build/scikit-learn/scikit-learn/sklearn/utils/testing.py", line 230, in assert_no_warnings
', '.join(str(warning) for warning in w)))
AssertionError: Got warnings when calling fit: [{message : RuntimeWarning('underflow encountered in exp',), category : 'RuntimeWarning', filename : '/home/travis/build/scikit-learn/scikit-learn/sklearn/metrics/pairwise.py', lineno : 837, line : None}]
I've realised that I didn't fix the random_state
in make_classification
. We should do that. But I also haven't investigated why we should be getting exp underflow. Do you know?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not something that comes to mind right now. I'll have look at it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't seem to get that warning on my system, but all Travis runs get it.
Could I suggest you try setting the kernel='knn'
in the test here, and we'll see if that works?
I've made a couple of finishing touches at #9192. |
Closing in favor of #9239. |
Referenced issues
This PR comes to fix #3550 and #5774. It's similar to PR #3758, which seems to be abandoned.
Important note: my development files
hack-dev/*
would be removed before merging this PR.Explanations
From the comments in the PR #3758, this PR improves the documentation of the parameter
alpha
, deprecates it forLabelPropagation
and fix the label clamping (the credit is all to @musically-ut).From [1] and [3], we can see that
LabelPropagation
doesn't have a clamping factor. In the case ofLabelSpreading
, from [2] and [3] we havewhich means that
alpha = 0
keeps the initial label informationŶ(0)
. As suggested by @amueller in #3758, this should be the only possible value forLabelPropagation
.In the current implementation, line 239,
alpha = 0
would not propagate label information to the unlabeled instances, but would propagate label information to the labeled instances. I saw this exact behavior with my data, but I couldn't find yet a simple test case to catch it.Some additional comments
In #5774, @musically-ut discussed a very important point about the current implementation, the graph construction. There is no mention about directed graphs in the referenced papers, but it's what the current implementation does (line 137). Maybe a specific issue should be created for this.
Referenced papers
[1] Zhu, Xiaojin, and Zoubin Ghahramani. Learning from labeled and unlabeled data with label propagation. Technical Report CMU-CALD-02-107, Carnegie Mellon University, 2002.
[2] Zhou, Dengyong, et al. "Learning with local and global consistency." Advances in neural information processing systems 16.16 (2004): 321-328.
[3] Bengio, Yoshua, Olivier Delalleau, and Nicolas Le Roux. "Label propagation and quadratic criterion." Semi-supervised learning (2006): 193-216.