# Buggy code
def _fit_stochastic(
    self,
    X,
    y,
    activations,
    deltas,
    coef_grads,
    intercept_grads,
    layer_units,
    incremental,
):
    if not incremental or not hasattr(self, "_optimizer"):
        params = self.coefs_ + self.intercepts_

        if self.solver == "sgd":
            self._optimizer = SGDOptimizer(
                params,
                self.learning_rate_init,
                self.learning_rate,
                self.momentum,
                self.nesterovs_momentum,
                self.power_t,
            )
        elif self.solver == "adam":
            self._optimizer = AdamOptimizer(
                params, self.learning_rate_init, self.beta_1, self.beta_2, self.epsilon
            )

    # early_stopping in partial_fit doesn't make sense
    early_stopping = self.early_stopping and not incremental
    if early_stopping:
        X, X_val, y, y_val = train_test_split(
            X, y, random_state=self._random_state, test_size=self.validation_fraction
        )
        if isinstance(self, ClassifierMixin):
            y_val = self.label_binarizer_.inverse_transform(y_val)
    else:
        X_val = None
        y_val = None

    n_samples = X.shape[0]

    if self.batch_size == "auto":
        batch_size = min(200, n_samples)
    else:
        batch_size = np.clip(self.batch_size, 1, n_samples)

    try:
        for it in range(self.max_iter):
            X, y = shuffle(X, y, random_state=self._random_state)
            accumulated_loss = 0.0
            for batch_slice in gen_batches(n_samples, batch_size):
                activations[0] = X[batch_slice]
                batch_loss, coef_grads, intercept_grads = self._backprop(
                    X[batch_slice],
                    y[batch_slice],
                    activations,
                    deltas,
                    coef_grads,
                    intercept_grads,
                )
                accumulated_loss += batch_loss * (batch_slice.stop - batch_slice.start)

                # update weights
                grads = coef_grads + intercept_grads
                self._optimizer.update_params(grads)

            self.n_iter_ += 1
            self.loss_ = accumulated_loss / X.shape[0]

            self.t_ += n_samples
            self.loss_curve_.append(self.loss_)
            if self.verbose:
                print("Iteration %d, loss = %.8f" % (self.n_iter_, self.loss_))

            # update no_improvement_count based on training loss or
            # validation score according to early_stopping
            self._update_no_improvement_count(early_stopping, X_val, y_val)

            # for learning rate that needs to be updated at iteration end
            self._optimizer.iteration_ends(self.t_)

            if self._no_improvement_count > 2:
                # not better than last two iterations by tol.
                # stop or decrease learning rate
                if early_stopping:
                    msg = (
                        "Validation score did not improve more than "
                        "tol=%f for two consecutive epochs." % self.tol
                    )
                else:
                    msg = (
                        "Training loss did not improve more than tol=%f"
                        " for two consecutive epochs." % self.tol
                    )

                is_stopping = self._optimizer.trigger_stopping(msg, self.verbose)
                if is_stopping:
                    break
                else:
                    self._no_improvement_count = 0

            if incremental:
                break

            if self.n_iter_ == self.max_iter:
                warnings.warn(
                    "Stochastic Optimizer: Maximum iterations"
                    " reached and the optimization hasn't "
                    "converged yet." % (),
                    ConvergenceWarning,
                )
    except KeyboardInterrupt:
        pass

    if early_stopping:
        # restore best weights
        self.coefs_ = self._best_coefs
        self.intercepts_ = self._best_intercepts


