|
| 1 | +<!DOCTYPE html> |
| 2 | +<html lang="en"> |
| 3 | +<head> |
| 4 | + <meta charset="UTF-8"> |
| 5 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 6 | + <title>Floating-Point Formats</title> |
| 7 | + <style> |
| 8 | + body { |
| 9 | + font-family: Arial, sans-serif; |
| 10 | + line-height: 1.6; |
| 11 | + margin: 0; |
| 12 | + padding: 0; |
| 13 | + background-color: #333; /* Dark grey background */ |
| 14 | + color: #f0f0f0; /* Off-white text color */ |
| 15 | + } |
| 16 | + |
| 17 | + header { |
| 18 | + text-align: center; |
| 19 | + background-color: #3498db; |
| 20 | + color: #fff; |
| 21 | + padding: 20px; |
| 22 | + position: sticky; |
| 23 | + top: 0; |
| 24 | + z-index: 999; |
| 25 | + } |
| 26 | + |
| 27 | + main { |
| 28 | + max-width: 800px; |
| 29 | + margin: 0 auto; |
| 30 | + padding: 20px; |
| 31 | + } |
| 32 | + |
| 33 | + img { |
| 34 | + display: block; |
| 35 | + margin: 0 auto; |
| 36 | + max-width: 100%; |
| 37 | + height: auto; |
| 38 | + } |
| 39 | + |
| 40 | + h1, h2 { |
| 41 | + color: #333; |
| 42 | + } |
| 43 | + |
| 44 | + p { |
| 45 | + text-indent: 35px; /* Indent paragraphs */ |
| 46 | + } |
| 47 | + |
| 48 | + table { |
| 49 | + border-collapse: collapse; |
| 50 | + width: 100%; |
| 51 | + } |
| 52 | + |
| 53 | + th, td { |
| 54 | + text-align: left; |
| 55 | + padding: 8px; |
| 56 | + border-bottom: 1px solid #ddd; |
| 57 | + } |
| 58 | + |
| 59 | + th { |
| 60 | + background-color: #f2f2f2; |
| 61 | + color: #000; |
| 62 | + } |
| 63 | + |
| 64 | + footer { |
| 65 | + text-align: center; |
| 66 | + background-color: #333; |
| 67 | + color: #fff; |
| 68 | + padding: 10px; |
| 69 | + } |
| 70 | + </style> |
| 71 | + |
| 72 | +</head> |
| 73 | + |
| 74 | +<body> |
| 75 | + <header> |
| 76 | + <h1>Floating-Point Formats</h1> |
| 77 | + </header> |
| 78 | + |
| 79 | + <main> |
| 80 | + <section> |
| 81 | + <img src="./float.png" alt="Floating Point"> |
| 82 | + </section> |
| 83 | + |
| 84 | + <section> |
| 85 | + <h2 style="color: #f0f0f0;">Introduction to Floating-Point Formats</h2> |
| 86 | + <p>Running an embedding model or a large language model requires a lot of math calculations and computers don't understand decimal |
| 87 | + numbers (1,2,3) like you and me. Rather, they use a series of ones and zeros to represent a number, which are called "bits." The |
| 88 | + more bits that are used, the more VRAM/RAM and computational horsepower required. However, more bits also "generally" means a |
| 89 | + higher quality result.</p> |
| 90 | + |
| 91 | + <p>I say "generally" becuase even if the same number of bits are used the quality also depends on how many of those bits are |
| 92 | + "exponent" versus "fraction" bits. The term "floating point format" is defined by both the total number of "bits" used |
| 93 | + as well as how many of the bits are "exponent" versus "fraction" bits. The three most common floating point formats above |
| 94 | + illustrate these concepts. For example, both float16 and bfloat16 have the same total bits (16) but a different number of |
| 95 | + "exponent" versus "fraction" bits.</p> |
| 96 | + |
| 97 | + <p>"Exponent" bits basically determine the "range" of numbers that a neural network can utilize when doing math. For example, |
| 98 | + since Float32 has 8 "exponent" bits lets pretend that this allows the neural network to use any integer |
| 99 | + between one and one-hundred for the math calculations. It's "range," therefore, is 1-100. Bfloat16 would have |
| 100 | + the same "range" because it also has 8 "exponent" bits. However, float16 only has 5 "exponent" bits so "range" might be 1-50.</p> |
| 101 | + |
| 102 | + <p></p> |
| 103 | + |
| 104 | + <p>In contrast, "fraction" bits basically determine the number of values that can be used within that "range." The number |
| 105 | + of "fraction" bits is informally referred to a neural network's "precision." To give another hypothetical, since float32 has 23 |
| 106 | + "fraction" bits let's assume it can use every whole number between 1-100 when doing math calculations Therefore, it has 100 |
| 107 | + "values" it can use. In contrast, because bfloat16 only has 7 "fraction" bits could only 25 integers within the "range" of 1-100.</p> |
| 108 | + |
| 109 | + <p>These are hypotheticals, however, the actual ranges and precision are summarized in this table:</p> |
| 110 | + |
| 111 | + <table border="1"> |
| 112 | + <tr> |
| 113 | + <th>Floating Point Format</th> |
| 114 | + <th>Range (Based on Exponent)</th> |
| 115 | + <th>Discrete Values (Based on Fraction)</th> |
| 116 | + </tr> |
| 117 | + <tr> |
| 118 | + <td>float32</td> |
| 119 | + <td>~3.4×10<sup>38</sup></td> |
| 120 | + <td>8,388,608</td> |
| 121 | + </tr> |
| 122 | + <tr> |
| 123 | + <td>float16</td> |
| 124 | + <td>±65,504</td> |
| 125 | + <td>1,024</td> |
| 126 | + </tr> |
| 127 | + <tr> |
| 128 | + <td>bfloat16</td> |
| 129 | + <td>~3.4×10<sup>38</sup></td> |
| 130 | + <td>128</td> |
| 131 | + </tr> |
| 132 | + </table> |
| 133 | + |
| 134 | + </section> |
| 135 | + |
| 136 | + <p>Overall, both "range" and "precision" determine the "quality" of an output but in different ways. The specifics are complex. |
| 137 | + However, in general the particular use case determines the best floating point format to use. For example, Google created |
| 138 | + bfloat16 and found that it was overall better for neural networks but that float16 was better for scientific calculations.</p> |
| 139 | + |
| 140 | + <p>You can see the floating point format used to create the various embedding models in this program by looking at the |
| 141 | + "config.json" file for each model.</p> |
| 142 | + |
| 143 | + <section> |
| 144 | + <h2 style="color: #f0f0f0;">What is Quantization?</h2> |
| 145 | + |
| 146 | + <p>"Quantization" refers to converting the original floating point format to one with a smaller "range" |
| 147 | + and/or "precision" - usually both. Projects like LLAMA.CPP and AutoGPTQ do this with slightly different algorithms but |
| 148 | + the same general concept applies. The overall goal is to reduce the memory and computational power needed while only |
| 149 | + experiencing a "reasonable" loss in quality. Specific "quantizations" like "Q8_0" or "8-bit" refer to the "floating point |
| 150 | + format" of "int8," for example. Technically, "int8" is no longer "floating" but you don't need to delve into the nuances |
| 151 | + of this to understand the basic concepts I'm trying to communicate.</p> |
| 152 | + |
| 153 | + <p>You can obviously see the huge change of "range" and "precision" when using "int8" compared to the above floating |
| 154 | + point formats:</p> |
| 155 | + |
| 156 | + <table border="1"> |
| 157 | + <tr> |
| 158 | + <th>Floating Point Format</th> |
| 159 | + <th>Range (Based on Exponent)</th> |
| 160 | + <th>Discrete Values (Based on Fraction)</th> |
| 161 | + </tr> |
| 162 | + <tr> |
| 163 | + <td>int8</td> |
| 164 | + <td>-128 to 127</td> |
| 165 | + <td>±127 (within integer range)</td> |
| 166 | + </tr> |
| 167 | + </table> |
| 168 | + </section> |
| 169 | + |
| 170 | + <section> |
| 171 | + <h2 style="color: #f0f0f0;">What is Ctranslate2?</h2> |
| 172 | + |
| 173 | + <p>Ctranslate2 is a C++ & Python library that both quantizes and runs large langauge models, but better than ggml, |
| 174 | + gguf, and gptq. Moreover, it supports more floating point formats:</p> |
| 175 | + |
| 176 | + <table border="1"> |
| 177 | + <tr> |
| 178 | + <th>Floating Point Format</th> |
| 179 | + <th>Quantized Model Size</th> |
| 180 | + <th>Summary</th> |
| 181 | + </tr> |
| 182 | + <tr> |
| 183 | + <td>float32</td> |
| 184 | + <td>100%</td> |
| 185 | + <td>Original</td> |
| 186 | + </tr> |
| 187 | + <tr> |
| 188 | + <td>int16</td> |
| 189 | + <td>51.37%</td> |
| 190 | + <td>Not used for neural networks.</td> |
| 191 | + </tr> |
| 192 | + <tr> |
| 193 | + <td>float16</td> |
| 194 | + <td>50.00%</td> |
| 195 | + <td>"Old school," not suited for neural networks.</td> |
| 196 | + </tr> |
| 197 | + <tr> |
| 198 | + <td>bfloat16</td> |
| 199 | + <td>50.00%</td> |
| 200 | + <td>Best for neural networks except for float32.</td> |
| 201 | + </tr> |
| 202 | + <tr> |
| 203 | + <td>int8_float32</td> |
| 204 | + <td>27.47%</td> |
| 205 | + <td>Good for neural networks despite low quantization.</td> |
| 206 | + </tr> |
| 207 | + <tr> |
| 208 | + <td>int8_bfloat16</td> |
| 209 | + <td>26.10%</td> |
| 210 | + <td>Good for neural networks despite low quantization, but not as good as int8_float32.</td> |
| 211 | + </tr> |
| 212 | + <tr> |
| 213 | + <td>int8_float16</td> |
| 214 | + <td>26.10%</td> |
| 215 | + <td>Slightly better than int8.</td> |
| 216 | + </tr> |
| 217 | + <tr> |
| 218 | + <td>int8</td> |
| 219 | + <td>25%</td> |
| 220 | + <td>Mediocre</td> |
| 221 | + </tr> |
| 222 | + </table> |
| 223 | + |
| 224 | + <p>In other words, a model converted to ctranslate2 format and run using "int8" quantization will run |
| 225 | + faster, produce a higher quality result, and require less vram/ram and computational power than the same |
| 226 | + model quantized to int8 with the ggml, gguf or gptq algorithms. Moreover, ctranslate2 supports the floating point |
| 227 | + formats that are more suitable for neural networks. All of this makes it more powerful.</p> |
| 228 | + |
| 229 | + <p>For example, here's a simple comparison an identical 7 billion parameter Llama2-based model:</p> |
| 230 | + <table border="1"> |
| 231 | + <tr> |
| 232 | + <th>Floating Point Format</th> |
| 233 | + <th>Backend Tech</th> |
| 234 | + <th>VRAM/RAM Needed</th> |
| 235 | + </tr> |
| 236 | + <tr> |
| 237 | + <td>float16</td> |
| 238 | + <td>ctranslate2</td> |
| 239 | + <td>15.5 GB</td> |
| 240 | + </tr> |
| 241 | + <tr> |
| 242 | + <td>bfloat16</td> |
| 243 | + <td>ctranslate2</td> |
| 244 | + <td>15.4 GB</td> |
| 245 | + </tr> |
| 246 | + <tr> |
| 247 | + <td>int8 ("Q8_0")</td> |
| 248 | + <td>ggml/gguf</td> |
| 249 | + <td>12.4 GB</td> |
| 250 | + </tr> |
| 251 | + <tr> |
| 252 | + <td>"Q6_0"</td> |
| 253 | + <td>ggml/gguf</td> |
| 254 | + <td>11.6 GB</td> |
| 255 | + </tr> |
| 256 | + <tr> |
| 257 | + <td>"Q5_k_m"</td> |
| 258 | + <td>ggml/gguf</td> |
| 259 | + <td>11.4 GB</td> |
| 260 | + </tr> |
| 261 | + <tr> |
| 262 | + <td>"Q4_k_m"</td> |
| 263 | + <td>ggml/gguf</td> |
| 264 | + <td>11.3 GB</td> |
| 265 | + </tr> |
| 266 | + <tr> |
| 267 | + <td>"Q3_k_l"</td> |
| 268 | + <td>ggml/gguf</td> |
| 269 | + <td>10.5 GB</td> |
| 270 | + </tr> |
| 271 | + <tr> |
| 272 | + <td>"Q3_k_m"</td> |
| 273 | + <td>ggml/gguf</td> |
| 274 | + <td>10.3 GB</td> |
| 275 | + </tr> |
| 276 | + <tr> |
| 277 | + <td>"Q3_k_s"</td> |
| 278 | + <td>ggml/gguf</td> |
| 279 | + <td>10 GB</td> |
| 280 | + </tr> |
| 281 | + <tr> |
| 282 | + <td>int8_float32</td> |
| 283 | + <td>ctranslate2</td> |
| 284 | + <td>9.4 GB</td> |
| 285 | + </tr> |
| 286 | + <tr> |
| 287 | + <td>int8_float16</td> |
| 288 | + <td>ctranslate2</td> |
| 289 | + <td>9.0 GB</td> |
| 290 | + </tr> |
| 291 | + <tr> |
| 292 | + <td>int8_bfloat16</td> |
| 293 | + <td>ctranslate2</td> |
| 294 | + <td>9.0 GB</td> |
| 295 | + </tr> |
| 296 | + <tr> |
| 297 | + <td>int8</td> |
| 298 | + <td>ctranslate2</td> |
| 299 | + <td>9.0 GB</td> |
| 300 | + </tr> |
| 301 | + </table> |
| 302 | + |
| 303 | + <p>For example, let's say you only have 12 GB of VRAM. This allows you to run an "int8_float32" quantization of |
| 304 | + a model converted with ctranslate versus only a "Q6_0" version converted using ggml/gguf. This is huge. |
| 305 | + You can easily see from the above table that the model quantized to int8_float32 using Ctranslate2 uses even |
| 306 | + LESS MEMORY than the much lower quality Q3_k_s ggml/gguf converstion of the same model!</p> |
| 307 | + |
| 308 | + <ul> |
| 309 | + <li>Ctranslate2 has numerous other benefits as well including but not limited to:</li> |
| 310 | + <ul> |
| 311 | + <li>Automatically choosing the next best quantization level if what you choose isn't supported by |
| 312 | + your CPU/GPU</li> |
| 313 | + <li>Having built-in CPU acceleration in the form of MKL (Intel's Math Kernel Library)</li> |
| 314 | + <li>Allowing a user to download a single model and then switching between whatever quantizations |
| 315 | + you want at runtime. GGML/GGUF/GPTQ all require you to download a separate model for each quantization.</li> |
| 316 | + </ul> |
| 317 | + </ul> |
| 318 | + </section> |
| 319 | + |
| 320 | + <section> |
| 321 | + <h2 style="color: #f0f0f0;">But is the Quality Loss Noticeable?</h2> |
| 322 | + |
| 323 | + <p>Yes. Anyone who's played with LLMs or embedding models knows that there's a significant loss in quality |
| 324 | + between, say, a Q8_0 and Q3_k_m model. One way to measure this is by analyzing the "perplexity" of a model.</p> |
| 325 | + </section> |
| 326 | + |
| 327 | + <img src="perplexity_loss.png" alt="Perplexity Loss"> |
| 328 | + <section> |
| 329 | + <h2 style="color: #f0f0f0;">So Why isn't Everybody using Ctranslate2?</h2> |
| 330 | + |
| 331 | + <p>This is only my opinion, but the primary reason is because the documentation for Ctranslate2 is written |
| 332 | + "by programmers for programmers" and can be difficult to understand and there aren't many examples out there.</p> |
| 333 | + </main> |
| 334 | + |
| 335 | + <footer> |
| 336 | + <nav><a href="http://www.chintellalaw.com" target="_blank">www.chintellalaw.com</a></nav> |
| 337 | + </footer> |
| 338 | +</body> |
| 339 | +</html> |
0 commit comments