gamespace.1 / README.md
GulkoA's picture
Add ONNX weights and projection for in-browser inference
e5b8529 verified
|
Raw History Blame Contribute Delete
6.15 kB
---
license: apache-2.0
language:
- en
library_name: sentence-transformers
pipeline_tag: sentence-similarity
base_model: sentence-transformers/all-MiniLM-L6-v2
datasets:
- FronkonGames/steam-games-dataset
tags:
- transformers.js
- onnx
- sentence-transformers
- sentence-similarity
- feature-extraction
- recommendation
- video-games
- steam
---
# gamespace.1
gamespace.1 embeds Steam games into a 128-dimensional space where games that play alike sit close
together. It powers the [GameMerge](https://huggingface.co/spaces/GulkoA/gamemerge) recommender,
which ranks every game on Steam by cosine similarity to the games you like.
It is [all-MiniLM-L6-v2](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2), fine-tuned
on 138,920 Steam games, with a trained projection from 384 to 128 dimensions. Output vectors are
L2-normalised, so a dot product is the cosine similarity.
## Usage
The model reads one short text document per game, built from store metadata. Use `docs.py` from
this repo to build documents in exactly the format the model was trained on.
```python
from huggingface_hub import hf_hub_download
from sentence_transformers import SentenceTransformer
import importlib.util
model = SentenceTransformer("GulkoA/gamespace.1")
spec = importlib.util.spec_from_file_location("docs", hf_hub_download("GulkoA/gamespace.1", "docs.py"))
docs = importlib.util.module_from_spec(spec); spec.loader.exec_module(docs)
game = {
"name": "Hollow Knight",
"genres": ["Action", "Adventure", "Indie"],
"tags": ["Metroidvania", "Souls-like", "Platformer", "Difficult", "Atmospheric"], # most-voted first
"categories": ["Single-player"],
"developers": ["Team Cherry"],
"short": "Forge your own path in Hollow Knight! An epic action adventure through a vast ruined kingdom of insects and heroes.",
"about": "",
}
vec = model.encode(docs.build_doc(game)) # shape (128,), unit length
```
The resulting document looks like this:
```
Hollow Knight. Genres: Action, Adventure, Indie. Tags: Metroidvania, Souls-like, ... Modes: Single-player. Developer: Team Cherry. Forge your own path...
```
### In the browser
`onnx/model_quantized.onnx` (22 MB, per-channel int8, cosine 0.995 to the PyTorch model) runs with
[transformers.js](https://huggingface.co/docs/transformers.js). Apply the 128x384 projection in
`dense.bin` (float32 weights, row-major, followed by the 128 biases) to the mean-pooled output:
```js
import { pipeline } from "@huggingface/transformers";
const extractor = await pipeline("feature-extraction", "GulkoA/gamespace.1", { dtype: "q8" });
const w = new Float32Array(await (await fetch("https://huggingface.co/GulkoA/gamespace.1/resolve/main/dense.bin")).arrayBuffer());
const { data: x } = await extractor("cozy farming game with fishing", { pooling: "mean", normalize: false });
const y = Array.from({ length: 128 }, (_, i) => w[128 * 384 + i] + x.reduce((s, xj, j) => s + w[i * 384 + j] * xj, 0));
const norm = Math.hypot(...y);
const vec = y.map((v) => v / norm); // 128-d, unit length
```
Use `dtype: "fp32"` with `onnx/model.onnx` for output identical to PyTorch.
Missing fields are simply left out. Games with no user tags still embed well from their
description, since training deliberately hid tags half the time.
## Training
- **Data.** The [Steam Games Dataset](https://huggingface.co/datasets/FronkonGames/steam-games-dataset)
has 147,352 apps. Soundtracks, demos, playtests, dedicated servers, SDKs, and empty records were
removed, leaving 138,920 games. 3,000 tagged games were held out from all training.
- **Objective.** Contrastive training uses `CachedMultipleNegativesRankingLoss` with 128 in-batch
negatives and 140,000 positive pairs:
- 70,000 pairs are two randomly degraded views of the same game. Each view may drop the tag list,
the description, or part of each.
- 70,000 pairs are two different games whose vote-weighted user-tag profiles have a cosine of at
least 0.6.
- **Projection.** A `Dense(384→128)` layer, initialised from the PCA basis of the base model's
embeddings, is trained end to end.
- **Settings.** One epoch, learning rate 3e-5, 128-token documents, fp16, on one RTX 3050 Ti laptop
GPU in about 20 minutes.
- **Excluded signals.** Review counts, price, playtime, and owner counts are never shown to the
model. Similarity reflects what a game is, not how popular it is.
## Evaluation
For each held-out game, we retrieve its 10 nearest neighbours from a fixed pool of 30,000 tagged
games. The score is the mean cosine between the query's vote-weighted, IDF-scaled tag profile and
those of its neighbours. "Description only" embeds the query with its tags removed.
| Model | With tags | Description only |
|---|---|---|
| Random pairs | 0.076 | 0.076 |
| all-MiniLM-L6-v2, no fine-tuning | 0.230 | 0.208 |
| TSDAE denoising autoencoder, then contrastive | 0.493 | 0.370 |
| **gamespace.1, contrastive only** | **0.503** | **0.376** |
| Ceiling, matching on true tags | 0.621 | n/a |
A TSDAE denoising-autoencoder stage before contrastive training scored the same within noise. A
side-by-side look at the neighbours of well-known games slightly favoured the model without it, so
gamespace.1 skips that stage.
## Example neighbours
| Game | Nearest games |
|---|---|
| DARK SOULS III | Dark Souls II: Scholar of the First Sin, Dark Souls Remastered, Elden Ring, Lies of P |
| Stardew Valley | Staxel, Dinkum, Coral Island, Sun Haven |
| Factorio | FOUNDRY, Satisfactory, shapez, Techtonica |
| Euro Truck Simulator 2 | American Truck Simulator, Truck & Logistics Simulator, The Bus |
## Limitations
- Similarity is about content, so obscure, low-quality, or unreleased games rank alongside
well-known ones.
- Tags are user-generated and English-centric. Descriptions in other languages embed less reliably.
- The catalog snapshot ends in September 2026.
## License
The model is licensed under Apache 2.0, the same as the base model. The training data is MIT-licensed.