Downloads · 30 days
5
6% of all-time downloads
pblrvo/Qwen3-4B-Game-semantic-IDs-v2
Qwen3-4B-Game-semantic-IDs-v2 is a text generation model from pblrvo. Use it when you need the model to write or continue text. It is set up for peft. The card lists the license as apache-2.0.
QLoRA fine-tune of Qwen/Qwen3-4B to reason over semantic IDs -- short discrete codes produced by an RQ-VAE trained on game-catalog item embeddings -- instead of ever seeing raw item IDs or embeddings directly. Trained…
Downloads · 30 days
5
6% of all-time downloads
All-time downloads
89
Public
Repo size
4.8 GB
Likes
0
Public
Click a slice to open those files.
.safetensors4.8 GB · 100%
From the Hugging Face model README
QLoRA fine-tune of Qwen/Qwen3-4B to reason over semantic IDs -- short discrete codes produced by an RQ-VAE trained on game-catalog item embeddings -- instead of ever seeing raw item IDs or embeddings directly. Trained on the paired dataset pblrvo/steam-games-semanticIds-instructions.
This is a second iteration over pblrvo/Qwen3-4B-Game-semantic-IDs (v1), kept as a separate model rather than replacing it -- the two make different tradeoffs (see Evaluation below) and v1 is still the better choice for some use cases.
nl_preference (open-ended natural-language queries, e.g. "I want a racing
game") and nl_similar_item (natural-language "recommend something like X" queries), both grounded
in the same catalog/co-occurrence data as the existing tasks.Game catalog items -> embedded (Qwen3-0.6B) -> compressed into 4-level semantic IDs via RQ-VAE -> those ID tokens become new vocabulary the LLM is fine-tuned to reason over. Two-stage fine-tuning:
Both stages run through 4-bit quantization -- full-parameter fine-tuning of a ~4B model doesn't fit a single 12GB consumer GPU alongside gradients/optimizer state.
Recall@K / NDCG@K via constrained beam search (candidates restricted to real catalog items through a
trie over valid semantic IDs / descriptions), the same methodology TIGER (Rajput et al. 2023) and
LC-Rec use for semantic-ID generative recommenders. n=500 per task (n=71-277 where a task's val split
has fewer examples than that), temperature=0.8, beam=10; catalog size ~8,563 items, so random-chance
Recall@10 is ~0.12%. grounding_id2name and asy (both name+genres(+blurb)-output tasks) are scored by
collapsing each beam candidate and the target down to just the item's plain Name before scoring, so the
metric asks "predicted the correct game" rather than requiring an exact match on genre/blurb text too.
| Task | v1 Recall@5 | v2 Recall@5 | v1 Recall@10 | v2 Recall@10 | v1 NDCG@10 | v2 NDCG@10 |
|---|---|---|---|---|---|---|
| grounding_name2id | 2% | 32.4% | 3% | 41.2% | 0.012 | 0.275 |
| grounding_id2name | 0% | 0.2% | 0% | 0.2% | 0.000 | 0.002 |
| asy | -- (not evaluated) | 0% | -- | 0% | -- | 0.000 |
| sequential | 12% | 2.6% | 13% | 3.0% | 0.094 | 0.023 |
| similar_item | 10% | 3.8% | 13% | 5.6% | 0.082 | 0.035 |
| nl_similar_item | -- (new) | 2.9% | -- | 5.1% | -- | 0.027 |
| nl_preference | -- (new) | 77.5% | -- | 87.3% | -- | 0.662 |
This is a real tradeoff, not a clean win. Grounding (name<->SID) improved dramatically. But
sequential/similar_item regressed substantially under strict exact-match Recall@K -- most likely
because the cross-task exposure cap cut raw training volume for those tasks by ~40%, trading some
ability to memorize the specific recorded co-occurrence pairing for eliminating the popularity-
collapse shortcut (v1's tendency to recommend the same few popular items regardless of input).
Qualitative spot-checks (10-15 examples each, decoded to game names) support that read only partly.
v2's predictions for sequential/similar_item are often genre/franchise-coherent and fully diverse (no
repeated defaults) even when they miss the specific recorded target -- e.g. a racing-game seed
predicts another racing game, a Saints Row 2 history predicts Saints Row: The Third. Recall@K can't
credit a plausible-but-different answer, so the metric understates v2's real recommendation quality on
these tasks to some degree. But a second check complicates the "just needs more training data" story:
for a batch of similar_item misses, the specific recorded target's own training exposure was solidly
mid-range (6-22 repeats, vs. a dataset median of 12 post-cap) -- not the low-exposure outliers a pure
data-starvation explanation would predict. And not every miss is genre-coherent either: a Time Mysteries 3 seed (same series as its recorded Time Mysteries 2 target) predicted an unrelated
Medieval: Total War, no genre or franchise logic behind it. The more accurate picture: similar_item's
ground truth itself is inherently ambiguous (a seed item can have up to 10 valid co-occurring partners
in the raw data, e.g. from bundles or sales rather than genre; only one is credited per eval example), so
some of the gap is metric-can't-credit-a-different-valid-answer, but some is a genuine specific-recall
gap unrelated to how often that particular item was seen. Checkpoint-by-checkpoint Recall@K was flat
across the entire back half of training (no late-training improvement), consistent with the model having
already reached whatever ceiling this recipe supports rather than needing more steps.
grounding_id2name/asy are the one place a real evaluation bug was found and fixed mid-analysis:
constrained beam search defaulted to max_new_tokens=32, plenty for the 6-token semantic-ID outputs but
far too small once grounding_id2name's target could include a ~90-token blurb -- generation was being
hard-cut before reaching any valid stopping point, so candidates never matched anything, correct or
not. Fixing that (raised to 96 for these two tasks) moved grounding_id2name from a measured 0.00% to
0.20% -- genuinely small, not an artifact. The likely real explanation: a semantic ID's coarser RQ-VAE
codes are deliberately shared across many similar items (that's what makes the hierarchy useful for
generalization elsewhere), so recovering the one specific name behind a shared/coarse code is close to
an arbitrary lookup problem, and a rank-8 LoRA adapter over ~8,500 items may not have the capacity to
memorize it precisely.
Qwen3-8B-Game-semantic-IDs-v3
(bigger model, full-parameter fine-tune, redesigned dataset) initially looked like it
regressed on sequential/asy relative to this model's numbers above -- but those
numbers were measured on a different, pre-redesign val set with temperature=0.8
sampling, not v3's deterministic eval on the redesigned data. That was never a
controlled comparison. Two things were checked to make it one:
Is the semantic-ID vocabulary even comparable? If the RQ-VAE had been retrained for
v3, this model's learned token embeddings would encode a different item mapping than
v3's, making any comparison invalid outright. Checked directly by joining this model's
own training data (8,093 grounding_name2id name->SID pairs) against the current
codebook by item name: 8,011/8,093 (99.0%) identical assignments -- the 82
mismatches are ambiguous duplicate catalog names (e.g. "Portal", "Contract"), not a
re-embedding. The codebook is unchanged, so a fair comparison is valid.
Re-run under identical conditions. This model was re-evaluated with v3's exact eval code, val set, and settings (n=500/task, seed=0, deterministic beam search):
| Task | This model (v2), fair comparison | v3 |
|---|---|---|
| grounding_name2id | 37.00% | 96.80% |
| sequential | 3.60% | 1.00% |
| similar_item | 1.00% | 1.00% |
| nl_similar_item | 4.40% | 2.00% |
| grounding_id2name | 0.20% | 7.20% |
| asy | 0.00% | 0.00% |
| nl_preference | 84.86% | 94.95% |
The sequential edge over v3 holds up under fair conditions -- not a dataset artifact.
But re-scored under a metric that asks "did the model recommend any game this user
actually played" instead of the one exact next-lowest-playtime item (justification:
these sequences are ordered by playtime, not real chronology -- see v3's README for the
full argument), the picture changes substantially:
| Task | Metric | This model (v2) | v3 |
|---|---|---|---|
| sequential | Any-played Hit@10 | 59.20% | 58.00% |
| sequential | Small-library Hit@10 (lift over random) | 49.03% (23.03x) | 43.24% (20.31x) |
| asy | Any-played Hit@10 | 21.80% | 36.20% |
| asy | Small-library Hit@10 (lift over random) | 7.54% (2.98x) | 21.83% (8.62x) |
sequential is a near-tie once measured this way (the apparent 3.6x gap was mostly an
artifact of exact-match Recall@K's sensitivity to an arbitrary playtime-rank position,
not a real capability gap). asy is not a tie -- v3 wins clearly (1.7x pooled, 2.9x on
the harder small-library stratum), a real improvement the exact-match metric couldn't
see because both models scored a flat 0.00% under it. Full writeup, including the
codebook-compatibility check and multi-target methodology:
SEQUENTIAL_ASY_REGRESSION_ANALYSIS.md
in the project repository.
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import PeftModel
ADAPTER = "pblrvo/Qwen3-4B-Game-semantic-IDs-v2"
BASE_MODEL = "Qwen/Qwen3-4B"
tokenizer = AutoTokenizer.from_pretrained(ADAPTER)
quantization_config = BitsAndBytesConfig(
load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True, llm_int8_skip_modules=["lm_head"],
)
base_model = AutoModelForCausalLM.from_pretrained(BASE_MODEL, dtype=torch.bfloat16, quantization_config=quantization_config)
base_model.resize_token_embeddings(len(tokenizer))
model = PeftModel.from_pretrained(base_model, ADAPTER)
The semantic-ID vocabulary (<|sid_start|>, <|sid_L{level}_{code}|>, <|sid_end|>) is only
meaningful relative to the specific RQ-VAE codebook trained in the source project -- this model isn't
usable standalone without that catalog/codebook context.