Linear Classification in Pytorch. Detect Breast Cancer Using Binary... | by Dieter Jordens | Towards Data Science

This Medium article will explore the Pytorch library and how you can implement the linear classification algorithm. We will apply the algorithm on a classic and easily understandable dataset. In this article, you’ll get more familiar with the basics of Pytorch. Afterwards, you should be ready to dive into more advanced problems (e.g. time series).
The structure of the article is the following:
Loading the dataset
Splitting the data
Preprocessing the data
Creating the model
Full Gradient Descent
Evaluation of the model
The dataset that will be used is the breast cancer Wisconsin dataset — which is perfect to demonstrate binary classification.
The problem is straightforward. Scientists collected features on patients with (malignant) or without (benign) breast cancer. Our job is to detect right from wrong. This can aid processing doctors data in their daily jobs. The reason behind breast cancer as an example is because of its relevancy. In 2018, it was estimated that 627.000 women worldwide died of breast cancer alone [WHO, 2020].
from sklearn.datasets import load_breast_cancerdata = load_breast_cancer()X, Y = data.data, data.target
In this dataset, there are 30 features (e.g. mean radius, mean texture).
print(data.feature_names)['mean radius' 'mean texture' 'mean perimeter' 'mean area'  'mean smoothness' 'mean compactness' 'mean concavity'  'mean concave points' 'mean symmetry' 'mean fractal dimension'  'radius error' 'texture error' 'perimeter error' 'area error'  'smoothness error' 'compactness error' 'concavity error'  'concave points error' 'symmetry error' 'fractal dimension error'  'worst radius' 'worst texture' 'worst perimeter' 'worst area'  'worst smoothness' 'worst compactness' 'worst concavity'  'worst concave points' 'worst symmetry' 'worst fractal dimension']
The target mapping is straightforward. The features indicate that you have a malignant or benign tumour. Most tumours are benign, which means they are not cancerous and will not kill you.
print(data.target_names)['malignant' 'benign']
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.3)
Firstly, a model is created with training data and afterwards, testing is done using test data. This should be a surprise if you are familiar with the field. Therefore, the code above splits the data up into a random training and test subset with sklearn. One line of code, but very important.
from sklearn.preprocessing import StandardScalerscaler = StandardScaler()X_train = scaler.fit_transform(X_train)X_test = scaler.transform(X_test)
To have better results, a bit of scaling is important. We don’t want one feature to dominate the other. What we can do is making sure the data is nicely distributed. Nothing new here, a machine learning course might help if you are unfamiliar with standardizing features (e.g. deeplearning.ai).
You can do this yourself, but why re-invent the wheel right? For this task, the StandardScaler of sklearn can be used. It’s a subtle detail, but it’s important to scale the test set in the same way as the training set. Because the training set is much larger as the testing set and both are chosen randomly, it should be a better estimate for the actual distribution.
class BinaryClassification(torch.nn.Module):def __init__(self, input_dimension):        super().__init__()        self.linear = torch.nn.Linear(input_dimension, 1)def forward(self, input_dimension):        return self.linear(input_dimension)_, input_dimension = X_train.shapemodel = BinaryClassification(input_dimension)
The model of interest is a very simple linear one. In the example, it shows how you can create your own Pytorch ‘module’, but you could have done it with a one-liner as well. The same thing could be done like this as well. So feel free to use one-liner if you like that more. However, this article intends to inform. It is this easy to create a custom neural network in Pytorch.
model = torch.nn.Linear(input_dimension, 1)
One more thing you could have noticed is that we didn’t use the sigmoid activation function, but this is explainable. Instead of using the binary cross-entropy loss function combined with the sigmoid function, the binary cross-entropy with logits loss function is favoured here. The latter is numerically more stable, which in turn leads to better results.
def configure_loss_function():    return torch.nn.BCEWithLogitsLoss()def configure_optimizer(model):    return torch.optim.Adam(model.parameters())
Finally, the Adam optimizer has been used. There might be a better optimizing algorithm out there, but it performed rather well. No need to experiment with others yet.
The rest of the code is just a full gradient descent loop and the calculation of training and test accuracy. In every epoch the following steps happen:
A forward pass through the BinaryClassification model is made.
Loss function measures the BCEWithLogits loss.
Gradients of the loss are reset to zero.
Loss function propagates backwards (gradients of the loss are calculated).
Adam optimizer steps in the ‘right’ direction.
It would be stupid to not give the full code at this point. Feel free to play around with the algorithm and dataset yourself.
Tip: Use Google Colab, it’s like Jupiter notebook on steroids — incredibly easy to get started with as well.
The results of the binary classification algorithm are about 98% accuracy on both the training and test set — amazing, isn’t it? And it didn’t require all that much effort either. If you spot any improvements to this article please let me know in the comments down below. This will aid me and future readers, thank you in advance.