Department of Computer Science and Engineering
SESSION- 2024-25
“MAJOR PROJECT REPORT SYNOPSIS”
On
“Deep Learning Methods For Breast Cancer Detection Using
Histopathology Images ”
Submitted In partial Fulfillment for the degree of Bachelor of
Technology in Computer Science and Engineering
SUBMITTED BY: GUIDED BY:
Scholar Name (Scholar No.) Supervisor Name
211112262- Vaibhav Patel Dr. MANASI GYANCHANDANI
211112276- Shivam Prabhu Associate Professor
211112201- Amrit Raj Computer Science & engineering
211112261- Shaswat Kashyap MANIT BHOPAL
I hereby declare that the work, which is presented in this Project Report,
entitled "Deep Learning Methods For Breast Cancer Detection" in partial
fulfillment of the requirements for the award of the degree, submitted in the
Department of Computer Science and Engineering, Maulana Azad National
Institute of Technology, Bhopal. It is an authentic record of my work carried
out from to under the noble guidance of my guide "Dr. Manasi Gyanchandani."
The following project and its report, in part or whole, have not been presented
or submitted by me for any purpose in any other institute or organization. We
hereby declare that the facts mentioned above are true to the best of our
knowledge. In case of any unlikely discrepancy that may possibly occur, we will
take responsibility.
CERTIFICATE
This is to certify that the project entitled "Deep Learning Methods For Breast
Cancer Detection" Submitted by:
Students of B.Tech 4th Year in Computer Science & Engineering, have
successfully completed their project in partial fulfillment of their Bachelor of
Technology in Computer Science & Engineering, and is an authentic work
carried out by them under my supervision and guidance.
INTRODUCTION
Breast cancer is one of the most prevalent cancers worldwide, and early detection
is crucial for effective treatment and improved survival rates. Traditional
diagnostic methods, while essential, can sometimes be slow and subject to
interpretation. With the rise of artificial intelligence (AI) in healthcare, machine
learning (ML) and deep learning have introduced new ways to enhance the
accuracy and efficiency of breast cancer detection, offering valuable support in
medical diagnostics.
Deep neural networks (DNNs) and convolutional neural networks (CNNs) are
advanced AI models that have proven particularly effective in analyzing medical
images. These networks can automatically learn to recognize complex patterns in
large datasets, such as histopathology images, helping to identify potential signs
of cancer with minimal human intervention. CNNs, in particular, are well-suited
for image analysis due to their ability to capture spatial patterns and distinguish
between benign and malignant features.
This report explores the use of CNNs in breast cancer detection, demonstrating
how these models can aid in identifying tumors more accurately and efficiently
than some traditional methods. As deep learning technology continues to evolve,
it holds significant potential for advancing early cancer diagnosis and improving
patient outcomes across healthcare.
PROBLEM STATEMENT
The synopsis outlines advancements in breast cancer detection through machine
learning (ML) and deep learning, particularly using Convolutional Neural Networks
(CNNs). Breast cancer is a significant health issue globally, and early, accurate
diagnosis is critical for improving survival rates. Traditional diagnostic methods like
mammography and ultrasound have limitations in terms of sensitivity and
specificity, often leading to false positives or missed detections.
In response, ML and CNN models have become prominent due to their ability to
analyze vast amounts of medical imaging data. CNNs, in particular, excel in image
recognition and classification tasks, making them ideal for detecting abnormalities
in breast tissue. Existing ML solutions include support vector machines (SVMs) and
k-nearest neighbors (KNN), which classify breast tissue types based on image
features. However, these methods rely heavily on feature extraction and are less
adaptive than deep learning models.
Deep learning approaches, primarily CNNs, provide automated feature extraction
and higher accuracy rates by learning complex patterns directly from image data.
Despite their promise, CNN-based systems face limitations, such as high
computational requirements and a need for extensive, diverse datasets to
improve generalizability and reduce bias in detection outcomes.
OBJECTIVE
The primary objectives of this project in breast cancer detection using
Convolutional Neural Networks (CNN) and machine learning methods include:
1. Enhanced Detection Accuracy: To develop a CNN model that improves the
accuracy of breast cancer detection by identifying subtle patterns in medical
imaging data, reducing false positives and negatives. This model aims to
assist radiologists in achieving earlier, more reliable diagnosis.
2. Automated Feature Extraction: Unlike traditional machine learning models
that rely on manual feature extraction, the project’s CNN model will
automatically extract relevant features from breast tissue images,
streamlining the process and enhancing diagnostic precision.
3. Scalability: To design the model with a scalable framework, allowing
integration with diverse datasets and adaptability to new imaging
technologies, facilitating widespread application across healthcare facilities.
4. User Interface Design: To build a user-friendly interface that enables
medical professionals to interact seamlessly with the system, view results,
and make informed decisions with minimal training.
5. Performance Optimization: By optimizing the computational efficiency of
the model, the project aims to deliver fast and reliable predictions, ensuring
feasibility in clinical settings where quick turnaround times are essential.
2 . Literature review and survey
Paper Author Methods
Breast cancer detection R. Sathesh Raaj Radon transform, a data
and diagnosis using hybrid augmentation module, and a hybrid
deep learning architecture
[12] AlexNet CNN architecture
Breast Cancer Detection Ömer Faruk Ereken; Cigdem Proposed an ensemble of deep
using Convolutional Tarhan learning models for the detection
Neural Networks of breast cancer in histopathology
images.
3
Convolutional Neural Networks (CNN):
Convolutional Neural Networks (CNNs) are a class of deep learning models designed
primarily for processing grid-like data, such as images. Convolutional Neural Network
consists of multiple layers like the input layer, Convolutional layer, Pooling layer, and
fully connected layers.
The Convolutional layer applies filters to the input image to extract features, the Pooling
layer downsamples the image to reduce computation, and the fully connected layer
makes the final prediction. The network learns the optimal filters through backpropagation
and gradient descent.
Fig.2.3.1 Layers of CNN [ CNN ]
CNNs have demonstrated impressive performance in various medical imaging tasks,
including breast cancer detection, where they excel at learning hierarchical features from
histopathology images.
Types of CNN Layers:
CNNs are composed of several types of layers that work together to process and extract
meaningful features from input data. Convolutional layers apply convolution operations
to detect patterns and features in the data. There are many types of layers used to build
Convolutional Neural Networks, but the ones you are most likely to encounter include:
6
● Convolutional (CONV)
● Activation (ACT or RELU, where we use the same or the actual activation function)
● Pooling (POOL)
● Fully connected (FC)
● Batch normalization (BN)
● Dropout (DO)
ReLU (Rectified Linear Unit) Activation Function:
The Rectified Linear Unit (ReLU) activation function plays a pivotal role in the
convolutional neural network (CNN) model utilized for breast cancer image classification.
It introduces non-linearity by outputting the input directly if it is positive; otherwise, it
outputs zero. ReLU activation is applied after each convolutional layer, enabling the
model to learn intricate patterns and features from the input images effectively. By
facilitating non-linear transformations, ReLU aids in the model's ability to capture
complex relationships within the data, contributing to its classification performance.
Fig.2.3.2 ReLU Activation Function [ ReLU ]
Adam Optimizer: In the CNN model for breast cancer image classification, the Adaptive
Moment Estimation (Adam) optimizer serves as a crucial component for optimizing
model parameters during training. Adam is an adaptive learning rate optimization
algorithm that dynamically adjusts the learning rate for each parameter based on past
gradients and current gradients. By leveraging both AdaGrad and RMSProp optimizers,
Adam facilitates faster convergence and efficient handling of sparse gradients. This
adaptive learning rate scheme enables the CNN model to converge more rapidly and
7
effectively during the training process, enhancing its ability to learn discriminative features
from the input data.
Max Pooling Layer:
The Max Pooling layer is instrumental in the down-sampling process within the CNN
model employed for breast cancer image classification. This layer contributes to the
reduction of spatial dimensions in the feature maps while retaining crucial features
extracted by the convolutional layers. By selecting the maximum value within a sliding
window, Max Pooling summarizes significant features and enhances the network's
computational efficiency. Furthermore, it aids in improving the model's generalization
performance by abstracting the most salient information from the feature maps, thereby
promoting robustness to variations in input data. Overall, Max Pooling facilitates efficient
feature extraction and spatial summarization, contributing to the CNN model's
effectiveness in classifying breast cancer images.
GoogleNet Architecture:
GoogleNet proposed by the researchers at Google is a 22-layer deep CNN model
containing inception blocks. In an Inception block, several convolutional layers have
been working simultaneously, which contains a sparse architecture that helps dimension
reduction. GoogleNet is renowned for its depth and computational efficiency, as it
achieves high accuracy with significantly fewer parameters compared to other deep
architectures at the time.
Fig.2.4.1 GoogleNet Architecture [GoogleNet Architecture]
Here are the key features of the GoogleNet architecture:
Inception Modules:
8
● The hallmark of GoogleNet is its Inception modules, which allow for efficient use
of computational resources by performing parallel convolutions at multiple scales.
● Each Inception module consists of several parallel convolutional layers with different
kernel sizes (1x1, 3x3, 5x5) and max pooling, concatenated along the depth dimension.
● By incorporating multiple kernel sizes in parallel, the network can capture features
at different spatial scales, facilitating better feature representation and learning.
Fig 2.4.2 Inception module in GoogleNet architecture [Inception modeule]
Network Depth :
● GoogleNet comprises multiple stacked Inception modules, allowing for increased
depth without significantly increasing the number of parameters.
● The depth of the network enables it to capture complex hierarchical features across
multiple scales, leading to improved performance on various image recognition tasks.
Auxiliary Classifiers:
● GoogleNet includes auxiliary classifiers at intermediate layers of the network to
alleviate the vanishing gradient problem during training.
● These auxiliary classifiers consist of convolutional and pooling layers followed by
fully connected layers and softmax activation.
● The gradients from these auxiliary classifiers are used for auxiliary loss computation
during training, aiding in the overall training process and enabling better feature
propagation.
Global Average Pooling :
9
● Instead of traditional fully connected layers at the end of the network, GoogleNet
employs global average pooling to reduce overfitting and the number of parameters.
● Global average pooling computes the average value of each feature map across
spatial dimensions, resulting in a fixed-size feature vector.
● The final layer of the network consists of a softmax classifier applied to the global
average pooled feature vector, producing class probabilities.
Computational Efficiency:
● Despite its depth and complexity, GoogleNet achieves high accuracy with relatively
fewer parameters compared to previous CNN architectures.
● This efficiency is achieved through the use of the Incep on modules, which exploit parallel
convolu ons and reduce redundant computa ons, making the network suitable for
deployment on resource-constrained devices.
10
CNN MODEL
Importing Necessary Libraries
In [20]:
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Conv1D,
MaxPool1D,Flatten,Dense,Dropout,BatchNormalization
from tensorflow.keras.optimizers import Adam
In [21]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
In [22]:
from sklearn import datasets,metrics
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
Loading the Built-in Sklearn Breast Cancer Dataset
In [23]:
cancerData = datasets.load_breast_cancer()
In [24]:
X = pd.DataFrame(data = cancerData.data, columns=cancerData.feature_names
)
X.head()
Out[24]:
m
w
e
w or
m a m w
m o st wo
e n ea o w
e m m m r w c w rst
a m c n r o w
a ea e me me ea s or wor wor o or fra
n ea o fra s r or
n n a an an n t st st st n st ct
t n n ct . t s st
r pe n sm com sy t pe sm com c sy al
e co c al . r t co
a ri a oot pact m e ri oot pact a m di
x nc a di . a a nc
d m r hne nes m x m hne nes v m m
t av v m d r av
i et e ss s etr t et ss s e etr en
u ity e en i e ity
u er a y u er p y sio
r p sio u a
s r oi n
e oi n s
e nt
nt
s
s
1 0. 2
1 1 2 1 0.
0 1 0. 0 0.
7 0 12 0.1 0.2 0. 0. . 5 7 18 0. 2 0.
0 4 07 1 0.1 0.6 11
0 . . 2. 184 776 30 24 . . . 4. 71 6 46
1 7 87 9 622 656 89
9 3 80 0 0 01 19 . 3 3 60 19 5 01
. 1 1 . 0
9 8 8 3 4
0 0 0
1 0. 1
2 1 2 2 0.
3 0 0. 9 0.
0 7 13 0.0 0.0 0. 0. . 4 3 15 0. 1 0.
2 7 05 5 0.1 0.1 08
1 . . 2. 847 786 08 18 . . . 8. 24 8 27
6 0 66 6 238 866 90
5 7 90 4 4 69 12 . 9 4 80 16 6 50
. 1 7 . 2
7 7 9 1 0
0 7 0
1 0. 1
1 2 2 2 0.
2 1 0. 7 0.
9 1 13 0.1 0.1 0. 0. . 3 5 15 0. 2 0.
0 2 05 0 0.1 0.4 08
2 . . 0. 096 599 19 20 . . . 2. 45 4 36
3 7 99 9 444 245 75
6 2 00 0 0 74 69 . 5 5 50 04 3 13
. 9 9 . 8
9 5 7 3 0
0 0 0
0.
1 2 3 1 2 5 0.
1 0. 0.
1 0 77 8 0.1 0.2 0. 0. . 4 6 98 6 0. 2 0.
0 09 0.2 0.8 17
3 . . .5 6 425 839 24 25 . . . .8 7 68 5 66
5 74 098 663 30
4 3 8 . 0 0 14 97 . 9 5 7 . 69 7 38
2 4 0
2 8 1 1 0 7 5
0
1 0. 1
2 1 2 1 0.
2 1 0. 5 0.
0 4 13 0.1 0.1 0. 0. . 2 6 15 0. 1 0.
9 0 05 7 0.1 0.2 07
4 . . 5. 003 328 19 18 . . . 2. 40 6 23
7 4 88 5 374 050 67
2 3 10 0 0 80 09 . 5 6 20 00 2 64
. 3 3 . 8
9 4 4 7 5
0 0 0
5 rows × 30 columns
In [25]:
y = cancerData.target
In [26]:
X.shape
Out[26]:
(569, 30)
Splitting into Train and Test datasets
In [27]:
X_train,X_test,y_train,y_test=
train_test_split(X,y,test_size=0.1,stratify=y)
In [28]:
X_train.shape
Out[28]:
(512, 30)
In [29]:
y_test.shape
Out[29]:
(57,)
Applying StandardScaler()
In [30]:
scaler = StandardScaler()
In [31]:
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
Reshaping the dataset to 3-D to pass it through CNN
In [32]:
X_train = X_train.reshape(512,30,1)
X_test = X_test.reshape(57,30,1)
Preparing the Model
In [33]:
model = Sequential()
model.add(Conv1D(filters=16,kernel_size=2,activation='relu',input_shape=(3
0,1)))
model.add(BatchNormalization())
model.add(Dropout(0.2))
model.add(Conv1D(32,2,activation='relu'))
model.add(BatchNormalization())
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(32,activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(1,activation='sigmoid'))
In [34]:
model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv1d_2 (Conv1D) (None, 29, 16) 48
_________________________________________________________________
batch_normalization_2 (Batch (None, 29, 16) 64
_________________________________________________________________
dropout_3 (Dropout) (None, 29, 16) 0
_________________________________________________________________
conv1d_3 (Conv1D) (None, 28, 32) 1056
_________________________________________________________________
batch_normalization_3 (Batch (None, 28, 32) 128
_________________________________________________________________
dropout_4 (Dropout) (None, 28, 32) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 896) 0
_________________________________________________________________
dense_2 (Dense) (None, 32) 28704
_________________________________________________________________
dropout_5 (Dropout) (None, 32) 0
_________________________________________________________________
dense_3 (Dense) (None, 1) 33
=================================================================
Total params: 30,033
Trainable params: 29,937
Non-trainable params: 96
_________________________________________________________________
In [35]:
model.compile(optimizer=Adam(learning_rate=0.0001),loss='binary_crossentro
py',metrics=['accuracy'])
In [36]:
history =
model.fit(X_train,y_train,epochs=35,verbose=1,validation_data=(X_test,y_te
st))
Train on 512 samples, validate on 57 samples
Epoch 1/35
512/512 [==============================] - 1s 2ms/sample - loss: 0.9711 -
accuracy: 0.5352 - val_loss: 0.6497 - val_accuracy: 0.7193
Epoch 2/35
512/512 [==============================] - 0s 159us/sample - loss: 0.6452
- accuracy: 0.6797 - val_loss: 0.5717 - val_accuracy: 0.8421
Epoch 3/35
512/512 [==============================] - 0s 150us/sample - loss: 0.4521
- accuracy: 0.7852 - val_loss: 0.5118 - val_accuracy: 0.8246
Epoch 4/35
512/512 [==============================] - 0s 156us/sample - loss: 0.3574
- accuracy: 0.8438 - val_loss: 0.4674 - val_accuracy: 0.8070
Epoch 5/35
512/512 [==============================] - 0s 147us/sample - loss: 0.2879
- accuracy: 0.8770 - val_loss: 0.4324 - val_accuracy: 0.7895
Epoch 6/35
512/512 [==============================] - 0s 147us/sample - loss: 0.2909
- accuracy: 0.8770 - val_loss: 0.4050 - val_accuracy: 0.7719
Epoch 7/35
512/512 [==============================] - 0s 155us/sample - loss: 0.2365
- accuracy: 0.8984 - val_loss: 0.3823 - val_accuracy: 0.7719
Epoch 8/35
512/512 [==============================] - 0s 152us/sample - loss: 0.2099
- accuracy: 0.9062 - val_loss: 0.3623 - val_accuracy: 0.7895
Epoch 9/35
512/512 [==============================] - 0s 152us/sample - loss: 0.2105
- accuracy: 0.9043 - val_loss: 0.3465 - val_accuracy: 0.7895
Epoch 10/35
512/512 [==============================] - 0s 151us/sample - loss: 0.1847
- accuracy: 0.9297 - val_loss: 0.3308 - val_accuracy: 0.8070
Epoch 11/35
512/512 [==============================] - 0s 151us/sample - loss: 0.1689
- accuracy: 0.9336 - val_loss: 0.3141 - val_accuracy: 0.8246
Epoch 12/35
512/512 [==============================] - 0s 160us/sample - loss: 0.1684
- accuracy: 0.9336 - val_loss: 0.3000 - val_accuracy: 0.8246
Epoch 13/35
512/512 [==============================] - 0s 149us/sample - loss: 0.1634
- accuracy: 0.9395 - val_loss: 0.2873 - val_accuracy: 0.8246
Epoch 14/35
512/512 [==============================] - 0s 145us/sample - loss: 0.1443
- accuracy: 0.9414 - val_loss: 0.2708 - val_accuracy: 0.8421
Epoch 15/35
512/512 [==============================] - 0s 149us/sample - loss: 0.1383
- accuracy: 0.9414 - val_loss: 0.2512 - val_accuracy: 0.8421
Epoch 16/35
512/512 [==============================] - 0s 155us/sample - loss: 0.1584
- accuracy: 0.9434 - val_loss: 0.2300 - val_accuracy: 0.8772
Epoch 17/35
512/512 [==============================] - 0s 147us/sample - loss: 0.1269
- accuracy: 0.9531 - val_loss: 0.2153 - val_accuracy: 0.8772
Epoch 18/35
512/512 [==============================] - 0s 151us/sample - loss: 0.1179
- accuracy: 0.9629 - val_loss: 0.2010 - val_accuracy: 0.8772
Epoch 19/35
512/512 [==============================] - 0s 156us/sample - loss: 0.1173
- accuracy: 0.9629 - val_loss: 0.1852 - val_accuracy: 0.8947
Epoch 20/35
512/512 [==============================] - 0s 152us/sample - loss: 0.1160
- accuracy: 0.9590 - val_loss: 0.1707 - val_accuracy: 0.9123
Epoch 21/35
512/512 [==============================] - 0s 161us/sample - loss: 0.1264
- accuracy: 0.9629 - val_loss: 0.1584 - val_accuracy: 0.9474
Epoch 22/35
512/512 [==============================] - 0s 164us/sample - loss: 0.1054
- accuracy: 0.9629 - val_loss: 0.1440 - val_accuracy: 0.9474
Epoch 23/35
512/512 [==============================] - 0s 155us/sample - loss: 0.1103
- accuracy: 0.9590 - val_loss: 0.1344 - val_accuracy: 0.9474
Epoch 24/35
512/512 [==============================] - 0s 154us/sample - loss: 0.1114
- accuracy: 0.9629 - val_loss: 0.1219 - val_accuracy: 0.9474
Epoch 25/35
512/512 [==============================] - 0s 156us/sample - loss: 0.1000
- accuracy: 0.9648 - val_loss: 0.1121 - val_accuracy: 0.9474
Epoch 26/35
512/512 [==============================] - 0s 152us/sample - loss: 0.0971
- accuracy: 0.9707 - val_loss: 0.1022 - val_accuracy: 0.9474
Epoch 27/35
512/512 [==============================] - 0s 159us/sample - loss: 0.0933
- accuracy: 0.9707 - val_loss: 0.0948 - val_accuracy: 0.9649
Epoch 28/35
512/512 [==============================] - 0s 160us/sample - loss: 0.0938
- accuracy: 0.9707 - val_loss: 0.0884 - val_accuracy: 0.9649
Epoch 29/35
512/512 [==============================] - 0s 144us/sample - loss: 0.0852
- accuracy: 0.9707 - val_loss: 0.0821 - val_accuracy: 0.9649
Epoch 30/35
512/512 [==============================] - 0s 151us/sample - loss: 0.0958
- accuracy: 0.9668 - val_loss: 0.0736 - val_accuracy: 0.9649
Epoch 31/35
512/512 [==============================] - 0s 148us/sample - loss: 0.0945
- accuracy: 0.9648 - val_loss: 0.0691 - val_accuracy: 0.9649
Epoch 32/35
512/512 [==============================] - 0s 147us/sample - loss: 0.0930
- accuracy: 0.9727 - val_loss: 0.0640 - val_accuracy: 0.9649
Epoch 33/35
512/512 [==============================] - 0s 150us/sample - loss: 0.0857
- accuracy: 0.9766 - val_loss: 0.0615 - val_accuracy: 0.9649
Epoch 34/35
512/512 [==============================] - 0s 151us/sample - loss: 0.0885
- accuracy: 0.9590 - val_loss: 0.0601 - val_accuracy: 0.9649
Epoch 35/35
512/512 [==============================] - 0s 147us/sample - loss: 0.0758
- accuracy: 0.9746 - val_loss: 0.0597 - val_accuracy: 0.9825
Plots of Accuracy and Loss
In [37]:
def plotLearningCurve(history,epochs):
epochRange = range(1,epochs+1)
plt.plot(epochRange,history.history['accuracy'])
plt.plot(epochRange,history.history['val_accuracy'])
plt.title('Model Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend(['Train','Validation'],loc='upper left')
plt.show()
plt.plot(epochRange,history.history['loss'])
plt.plot(epochRange,history.history['val_loss'])
plt.title('Model Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend(['Train','Validation'],loc='upper left')
plt.show()
In [38]:
linkcode
plotLearningCurve(history,35)
CNN Classification report
The CNN model achieved a validation accuracy of 98.25% on scaled data after 35 epochs.
Explanation by Class:
Malignant (Assumed as Class 0.0):
Precision: Indicates the proportion of correct malignant predictions out of all malignant
predictions.
Recall: Represents the proportion of actual malignant cases correctly identified.
F1-score: The harmonic mean of precision and recall for malignant cases.
Benign (Assumed as Class 1.0):
Precision: The proportion of benign predictions that were accurate.
Recall: The proportion of actual benign cases correctly identified.
F1-score: The harmonic mean of precision and recall for benign cases.
Overall Performance Metrics:
Accuracy: 98.25% – The percentage of total predictions (both benign and malignant) that were
correct.
Macro Average: Unweighted average across both classes, assessing performance without class
size influence.
Weighted Average: Weighted by class support, accounting for any class imbalance, giving a
balanced view of the performance.
The high precision, recall, and F1-scores across both classes indicate strong performance,
though false positives and false negatives may exist in minimal quantities. This is demonstrated
by the stable loss reduction over epochs and consistent validation accuracy nearing 98%.