Hannah-AI-Companion / README.md
Drocho's picture
Upload README.md
6d8b294 verified
|
Raw
History Blame Contribute Delete
9.22 kB
---
license: cc-by-nc-4.0
language:
- en
pipeline_tag: text-generation
tags:
- conversational
- companion-ai
- olmo
- dpo
- rag
- pytorch
---
# Hannah 360M
Hannah is a 367M-parameter conversational language model designed to act as the **fast-response component** of the [Hannah AI Companion](https://github.com/Hannah-AI-companion) system — a multi-model architecture in which Hannah provides quick, emotionally-attuned replies while a larger model (Qwen2.5-14B) handles deeper reasoning and retrieval-augmented context. The goal of the project is to give people who are dealing with loneliness a low-latency, locally-runnable companion model.
This repository contains three checkpoints representing the successive stages of training:
| Folder | File | Stage |
|---|---|---|
| `pretrained/` | `hannah_final.pt` | Base language model (next-token pretraining) |
| `sft/` | `hannah_sft_final.pt` | Supervised fine-tuning on conversational data |
| `finetuned/` | `hannah_personality_final.pt` | RAG grounding + DPO personality alignment (final model) |
For most use cases, **`finetuned/hannah_personality_final.pt` is the model you want** — it includes everything from the earlier stages.
---
## Model Details
- **Architecture:** OLMo3-style transformer (built via `olmo_core.nn.transformer.TransformerConfig`)
- **Parameters:** 367M
- **Hidden size (`d_model`):** 1024
- **Layers:** 24
- **Attention heads:** 16 (no grouped-query attention — `n_kv_heads = n_heads`)
- **Feed-forward hidden size:** 2730 (≈ 8/3 × `d_model`, SwiGLU-style)
- **Vocab size:** 32,000
- **Training sequence length:** 1024 tokens
- **Attention backend:** PyTorch SDPA (`AttentionBackendName.torch`)
- **Precision:** bfloat16 mixed precision, trained with gradient checkpointing + `torch.compile`
- **Language:** English only
### Tokenizer
Custom `LlamaTokenizer`-based tokenizer, vocab size 32,000, with the following special tokens used to format conversational turns and injected memory:
```json
{
"bos_token": "<bos>",
"eos_token": "<eos>",
"unk_token": "<unk>",
"pad_token": "<pad>",
"additional_special_tokens": [
"[SYS]", "[/SYS]",
"[USR]", "[/USR]",
"[ASS]", "[/ASS]",
"[MEMORY]", "[/MEMORY]"
]
}
```
Conversations are formatted as:
```
[SYS] <system prompt, optionally containing [MEMORY]...[/MEMORY]> [/SYS][USR] <user message> [/USR][ASS] <assistant reply> [/ASS]
```
> Note: the tokenizer config reports `model_max_length: 32768`, but the model was **trained at a sequence length of 1024 tokens**. Using significantly longer contexts at inference is unsupported / untested.
---
## Training Data & Procedure
All training was done on a single **NVIDIA RTX 5070 Ti (16GB VRAM)**.
### 1. Pretraining (`pretrained/hannah_final.pt`)
- **~5B tokens**, trained for roughly 2 epochs (cosine LR schedule, warmup 800 steps, peak LR 3e-4, AdamW, effective batch size of 64 sequences × 1024 tokens).
- Corpus built from a mix of public datasets:
- Conversational/dialogue: `Estwld/empathetic_dialogues_llm`, `AlekseyKorshuk/persona-chat`, `allenai/soda`, `OpenAssistant/oasst1`
- General text: `roneneldan/TinyStories`, `lucadiliello/bookcorpusopen`, `wikimedia/wikipedia` (Simple English), `allenai/c4` (English subset)
- Literary/narrative text: a curated set of public-domain novels from Project Gutenberg (classic English literature — Austen, Brontë, Hardy, Wilde, Tolstoy, etc., plus a smaller selection of public-domain romance/erotic-literature titles included to add narrative variety in romantic/relationship contexts)
### 2. Supervised Fine-Tuning (`sft/hannah_sft_final.pt`)
- Conversational fine-tuning on a corpus assembled from:
- `allenai/soda`, `allenai/prosocial-dialog`, `Estwld/empathetic_dialogues_llm`, `jihyoung/ConversationChronicles`, `icybee/share_gpt_90k_v1`, and (optionally) `allenai/WildChat-4.8M` (English-only subset)
- All conversations cleaned and reformatted into `Human: / Assistant:` turn format, language-filtered to English, deduplicated, and length-filtered.
### 3. RAG Grounding + Personality Alignment (`finetuned/hannah_personality_final.pt`)
This is the final model, fine-tuned in two stages on top of the SFT checkpoint:
- **RAG SFT:** ~10K synthetic examples teaching the model to read and naturally use `[MEMORY]...[/MEMORY]` blocks injected into the system prompt — fictional facts about "Hannah" the persona, facts the user shares about themselves, and multi-turn examples requiring recall of earlier context.
- **DPO personality alignment:** ~15K preference pairs covering Hannah's personality and conversational voice (identity, romance, flirting/banter, daily check-ins, light emotional support, robustness to garbled/non-English input, and crisis-message handling — where the "chosen" response gently encourages the user to seek real human/professional support).
Both synthetic datasets were generated using **Qwen2.5-14B-Instruct** as the data-generation model, with automatic filtering to remove AI-assistant-sounding responses (e.g. "as an AI", "I understand your feelings").
---
## Intended Use
Hannah 360M is intended to be used as the **fast-path conversational model** in a larger companion-AI system, optimized for low-latency, casual, emotionally warm replies (texting-style, 1–2 sentences). It is designed to run alongside a larger reasoning model that supplies retrieved memory/context via `[MEMORY]` blocks in the system prompt.
It can also be used standalone for lightweight conversational/companion experiments, but at 367M parameters it has limited factual knowledge and reasoning ability compared to larger models — this is by design, since it's meant to be paired with a stronger model for anything requiring depth.
### Out-of-scope use
- Factual question answering, coding, math, or other reasoning-heavy tasks
- Use as a replacement for mental health support or crisis intervention — the model is trained to *redirect* users toward real support in crisis scenarios, not to provide it itself
- Languages other than English (the model was trained to recognize non-English input only enough to ask the user to switch to English)
---
## Limitations, Risks & Bias
- **No formal evaluation has been run yet** (no benchmark numbers are currently available for any of the three checkpoints).
- The pretraining corpus includes a small amount of **mature/romantic literary content** from public-domain sources (older romance and erotic literature from Project Gutenberg), included to help the model handle romantic-relationship conversation naturally. This means the base model's outputs may occasionally drift toward romantic/suggestive register more readily than a general-purpose model trained on a more neutral corpus.
- The personality/DPO data was synthetically generated by another LLM (Qwen2.5-14B-Instruct) and automatically filtered — it has not been manually reviewed at scale, so some stylistic artifacts or inconsistencies from the generator may be present.
- As a small (367M) model, it is prone to factual hallucination and should not be relied on for accurate information.
- The crisis-handling behavior (encouraging users to seek help) was trained via a relatively small set of synthetic examples (~300) and **should not be treated as a reliable safety mechanism** — it is a best-effort behavioral nudge, not a safety system, and should be paired with proper human-in-the-loop or crisis-resource integrations in any deployed product.
---
## License
Released under **CC BY-NC 4.0** (non-commercial). This choice reflects the fact that part of the pretraining corpus includes data released under non-commercial licenses (e.g. `empathetic_dialogues_llm` is CC-BY-NC-SA 4.0). This is not legal advice — if you plan to use this model commercially, please review the licenses of the underlying datasets listed above for your specific use case.
---
## How to Use
This is a raw `torch.save` checkpoint (not a `transformers`-format model), containing the model's `state_dict` plus training metadata (`step`, `optimizer`, `config`, `loss`). To load it, rebuild the same architecture and load the weights:
```python
import torch
from olmo_core.nn.transformer import TransformerConfig
from olmo_core.nn.attention import AttentionBackendName
VOCAB_SIZE = 32000
D_MODEL = 1024
N_HEADS = 16
N_LAYERS = 24
config = TransformerConfig.olmo3_7B(
vocab_size=VOCAB_SIZE,
attn_backend=AttentionBackendName.torch,
)
config.d_model = D_MODEL
config.n_layers = N_LAYERS
config.block.sequence_mixer.d_model = D_MODEL
config.block.sequence_mixer.n_heads = N_HEADS
config.block.sequence_mixer.n_kv_heads = N_HEADS
config.block.feed_forward.hidden_size = int(D_MODEL * 8 / 3)
model = config.build()
ckpt = torch.load("hannah_personality_final.pt", map_location="cpu")
state_dict = ckpt["model"]
# Strip torch.compile's "_orig_mod." prefix if present
state_dict = { k.replace("_orig_mod.", ""): v for k, v in state_dict.items() }
model.load_state_dict(state_dict)
model.eval()
```
> Update with the actual generation/sampling code from `generate_hannah.py` for full inference (tokenization, prompt formatting with `[SYS]/[USR]/[ASS]` tags, and sampling loop).