├── README.md ├── compression.ipynb └── output.png /README.md: -------------------------------------------------------------------------------- 1 | # Compression using Arithmetic Encoding and Binary Search 2 | 3 | This repo showcases how to compress data given a known probability distribution over the data. 4 | 5 | ![Compression Ratio vs Advantage](./output.png) -------------------------------------------------------------------------------- /compression.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 7, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stdout", 10 | "output_type": "stream", 11 | "text": [ 12 | "compress uniform\n", 13 | "compress with prior\n", 14 | "====================\n", 15 | "Advantage: 1\n", 16 | "Theoretical accuracy@uniform: 9.5367431640625e-07\n", 17 | "Accuracy@uniform: 0.0\n", 18 | "Accuracy@prior: 1.0\n", 19 | "#bits_uncompressed: 400\n", 20 | "#bits_compressed@uniform: 471\n", 21 | "#bits_compressed@prior: 422\n", 22 | "Compression ratio@uniform: -0.1775\n", 23 | "Compression ratio@prior: -0.05499999999999994\n", 24 | "====================\n", 25 | "Advantage: 10\n", 26 | "Theoretical accuracy@uniform: 9.5367431640625e-07\n", 27 | "Accuracy@uniform: 0.0\n", 28 | "Accuracy@prior: 1.0\n", 29 | "#bits_uncompressed: 400\n", 30 | "#bits_compressed@uniform: 471\n", 31 | "#bits_compressed@prior: 372\n", 32 | "Compression ratio@uniform: -0.1775\n", 33 | "Compression ratio@prior: 0.06999999999999995\n", 34 | "====================\n", 35 | "Advantage: 100\n", 36 | "Theoretical accuracy@uniform: 9.5367431640625e-07\n", 37 | "Accuracy@uniform: 0.0\n", 38 | "Accuracy@prior: 1.0\n", 39 | "#bits_uncompressed: 400\n", 40 | "#bits_compressed@uniform: 471\n", 41 | "#bits_compressed@prior: 304\n", 42 | "Compression ratio@uniform: -0.1775\n", 43 | "Compression ratio@prior: 0.24\n", 44 | "====================\n", 45 | "Advantage: 1000\n", 46 | "Theoretical accuracy@uniform: 9.5367431640625e-07\n", 47 | "Accuracy@uniform: 0.0\n", 48 | "Accuracy@prior: 1.0\n", 49 | "#bits_uncompressed: 400\n", 50 | "#bits_compressed@uniform: 471\n", 51 | "#bits_compressed@prior: 244\n", 52 | "Compression ratio@uniform: -0.1775\n", 53 | "Compression ratio@prior: 0.39\n", 54 | "====================\n", 55 | "Advantage: 10000\n", 56 | "Theoretical accuracy@uniform: 9.5367431640625e-07\n", 57 | "Accuracy@uniform: 0.0\n", 58 | "Accuracy@prior: 1.0\n", 59 | "#bits_uncompressed: 400\n", 60 | "#bits_compressed@uniform: 471\n", 61 | "#bits_compressed@prior: 173\n", 62 | "Compression ratio@uniform: -0.1775\n", 63 | "Compression ratio@prior: 0.5675\n", 64 | "====================\n", 65 | "Advantage: 100000\n", 66 | "Theoretical accuracy@uniform: 9.5367431640625e-07\n", 67 | "Accuracy@uniform: 0.0\n", 68 | "Accuracy@prior: 1.0\n", 69 | "#bits_uncompressed: 400\n", 70 | "#bits_compressed@uniform: 471\n", 71 | "#bits_compressed@prior: 129\n", 72 | "Compression ratio@uniform: -0.1775\n", 73 | "Compression ratio@prior: 0.6775\n", 74 | "====================\n", 75 | "Advantage: 1000000\n", 76 | "Theoretical accuracy@uniform: 9.5367431640625e-07\n", 77 | "Accuracy@uniform: 0.0\n", 78 | "Accuracy@prior: 1.0\n", 79 | "#bits_uncompressed: 400\n", 80 | "#bits_compressed@uniform: 471\n", 81 | "#bits_compressed@prior: 100\n", 82 | "Compression ratio@uniform: -0.1775\n", 83 | "Compression ratio@prior: 0.75\n", 84 | "====================\n", 85 | "Advantage: 10000000\n", 86 | "Theoretical accuracy@uniform: 9.5367431640625e-07\n", 87 | "Accuracy@uniform: 0.0\n", 88 | "Accuracy@prior: 1.0\n", 89 | "#bits_uncompressed: 400\n", 90 | "#bits_compressed@uniform: 471\n", 91 | "#bits_compressed@prior: 100\n", 92 | "Compression ratio@uniform: -0.1775\n", 93 | "Compression ratio@prior: 0.75\n" 94 | ] 95 | }, 96 | { 97 | "data": { 98 | "text/plain": [ 99 | "" 100 | ] 101 | }, 102 | "execution_count": 7, 103 | "metadata": {}, 104 | "output_type": "execute_result" 105 | }, 106 | { 107 | "data": { 108 | "image/png": "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cXE5tr148SJHAHjT65u/JkyYgDp16uR4/XXdxsbGGDp0KIYOHYqIiAgcP34cS5Yswbhx47Sjf0FBQQgKCkJSUhJOnTqFlStXYvz48fDz88sRzG1sbHJdauz1toLoxz/Vq1cPn3zyCTZv3owdO3agW7duAIAVK1Zg3bp1+O6779CyZUtYWVkBeLVU2rt6HahyuxEvJibmXz8fKysrNG3aFL/88gsCAwNx7949fP3119rX5XI5evTogR49euDly5f4448/sGzZMowcORKnT5+GsbHxf9a3e/dumJubY8mSJZDLs/8Cc8qUKdi+fTs++eQT2NraQi6X5/g83lzi7bWOHTti+fLlOH/+PA4dOoSAgADte/vx48cYPnw4mjdvjuXLl8PV1RUymQybN2/GyZMn/7Pef5OcnIyBAwfC3d0dBw8eROXKlSGXy/HHH3/g8OHDAF790GdkZJTj89BoNNk+FysrK1SsWBGzZ8/O9VrlypXTqVaikoLTHogIANC/f3/Ex8dj/vz5OV6LiYnBmjVrULVqVXh6emqD5eug+NrBgwehVqvh5+encz1///03Hjx4oP04KioKoaGhqFev3luPqVy5MhwcHPD06VPUrFlT+6dMmTKYM2cObt68ifT0dLRq1Qpr1qwBADg7O6NHjx5o166dduT7s88+w/DhwwG8ChRt2rTBsGHDkJWVpR09flNAQABCQ0Px7NmzbNv37duH0qVLo0KFCjr3IzdjxoxBqVKlMHfuXG0Iunz5MqpWrYoPPvhAG3yjoqJw9+7dbKOP/wyNb6pUqRJKly6NAwcOZNv+5MkTXLlyBbVr1/7Xujp27IgrV65g69atcHZ2zvaDSPfu3bUrKDg4OKBLly7o0aMHEhMTs62m8TYqlQr79+9H06ZNUa9ePdStWzfbn06dOuH27du4cuUKTExM4OvriyNHjmQbnf39999znLdKlSrw9PTEwYMH8ccff6BDhw7a165fv46MjAwMHjwY5cuX147mvg6+7zJy/9rrKUavhYeHIz4+Hr1790bVqlW1X5fXK0RoNBooFArUrl07x+ohv//+O7KysrQf16lTB8+fP4eDg0O29//p06exatWqHNcmMlQc+SUiAK/moo4ePRrz58/HgwcP0KlTJ9jZ2eHevXtYvXo1MjIytMG4atWq6Ny5MxYuXIi0tDQEBATg1q1bCA4ORt26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", 109 | "text/plain": [ 110 | "
" 111 | ] 112 | }, 113 | "metadata": {}, 114 | "output_type": "display_data" 115 | } 116 | ], 117 | "source": [ 118 | "import numpy as np\n", 119 | "import matplotlib.pyplot as plt\n", 120 | "from typing import List\n", 121 | "import seaborn as sns\n", 122 | "\n", 123 | "\n", 124 | "def gen_proba_uniform(rng: np.random.RandomState, n: int, m: int):\n", 125 | " \"\"\"\n", 126 | " :param n: number of tokens\n", 127 | " :param m: codebook size\n", 128 | " \"\"\"\n", 129 | " proba_uniform = rng.uniform(size=(n, m))\n", 130 | " proba_uniform /= proba_uniform.sum(axis=1, keepdims=True)\n", 131 | " return proba_uniform\n", 132 | "\n", 133 | "\n", 134 | "def gen_proba_with_prior(\n", 135 | " rng: np.random.RandomState, tokens: List[int], m: int, advantage: float = 0.5\n", 136 | "):\n", 137 | " \"\"\"\n", 138 | " :param tokens: list of tokens\n", 139 | " :param m: codebook size\n", 140 | " :param advantage: advantage of the prior\n", 141 | " \"\"\"\n", 142 | " n = len(tokens)\n", 143 | " proba_with_prior = rng.uniform(size=(n, m))\n", 144 | " proba_with_prior[np.arange(n), tokens] += advantage\n", 145 | " proba_with_prior /= proba_with_prior.sum(axis=1, keepdims=True)\n", 146 | " return proba_with_prior\n", 147 | "\n", 148 | "\n", 149 | "# Compresssion & Decompression Algorithm\n", 150 | "def encode(proba: List[int], k: int):\n", 151 | " \"\"\"\n", 152 | " Encode data k using binary search\n", 153 | " \"\"\"\n", 154 | "\n", 155 | " pcsum = proba.cumsum()\n", 156 | " assert np.allclose(pcsum[-1], 1)\n", 157 | "\n", 158 | " left, right = 0.0, 1.0\n", 159 | " bisection_sequence = []\n", 160 | " # print(\"target: \", pcsum[k])\n", 161 | " while True:\n", 162 | " mid = (left + right) * 0.5\n", 163 | " # l = np.where(pcsum > mid)\n", 164 | " # a faster way to find the index of the first element that is greater than mid\n", 165 | " idx = np.searchsorted(pcsum, mid, side=\"right\")\n", 166 | "\n", 167 | " # print(\"=\" * 20)\n", 168 | " # print(\"pcsum:\", pcsum)\n", 169 | " # print(\"left, right, mid:\", left, right, mid)\n", 170 | " # print(\"bisect idx:\", idx)\n", 171 | " # print(\"k:\", k)\n", 172 | " # print(\"pcsum[idx]:\", pcsum[idx])\n", 173 | "\n", 174 | " if idx < k:\n", 175 | " left = mid\n", 176 | " bisection_sequence.append(1)\n", 177 | " elif idx > k:\n", 178 | " right = mid\n", 179 | " bisection_sequence.append(0)\n", 180 | " else:\n", 181 | " break\n", 182 | " # print(\"bisection_sequence:\", bisection_sequence)\n", 183 | "\n", 184 | " return bisection_sequence\n", 185 | "\n", 186 | "\n", 187 | "def decode(proba: List[int], bisection_sequence: List[int]):\n", 188 | " \"\"\"\n", 189 | " Decode data using binary search\n", 190 | " \"\"\"\n", 191 | "\n", 192 | " pcsum = proba.cumsum()\n", 193 | " assert np.allclose(pcsum[-1], 1)\n", 194 | "\n", 195 | " left, right = 0.0, 1.0\n", 196 | " for bit in bisection_sequence:\n", 197 | " mid = (left + right) * 0.5\n", 198 | " # print(\"=\" * 20)\n", 199 | " # print(\"left, right, mid:\", left, right, mid)\n", 200 | " if bit == 0:\n", 201 | " right = mid\n", 202 | " else:\n", 203 | " left = mid\n", 204 | "\n", 205 | " mid = (left + right) * 0.5\n", 206 | " idx = np.searchsorted(pcsum, mid, side=\"right\")\n", 207 | " return idx\n", 208 | "\n", 209 | "\n", 210 | "def do_compress_and_decompress(tokens: List[int], proba: List[List[float]]):\n", 211 | " \"\"\"\n", 212 | " Compress and decompress a sequence of tokens\n", 213 | " :param tokens: a sequence of tokens\n", 214 | " :param proba: a list of probability distributions of shape (n, m),\n", 215 | " where n is the number of tokens and m is the codebook size\n", 216 | " \"\"\"\n", 217 | "\n", 218 | " # to store \"the number of compressed bits\" of a token, we need at most log2(log2(m)) bits\n", 219 | " # e.g., if codebook size m = 256, the length of the compressed sequence is at most 8 bits,\n", 220 | " # so we need at most 3 bits to represent the length of the compressed sequence\n", 221 | " num_bits_to_represent_num_compressed_bits = int(\n", 222 | " np.ceil(np.log2(np.log2(len(proba[0]))))\n", 223 | " )\n", 224 | "\n", 225 | " num_bits_compressed = 0\n", 226 | "\n", 227 | " for i, k0 in enumerate(tokens):\n", 228 | " bisection_sequence = encode(proba[i], k0)\n", 229 | " k1 = decode(proba[i], bisection_sequence)\n", 230 | "\n", 231 | " assert k0 == k1\n", 232 | "\n", 233 | " num_bits_compressed += num_bits_to_represent_num_compressed_bits\n", 234 | "\n", 235 | " num_bits_compressed += len(bisection_sequence)\n", 236 | "\n", 237 | " return num_bits_compressed\n", 238 | "\n", 239 | "\n", 240 | "def compress_algorithm_test(\n", 241 | " rng: np.random.RandomState,\n", 242 | " seqlen: int,\n", 243 | " bits_per_token: int,\n", 244 | " advantages: List[float],\n", 245 | "):\n", 246 | " \"\"\"\n", 247 | " :param rng: random number generator\n", 248 | " :param seqlen: sequence length\n", 249 | " :param bits_per_token: bits per token\n", 250 | " :param advantages: advantages of the prior\n", 251 | " \"\"\"\n", 252 | "\n", 253 | " # hyperparameters\n", 254 | " n = seqlen\n", 255 | " m = 2**bits_per_token\n", 256 | "\n", 257 | " # generate tokens\n", 258 | " tokens = rng.randint(m, size=n)\n", 259 | "\n", 260 | " # generate uniform probability\n", 261 | " proba_uniform = gen_proba_uniform(rng, n, m)\n", 262 | "\n", 263 | " print(\"compress uniform\")\n", 264 | " num_bits_uncompressed = n * bits_per_token\n", 265 | " num_bits_compressed_uniform = do_compress_and_decompress(tokens, proba_uniform)\n", 266 | "\n", 267 | " print(\"compress with prior\")\n", 268 | " compression_ratios_with_prior = []\n", 269 | " for advantage in advantages:\n", 270 | " # generate probability with prior\n", 271 | " proba_with_prior = gen_proba_with_prior(rng, tokens, m, advantage=advantage)\n", 272 | " print(\"=\" * 20)\n", 273 | " print(\"Advantage:\", advantage)\n", 274 | " print(\"Theoretical accuracy@uniform:\", 1 / m)\n", 275 | " print(\"Accuracy@uniform:\", np.mean(proba_uniform.argmax(axis=1) == tokens))\n", 276 | " print(\"Accuracy@prior:\", np.mean(proba_with_prior.argmax(axis=1) == tokens))\n", 277 | "\n", 278 | " num_bits_compressed_with_prior = do_compress_and_decompress(\n", 279 | " tokens, proba_with_prior\n", 280 | " )\n", 281 | "\n", 282 | " print(\"#bits_uncompressed:\", num_bits_uncompressed)\n", 283 | " print(\"#bits_compressed@uniform:\", num_bits_compressed_uniform)\n", 284 | " print(\"#bits_compressed@prior:\", num_bits_compressed_with_prior)\n", 285 | " compression_ratio_uniform = (\n", 286 | " 1 - num_bits_compressed_uniform / num_bits_uncompressed\n", 287 | " )\n", 288 | "\n", 289 | " print(\"Compression ratio@uniform:\", compression_ratio_uniform)\n", 290 | "\n", 291 | " cr_prior = 1 - num_bits_compressed_with_prior / num_bits_uncompressed\n", 292 | " compression_ratios_with_prior.append(cr_prior)\n", 293 | " print(\"Compression ratio@prior:\", cr_prior)\n", 294 | "\n", 295 | " return {\n", 296 | " 'cr_uniform': compression_ratio_uniform,\n", 297 | " 'cr_prior': compression_ratios_with_prior,\n", 298 | " }\n", 299 | "\n", 300 | "\n", 301 | "\n", 302 | "rng = np.random.RandomState(42)\n", 303 | "seqlen = 20\n", 304 | "bits_per_token = 20\n", 305 | "advantages = [10**i for i in range(8)]\n", 306 | "rst = compress_algorithm_test(rng, seqlen, bits_per_token, advantages)\n", 307 | "\n", 308 | "# plot the results\n", 309 | "sns.set()\n", 310 | "plt.figure(figsize=(8, 6))\n", 311 | "\n", 312 | "plt.plot(advantages, np.zeros_like(advantages), label='no compression')\n", 313 | "plt.plot(advantages, rst['cr_uniform'] * np.ones_like(advantages), label='uniform')\n", 314 | "plt.plot(advantages, rst['cr_prior'], label='prior')\n", 315 | "\n", 316 | "plt.xscale('log')\n", 317 | "plt.xlabel('advantage')\n", 318 | "plt.ylabel('compression ratio')\n", 319 | "\n", 320 | "plt.title('Compression Ratio vs. Advantage')\n", 321 | "\n", 322 | "plt.legend()\n" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": null, 328 | "metadata": {}, 329 | "outputs": [], 330 | "source": [] 331 | } 332 | ], 333 | "metadata": { 334 | "kernelspec": { 335 | "display_name": "Python 3", 336 | "language": "python", 337 | "name": "python3" 338 | }, 339 | "language_info": { 340 | "codemirror_mode": { 341 | "name": "ipython", 342 | "version": 3 343 | }, 344 | "file_extension": ".py", 345 | "mimetype": "text/x-python", 346 | "name": "python", 347 | "nbconvert_exporter": "python", 348 | "pygments_lexer": "ipython3", 349 | "version": "3.10.10" 350 | }, 351 | "orig_nbformat": 4, 352 | "vscode": { 353 | "interpreter": { 354 | "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" 355 | } 356 | } 357 | }, 358 | "nbformat": 4, 359 | "nbformat_minor": 2 360 | } 361 | -------------------------------------------------------------------------------- /output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxytim/arithmetic-encoding-compression/592633ad2baf59b56117186062caf750a98d2358/output.png --------------------------------------------------------------------------------