### Import Keras utility to load images from directories and augment them. # Create the CNN model from tensorflow.keras.preprocessing.image import ImageDataGenerator ### Import core CNN layers and dense layers for classification. from tensorflow.keras.layers import Conv2D , MaxPooling2D , Flatten, Dense, Dropout ### Import the Sequential API to stack layers linearly. from tensorflow.keras.models import Sequential ### Import the Adam optimizer class (string alias also works). from tensorflow.keras.optimizers import Adam ### Import callbacks for training control and checkpointing. from tensorflow.keras.callbacks import EarlyStopping , ModelCheckpoint ### Import plotting to visualize training metrics after fit. import matplotlib.pyplot as plt ### Import glob to count class subfolders and infer number of classes. from glob import glob ### Set target input width in pixels. imgWidth = 256 ### Set target input height in pixels. imgHeight = 256 ### Set images processed per batch. batchSize = 32 ### Set the maximum number of training epochs. numOfEpochs = 100 ### Path to training directory that contains one subfolder per class. TRAINING_DIR = "C:/Python-cannot-upload-to-GitHub/Chessman-image-dataset/train" ### Determine number of classes by counting subdirectories under train. NumOfClasses = len(glob('C:/Python-cannot-upload-to-GitHub/Chessman-image-dataset/train/*')) # dont forget the ' /* ' ### Print the class count (should be 6 for chess pieces). print (NumOfClasses) # 6 classes ### Configure data augmentation and rescaling to 0-1 for robust training. # data augmentation to increase the train data train_datagen = ImageDataGenerator(rescale = 1/255.0, #normalize between 0 - 1 rotation_range = 30 , zoom_range = 0.4 , horizontal_flip=True, shear_range=0.4) ### Create a generator that yields augmented training batches and labels. train_generator = train_datagen.flow_from_directory(TRAINING_DIR, batch_size = batchSize, class_mode = 'categorical', target_size = (imgHeight,imgWidth)) ### Path to validation directory for on-the-fly normalization only. validation_DIR = "C:/Python-cannot-upload-to-GitHub/Chessman-image-dataset/validation" ### Rescale validation images without augmentation to measure true generalization. val_datagen = ImageDataGenerator(rescale = 1/255.0) ### Create a generator for validation batches and labels. val_generator = val_datagen.flow_from_directory(validation_DIR, batch_size = batchSize, class_mode='categorical', target_size = (imgHeight, imgWidth)) ### Define EarlyStopping to halt if validation loss stops improving. # early stopping callBack = EarlyStopping(monitor='val_loss', patience=5, verbose=1, mode='auto') ### Choose a path to save the best-performing model file by validation accuracy. # if we will find a better model we will save it here : bestModelFileName = "C:/Python-cannot-upload-to-GitHub/Chessman-image-dataset/chess_best_model.h5" ### Create a ModelCheckpoint to keep only the best model weights. bestModel = ModelCheckpoint(bestModelFileName, monitor='val_accuracy', verbose=1, save_best_only=True) ### Define a sequential CNN architecture with multiple Conv+Pool blocks. # the model : model = Sequential([ ### First convolutional block with input shape declaration. Conv2D(32, (3,3) , activation='relu' , input_shape=(imgHeight, imgWidth, 3) ) , ### Downsample feature maps to reduce spatial size. MaxPooling2D(2,2), ### Second convolutional block to increase capacity. Conv2D(64 , (3,3) , activation='relu'), ### Pooling to control overfitting and computation. MaxPooling2D(2,2), ### Third convolutional block. Conv2D(64 , (3,3) , activation='relu'), ### Pooling again to reduce spatial dimensions. MaxPooling2D(2,2), ### Fourth convolutional block with more filters for richer features. Conv2D(128 , (3,3) , activation='relu'), ### Pooling for downsampling. MaxPooling2D(2,2), ### Fifth convolutional block for high-level features. Conv2D(256 , (3,3) , activation='relu'), ### Pool to summarize features. MaxPooling2D(2,2), ### Flatten spatial maps to a vector for dense layers. Flatten(), ### Dense layer for learned combinations of features. Dense(512 , activation='relu'), ### Additional dense layer to increase representational power. Dense(512 , activation='relu'), ### Final softmax layer for multi-class probabilities. Dense(NumOfClasses , activation='softmax') # softmax -> 0 to 1 ]) ### Print a model summary for verification of layers and params. print (model.summary() ) ### Compile with Adam optimizer and categorical cross-entropy for multi-class labels. # compile the model with Adam optimizer model.compile(optimizer='Adam', loss='categorical_crossentropy', metrics=['accuracy']) ### Train the model with validation monitoring and checkpointing. history = model.fit(train_generator, epochs = numOfEpochs, verbose=1, validation_data = val_generator, callbacks = [bestModel]) ### Extract accuracy and loss from the training history for plotting. # display the result using pyplot acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss'] ### Prepare an array of epoch indices for plotting curves. epochs = range(len(acc)) # for the max value in the diagram ### Plot training vs validation accuracy. # accuracy chart fig = plt.figure(figsize=(14,7)) plt.plot(epochs, acc , 'r', label="Train accuracy") plt.plot(epochs, val_acc , 'b', label="Validation accuracy") plt.xlabel('Epochs') plt.ylabel('Accuracy') plt.title('Train and validation accuracy') plt.legend(loc='lower right') plt.show() ### Plot training vs validation loss. #loss chart fig2 = plt.figure(figsize=(14,7)) plt.plot(epochs, loss , 'r', label="Train loss") plt.plot(epochs, val_loss , 'b', label="Validation loss") plt.xlabel('Epochs') plt.ylabel('Loss') plt.title('Train and validation Loss') plt.legend(loc='upper right') plt.show()