dl-experiment-code 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. dl_experiment_code-1.0.0/PKG-INFO +146 -0
  2. dl_experiment_code-1.0.0/README.md +139 -0
  3. dl_experiment_code-1.0.0/dl_experiment_code/__init__.py +1 -0
  4. dl_experiment_code-1.0.0/dl_experiment_code/cli.py +94 -0
  5. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp10_local.py +120 -0
  6. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp10_online.py +95 -0
  7. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp5_local.py +87 -0
  8. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp5_online.py +60 -0
  9. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp6_local.py +97 -0
  10. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp6_online.py +68 -0
  11. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp7_local.py +66 -0
  12. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp7_online.py +66 -0
  13. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp8_local.py +135 -0
  14. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp8_online.py +118 -0
  15. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp9_local.py +84 -0
  16. dl_experiment_code-1.0.0/dl_experiment_code/templates/exp9_online.py +49 -0
  17. dl_experiment_code-1.0.0/dl_experiment_code/templates/rnn_scratch.py +130 -0
  18. dl_experiment_code-1.0.0/dl_experiment_code.egg-info/PKG-INFO +146 -0
  19. dl_experiment_code-1.0.0/dl_experiment_code.egg-info/SOURCES.txt +22 -0
  20. dl_experiment_code-1.0.0/dl_experiment_code.egg-info/dependency_links.txt +1 -0
  21. dl_experiment_code-1.0.0/dl_experiment_code.egg-info/entry_points.txt +2 -0
  22. dl_experiment_code-1.0.0/dl_experiment_code.egg-info/top_level.txt +1 -0
  23. dl_experiment_code-1.0.0/pyproject.toml +20 -0
  24. dl_experiment_code-1.0.0/setup.cfg +4 -0
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.4
2
+ Name: dl-experiment-code
3
+ Version: 1.0.0
4
+ Summary: Ready-to-use Deep Learning experiment code for experiments 5-10 and a NumPy RNN from scratch
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+
8
+ # Deep Learning Experiment Code Package
9
+
10
+ This package provides ready-to-use code for:
11
+
12
+ - Experiment 5: CNN image classification
13
+ - Experiment 6: CNN hyperparameter tuning
14
+ - Experiment 7: Autoencoder dimensionality reduction
15
+ - Experiment 8: Educational single-object detection
16
+ - Experiment 9: LSTM sentiment analysis
17
+ - Experiment 10: LSTM hyperparameter tuning
18
+ - Additional: Vanilla RNN implemented from scratch with NumPy
19
+
20
+ For experiments 5-10 there are two versions:
21
+
22
+ 1. `local` - uses a local CSV/image/Pascal VOC dataset.
23
+ 2. `online` - uses a Keras dataset or an online TensorFlow Datasets dataset.
24
+
25
+ The code follows the structure and concepts of the supplied original experiments.
26
+
27
+ ## Installation
28
+
29
+ From this folder:
30
+
31
+ ```bash
32
+ pip install .
33
+ ```
34
+
35
+ For development/editable installation:
36
+
37
+ ```bash
38
+ pip install -e .
39
+ ```
40
+
41
+ ## List experiments
42
+
43
+ ```bash
44
+ dlab-code list
45
+ ```
46
+
47
+ ## Get code
48
+
49
+ Online/Keras dataset version:
50
+
51
+ ```bash
52
+ dlab-code get 5 --dataset online
53
+ ```
54
+
55
+ Local dataset version:
56
+
57
+ ```bash
58
+ dlab-code get 5 --dataset local
59
+ ```
60
+
61
+ Experiments 6-10 work the same way:
62
+
63
+ ```bash
64
+ dlab-code get 6 --dataset online
65
+ dlab-code get 7 --dataset local
66
+ dlab-code get 8 --dataset online
67
+ dlab-code get 9 --dataset local
68
+ dlab-code get 10 --dataset online
69
+ ```
70
+
71
+ ## Save directly to a Python file
72
+
73
+ ```bash
74
+ dlab-code get 5 --dataset online --save exp5.py
75
+ ```
76
+
77
+ Then:
78
+
79
+ ```bash
80
+ python exp5.py
81
+ ```
82
+
83
+ ## RNN from scratch
84
+
85
+ ```bash
86
+ dlab-code get rnn-scratch
87
+ ```
88
+
89
+ Or save it:
90
+
91
+ ```bash
92
+ dlab-code get rnn-scratch --save rnn_from_scratch.py
93
+ ```
94
+
95
+ The RNN uses NumPy only for the recurrent computation and manually implements:
96
+
97
+ - hidden-state calculation
98
+ - output calculation
99
+ - loss
100
+ - backpropagation through time
101
+ - gradient clipping
102
+ - parameter updates
103
+
104
+ ## Dataset notes
105
+
106
+ ### Experiment 5
107
+ - Online: Keras CIFAR-10
108
+ - Local: image directory with one folder per class
109
+
110
+ ### Experiment 6
111
+ - Online: Keras CIFAR-10
112
+ - Local: image directory with one folder per class
113
+
114
+ ### Experiment 7
115
+ - Online: Keras MNIST
116
+ - Local: numeric CSV
117
+
118
+ ### Experiment 8
119
+ - Online: Pascal VOC through TensorFlow Datasets
120
+ - Local: Pascal VOC-style images + XML annotations
121
+
122
+ The object detector is deliberately educational and predicts the first object in an image. It is not a production multi-object detector.
123
+
124
+ ### Experiment 9
125
+ - Online: Keras IMDB
126
+ - Local: `text,label` CSV
127
+
128
+ ### Experiment 10
129
+ - Online: Keras IMDB
130
+ - Local: `text,label` CSV
131
+
132
+ ## Dependencies for running generated code
133
+
134
+ Install the common ML stack:
135
+
136
+ ```bash
137
+ pip install tensorflow scikit-learn pandas numpy matplotlib pillow
138
+ ```
139
+
140
+ Experiment 8 online additionally needs:
141
+
142
+ ```bash
143
+ pip install tensorflow-datasets
144
+ ```
145
+
146
+ The package itself has no heavy ML dependency because it only generates/prints the code.
@@ -0,0 +1,139 @@
1
+ # Deep Learning Experiment Code Package
2
+
3
+ This package provides ready-to-use code for:
4
+
5
+ - Experiment 5: CNN image classification
6
+ - Experiment 6: CNN hyperparameter tuning
7
+ - Experiment 7: Autoencoder dimensionality reduction
8
+ - Experiment 8: Educational single-object detection
9
+ - Experiment 9: LSTM sentiment analysis
10
+ - Experiment 10: LSTM hyperparameter tuning
11
+ - Additional: Vanilla RNN implemented from scratch with NumPy
12
+
13
+ For experiments 5-10 there are two versions:
14
+
15
+ 1. `local` - uses a local CSV/image/Pascal VOC dataset.
16
+ 2. `online` - uses a Keras dataset or an online TensorFlow Datasets dataset.
17
+
18
+ The code follows the structure and concepts of the supplied original experiments.
19
+
20
+ ## Installation
21
+
22
+ From this folder:
23
+
24
+ ```bash
25
+ pip install .
26
+ ```
27
+
28
+ For development/editable installation:
29
+
30
+ ```bash
31
+ pip install -e .
32
+ ```
33
+
34
+ ## List experiments
35
+
36
+ ```bash
37
+ dlab-code list
38
+ ```
39
+
40
+ ## Get code
41
+
42
+ Online/Keras dataset version:
43
+
44
+ ```bash
45
+ dlab-code get 5 --dataset online
46
+ ```
47
+
48
+ Local dataset version:
49
+
50
+ ```bash
51
+ dlab-code get 5 --dataset local
52
+ ```
53
+
54
+ Experiments 6-10 work the same way:
55
+
56
+ ```bash
57
+ dlab-code get 6 --dataset online
58
+ dlab-code get 7 --dataset local
59
+ dlab-code get 8 --dataset online
60
+ dlab-code get 9 --dataset local
61
+ dlab-code get 10 --dataset online
62
+ ```
63
+
64
+ ## Save directly to a Python file
65
+
66
+ ```bash
67
+ dlab-code get 5 --dataset online --save exp5.py
68
+ ```
69
+
70
+ Then:
71
+
72
+ ```bash
73
+ python exp5.py
74
+ ```
75
+
76
+ ## RNN from scratch
77
+
78
+ ```bash
79
+ dlab-code get rnn-scratch
80
+ ```
81
+
82
+ Or save it:
83
+
84
+ ```bash
85
+ dlab-code get rnn-scratch --save rnn_from_scratch.py
86
+ ```
87
+
88
+ The RNN uses NumPy only for the recurrent computation and manually implements:
89
+
90
+ - hidden-state calculation
91
+ - output calculation
92
+ - loss
93
+ - backpropagation through time
94
+ - gradient clipping
95
+ - parameter updates
96
+
97
+ ## Dataset notes
98
+
99
+ ### Experiment 5
100
+ - Online: Keras CIFAR-10
101
+ - Local: image directory with one folder per class
102
+
103
+ ### Experiment 6
104
+ - Online: Keras CIFAR-10
105
+ - Local: image directory with one folder per class
106
+
107
+ ### Experiment 7
108
+ - Online: Keras MNIST
109
+ - Local: numeric CSV
110
+
111
+ ### Experiment 8
112
+ - Online: Pascal VOC through TensorFlow Datasets
113
+ - Local: Pascal VOC-style images + XML annotations
114
+
115
+ The object detector is deliberately educational and predicts the first object in an image. It is not a production multi-object detector.
116
+
117
+ ### Experiment 9
118
+ - Online: Keras IMDB
119
+ - Local: `text,label` CSV
120
+
121
+ ### Experiment 10
122
+ - Online: Keras IMDB
123
+ - Local: `text,label` CSV
124
+
125
+ ## Dependencies for running generated code
126
+
127
+ Install the common ML stack:
128
+
129
+ ```bash
130
+ pip install tensorflow scikit-learn pandas numpy matplotlib pillow
131
+ ```
132
+
133
+ Experiment 8 online additionally needs:
134
+
135
+ ```bash
136
+ pip install tensorflow-datasets
137
+ ```
138
+
139
+ The package itself has no heavy ML dependency because it only generates/prints the code.
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,94 @@
1
+ import argparse
2
+ from pathlib import Path
3
+ import shutil
4
+
5
+ TEMPLATE_DIR = Path(__file__).parent / "templates"
6
+
7
+ EXPERIMENTS = {
8
+ "5": {
9
+ "local": ("exp5_local.py", "CNN image classification - local dataset"),
10
+ "online": ("exp5_online.py", "CNN image classification - Keras CIFAR-10"),
11
+ },
12
+ "6": {
13
+ "local": ("exp6_local.py", "CNN hyperparameter tuning - local dataset"),
14
+ "online": ("exp6_online.py", "CNN hyperparameter tuning - Keras CIFAR-10"),
15
+ },
16
+ "7": {
17
+ "local": ("exp7_local.py", "Autoencoder dimensionality reduction - local CSV"),
18
+ "online": ("exp7_online.py", "Autoencoder dimensionality reduction - Keras MNIST"),
19
+ },
20
+ "8": {
21
+ "local": ("exp8_local.py", "Educational object detection - local Pascal VOC XML"),
22
+ "online": ("exp8_online.py", "Educational object detection - Pascal VOC via TFDS"),
23
+ },
24
+ "9": {
25
+ "local": ("exp9_local.py", "LSTM sentiment analysis - local CSV"),
26
+ "online": ("exp9_online.py", "LSTM sentiment analysis - Keras IMDB"),
27
+ },
28
+ "10": {
29
+ "local": ("exp10_local.py", "LSTM hyperparameter tuning - local CSV"),
30
+ "online": ("exp10_online.py", "LSTM hyperparameter tuning - Keras IMDB"),
31
+ },
32
+ }
33
+
34
+ def read_template(filename):
35
+ return (TEMPLATE_DIR / filename).read_text(encoding="utf-8")
36
+
37
+ def main():
38
+ parser = argparse.ArgumentParser(
39
+ prog="dlab-code",
40
+ description="Get ready-to-use Deep Learning experiment code.",
41
+ )
42
+ sub = parser.add_subparsers(dest="command", required=True)
43
+
44
+ get = sub.add_parser("get", help="Print or save experiment code")
45
+ get.add_argument("experiment", help="Experiment number: 5-10 or rnn-scratch")
46
+ get.add_argument(
47
+ "--dataset",
48
+ choices=["local", "online"],
49
+ default="online",
50
+ help="Dataset variant for experiments 5-10 (default: online)",
51
+ )
52
+ get.add_argument(
53
+ "--save",
54
+ metavar="FILE",
55
+ help="Save the generated code to a .py file instead of only printing it",
56
+ )
57
+
58
+ ls = sub.add_parser("list", help="List available experiments")
59
+
60
+ args = parser.parse_args()
61
+
62
+ if args.command == "list":
63
+ print("Available experiments:")
64
+ for number, variants in EXPERIMENTS.items():
65
+ print(f"\nExperiment {number}:")
66
+ for dataset, (_, description) in variants.items():
67
+ print(f" {dataset:7s} - {description}")
68
+ print("\nAdditional:")
69
+ print(" rnn-scratch - Vanilla RNN from scratch using NumPy")
70
+ return
71
+
72
+ exp = args.experiment.lower()
73
+
74
+ if exp in {"rnn-scratch", "rnn_scratch", "rnn"}:
75
+ code = read_template("rnn_scratch.py")
76
+ default_name = "rnn_from_scratch.py"
77
+ elif exp in EXPERIMENTS:
78
+ filename, _ = EXPERIMENTS[exp][args.dataset]
79
+ code = read_template(filename)
80
+ default_name = filename
81
+ else:
82
+ raise SystemExit(
83
+ "Unknown experiment. Use 'dlab-code list' to see available options."
84
+ )
85
+
86
+ if args.save:
87
+ output = Path(args.save)
88
+ output.write_text(code, encoding="utf-8")
89
+ print(f"Code saved to: {output.resolve()}")
90
+ else:
91
+ print(code)
92
+
93
+ if __name__ == "__main__":
94
+ main()
@@ -0,0 +1,120 @@
1
+ """
2
+ Experiment 10 - LSTM hyperparameter tuning using a LOCAL CSV.
3
+
4
+ CSV format:
5
+ text,label
6
+ """
7
+
8
+ import pandas as pd
9
+ import tensorflow as tf
10
+ from tensorflow import keras
11
+ from sklearn.model_selection import train_test_split
12
+ from sklearn.preprocessing import LabelEncoder
13
+
14
+ CSV_PATH = "data/sentiment.csv"
15
+ TEXT_COLUMN = "text"
16
+ LABEL_COLUMN = "label"
17
+ MAX_WORDS = 10000
18
+ MAX_LENGTH = 150
19
+
20
+ df = pd.read_csv(CSV_PATH)[[TEXT_COLUMN, LABEL_COLUMN]].dropna()
21
+
22
+ texts = df[TEXT_COLUMN].astype(str).values
23
+ encoder = LabelEncoder()
24
+ labels = encoder.fit_transform(df[LABEL_COLUMN])
25
+
26
+ X_train, X_test, y_train, y_test = train_test_split(
27
+ texts,
28
+ labels,
29
+ test_size=0.2,
30
+ random_state=42,
31
+ stratify=labels,
32
+ )
33
+
34
+ vectorizer = keras.layers.TextVectorization(
35
+ max_tokens=MAX_WORDS,
36
+ output_sequence_length=MAX_LENGTH,
37
+ )
38
+ vectorizer.adapt(X_train)
39
+
40
+ def build_model(embedding_dim, lstm_units, dropout, learning_rate):
41
+ model = keras.Sequential([
42
+ keras.layers.Input(shape=(), dtype=tf.string),
43
+ vectorizer,
44
+ keras.layers.Embedding(
45
+ input_dim=MAX_WORDS,
46
+ output_dim=embedding_dim,
47
+ mask_zero=True,
48
+ ),
49
+ keras.layers.LSTM(lstm_units),
50
+ keras.layers.Dropout(dropout),
51
+ keras.layers.Dense(
52
+ len(encoder.classes_),
53
+ activation="softmax",
54
+ ),
55
+ ])
56
+
57
+ model.compile(
58
+ optimizer=keras.optimizers.Adam(learning_rate=learning_rate),
59
+ loss="sparse_categorical_crossentropy",
60
+ metrics=["accuracy"],
61
+ )
62
+ return model
63
+
64
+ best_accuracy = -1
65
+ best_config = None
66
+
67
+ embedding_dims = [64, 128]
68
+ lstm_units_list = [32, 64]
69
+ dropouts = [0.3, 0.5]
70
+ learning_rates = [0.001, 0.0005]
71
+
72
+ for embedding_dim in embedding_dims:
73
+ for lstm_units in lstm_units_list:
74
+ for dropout in dropouts:
75
+ for learning_rate in learning_rates:
76
+ print(
77
+ f"\nembedding={embedding_dim}, "
78
+ f"LSTM={lstm_units}, dropout={dropout}, "
79
+ f"lr={learning_rate}"
80
+ )
81
+
82
+ model = build_model(
83
+ embedding_dim,
84
+ lstm_units,
85
+ dropout,
86
+ learning_rate,
87
+ )
88
+
89
+ model.fit(
90
+ X_train,
91
+ y_train,
92
+ validation_split=0.2,
93
+ epochs=5,
94
+ batch_size=32,
95
+ verbose=0,
96
+ )
97
+
98
+ _, accuracy = model.evaluate(
99
+ X_test,
100
+ y_test,
101
+ verbose=0,
102
+ )
103
+
104
+ print("Test accuracy:", round(accuracy, 4))
105
+
106
+ if accuracy > best_accuracy:
107
+ best_accuracy = accuracy
108
+ best_config = (
109
+ embedding_dim,
110
+ lstm_units,
111
+ dropout,
112
+ learning_rate,
113
+ )
114
+
115
+ print("\nBest LSTM configuration:")
116
+ print("Embedding dimension:", best_config[0])
117
+ print("LSTM units :", best_config[1])
118
+ print("Dropout :", best_config[2])
119
+ print("Learning rate :", best_config[3])
120
+ print("Test accuracy :", round(best_accuracy, 4))
@@ -0,0 +1,95 @@
1
+ """
2
+ Experiment 10 - LSTM hyperparameter tuning using the Keras IMDB dataset.
3
+ """
4
+
5
+ import numpy as np
6
+ import tensorflow as tf
7
+ from tensorflow import keras
8
+
9
+ MAX_WORDS = 10000
10
+ MAX_LENGTH = 150
11
+
12
+ (x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(
13
+ num_words=MAX_WORDS
14
+ )
15
+
16
+ x_train = keras.preprocessing.sequence.pad_sequences(
17
+ x_train, maxlen=MAX_LENGTH
18
+ )
19
+ x_test = keras.preprocessing.sequence.pad_sequences(
20
+ x_test, maxlen=MAX_LENGTH
21
+ )
22
+
23
+ def build_model(embedding_dim, lstm_units, dropout, learning_rate):
24
+ model = keras.Sequential([
25
+ keras.layers.Input(shape=(MAX_LENGTH,)),
26
+ keras.layers.Embedding(MAX_WORDS, embedding_dim),
27
+ keras.layers.LSTM(lstm_units),
28
+ keras.layers.Dropout(dropout),
29
+ keras.layers.Dense(1, activation="sigmoid"),
30
+ ])
31
+
32
+ model.compile(
33
+ optimizer=keras.optimizers.Adam(learning_rate=learning_rate),
34
+ loss="binary_crossentropy",
35
+ metrics=["accuracy"],
36
+ )
37
+ return model
38
+
39
+ best_accuracy = -1
40
+ best_config = None
41
+
42
+ embedding_dims = [64, 128]
43
+ lstm_units_list = [32, 64]
44
+ dropouts = [0.3, 0.5]
45
+ learning_rates = [0.001, 0.0005]
46
+
47
+ for embedding_dim in embedding_dims:
48
+ for lstm_units in lstm_units_list:
49
+ for dropout in dropouts:
50
+ for learning_rate in learning_rates:
51
+ print(
52
+ f"\nembedding={embedding_dim}, "
53
+ f"LSTM={lstm_units}, dropout={dropout}, "
54
+ f"lr={learning_rate}"
55
+ )
56
+
57
+ model = build_model(
58
+ embedding_dim,
59
+ lstm_units,
60
+ dropout,
61
+ learning_rate,
62
+ )
63
+
64
+ model.fit(
65
+ x_train,
66
+ y_train,
67
+ validation_split=0.2,
68
+ epochs=5,
69
+ batch_size=32,
70
+ verbose=0,
71
+ )
72
+
73
+ _, accuracy = model.evaluate(
74
+ x_test,
75
+ y_test,
76
+ verbose=0,
77
+ )
78
+
79
+ print("Test accuracy:", round(accuracy, 4))
80
+
81
+ if accuracy > best_accuracy:
82
+ best_accuracy = accuracy
83
+ best_config = (
84
+ embedding_dim,
85
+ lstm_units,
86
+ dropout,
87
+ learning_rate,
88
+ )
89
+
90
+ print("\nBest LSTM configuration:")
91
+ print("Embedding dimension:", best_config[0])
92
+ print("LSTM units :", best_config[1])
93
+ print("Dropout :", best_config[2])
94
+ print("Learning rate :", best_config[3])
95
+ print("Test accuracy :", round(best_accuracy, 4))
@@ -0,0 +1,87 @@
1
+ """
2
+ Experiment 5 - CNN image classification using a LOCAL image directory.
3
+
4
+ Expected structure:
5
+ dataset/
6
+ class_a/
7
+ image1.jpg
8
+ image2.jpg
9
+ class_b/
10
+ image3.jpg
11
+ ...
12
+
13
+ Change DATASET_PATH if required.
14
+ """
15
+
16
+ import tensorflow as tf
17
+ from tensorflow import keras
18
+ import matplotlib.pyplot as plt
19
+
20
+ DATASET_PATH = "dataset"
21
+ IMAGE_SIZE = (128, 128)
22
+ BATCH_SIZE = 32
23
+ EPOCHS = 10
24
+
25
+ train_ds = keras.utils.image_dataset_from_directory(
26
+ DATASET_PATH,
27
+ image_size=IMAGE_SIZE,
28
+ batch_size=BATCH_SIZE,
29
+ validation_split=0.2,
30
+ subset="training",
31
+ seed=42,
32
+ )
33
+
34
+ val_ds = keras.utils.image_dataset_from_directory(
35
+ DATASET_PATH,
36
+ image_size=IMAGE_SIZE,
37
+ batch_size=BATCH_SIZE,
38
+ validation_split=0.2,
39
+ subset="validation",
40
+ seed=42,
41
+ )
42
+
43
+ class_names = train_ds.class_names
44
+ num_classes = len(class_names)
45
+
46
+ normalization = keras.layers.Rescaling(1.0 / 255)
47
+ train_ds = train_ds.map(lambda x, y: (normalization(x), y))
48
+ val_ds = val_ds.map(lambda x, y: (normalization(x), y))
49
+
50
+ model = keras.Sequential([
51
+ keras.layers.Input(shape=(*IMAGE_SIZE, 3)),
52
+ keras.layers.Conv2D(32, 3, activation="relu"),
53
+ keras.layers.MaxPooling2D(),
54
+ keras.layers.Conv2D(64, 3, activation="relu"),
55
+ keras.layers.MaxPooling2D(),
56
+ keras.layers.Conv2D(128, 3, activation="relu"),
57
+ keras.layers.MaxPooling2D(),
58
+ keras.layers.Flatten(),
59
+ keras.layers.Dense(128, activation="relu"),
60
+ keras.layers.Dropout(0.5),
61
+ keras.layers.Dense(num_classes, activation="softmax"),
62
+ ])
63
+
64
+ model.compile(
65
+ optimizer="adam",
66
+ loss="sparse_categorical_crossentropy",
67
+ metrics=["accuracy"],
68
+ )
69
+
70
+ model.summary()
71
+
72
+ history = model.fit(
73
+ train_ds,
74
+ validation_data=val_ds,
75
+ epochs=EPOCHS,
76
+ )
77
+
78
+ loss, accuracy = model.evaluate(val_ds)
79
+ print(f"\nValidation accuracy: {accuracy:.4f}")
80
+
81
+ plt.plot(history.history["accuracy"], label="Training")
82
+ plt.plot(history.history["val_accuracy"], label="Validation")
83
+ plt.xlabel("Epoch")
84
+ plt.ylabel("Accuracy")
85
+ plt.legend()
86
+ plt.title("CNN Image Classification - Local Dataset")
87
+ plt.show()