tensorflow estimator custom metrics: use sklearn metrics? - tensorflow

Is there a way to use sklearn metrics as custom metrics in tf.estimator ? I have tried the custom score function below.
from sklearn.metrics import recall_score
def my_score(labels, predictions):
return {'MARecall': recall_score(labels, predictions, average='macro')}
But it does not work :
eval_results = classifier.evaluate(input_fn=tf.estimator.inputs.numpy_input_fn(x={'x': val_x}, y=np.array(val_y), num_epochs=1, batch_size=20, shuffle=False))
... ...
... ...
<ipython-input-81-e433b0457af2> in my_acc(labels, predictions)
1 def my_acc(labels, predictions):
----> 2 return {'WA': np.array(recall_score(labels, predictions, average='micro'))}
3
/anaconda/envs/py35/lib/python3.5/site-packages/sklearn/metrics/classification.py in recall_score(y_true, y_pred, labels, pos_label, average, sample_weight)
1357 average=average,
1358 warn_for=('recall',),
-> 1359 sample_weight=sample_weight)
1360 return r
1361
/anaconda/envs/py35/lib/python3.5/site-packages/sklearn/metrics/classification.py in precision_recall_fscore_support(y_true, y_pred, beta, labels, pos_label, average, warn_for, sample_weight)
1023 raise ValueError("beta should be >0 in the F-beta score")
1024
-> 1025 y_type, y_true, y_pred = _check_targets(y_true, y_pred)
1026 present_labels = unique_labels(y_true, y_pred)
1027
/anaconda/envs/py35/lib/python3.5/site-packages/sklearn/metrics/classification.py in _check_targets(y_true, y_pred)
70 """
71 check_consistent_length(y_true, y_pred)
---> 72 type_true = type_of_target(y_true)
73 type_pred = type_of_target(y_pred)
74
/anaconda/envs/py35/lib/python3.5/site-packages/sklearn/utils/multiclass.py in type_of_target(y)
242 if not valid:
243 raise ValueError('Expected array-like (array or non-string sequence), '
--> 244 'got %r' % y)
245
246 sparseseries = (y.__class__.__name__ == 'SparseSeries')
ValueError: Expected array-like (array or non-string sequence), got <tf.Tensor 'fifo_queue_DequeueUpTo:2' shape=(?,) dtype=int64>
Is there a way around this? I have a multi-class classification problem at hand, and need to log both macro and micro averaged scores during training and evaluation.

In order to work properly inside tensorflow training loop, metrics need to be updated. Every function in tf.metrics has an update_op for it. So it's strongly recommended to construct your custom metric using lower level functions like tf.metrics.true_positives I'm not aware of particular formula used in sklearn, you can define your own metric like this
def custom_metric(labels, predictions):
metric1, update_op_m1 = tf.metrics.any_function(labels, predictions)
metric2, update_op_m2 = tf.metrics.any_other_function(labels, predictions)
output = tf.reduce_mean(metric1 + metric2)
return output, tf.group(update_op_m1, update_op_m2) #Note that you need to group all update ops

One solution is to use the metric functions from https://github.com/guillaumegenthial/tf_metrics

Related

TypeError when trying to use EarlyStopping with f1-metric as stopping criterion

I want for training a CNN with Early Stopping and want to use the f1-metric as stopping criterion.
When I compile the code for the CNN model I get the a TypeError as error message.
I'm still using Tensorflow 1.4 would like to avoid an upgrade to 2.0, because I have in mind that my previous code doesn't work anymore.
The error message is as follows:
TypeError Traceback (most recent call last)
/usr/local/lib/python3.6/dist-packages/sklearn/utils/validation.py in _num_samples(x)
158 try:
--> 159 return len(x)
160 except TypeError:
14 frames
/usr/local/lib/python3.6/dist-
packages/tensorflow_core/python/framework/ops.py in __len__(self)
740 "Please call `x.shape` rather than `len(x)` for "
--> 741 "shape information.".format(self.name))
742
TypeError: len is not well defined for symbolic Tensors. (dense_16_target:0) Please call `x.shape` rather than `len(x)` for shape information.
During handling of the above exception, another exception occurred:
TypeError Traceback (most recent call last)
<ipython-input-44-cd3da16e057c> in <module>()
----> 1 model = model_cnn(False,False, False,True,6, 0.2, 0.5)
2 X_train, X_val, y_train, y_val = split_data(X_train, y_train,1)
3 cnn, ep = train_model_es(model, X_train, y_train, X_val, y_val, X_test, y_test, 50, 500,1)
<ipython-input-42-d275d9c69c03> in model_cnn(spat, extra_pool, avg_pool, cw, numb_conv, drop_conv, drop_dense)
36 if cw == True:
37 print("sparse categorical crossentropy")
---> 38 model.compile(loss="sparse_categorical_crossentropy", optimizer=Adam(), metrics=['accuracy', f1_metric])
39 #model.compile(loss="sparse_categorical_crossentropy", optimizer=Adam(), metrics=['accuracy'])
40 print("nothing")
/usr/local/lib/python3.6/dist-packages/keras/engine/training.py in compile(self, optimizer, loss, metrics, loss_weights, sample_weight_mode, weighted_metrics, target_tensors, **kwargs)
452 output_metrics = nested_metrics[i]
453 output_weighted_metrics = nested_weighted_metrics[i]
--> 454 handle_metrics(output_metrics)
455 handle_metrics(output_weighted_metrics, weights=weights)
456
/usr/local/lib/python3.6/dist-packages/keras/engine/training.py in handle_metrics(metrics, weights)
421 metric_result = weighted_metric_fn(y_true, y_pred,
422 weights=weights,
--> 423 mask=masks[i])
424
425 # Append to self.metrics_names, self.metric_tensors,
/usr/local/lib/python3.6/dist-packages/keras/engine/training_utils.py in weighted(y_true, y_pred, weights, mask)
426 """
427 # score_array has ndim >= 2
--> 428 score_array = fn(y_true, y_pred)
429 if mask is not None:
430 # Cast the mask to floatX to avoid float64 upcasting in Theano
<ipython-input-9-b21dc3bd89a6> in f1_metric(y_test, y_pred)
1 def f1_metric(y_test, y_pred):
----> 2 f1 = f1_score(y_test, y_pred, average='macro')
3 return f1
/usr/local/lib/python3.6/dist-packages/sklearn/metrics/_classification.py in f1_score(y_true, y_pred, labels, pos_label, average, sample_weight, zero_division)
1097 pos_label=pos_label, average=average,
1098 sample_weight=sample_weight,
-> 1099 zero_division=zero_division)
1100
1101
/usr/local/lib/python3.6/dist-packages/sklearn/metrics/_classification.py in fbeta_score(y_true, y_pred, beta, labels, pos_label, average, sample_weight, zero_division)
1224 warn_for=('f-score',),
1225 sample_weight=sample_weight,
-> 1226 zero_division=zero_division)
1227 return f
1228
/usr/local/lib/python3.6/dist-packages/sklearn/metrics/_classification.py in precision_recall_fscore_support(y_true, y_pred, beta, labels, pos_label, average, warn_for, sample_weight, zero_division)
1482 raise ValueError("beta should be >=0 in the F-beta score")
1483 labels = _check_set_wise_labels(y_true, y_pred, average, labels,
-> 1484 pos_label)
1485
1486 # Calculate tp_sum, pred_sum, true_sum ###
/usr/local/lib/python3.6/dist-packages/sklearn/metrics/_classification.py in _check_set_wise_labels(y_true, y_pred, average, labels, pos_label)
1299 str(average_options))
1300
-> 1301 y_type, y_true, y_pred = _check_targets(y_true, y_pred)
1302 present_labels = unique_labels(y_true, y_pred)
1303 if average == 'binary':
/usr/local/lib/python3.6/dist-packages/sklearn/metrics/_classification.py in _check_targets(y_true, y_pred)
78 y_pred : array or indicator matrix
79 """
---> 80 check_consistent_length(y_true, y_pred)
81 type_true = type_of_target(y_true)
82 type_pred = type_of_target(y_pred)
/usr/local/lib/python3.6/dist-packages/sklearn/utils/validation.py in check_consistent_length(*arrays)
206 """
207
--> 208 lengths = [_num_samples(X) for X in arrays if X is not None]
209 uniques = np.unique(lengths)
210 if len(uniques) > 1:
/usr/local/lib/python3.6/dist-packages/sklearn/utils/validation.py in <listcomp>(.0)
206 """
207
--> 208 lengths = [_num_samples(X) for X in arrays if X is not None]
209 uniques = np.unique(lengths)
210 if len(uniques) > 1:
/usr/local/lib/python3.6/dist-packages/sklearn/utils/validation.py in _num_samples(x)
159 return len(x)
160 except TypeError:
--> 161 raise TypeError(message)
162
163
TypeError: Expected sequence or array-like, got <class 'tensorflow.python.framework.ops.Tensor'>
And here is the relevant code:
def f1_metric(y_test, y_pred):
f1 = f1_score(y_test, y_pred, average='macro')
return f1
def train_model_es(model, X, y, X_val, y_val, X_test, y_test):
es = EarlyStopping(monitor='f1_metric', mode='max', patience=20, restore_best_weights=True)
y = np.argmax(y, axis=1)
y_val = np.argmax(y_val, axis=1)
y_test = np.argmax(y_test, axis=1)
class_weights = class_weight.compute_class_weight('balanced', np.unique(y), y)
class_weights = dict(enumerate(class_weights))
history = model.fit(X, y, class_weight=class_weights, batch_size=32,epochs=20, verbose=1,
validation_data=(X_val, y_val), callbacks=[es])
def model_cnn():
model = Sequential()
model.add(Conv2D(32, kernel_size=(3,3), input_shape=(28,28,1),padding='same'))
model.add(BatchNormalization())
model.add(ELU())
model.add(Conv2D(32, kernel_size=(3,3), padding='same'))
model.add(BatchNormalization())
model.add(ELU())
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(256))
model.add(BatchNormalization())
model.add(ELU())
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
model.compile(loss="sparse_categorical_crossentroy",optimizer=Adam(),metrics=["accuracy",f1_metric])
return model
Does anyone have a tip on how to fix this error message.
Many thanks for every hint
As the error message suggests,
Error 1) You are doing a len() operation on symbolic tensor. You cannot do that operation on symbolic tensor. You can find difference between a variable tensor and symbolic tensor here.
Error 2) You are using a tensor for the operation which expects array as input. Can you please convert y_true and y_pred from tensor to array and use in the f1_score and other operations.
Example - To convert tensor to array
%tensorflow_version 1.x
print(tf.__version__)
import tensorflow as tf
import numpy as np
x = tf.constant([1,2,3,4,5,6])
print("Type of x:",x)
with tf.Session() as sess:
y = np.array(x.eval())
print("Type of y:",y.shape,y)
Output -
1.15.2
Type of x: Tensor("Const_24:0", shape=(6,), dtype=int32)
Type of y: (6,) [1 2 3 4 5 6]

How do you write a custom activation function in python for Keras?

I'm trying to write a custom activation function for use with Keras. I can not write it with tensorflow primitives as it does properly compute the derivative. I followed How to make a custom activation function with only Python in Tensorflow? and it works very we in creating a tensorflow function. However, when I tried putting it into Keras as an activation function for the classic MNIST demo. I got errors. I also tried the tf_spiky function from the above reference.
Here is the sample code
tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(512, activation=tf_spiky),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)])
Here's my entire error:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-48-73a57f81db19> in <module>
3 tf.keras.layers.Dense(512, activation=tf_spiky),
4 tf.keras.layers.Dropout(0.2),
----> 5 tf.keras.layers.Dense(10, activation=tf.nn.softmax)])
6 x=tf.keras.layers.Activation(tf_spiky)
7 y=tf.keras.layers.Flatten(input_shape=(28, 28))
/opt/conda/lib/python3.6/site-packages/tensorflow/python/training/checkpointable/base.py in _method_wrapper(self, *args, **kwargs)
472 self._setattr_tracking = False # pylint: disable=protected-access
473 try:
--> 474 method(self, *args, **kwargs)
475 finally:
476 self._setattr_tracking = previous_value # pylint: disable=protected-access
/opt/conda/lib/python3.6/site-packages/tensorflow/python/keras/engine/sequential.py in __init__(self, layers, name)
106 if layers:
107 for layer in layers:
--> 108 self.add(layer)
109
110 #property
/opt/conda/lib/python3.6/site-packages/tensorflow/python/training/checkpointable/base.py in _method_wrapper(self, *args, **kwargs)
472 self._setattr_tracking = False # pylint: disable=protected-access
473 try:
--> 474 method(self, *args, **kwargs)
475 finally:
476 self._setattr_tracking = previous_value # pylint: disable=protected-access
/opt/conda/lib/python3.6/site-packages/tensorflow/python/keras/engine/sequential.py in add(self, layer)
173 # If the model is being built continuously on top of an input layer:
174 # refresh its output.
--> 175 output_tensor = layer(self.outputs[0])
176 if isinstance(output_tensor, list):
177 raise TypeError('All layers in a Sequential model '
/opt/conda/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py in __call__(self, inputs, *args, **kwargs)
728
729 # Check input assumptions set before layer building, e.g. input rank.
--> 730 self._assert_input_compatibility(inputs)
731 if input_list and self._dtype is None:
732 try:
/opt/conda/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py in _assert_input_compatibility(self, inputs)
1463 if x.shape.ndims is None:
1464 raise ValueError('Input ' + str(input_index) + ' of layer ' +
-> 1465 self.name + ' is incompatible with the layer: '
1466 'its rank is undefined, but the layer requires a '
1467 'defined rank.')
ValueError: Input 0 of layer dense_1 is incompatible with the layer: its rank is undefined, but the layer requires a defined rank.
From this I gather the last Dense layer is unable to get the dimensions of the output after the activation function or something to that. I did see in the tensorflow code that many activation functions register a shape. But either I'm not doing that correctly or I'm going in the wrong direction. But I'm guessing something needs to be done to the tensorflow function to make it an activation function that Keras can use.
I would appreciate any help you can give.
As requested here is the sample codes for tf_spiky, it works as described in the above reference. However, once put into Keras I get the errors shown. This is pretty much as shown in the *How to make a custom activation function with only Python in Tensorflow?" stackoverflow article.
def spiky(x):
print(x)
r = x % 1
if r <= 0.5:
return r
else:
return 0
def d_spiky(x):
r = x % 1
if r <= 0.5:
return 1
else:
return 0
np_spiky = np.vectorize(spiky)
np_d_spiky = np.vectorize(d_spiky)
np_d_spiky_32 = lambda x: np_d_spiky(x).astype(np.float32)
import tensorflow as tf
from tensorflow.python.framework import ops
def tf_d_spiky(x,name=None):
with tf.name_scope(name, "d_spiky", [x]) as name:
y = tf.py_func(np_d_spiky_32,
[x],
[tf.float32],
name=name,
stateful=False)
return y[0]
def py_func(func, inp, Tout, stateful=True, name=None, grad=None):
# Need to generate a unique name to avoid duplicates:
rnd_name = 'PyFuncGrad' + str(np.random.randint(0, 1E+8))
tf.RegisterGradient(rnd_name)(grad) # see _MySquareGrad for grad example
g = tf.get_default_graph()
with g.gradient_override_map({"PyFunc": rnd_name}):
return tf.py_func(func, inp, Tout, stateful=stateful, name=name)
def spikygrad(op, grad):
x = op.inputs[0]
n_gr = tf_d_spiky(x)
return grad * n_gr
np_spiky_32 = lambda x: np_spiky(x).astype(np.float32)
def tf_spiky(x, name=None):
with tf.name_scope(name, "spiky", [x]) as name:
y = py_func(np_spiky_32,
[x],
[tf.float32],
name=name,
grad=spikygrad) # <-- here's the call to the gradient
return y[0]
The solution is in this post Output from TensorFlow `py_func` has unknown rank/shape
The easiest fix is to add y[0].set_shape(x.get_shape()) before the return statement in the definition of tf_spiky.
Perhaps someone out there knows how to properly work with tensorflow shape functions. Digging around I found a unchanged_shape shape function in tensorflow.python.framework.common_shapes, which be appropriate here, but I don't know how to attach it to the tf_spiky function. Seems a python decorator is in order here. It would probably be a service to others to explain customizing tensorflow functions with shape functions.

Keras Tensorflow 'Cannot apply softmax to a tensor that is 1D'

I'm going over the Book Deep Learning with Python from F. Chollet.
https://www.manning.com/books/deep-learning-with-python
I'm trying to follow along with the code examples. I just installed keras, and I am getting this error when trying to run this:
from this notebook:
https://github.com/fchollet/deep-learning-with-python-notebooks/blob/master/2.1-a-first-look-at-a-neural-network.ipynb
from keras import models
from keras import layers
network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
network.add(layers.Dense(10, activation='softmax'))
TypeError Traceback (most recent call
last) in ()
4 network = models.Sequential()
5 network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
----> 6 network.add(layers.Dense(10, activation='softmax'))
~/anaconda3/lib/python3.6/site-packages/keras/engine/sequential.py in
add(self, layer)
179 self.inputs = network.get_source_inputs(self.outputs[0])
180 elif self.outputs:
--> 181 output_tensor = layer(self.outputs[0])
182 if isinstance(output_tensor, list):
183 raise TypeError('All layers in a Sequential model '
~/anaconda3/lib/python3.6/site-packages/keras/engine/base_layer.py in
call(self, inputs, **kwargs)
455 # Actually call the layer,
456 # collecting output(s), mask(s), and shape(s).
--> 457 output = self.call(inputs, **kwargs)
458 output_mask = self.compute_mask(inputs, previous_mask)
459
~/anaconda3/lib/python3.6/site-packages/keras/layers/core.py in
call(self, inputs)
881 output = K.bias_add(output, self.bias, data_format='channels_last')
882 if self.activation is not None:
--> 883 output = self.activation(output)
884 return output
885
~/anaconda3/lib/python3.6/site-packages/keras/activations.py in
softmax(x, axis)
29 raise ValueError('Cannot apply softmax to a tensor that is 1D')
30 elif ndim == 2:
---> 31 return K.softmax(x)
32 elif ndim > 2:
33 e = K.exp(x - K.max(x, axis=axis, keepdims=True))
~/anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py
in softmax(x, axis) 3229 A tensor. 3230 """
-> 3231 return tf.nn.softmax(x, axis=axis) 3232 3233
TypeError: softmax() got an unexpected keyword argument 'axis'
I'm wondering if there's something off with my installation?
keras.__version__
2.2.4
If anyone could give me a clue of what to look into.
Seems like you have an incompatible Tensorflow version (which Keras is using as a backend). For details look here

