haystack/test/test_reader.py
Sara Zan 13510aa753
Refactoring of the haystack package (#1624)
* Files moved, imports all broken

* Fix most imports and docstrings into

* Fix the paths to the modules in the API docs

* Add latest docstring and tutorial changes

* Add a few pipelines that were lost in the inports

* Fix a bunch of mypy warnings

* Add latest docstring and tutorial changes

* Create a file_classifier module

* Add docs for file_classifier

* Fixed most circular imports, now the REST API can start

* Add latest docstring and tutorial changes

* Tackling more mypy issues

* Reintroduce  from FARM and fix last mypy issues hopefully

* Re-enable old-style imports

* Fix some more import from the top-level  package in an attempt to sort out circular imports

* Fix some imports in tests to new-style to prevent failed class equalities from breaking tests

* Change document_store into document_stores

* Update imports in tutorials

* Add latest docstring and tutorial changes

* Probably fixes summarizer tests

* Improve the old-style import allowing module imports (should work)

* Try to fix the docs

* Remove dedicated KnowledgeGraph page from autodocs

* Remove dedicated GraphRetriever page from autodocs

* Fix generate_docstrings.sh with an updated list of yaml files to look for

* Fix some more modules in the docs

* Fix the document stores docs too

* Fix a small issue on Tutorial14

* Add latest docstring and tutorial changes

* Add deprecation warning to old-style imports

* Remove stray folder and import Dict into dense.py

* Change import path for MLFlowLogger

* Add old loggers path to the import path aliases

* Fix debug output of convert_ipynb.py

* Fix circular import on BaseRetriever

* Missed one merge block

* re-run tutorial 5

* Fix imports in tutorial 5

* Re-enable squad_to_dpr CLI from the root package and move get_batches_from_generator into document_stores.base

* Add latest docstring and tutorial changes

* Fix typo in utils __init__

* Fix a few more imports

* Fix benchmarks too

* New-style imports in test_knowledge_graph

* Rollback setup.py

* Rollback squad_to_dpr too

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2021-10-25 15:50:23 +02:00

171 lines
7.3 KiB
Python

import math
import pytest
from haystack.schema import Document, Answer
from haystack.nodes.reader.base import BaseReader
from haystack.nodes.reader.farm import FARMReader
def test_reader_basic(reader):
assert reader is not None
assert isinstance(reader, BaseReader)
def test_output(prediction):
assert prediction is not None
assert prediction["query"] == "Who lives in Berlin?"
assert prediction["answers"][0].answer == "Carla"
assert prediction["answers"][0].offsets_in_context[0].start == 11
assert prediction["answers"][0].offsets_in_context[0].end== 16
assert prediction["answers"][0].score <= 1
assert prediction["answers"][0].score >= 0
assert prediction["answers"][0].context == "My name is Carla and I live in Berlin"
assert len(prediction["answers"]) == 5
@pytest.mark.slow
def test_no_answer_output(no_answer_prediction):
assert no_answer_prediction is not None
assert no_answer_prediction["query"] == "What is the meaning of life?"
assert math.isclose(no_answer_prediction["no_ans_gap"], -13.048564434051514, rel_tol=0.0001)
assert no_answer_prediction["answers"][0].answer == ""
assert no_answer_prediction["answers"][0].offsets_in_context[0].start == 0
assert no_answer_prediction["answers"][0].offsets_in_context[0].end == 0
assert no_answer_prediction["answers"][0].score <= 1
assert no_answer_prediction["answers"][0].score >= 0
assert no_answer_prediction["answers"][0].context == None
assert no_answer_prediction["answers"][0].document_id == None
answers = [x.answer for x in no_answer_prediction["answers"]]
assert answers.count("") == 1
assert len(no_answer_prediction["answers"]) == 5
# TODO Directly compare farm and transformers reader outputs
# TODO checks to see that model is responsive to input arguments e.g. context_window_size - topk
@pytest.mark.slow
def test_prediction_attributes(prediction):
# TODO FARM's prediction also has no_ans_gap
attributes_gold = ["query", "answers"]
for ag in attributes_gold:
assert ag in prediction
@pytest.mark.slow
def test_model_download_options():
# download disabled and model is not cached locally
with pytest.raises(OSError):
impossible_reader = FARMReader("mfeb/albert-xxlarge-v2-squad2", local_files_only=True)
def test_answer_attributes(prediction):
# TODO Transformers answer also has meta key
answer = prediction["answers"][0]
assert type(answer) == Answer
attributes_gold = ['answer', 'score', 'context', 'offsets_in_context', 'offsets_in_document','type']
for ag in attributes_gold:
assert getattr(answer,ag,None) is not None
@pytest.mark.slow
@pytest.mark.parametrize("reader", ["farm"], indirect=True)
@pytest.mark.parametrize("window_size", [10, 15, 20])
def test_context_window_size(reader, test_docs_xs, window_size):
docs = [Document.from_dict(d) if isinstance(d, dict) else d for d in test_docs_xs]
assert isinstance(reader, FARMReader)
old_window_size = reader.inferencer.model.prediction_heads[0].context_window_size
reader.inferencer.model.prediction_heads[0].context_window_size = window_size
prediction = reader.predict(query="Who lives in Berlin?", documents=docs, top_k=5)
for answer in prediction["answers"]:
# If the extracted answer is larger than the context window, the context window is expanded.
# If the extracted answer is odd in length, the resulting context window is one less than context_window_size
# due to rounding (See FARM's QACandidate)
# TODO Currently the behaviour of context_window_size in FARMReader and TransformerReader is different
if len(answer.answer) <= window_size:
assert len(answer.context) in [window_size, window_size - 1]
else:
assert len(answer.answer) == len(answer.context)
reader.inferencer.model.prediction_heads[0].context_window_size = old_window_size
# TODO Need to test transformers reader
# TODO Currently the behaviour of context_window_size in FARMReader and TransformerReader is different
@pytest.mark.parametrize("reader", ["farm"], indirect=True)
@pytest.mark.parametrize("top_k", [2, 5, 10])
def test_top_k(reader, test_docs_xs, top_k):
docs = [Document.from_dict(d) if isinstance(d, dict) else d for d in test_docs_xs]
assert isinstance(reader, FARMReader)
old_top_k_per_candidate = reader.top_k_per_candidate
reader.top_k_per_candidate = 4
reader.inferencer.model.prediction_heads[0].n_best = reader.top_k_per_candidate + 1
try:
old_top_k_per_sample = reader.inferencer.model.prediction_heads[0].n_best_per_sample
reader.inferencer.model.prediction_heads[0].n_best_per_sample = 4
except:
print("WARNING: Could not set `top_k_per_sample` in FARM. Please update FARM version.")
prediction = reader.predict(query="Who lives in Berlin?", documents=docs, top_k=top_k)
assert len(prediction["answers"]) == top_k
reader.top_k_per_candidate = old_top_k_per_candidate
reader.inferencer.model.prediction_heads[0].n_best = reader.top_k_per_candidate + 1
try:
reader.inferencer.model.prediction_heads[0].n_best_per_sample = old_top_k_per_sample
except:
print("WARNING: Could not set `top_k_per_sample` in FARM. Please update FARM version.")
def test_farm_reader_update_params(test_docs_xs):
reader = FARMReader(
model_name_or_path="deepset/roberta-base-squad2",
use_gpu=False,
no_ans_boost=0,
num_processes=0
)
docs = [Document.from_dict(d) if isinstance(d, dict) else d for d in test_docs_xs]
# original reader
prediction = reader.predict(query="Who lives in Berlin?", documents=docs, top_k=3)
assert len(prediction["answers"]) == 3
assert prediction["answers"][0].answer == "Carla"
# update no_ans_boost
reader.update_parameters(
context_window_size=100, no_ans_boost=100, return_no_answer=True, max_seq_len=384, doc_stride=128
)
prediction = reader.predict(query="Who lives in Berlin?", documents=docs, top_k=3)
assert len(prediction["answers"]) == 3
assert prediction["answers"][0].answer == ""
# update no_ans_boost
reader.update_parameters(
context_window_size=100, no_ans_boost=0, return_no_answer=False, max_seq_len=384, doc_stride=128
)
prediction = reader.predict(query="Who lives in Berlin?", documents=docs, top_k=3)
assert len(prediction["answers"]) == 3
assert None not in [ans.answer for ans in prediction["answers"]]
# update context_window_size
reader.update_parameters(context_window_size=6, no_ans_boost=-10, max_seq_len=384, doc_stride=128)
prediction = reader.predict(query="Who lives in Berlin?", documents=docs, top_k=3)
assert len(prediction["answers"]) == 3
assert len(prediction["answers"][0].context) == 6
# update doc_stride with invalid value
with pytest.raises(Exception):
reader.update_parameters(context_window_size=100, no_ans_boost=-10, max_seq_len=384, doc_stride=999)
reader.predict(query="Who lives in Berlin?", documents=docs, top_k=3)
# update max_seq_len with invalid value
with pytest.raises(Exception):
reader.update_parameters(context_window_size=6, no_ans_boost=-10, max_seq_len=99, doc_stride=128)
reader.predict(query="Who lives in Berlin?", documents=docs, top_k=3)