<jupyter_start><jupyter_text>Deep learning---------------------------This example shows how to use ATOM to train and validate a Convolutional Neural Network implemented with [Keras](https://keras.io/) in two different ways: using [scikeras](https://www.adriangb.com/scikeras/refs/heads/master/index.html) (recommended) and using [keras.wrappers.scikit_learn](https://faroit.com/keras-docs/1.0.6/scikit-learn-api/) (old way, will be deprecated in a future release).Import the MNIST dataset from [keras.datasets](https://keras.io/api/datasets/mnist/). This is a well known image dataset whose goal is to classify handwritten digits.  Using scikeras<jupyter_code># Disable annoying tf warnings
import logging
import tensorflow as tf
tf.get_logger().setLevel(logging.ERROR)

from atom import ATOMClassifier, ATOMModel
from sklearn.preprocessing import FunctionTransformer
from skopt.space.space import Categorical

from scikeras.wrappers import KerasClassifier
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Flatten, Conv2D, Dropout
# Create the convolutional neural network
class ConvNN(KerasClassifier):
    """Convolutional neural network model."""

    @property
    def feature_encoder(self):
        """Convert the 2d input to the image's format (len(X), 28, 28, 1)."""
        return FunctionTransformer(
            func=lambda X: X.reshape(X.shape[0], 28, 28, 1),
        )

    @staticmethod
    def _keras_build_fn():
        """Create the model's architecture."""
        model = Sequential()
        model.add(
            Conv2D(
                filters=64,
                kernel_size=3,
                activation="relu",
                input_shape=(28, 28, 1),
            )
        )
        model.add(Conv2D(filters=64, kernel_size=3, activation="relu"))
        model.add(Flatten())
        model.add(Dense(units=10, activation="softmax"))
        model.compile(
            optimizer="adam",
            loss="sparse_categorical_crossentropy",
            metrics=["accuracy"],
        )

        return model
# Convert the model to an ATOM model
model = ATOMModel(
    estimator=ConvNN(epochs=5, verbose=0),
    acronym="NN",
    fullname="Neural network",
)
# Download the MNIST dataset
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# Flatten data to follow sklearn's API (2d input)
X_train = X_train.reshape(len(X_train), -1)
X_test = X_test.reshape(len(X_test), -1)

data = (X_train, y_train), (X_test, y_test)
atom = ATOMClassifier(*data, n_rows=0.1, n_jobs=6, warnings=False, verbose=2)
# Like any other model, we can define custom dimensions for the bayesian optimization
atom.run(
    models=model,
    metric="f1_weighted",
    n_calls=5,
    bo_params={
        "dimensions": [Categorical([32, 64, 128, 256], name="batch_size")],
        "max_time": 120,
    }
)<jupyter_output>Training ========================= >>
Models: NN
Metric: f1_weighted


Running BO for Neural network...
| call             | batch_size | f1_weighted | best_f1_weighted |    time | total_time |
| ---------------- | ---------- | ----------- | ---------------- | ------- | ---------- |
| Initial point 1  |         64 |       0.957 |            0.957 | 27.868s |    27.871s |
| Initial point 2  |         32 |      0.9441 |            0.957 | 31.598s |    59.710s |
| Initial point 3  |         32 |      0.9441 |            0.957 |  0.001s |    59.789s |
| Initial point 4  |        128 |      0.9721 |           0.9721 | 24.759s |     1m:25s |
| Initial point 5  |        128 |      0.9721 |           0.9721 |  0.000s |     1m:25s |
Bayesian Optimization ---------------------------
Best call --> Initial point 4
Best parameters --> {'batch_size': 128}
Best evaluation --> f1_weighted: 0.9721
Time elapsed: 1m:25s
Fit ---------------------------------------------
Train evaluation --> f1_weighted: [...]<jupyter_text>Using keras.wrappers.scikit_learn<jupyter_code># Disable annoying tf warnings
import logging
import tensorflow as tf
tf.get_logger().setLevel(logging.ERROR)

# Import standard packages
from atom import ATOMClassifier, ATOMModel
from skopt.space.space import Categorical

# Keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Flatten, Conv2D
from keras.wrappers.scikit_learn import KerasClassifier
# Create the convolutional neural network
def neural_network():
    """Create the model's architecture."""
    model = Sequential()
    model.add(
        Conv2D(
            filters=64,
            kernel_size=3,
            activation="relu",
            input_shape=(28, 28, 1),
        )
    )
    model.add(Conv2D(filters=64, kernel_size=3, activation="relu"))
    model.add(Flatten())
    model.add(Dense(units=10, activation="softmax"))
    model.compile(
        optimizer="adam",
        loss="sparse_categorical_crossentropy",
        metrics=["accuracy"],
    )

    return model
# Since ATOM uses sklearn's API, use Keras' wrapper
model = KerasClassifier(neural_network, epochs=5, verbose=0)

# Convert the model to an ATOM model
model = ATOMModel(model, acronym="NN", fullname="Neural network")
# Download the MNIST dataset
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# Reshape data to fit model
X_train = X_train.reshape(len(X_train), 28, 28, 1)
X_test = X_test.reshape(len(X_test), 28, 28, 1)

data = (X_train, y_train), (X_test, y_test)
atom = ATOMClassifier(*data, n_rows=0.1, n_jobs=6, warnings=False, verbose=2)
# When the input data has more than 2 dimensions, ATOM creates a 
# dataset with just one column of shape (n_samples, shape_sample)
atom.head()
# Every row in the column contains the data of one image
print(f"Shape of one image: {atom.iloc[0, 0].shape}")
print(f"atom's shape (n_rows, (shape_image), n_cols): {atom.shape}")
# Like any other model, we can define custom dimensions for the bayesian optimization
atom.run(
    models=model,
    metric="f1_weighted",
    n_calls=5,
    bo_params={
        "dimensions": [Categorical([32, 64, 128, 256], name="batch_size")],
        "max_time": 120,
    }
)<jupyter_output>Training ========================= >>
Models: NN
Metric: f1_weighted


Running BO for Neural network...
| call             | batch_size | f1_weighted | best_f1_weighted |    time | total_time |
| ---------------- | ---------- | ----------- | ---------------- | ------- | ---------- |
| Initial point 1  |        128 |      0.9568 |           0.9568 | 24.755s |    24.758s |
| Initial point 2  |         64 |        0.95 |           0.9568 | 26.815s |    51.651s |
| Initial point 3  |         64 |        0.95 |           0.9568 |  0.001s |    51.730s |
| Initial point 4  |        128 |      0.9568 |           0.9568 |  0.000s |    51.808s |
| Initial point 5  |         32 |      0.9418 |           0.9568 | 30.575s |     1m:22s |
Bayesian Optimization ---------------------------
Best call --> Initial point 1
Best parameters --> {'batch_size': 128}
Best evaluation --> f1_weighted: 0.9568
Time elapsed: 1m:23s
Fit ---------------------------------------------
Train evaluation --> f1_weighted: [...]<jupyter_text>Analyze the results<jupyter_code># Use the prediction methods like any other model
atom.nn.predict_proba(X_train)
# Or make plots...
atom.nn.plot_confusion_matrix()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15933315113418967, 'fraction_numerical': 0.0485105220005466, 'mean_word_length': 2.542594385285576, 'pattern_counts': {'":': 4, '<': 11, '<?xml version=': 0, '>': 23, 'https://': 4, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '404846', 'license': 'MIT', 'n_tokens_mistral': 2558, 'n_tokens_neox': 2299, 'n_words': 618, 'path': 'examples/deep_learning.ipynb', 'repo_name': 'jaswinder9051998/ATOM', 'size': '7318'}