diff --git a/docs/examples/Throughput_Comparison.ipynb b/docs/examples/Throughput_Comparison.ipynb new file mode 100644 index 00000000..5098cbd7 --- /dev/null +++ b/docs/examples/Throughput_Comparison.ipynb @@ -0,0 +1,316 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 🤗 Huggingface vs ⚡ FastEmbed️\n", + "\n", + "Comparing the performance of Huggingface's 🤗 Transformers and ⚡ FastEmbed️ on a simple task on the following machine: Apple M2 Max, 32 GB RAM\n", + "\n", + "## 📦 Imports\n", + "\n", + "Importing the necessary libraries for this comparison." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "from pathlib import Path\n", + "from typing import Any, Callable, List, Tuple\n", + "\n", + "import numpy as np\n", + "import torch.nn.functional as F\n", + "from fastembed.embedding import DefaultEmbedding\n", + "from torch import Tensor\n", + "from transformers import AutoModel, AutoTokenizer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 📖 Data\n", + "\n", + "data is a list of strings, each string is a document." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "12" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "documents: List[str] = [\n", + " \"Chandrayaan-3 is India's third lunar mission\",\n", + " \"It aimed to land a rover on the Moon's surface - joining the US, China and Russia\",\n", + " \"The mission is a follow-up to Chandrayaan-2, which had partial success\",\n", + " \"Chandrayaan-3 will be launched by the Indian Space Research Organisation (ISRO)\",\n", + " \"The estimated cost of the mission is around $35 million\",\n", + " \"It will carry instruments to study the lunar surface and atmosphere\",\n", + " \"Chandrayaan-3 landed on the Moon's surface on 23rd August 2023\",\n", + " \"It consists of a lander named Vikram and a rover named Pragyan similar to Chandrayaan-2. Its propulsion module would act like an orbiter.\",\n", + " \"The propulsion module carries the lander and rover configuration until the spacecraft is in a 100-kilometre (62 mi) lunar orbit\",\n", + " \"The mission used GSLV Mk III rocket for its launch\",\n", + " \"Chandrayaan-3 was launched from the Satish Dhawan Space Centre in Sriharikota\",\n", + " \"Chandrayaan-3 was launched earlier in the year 2023\",\n", + "]\n", + "len(documents)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting up 🤗 Huggingface\n", + "\n", + "We'll be using the [Huggingface Transformers](https://huggingface.co/transformers/) with PyTorch library to generate embeddings. We'll be using the same model across both libraries for a fair(er?) comparison." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([12, 384])" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "class HF:\n", + " \"\"\"\n", + " HuggingFace Transformer implementation of FlagEmbedding\n", + " Based on https://huggingface.co/BAAI/bge-base-en\n", + " \"\"\"\n", + "\n", + " def __init__(self, model_id: str):\n", + " self.model = AutoModel.from_pretrained(model_id)\n", + " self.tokenizer = AutoTokenizer.from_pretrained(model_id)\n", + "\n", + " def embed(self, texts: List[str]):\n", + " encoded_input = self.tokenizer(texts, max_length=512, padding=True, truncation=True, return_tensors=\"pt\")\n", + " model_output = self.model(**encoded_input)\n", + " sentence_embeddings = model_output[0][:, 0]\n", + " sentence_embeddings = F.normalize(sentence_embeddings)\n", + " return sentence_embeddings\n", + "\n", + "hf = HF(model_id=\"BAAI/bge-small-en\")\n", + "hf.embed(documents).shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting up ⚡️FastEmbed\n", + "\n", + "Sorry, don't have a lot to set up here. We'll be using the default model, which is Flag Embedding, same as the Huggingface model." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "embedding_model = DefaultEmbedding()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 📊 Comparison\n", + "\n", + "We'll be comparing the following metrics: Minimum, Maximum, Mean, across k runs. Let's write a function to do that:\n", + "\n", + "### 🚀 Calculating Stats" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def calculate_time_stats(embed_func: Callable, documents: list, k: int) -> Tuple[float, float, float]:\n", + " times = []\n", + " for _ in range(k):\n", + " # Timing the embed_func call\n", + " start_time = time.time()\n", + " embeddings = embed_func(documents)\n", + " end_time = time.time()\n", + "\n", + " times.append(end_time - start_time)\n", + "\n", + " # Returning mean, max, and min time for the call\n", + " return (sum(times) / k, max(times), min(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Asking to truncate to max_length but no maximum length is provided and the model has no predefined maximum length. Default to no truncation.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Huggingface Transformers (Average, Max, Min): (0.06037795543670654, 0.06067395210266113, 0.06008195877075195)\n", + "FastEmbed (Average, Max, Min): (0.03734695911407471, 0.03747200965881348, 0.03722190856933594)\n" + ] + } + ], + "source": [ + "hf_stats = calculate_time_stats(hf.embed, documents, k=2)\n", + "print(f\"Huggingface Transformers (Average, Max, Min): {hf_stats}\")\n", + "fst_stats = calculate_time_stats(embedding_model.embed, documents, k=2)\n", + "print(f\"FastEmbed (Average, Max, Min): {fst_stats}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 📈 Results\n", + "\n", + "Let's run the comparison and see the results." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n", + "To disable this warning, you can either:\n", + "\t- Avoid using `tokenizers` before the fork if possible\n", + "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n", + "\u001b[33mDEPRECATION: pytorch-lightning 1.6.5 has a non-standard dependency specifier torch>=1.8.*. pip 23.3 will enforce this behaviour change. A possible replacement is to upgrade to a newer version of pytorch-lightning or contact the author to suggest that they release a version with a conforming dependency specifiers. Discussion can be found at https://github.com/pypa/pip/issues/12063\u001b[0m\u001b[33m\n", + "\u001b[0m" + ] + } + ], + "source": [ + "!pip install matplotlib --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Tw6WxkkBwKQZq5H7OA/eVSsiLz8ff287iTMXrmPGxPdR0bGcFNe/VzOs2nQEAz9egOBezVDRsRyOnrqCDdtPoqlfddSt6SbFTp27AWs2H8P+9ZOkQi5k5Dw42tugbg1X2Ja1wu2U+1i18QhS7mbixykcT6uPWDQREZHeufjPTQDAzv3nsXP/ea3l3drV17nPsRGdoVSaY9m6g1iz6SjcXOwwa3J/dHluQswans747a89+Dv6OAwMDFDbuxKWzo3QmIIAeDo9wcbfx2DGvE1Yv/UE0u6pYG9njcHvt8aoZ6ZFKEqvTg2xcftJ/PrXHqgeZMNaaY66Nd0w+6tgNKhbRef9o5KnV98992/G754jIiL699Hl97fefI0KERERkT5j0UREREQkA8c0ERHpiatuHUs7BSK9VjlxU6lun2eaiIiIiGRg0UREREQkA4smIiIiIhlYNBERERHJwKKJiIiISAYWTUREREQysGgiIiIikoFFExEREZEMLJqIiIiIZGDRRERERCQDiyYiIiIiGVg0EREREcnAoomIiIhIBhZNRERERDKwaCIiIiKSgUUTERERkQwsmoiIiIhkYNFEREREJAOLJiIiIiIZWDQRERERycCiiYiIiEgGFk1EREREMrBoIiIiIpKBRRMRERGRDCyaiIiIiGRg0UREREQkA4smIiIiIhlYNBERERHJwKKJiIiISAYWTUREREQysGgiIiIikoFFExEREZEMLJqIiIiIZGDRRERERCQDiyYiIiIiGVg0EREREcnAoomIiIhIBhZNRERERDKwaCIiIiKSgUUTERERkQwsmoiIiIhkYNFEREREJAOLJiIiIiIZWDQRERERycCiiYiIiEgGFk1EREREMrBoIiIiIpKBRRMRERGRDCyaiIiIiGRg0UREREQkA4smIiIiIhlYNBERERHJwKKJiIiISAYWTUREREQysGgiIiIikqFUi6aoqCjUr18fVlZWsLe3R9euXREfH68Rk5OTg/DwcNja2sLS0hI9evRASkqKRkxSUhI6dOgAc3Nz2Nvb45NPPkFeXp5GzJ49e/DOO+/AxMQEVapUweLFi7XymTt3Ltzc3GBqago/Pz8cO3as2PeZiIiI/p1KtWjau3cvwsPDceTIEezYsQNPnjxBYGAgHj58KMWMGjUKGzduxKpVq7B3717cvn0b3bt3l5bn5+ejQ4cOePz4MQ4dOoQlS5Zg8eLFmDBhghRz7do1dOjQAS1btkRsbCxGjhyJgQMHYtu2bVLMihUrEBkZiYkTJ+LUqVOoXbs2goKCkJqa+mYOBhEREek1hRBClHYSamlpabC3t8fevXvRrFkzZGZmws7ODsuWLcO7774LAIiLi4OXlxcOHz6Mhg0bYuvWrejYsSNu374NBwcHAMD8+fMxduxYpKWlwdjYGGPHjsXmzZtx/vx5aVu9e/dGRkYGoqOjAQB+fn6oX78+fvzxRwBAQUEBXFxcMGzYMIwbN+6luatUKlhbWyMzMxNKpbK4Dw0R/QdcdetY2ikQ6bXKiZuKvU9dfn/r1ZimzMxMAEC5cuUAACdPnsSTJ08QEBAgxVSvXh2VKlXC4cOHAQCHDx+Gj4+PVDABQFBQEFQqFS5cuCDFPNuHOkbdx+PHj3Hy5EmNGAMDAwQEBEgxz8vNzYVKpdJ4EBER0dtLb4qmgoICjBw5Eo0bN0bNmjUBAMnJyTA2NoaNjY1GrIODA5KTk6WYZwsm9XL1shfFqFQqPHr0CHfv3kV+fn6hMeo+nhcVFQVra2vp4eLi8mo7TkRERP8KelM0hYeH4/z581i+fHlppyLL+PHjkZmZKT1u3LhR2ikRERFRCSpT2gkAQEREBDZt2oR9+/bB2dlZand0dMTjx4+RkZGhcbYpJSUFjo6OUszzd7mp7657Nub5O+5SUlKgVCphZmYGQ0NDGBoaFhqj7uN5JiYmMDExebUdJiIion+dUj3TJIRAREQE1q1bh127dsHd3V1jua+vL4yMjBATEyO1xcfHIykpCf7+/gAAf39/nDt3TuMutx07dkCpVMLb21uKebYPdYy6D2NjY/j6+mrEFBQUICYmRoohIiKi/7ZSPdMUHh6OZcuW4e+//4aVlZU0fsja2hpmZmawtrZGWFgYIiMjUa5cOSiVSgwbNgz+/v5o2LAhACAwMBDe3t744IMPMG3aNCQnJ+Pzzz9HeHi4dCboo48+wo8//ogxY8ZgwIAB2LVrF1auXInNmzdLuURGRiI4OBj16tVDgwYNMGvWLDx8+BChoaFv/sAQERGR3inVomnevHkAgBYtWmi0L1q0CCEhIQCAmTNnwsDAAD169EBubi6CgoLw008/SbGGhobYtGkThgwZAn9/f1hYWCA4OBiTJ0+WYtzd3bF582aMGjUKs2fPhrOzM3755RcEBQVJMe+99x7S0tIwYcIEJCcno06dOoiOjtYaHE5ERET/TXo1T9O/GedpIqLXxXmaiF6M8zQRERER/QuwaCIiIiKSgUUTERERkQwsmoiIiIhkYNFEREREJAOLJiIiIiIZWDQRERERycCiiYiIiEgGFk1EREREMrBoIiIiIpKBRRMRERGRDCyaiIiIiGRg0UREREQkA4smIiIiIhlYNBERERHJwKKJiIiISAYWTUREREQysGgiIiIikoFFExEREZEMLJqIiIiIZGDRRERERCQDiyYiIiIiGVg0EREREcnAoomIiIhIhjJygiIjI2V3+P33379yMkRERET6SlbRdPr0aY3np06dQl5eHjw9PQEA//zzDwwNDeHr61v8GRIRERHpAVlF0+7du6X/f//997CyssKSJUtQtmxZAMD9+/cRGhqKpk2blkyWRERERKVMIYQQuqxQsWJFbN++HTVq1NBoP3/+PAIDA3H79u1iTfDfQqVSwdraGpmZmVAqlaWdDhH9C11161jaKRDptcqJm4q9T11+f+s8EFylUiEtLU2rPS0tDQ8ePNC1OyIiIqJ/BZ2Lpm7duiE0NBRr167FzZs3cfPmTaxZswZhYWHo3r17SeRIREREVOpkjWl61vz58zF69Gj07dsXT548edpJmTIICwvD9OnTiz1BIiIiIn2g85gmtYcPHyIhIQEA4OHhAQsLi2JN7N+GY5qI6HVxTBPRi5X2mCadzzSpWVhYoFatWq+6OhEREdG/is5F08OHD/Htt98iJiYGqampKCgo0Fh+9erVYkuOiIiISF/oXDQNHDgQe/fuxQcffIAKFSpAoVCURF5EREREekXnomnr1q3YvHkzGjduXBL5EBEREeklnaccKFu2LMqVK1cSuRARERHpLZ2Lpq+++goTJkxAdnZ2SeRDREREpJd0vjw3Y8YMJCQkwMHBAW5ubjAyMtJYfurUqWJLjoiIiEhf6Fw0de3atQTSICIiItJvOhdNEydOLIk8iIiIiPTaK09uefLkSVy6dAkAUKNGDdStW7fYkiIiIiLSNzoXTampqejduzf27NkDGxsbAEBGRgZatmyJ5cuXw87OrrhzJCIiIip1Ot89N2zYMDx48AAXLlxAeno60tPTcf78eahUKgwfPrwkciQiIiIqdTqfaYqOjsbOnTvh5eUltXl7e2Pu3LkIDAws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uXgzJCIiItIDsoqmrl27arVNnjxZq02hUCA/P/+1kyIiIiLSN7KKpuenFSAiIiL6r9F5TBMRERHRf5HsomnXrl3w9vaGSqXSWpaZmYkaNWpg3759xZocERERkb6QXTTNmjULgwYNglKp1FpmbW2NDz/8EDNnzizW5IiIiIj0heyi6cyZM2jbtm2RywMDA3Hy5MliSYqIiIhI38gumlJSUrSmF3hWmTJlkJaWVixJEREREekb2UVTxYoVcf78+SKXnz17FhUqVCiWpIiIiIj0jeyiqX379vjiiy+Qk5OjtezRo0eYOHEiOnbsWKzJEREREekLWfM0AcDnn3+OtWvXolq1aoiIiICnpycAIC4uDnPnzkV+fj4+++yzEkuUiIiIqDTJLpocHBxw6NAhDBkyBOPHj4cQAsDTWcCDgoIwd+5cODg4lFiiRERERKVJdtEEAK6urtiyZQvu37+PK1euQAiBqlWromzZsiWVHxEREZFe0KloUitbtizq169f3LkQERER6S1+jQoRERGRDCyaiIiIiGRg0UREREQkA4smIiIiIhlYNBERERHJwKKJiIiISAYWTUREREQysGgiIiIikoFFExEREZEMLJqIiIiIZGDRRERERCQDiyYiIiIiGVg0EREREcnAoomIiIhIBhZNRERERDKwaCIiIiKSgUUTERERkQwsmoiIiIhkYNFEREREJAOLJiIiIiIZWDQRERERycCiiYiIiEgGFk1EREREMrBoIiIiIpKBRRMRERGRDHpdNE2aNAkKhULjUb16dWl5Tk4OwsPDYWtrC0tLS/To0QMpKSkafSQlJaFDhw4wNzeHvb09PvnkE+Tl5WnE7NmzB++88w5MTExQpUoVLF68+E3sHhEREf2L6HXRBAA1atTAnTt3pMeBAwekZaNGjcLGjRuxatUq7N27F7dv30b37t2l5fn5+ejQoQMeP36MQ4cOYcmSJVi8eDEmTJggxVy7dg0dOnRAy5YtERsbi5EjR2LgwIHYtm3bG91PIiIi0m9lSjuBlylTpgwcHR212jMzM/Hrr79i2bJlaNWqFQBg0aJF8PLywpEjR9CwYUNs374dFy9exM6dO+Hg4IA6dergq6++wtixYzFp0iQYGxtj/vz5cHd3x4wZMwAAXl5eOHDgAGbOnImgoKA3uq9ERESkv/T+TNPly5fh5OSEypUro1+/fkhK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fRRGPcZLTc7gcTnHKD09vcQG4RIV5vnPksTERHTs2BFDhgzBlClTUK5cORw4cABhYWF4/PgxzM3NMXDgQAQFBWHz5s3Yvn07oqKiMGPGDAwbNkynbRXm+c+Wotrkfr6ox2L9/PPP8PPz01j2/GcN6R8OBKf/rKNHj2o8P3LkCKpWrQpDQ0PUrVsX+fn5SE1NRZUqVTQejo6OAAAvL69C+3gRY2NjeHt74+LFi7Jy9PLywsGDBzXaDh48CG9v7xeuV6tWLcTExMjaxoucP38edevWfe1+iF7VyZMnUVBQgBkzZqBhw4aoVq0abt++rRXn4uKCjz76CGvXrsXHH3+Mn3/+GcDT9xwA6Q7VNyEpKUkjxyNHjsDAwACenp5wcHCAk5MTrl69qvXZ4u7uDuDp+/7s2bPIycnR6INKH880kd578OABkpOTNdrMzc01pi14FUlJSYiMjMSHH36IU6dOYc6cOZgxYwYAoFq1aujXrx/69++PGTNmoG7dukhLS0NMTAxq1aqFDh06YPjw4WjcuDG+++47dOnSBdu2bXvhpTm1oKAgHDhwQNbkmp988gl69eqFunXrIiAgABs3bsTatWuxc+fOF643ceJEtG7dGh4eHujduzfy8vKwZcsWjB07VtaxAZ7eXXfy5El88803stchKm5VqlTBkydPMGfOHHTq1AkHDx7E/PnzNWJGjhyJdu3aoVq1arh//z52794NLy8vAICrqysUCgU2bdqE9u3bw8zMTDpbnJubq/XZUqZMGZQvX/61cjY1NUVwcDC+++47qFQqDB8+HL169ZL+4Pryyy8xfPhwWFtbo23btsjNzcWJEydw//59REZGom/fvvjss88waNAgjB8/HomJifjuu+9eKycqHjzTRHpvwoQJqFChgsZjzJgxr91v//798ejRIzRo0ADh4eEYMWKExvihRYsWoX///vj444/h6emJrl274vjx46hUqRKAp2Oifv75Z8yePRu1a9fG9u3bXzhRp1pYWBi2bNmidQtyYbp27YrZs2fju+++Q40aNbBgwQIsWrQILVq0eOF6LVq0wKpVq7BhwwbUqVMHrVq10hrT9TJ///03KlWqhKZNm+q0HlFxql27Nr7//ntMnToVNWvWxNKlSxEVFaURk5+fj/DwcHh5eaFt27aoVq2adAt/xYoV8eWXX2LcuHFwcHBARESEtF50dLTWZ0uTJk1eO+cqVaqge/fuaN++PQIDA1GrVi2NKQUGDhyIX375BYsWLYKPjw+aN2+OxYsXS2eaLC0tsXHjRpw7dw5169bFZ599hqlTp752XvT6FEI8MzENEb0RPXv2xDvvvIPx48eXdipFatiwIYYPH46+ffuWdipERHqBZ5qISsH06dNfa0B5Sbt79y66d++OPn36lHYqRER6g2eaiIiIiGTgmSYiIiIiGVg0EREREcnAoomIiIhIBhZNRERERDKwaCIiIiKSgUUTERERkQwsmoiIiIhkYNFEREREJAOLJiIiIiIZ/g9NBYpH+LSQ1QAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def plot_character_per_second_comparison(\n", + " hf_stats: Tuple[float, float, float], fst_stats: Tuple[float, float, float], documents: list\n", + "):\n", + " # Calculating total characters in documents\n", + " total_characters = sum(len(doc) for doc in documents)\n", + "\n", + " # Calculating characters per second for each model\n", + " hf_chars_per_sec = total_characters / hf_stats[0] # Mean time is at index 0\n", + " fst_chars_per_sec = total_characters / fst_stats[0]\n", + "\n", + " # Plotting the bar chart\n", + " models = [\"HF Embed (Torch)\", \"FastEmbed\"]\n", + " chars_per_sec = [hf_chars_per_sec, fst_chars_per_sec]\n", + "\n", + " bars = plt.bar(models, chars_per_sec, color=[\"#1f356c\", \"#dd1f4b\"])\n", + " plt.ylabel(\"Characters per Second\")\n", + " plt.title(\"Characters Processed per Second Comparison\")\n", + "\n", + " # Adding the number at the top of each bar\n", + " for bar, chars in zip(bars, chars_per_sec):\n", + " plt.text(\n", + " bar.get_x() + bar.get_width() / 2,\n", + " bar.get_height(),\n", + " f\"{chars:.1f}\",\n", + " ha=\"center\",\n", + " va=\"bottom\",\n", + " color=\"#1f356c\",\n", + " fontsize=12,\n", + " )\n", + "\n", + " plt.show()\n", + "\n", + "\n", + "plot_character_per_second_comparison(hf_stats, fst_stats, documents)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "fst", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.17" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/fooling_around/02_HF_vs_FastEmbed.ipynb b/fooling_around/02_HF_vs_FastEmbed.ipynb deleted file mode 100644 index 7ca3cd9f..00000000 --- a/fooling_around/02_HF_vs_FastEmbed.ipynb +++ /dev/null @@ -1,309 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 🤗 Huggingface vs ⚡ FastEmbed️\n", - "\n", - "Comparing the performance of Huggingface's 🤗 Transformers and ⚡ FastEmbed️ on a simple task on the following machine: Apple M2 Max, 32 GB RAM\n", - "\n", - "## 📦 Imports\n", - "\n", - "Importing the necessary libraries for this comparison." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "from pathlib import Path\n", - "from typing import Any, Callable, List, Tuple\n", - "\n", - "import numpy as np\n", - "import torch.nn.functional as F\n", - "from fastembed.embedding import DefaultEmbedding\n", - "from torch import Tensor\n", - "from transformers import AutoModel, AutoTokenizer" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 📖 Data\n", - "\n", - "data is a list of strings, each string is a document." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "12" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "documents: List[str] = [\n", - " \"Chandrayaan-3 is India's third lunar mission\",\n", - " \"It aimed to land a rover on the Moon's surface - joining the US, China and Russia\",\n", - " \"The mission is a follow-up to Chandrayaan-2, which had partial success\",\n", - " \"Chandrayaan-3 will be launched by the Indian Space Research Organisation (ISRO)\",\n", - " \"The estimated cost of the mission is around $35 million\",\n", - " \"It will carry instruments to study the lunar surface and atmosphere\",\n", - " \"Chandrayaan-3 landed on the Moon's surface on 23rd August 2023\",\n", - " \"It consists of a lander named Vikram and a rover named Pragyan similar to Chandrayaan-2. Its propulsion module would act like an orbiter.\",\n", - " \"The propulsion module carries the lander and rover configuration until the spacecraft is in a 100-kilometre (62 mi) lunar orbit\",\n", - " \"The mission used GSLV Mk III rocket for its launch\",\n", - " \"Chandrayaan-3 was launched from the Satish Dhawan Space Centre in Sriharikota\",\n", - " \"Chandrayaan-3 was launched earlier in the year 2023\",\n", - "]\n", - "len(documents)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setting up 🤗 Huggingface\n", - "\n", - "We'll be using the [Huggingface Transformers](https://huggingface.co/transformers/) with PyTorch library to generate embeddings. We'll be using the same model across both libraries for a fair(er?) comparison." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "torch.Size([12, 384])" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "class HF:\n", - " \"\"\"\n", - " HuggingFace Transformer implementation of FlagEmbedding\n", - " Based on https://huggingface.co/BAAI/bge-base-en\n", - " \"\"\"\n", - "\n", - " def __init__(self, model_id: str):\n", - " self.model = AutoModel.from_pretrained(model_id)\n", - " self.tokenizer = AutoTokenizer.from_pretrained(model_id)\n", - "\n", - " def embed(self, texts: List[str]):\n", - " encoded_input = self.tokenizer(texts, max_length=512, padding=True, truncation=True, return_tensors=\"pt\")\n", - " model_output = self.model(**encoded_input)\n", - " sentence_embeddings = model_output[0][:, 0]\n", - " sentence_embeddings = F.normalize(sentence_embeddings)\n", - " return sentence_embeddings\n", - "\n", - "hf = HF(model_id=\"BAAI/bge-small-en\")\n", - "hf.embed(documents).shape" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setting up ⚡️FastEmbed\n", - "\n", - "Sorry, don't have a lot to set up here. We'll be using the default model, which is Flag Embedding, same as the Huggingface model." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "embedding_model = DefaultEmbedding()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 📊 Comparison\n", - "\n", - "We'll be comparing the following metrics: Minimum, Maximum, Mean, across k runs. Let's write a function to do that:\n", - "\n", - "### 🚀 Calculating Stats" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "def calculate_time_stats(embed_func: Callable, documents: list, k: int) -> Tuple[float, float, float]:\n", - " times = []\n", - " for _ in range(k):\n", - " # Timing the embed_func call\n", - " start_time = time.time()\n", - " embeddings = embed_func(documents)\n", - " end_time = time.time()\n", - "\n", - " times.append(end_time - start_time)\n", - "\n", - " # Returning mean, max, and min time for the call\n", - " return (sum(times) / k, max(times), min(times))" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Huggingface Transformers (Average, Max, Min): (0.06899809837341309, 0.07179117202758789, 0.06620502471923828)\n", - "FastEmbed (Average, Max, Min): (0.6830369234085083, 0.6874828338623047, 0.6785910129547119)\n" - ] - } - ], - "source": [ - "hf_stats = calculate_time_stats(hf.embed, documents, k=2)\n", - "print(f\"Huggingface Transformers (Average, Max, Min): {hf_stats}\")\n", - "fst_stats = calculate_time_stats(lambda x: list(embedding_model.embed(x)), documents, k=2)\n", - "print(f\"FastEmbed (Average, Max, Min): {fst_stats}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 📈 Results\n", - "\n", - "Let's run the comparison and see the results." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n", - "To disable this warning, you can either:\n", - "\t- Avoid using `tokenizers` before the fork if possible\n", - "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n", - "\u001b[33mDEPRECATION: pytorch-lightning 1.6.5 has a non-standard dependency specifier torch>=1.8.*. pip 23.3 will enforce this behaviour change. A possible replacement is to upgrade to a newer version of pytorch-lightning or contact the author to suggest that they release a version with a conforming dependency specifiers. Discussion can be found at https://github.com/pypa/pip/issues/12063\u001b[0m\u001b[33m\n", - "\u001b[0m" - ] - } - ], - "source": [ - "!pip install matplotlib --quiet" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "def plot_character_per_second_comparison(\n", - " hf_stats: Tuple[float, float, float], fst_stats: Tuple[float, float, float], documents: list\n", - "):\n", - " # Calculating total characters in documents\n", - " total_characters = sum(len(doc) for doc in documents)\n", - "\n", - " # Calculating characters per second for each model\n", - " hf_chars_per_sec = total_characters / hf_stats[0] # Mean time is at index 0\n", - " fst_chars_per_sec = total_characters / fst_stats[0]\n", - "\n", - " # Plotting the bar chart\n", - " models = [\"HF Embed (Torch)\", \"FastEmbed\"]\n", - " chars_per_sec = [hf_chars_per_sec, fst_chars_per_sec]\n", - "\n", - " bars = plt.bar(models, chars_per_sec, color=[\"#1f356c\", \"#dd1f4b\"])\n", - " plt.ylabel(\"Characters per Second\")\n", - " plt.title(\"Characters Processed per Second Comparison\")\n", - "\n", - " # Adding the number at the top of each bar\n", - " for bar, chars in zip(bars, chars_per_sec):\n", - " plt.text(\n", - " bar.get_x() + bar.get_width() / 2,\n", - " bar.get_height(),\n", - " f\"{chars:.1f}\",\n", - " ha=\"center\",\n", - " va=\"bottom\",\n", - " color=\"#1f356c\",\n", - " fontsize=12,\n", - " )\n", - "\n", - " plt.show()\n", - "\n", - "\n", - "plot_character_per_second_comparison(hf_stats, fst_stats, documents)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "fst", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.17" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -}