Upload README.md with huggingface_hub
Browse files
README.md
CHANGED
|
@@ -39,23 +39,23 @@ was measured against.
|
|
| 39 |
|
| 40 |
| build | encoder | decoder | encoder speed | decoder speed |
|
| 41 |
|---|---|---|---|---|
|
| 42 |
-
| **Core ML + XNNPACK int8** | `manga_ocr_encoder_coreml_all.pte` **172.1 MB** | `manga_ocr_decoder_xnnpack_int8.pte` **45.0 MB** | **4.
|
| 43 |
-
| XNNPACK int8 | `manga_ocr_encoder_xnnpack_int8.pte` 88.9 MB | `manga_ocr_decoder_xnnpack_int8.pte` 45.0 MB |
|
| 44 |
-
| XNNPACK fp32 | `manga_ocr_encoder_xnnpack_fp32.pte` 343.
|
| 45 |
-
| XNNPACK fp16 | `manga_ocr_encoder_xnnpack_fp16.pte` 173.1 MB | `manga_ocr_decoder_xnnpack_fp16.pte` 58.8 MB |
|
| 46 |
|
| 47 |
Host numbers, on a loaded machine, decoder timed at a 3-character prefix β read them as a
|
| 48 |
lower bound and as ratios rather than as device latency. Eager fp32 on the same host is
|
| 49 |
-
29.
|
|
|
|
| 50 |
|
| 51 |
-
**fp16 is the row nothing should pick.**
|
| 52 |
-
half the speed of fp32
|
| 53 |
-
|
| 54 |
-
anything.
|
| 55 |
|
| 56 |
**int8 is the row to pick on Android**: half of fp16 on the encoder and three-quarters of
|
| 57 |
-
it on the decoder, faster than
|
| 58 |
-
anywhere it was measured. What that costs is margin, not characters β see below.
|
| 59 |
|
| 60 |
## Running it
|
| 61 |
|
|
@@ -118,15 +118,16 @@ the boundary per step instead of L times that.
|
|
| 118 |
## Greedy, not beam search
|
| 119 |
|
| 120 |
The checkpoint's own generation config asks for 4 beams. Greedy is what the graph is
|
| 121 |
-
shaped for
|
| 122 |
-
greedy and beam-4 read the same string
|
| 123 |
-
|
| 124 |
-
|
|
|
|
| 125 |
|
| 126 |
## Core ML: the encoder yes, the decoder no
|
| 127 |
|
| 128 |
-
**The encoder is the whole speed story**: 100% delegated, 4.
|
| 129 |
-
on the same host, at 172.1 MB. Worst-output correlation against fp32 eager is 0.
|
| 130 |
|
| 131 |
**The decoder is not shipped for Core ML, and the reason is specific.** It converts, it
|
| 132 |
delegates 100%, and β once eight zero-element constants that transformers' BERT attention
|
|
@@ -170,17 +171,17 @@ is a tie, below 0.0 is a changed character.
|
|
| 170 |
| build | median | worst step | steps changed |
|
| 171 |
|---|---|---|---|
|
| 172 |
| XNNPACK fp32 | 1.0000 | 1.0000 | 0 / 1008 |
|
| 173 |
-
| XNNPACK fp16 |
|
| 174 |
-
| XNNPACK int8 |
|
| 175 |
|
| 176 |
-
**int8's worst moment still kept
|
| 177 |
-
recommendation, not the 84 identical strings.
|
| 178 |
|
| 179 |
-
|
| 180 |
-
error anywhere in the 6,144 logits
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
|
| 185 |
### What a whole line costs
|
| 186 |
|
|
@@ -189,15 +190,15 @@ emitted. Measured per call, median of 20:
|
|
| 189 |
|
| 190 |
| prefix | fp32 | fp16 | int8 |
|
| 191 |
|---|---|---|---|
|
| 192 |
-
| 1 | 2.
|
| 193 |
-
| 8 | 3.
|
| 194 |
-
| 32 |
|
| 195 |
-
| 64 |
|
| 196 |
-
|
| 197 |
-
**Sixty-four times the prefix costs 2.
|
| 198 |
-
cache a fair trade. Summed over the prefixes a real line walks through, the decoder side
|
| 199 |
-
|
| 200 |
-
|
| 201 |
|
| 202 |
### What this does not say
|
| 203 |
|
|
|
|
| 39 |
|
| 40 |
| build | encoder | decoder | encoder speed | decoder speed |
|
| 41 |
|---|---|---|---|---|
|
| 42 |
+
| **Core ML + XNNPACK int8** | `manga_ocr_encoder_coreml_all.pte` **172.1 MB** | `manga_ocr_decoder_xnnpack_int8.pte` **45.0 MB** | **4.2 ms** | 2.5 ms |
|
| 43 |
+
| XNNPACK int8 | `manga_ocr_encoder_xnnpack_int8.pte` 88.9 MB | `manga_ocr_decoder_xnnpack_int8.pte` 45.0 MB | 25.5 ms | 2.5 ms |
|
| 44 |
+
| XNNPACK fp32 | `manga_ocr_encoder_xnnpack_fp32.pte` 343.3 MB | `manga_ocr_decoder_xnnpack_fp32.pte` 117.4 MB | 29.5 ms | 3.2 ms |
|
| 45 |
+
| XNNPACK fp16 | `manga_ocr_encoder_xnnpack_fp16.pte` 173.1 MB | `manga_ocr_decoder_xnnpack_fp16.pte` 58.8 MB | 71.2 ms | 3.1 ms |
|
| 46 |
|
| 47 |
Host numbers, on a loaded machine, decoder timed at a 3-character prefix β read them as a
|
| 48 |
lower bound and as ratios rather than as device latency. Eager fp32 on the same host is
|
| 49 |
+
29.9 ms for the encoder and 4.6 ms for the decoder. XNNPACK takes 82.9% of the encoder
|
| 50 |
+
and 51.9% of the decoder; Core ML takes all of the encoder.
|
| 51 |
|
| 52 |
+
**fp16 is the row nothing should pick.** Its encoder is the size of the Core ML build and
|
| 53 |
+
less than half the speed of fp32, because XNNPACK inserts a cast at every boundary it
|
| 54 |
+
cannot fuse. It is listed because it was built and measured, not because it wins anything.
|
|
|
|
| 55 |
|
| 56 |
**int8 is the row to pick on Android**: half of fp16 on the encoder and three-quarters of
|
| 57 |
+
it on the decoder, **faster than eager PyTorch on both**, and no character different from
|
| 58 |
+
eager anywhere it was measured. What that costs is margin, not characters β see below.
|
| 59 |
|
| 60 |
## Running it
|
| 61 |
|
|
|
|
| 118 |
## Greedy, not beam search
|
| 119 |
|
| 120 |
The checkpoint's own generation config asks for 4 beams. Greedy is what the graph is
|
| 121 |
+
shaped for and what every number here was measured with; on the horizontal gate image
|
| 122 |
+
greedy and beam-4 read the same string, and the 84-line set never needed more than greedy
|
| 123 |
+
to match eager. Beam search remains possible from outside β the decoder is a pure function
|
| 124 |
+
of `(prefix, hidden)`, so a caller can run it once per beam per step β but what it buys on
|
| 125 |
+
harder input than this has not been measured.
|
| 126 |
|
| 127 |
## Core ML: the encoder yes, the decoder no
|
| 128 |
|
| 129 |
+
**The encoder is the whole speed story**: 100% delegated, 4.2 ms against 29.9 ms for eager
|
| 130 |
+
on the same host, at 172.1 MB. Worst-output correlation against fp32 eager is 0.999984.
|
| 131 |
|
| 132 |
**The decoder is not shipped for Core ML, and the reason is specific.** It converts, it
|
| 133 |
delegates 100%, and β once eight zero-element constants that transformers' BERT attention
|
|
|
|
| 171 |
| build | median | worst step | steps changed |
|
| 172 |
|---|---|---|---|
|
| 173 |
| XNNPACK fp32 | 1.0000 | 1.0000 | 0 / 1008 |
|
| 174 |
+
| XNNPACK fp16 | 0.9999 | 0.9820 | 0 / 1008 |
|
| 175 |
+
| XNNPACK int8 | 0.9999 | **0.6513** | 0 / 1008 |
|
| 176 |
|
| 177 |
+
**int8's worst moment still kept 65% of the margin**, and it is the only step below 0.9.
|
| 178 |
+
That is the number behind the recommendation, not the 84 identical strings.
|
| 179 |
|
| 180 |
+
The same steps also carry a worst-case bound β the reference gap over twice the largest
|
| 181 |
+
error anywhere in the 6,144 logits, which assumes that error landed exactly where it would
|
| 182 |
+
do the most damage. Its minimum is **1.16 for int8**, above 1.0, so on this set a changed
|
| 183 |
+
character is not merely absent but arithmetically impossible. Both numbers are printed by
|
| 184 |
+
`convert/check_manga_ocr.py`.
|
| 185 |
|
| 186 |
### What a whole line costs
|
| 187 |
|
|
|
|
| 190 |
|
| 191 |
| prefix | fp32 | fp16 | int8 |
|
| 192 |
|---|---|---|---|
|
| 193 |
+
| 1 | 2.36 ms | 2.27 ms | 2.18 ms |
|
| 194 |
+
| 8 | 3.37 ms | 3.45 ms | 2.90 ms |
|
| 195 |
+
| 32 | 3.94 ms | 4.88 ms | 4.26 ms |
|
| 196 |
+
| 64 | 5.31 ms | 6.94 ms | 4.99 ms |
|
| 197 |
+
|
| 198 |
+
**Sixty-four times the prefix costs 2.3 times the step**, which is what makes the missing
|
| 199 |
+
cache a fair trade. Summed over the prefixes a real line walks through, the decoder side of
|
| 200 |
+
a **12-character line is 33 ms on int8** (39 ms fp32); add one encoder run β 4.2 ms on
|
| 201 |
+
Core ML, 25.5 ms on XNNPACK int8 β for the whole read.
|
| 202 |
|
| 203 |
### What this does not say
|
| 204 |
|