Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add runtime parameters to component initialization #873

Merged
merged 2 commits into from
Mar 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/_src/api/api/generator.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ i.e. the model can easily adjust to domain documents even after training has fin
#### \_\_init\_\_

```python
| __init__(model_name_or_path: str = "facebook/rag-token-nq", model_version: Optional[str] = None, retriever: Optional[DensePassageRetriever] = None, generator_type: RAGeneratorType = RAGeneratorType.TOKEN, top_k_answers: int = 2, max_length: int = 200, min_length: int = 2, num_beams: int = 2, embed_title: bool = True, prefix: Optional[str] = None, use_gpu: bool = True)
| __init__(model_name_or_path: str = "facebook/rag-token-nq", model_version: Optional[str] = None, retriever: Optional[DensePassageRetriever] = None, generator_type: RAGeneratorType = RAGeneratorType.TOKEN, top_k: int = 2, max_length: int = 200, min_length: int = 2, num_beams: int = 2, embed_title: bool = True, prefix: Optional[str] = None, use_gpu: bool = True)
```

Load a RAG model from Transformers along with passage_embedding_model.
Expand All @@ -98,7 +98,7 @@ See https://huggingface.co/models for full list of available models.
- `model_version`: The version of model to use from the HuggingFace model hub. Can be tag name, branch name, or commit hash.
- `retriever`: `DensePassageRetriever` used to embedded passage
- `generator_type`: Which RAG generator implementation to use? RAG-TOKEN or RAG-SEQUENCE
- `top_k_answers`: Number of independently generated text to return
- `top_k`: Number of independently generated text to return
- `max_length`: Maximum length of generated text
- `min_length`: Minimum length of generated text
- `num_beams`: Number of beams for beam search. 1 means no beam search.
Expand Down
2 changes: 1 addition & 1 deletion docs/_src/api/api/pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ Initialize a Pipeline that retrieves documents for a query and then summarizes t
#### run

```python
| run(query: str, filters: Optional[Dict] = None, top_k_retriever: int = 10, generate_single_summary: bool = False, return_in_answer_format=False)
| run(query: str, filters: Optional[Dict] = None, top_k_retriever: Optional[int] = None, generate_single_summary: Optional[bool] = None, return_in_answer_format: bool = False)
```

**Arguments**:
Expand Down
6 changes: 4 additions & 2 deletions docs/_src/api/api/reader.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ While the underlying model can vary (BERT, Roberta, DistilBERT, ...), the interf
#### \_\_init\_\_

```python
| __init__(model_name_or_path: Union[str, Path], model_version: Optional[str] = None, context_window_size: int = 150, batch_size: int = 50, use_gpu: bool = True, no_ans_boost: float = 0.0, return_no_answer: bool = False, top_k_per_candidate: int = 3, top_k_per_sample: int = 1, num_processes: Optional[int] = None, max_seq_len: int = 256, doc_stride: int = 128, progress_bar: bool = True)
| __init__(model_name_or_path: Union[str, Path], model_version: Optional[str] = None, context_window_size: int = 150, batch_size: int = 50, use_gpu: bool = True, no_ans_boost: float = 0.0, return_no_answer: bool = False, top_k: int = 10, top_k_per_candidate: int = 3, top_k_per_sample: int = 1, num_processes: Optional[int] = None, max_seq_len: int = 256, doc_stride: int = 128, progress_bar: bool = True)
```

**Arguments**:
Expand All @@ -43,6 +43,7 @@ If set to 0 (default), the no_answer logit is not changed.
If a negative number, there is a lower chance of "no_answer" being predicted.
If a positive number, there is an increased chance of "no_answer"
- `return_no_answer`: Whether to include no_answer predictions in the results.
- `top_k`: The maximum number of answers to return
- `top_k_per_candidate`: How many answers to extract for each candidate doc that is coming from the retriever (might be a long text).
Note that this is not the number of "final answers" you will receive
(see `top_k` in FARMReader.predict() or Finder.get_answers() for that)
Expand Down Expand Up @@ -315,7 +316,7 @@ With this reader, you can directly get predictions via predict()
#### \_\_init\_\_

