Keras
neural network
modulus
machine learning
Python

Keras Making a neural network to find a number's modulus

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Predicting a modulus value with Keras is a good exercise because it looks numeric but is really a classification problem. The model must map an integer input to one of a small set of remainder classes. This walkthrough builds a working TensorFlow Keras pipeline for x mod n and explains why feature encoding matters.

Model the Task as Classification

If n equals 5, the valid outputs are 0 through 4. That means five classes, not a single regression target. The neural network should end with a softmax layer and be trained with sparse categorical cross-entropy.

python
1import numpy as np
2import tensorflow as tf
3
4np.random.seed(7)
5tf.random.set_seed(7)
6
7MODULUS = 5
8MAX_X = 5000
9
10x = np.arange(MAX_X + 1, dtype=np.int32)
11y = x % MODULUS
12
13# Normalize input so optimization is easier.
14x_float = x.astype("float32") / MAX_X
15
16split = int(len(x_float) * 0.8)
17x_train, x_test = x_float[:split], x_float[split:]
18y_train, y_test = y[:split], y[split:]
19
20print(x_train.shape, y_train.shape)

This dataset is synthetic, deterministic, and perfect for learning experiments because you know the exact target function.

Build and Train a Keras Network

A small feed-forward model is enough for this task. For more difficult periodic mappings, feature engineering can matter more than network depth.

python
1import tensorflow as tf
2
3model = tf.keras.Sequential(
4    [
5        tf.keras.layers.Input(shape=(1,)),
6        tf.keras.layers.Dense(64, activation="relu"),
7        tf.keras.layers.Dense(64, activation="relu"),
8        tf.keras.layers.Dense(5, activation="softmax"),
9    ]
10)
11
12model.compile(
13    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),
14    loss="sparse_categorical_crossentropy",
15    metrics=["accuracy"],
16)
17
18history = model.fit(
19    x_train,
20    y_train,
21    validation_split=0.2,
22    epochs=25,
23    batch_size=128,
24    verbose=2,
25)
26
27test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
28print(f"test_loss={test_loss:.4f} test_acc={test_acc:.4f}")

If accuracy stalls, that is not unusual. A plain normalized scalar does not represent periodic structure very well.

Improve Results with Periodic Features

The modulus function repeats. You can encode periodicity with sine and cosine features so the model receives a more useful representation.

python
1import numpy as np
2import tensorflow as tf
3
4MODULUS = 5
5x = np.arange(0, 5001, dtype=np.float32)
6y = (x.astype(np.int32) % MODULUS)
7
8angle = 2.0 * np.pi * (x / MODULUS)
9features = np.column_stack([np.sin(angle), np.cos(angle)]).astype("float32")
10
11split = int(len(features) * 0.8)
12x_train, x_test = features[:split], features[split:]
13y_train, y_test = y[:split], y[split:]
14
15model = tf.keras.Sequential(
16    [
17        tf.keras.layers.Input(shape=(2,)),
18        tf.keras.layers.Dense(32, activation="relu"),
19        tf.keras.layers.Dense(MODULUS, activation="softmax"),
20    ]
21)
22
23model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
24model.fit(x_train, y_train, epochs=20, batch_size=64, verbose=0)
25print("accuracy:", model.evaluate(x_test, y_test, verbose=0)[1])

For many periodic tasks, this feature design can beat a deeper model with raw input.

Run Targeted Sanity Checks

Overall accuracy is useful, but spot checks make debugging faster because they reveal exact mistakes. After training, test a few integers you can verify mentally.

python
1import numpy as np
2
3def predict_mod(model, values, modulus):
4    values = np.array(values, dtype=np.float32)
5    angle = 2.0 * np.pi * (values / modulus)
6    features = np.column_stack([np.sin(angle), np.cos(angle)]).astype("float32")
7    probs = model.predict(features, verbose=0)
8    return probs.argmax(axis=1)
9
10
11samples = [7, 18, 24, 55, 102]
12pred = predict_mod(model, samples, MODULUS)
13truth = np.array(samples) % MODULUS
14
15for s, p, t in zip(samples, pred, truth):
16    print(f"x={s} predicted={p} expected={t}")

When these checks fail, inspect preprocessing first. Inconsistent feature scaling is the most common cause.

Common Pitfalls

A common error is using a linear output layer with mean squared error. That treats class labels as continuous distances, which is not the objective here.

Another mistake is forgetting that labels must be integer class ids when using sparse categorical cross-entropy. If labels are one-hot vectors, use categorical cross-entropy instead.

Small training ranges can also create false confidence. A model may memorize the observed interval without generalizing to larger values. Evaluate on a holdout range with larger integers.

Input scaling is often overlooked. Extremely large raw integers can lead to unstable optimization and slow convergence. Normalize or engineer periodic features before training.

Summary

  • Predicting x mod n is a multi-class classification problem.
  • Use softmax output with sparse categorical cross-entropy for integer class labels.
  • Normalize inputs and test on a separate holdout range.
  • Consider sine and cosine periodic features for cleaner learning dynamics.
  • Validate with both accuracy and targeted spot checks on known values.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.