### 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 ()