Your First Neural Network
Keras Basics
2 min read
Published Nov 17 2025, updated Aug 17 2026
Guide Sections
Guide Comments
In this section, you’ll build your first complete Keras model using a real dataset: MNIST handwritten digits.
This section demonstrates all core steps you'll use in every deep learning project:
- Load data
- Prepare data
- Build model
- Compile model
- Train model
- Evaluate model
- Predict using model
Load the MNIST Dataset
MNIST is built into Keras:
from tensorflow.keras import datasets(x_train, y_train), (x_test, y_test) = datasets.mnist.load_data()MNIST consists of:
- 60,000 training images
- 10,000 test images
- Each image is 28×28 grayscale
- Each label is an integer from 0 to 9
Inspect shapes:
print(x_train.shape) # (60000, 28, 28)print(y_train.shape) # (60000,)Preprocess the Data
Neural networks work best with scaled data.
Convert pixel values (0–255) to floats (0–1):
x_train = x_train.astype("float32") / 255.0x_test = x_test.astype("float32") / 255.0Flatten images (28×28 → 784)
Our first model is a simple Dense network, so flattening is required.
x_train = x_train.reshape(-1, 28*28)x_test = x_test.reshape(-1, 28*28)Later sections (CNNs) will use unflattened images.
Build the Model
Use a basic Sequential API MLP (multi-layer perceptron):
from tensorflow import kerasfrom tensorflow.keras import layersmodel = keras.Sequential([ layers.Dense(128, activation='relu', input_shape=(784,)), layers.Dense(10, activation='softmax')])Explanation:
- 128 hidden units → moderate-sized hidden layer
- ReLU activation → standard for hidden layers
- Softmax output → required for multi-class classification
Compile the Model
Compile defines:
- Loss function
- Optimiser
- Metrics
model.compile( optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])Why these choices?
- Adam: good general-purpose optimizer
- Sparse categorical crossentropy: correct loss for multi-class integer labels
- Accuracy: practical metric for classification
Train the Model
Training is done via .fit().
history = model.fit( x_train, y_train, batch_size=32, epochs=5, validation_split=0.1)What each parameter means:
batch_size=32- Standard mini-batch gradient descent batch sizeepochs=5- Full passes through the training datavalidation_split=0.1- Reserves 10% of training data for validation monitoring
Training output shows:
- Loss
- Accuracy
- Validation loss
- Validation accuracy
Evaluate the Model
test_loss, test_acc = model.evaluate(x_test, y_test)print("Test accuracy:", test_acc)MNIST typically gives:
Test accuracy: ~0.97Making Predictions
Predict class probabilities:
pred_probs = model.predict(x_test[:5])print(pred_probs[0])Predict most likely classes:
import numpy as nppred_classes = np.argmax(pred_probs, axis=1)print(pred_classes)Compare with true labels:
print(y_test[:5])Visualising a Prediction
import matplotlib.pyplot as pltplt.imshow(x_test[0].reshape(28,28), cmap='gray')plt.title(f"Predicted: {pred_classes[0]}, True: {y_test[0]}")plt.show()
Understanding the Training History
The .fit() method returns a history object containing training curves:
history.history.keys()Common keys:
lossaccuracyval_lossval_accuracy
Example plotting accuracy:
plt.plot(history.history["accuracy"])plt.plot(history.history["val_accuracy"])plt.legend(["Train", "Validation"])plt.show()
The Full Script (Complete Working Example)
from tensorflow.keras import datasetsfrom tensorflow import kerasfrom tensorflow.keras import layersimport numpy as np# Load data(x_train, y_train), (x_test, y_test) = datasets.mnist.load_data()# Preprocessx_train = x_train.astype("float32") / 255.0x_test = x_test.astype("float32") / 255.0x_train = x_train.reshape(-1, 28*28)x_test = x_test.reshape(-1, 28*28)# Buildmodel = keras.Sequential([ layers.Dense(128, activation='relu', input_shape=(784,)), layers.Dense(10, activation='softmax')])# Compilemodel.compile( optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])# Trainmodel.fit(x_train, y_train, epochs=5, batch_size=32, validation_split=0.1)# Evaluatemodel.evaluate(x_test, y_test)# Predictpred_probs = model.predict(x_test[:1])pred_class = np.argmax(pred_probs)print("Prediction:", pred_class, "Label:", y_test[0])