Update README.md
Browse files
README.md
CHANGED
|
@@ -18,8 +18,17 @@ instance.
|
|
| 18 |
## How it works
|
| 19 |
|
| 20 |
- **Inference engine**: `llama-server` (from [llama.cpp](https://github.com/ggml-org/llama.cpp)),
|
| 21 |
-
compiled from source in the Docker build
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
It's started with `--threads 8 --parallel 8 --cont-batching`, which uses
|
| 24 |
llama.cpp's continuous batching to combine multiple in-flight requests'
|
| 25 |
forward passes into shared compute instead of running them one at a time.
|
|
@@ -47,12 +56,11 @@ Hy-MT2 documents support for).
|
|
| 47 |
```json
|
| 48 |
{
|
| 49 |
"text": "Where is the nearest potion shop?",
|
| 50 |
-
"target_lang": "tr"
|
| 51 |
-
"preserve_placeholders": true
|
| 52 |
}
|
| 53 |
```
|
| 54 |
```json
|
| 55 |
-
{ "translation": "En yakın iksir dükkanı nerede?", "elapsed_seconds":
|
| 56 |
```
|
| 57 |
|
| 58 |
### `POST /translate/batch` — many strings in one call (recommended: 50-100 per call)
|
|
@@ -88,7 +96,7 @@ server-side safety cap on a single call.
|
|
| 88 |
| `source_lang` | string, optional | omit to let the model auto-detect |
|
| 89 |
| `style` | string, optional | e.g. `"casual, playful"` — injected as a style instruction |
|
| 90 |
| `glossary` | object, optional | `{"HP": "Can Puanı"}` — forces specific term translations |
|
| 91 |
-
| `preserve_placeholders` | bool, default `
|
| 92 |
|
| 93 |
### Auth
|
| 94 |
Set the `API_KEY` env var on the Space to require an `X-API-Key` header on
|
|
@@ -98,7 +106,8 @@ Set the `API_KEY` env var on the Space to require an `X-API-Key` header on
|
|
| 98 |
|
| 99 |
| var | default | meaning |
|
| 100 |
|---|---|---|
|
| 101 |
-
| `
|
|
|
|
| 102 |
| `THREADS` | `8` | CPU threads for llama-server |
|
| 103 |
| `PARALLEL_SLOTS` | `8` | concurrent generation slots (continuous batching) |
|
| 104 |
| `CTX_SIZE` | `16384` | total context, split across `PARALLEL_SLOTS` slots |
|
|
@@ -128,3 +137,72 @@ docker run -p 7860:7860 --cpus 8 --memory 32g hy-mt2-api
|
|
| 128 |
|
| 129 |
Then open `test-ui/index.html` in a browser, point it at
|
| 130 |
`http://localhost:7860`, and use it to benchmark single vs. batch requests.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
## How it works
|
| 19 |
|
| 20 |
- **Inference engine**: `llama-server` (from [llama.cpp](https://github.com/ggml-org/llama.cpp)),
|
| 21 |
+
compiled from source in the Docker build. This GGUF depends on the
|
| 22 |
+
`STQ1_0` quant kernel from
|
| 23 |
+
[PR #22836](https://github.com/ggml-org/llama.cpp/pull/22836), which is
|
| 24 |
+
**not yet merged into llama.cpp `master`** (verified directly) — a plain
|
| 25 |
+
`pip install llama-cpp-python` or a vanilla clone of master will compile
|
| 26 |
+
but fail to load this GGUF at runtime. The `Dockerfile` clones master and
|
| 27 |
+
cherry-picks the 3 commits that make up that PR (verified to apply
|
| 28 |
+
cleanly, zero conflicts); it auto-skips the cherry-pick once upstream
|
| 29 |
+
merges it, so no edits are needed later.
|
| 30 |
+
The build is pinned to `-j2` (`BUILD_JOBS`) — see
|
| 31 |
+
[Build notes](#build-notes), this is what stopped the build from hanging.
|
| 32 |
It's started with `--threads 8 --parallel 8 --cont-batching`, which uses
|
| 33 |
llama.cpp's continuous batching to combine multiple in-flight requests'
|
| 34 |
forward passes into shared compute instead of running them one at a time.
|
|
|
|
| 56 |
```json
|
| 57 |
{
|
| 58 |
"text": "Where is the nearest potion shop?",
|
| 59 |
+
"target_lang": "tr"
|
|
|
|
| 60 |
}
|
| 61 |
```
|
| 62 |
```json
|
| 63 |
+
{ "translation": "En yakın iksir dükkanı nerede?", "elapsed_seconds": 4.82 }
|
| 64 |
```
|
| 65 |
|
| 66 |
### `POST /translate/batch` — many strings in one call (recommended: 50-100 per call)
|
|
|
|
| 96 |
| `source_lang` | string, optional | omit to let the model auto-detect |
|
| 97 |
| `style` | string, optional | e.g. `"casual, playful"` — injected as a style instruction |
|
| 98 |
| `glossary` | object, optional | `{"HP": "Can Puanı"}` — forces specific term translations |
|
| 99 |
+
| `preserve_placeholders` | bool, default `false` | adds an explicit "keep placeholders verbatim" clause. **Leave it off**: Hy-MT2 already preserves `\V[1]`, `%1`, `{var}` etc. on its own (measured — see [Verified behaviour](#verified-behaviour)), so the clause only costs prompt tokens |
|
| 100 |
|
| 101 |
### Auth
|
| 102 |
Set the `API_KEY` env var on the Space to require an `X-API-Key` header on
|
|
|
|
| 106 |
|
| 107 |
| var | default | meaning |
|
| 108 |
|---|---|---|
|
| 109 |
+
| `MODEL_REPO` | `tencent/Hy-MT2-7B-GGUF` | set to `tencent/Hy-MT2-1.8B-GGUF` (with a matching `MODEL_FILE`) to trade quality for a large throughput win on bulk jobs |
|
| 110 |
+
| `MODEL_FILE` | `Hy-MT2-7B-Q4_K_M.gguf` | `HY-MT2-7B-Q6_K.gguf` / `HY-MT2-7B-Q8_0.gguf` for higher quality (both fit in 32 GB), or `Hy-MT2-1.8B-Q4_K_M.gguf` with the 1.8B repo |
|
| 111 |
| `THREADS` | `8` | CPU threads for llama-server |
|
| 112 |
| `PARALLEL_SLOTS` | `8` | concurrent generation slots (continuous batching) |
|
| 113 |
| `CTX_SIZE` | `16384` | total context, split across `PARALLEL_SLOTS` slots |
|
|
|
|
| 137 |
|
| 138 |
Then open `test-ui/index.html` in a browser, point it at
|
| 139 |
`http://localhost:7860`, and use it to benchmark single vs. batch requests.
|
| 140 |
+
|
| 141 |
+
## Verified behaviour
|
| 142 |
+
|
| 143 |
+
The stack below was actually run end to end against
|
| 144 |
+
`Hy-MT2-7B-Q4_K_M.gguf` (real model, real llama-server built exactly as the
|
| 145 |
+
`Dockerfile` builds it) on a **4-core / 15 GB** box — smaller than the 8 vCPU
|
| 146 |
+
Space, so treat these as a floor, not a target.
|
| 147 |
+
|
| 148 |
+
- The STQ1_0 cherry-pick works: the model loads and generates. This was the
|
| 149 |
+
whole open question, and it is settled.
|
| 150 |
+
- Translation quality spot-checks (EN→TR): `"Potion"` → `"İksir"`,
|
| 151 |
+
`"Are you sure you want to quit the game?"` →
|
| 152 |
+
`"Oyundan çıkmak istediğinizden emin misiniz?"`.
|
| 153 |
+
- **Placeholders survive untouched with no special instruction**:
|
| 154 |
+
`"You have obtained \V[1] gold."` → `"\V[1] altın elde ettiniz."`, and
|
| 155 |
+
`"Press %1 to open your inventory."` →
|
| 156 |
+
`"Envanterinizi açmak için %1'e basın."`.
|
| 157 |
+
- `glossary` and `style` both take effect: with `{"gold": "altın", "HP": "Can
|
| 158 |
+
Puanı"}` the model returned `"50 altınınız ve dolu Can Puanınız var."`;
|
| 159 |
+
with style `medieval, formal`, `"Hey, watch out!"` → `"Ey dostum, dikkatli
|
| 160 |
+
ol!"`.
|
| 161 |
+
- Throughput, 8 short game strings, 4 slots on 4 cores:
|
| 162 |
+
**sequential 19.2 s vs. batch 12.2 s (1.58×)**. A 24-item batch of longer
|
| 163 |
+
sentences ran at 0.34 items/s. Expect roughly double on 8 vCPU.
|
| 164 |
+
|
| 165 |
+
Planning number: at ~0.7 items/s (8 vCPU, 7B, sentence-length strings)
|
| 166 |
+
50,000 strings is on the order of a day of wall-clock time. If that matters
|
| 167 |
+
more than the last few quality points, switch `MODEL_REPO`/`MODEL_FILE` to
|
| 168 |
+
the 1.8B GGUF — same API, same prompts, several times faster.
|
| 169 |
+
|
| 170 |
+
### A note on `preserve_placeholders`
|
| 171 |
+
|
| 172 |
+
An earlier version of this API sent a long "never translate `\N[..]`,
|
| 173 |
+
`{variable}`, `%s` …" instruction on every request, with that list spelled
|
| 174 |
+
out. Hy-MT2 is a pure translation model, not a general chat model: it
|
| 175 |
+
**translated the instruction** instead of following it, and short inputs were
|
| 176 |
+
destroyed outright — `"Potion"` came back as the Turkish text of the
|
| 177 |
+
instruction, with the actual word gone. Anything the model is meant to obey
|
| 178 |
+
has to live inside the single instruction line of the model card's documented
|
| 179 |
+
templates, never as its own paragraph in front of the source text. The flag
|
| 180 |
+
now defaults to off and, when enabled, adds one short clause with no literal
|
| 181 |
+
placeholder examples.
|
| 182 |
+
|
| 183 |
+
## Build notes
|
| 184 |
+
|
| 185 |
+
The Docker build compiles llama.cpp, which is the slow part. Earlier builds
|
| 186 |
+
**hung at 24% for 5+ hours and then died with no error message** — the giveaway
|
| 187 |
+
was that they stopped at exactly the same source file every time. Cause:
|
| 188 |
+
`-j$(nproc)` reads the *host's* core count on a Hugging Face build worker
|
| 189 |
+
while the worker's memory ceiling is much lower, so dozens of concurrent g++
|
| 190 |
+
processes thrash it into swap. Bounding it (`BUILD_JOBS=2`, plus
|
| 191 |
+
`LLAMA_BUILD_UI=OFF` so the build stops fetching a UI tarball over the
|
| 192 |
+
network) is the fix: the same target builds in **about 4 minutes at -j4** on a
|
| 193 |
+
4-core machine.
|
| 194 |
+
|
| 195 |
+
This cost is paid once — Docker layer caching skips the whole compile on
|
| 196 |
+
later deploys as long as you don't edit the `Dockerfile`. Editing only
|
| 197 |
+
`app/` or `test-ui/` rebuilds in seconds.
|
| 198 |
+
|
| 199 |
+
Two other latent problems were fixed at the same time:
|
| 200 |
+
|
| 201 |
+
- The old build produced a **shared** llama-server (`libllama.so`,
|
| 202 |
+
`libggml*.so`) but the runtime stage copied only the executable, so even a
|
| 203 |
+
successful build would have crashed at startup on a missing shared library.
|
| 204 |
+
The build is now static (`BUILD_SHARED_LIBS=OFF`), one file, and
|
| 205 |
+
`llama-server --version` runs as a build-time smoke test.
|
| 206 |
+
- `--mlock` is deprecated in current llama.cpp (superseded by `--load-mode`),
|
| 207 |
+
so `entrypoint.sh` does not use it; the default mmap loading is right for a
|
| 208 |
+
4.6 GB model on 32 GB of RAM.
|