188 lines
6.4 KiB
Python
Raw Normal View History

Create time and performance benchmarks for all readers and retrievers (#339) * add time and perf benchmark for es * Add retriever benchmarking * Add Reader benchmarking * add nq to squad conversion * add conversion stats * clean benchmarks * Add link to dataset * Update imports * add first support for neg psgs * Refactor test * set max_seq_len * cleanup benchmark * begin retriever speed benchmarking * Add support for retriever query index benchmarking * improve reader eval, retriever speed benchmarking * improve retriever speed benchmarking * Add retriever accuracy benchmark * Add neg doc shuffling * Add top_n * 3x speedup of SQL. add postgres docker run. make shuffle neg a param. add more logging * Add models to sweep * add option for faiss index type * remove unneeded line * change faiss to faiss_flat * begin automatic benchmark script * remove existing postgres docker for benchmarking * Add data processing scripts * Remove shuffle in script bc data already shuffled * switch hnsw setup from 256 to 128 * change es similarity to dot product by default * Error includes stack trace * Change ES default timeout * remove delete_docs() from timing for indexing * Add support for website export * update website on push to benchmarks * add complete benchmarks results * new json format * removed NaN as is not a valid json token * fix benchmarking for faiss hnsw queries. do sql calls in update_embeddings() as batches * update benchmarks for hnsw 128,20,80 * don't delete full index in delete_all_documents() * update texts for charts * update recall column for retriever * change scale and add units to desc * add units to legend * add axis titles. update desc * add html tags Co-authored-by: deepset <deepset@Crenolape.localdomain> Co-authored-by: Malte Pietsch <malte.pietsch@deepset.ai> Co-authored-by: PiffPaffM <markuspaff.mp@gmail.com>
2020-10-12 13:34:42 +02:00
import os
import tarfile
import tempfile
import pandas as pd
from haystack import Label, Document, Answer, Pipeline
from haystack.document_stores import eval_data_from_json
from haystack.nodes import BaseReader, BaseRetriever
from haystack.utils import launch_es, launch_opensearch, launch_weaviate
from haystack.modeling.data_handler.processor import http_get
Create time and performance benchmarks for all readers and retrievers (#339) * add time and perf benchmark for es * Add retriever benchmarking * Add Reader benchmarking * add nq to squad conversion * add conversion stats * clean benchmarks * Add link to dataset * Update imports * add first support for neg psgs * Refactor test * set max_seq_len * cleanup benchmark * begin retriever speed benchmarking * Add support for retriever query index benchmarking * improve reader eval, retriever speed benchmarking * improve retriever speed benchmarking * Add retriever accuracy benchmark * Add neg doc shuffling * Add top_n * 3x speedup of SQL. add postgres docker run. make shuffle neg a param. add more logging * Add models to sweep * add option for faiss index type * remove unneeded line * change faiss to faiss_flat * begin automatic benchmark script * remove existing postgres docker for benchmarking * Add data processing scripts * Remove shuffle in script bc data already shuffled * switch hnsw setup from 256 to 128 * change es similarity to dot product by default * Error includes stack trace * Change ES default timeout * remove delete_docs() from timing for indexing * Add support for website export * update website on push to benchmarks * add complete benchmarks results * new json format * removed NaN as is not a valid json token * fix benchmarking for faiss hnsw queries. do sql calls in update_embeddings() as batches * update benchmarks for hnsw 128,20,80 * don't delete full index in delete_all_documents() * update texts for charts * update recall column for retriever * change scale and add units to desc * add units to legend * add axis titles. update desc * add html tags Co-authored-by: deepset <deepset@Crenolape.localdomain> Co-authored-by: Malte Pietsch <malte.pietsch@deepset.ai> Co-authored-by: PiffPaffM <markuspaff.mp@gmail.com>
2020-10-12 13:34:42 +02:00
import logging
from typing import Dict, Union, Tuple
Create time and performance benchmarks for all readers and retrievers (#339) * add time and perf benchmark for es * Add retriever benchmarking * Add Reader benchmarking * add nq to squad conversion * add conversion stats * clean benchmarks * Add link to dataset * Update imports * add first support for neg psgs * Refactor test * set max_seq_len * cleanup benchmark * begin retriever speed benchmarking * Add support for retriever query index benchmarking * improve reader eval, retriever speed benchmarking * improve retriever speed benchmarking * Add retriever accuracy benchmark * Add neg doc shuffling * Add top_n * 3x speedup of SQL. add postgres docker run. make shuffle neg a param. add more logging * Add models to sweep * add option for faiss index type * remove unneeded line * change faiss to faiss_flat * begin automatic benchmark script * remove existing postgres docker for benchmarking * Add data processing scripts * Remove shuffle in script bc data already shuffled * switch hnsw setup from 256 to 128 * change es similarity to dot product by default * Error includes stack trace * Change ES default timeout * remove delete_docs() from timing for indexing * Add support for website export * update website on push to benchmarks * add complete benchmarks results * new json format * removed NaN as is not a valid json token * fix benchmarking for faiss hnsw queries. do sql calls in update_embeddings() as batches * update benchmarks for hnsw 128,20,80 * don't delete full index in delete_all_documents() * update texts for charts * update recall column for retriever * change scale and add units to desc * add units to legend * add axis titles. update desc * add html tags Co-authored-by: deepset <deepset@Crenolape.localdomain> Co-authored-by: Malte Pietsch <malte.pietsch@deepset.ai> Co-authored-by: PiffPaffM <markuspaff.mp@gmail.com>
2020-10-12 13:34:42 +02:00
from pathlib import Path
Create time and performance benchmarks for all readers and retrievers (#339) * add time and perf benchmark for es * Add retriever benchmarking * Add Reader benchmarking * add nq to squad conversion * add conversion stats * clean benchmarks * Add link to dataset * Update imports * add first support for neg psgs * Refactor test * set max_seq_len * cleanup benchmark * begin retriever speed benchmarking * Add support for retriever query index benchmarking * improve reader eval, retriever speed benchmarking * improve retriever speed benchmarking * Add retriever accuracy benchmark * Add neg doc shuffling * Add top_n * 3x speedup of SQL. add postgres docker run. make shuffle neg a param. add more logging * Add models to sweep * add option for faiss index type * remove unneeded line * change faiss to faiss_flat * begin automatic benchmark script * remove existing postgres docker for benchmarking * Add data processing scripts * Remove shuffle in script bc data already shuffled * switch hnsw setup from 256 to 128 * change es similarity to dot product by default * Error includes stack trace * Change ES default timeout * remove delete_docs() from timing for indexing * Add support for website export * update website on push to benchmarks * add complete benchmarks results * new json format * removed NaN as is not a valid json token * fix benchmarking for faiss hnsw queries. do sql calls in update_embeddings() as batches * update benchmarks for hnsw 128,20,80 * don't delete full index in delete_all_documents() * update texts for charts * update recall column for retriever * change scale and add units to desc * add units to legend * add axis titles. update desc * add html tags Co-authored-by: deepset <deepset@Crenolape.localdomain> Co-authored-by: Malte Pietsch <malte.pietsch@deepset.ai> Co-authored-by: PiffPaffM <markuspaff.mp@gmail.com>
2020-10-12 13:34:42 +02:00
logger = logging.getLogger(__name__)
def prepare_environment(pipeline_config: Dict, benchmark_config: Dict):
"""
Prepare the environment for running a benchmark.
"""
# Download data if specified in benchmark config
if "data_url" in benchmark_config:
download_from_url(url=benchmark_config["data_url"], target_dir="data/")
n_docs = 0
if "documents_directory" in benchmark_config:
documents_dir = Path(benchmark_config["documents_directory"])
n_docs = len(
[
file_path
for file_path in documents_dir.iterdir()
if file_path.is_file() and not file_path.name.startswith(".")
]
)
# Launch DocumentStore Docker container if needed
ci: Add Github workflow to automate benchmark runs (#5399) * Add config files * log benchmarks to stdout * Add top-k and batch size to configs * Add batch size to configs * fix: don't download files if they already exist * Add batch size to configs * refine script * Remove configs using 1m docs * update run script * update run script * update run script * datadog integration * remove out folder * gitignore benchmarks output * test: send benchmarks to datadog * remove uncommented lines in script * feat: take branch/tag argument for benchmark setup script * fix: run.sh should ignore errors * Add GH workflow to run benchmarks periodically * Remove unused script * Adapt cml.yml * Adapt cml.yml * Rename cml.yml to benchmarks.yml * Revert "Rename cml.yml to benchmarks.yml" This reverts commit 897299433a71a55827124728adff5de918d46d21. * remove benchmarks.yml * Use same file extension for all config files * Use checkout@v3 * Run benchmarks sequentially * Add timeout-minutes parameter * Remove changes unrelated to datadog * Apply black * use haystack-oss aws account * Update test/benchmarks/utils.py Co-authored-by: Silvano Cerza <3314350+silvanocerza@users.noreply.github.com> * PR feedback * fix aws credentials step * Fix path * check docker * Allow spinning up containers from within container * Allow spinning up containers from within container * Separate launching doc stores from benchmarks * Remove docker related commands * run only retrievers * change port * Revert "change port" This reverts commit 6e5bcebb1d16e03ba7672be7e8a089084c7fc3a7. * Run opensearch benchmark only * Run weaviate benchmark only * Run bm25 benchmarks only * Changes host of doc stores * add step to get docker logs * Revert "add step to get docker logs" This reverts commit c10e6faa76bde5df406a027203bd775d18c93c90. * Install docker * Launch doc store containers from wtihin runner container * Remove kill command * Change host * dump docker logs * change port * Add cloud startup script * dump docker logs * add network param * add network to startup.sh * check cluster health * move steps * change port * try using services * check cluster health * use services * run only weaviate * change host * Upload benchmark results as artifacts * Update configs * Delete index after benchmark run * Use correct index name * Run only failing config * Use smaller batch size * Increase memory for opensearch * Reduce batch size further * Provide more storage * Reduce batch size * dump docker logs * add java opts * Spin up only opensearch container * Create separate job for each doc store * Run benchmarks sequentially * Set working directory * Account for reader benchmarks not doing indexing * Change key of reader metrics * Apply PR feedback * Remove whitespace * Adapt workflow to changes in datadog scripts * Adapt workflow to changes in datadog scripts * Increase memory for opensearch * Reduce batch size * Add preprocessing_batch_size to Readers * Remove unrelated change * Move order * Fix path * Manually terminate EC2 instance Manually terminate EC2 instance Manually terminate EC2 instance Manually terminate EC2 instance Manually terminate EC2 instance Manually terminate EC2 instance Manually terminate EC2 instance Manually terminate EC2 instance * Manually terminate EC2 instance * Manually terminate EC2 instance * Always terminate runner * Always terminate runner * Remove unnecessary terminate-runner job * Add cron schedule * Disable telemetry * Rename cml.yml to benchmarks.yml --------- Co-authored-by: rjanjua <rohan.janjua@gmail.com> Co-authored-by: Paul Steppacher <p.steppacher91@gmail.com> Co-authored-by: Silvano Cerza <3314350+silvanocerza@users.noreply.github.com> Co-authored-by: Silvano Cerza <silvanocerza@gmail.com>
2023-08-17 12:56:45 +02:00
if "launch_document_store" in benchmark_config and benchmark_config["launch_document_store"]:
for comp in pipeline_config["components"]:
if comp["type"].endswith("DocumentStore"):
launch_document_store(comp["type"], n_docs=n_docs)
break
Create time and performance benchmarks for all readers and retrievers (#339) * add time and perf benchmark for es * Add retriever benchmarking * Add Reader benchmarking * add nq to squad conversion * add conversion stats * clean benchmarks * Add link to dataset * Update imports * add first support for neg psgs * Refactor test * set max_seq_len * cleanup benchmark * begin retriever speed benchmarking * Add support for retriever query index benchmarking * improve reader eval, retriever speed benchmarking * improve retriever speed benchmarking * Add retriever accuracy benchmark * Add neg doc shuffling * Add top_n * 3x speedup of SQL. add postgres docker run. make shuffle neg a param. add more logging * Add models to sweep * add option for faiss index type * remove unneeded line * change faiss to faiss_flat * begin automatic benchmark script * remove existing postgres docker for benchmarking * Add data processing scripts * Remove shuffle in script bc data already shuffled * switch hnsw setup from 256 to 128 * change es similarity to dot product by default * Error includes stack trace * Change ES default timeout * remove delete_docs() from timing for indexing * Add support for website export * update website on push to benchmarks * add complete benchmarks results * new json format * removed NaN as is not a valid json token * fix benchmarking for faiss hnsw queries. do sql calls in update_embeddings() as batches * update benchmarks for hnsw 128,20,80 * don't delete full index in delete_all_documents() * update texts for charts * update recall column for retriever * change scale and add units to desc * add units to legend * add axis titles. update desc * add html tags Co-authored-by: deepset <deepset@Crenolape.localdomain> Co-authored-by: Malte Pietsch <malte.pietsch@deepset.ai> Co-authored-by: PiffPaffM <markuspaff.mp@gmail.com>
2020-10-12 13:34:42 +02:00
def launch_document_store(document_store: str, n_docs: int = 0):
"""
Launch a DocumentStore Docker container.
"""
java_opts = None if n_docs < 500000 else "-Xms4096m -Xmx4096m"
if document_store == "ElasticsearchDocumentStore":
launch_es(sleep=30, delete_existing=True, java_opts=java_opts)
elif document_store == "OpenSearchDocumentStore":
launch_opensearch(sleep=30, delete_existing=True, java_opts=java_opts)
elif document_store == "WeaviateDocumentStore":
launch_weaviate(sleep=30, delete_existing=True)
Create time and performance benchmarks for all readers and retrievers (#339) * add time and perf benchmark for es * Add retriever benchmarking * Add Reader benchmarking * add nq to squad conversion * add conversion stats * clean benchmarks * Add link to dataset * Update imports * add first support for neg psgs * Refactor test * set max_seq_len * cleanup benchmark * begin retriever speed benchmarking * Add support for retriever query index benchmarking * improve reader eval, retriever speed benchmarking * improve retriever speed benchmarking * Add retriever accuracy benchmark * Add neg doc shuffling * Add top_n * 3x speedup of SQL. add postgres docker run. make shuffle neg a param. add more logging * Add models to sweep * add option for faiss index type * remove unneeded line * change faiss to faiss_flat * begin automatic benchmark script * remove existing postgres docker for benchmarking * Add data processing scripts * Remove shuffle in script bc data already shuffled * switch hnsw setup from 256 to 128 * change es similarity to dot product by default * Error includes stack trace * Change ES default timeout * remove delete_docs() from timing for indexing * Add support for website export * update website on push to benchmarks * add complete benchmarks results * new json format * removed NaN as is not a valid json token * fix benchmarking for faiss hnsw queries. do sql calls in update_embeddings() as batches * update benchmarks for hnsw 128,20,80 * don't delete full index in delete_all_documents() * update texts for charts * update recall column for retriever * change scale and add units to desc * add units to legend * add axis titles. update desc * add html tags Co-authored-by: deepset <deepset@Crenolape.localdomain> Co-authored-by: Malte Pietsch <malte.pietsch@deepset.ai> Co-authored-by: PiffPaffM <markuspaff.mp@gmail.com>
2020-10-12 13:34:42 +02:00
def file_previously_downloaded(url_path: Path, target_dir: Union[str, Path]) -> bool:
if ".tar" in url_path.suffixes:
return Path(target_dir, url_path.parent).exists()
return Path(target_dir, url_path.name).exists()
def download_from_url(url: str, target_dir: Union[str, Path]) -> None:
"""
Download from a URL to a local file.
Create time and performance benchmarks for all readers and retrievers (#339) * add time and perf benchmark for es * Add retriever benchmarking * Add Reader benchmarking * add nq to squad conversion * add conversion stats * clean benchmarks * Add link to dataset * Update imports * add first support for neg psgs * Refactor test * set max_seq_len * cleanup benchmark * begin retriever speed benchmarking * Add support for retriever query index benchmarking * improve reader eval, retriever speed benchmarking * improve retriever speed benchmarking * Add retriever accuracy benchmark * Add neg doc shuffling * Add top_n * 3x speedup of SQL. add postgres docker run. make shuffle neg a param. add more logging * Add models to sweep * add option for faiss index type * remove unneeded line * change faiss to faiss_flat * begin automatic benchmark script * remove existing postgres docker for benchmarking * Add data processing scripts * Remove shuffle in script bc data already shuffled * switch hnsw setup from 256 to 128 * change es similarity to dot product by default * Error includes stack trace * Change ES default timeout * remove delete_docs() from timing for indexing * Add support for website export * update website on push to benchmarks * add complete benchmarks results * new json format * removed NaN as is not a valid json token * fix benchmarking for faiss hnsw queries. do sql calls in update_embeddings() as batches * update benchmarks for hnsw 128,20,80 * don't delete full index in delete_all_documents() * update texts for charts * update recall column for retriever * change scale and add units to desc * add units to legend * add axis titles. update desc * add html tags Co-authored-by: deepset <deepset@Crenolape.localdomain> Co-authored-by: Malte Pietsch <malte.pietsch@deepset.ai> Co-authored-by: PiffPaffM <markuspaff.mp@gmail.com>
2020-10-12 13:34:42 +02:00
:param url: URL
:param target_dir: Local directory where the URL content will be saved.
"""
url_path = Path(url)
if file_previously_downloaded(url_path, target_dir):
logger.info(f"Skipping download of {url}, as a previous copy exists")
return
if not os.path.exists(target_dir):
os.makedirs(target_dir)
2020-10-15 18:12:17 +02:00
logger.info("Downloading %s to %s", url_path.name, target_dir)
with tempfile.NamedTemporaryFile() as temp_file:
http_get(url=url, temp_file=temp_file)
temp_file.flush()
temp_file.seek(0)
if tarfile.is_tarfile(temp_file.name):
with tarfile.open(temp_file.name) as tar:
tar.extractall(target_dir)
else:
with open(Path(target_dir) / url_path.name, "wb") as file:
file.write(temp_file.read())
2020-10-15 18:12:17 +02:00
def load_eval_data(eval_set_file: Path):
"""
Load evaluation data from a file.
:param eval_set_file: Path to the evaluation data file.
"""
if not os.path.exists(eval_set_file):
raise FileNotFoundError(f"The file {eval_set_file} does not exist.")
elif os.path.isdir(eval_set_file):
raise IsADirectoryError(f"The path {eval_set_file} is a directory, not a file.")
if eval_set_file.suffix == ".json":
_, labels = eval_data_from_json(str(eval_set_file))
queries = [label.query for label in labels]
elif eval_set_file.suffix == ".csv":
eval_data = pd.read_csv(eval_set_file)
labels = []
queries = []
for idx, row in eval_data.iterrows():
query = row["question"]
context = row["context"]
answer = Answer(answer=row["text"]) if "text" in row else None
label = Label(
query=query,
document=Document(context),
answer=answer,
is_correct_answer=True,
is_correct_document=True,
origin="gold-label",
)
labels.append(label)
queries.append(query)
else:
raise ValueError(
f"Unsupported file format: {eval_set_file.suffix}. Provide a SQuAD-style .json or a .csv file containing "
f"the columns 'question' and 'context' for Retriever evaluations and additionally 'text' (containing the "
f"answer string) for Reader evaluations."
)
return labels, queries
def get_reader_config(pipeline: Pipeline) -> Tuple[str, str, Union[int, str]]:
"""
Get the configuration of the Reader component of a pipeline.
:param pipeline: Pipeline
:return: Tuple of Reader type, model name or path, and top_k
"""
readers = pipeline.get_nodes_by_class(BaseReader)
if not readers:
message = "No component of type BaseReader found"
return message, message, message
reader = readers[0]
reader_type = reader.__class__.__name__
reader_model = reader.model_name_or_path
reader_top_k = reader.top_k
return reader_type, reader_model, reader_top_k
def get_retriever_config(pipeline: Pipeline) -> Tuple[str, Union[int, str]]:
"""
Get the configuration of the Retriever component of a pipeline.
:param pipeline: Pipeline
:return: Tuple of Retriever type and top_k
"""
retrievers = pipeline.get_nodes_by_class(BaseRetriever)
if not retrievers:
message = "No component of type Retriever found"
return message, message
retriever = retrievers[0]
retriever_type = retriever.__class__.__name__
retriever_top_k = retriever.top_k
return retriever_type, retriever_top_k
def contains_reader(pipeline: Pipeline) -> bool:
"""
Check if a pipeline contains a Reader component.
:param pipeline: Pipeline
"""
components = list(pipeline.components.values())
return any(isinstance(comp, BaseReader) for comp in components)
def contains_retriever(pipeline: Pipeline) -> bool:
"""
Check if a pipeline contains a Retriever component.
"""
components = list(pipeline.components.values())
return any(isinstance(comp, BaseRetriever) for comp in components)