# Traceback (ValueError)
Traceback (most recent call last):
File "fail.py", line 7, in <module>
clf.partial_fit([[4]],["d"])
File "/usr/local/lib/python3.4/dist-packages/sklearn/neural_network/multilayer_perceptron.py", line 989, in _partial_fit
super(MLPClassifier, self)._partial_fit(X, y)
File "/usr/local/lib/python3.4/dist-packages/sklearn/neural_network/multilayer_perceptron.py", line 640, in _partial_fit
return self._fit(X, y, incremental=True)
File "/usr/local/lib/python3.4/dist-packages/sklearn/neural_network/multilayer_perceptron.py", line 375, in _fit
intercept_grads, layer_units, incremental)
File "/usr/local/lib/python3.4/dist-packages/sklearn/neural_network/multilayer_perceptron.py", line 512, in _fit_stochastic
coef_grads, intercept_grads)
File "/usr/local/lib/python3.4/dist-packages/sklearn/neural_network/multilayer_perceptron.py", line 225, in _backprop
loss = LOSS_FUNCTIONS[self.loss](y, activations[-1])
File "/usr/local/lib/python3.4/dist-packages/sklearn/neural_network/_base.py", line 208, in log_loss
return -np.sum(y_true * np.log(y_prob)) / y_prob.shape[0]
ValueError: operands could not be broadcast together with shapes (1,2) (1,3)

# Fixed code
def _fit_stochastic(
    self,
    X,
    y,
    activations,
    deltas,
    coef_grads,
    intercept_grads,
    layer_units,
    incremental,
):
    if not incremental or not hasattr(self, "_optimizer"):
        params = self.coefs_ + self.intercepts_

        if self.solver == "sgd":
            self._optimizer = SGDOptimizer(
                params,
                self.learning_rate_init,
                self.learning_rate,
                self.momentum,
                self.nesterovs_momentum,
                self.power_t,
            )
        elif self.solver == "adam":
            self._optimizer = AdamOptimizer(
                params, self.learning_rate_init, self.beta_1, self.beta_2, self.epsilon
            )

    # early_stopping in partial_fit doesn't make sense
    early_stopping = self.early_stopping and not incremental
    if early_stopping:
        X, X_val, y, y_val = train_test_split(
            X, y, random_state=self._random_state, test_size=self.validation_fraction
        )
        if isinstance(self, ClassifierMixin):
            y_val = self._label_binarizer.inverse_transform(y_val)
    else:
        X_val = None
        y_val = None

    n_samples = X.shape[0]

    if self.batch_size == "auto":
        batch_size = min(200, n_samples)
    else:
        batch_size = np.clip(self.batch_size, 1, n_samples)

    try:
        for it in range(self.max_iter):
            X, y = shuffle(X, y, random_state=self._random_state)
            accumulated_loss = 0.0
            for batch_slice in gen_batches(n_samples, batch_size):
                activations[0] = X[batch_slice]
                batch_loss, coef_grads, intercept_grads = self._backprop(
                    X[batch_slice],
                    y[batch_slice],
                    activations,
                    deltas,
                    coef_grads,
                    intercept_grads,
                )
                accumulated_loss += batch_loss * (batch_slice.stop - batch_slice.start)

                # update weights
                grads = coef_grads + intercept_grads
                self._optimizer.update_params(grads)

            self.n_iter_ += 1
            self.loss_ = accumulated_loss / X.shape[0]

            self.t_ += n_samples
            self.loss_curve_.append(self.loss_)
            if self.verbose:
                print("Iteration %d, loss = %.8f" % (self.n_iter_, self.loss_))

            # update no_improvement_count based on training loss or
            # validation score according to early_stopping
            self._update_no_improvement_count(early_stopping, X_val, y_val)

            # for learning rate that needs to be updated at iteration end
            self._optimizer.iteration_ends(self.t_)

            if self._no_improvement_count > 2:
                # not better than last two iterations by tol.
                # stop or decrease learning rate
                if early_stopping:
                    msg = (
                        "Validation score did not improve more than "
                        "tol=%f for two consecutive epochs." % self.tol
                    )
                else:
                    msg = (
                        "Training loss did not improve more than tol=%f"
                        " for two consecutive epochs." % self.tol
                    )

                is_stopping = self._optimizer.trigger_stopping(msg, self.verbose)
                if is_stopping:
                    break
                else:
                    self._no_improvement_count = 0

            if incremental:
                break

            if self.n_iter_ == self.max_iter:
                warnings.warn(
                    "Stochastic Optimizer: Maximum iterations"
                    " reached and the optimization hasn't "
                    "converged yet." % (),
                    ConvergenceWarning,
                )
    except KeyboardInterrupt:
        pass

    if early_stopping:
        # restore best weights
        self.coefs_ = self._best_coefs
        self.intercepts_ = self._best_intercepts