```python
| __init__(model_name_or_path: str = "distilbert-base-uncased-distilled-squad", model_version: Optional[str] = None, tokenizer: Optional[str] = None, context_window_size: int = 70, use_gpu: int = 0, top_k_per_candidate: int = 4, return_no_answers: bool = True, max_seq_len: int = 256, doc_stride: int = 128)
| __init__(model_name_or_path: str = "distilbert-base-uncased-distilled-squad", model_version: Optional[str] = None, tokenizer: Optional[str] = None, context_window_size: int = 70, use_gpu: int = 0, top_k: int = 10, top_k_per_candidate: int = 4, return_no_answers: bool = True, max_seq_len: int = 256, doc_stride: int = 128)
```

Load a QA model from Transformers.
Expand All @@ -337,6 +338,7 @@ See https://huggingface.co/models for full list of available models.
- `context_window_size`: Num of chars (before and after the answer) to return as "context" for each answer.
The context usually helps users to understand if the answer really makes sense.
- `use_gpu`: If < 0, then use cpu. If >= 0, this is the ordinal of the gpu to use
- `top_k`: The maximum number of answers to return
- `top_k_per_candidate`: How many answers to extract for each candidate doc that is coming from the retriever (might be a long text).
Note that this is not the number of "final answers" you will receive
(see `top_k` in TransformersReader.predict() or Finder.get_answers() for that)
Expand Down
33 changes: 24 additions & 9 deletions docs/_src/api/api/retriever.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class BaseRetriever(BaseComponent)

```python
| @abstractmethod
| retrieve(query: str, filters: dict = None, top_k: int = 10, index: str = None) -> List[Document]
| retrieve(query: str, filters: dict = None, top_k: Optional[int] = None, index: str = None) -> List[Document]
```

Scan through documents in DocumentStore and return a small number documents
Expand Down Expand Up @@ -83,7 +83,7 @@ class ElasticsearchRetriever(BaseRetriever)
#### \_\_init\_\_

```python
| __init__(document_store: ElasticsearchDocumentStore, custom_query: str = None)
| __init__(document_store: ElasticsearchDocumentStore, top_k: int = 10, custom_query: str = None)
```

