Files
fastembed/experiments/Throughput_Across_Models_GPU.ipynb
2025-03-07 06:23:01 +02:00

493 lines
55 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "2Novt26HXCxC"
},
"source": [
"# 🤗 Huggingface vs ⚡ FastEmbed\n",
"\n",
"Comparing the performance of Huggingface's 🤗 Transformers and ⚡ FastEmbed on a simple task (GPU)\n",
"## 📦 Imports\n",
"\n",
"Importing the necessary libraries for this comparison."
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ZPBcPVLFapCs",
"outputId": "d8d78e12-8cf9-4115-d187-dfbc38e63bae"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: fastembed-gpu in /usr/local/lib/python3.11/dist-packages (0.6.0)\n",
"Requirement already satisfied: huggingface-hub<1.0,>=0.20 in /usr/local/lib/python3.11/dist-packages (from fastembed-gpu) (0.28.1)\n",
"Requirement already satisfied: loguru<0.8.0,>=0.7.2 in /usr/local/lib/python3.11/dist-packages (from fastembed-gpu) (0.7.3)\n",
"Requirement already satisfied: mmh3<6.0.0,>=4.1.0 in /usr/local/lib/python3.11/dist-packages (from fastembed-gpu) (5.1.0)\n",
"Requirement already satisfied: numpy>=1.21 in /usr/local/lib/python3.11/dist-packages (from fastembed-gpu) (1.26.4)\n",
"Requirement already satisfied: onnxruntime-gpu!=1.20.0,>=1.17.0 in /usr/local/lib/python3.11/dist-packages (from fastembed-gpu) (1.20.1)\n",
"Requirement already satisfied: pillow<12.0.0,>=10.3.0 in /usr/local/lib/python3.11/dist-packages (from fastembed-gpu) (11.1.0)\n",
"Requirement already satisfied: py-rust-stemmers<0.2.0,>=0.1.0 in /usr/local/lib/python3.11/dist-packages (from fastembed-gpu) (0.1.5)\n",
"Requirement already satisfied: requests<3.0,>=2.31 in /usr/local/lib/python3.11/dist-packages (from fastembed-gpu) (2.32.3)\n",
"Requirement already satisfied: tokenizers<1.0,>=0.15 in /usr/local/lib/python3.11/dist-packages (from fastembed-gpu) (0.21.0)\n",
"Requirement already satisfied: tqdm<5.0,>=4.66 in /usr/local/lib/python3.11/dist-packages (from fastembed-gpu) (4.67.1)\n",
"Requirement already satisfied: filelock in /usr/local/lib/python3.11/dist-packages (from huggingface-hub<1.0,>=0.20->fastembed-gpu) (3.17.0)\n",
"Requirement already satisfied: fsspec>=2023.5.0 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub<1.0,>=0.20->fastembed-gpu) (2024.10.0)\n",
"Requirement already satisfied: packaging>=20.9 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub<1.0,>=0.20->fastembed-gpu) (24.2)\n",
"Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub<1.0,>=0.20->fastembed-gpu) (6.0.2)\n",
"Requirement already satisfied: typing-extensions>=3.7.4.3 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub<1.0,>=0.20->fastembed-gpu) (4.12.2)\n",
"Requirement already satisfied: coloredlogs in /usr/local/lib/python3.11/dist-packages (from onnxruntime-gpu!=1.20.0,>=1.17.0->fastembed-gpu) (15.0.1)\n",
"Requirement already satisfied: flatbuffers in /usr/local/lib/python3.11/dist-packages (from onnxruntime-gpu!=1.20.0,>=1.17.0->fastembed-gpu) (25.2.10)\n",
"Requirement already satisfied: protobuf in /usr/local/lib/python3.11/dist-packages (from onnxruntime-gpu!=1.20.0,>=1.17.0->fastembed-gpu) (4.25.6)\n",
"Requirement already satisfied: sympy in /usr/local/lib/python3.11/dist-packages (from onnxruntime-gpu!=1.20.0,>=1.17.0->fastembed-gpu) (1.13.1)\n",
"Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests<3.0,>=2.31->fastembed-gpu) (3.4.1)\n",
"Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests<3.0,>=2.31->fastembed-gpu) (3.10)\n",
"Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests<3.0,>=2.31->fastembed-gpu) (2.3.0)\n",
"Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/dist-packages (from requests<3.0,>=2.31->fastembed-gpu) (2025.1.31)\n",
"Requirement already satisfied: humanfriendly>=9.1 in /usr/local/lib/python3.11/dist-packages (from coloredlogs->onnxruntime-gpu!=1.20.0,>=1.17.0->fastembed-gpu) (10.0)\n",
"Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from sympy->onnxruntime-gpu!=1.20.0,>=1.17.0->fastembed-gpu) (1.3.0)\n"
]
}
],
"source": [
"!pip install fastembed-gpu"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "iFgsdd7vabSW",
"outputId": "3a6abe8e-6111-4820-aa1e-8c2d6bb25381"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: torch in /usr/local/lib/python3.11/dist-packages (2.5.1+cu124)\n",
"Requirement already satisfied: transformers in /usr/local/lib/python3.11/dist-packages (4.48.3)\n",
"Requirement already satisfied: matplotlib in /usr/local/lib/python3.11/dist-packages (3.10.0)\n",
"Requirement already satisfied: filelock in /usr/local/lib/python3.11/dist-packages (from torch) (3.17.0)\n",
"Requirement already satisfied: typing-extensions>=4.8.0 in /usr/local/lib/python3.11/dist-packages (from torch) (4.12.2)\n",
"Requirement already satisfied: networkx in /usr/local/lib/python3.11/dist-packages (from torch) (3.4.2)\n",
"Requirement already satisfied: jinja2 in /usr/local/lib/python3.11/dist-packages (from torch) (3.1.5)\n",
"Requirement already satisfied: fsspec in /usr/local/lib/python3.11/dist-packages (from torch) (2024.10.0)\n",
"Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch) (12.4.127)\n",
"Requirement already satisfied: nvidia-cuda-runtime-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch) (12.4.127)\n",
"Requirement already satisfied: nvidia-cuda-cupti-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch) (12.4.127)\n",
"Requirement already satisfied: nvidia-cudnn-cu12==9.1.0.70 in /usr/local/lib/python3.11/dist-packages (from torch) (9.1.0.70)\n",
"Requirement already satisfied: nvidia-cublas-cu12==12.4.5.8 in /usr/local/lib/python3.11/dist-packages (from torch) (12.4.5.8)\n",
"Requirement already satisfied: nvidia-cufft-cu12==11.2.1.3 in /usr/local/lib/python3.11/dist-packages (from torch) (11.2.1.3)\n",
"Requirement already satisfied: nvidia-curand-cu12==10.3.5.147 in /usr/local/lib/python3.11/dist-packages (from torch) (10.3.5.147)\n",
"Requirement already satisfied: nvidia-cusolver-cu12==11.6.1.9 in /usr/local/lib/python3.11/dist-packages (from torch) (11.6.1.9)\n",
"Requirement already satisfied: nvidia-cusparse-cu12==12.3.1.170 in /usr/local/lib/python3.11/dist-packages (from torch) (12.3.1.170)\n",
"Requirement already satisfied: nvidia-nccl-cu12==2.21.5 in /usr/local/lib/python3.11/dist-packages (from torch) (2.21.5)\n",
"Requirement already satisfied: nvidia-nvtx-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch) (12.4.127)\n",
"Requirement already satisfied: nvidia-nvjitlink-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch) (12.4.127)\n",
"Requirement already satisfied: triton==3.1.0 in /usr/local/lib/python3.11/dist-packages (from torch) (3.1.0)\n",
"Requirement already satisfied: sympy==1.13.1 in /usr/local/lib/python3.11/dist-packages (from torch) (1.13.1)\n",
"Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from sympy==1.13.1->torch) (1.3.0)\n",
"Requirement already satisfied: huggingface-hub<1.0,>=0.24.0 in /usr/local/lib/python3.11/dist-packages (from transformers) (0.28.1)\n",
"Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.11/dist-packages (from transformers) (1.26.4)\n",
"Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from transformers) (24.2)\n",
"Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.11/dist-packages (from transformers) (6.0.2)\n",
"Requirement already satisfied: regex!=2019.12.17 in /usr/local/lib/python3.11/dist-packages (from transformers) (2024.11.6)\n",
"Requirement already satisfied: requests in /usr/local/lib/python3.11/dist-packages (from transformers) (2.32.3)\n",
"Requirement already satisfied: tokenizers<0.22,>=0.21 in /usr/local/lib/python3.11/dist-packages (from transformers) (0.21.0)\n",
"Requirement already satisfied: safetensors>=0.4.1 in /usr/local/lib/python3.11/dist-packages (from transformers) (0.5.3)\n",
"Requirement already satisfied: tqdm>=4.27 in /usr/local/lib/python3.11/dist-packages (from transformers) (4.67.1)\n",
"Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (1.3.1)\n",
"Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (0.12.1)\n",
"Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (4.56.0)\n",
"Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (1.4.8)\n",
"Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (11.1.0)\n",
"Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (3.2.1)\n",
"Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (2.8.2)\n",
"Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.7->matplotlib) (1.17.0)\n",
"Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.11/dist-packages (from jinja2->torch) (3.0.2)\n",
"Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests->transformers) (3.4.1)\n",
"Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests->transformers) (3.10)\n",
"Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests->transformers) (2.3.0)\n",
"Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/dist-packages (from requests->transformers) (2025.1.31)\n"
]
}
],
"source": [
"!pip3 install torch transformers matplotlib"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"ExecuteTime": {
"end_time": "2024-03-30T00:33:35.753669Z",
"start_time": "2024-03-30T00:33:34.371658Z"
},
"id": "veEu-ceoXCxF"
},
"outputs": [],
"source": [
"import time\n",
"from typing import Callable\n",
"\n",
"import torch\n",
"import torch.nn.functional as F\n",
"from fastembed import TextEmbedding\n",
"import matplotlib.pyplot as plt\n",
"from transformers import AutoModel, AutoTokenizer"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "9IfJREvLXCxG"
},
"source": [
"## 📖 Data\n",
"\n",
"data is a list of strings, each string is a document."
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"ExecuteTime": {
"end_time": "2024-03-30T00:33:35.766679Z",
"start_time": "2024-03-30T00:33:35.755112Z"
},
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "BHqha4PNXCxG",
"outputId": "e08b7609-b3ac-4512-aac5-3a14022b2abb"
},
"outputs": [
{
"data": {
"text/plain": [
"12"
]
},
"execution_count": 40,
"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": "code",
"execution_count": 41,
"metadata": {
"ExecuteTime": {
"end_time": "2024-03-30T00:33:35.766791Z",
"start_time": "2024-03-30T00:33:35.756803Z"
},
"id": "7xdiTTcuXCxH"
},
"outputs": [],
"source": [
"model_id = \"BAAI/bge-small-en\""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "s2Ei2QrmXCxH"
},
"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": 42,
"metadata": {
"ExecuteTime": {
"end_time": "2024-03-30T00:34:03.988Z",
"start_time": "2024-03-30T00:33:37.460865Z"
},
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "QiE-lfI5XCxH",
"outputId": "edc71144-62f1-4349-a203-208b8e5fc386"
},
"outputs": [
{
"data": {
"text/plain": [
"torch.Size([12, 384])"
]
},
"execution_count": 42,
"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__(\n",
" self, model_id: str, device: str = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
" ):\n",
" self.device = device\n",
" self.model = AutoModel.from_pretrained(model_id).to(self.device)\n",
" self.tokenizer = AutoTokenizer.from_pretrained(model_id)\n",
"\n",
" def embed(self, texts: list[str]):\n",
" encoded_input = self.tokenizer(\n",
" texts, max_length=512, padding=True, truncation=True, return_tensors=\"pt\"\n",
" ).to(self.device)\n",
"\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",
"\n",
"hf = HF(model_id=model_id)\n",
"hf.embed(documents).shape"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ySKCZyJbXCxJ"
},
"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": 43,
"metadata": {
"ExecuteTime": {
"end_time": "2024-03-30T00:34:04.076422Z",
"start_time": "2024-03-30T00:34:03.987162Z"
},
"id": "HQU9j4_AXCxJ"
},
"outputs": [],
"source": [
"embedding_model = TextEmbedding(model_name=model_id, cuda=True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ziD5ifdCXCxK"
},
"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": 44,
"metadata": {
"ExecuteTime": {
"end_time": "2024-03-30T00:34:06.543782Z",
"start_time": "2024-03-30T00:34:06.357816Z"
},
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "E5BPzLwrXCxK",
"outputId": "d9c9bae5-cb54-46e1-8cfe-f2bd24beb64d"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Huggingface Transformers (Average, Max, Min): (0.014735164642333985, 0.03357124328613281, 0.011344671249389648)\n",
"FastEmbed (Average, Max, Min): (0.008367671966552734, 0.020212650299072266, 0.006894826889038086)\n"
]
}
],
"source": [
"import types\n",
"\n",
"\n",
"def calculate_time_stats(\n",
" embed_func: Callable, documents: list[str], k: int\n",
") -> 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",
" # Force computation if embed_func returns a generator\n",
" if isinstance(embeddings, types.GeneratorType):\n",
" list(embeddings)\n",
"\n",
" end_time = time.time()\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))\n",
"\n",
"\n",
"hf_stats = calculate_time_stats(hf.embed, documents, k=100)\n",
"print(f\"Huggingface Transformers (Average, Max, Min): {hf_stats}\")\n",
"fst_stats = calculate_time_stats(embedding_model.embed, documents, k=100)\n",
"print(f\"FastEmbed (Average, Max, Min): {fst_stats}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "dpudV0MIXCxK"
},
"source": [
"## 📈 Results\n",
"\n",
"Let's run the comparison and see the results."
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"ExecuteTime": {
"end_time": "2024-03-30T00:34:11.032206Z",
"start_time": "2024-03-30T00:34:10.828410Z"
},
"colab": {
"base_uri": "https://localhost:8080/",
"height": 452
},
"id": "c7Bi9_3XXCxL",
"outputId": "eabef8b4-ae7a-466c-c625-6bdb52885872"
},
"outputs": [
{
"data": {
"image/png": "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FQsAlJamaNm4Gv49FoONO44hV62Gq5Mtxg3tgMEft5SuKAFAE+8qWH3vEFZtOIiU1AwoLc1Qv5Ybhg1ojWpVnDXGtS2txIafR2Hm/M347c/9eJqTi9pe5fHDV30LvE2Zx8jQAOuXjcSCX0Ox/9AFbN0TBQszE/h94IXxQzrA2sqi0OeU5KMQQojiTuJ9kZqaCpVKhZSUFH73HxERUQlR2L/fnFNFREREJAMWVUREREQy4JwqIqIS5Lpr++JOgeitVeHm9mLdP69UEREREcmARRURERGRDFhUEREREcmARRURERGRDFhUEREREcmARRURERGRDFhUEREREcmARRURERGRDFhUEREREcmARRURERGRDFhUEREREcmARRURERGRDFhUEREREcmARRURERGRDFhUEREREcmARRURERGRDFhUEREREcmARRURERGRDFhUEREREcmARRURERGRDIq1qIqIiECHDh3g6OgIhUKBLVu2aPQLITBlyhSUKVMGpqam8PX1xZUrVzRikpKS0KdPHyiVSlhZWSEwMBBpaWkaMWfPnkWTJk1gYmICZ2dnzJ49WyuX9evXo0qVKjAxMYGXlxd27typcy5ERET0/irWoio9PR01atTAokWL8u2fPXs2FixYgCVLluDo0aMwNzeHv78/MjMzpZg+ffrgwoUL2Lt3L7Zv346IiAgMHjxY6k9NTYWfnx9cXFwQFRWFOXPmYNq0aVi2bJkUc/jwYfTq1QuBgYE4deoUOnfujM6dO+P8+fM65UJERETvL4UQQhR3EgCgUCiwefNmdO7cGcCzK0OOjo4YM2YMxo4dCwBISUmBvb09VqxYgZ49e+LSpUvw9PTE8ePHUbduXQBAaGgo2rZti7t378LR0RGLFy/GF198gdjYWBgZGQEAJk6ciC1btiA6OhoA0KNHD6Snp2P79u1SPg0aNEDNmjWxZMmSQuVSGKmpqVCpVEhJSYFSqZTlvBHR++W6a/viToHorVXh5vZXB72Gwv79fmvnVN24cQOxsbHw9fWV2lQqFby9vREZGQkAiIyMhJWVlVRQAYCvry/09PRw9OhRKaZp06ZSQQUA/v7+iImJwaNHj6SY5/eTF5O3n8Lkkp+srCykpqZq/BAREdG76a0tqmJjYwEA9vb2Gu329vZSX2xsLOzs7DT6DQwMYG1trRGT3xjP76OgmOf7X5VLfkJCQqBSqaQfZ2fnVxw1ERERlVRvbVH1Lpg0aRJSUlKknzt37hR3SkRERFRE3tqiysHBAQAQFxen0R4XFyf1OTg4ID4+XqM/JycHSUlJGjH5jfH8PgqKeb7/Vbnkx9jYGEqlUuOHiIiI3k1vbVFVvnx5ODg4ICwsTGpLTU3F0aNH4ePjAwDw8fFBcnIyoqKipJjw8HCo1Wp4e3tLMREREXj69KkUs3fvXri7u6NUqVJSzPP7yYvJ209hciEiIqL3W7EWVWlpaTh9+jROnz4N4NmE8NOnT+P27dtQKBQYOXIkZsyYga1bt+LcuXPo27cvHB0dpU8Ienh4oHXr1hg0aBCOHTuGQ4cOITg4GD179oSjoyMAoHfv3jAyMkJgYCAuXLiAtWvXYv78+Rg9erSUx4gRIxAaGoq5c+ciOjoa06ZNw4kTJxAcHAwAhcqFiIiI3m8GxbnzEydOoHnz5tLjvEInICAAK1aswPjx45Geno7BgwcjOTkZjRs3RmhoKExMTKRtVq9ejeDgYLRs2RJ6enro1q0bFixYIPWrVCrs2bMHQUFBqFOnDmxsbDBlyhSNtawaNmyINWvW4Msvv8Tnn3+OSpUqYcuWLahWrZoUU5hciIiI6P311qxT9T7gOlVE9Ka4ThVRwbhOFREREdE7gEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJ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0aJFGDduHBo1aoQTJ06ga9eu+PXXX4sq1xKvsOtcvA6uU0X0clyniujdV+LWqVq2bBnUajUASF8Pc/jwYXTs2BGffvrp62dMREREVILpXFTp6elBT+//57f37NkTPXv2lDUpIiIiopLmtdapSk5OxrFjxxAfHy9dtcrTt29fWRIjIiIiKkl0Lqq2bduGPn36IC0tDUqlEgqFQupTKBQsqoiIiOi9pPM6VWPGjMGAAQOQlpaG5ORkPHr0SPpJSkoqihyJiIiI3no6F1X37t3D8OHDYWZmVhT5EBEREZVIOhdV/v7+OHHiRFHkQkRERFRiFWpO1datW6X/b9euHcaNG4eLFy/Cy8sLhoaGGrEdO3aUN0MiIiKiEqBQRVXnzp212p5fkTyPQqFAbm7uGydFREREVNIUqqh6cdkEIiIiItKk85wqIiIiItJW6KIqPDwcnp6eSE1N1epLSUlB1apVERERIWtyRERERCVFoYuqefPmYdCgQfl+kaBKpcKnn36KH374QdbkiIiIiEqKQhdVZ86cQevWrQvs9/PzQ1RUlCxJEREREZU0hS6q4uLitJZPeJ6BgQESEhJkSYqIiIiopCl0UVW2bFmcP3++wP6zZ8+iTJkysiRFREREVNIUuqhq27YtJk+ejMzMTK2+J0+eYOrUqWjfvr2syRERERGVFIVapwoAvvzyS2zatAmVK1dGcHAw3N3dAQDR0dFYtGgRcnNz8cUXXxRZokRERERvs0IXVfb29jh8+DCGDBmCSZMmQQgB4Nkq6v7+/li0aBHs7e2LLFEiIiKit1mhiyoAcHFxwc6dO/Ho0SNcvXoVQghUqlQJpUqVKqr8iIiIiEoEnYqqPKVKlUK9evXkzoWIiIioxOLX1BARERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxY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\n",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def plot_character_per_second_comparison(\n",
" hf_stats: tuple[float, ...], fst_stats: tuple[float, ...], documents: list[str]\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)"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"id": "5Y_ilYACXCxL"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"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": 0
}