In [1]:
# Importing necessary libraries
import os
import numpy as np
import random
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision import datasets, transforms
from torch.utils.data import DataLoader, WeightedRandomSampler, Subset
from torchsummary import summary
from PIL import Image
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
import matplotlib.pyplot as plt
# Checking for GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"\nUsing device: {device}\n")
Using device: cuda
In [2]:
# Defining the dataset path
dataset_path = "PBC_dataset_normal_DIB"
# Applying Transformations for data preprocessing
transform = transforms.Compose([
transforms.Resize((360, 360)), # Resizing to 360x360
transforms.RandomHorizontalFlip(p=0.5), # Applying Horizontal flip with 50% probability
transforms.RandomRotation(degrees=15), # Applying Rotation range of 15 degrees
transforms.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3, hue=0.1), # Applying Color jitter parameters
transforms.RandomAffine(degrees=10, scale=(0.9, 1.1)), # Adding affine transformations
transforms.ToTensor(), # Converting images to PyTorch tensors
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) # Normalizing the range to [-1, 1]
])
In [3]:
# Loading of dataset
print("Loading dataset...\n")
dataset = datasets.ImageFolder(root=dataset_path, transform=transform)
# Printing the classes (folders) being loaded
print("Classes found in dataset:\n")
for cls, count in zip(dataset.classes, np.bincount([sample[1] for sample in dataset.samples])):
print(f" - {cls}: {count} images")
# Getting dataset's indices and labels
indices = np.arange(len(dataset))
labels = [label for _, label in dataset.samples]
# Performing train - test split (75% train, 25% test)
train_indices, test_indices = train_test_split(indices, test_size=0.25, stratify=labels, random_state=42)
# Creating subsets for train and test
train_dataset = Subset(dataset, train_indices)
test_dataset = Subset(dataset, test_indices)
# Calculating class weights for the training set
train_labels = [dataset.samples[i][1] for i in train_indices]
train_class_counts = np.bincount(train_labels)
train_class_weights = 1.0 / train_class_counts
train_class_weights = torch.tensor(train_class_weights, dtype=torch.float)
# Applying Weighted sampler for training set
train_sample_weights = [train_class_weights[label] for label in train_labels]
train_sampler = WeightedRandomSampler(train_sample_weights, num_samples=len(train_sample_weights), replacement=True)
test_loader = DataLoader(test_dataset, batch_size=8, shuffle=True) # Regular shuffling for testing
# Creating of DataLoaders
train_loader = DataLoader(train_dataset, batch_size=8, sampler=train_sampler)
# Printing the number of images per class in the train and test splits
train_class_counts_split = np.bincount([train_labels[i] for i in range(len(train_labels))])
test_labels = [dataset.samples[i][1] for i in test_indices]
test_class_counts_split = np.bincount([test_labels[i] for i in range(len(test_labels))])
print("\nNumber of images per class in the training set (75%):\n")
for cls, count in zip(dataset.classes, train_class_counts_split):
print(f" - {cls}: {count} images")
print("\nNumber of images per class in the testing set (25%):\n")
for cls, count in zip(dataset.classes, test_class_counts_split):
print(f" - {cls}: {count} images")
Loading dataset... Classes found in dataset: - Basophil: 1218 images - Eosinophil: 3117 images - Erythroblast: 1551 images - Ig: 2895 images - Lymphocyte: 1214 images - Monocyte: 1420 images - Neutrophil: 3329 images - Platelet: 2348 images Number of images per class in the training set (75%): - Basophil: 913 images - Eosinophil: 2338 images - Erythroblast: 1163 images - Ig: 2171 images - Lymphocyte: 911 images - Monocyte: 1065 images - Neutrophil: 2497 images - Platelet: 1761 images Number of images per class in the testing set (25%): - Basophil: 305 images - Eosinophil: 779 images - Erythroblast: 388 images - Ig: 724 images - Lymphocyte: 303 images - Monocyte: 355 images - Neutrophil: 832 images - Platelet: 587 images
In [4]:
class ForwardConvBlock(nn.Module):
def __init__(self, in_channels, out_channels):
super(ForwardConvBlock, self).__init__()
self.conv_block = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True),
nn.BatchNorm2d(out_channels),
nn.LeakyReLU(0.1, inplace=True),
nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True),
nn.BatchNorm2d(out_channels),
nn.LeakyReLU(0.1, inplace=True),
)
def forward(self, x):
return self.conv_block(x)
class BCNet(nn.Module):
def __init__(self, num_classes=8):
super(BCNet, self).__init__()
# Initial Convolution
self.initial_conv = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1, bias=True),
nn.BatchNorm2d(32),
nn.LeakyReLU(0.1, inplace=True),
)
# Forward Conv. Blocks
self.for_block1 = ForwardConvBlock(32, 64)
self.for_block2 = ForwardConvBlock(64, 128)
self.for_block3 = ForwardConvBlock(128, 256)
self.for_block4 = ForwardConvBlock(256, 512)
# Max Pooling
self.pool = nn.MaxPool2d(2, 2)
# Global Average Pooling
self.global_avg_pool = nn.AdaptiveAvgPool2d(1)
# Fully Connected Layers
self.fc = nn.Sequential(nn.Linear(512, num_classes))
# Softmax
self.softmax = nn.Softmax(dim=1)
def forward(self, x):
x = self.initial_conv(x)
x = self.pool(self.for_block1(x))
x = self.pool(self.for_block2(x))
x = self.pool(self.for_block3(x))
x = self.pool(self.for_block4(x))
x = self.global_avg_pool(x)
x = x.view(x.size(0), -1) # Flatten for the fully connected layer
x = self.fc(x)
x = self.softmax(x)
return x
In [5]:
# Defining the model
model = BCNet(num_classes=8)
# Moving the model to the device (GPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
# Printing the model summary
print("\nModel Summary:")
summary(model, input_size=(3, 360, 360))
# Checking the size of the first batch of images
for inputs, labels in train_loader:
print(inputs.shape)
break
Model Summary: ---------------------------------------------------------------- Layer (type) Output Shape Param # ================================================================ Conv2d-1 [-1, 32, 360, 360] 896 BatchNorm2d-2 [-1, 32, 360, 360] 64 LeakyReLU-3 [-1, 32, 360, 360] 0 Conv2d-4 [-1, 64, 360, 360] 18,496 BatchNorm2d-5 [-1, 64, 360, 360] 128 LeakyReLU-6 [-1, 64, 360, 360] 0 Conv2d-7 [-1, 64, 360, 360] 36,928 BatchNorm2d-8 [-1, 64, 360, 360] 128 LeakyReLU-9 [-1, 64, 360, 360] 0 ForwardConvBlock-10 [-1, 64, 360, 360] 0 MaxPool2d-11 [-1, 64, 180, 180] 0 Conv2d-12 [-1, 128, 180, 180] 73,856 BatchNorm2d-13 [-1, 128, 180, 180] 256 LeakyReLU-14 [-1, 128, 180, 180] 0 Conv2d-15 [-1, 128, 180, 180] 147,584 BatchNorm2d-16 [-1, 128, 180, 180] 256 LeakyReLU-17 [-1, 128, 180, 180] 0 ForwardConvBlock-18 [-1, 128, 180, 180] 0 MaxPool2d-19 [-1, 128, 90, 90] 0 Conv2d-20 [-1, 256, 90, 90] 295,168 BatchNorm2d-21 [-1, 256, 90, 90] 512 LeakyReLU-22 [-1, 256, 90, 90] 0 Conv2d-23 [-1, 256, 90, 90] 590,080 BatchNorm2d-24 [-1, 256, 90, 90] 512 LeakyReLU-25 [-1, 256, 90, 90] 0 ForwardConvBlock-26 [-1, 256, 90, 90] 0 MaxPool2d-27 [-1, 256, 45, 45] 0 Conv2d-28 [-1, 512, 45, 45] 1,180,160 BatchNorm2d-29 [-1, 512, 45, 45] 1,024 LeakyReLU-30 [-1, 512, 45, 45] 0 Conv2d-31 [-1, 512, 45, 45] 2,359,808 BatchNorm2d-32 [-1, 512, 45, 45] 1,024 LeakyReLU-33 [-1, 512, 45, 45] 0 ForwardConvBlock-34 [-1, 512, 45, 45] 0 MaxPool2d-35 [-1, 512, 22, 22] 0 AdaptiveAvgPool2d-36 [-1, 512, 1, 1] 0 Linear-37 [-1, 8] 4,104 Softmax-38 [-1, 8] 0 ================================================================ Total params: 4,710,984 Trainable params: 4,710,984 Non-trainable params: 0 ---------------------------------------------------------------- Input size (MB): 1.48 Forward/backward pass size (MB): 955.07 Params size (MB): 17.97 Estimated Total Size (MB): 974.52 ---------------------------------------------------------------- torch.Size([8, 3, 360, 360])
In [6]:
# Setting up the loss function and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# Training parameters
epochs = 8
train_losses = []
train_accuracies = []
# Using mixed precision for faster training
scaler = torch.amp.GradScaler()
print("\nTraining Process is going on.........\n")
# Training Loop
for epoch in range(epochs):
model.train() # Setting the model to training mode
running_loss = 0.0
correct = 0
total = 0
for inputs, labels in train_loader:
inputs, labels = inputs.to(device), labels.to(device)
# Zero the gradients
optimizer.zero_grad()
# Mixed precision
with torch.amp.autocast(device_type='cuda' if torch.cuda.is_available() else 'cpu'):
outputs = model(inputs)
loss = criterion(outputs, labels)
# Scaling the loss, calling backward(), and updating the optimizer
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
# Tracking the loss
running_loss += loss.item()
# Calculating the accuracy
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# Average loss and accuracy for this perticular epoch
epoch_loss = running_loss / len(train_loader)
epoch_accuracy = 100 * correct / total
train_losses.append(epoch_loss)
train_accuracies.append(epoch_accuracy)
print(f"Epoch [{epoch+1}/{epochs}], Loss: {epoch_loss:.4f}, Accuracy: {epoch_accuracy:.2f}%")
print("\nTraining is Completed!\n")
mean_loss = sum(train_losses) / len(train_losses)
mean_accuracy = sum(train_accuracies) / len(train_accuracies)
print("\n---------------------------------------------------------------------------\n")
Training Process is going on......... Epoch [1/8], Loss: 1.9505, Accuracy: 30.93% Epoch [2/8], Loss: 1.8462, Accuracy: 43.58% Epoch [3/8], Loss: 1.7099, Accuracy: 58.11% Epoch [4/8], Loss: 1.6326, Accuracy: 65.39% Epoch [5/8], Loss: 1.5896, Accuracy: 69.28% Epoch [6/8], Loss: 1.5549, Accuracy: 72.56% Epoch [7/8], Loss: 1.5231, Accuracy: 75.60% Epoch [8/8], Loss: 1.5027, Accuracy: 77.79% Training is Completed! ---------------------------------------------------------------------------
In [7]:
# Plotting the Training Loss and Accuracy
plt.figure(figsize=(12, 5))
# Plotting Loss Graph
plt.subplot(1, 2, 1)
plt.plot(range(1, epochs + 1), train_losses, label='Training Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.grid(True)
# Plotting Accuracy Graph
plt.subplot(1, 2, 2)
plt.plot(range(1, epochs + 1), train_accuracies, label='Training Accuracy', color='green')
plt.xlabel('Epochs')
plt.ylabel('Accuracy (%)')
plt.title('Training Accuracy')
plt.grid(True)
plt.tight_layout()
plt.show()
In [8]:
# Saving the graph as an image file
plt.savefig('Training_Graph.png')
print("Training Graph saved to 'Training_Graph.png'\n")
# Saving the model weights
torch.save(model.state_dict(), "Trained_MBC_Data.pth")
print("Model saved to 'Trained_MBC_Data.pth'\n")
Training Graph saved to 'Training_Graph.png' Model saved to 'Trained_MBC_Data.pth'
<Figure size 640x480 with 0 Axes>
In [9]:
# Setting the model to evaluation / testing mode
model.eval()
print("\n\nTesting Process is going on.........\n")
# Initializing variables to track loss and accuracy
test_loss = 0.0
correct_preds_test = 0
total_preds_test = 0
all_preds = []
all_labels = []
class_names = ['Basophil', 'Eosinophil', 'Erythroblast', 'Ig', 'Lymphocyte', 'Monocyte', 'Neutrophil', 'Platelet']
# Using the same loss function and optimizer used during training
criterion = torch.nn.CrossEntropyLoss()
# Evaluating the model on the test dataset
with torch.no_grad():
for images, labels in test_loader:
images, labels = images.to(device), labels.to(device)
outputs = model(images) # Forward pass
# Computing the loss
loss = criterion(outputs, labels)
test_loss += loss.item() * images.size(0) # Accumulating the loss
# Computing the accuracy
_, predicted = torch.max(outputs, 1)
correct_preds_test += (predicted == labels).sum().item()
total_preds_test += labels.size(0)
# Collecting predictions and labels for classification report
all_preds.extend(predicted.cpu().numpy())
all_labels.extend(labels.cpu().numpy())
# Calculating the average test loss and accuracy
test_loss /= len(test_loader.dataset)
test_accuracy = (correct_preds_test / total_preds_test ) * 100
print("\nTesting is Completed!\n")
Testing Process is going on......... Testing is Completed!
In [10]:
# Printing the detailed classification report
print("Classification Report on Testing Set:\n")
print(classification_report(all_labels, all_preds, target_names=class_names))
Classification Report on Testing Set: precision recall f1-score support Basophil 0.37 0.94 0.53 305 Eosinophil 0.91 0.83 0.86 779 Erythroblast 0.76 0.82 0.79 388 Ig 0.74 0.15 0.25 724 Lymphocyte 0.73 0.73 0.73 303 Monocyte 0.75 0.70 0.73 355 Neutrophil 0.76 0.93 0.84 832 Platelet 0.98 0.95 0.97 587 accuracy 0.74 4273 macro avg 0.75 0.76 0.71 4273 weighted avg 0.78 0.74 0.72 4273
In [11]:
# Printing the file names of the test set images for each class
test_class_names = dataset.classes
test_class_files = {cls: [] for cls in test_class_names}
# Retrieving samples of the test dataset
test_samples = [dataset.samples[idx] for idx in test_dataset.indices]
# Collecting file names for each class
for file_path, label in test_samples:
test_class_name = class_names[label]
test_class_files[test_class_name].append(file_path)
# Printing file names for each class (showing 10 files per class)
for test_class_name, files in test_class_files.items():
print(f"\nClass: {test_class_name}\n")
for file in files[:10]:
print(f" {file}")
# Function to load an image from a file path and predict its class
def classify_image(image_path):
# Loading the image
image = Image.open(image_path)
image = transform(image).unsqueeze(0).to(device)
# Displaying the input image
img_disp = image.squeeze(0).cpu()
img_disp = img_disp.permute(1, 2, 0) # CHW → HWC
img_disp = (img_disp - img_disp.min()) / (img_disp.max() - img_disp.min()) # scale to [0, 1]
plt.imshow(img_disp)
plt.title(f"Input Image")
plt.axis('off')
plt.show()
# Model inference (i.e., Classification)
output = model(image)
_, predicted = torch.max(output, 1) # Getting the predicted class
# Getting the class label
predicted_label = predicted.item()
# The true label can be obtained directly from the folder structure
true_class_label = class_names.index(image_path.split('/')[-2])
# Checking if classification is correct or wrong
if predicted_label == true_class_label:
classification_status = "Yay!!! Correct Classification. I now think I can classify the Blood Cells."
else:
classification_status = "Oops!!! Wrong Classification. I think I should train hard to classify the Blood Cells."
# Printing the results
print(f"\nTrue Class of the Blood Cell: {class_names[true_class_label]}")
print(f"Predicted Class of the Blood Cell: {class_names[predicted_label]}")
print(f"\n{classification_status}")
Class: Basophil PBC_dataset_normal_DIB/Basophil/BA_46660.jpg PBC_dataset_normal_DIB/Basophil/BA_589260.jpg PBC_dataset_normal_DIB/Basophil/BA_365212.jpg PBC_dataset_normal_DIB/Basophil/BA_600449.jpg PBC_dataset_normal_DIB/Basophil/BA_981874.jpg PBC_dataset_normal_DIB/Basophil/BA_912566.jpg PBC_dataset_normal_DIB/Basophil/BA_572677.jpg PBC_dataset_normal_DIB/Basophil/BA_80990.jpg PBC_dataset_normal_DIB/Basophil/BA_66312.jpg PBC_dataset_normal_DIB/Basophil/BA_121897.jpg Class: Eosinophil PBC_dataset_normal_DIB/Eosinophil/EO_464699.jpg PBC_dataset_normal_DIB/Eosinophil/EO_198556.jpg PBC_dataset_normal_DIB/Eosinophil/EO_189413.jpg PBC_dataset_normal_DIB/Eosinophil/EO_398624.jpg PBC_dataset_normal_DIB/Eosinophil/EO_316082.jpg PBC_dataset_normal_DIB/Eosinophil/EO_817196.jpg PBC_dataset_normal_DIB/Eosinophil/EO_53483.jpg PBC_dataset_normal_DIB/Eosinophil/EO_336692.jpg PBC_dataset_normal_DIB/Eosinophil/EO_661088.jpg PBC_dataset_normal_DIB/Eosinophil/EO_195696.jpg Class: Erythroblast PBC_dataset_normal_DIB/Erythroblast/ERB_267711.jpg PBC_dataset_normal_DIB/Erythroblast/ERB_705706.jpg PBC_dataset_normal_DIB/Erythroblast/ERB_567457.jpg PBC_dataset_normal_DIB/Erythroblast/ERB_934384.jpg PBC_dataset_normal_DIB/Erythroblast/ERB_956878.jpg PBC_dataset_normal_DIB/Erythroblast/ERB_959509.jpg PBC_dataset_normal_DIB/Erythroblast/ERB_512946.jpg PBC_dataset_normal_DIB/Erythroblast/ERB_631080.jpg PBC_dataset_normal_DIB/Erythroblast/ERB_752263.jpg PBC_dataset_normal_DIB/Erythroblast/ERB_48740.jpg Class: Ig PBC_dataset_normal_DIB/Ig/MY_866747.jpg PBC_dataset_normal_DIB/Ig/MMY_48577.jpg PBC_dataset_normal_DIB/Ig/MY_482727.jpg PBC_dataset_normal_DIB/Ig/PMY_241.jpg PBC_dataset_normal_DIB/Ig/MMY_696538.jpg PBC_dataset_normal_DIB/Ig/MMY_917920.jpg PBC_dataset_normal_DIB/Ig/MMY_803720.jpg PBC_dataset_normal_DIB/Ig/PMY_548200.jpg PBC_dataset_normal_DIB/Ig/MMY_63678.jpg PBC_dataset_normal_DIB/Ig/MMY_873744.jpg Class: Lymphocyte PBC_dataset_normal_DIB/Lymphocyte/LY_424808.jpg PBC_dataset_normal_DIB/Lymphocyte/LY_393334.jpg PBC_dataset_normal_DIB/Lymphocyte/LY_168926.jpg PBC_dataset_normal_DIB/Lymphocyte/LY_444522.jpg PBC_dataset_normal_DIB/Lymphocyte/LY_647287.jpg PBC_dataset_normal_DIB/Lymphocyte/LY_754771.jpg PBC_dataset_normal_DIB/Lymphocyte/LY_700280.jpg PBC_dataset_normal_DIB/Lymphocyte/LY_382149.jpg PBC_dataset_normal_DIB/Lymphocyte/LY_245917.jpg PBC_dataset_normal_DIB/Lymphocyte/LY_592355.jpg Class: Monocyte PBC_dataset_normal_DIB/Monocyte/MO_854196.jpg PBC_dataset_normal_DIB/Monocyte/MO_225079.jpg PBC_dataset_normal_DIB/Monocyte/MO_344372.jpg PBC_dataset_normal_DIB/Monocyte/MO_68925.jpg PBC_dataset_normal_DIB/Monocyte/MO_660670.jpg PBC_dataset_normal_DIB/Monocyte/MO_648679.jpg PBC_dataset_normal_DIB/Monocyte/MO_686892.jpg PBC_dataset_normal_DIB/Monocyte/MO_377587.jpg PBC_dataset_normal_DIB/Monocyte/MO_463322.jpg PBC_dataset_normal_DIB/Monocyte/MO_560988.jpg Class: Neutrophil PBC_dataset_normal_DIB/Neutrophil/BNE_7938.jpg PBC_dataset_normal_DIB/Neutrophil/SNE_825561.jpg PBC_dataset_normal_DIB/Neutrophil/BNE_477145.jpg PBC_dataset_normal_DIB/Neutrophil/SNE_721798.jpg PBC_dataset_normal_DIB/Neutrophil/SNE_790875.jpg PBC_dataset_normal_DIB/Neutrophil/BNE_417307.jpg PBC_dataset_normal_DIB/Neutrophil/SNE_987130.jpg PBC_dataset_normal_DIB/Neutrophil/SNE_42209.jpg PBC_dataset_normal_DIB/Neutrophil/SNE_891808.jpg PBC_dataset_normal_DIB/Neutrophil/BNE_939554.jpg Class: Platelet PBC_dataset_normal_DIB/Platelet/PLATELET_113142.jpg PBC_dataset_normal_DIB/Platelet/PLATELET_570398.jpg PBC_dataset_normal_DIB/Platelet/PLATELET_894861.jpg PBC_dataset_normal_DIB/Platelet/PLATELET_102535.jpg PBC_dataset_normal_DIB/Platelet/PLATELET_15706.jpg PBC_dataset_normal_DIB/Platelet/PLATELET_809212.jpg PBC_dataset_normal_DIB/Platelet/PLATELET_273514.jpg PBC_dataset_normal_DIB/Platelet/PLATELET_662037.jpg PBC_dataset_normal_DIB/Platelet/PLATELET_249998.jpg PBC_dataset_normal_DIB/Platelet/PLATELET_237971.jpg
In [ ]:
# Main loop to continuously ask the user to input an image
while True:
# Prompting the user to input the path to an image and validate the path
while True:
image_path = input("\nEnter the path to the Test Image from the file names given above:").strip()
# Checking if the path ends with .jpg
if image_path.lower().endswith('.jpg'):
# Checking if the file exists
if os.path.isfile(image_path):
break
else:
print("\nThe file does not exist. Please Try again.")
else:
print("\nThe file must be a .jpg file. Please Try again.")
# Calling the function to classify the image
classify_image(image_path)
# Asking the user if they want to classify another image or not
while True:
repeat = input("\nDo you want to classify another image? (yes/no): ").strip().lower()
if repeat == 'yes':
break
elif repeat == 'no':
print("\nExiting the Program. Thank you!\n")
loop_exit = True
break
else:
print("\nInvalid input. Please type 'yes' or 'no'")
if 'loop_exit' in locals() and loop_exit:
break
True Class of the Blood Cell: Basophil Predicted Class of the Blood Cell: Basophil Yay!!! Correct Classification. I now think I can classify the Blood Cells.
True Class of the Blood Cell: Eosinophil Predicted Class of the Blood Cell: Eosinophil Yay!!! Correct Classification. I now think I can classify the Blood Cells.
True Class of the Blood Cell: Erythroblast Predicted Class of the Blood Cell: Erythroblast Yay!!! Correct Classification. I now think I can classify the Blood Cells.
True Class of the Blood Cell: Ig Predicted Class of the Blood Cell: Basophil Oops!!! Wrong Classification. I think I should train hard to classify the Blood Cells.
True Class of the Blood Cell: Lymphocyte Predicted Class of the Blood Cell: Basophil Oops!!! Wrong Classification. I think I should train hard to classify the Blood Cells.
True Class of the Blood Cell: Monocyte Predicted Class of the Blood Cell: Monocyte Yay!!! Correct Classification. I now think I can classify the Blood Cells.
True Class of the Blood Cell: Neutrophil Predicted Class of the Blood Cell: Neutrophil Yay!!! Correct Classification. I now think I can classify the Blood Cells.
In [ ]:
!jupyter nbconvert --to html MBC_Project.ipynb
In [ ]: