Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nvisual

A tiny terminal-based neural network visualizer that trains a small model on a JSONL dataset and shows its predictions in a colorful ncurses interface.

It is intended for aesthetic and educational use, giving a simple and visual way to explore how a tiny neural network behaves in the terminal.

nvisual preview

Features

  • Train a compact classifier from prompt/answer pairs with --train
  • Run inference on custom prompts loaded from configuration
  • Visualize activations, predictions, and training progress directly in the terminal
  • Save and reload the trained model and tokenizer for later use

This project is intentionally simple and educational. The model is small, the tokenizer is minimal, and the training loop is hand-rolled. It is useful for understanding:

  • how a tiny neural network can learn a few simple classification tasks,
  • how prompt/answer pairs are represented as training data,
  • how configuration files control runtime behavior,
  • and how a terminal UI can visualize activations and training progress.

What this project does

At a high level, nvisual works in three stages:

  1. Load a configuration file.
  2. Load or train a tiny neural network from a JSONL dataset.
  3. Run inference on a list of prompts and display the results in a ncurses-based visualizer.

The program can:

  • train a model from a local dataset with --train,
  • run inference repeatedly over configured prompts,
  • show a live animated view of the network during inference and training,
  • and save the trained model and tokenizer to your user config directory.

Project goals and limitations

This is not a production-grade AI system.

It uses:

  • a very small vocabulary,
  • a very small embedding table,
  • a tiny multi-layer perceptron,
  • and a very simple tokenizer.

Because of that, it is best viewed as a learning/demo project. It can learn simple patterns and answer small toy questions, but it will not behave like a modern large language model.

The README below explains how the pieces fit together so you can understand and modify the project confidently.


Architecture overview

The model is a tiny feed-forward classifier built around these components:

  • Tokenizer: converts text prompts into integer token IDs.
  • Neural network: turns token IDs into embeddings, processes them through hidden layers, and produces a probability distribution over answer classes.
  • Dataset: loads prompt/answer pairs from JSONL.
  • Config: loads user settings and prompt list.
  • Visualizer: renders the network and training state in the terminal using ncurses.

Model structure

The network is defined in src/nn.hpp and src/nn.cpp.

Its architecture is:

  • embedding table: vocabulary size × embedding dimension,
  • hidden layer 1,
  • hidden layer 2,
  • output layer over the number of class labels.

In the current implementation:

  • vocabulary size: 32
  • embedding dimension: 8
  • hidden layer 1: 16 neurons
  • hidden layer 2: 8 neurons

That makes the model very small and easy to inspect visually.

Training method

Training uses mini-batch-style single-example SGD (stochastic gradient descent) with a cross-entropy loss.

Each training step:

  1. tokenizes the prompt,
  2. runs a forward pass,
  3. computes the loss against the correct label,
  4. performs backpropagation through the linear layers and ReLU activations,
  5. updates the weights and biases.

This is simple and transparent, but it is not optimized for high accuracy.


File and folder layout

The repository contains the following major pieces:


Build and run

Build

From the repo root:

cmake -S . -B build
cmake --build build

This produces the executable at:

build/nvisual

Run the program

Basic run:

./build/nvisual

Train the model from the dataset:

./build/nvisual --train

Help:

./build/nvisual --help

Where files are stored

The program uses the user config directory:

~/.config/nvisual

It will create and/or use these files there:

  • config.conf: runtime configuration.
  • dataset/dataset.jsonl: training dataset.
  • model.bin: trained neural network weights.
  • tokenizer.txt: saved tokenizer vocabulary.

On first run, if these files do not exist, the program creates defaults.


Configuration system

The configuration file is read from:

~/.config/nvisual/config.conf

The repository also includes a sample config at config.conf.

File format

The parser supports a simple INI-style format:

[settings]
auto_cycle = true
cycle_delay_ms = 0
warn_accuracy = true
learning_rate = 0.05
train_epochs = 100

[prompts]
prompt1 = What is 2 + 2?
prompt2 = What is the capital of France?

Section: [settings]

These values control the runtime behavior of the application.

auto_cycle

  • Type: boolean
  • Default behavior: true
  • Meaning: whether the program automatically advances through the prompt list without waiting for input.

When enabled, the program cycles through configured prompts. When disabled, it may behave more like a one-shot viewer depending on the flow.

cycle_delay_ms

  • Type: integer (milliseconds)
  • Default: 0
  • Meaning: how long the program waits before moving to the next prompt.

A higher value makes the visualization more readable and gives you more time to observe each prediction.

warn_accuracy

  • Type: boolean
  • Default: true
  • Meaning: whether the visualizer shows a warning that the model may be inaccurate.

This warning is shown in the UI and is intended to remind you that the model is small and toy-like.

learning_rate

  • Type: float
  • Default: 0.05
  • Meaning: step size used during training.

A larger value makes training faster but can be unstable; a smaller value is more stable but slower.

train_epochs

  • Type: integer
  • Default: 100 in the shipped config
  • Meaning: number of training epochs used when training is run.

This value controls how long the model trains over the dataset before saving weights.

Section: [prompts]

The [prompts] section contains the prompt list used during inference.

Each entry is simply a line like:

[prompts]
prompt1 = What is 2 + 2?
prompt2 = What is the capital of France?

The parser reads every non-empty value under [prompts] and stores it in a vector of strings.

Important detail:

  • These prompts are used for inference/display.
  • They are not the same thing as the training examples in the JSONL dataset.

The program will use the configured prompts as the runtime prompt loop. If the prompt list is empty, it falls back to a few hardcoded defaults.


Prompts and how they are used

There are two different concepts related to prompts in this project:

  1. Runtime prompts from the config file.
  2. Training examples from the dataset file.

1. Runtime prompts

These are the questions the program will show and answer during the inference loop.

They come from the [prompts] section of the config file.

Example:

[prompts]
prompt1 = What is the capital of France?
prompt2 = What is 2 + 2?

When the program is run normally, it cycles through these prompts and displays the network’s prediction for each one.

2. Training prompts

These are the examples used to teach the model.

They live in the dataset file:

~/.config/nvisual/dataset/dataset.jsonl

Each line must contain a JSON object with:

{"prompt": "What is 2 + 2?", "answer": "4"}

The dataset loader expects each line to contain a simple flat JSON object with a prompt field and an answer field.

The model is trained to map prompt text to one of the known answer labels.


Dataset format

The dataset file is newline-delimited JSON (JSONL).

Each line should look like this:

{"prompt": "What is 2 + 2?", "answer": "4"}

Rules

  • Each line is one training example.
  • prompt is the input question.
  • answer is the expected class label.
  • The parser is minimal and expects simple JSON strings.
  • It does not support nested objects or complex JSON structures.

What the dataset loader does

The dataset system:

  • reads all valid examples,
  • stores the prompt/answer pairs,
  • deduplicates the answers into a list of class labels,
  • and builds a deterministic label index for training.

The answer labels are sorted and used as output classes for the network.

Example training dataset

The repository’s default dataset file includes examples like:

{"prompt": "What is 2 + 2?", "answer": "4"}
{"prompt": "What is the capital of France?", "answer": "Paris"}
{"prompt": "What color is the sky?", "answer": "Blue"}

These examples are intentionally simple and easy for a tiny model to learn.


Tokenizer behavior

The tokenizer is implemented in src/tokenizer.cpp.

What it does

  1. Normalizes text to lowercase.
  2. Keeps alphanumeric characters and converts punctuation to spaces.
  3. Splits text into words.
  4. Maps words to integer IDs.
  5. Limits the input to a maximum token length.

Important implementation details

  • Token ID 0 is reserved for <UNK>.
  • The vocabulary size is capped at 32 tokens.
  • The tokenizer only uses the most frequent words from the training prompts.
  • Text that is not in the vocabulary becomes <UNK>.

Why this matters

Because the model is tiny, the tokenizer is very simple. If you add many varied prompts, the tokenizer may fail to capture enough vocabulary to make predictions accurate.


Neural network behavior

The model is implemented in src/nn.cpp.

Overview

The forward pass does the following:

  1. Look up token embeddings.
  2. Average-pool them into a single embedding vector.
  3. Pass that through hidden layer 1.
  4. Apply ReLU.
  5. Pass to hidden layer 2.
  6. Apply ReLU.
  7. Produce logits for each class.
  8. Apply softmax to get probabilities.

Inference output

For each input prompt, the network outputs a probability distribution over all known answers.

The program chooses the answer with the highest probability as the predicted label.

Training update

Training adjusts the weights and biases using the gradient of cross-entropy loss.

Because the network is tiny, accuracy will depend heavily on how well the dataset matches the prompts you test it with.


Terminal visualizer

The UI is drawn with ncurses in src/visualizer.cpp.

It provides a colorful terminal interface with:

  • a title bar,
  • a network visualization panel,
  • an information panel showing the prompt and answer,
  • a status bar,
  • and animated transitions during inference.

What you will see

During inference, the program animates a ball moving through the network layers. The visualizer also shows the current prompt, the predicted answer, and the confidence value.

During training, it shows:

  • current epoch,
  • total epochs,
  • loss,
  • accuracy,
  • and dataset size.

Keyboard controls

The visualizer listens for keyboard input:

  • q or Esc: quit
  • Space, Enter, or right arrow: skip to the next prompt while waiting in the cycle delay

Runtime flow

This is the practical flow of the program when you run ./build/nvisual:

  1. The program determines the home directory.
  2. It creates ~/.config/nvisual if needed.
  3. It creates a default config file and dataset if they do not exist.
  4. It loads the config.
  5. It checks whether a model and tokenizer already exist.
  6. If they do not exist, it trains the model immediately.
  7. It loads the model and tokenizer.
  8. It loops over the configured prompts.
  9. For each prompt, it runs inference and draws the visualizer.
  10. It advances to the next prompt or waits according to the configured delay.

When you run ./build/nvisual --train, the flow changes slightly:

  1. The program loads the dataset.
  2. It builds the tokenizer vocabulary.
  3. It initializes the neural network.
  4. It trains for the configured number of epochs.
  5. It saves the model and tokenizer.

How to improve accuracy

Because the model is tiny, the best way to improve performance is to improve the training data.

Recommended approach

  1. Add more prompt/answer examples to the dataset.
  2. Use prompts that are similar to the questions you want the model to answer.
  3. Keep answers short and consistent.
  4. Run nvisual --train again.

Tips

  • Avoid mixing too many unrelated topics in one dataset.
  • Prefer a focused domain if you want better results.
  • If the model is failing on a specific prompt, add several similar examples for that prompt.

The model is small enough that it can learn simple patterns, but it will not generalize well to arbitrary knowledge.


Example configuration

Here is a minimal example you can use:

[settings]
auto_cycle = true
cycle_delay_ms = 1000
warn_accuracy = true
learning_rate = 0.05
train_epochs = 100

[prompts]
prompt1 = What is 2 + 2?
prompt2 = What is the capital of France?
prompt3 = What color is the sky?

And a matching dataset example:

{"prompt": "What is 2 + 2?", "answer": "4"}
{"prompt": "What is the capital of France?", "answer": "Paris"}
{"prompt": "What color is the sky?", "answer": "Blue"}

Summary

nvisual is a compact educational project that combines:

  • a tiny neural network,
  • a simple tokenizer,
  • a JSONL dataset loader,
  • and a ncurses visualizer.

Its main purpose is not to be a serious AI model. Its purpose is to show, in a simple and understandable way, how a small neural network can be trained and visualized from scratch.

If you want to extend it, the best next steps are usually:

  • add more training data,
  • improve the tokenizer,
  • enlarge the neural network,
  • or add more sophisticated visualization.

Quick reference

Commands

./build/nvisual            # run inference
./build/nvisual --train    # train/fine-tune
./build/nvisual --help     # show usage

Config file

~/.config/nvisual/config.conf

Dataset file

~/.config/nvisual/dataset/dataset.jsonl

Model files

~/.config/nvisual/model.bin
~/.config/nvisual/tokenizer.txt

About

A lightweight CLI neural network visualizer (~1K parameters) for decoration.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages