Repository: keras-team/keras

Issue:
ValueError: KerasClassifier doesn't support sample_weight.

I want to use AdaBoostClassifier on CNN. I created a function called ‘create_model’ that define my model and compile it. Then I use KerasClassifier:

model = KerasClassifier(build_fn=create_model, epochs=2, batch_size=128, verbose=0, sample_weight=None)
bdt_discrete = AdaBoostClassifier( model, n_estimators=2, learning_rate=1.5,
algorithm=”SAMME”)
bdt_discrete.fit(X_train, y_train, sample_weight=None)
It gives the following error:
ValueError: KerasClassifier doesn’t support sample_weight.
Is there any solutions for the error:
###################################

File “/usr/local/lib/python2.7/dist-packages/spyder/utils/site/sitecustomize.py”, line 688, in runfile
execfile(filename, namespace)

File “/usr/local/lib/python2.7/dist-packages/spyder/utils/site/sitecustomize.py”, line 93, in execfile
builtins.execfile(filename, *where)

File “~adaboost_CNN3.py”, line 251, in
bdt_discrete.fit(X_train, y_train, sample_weight=None)

File “/usr/local/lib/python2.7/dist-packages/sklearn/ensemble/weight_boosting.py”, line 413, in fit
return super(AdaBoostClassifier, self).fit(X, y, sample_weight)

File “/usr/local/lib/python2.7/dist-packages/sklearn/ensemble/weight_boosting.py”, line 130, in fit
self._validate_estimator()

File “/usr/local/lib/python2.7/dist-packages/sklearn/ensemble/weight_boosting.py”, line 431, in _validate_estimator
% self.base_estimator_.__class__.__name__)

ValueError: KerasClassifier doesn’t support sample_weight.
##########################
Please let me know if there are any advice.





Discussion:
Thats because the AdaboostClassifier only support those base_estimators which have a sample_weight in their fit() method.

Now although KerasClassifier supports sample_weight (`from Sequential.fit()`) by using the **kwargs in KerasClassifier.fit(), but scikit-learn uses a [signature detecting function](https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/utils/validation.py#L671) which checks the parameters available only in the KerasClassifier.fit()

This is what it returns:

```
from sklearn.utils.fixes import signature
print(signature(model.fit))
```
**Output: (x, y, **kwargs)**

As you can see that the sample_weight is not present here, so AdaBoostClassifier will throw an error. One possible workaround is to extend the KerasClassifier class and then update the fit() method to add sample_weight there. 

I am not sure what can be done in the source code of KerasClassifier or in AdaboostClassifier for that case to handle this.
> I am not sure what can be done in the source code of KerasClassifier or in AdaboostClassifier for that case to handle this.

You could change the signature of `KerasClassifier.fit()` to include `sample_weight` explicitly. Feel free to open a PR (with tests).

Resolving patch:
diff --git a/keras/wrappers/scikit_learn.py b/keras/wrappers/scikit_learn.py
--- a/keras/wrappers/scikit_learn.py
+++ b/keras/wrappers/scikit_learn.py
@@ -176,7 +176,7 @@ class KerasClassifier(BaseWrapper):
     """Implementation of the scikit-learn classifier API for Keras.
     """
 
-    def fit(self, x, y, **kwargs):
+    def fit(self, x, y, sample_weight=None, **kwargs):
         """Constructs a new model with `build_fn` & fit the model to `(x, y)`.
 
         # Arguments
@@ -204,6 +204,8 @@ def fit(self, x, y, **kwargs):
         else:
             raise ValueError('Invalid shape for y: ' + str(y.shape))
         self.n_classes_ = len(self.classes_)
+        if sample_weight is not None:
+            kwargs['sample_weight'] = sample_weight
         return super(KerasClassifier, self).fit(x, y, **kwargs)
 
     def predict(self, x, **kwargs):


Test patch:
diff --git a/tests/keras/wrappers/scikit_learn_test.py b/tests/keras/wrappers/scikit_learn_test.py
--- a/tests/keras/wrappers/scikit_learn_test.py
+++ b/tests/keras/wrappers/scikit_learn_test.py
@@ -75,7 +75,7 @@ def __call__(self, hidden_dims):
 
 
 def assert_classification_works(clf):
-    clf.fit(X_train, y_train, batch_size=batch_size, epochs=epochs)
+    clf.fit(X_train, y_train, sample_weight=np.ones(X_train.shape[0]), batch_size=batch_size, epochs=epochs)
 
     score = clf.score(X_train, y_train, batch_size=batch_size)
     assert np.isscalar(score) and np.isfinite(score)