How to include kernel constraints in Tensorflow eager conv2D?

I'm having trouble using kernel_constraint=maxnorm(3) within keras when using Tensorflow eager execution. This works fine when not using the standard Sequential method outside of eager execution, but seems to fail with an error here (it seems to be because of a multiplication step *= which I don't know if there is a substitute for in this context).
Question: Is there a way to incorporate the maximum $L^2$ norm functionality within the Eager Tensorflow execution framework? Below are more details.
Here is how I activate tensorflow eager.
from __future__ import absolute_import, division, print_function
import tensorflow as tf
import tensorflow.contrib.eager as tfe
from keras.datasets import cifar10
tf.enable_eager_execution()
The following code works fine
Works:
class ObjectDet(tf.keras.Model):
def __init__(self):
super(ObjectDet,self).__init__()
self.layer1= tf.keras.layers.Conv2D(32, (3, 3), input_shape=(32,32,3), padding='same', activation='relu')
self.layer2=tf.keras.layers.Dropout(0.2)
self.layer3=tf.keras.layers.Conv2D(32, (3, 3), activation='relu', padding='same')
self.layer4=tf.keras.layers.MaxPooling2D(pool_size=(2,2))
self.layer5=tf.keras.layers.Flatten()
self.layer6=tf.keras.layers.Dense(512, activation='relu')
self.layer7=tf.keras.layers.Dropout(0.1)
self.layer8=tf.keras.layers.Dense(10, activation='softmax')
def call(self, input):
"""Run the model."""
result = self.layer1(input)
result = self.layer2(result)
result = self.layer3(result)
result = self.layer4(result)
result = self.layer5(result)
result = self.layer6(result)
result = self.layer7(result)
result = self.layer8(result)
return result
def loss(model, x, y):
prediction = model(x)
return cross_entropy(prediction,y)
def grad(model, inputs, targets):
with tf.GradientTape() as tape:
loss_value = loss(model, inputs, targets)
return tape.gradient(loss_value, model.variables)
x, y = iter(train_ds).next()
print("Initial loss: {:.3f}".format(loss(model, x, y)))
# Training loop
for (i, (x, y)) in enumerate(train_ds):
# Calculate derivatives of the input function with respect to its parameters.
grads = grad(model, x, y)
# Apply the gradient to the model
optimizer.apply_gradients(zip(grads, model.variables),
global_step=tf.train.get_or_create_global_step())
if i % 200 == 0:
pass
print("Loss at step {:04d}: {:.3f}".format(i, loss(model, x, y)))
Does not work:
If I replace
self.layer1= tf.keras.layers.Conv2D(32, (3, 3), input_shape=(32,32,3), padding='same', activation='relu')
with
self.layer1= tf.keras.layers.Conv2D(32, (3, 3), input_shape=(32,32,3), padding='same', activation='relu',kernel_constraint=maxnorm(3))
I obtain the error:
RuntimeErrorTraceback (most recent call last)
<ipython-input-74-629273c4a534> in <module>()
19
20 optimizer.apply_gradients(zip(grads, model.variables),
---> 21 global_step=tf.train.get_or_create_global_step())
22 if i % 200 == 0:
23 pass
/home/dgoldma1/.local/lib/python2.7/site-packages/tensorflow/python/training/optimizer.pyc in apply_gradients(self, grads_and_vars, global_step, name)
615 scope_name = var.op.name
616 with ops.name_scope("update_" + scope_name), ops.colocate_with(var):
--> 617 update_ops.append(processor.update_op(self, grad))
618 if global_step is None:
619 apply_updates = self._finish(update_ops, name)
/home/dgoldma1/.local/lib/python2.7/site-packages/tensorflow/python/training/optimizer.pyc in update_op(self, optimizer, g)
166 if self._v.constraint is not None:
167 with ops.control_dependencies([update_op]):
--> 168 return self._v.assign(self._v.constraint(self._v))
169 else:
170 return update_op
/home/dgoldma1/.local/lib/python2.7/site-packages/keras/constraints.pyc in __call__(self, w)
51 norms = K.sqrt(K.sum(K.square(w), axis=self.axis, keepdims=True))
52 desired = K.clip(norms, 0, self.max_value)
---> 53 w *= (desired / (K.epsilon() + norms))
54 return w
55
/home/dgoldma1/.local/lib/python2.7/site-packages/tensorflow/python/ops/resource_variable_ops.pyc in __imul__(self, unused_other)
931
932 def __imul__(self, unused_other):
--> 933 raise RuntimeError("Variable *= value not supported. Use "
934 "variable.assign_mul(value) to modify the variable "
935 "value and variable = variable * value to get a new "
RuntimeError: Variable *= value not supported. Use variable.assign_mul(value) to modify the variable value and variable = variable * value to get a new Tensor object.
Thanks!
It seems you have found a bug in the code. You could submit it to the dev team here.
Eager is a somewhat recent addition to tensorflow that has a profound impact on the code, so it lacks a little polish. I am not too surprised that this kind of bug in corner cases still happen.

GridSearchCV: "TypeError: 'StratifiedKFold' object is not iterable"

I want to perform GridSearchCV in a RandomForestClassifier, but data is not balanced, so I use StratifiedKFold:
from sklearn.model_selection import StratifiedKFold
from sklearn.grid_search import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
param_grid = {'n_estimators':[10, 30, 100, 300], "max_depth": [3, None],
"max_features": [1, 5, 10], "min_samples_leaf": [1, 10, 25, 50], "criterion": ["gini", "entropy"]}
rfc = RandomForestClassifier()
clf = GridSearchCV(rfc, param_grid=param_grid, cv=StratifiedKFold()).fit(X_train, y_train)
But I get an error:
TypeError Traceback (most recent call last)
<ipython-input-597-b08e92c33165> in <module>()
9 rfc = RandomForestClassifier()
10
---> 11 clf = GridSearchCV(rfc, param_grid=param_grid, cv=StratifiedKFold()).fit(X_train, y_train)
c:\python34\lib\site-packages\sklearn\grid_search.py in fit(self, X, y)
811
812 """
--> 813 return self._fit(X, y, ParameterGrid(self.param_grid))
c:\python34\lib\site-packages\sklearn\grid_search.py in _fit(self, X, y, parameter_iterable)
559 self.fit_params, return_parameters=True,
560 error_score=self.error_score)
--> 561 for parameters in parameter_iterable
562 for train, test in cv)
c:\python34\lib\site-packages\sklearn\externals\joblib\parallel.py in __call__(self, iterable)
756 # was dispatched. In particular this covers the edge
757 # case of Parallel used with an exhausted iterator.
--> 758 while self.dispatch_one_batch(iterator):
759 self._iterating = True
760 else:
c:\python34\lib\site-packages\sklearn\externals\joblib\parallel.py in dispatch_one_batch(self, iterator)
601
602 with self._lock:
--> 603 tasks = BatchedCalls(itertools.islice(iterator, batch_size))
604 if len(tasks) == 0:
605 # No more tasks available in the iterator: tell caller to stop.
c:\python34\lib\site-packages\sklearn\externals\joblib\parallel.py in __init__(self, iterator_slice)
125
126 def __init__(self, iterator_slice):
--> 127 self.items = list(iterator_slice)
128 self._size = len(self.items)
c:\python34\lib\site-packages\sklearn\grid_search.py in <genexpr>(.0)
560 error_score=self.error_score)
561 for parameters in parameter_iterable
--> 562 for train, test in cv)
563
564 # Out is a list of triplet: score, estimator, n_test_samples
TypeError: 'StratifiedKFold' object is not iterable
When I write cv=StratifiedKFold(y_train) I have ValueError: The number of folds must be of Integral type. But when I write `cv=5, it works.
I don't understand what is wrong with StratifiedKFold
I had exactly the same problem. The solution that worked for me is to replace:
from sklearn.grid_search import GridSearchCV
with
from sklearn.model_selection import GridSearchCV
Then it should work fine.
The problem here is an API change as mentioned in other answers, however the answers could be more explicit.
The cv parameter documentation states:
cv : int, cross-validation generator or an iterable, optional
Determines the cross-validation splitting strategy. Possible inputs
for cv are:
None, to use the default 3-fold cross-validation, integer,
to specify the number of folds.
An object to be used as a
cross-validation generator.
An iterable yielding train/test splits.
For integer/None inputs, if y is binary or multiclass, StratifiedKFold
used. If the estimator is a classifier or if y is neither binary nor
multiclass, KFold is used.
So, whatever the cross validation strategy used, all that is needed is to provide the generator using the function split, as suggested:
kfolds = StratifiedKFold(5)
clf = GridSearchCV(estimator, parameters, scoring=qwk, cv=kfolds.split(xtrain,ytrain))
clf.fit(xtrain, ytrain)
It seems that cv=StratifiedKFold()).fit(X_train, y_train) should be changed to cv=StratifiedKFold()).split(X_train, y_train).
The api changed in the latest version. You used to pass y and now you pass just the number when you create the stratifiedKFold object. You pass the y later.