- AmoreSignal
- What makes this different from a typical text classifier
- Architecture, in plain terms
- The 53 signals, by category
- A note on the training data and where this is strongest
- Training history
- Honest evaluation results
- Known limitations, stated plainly
- Files in this repository
- Fine-tuning on your own data
- What makes this different from a typical text classifier
AmoreSignal
AmoreSignal reads free-form text — a bio, a chat message, a written reflection — and identifies the psychological and relational patterns present in it. It doesn't just classify text; it generates a ranked, structured list of what it detects, one signal at a time, each with a strength (how present the trait is) and a confidence score (how sure the model is).
Think of it as an automatic reader of how someone relates to others and the world — attachment style, communication habits, values, emotional patterns — built entirely from scratch, not adapted from an existing language model.
What makes this different from a typical text classifier
Most systems that tag text with labels treat every possible label as an independent yes/no question. AmoreSignal instead works the way a thoughtful reader would: it reads the whole text once, then reports out the traits it notices one at a time, in order of how clearly they show up, stopping on its own once it has said what it genuinely found — rather than being forced to score all 53 possible traits on every single input.
Architecture, in plain terms
The model has two parts that work together:
- An encoder — reads and understands the input text.
- A decoder — looks at what the encoder understood, and generates signals one at a time: pick a trait → say how strong it is → decide whether to continue or stop.
Both parts use a technique called weight-sharing, where a single layer's parameters are reused multiple times instead of stacking many different layers — a deliberate design choice to keep the model small and efficient without sacrificing depth of processing.
No pretrained weights of any kind were used anywhere in this pipeline. Every parameter, in both the encoder and the decoder, was learned entirely from scratch.
| Encoder | Decoder | |
|---|---|---|
| Vocabulary | 5,000 (custom tokenizer) | — |
| d_model | 64 | 64 |
| Attention heads | 4 | 4 |
| Layers (weight-shared) | 8 | 8 |
| Feedforward dim | 256 | 256 |
| Output | — | 54 classes (53 signals + a "stop" signal) |
| Parameters | 408,392 | 79,351 |
| Combined total | 487,743 |
A deliberate design decision worth explaining: how confidence works
An earlier version of this model tried to train a separate "confidence" output to imitate how an outside evaluator judged the training data's quality. That was removed — confidence should reflect the model's own certainty, not something borrowed from an external rater that isn't present when the model is actually used.
Instead, confidence here is simply the model's own probability at the
moment it chooses each signal, then passed through a small calibration
step (decoder_calibrator.json) that corrects a well-known problem:
raw model probabilities tend to be poorly calibrated (overconfident or
underconfident) without this kind of correction.
The 53 signals, by category
The model can detect any of the following, organized here by theme for readability — the model itself doesn't use these category labels, it simply predicts individual signals.
Attachment style
anxious_attachment · avoidant_attachment · secure_attachment · fearful_avoidant
Social orientation
introvert · extrovert · intellectual_depth
How someone feels loved (love languages)
love_language_words · love_language_touch · love_language_time · love_language_service · love_language_gifts
Giving patterns
over_giver · balanced_giver · high_emotional_depth
Relationship history and healing
ghosting_trauma · love_bombing_trauma · situationship_trauma · breadcrumbing_trauma · narcissist_survivor · in_healing · post_healing_secure
Lifestyle
homebody · adventurous · fitness_focused · career_ambitious
Dealbreakers
dishonesty_dealbreaker · control_dealbreaker · emotional_unavailability_dealbreaker
Self-worth
low_self_worth · high_self_worth
Family and cultural context
family_oriented · family_pressure · progressive_indian · arranged_marriage_open
Communication style
good_communicator · conflict_avoidant · overthinker
Relationship intent
wants_serious · wants_friendship_first · not_ready
Identity and independence
demisexual · independent_person · needs_stability · needs_adventure
Growth and outlook
spiritual_person · humor_important · wants_growth_partner
Boundaries and awareness
body_autonomy · mental_health_aware · boundary_setter · trauma_aware
Values
values_aligned
A note on the training data and where this is strongest
The signal set above is explicitly built around how people relate
to romantic partners — attachment, love languages, relationship
history, intent. This isn't accidental: the model was trained on
text written in the style of dating-app conversations and
profiles, with several signals (progressive_indian,
arranged_marriage_open, family_pressure) reflecting an Indian
cultural context specifically.
That means the released weights are strongest on exactly this kind of input. The underlying technique — reading text and generating a ranked list of psychological signals — isn't tied to dating at all, and the same approach could reasonably be retrained or fine-tuned for other relational contexts (friendships, workplace dynamics, family relationships), but the weights shared here have not been tested outside the romantic-relationship, Indian-context domain they were trained on.
Training history
Pretraining (learning to understand language), by dataset version
| Version | Profiles | Train tokens | Best validation loss |
|---|---|---|---|
| v1 | 4,002 | 881,633 | 5.8054 |
| v2 | 10,002 | 2,031,052 | 5.6192 |
| v3 (solo) | 23,000 | 4,872,881 | 4.2047 |
| final | 33,002 | 6,807,846 | 2.5625 |
| v2final (targeted fix) | 36,999 | 7,691,704 | 2.6187 |
| v3final (added short-text data) | 39,932 | 7,862,192 | 2.6269 |
Decoder training (learning to generate signals)
| Base encoder | Best validation loss | Real-world F1 score |
|---|---|---|
| v2final | 2.6731 | 0.664 (precision 0.774, recall 0.591) |
| v3final | 2.6408 | see short-text notes below |
For context: independently reproduced GPT-2-scale language models typically converge to a loss around 3.0–3.2 on a vocabulary roughly 1,000 times larger than this model's 54-option output. A loss around 2.6 on this much smaller, more specific task is a solid, realistic result.
Honest evaluation results
Is the model's confidence trustworthy?
Tested on 300 examples the model had never seen during training:
| When the model reports confidence around... | ...how often is it actually right? |
|---|---|
| 40–60% | 35.9% (a small sample; slightly underconfident here) |
| 60–80% | 69.6% |
| 80–100% | 86.8% |
For the vast majority of predictions (98%), the model's stated confidence closely tracks its actual accuracy — a genuinely trustworthy signal, not just a number for show.
Does changing how the model generates output help?
| Approach | Precision | Recall | Overall (F1) |
|---|---|---|---|
| Standard generation (used in production) | 0.774 | 0.591 | 0.664 |
| Forcing a minimum output length | 0.629–0.746 | 0.608–0.681 | 0.647–0.664 |
| Exploring multiple options before choosing (beam search) | 0.790 | 0.572 | 0.657 |
None of these alternatives improved results — the model's real ceiling on recall reflects a genuine limit in what it has learned, not something fixable by generating differently.
Known limitations, stated plainly
- The model misses real signals. On average, it identifies about 60% of the traits actually present in a piece of text — it's more likely to under-report than to make things up.
- A specific group of related signals gets confused with each
other:
narcissist_survivor,boundary_setter,high_self_worth, andtrauma_awareare sometimes mixed up. Targeted fixes improved this in aggregate but didn't fully resolve it on individual real examples. - Short pieces of text are handled inconsistently. The original training data barely contained any text under 100 words, causing systematic misreads (frequently defaulting to insecure attachment styles) on short, casual messages. A fix added thousands of new short examples, and testing shows real improvement on single-topic short messages — but messages that pack in several different topics at once are still unreliable, regardless of length.
- Negation isn't understood. Text that explicitly denies a trait — "I'm not someone who overthinks things" — is still frequently misread as confirming that trait. The training data never included examples of traits being denied, only examples of traits being expressed. This is a known, unresolved gap.
- English only. No validation has been performed on real users — all training data was synthetically generated (using Qwen 2.5 7B Instruct) rather than collected from real people.
Files in this repository
| File | What it is |
|---|---|
encoder_model.safetensors / encoder_model.pt |
Encoder weights |
decoder_model.safetensors / decoder_model.pt |
Decoder weights |
tokenizer.json |
The matching tokenizer |
config.json |
Exact architecture settings |
modeling_amoresignal.py |
Model code + a load_pretrained() helper |
decoder_calibrator.json |
The confidence calibration step described above |
amore_scoring_readable.json |
Maps each of the 53 signals to broader psychological dimensions |
finetune.py |
A ready-to-run script for fine-tuning this model on your own data |
Fine-tuning on your own data
python finetune.py --data your_data.json --output ./finetuned
See the docstring inside finetune.py for the exact data format
expected and practical guidance on how much data you'll likely need.
- Downloads last month
- 52