**Arguments**:
Expand Down Expand Up @@ -121,12 +121,13 @@ names must match with the filters dict supplied in self.retrieve().
| self.retrieve(query="Why did the revenue increase?",
| filters={"years": ["2019"], "quarters": ["Q1", "Q2"]})
```
- `top_k`: How many documents to return per query.

<a name="sparse.ElasticsearchRetriever.retrieve"></a>
#### retrieve

```python
| retrieve(query: str, filters: dict = None, top_k: int = 10, index: str = None) -> List[Document]
| retrieve(query: str, filters: dict = None, top_k: Optional[int] = None, index: str = None) -> List[Document]
```

Scan through documents in DocumentStore and return a small number documents
Expand All @@ -153,7 +154,7 @@ Helpful for benchmarking, testing and if you want to do QA on small documents wi
#### retrieve

```python
| retrieve(query: str, filters: dict = None, top_k: int = 10, index: str = None) -> List[Document]
| retrieve(query: str, filters: dict = None, top_k: Optional[int] = None, index: str = None) -> List[Document]
```

Scan through documents in DocumentStore and return a small number documents
Expand All @@ -180,11 +181,23 @@ computations when text is passed on to a Reader for QA.

It uses sklearn's TfidfVectorizer to compute a tf-idf matrix.

<a name="sparse.TfidfRetriever.__init__"></a>
#### \_\_init\_\_

```python
| __init__(document_store: BaseDocumentStore, top_k: int = 10)
```

**Arguments**:

- `document_store`: an instance of a DocumentStore to retrieve documents from.
- `top_k`: How many documents to return per query.

<a name="sparse.TfidfRetriever.retrieve"></a>
#### retrieve

```python
| retrieve(query: str, filters: dict = None, top_k: int = 10, index: str = None) -> List[Document]
| retrieve(query: str, filters: dict = None, top_k: Optional[int] = None, index: str = None) -> List[Document]
```

Scan through documents in DocumentStore and return a small number documents
Expand Down Expand Up @@ -225,7 +238,7 @@ Karpukhin, Vladimir, et al. (2020): "Dense Passage Retrieval for Open-Domain Que
#### \_\_init\_\_

```python
| __init__(document_store: BaseDocumentStore, query_embedding_model: Union[Path, str] = "facebook/dpr-question_encoder-single-nq-base", passage_embedding_model: Union[Path, str] = "facebook/dpr-ctx_encoder-single-nq-base", model_version: Optional[str] = None, max_seq_len_query: int = 64, max_seq_len_passage: int = 256, use_gpu: bool = True, batch_size: int = 16, embed_title: bool = True, use_fast_tokenizers: bool = True, infer_tokenizer_classes: bool = False, similarity_function: str = "dot_product", progress_bar: bool = True)
| __init__(document_store: BaseDocumentStore, query_embedding_model: Union[Path, str] = "facebook/dpr-question_encoder-single-nq-base", passage_embedding_model: Union[Path, str] = "facebook/dpr-ctx_encoder-single-nq-base", model_version: Optional[str] = None, max_seq_len_query: int = 64, max_seq_len_passage: int = 256, top_k: int = 10, use_gpu: bool = True, batch_size: int = 16, embed_title: bool = True, use_fast_tokenizers: bool = True, infer_tokenizer_classes: bool = False, similarity_function: str = "dot_product", progress_bar: bool = True)
```

Init the Retriever incl. the two encoder models from a local or remote model checkpoint.
Expand Down Expand Up @@ -256,6 +269,7 @@ Currently available remote names: ``"facebook/dpr-ctx_encoder-single-nq-base"``
- `model_version`: The version of model to use from the HuggingFace model hub. Can be tag name, branch name, or commit hash.
- `max_seq_len_query`: Longest length of each query sequence. Maximum number of tokens for the query text. Longer ones will be cut down."
- `max_seq_len_passage`: Longest length of each passage/context sequence. Maximum number of tokens for the passage text. Longer ones will be cut down."
- `top_k`: How many documents to return per query.
- `use_gpu`: Whether to use gpu or not
- `batch_size`: Number of questions or passages to encode at once
- `embed_title`: Whether to concatenate title and passage to a text pair that is then used to create the embedding.
Expand All @@ -276,7 +290,7 @@ Can be helpful to disable in production deployments to keep the logs clean.
#### retrieve

```python
| retrieve(query: str, filters: dict = None, top_k: int = 10, index: str = None) -> List[Document]
| retrieve(query: str, filters: dict = None, top_k: Optional[int] = None, index: str = None) -> List[Document]
```

Scan through documents in DocumentStore and return a small number documents
Expand Down Expand Up @@ -396,7 +410,7 @@ class EmbeddingRetriever(BaseRetriever)
#### \_\_init\_\_

```python
| __init__(document_store: BaseDocumentStore, embedding_model: str, model_version: Optional[str] = None, use_gpu: bool = True, model_format: str = "farm", pooling_strategy: str = "reduce_mean", emb_extraction_layer: int = -1)
| __init__(document_store: BaseDocumentStore, embedding_model: str, model_version: Optional[str] = None, use_gpu: bool = True, model_format: str = "farm", pooling_strategy: str = "reduce_mean", emb_extraction_layer: int = -1, top_k: int = 10)
```

**Arguments**:
Expand All @@ -419,12 +433,13 @@ Options:
- ``'per_token'`` (individual token vectors)
- `emb_extraction_layer`: Number of layer from which the embeddings shall be extracted (for farm / transformers models only).
Default: -1 (very last layer).
- `top_k`: How many documents to return per query.

<a name="dense.EmbeddingRetriever.retrieve"></a>
#### retrieve

```python
| retrieve(query: str, filters: dict = None, top_k: int = 10, index: str = None) -> List[Document]
| retrieve(query: str, filters: dict = None, top_k: Optional[int] = None, index: str = None) -> List[Document]
```

Scan through documents in DocumentStore and return a small number documents
Expand Down
2 changes: 1 addition & 1 deletion haystack/generator/base.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from abc import ABC, abstractmethod
from abc import abstractmethod
from typing import List, Optional, Dict

from haystack import Document, BaseComponent
Expand Down
23 changes: 11 additions & 12 deletions haystack/generator/transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def __init__(
model_version: Optional[str] = None,
retriever: Optional[DensePassageRetriever] = None,
generator_type: RAGeneratorType = RAGeneratorType.TOKEN,
top_k_answers: int = 2,
top_k: int = 2,
max_length: int = 200,
min_length: int = 2,
num_beams: int = 2,
Expand All @@ -85,7 +85,7 @@ def __init__(
:param model_version: The version of model to use from the HuggingFace model hub. Can be tag name, branch name, or commit hash.
:param retriever: `DensePassageRetriever` used to embedded passage
:param generator_type: Which RAG generator implementation to use? RAG-TOKEN or RAG-SEQUENCE
:param top_k_answers: Number of independently generated text to return
:param top_k: Number of independently generated text to return
:param max_length: Maximum length of generated text
:param min_length: Minimum length of generated text
:param num_beams: Number of beams for beam search. 1 means no beam search.
Expand All @@ -103,11 +103,11 @@ def __init__(
self.prefix = prefix
self.retriever = retriever

if top_k_answers > self.num_beams:
top_k_answers = self.num_beams
logger.warning(f'top_k_answers value should not be greater than num_beams, hence setting it to {num_beams}')
if top_k > self.num_beams:
top_k = self.num_beams
logger.warning(f'top_k value should not be greater than num_beams, hence setting it to {num_beams}')

self.top_k_answers = top_k_answers
self.top_k = top_k

if use_gpu and torch.cuda.is_available():
self.device = torch.device("cuda")
Expand Down Expand Up @@ -211,12 +211,11 @@ def predict(self, query: str, documents: List[Document], top_k: Optional[int] =
if len(documents) == 0:
raise AttributeError("generator need documents to predict the answer")

top_k_answers = top_k if top_k is not None else self.top_k_answers
top_k = top_k if top_k is not None else self.top_k

if top_k_answers > self.num_beams:
top_k_answers = self.num_beams
logger.warning(f'top_k value should not be greater than num_beams, '
f'hence setting it to {top_k_answers}')
if top_k > self.num_beams:
top_k = self.num_beams
logger.warning(f'top_k value should not be greater than num_beams, hence setting it to {top_k}')

# Flatten the documents so easy to reference
flat_docs_dict: Dict[str, Any] = {}
Expand Down Expand Up @@ -258,7 +257,7 @@ def predict(self, query: str, documents: List[Document], top_k: Optional[int] =
context_input_ids=context_input_ids,
context_attention_mask=context_attention_mask,
doc_scores=doc_scores,
num_return_sequences=top_k_answers,
num_return_sequences=top_k,
num_beams=self.num_beams,
max_length=self.max_length,
min_length=self.min_length,
Expand Down
18 changes: 12 additions & 6 deletions haystack/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ def __init__(self, retriever: BaseRetriever):
self.pipeline = Pipeline()
self.pipeline.add_node(component=retriever, name="Retriever", inputs=["Query"])

def run(self, query: str, filters: Optional[Dict] = None, top_k_retriever: int = 10):
def run(self, query: str, filters: Optional[Dict] = None, top_k_retriever: Optional[int] = None):
output = self.pipeline.run(query=query, filters=filters, top_k_retriever=top_k_retriever)
document_dicts = [doc.to_dict() for doc in output["documents"]]
output["documents"] = document_dicts
Expand All @@ -368,7 +368,13 @@ def __init__(self, generator: BaseGenerator, retriever: BaseRetriever):
self.pipeline.add_node(component=retriever, name="Retriever", inputs=["Query"])
self.pipeline.add_node(component=generator, name="Generator", inputs=["Retriever"])

def run(self, query: str, filters: Optional[Dict] = None, top_k_retriever: int = 10, top_k_generator: int = 10):
def run(
self,
query: str,
filters: Optional[Dict] = None,
top_k_retriever: Optional[int] = None,
top_k_generator: Optional[int] = None
):
output = self.pipeline.run(
query=query, filters=filters, top_k_retriever=top_k_retriever, top_k_generator=top_k_generator
)
Expand All @@ -391,9 +397,9 @@ def run(
self,
query: str,
filters: Optional[Dict] = None,
top_k_retriever: int = 10,
generate_single_summary: bool = False,
return_in_answer_format=False
top_k_retriever: Optional[int] = None,
generate_single_summary: Optional[bool] = None,
return_in_answer_format: bool = False,
):
"""
:param query: Your search query
Expand Down Expand Up @@ -441,7 +447,7 @@ def __init__(self, retriever: BaseRetriever):
self.pipeline = Pipeline()
self.pipeline.add_node(component=retriever, name="Retriever", inputs=["Query"])

def run(self, query: str, filters: Optional[Dict] = None, top_k_retriever: int = 10):
def run(self, query: str, filters: Optional[Dict] = None, top_k_retriever: Optional[int] = None):
output = self.pipeline.run(query=query, filters=filters, top_k_retriever=top_k_retriever)
documents = output["documents"]

Expand Down
8 changes: 7 additions & 1 deletion haystack/reader/farm.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def __init__(
use_gpu: bool = True,
no_ans_boost: float = 0.0,
return_no_answer: bool = False,
top_k: int = 10,
top_k_per_candidate: int = 3,
top_k_per_sample: int = 1,
num_processes: Optional[int] = None,
Expand All @@ -71,6 +72,7 @@ def __init__(
If a negative number, there is a lower chance of "no_answer" being predicted.
If a positive number, there is an increased chance of "no_answer"
:param return_no_answer: Whether to include no_answer predictions in the results.
:param top_k: The maximum number of answers to return
:param top_k_per_candidate: How many answers to extract for each candidate doc that is coming from the retriever (might be a long text).
Note that this is not the number of "final answers" you will receive
(see `top_k` in FARMReader.predict() or Finder.get_answers() for that)
Expand All @@ -92,6 +94,7 @@ def __init__(
"""

self.return_no_answers = return_no_answer
self.top_k = top_k
self.top_k_per_candidate = top_k_per_candidate
self.inferencer = QAInferencer.load(model_name_or_path, batch_size=batch_size, gpu=use_gpu,
task_type="question_answering", max_seq_len=max_seq_len,
Expand Down Expand Up @@ -283,6 +286,8 @@ def predict_batch(self, query_doc_list: List[dict], top_k: int = None, batch_siz
:return: List of dictionaries containing query and answers
"""

if top_k is None:
top_k = self.top_k
# convert input to FARM format
inputs = []
number_of_docs = []
Expand Down Expand Up @@ -357,7 +362,8 @@ def predict(self, query: str, documents: List[Document], top_k: Optional[int] =
:param top_k: The maximum number of answers to return
:return: Dict containing query and answers
"""

if top_k is None:
top_k = self.top_k
# convert input to FARM format
inputs = []
for doc in documents:
Expand Down
Loading