diff --git a/.gitignore b/.gitignore index b4b9aad58..d939fb273 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,9 @@ credentials.toml # test files generated by benchmark experiments **/tests/*.csv **/results/*.csv +**/experiments/mlruns/ +**/experiments/*.zip +**/experiments/*/*.csv # test files generated by pytest test-output.xml diff --git a/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/competitive_analysis.ipynb b/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/competitive_analysis.ipynb index dcfbea3aa..6238110c5 100644 --- a/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/competitive_analysis.ipynb +++ b/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/competitive_analysis.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## TruLens vs RAGAS performance analysis for groundedness\n", + "## TruLens vs RAGAS vs MLFlow performance comparison for groundedness\n", "\n", "In this notebook, we analyze the performance of TruLens current groundedness feedback function and its comparable or equivalent implementations from other evaluation frameworks using the same model for LLM-as-judges. \n", "\n", @@ -14,6 +14,9 @@ "\n", "2. RAGAS `faithfulness`: measures the factual consistency of the generated answer against the given context [source](https://docs.ragas.io/en/stable/concepts/metrics/faithfulness.html)\n", "\n", + "3. MLflow `faithfulness`: Faithfulness will be assessed based on how factually consistent the output is to the context\n", + "[source](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.genai.faithfulness)\n", + "\n", "\n", "\n" ] @@ -24,7 +27,7 @@ "metadata": {}, "outputs": [], "source": [ - "# ! pip install trulens-core trulens-providers-openai ragas" + "# ! pip install trulens-core trulens-providers-openai ragas mlflow" ] }, { @@ -33,14 +36,35 @@ "metadata": {}, "outputs": [], "source": [ - "# os.environ[\"OPENAI_API_KEY\"] = \"sk-...\"" + "import os\n", + "\n", + "from trulens.core.session import TruSession\n", + "\n", + "# os.environ[\"OPENAI_API_KEY\"] = \"sk-...\"\n", + "\n", + "connection_params = {\n", + " \"account\": os.environ.get(\"SNOWFLAKE_ACCOUNT\"),\n", + " \"user\": os.environ.get(\"SNOWFLAKE_USER\"),\n", + " \"password\": os.environ.get(\"SNOWFLAKE_USER_PASSWORD\"),\n", + " \"database\": os.environ.get(\"SNOWFLAKE_DATABASE\"),\n", + " \"schema\": os.environ.get(\"SNOWFLAKE_SCHEMA\"),\n", + " \"warehouse\": os.environ.get(\"SNOWFLAKE_WAREHOUSE\"),\n", + " \"role\": os.environ.get(\"SNOWFLAKE_ROLE\"),\n", + " \"init_server_side\": False, # Set to True to enable server side feedback functions\n", + "}\n", + "\n", + "# connector = SnowflakeConnector(**connection_params)\n", + "# session = TruSession(connector=connector)\n", + "\n", + "session = TruSession()\n", + "session.reset_database()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Prepare public benchmark datasets" + "### Prepare 3 public benchmark datasets: QAGS CNN/Daily Mail, QAGS XSum, and SummEval" ] }, { @@ -73,14 +97,11 @@ " )\n", ")\n", "\n", - "# summeval_subset = summeval.sample(n=200, random_state=42)\n", - "summeval_subset = summeval\n", - "summeval_subset_true_labels = [\n", - " row[\"expected_score\"] for _, row in summeval_subset.iterrows()\n", - "]\n", "\n", - "summeval_subset_true_labels_binary = [\n", - " 1 if label >= 0.5 else 0 for label in summeval_subset_true_labels\n", + "summeval_true_labels = [row[\"expected_score\"] for _, row in summeval.iterrows()]\n", + "\n", + "summeval_true_labels_binary = [\n", + " 1 if label >= 0.5 else 0 for label in summeval_true_labels\n", "]\n", "\n", "qags_cnn_dm_true_labels = [\n", @@ -97,7 +118,25 @@ "\n", "qags_xsum_true_labels_binary = [\n", " 1 if label >= 0.5 else 0 for label in qags_xsum_true_labels\n", - "]" + "]\n", + "combined_dataset = pd.concat(\n", + " [qags_cnn_dm, qags_xsum, summeval], ignore_index=False\n", + ")\n", + "combined_true_labels = (\n", + " qags_cnn_dm_true_labels + qags_xsum_true_labels + summeval_true_labels\n", + ")\n", + "\n", + "assert len(combined_dataset) == len(combined_true_labels)\n", + "print(f\"Total number of samples: {len(combined_dataset)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "combined_dataset" ] }, { @@ -110,17 +149,24 @@ " visualize_expected_score_distribution,\n", ")\n", "\n", - "# making sure the distribution of the expected scores is balanced for the datasets\n", - "visualize_expected_score_distribution(qags_xsum_true_labels)\n", - "\n", - "len(qags_xsum_true_labels)" + "# making sure the distribution of the expected scores is as balanced as possible for the datasets\n", + "visualize_expected_score_distribution(combined_true_labels)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Setup TruLens groundedness experiments" + "## Setup experiments with TruLens `TruBasicApp` recorder" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "session.reset_database()" ] }, { @@ -129,109 +175,211 @@ "metadata": {}, "outputs": [], "source": [ - "import math\n", - "import time\n", - "\n", "from datasets import Dataset\n", - "import numpy as np\n", + "import mlflow\n", + "from mlflow.metrics.genai import answer_relevance as answer_relevance_mlflow\n", + "from mlflow.metrics.genai import faithfulness as faithfulness_mlflow\n", + "from mlflow.metrics.genai import relevance as context_relevance_mlflow\n", + "from ragas import evaluate\n", + "from ragas.cost import get_token_usage_for_openai\n", + "from ragas.llms import llm_factory\n", + "from ragas.metrics import faithfulness as faithfulness_ragas\n", "from trulens.apps.basic import TruBasicApp\n", - "from trulens.benchmark.benchmark_frameworks.experiments.dataset_preprocessing import (\n", - " write_results,\n", - ")\n", + "from trulens.core import Feedback\n", "from trulens.providers.openai import OpenAI\n", "\n", - "gpt_4o_mini = OpenAI(model_engine=\"gpt-4o-mini\")\n", + "OPENAI_LLM_NAME = \"gpt-4o-mini\"\n", + "gpt_4o_mini = OpenAI(model_engine=OPENAI_LLM_NAME)\n", "\n", "\n", - "def trulens_groundedness(input, output) -> float:\n", - " return gpt_4o_mini.groundedness_measure_with_cot_reasons(\n", - " source=input,\n", - " statement=output,\n", - " use_sent_tokenize=True,\n", - " )[0]\n", + "def trulens_groundedness(context: str, response: str, gt_score: float) -> str:\n", + " trulens_groundedness_res = (\n", + " gpt_4o_mini.groundedness_measure_with_cot_reasons(\n", + " source=context, statement=response, use_sent_tokenize=True\n", + " )\n", + " )\n", + " return f\"{trulens_groundedness_res[0]};{gt_score};{trulens_groundedness_res[1]}\"\n", "\n", "\n", - "def trulens_groundedness_binary(input, output) -> float:\n", - " return gpt_4o_mini.groundedness_measure_with_cot_reasons(\n", - " source=input,\n", - " statement=output,\n", - " use_sent_tokenize=True,\n", - " min_score_val=0,\n", - " max_score_val=1,\n", - " criteria=\"A grounded response to the query should get a score of 1, and an ungrounded response should get a score of 0. The score can only be either 0 or 1 (binary).\",\n", - " )[0]\n", + "langchain_llm = llm_factory(model=OPENAI_LLM_NAME)\n", + "faithfulness_ragas.llm = langchain_llm\n", "\n", "\n", - "def run_trulens_experiment(\n", - " feedback_func_wrapper, app_name, app_version, dataset_df, true_labels\n", + "def ragas_faithfulness(context: str, response: str, gt_score: float) -> str:\n", + " data_samples = {\"question\": [], \"answer\": [], \"contexts\": []}\n", + " data_samples[\"question\"].append(\"dummy text\")\n", + " data_samples[\"answer\"].append(response)\n", + " data_samples[\"contexts\"].append([context])\n", + " ragas_dataset = Dataset.from_dict(data_samples)\n", + "\n", + " score_dict = evaluate(\n", + " ragas_dataset,\n", + " metrics=[faithfulness_ragas],\n", + " llm=langchain_llm,\n", + " token_usage_parser=get_token_usage_for_openai,\n", + " )\n", + "\n", + " return f\"{score_dict['faithfulness'][0]};{gt_score}\"\n", + "\n", + "\n", + "# not supplying any example as other metrics do zero-shot evaluation as well\n", + "faithfulness_metric = faithfulness_mlflow(model=f\"openai:/{OPENAI_LLM_NAME}\")\n", + "context_relevance_metric = context_relevance_mlflow(\n", + " model=f\"openai:/{OPENAI_LLM_NAME}\"\n", + ")\n", + "\n", + "answer_relevance_metric = answer_relevance_mlflow(\n", + " model=f\"openai:/{OPENAI_LLM_NAME}\"\n", + ")\n", + "\n", + "\n", + "def mlflow_context_relevance(\n", + " query: str, context: str, response: str, gt_score: float\n", + ") -> str:\n", + " eval_data = pd.DataFrame({\n", + " \"inputs\": [query],\n", + " \"predictions\": [\n", + " response\n", + " ], # note that we are using the response as the prediction\n", + " \"context\": [context],\n", + " })\n", + "\n", + " with mlflow.start_run() as _:\n", + " results = mlflow.evaluate(\n", + " data=eval_data,\n", + " predictions=\"predictions\",\n", + " extra_metrics=[context_relevance_metric],\n", + " evaluators=\"default\",\n", + " )\n", + "\n", + " mlflow_context_relevance_score = results.metrics[\"relevance/v1/mean\"]\n", + "\n", + " mlflow_context_relevance_score_norm = (\n", + " mlflow_context_relevance_score - 1\n", + " ) / 4.0 # normalizing the score to be between 0 and 1\n", + "\n", + " return f\"{mlflow_context_relevance_score_norm};{gt_score}\"\n", + "\n", + "\n", + "def mlflow_answer_relevance(query: str, response: str, gt_score: float) -> str:\n", + " eval_data = pd.DataFrame({\n", + " \"inputs\": [query],\n", + " \"predictions\": [response],\n", + " \"context\": [\n", + " \"dummy text\"\n", + " ], # we are not using the context for answer relevance evaluation\n", + " })\n", + "\n", + " with mlflow.start_run() as _:\n", + " results = mlflow.evaluate(\n", + " data=eval_data,\n", + " predictions=\"predictions\",\n", + " extra_metrics=[answer_relevance_metric],\n", + " evaluators=\"default\",\n", + " )\n", + "\n", + " mlflow_answer_relevance_score = results.metrics[\"answer_relevance/v1/mean\"]\n", + "\n", + " mlflow_answer_relevance_score_norm = (\n", + " mlflow_answer_relevance_score - 1\n", + " ) / 4.0 # normalizing the score to be between 0 and 1\n", + "\n", + " return f\"{mlflow_answer_relevance_score_norm};{gt_score}\"\n", + "\n", + "\n", + "def mlflow_faithfulness(context: str, response: str, gt_score: float) -> str:\n", + " eval_data = pd.DataFrame({\n", + " \"inputs\": [\n", + " \"dummy text\" # we are not using the inputs (user's queries) for faithfulness evaluation\n", + " ],\n", + " \"predictions\": [response],\n", + " \"context\": [context],\n", + " })\n", + "\n", + " with mlflow.start_run() as _:\n", + " results = mlflow.evaluate(\n", + " data=eval_data,\n", + " predictions=\"predictions\",\n", + " extra_metrics=[faithfulness_metric],\n", + " evaluators=\"default\",\n", + " )\n", + "\n", + " mlflow_faithfulness_score = results.metrics[\"faithfulness/v1/mean\"]\n", + "\n", + " mlflow_faithfulness_score_norm = (\n", + " mlflow_faithfulness_score - 1\n", + " ) / 4.0 # normalizing the score to be between 0 and 1\n", + "\n", + " return f\"{mlflow_faithfulness_score_norm};{gt_score}\"\n", + "\n", + "\n", + "def run_experiment_and_record(\n", + " evaluate_func_wrapper, app_name, app_version, dataset_df, true_labels\n", "):\n", " if len(dataset_df) != len(true_labels):\n", " raise ValueError(\"dataset df must have the same length as labels\")\n", + "\n", " tru_wrapped_basic_app = TruBasicApp(\n", - " feedback_func_wrapper, app_name=app_name, app_version=app_version\n", + " evaluate_func_wrapper,\n", + " app_name=app_name,\n", + " app_version=app_version,\n", + " feedbacks=CUSTOM_FEEDBACK_FUNCS,\n", " )\n", "\n", - " generated_scores, labels, latencies = [], [], []\n", " for i in range(len(dataset_df)):\n", " arg_1 = dataset_df.iloc[i][\"query\"]\n", " arg_2 = dataset_df.iloc[i][\"expected_response\"]\n", - " true_score = true_labels[i]\n", + " arg_3 = true_labels[i]\n", + "\n", " try:\n", " with tru_wrapped_basic_app as _:\n", - " start_time = time.time()\n", - " score = tru_wrapped_basic_app.app(arg_1, arg_2)\n", + " tru_wrapped_basic_app.app(arg_1, arg_2, arg_3)\n", "\n", - " if math.isnan(score):\n", - " score = 0 # if there is an NAN, we assume the score is 0\n", - "\n", - " # print(f\"Generated score: {score} | true_score: {true_score} \\n\")\n", " except Exception as e:\n", " print(\n", " f\"Error {e} in run_feedback_experiment row {i} with first arg {arg_1} and second arg {arg_2}\"\n", - " )\n", - " score = 0 # if there is an error, we assume the score is 0\n", - "\n", - " end_time = time.time()\n", - " generated_scores.append(score)\n", - " labels.append(true_score)\n", - " latencies.append(end_time - start_time)\n", - "\n", - " write_results(\n", - " generated_scores,\n", - " labels,\n", - " latencies,\n", - " f\"results/{app_name}_{app_version}_results.csv\",\n", - " )\n", - "\n", - "\n", - "run_trulens_experiment(\n", - " feedback_func_wrapper=trulens_groundedness_binary,\n", - " app_name=\"groundedness-binary-10102024\",\n", - " app_version=\"summeval-subset\",\n", - " dataset_df=summeval_subset,\n", - " true_labels=summeval_subset_true_labels,\n", - ")\n", - "run_trulens_experiment(\n", - " feedback_func_wrapper=trulens_groundedness_binary,\n", - " app_name=\"groundedness-binary-10102024\",\n", - " app_version=\"qags-cnn-dm\",\n", - " dataset_df=qags_cnn_dm,\n", - " true_labels=qags_cnn_dm_true_labels,\n", - ")\n", - "run_trulens_experiment(\n", - " feedback_func_wrapper=trulens_groundedness_binary,\n", - " app_name=\"groundedness-binary-10102024\",\n", - " app_version=\"qags-xsum\",\n", - " dataset_df=qags_xsum,\n", - " true_labels=qags_xsum_true_labels,\n", - ")" + " )" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], + "source": [ + "# EXP_NAME = \"competitive-analysis-10312024\"\n", + "# run_experiment_and_record(\n", + "# evaluate_func_wrapper=trulens_groundedness,\n", + "# app_version=\"trulens-groundedness\",\n", + "# app_name=EXP_NAME,\n", + "# dataset_df=combined_dataset,\n", + "# true_labels=combined_true_labels,\n", + "# )\n", + "\n", + "# run_experiment_and_record(\n", + "# evaluate_func_wrapper=ragas_faithfulness,\n", + "# app_version=\"ragas-faithfulness\",\n", + "# app_name=EXP_NAME,\n", + "# dataset_df=combined_dataset,\n", + "# true_labels=combined_true_labels,\n", + "# )\n", + "\n", + "# run_experiment_and_record(\n", + "# evaluate_func_wrapper=mlflow_faithfulness,\n", + "# app_version=\"mlflow-faithfulness\",\n", + "# app_name=EXP_NAME,\n", + "# dataset_df=combined_dataset,\n", + "# true_labels=combined_true_labels,\n", + "# )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ - "### in all our dataframes (CNN/DM, XSUM, and SummEval), the \"expected_score\" column is the true label for the groundedness score, query corresponds to the context, and expected_response corresponds to the response." + "session.get_leaderboard()" ] }, { @@ -240,14 +388,21 @@ "metadata": {}, "outputs": [], "source": [ - "qags_cnn_dm" + "session.run_dashboard()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Setup RAGAS faithfulness experiments" + "#### Note about column name mapping: in all our dataframes (CNN/DM, XSUM, and SummEval), the \"expected_score\" column is the ground truth (true) label for the groundedness score, query corresponds to the context, and expected_response corresponds to the response." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### MLflow Answer Relevance and Contex Relevance experiments \n" ] }, { @@ -256,60 +411,116 @@ "metadata": {}, "outputs": [], "source": [ - "from ragas import evaluate\n", - "from ragas.cost import get_token_usage_for_openai\n", - "from ragas.llms import llm_factory\n", - "from ragas.metrics import faithfulness\n", + "import random\n", "\n", - "langchain_llm = llm_factory(model=\"gpt-4o-mini\")\n", + "from trulens.benchmark.benchmark_frameworks.dataset.beir_loader import (\n", + " TruBEIRDataLoader,\n", + ")\n", "\n", - "faithfulness.llm = langchain_llm\n", + "random.seed(42)\n", "\n", "\n", - "def ragas_experiment(\n", - " dataset_df,\n", + "def generate_ms_marco_context_relevance_benchmark_for_mlflow(\n", + " file_path: str = \"data/ms_marco_v2_1_val.parquet\",\n", "):\n", - " data_samples = {\"question\": [], \"answer\": [], \"contexts\": []}\n", - " for i, row in dataset_df.iterrows():\n", - " data_samples[\"question\"].append(str(i))\n", - " data_samples[\"answer\"].append(row[\"expected_response\"])\n", - " data_samples[\"contexts\"].append([row[\"query\"]])\n", - "\n", - " ragas_dataset = Dataset.from_dict(data_samples)\n", + " df = pd.read_parquet(file_path, engine=\"pyarrow\") # or engine='fastparquet'\n", "\n", - " score = evaluate(\n", - " ragas_dataset,\n", - " metrics=[faithfulness],\n", - " llm=langchain_llm,\n", - " token_usage_parser=get_token_usage_for_openai,\n", - " )\n", - " avg_cost = (\n", - " score.total_cost(\n", - " cost_per_input_token=0.15 / 1e6, cost_per_output_token=0.6 / 1e6\n", + " for _, row in df.iterrows():\n", + " assert len(row[\"passages\"][\"is_selected\"]) == len(\n", + " row[\"passages\"][\"passage_text\"]\n", " )\n", - " / 200\n", - " )\n", - " print(f\"Average cost per sample: {avg_cost}\")\n", "\n", - " return score\n", + " if sum(row[\"passages\"][\"is_selected\"]) < 1:\n", + " # currently we only consider sample with one passage marked as relevant (there are samples where zero passage_text is selected)\n", + " continue\n", + " for i, passage_text in enumerate(row[\"passages\"][\"passage_text\"]):\n", + " yield {\n", + " \"query_id\": row[\"query_id\"],\n", + " \"query\": row[\"query\"],\n", + " \"expected_response\": row[\"answers\"][0],\n", + " \"expected_context\": passage_text,\n", + " \"expected_score\": row[\"passages\"][\"is_selected\"][\n", + " i\n", + " ], # Binary relevance\n", + " }\n", "\n", "\n", - "ragas_cnn_score = ragas_experiment(qags_cnn_dm)\n", - "qags_cnn_dm_true_labels = [\n", - " row[\"expected_score\"] for _, row in qags_cnn_dm.iterrows()\n", - "]\n", + "ms_marco = list(generate_ms_marco_context_relevance_benchmark_for_mlflow())\n", "\n", - "qags_cnn_dm_true_labels_binary = [\n", - " 1 if label > 0.5 else 0 for label in qags_cnn_dm_true_labels\n", + "\n", + "score_1_entries = [entry for entry in ms_marco if entry[\"expected_score\"] == 1]\n", + "score_0_entries = [entry for entry in ms_marco if entry[\"expected_score\"] == 0]\n", + "\n", + "# Calculate the number of samples needed from each group\n", + "num_samples_per_group = min(\n", + " len(score_1_entries), len(score_0_entries), 150\n", + ") # Sample 150 from each\n", + "\n", + "\n", + "sampled_score_1 = random.sample(score_1_entries, num_samples_per_group)\n", + "sampled_score_0 = random.sample(score_0_entries, num_samples_per_group)\n", + "\n", + "# Combine and shuffle the samples to get a balanced dataset\n", + "balanced_sample = sampled_score_1 + sampled_score_0\n", + "random.shuffle(balanced_sample)\n", + "\n", + "# Ensure the combined length is 300\n", + "assert len(balanced_sample) == 300\n", + "\n", + "# Now you can use `balanced_sample` as your final dataset\n", + "print(\n", + " f\"Number of entries with expected_score = 1: {len([e for e in balanced_sample if e['expected_score'] == 1])}\"\n", + ")\n", + "print(\n", + " f\"Number of entries with expected_score = 0: {len([e for e in balanced_sample if e['expected_score'] == 0])}\"\n", + ")\n", + "\n", + "ms_marco_balanced_sample_300 = pd.DataFrame(balanced_sample)\n", + "\n", + "\n", + "beir_data_loader = TruBEIRDataLoader(data_folder=\"./\", dataset_name=\"hotpotqa\")\n", + "hotpotqa = beir_data_loader.load_dataset_to_df(download=True)\n", + "\n", + "\n", + "hotpotqa_raw_subset = hotpotqa.sample(n=200, random_state=42)\n", + "\n", + "all_responses = [\n", + " (row[\"query\"], row[\"expected_response\"])\n", + " for idx, row in hotpotqa_raw_subset.iterrows()\n", "]\n", - "ragas_xsum_score = ragas_experiment(qags_xsum)\n", - "qags_xsum_true_labels = [\n", - " row[\"expected_score\"] for _, row in qags_xsum.iterrows()\n", + "\n", + "\n", + "hotpotqa_subset_for_answer_relevance = []\n", + "\n", + "for idx, row in hotpotqa_raw_subset.iterrows():\n", + " # Positive examples for answer relevance\n", + " hotpotqa_subset_for_answer_relevance.append({\n", + " \"query\": row[\"query\"],\n", + " \"expected_response\": row[\"expected_response\"], # Positive response\n", + " \"expected_score\": 1, # Positive example, score = 1\n", + " })\n", + "\n", + " # Negative examples for answer relevance (random unrelated response)\n", + " negative_response = random.choice([\n", + " r\n", + " for q, r in all_responses\n", + " if q != row[\"query\"] # Pick response from another query\n", + " ])\n", + "\n", + " hotpotqa_subset_for_answer_relevance.append({\n", + " \"query\": row[\"query\"],\n", + " \"expected_response\": negative_response, # Negative response\n", + " \"expected_score\": 0, # Negative example, score = 0\n", + " })\n", + "\n", + "\n", + "hotpotqa_subset_for_answer_relevance_true_labels = [\n", + " entry[\"expected_score\"] for entry in hotpotqa_subset_for_answer_relevance\n", "]\n", "\n", - "qags_xsum_true_labels_binary = [\n", - " 1 if label > 0.5 else 0 for label in qags_xsum_true_labels\n", - "]" + "hotpotqa_subset_for_answer_relevance = pd.DataFrame(\n", + " hotpotqa_subset_for_answer_relevance\n", + ")" ] }, { @@ -318,14 +529,18 @@ "metadata": {}, "outputs": [], "source": [ - "ragas_cnn_score.to_pandas()" + "ms_marco_balanced_sample_300_true_labels = ms_marco_balanced_sample_300[\n", + " \"expected_score\"\n", + "]" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "### Benchmarking with real-valued output scores (both TruLens' feedback scores and RAGAS scores are normalized to 0.0 to 1.0)" + "hotpotqa_subset_for_answer_relevance" ] }, { @@ -334,16 +549,7 @@ "metadata": {}, "outputs": [], "source": [ - "from trulens.benchmark.benchmark_frameworks.experiments.dataset_preprocessing import (\n", - " read_results,\n", - ")\n", - "\n", - "trulens_cnn_scores, cnn_labels, latencies = read_results(\n", - " \"results/QAGS CNN_DM - gpt-4o-mini_groundedness_likert4_results.csv\"\n", - ")\n", - "trulens_xsum_scores, xsum_labels, latencies = read_results(\n", - " \"results/QAGS XSum - gpt-4o-mini_groundedness_likert4_results.csv\"\n", - ")" + "ms_marco_balanced_sample_300" ] }, { @@ -352,28 +558,15 @@ "metadata": {}, "outputs": [], "source": [ - "cnn_true_scores = np.array(cnn_labels)\n", - "mae_trulens_cnn = np.mean(np.abs(trulens_cnn_scores - cnn_true_scores))\n", - "mae_ragas_cnn = np.mean(\n", - " np.abs(\n", - " ragas_cnn_score.to_pandas()[\"faithfulness\"] - qags_cnn_dm_true_labels\n", - " )\n", - ")\n", + "import os\n", "\n", - "print(\n", - " f\"QAGS CNN/DM: Trulens MAE: {mae_trulens_cnn:.4f}, Ragas MAE: {mae_ragas_cnn:.4f}\"\n", - ")\n", + "from trulens.core.session import TruSession\n", "\n", + "# os.environ[\"OPENAI_API_KEY\"] = \"sk-...\"\n", "\n", - "xsum_true_scores = np.array(xsum_labels)\n", - "mae_trulens_xsum = np.mean(np.abs(trulens_xsum_scores - xsum_true_scores))\n", - "mae_ragas_xsum = np.mean(\n", - " np.abs(ragas_xsum_score.to_pandas()[\"faithfulness\"] - qags_xsum_true_labels)\n", - ")\n", "\n", - "print(\n", - " f\"QAGS XSum: Trulens MAE: {mae_trulens_xsum:.4f}, Ragas MAE: {mae_ragas_xsum:.4f}\"\n", - ")" + "session = TruSession()\n", + "session.reset_database()" ] }, { @@ -382,20 +575,109 @@ "metadata": {}, "outputs": [], "source": [ - "summeval_ragas_data_samples = {\"question\": [], \"answer\": [], \"contexts\": []}\n", - "for i, row in summeval_subset.iterrows():\n", - " summeval_ragas_data_samples[\"question\"].append(str(i))\n", - " summeval_ragas_data_samples[\"answer\"].append(row[\"expected_response\"])\n", - " summeval_ragas_data_samples[\"contexts\"].append([row[\"query\"]])\n", - "\n", - "summeval_ragas_dataset = Dataset.from_dict(summeval_ragas_data_samples)\n", - "\n", - "ragas_summeval_scores = evaluate(\n", - " summeval_ragas_dataset,\n", - " metrics=[faithfulness],\n", - " llm=langchain_llm,\n", - " token_usage_parser=get_token_usage_for_openai,\n", - ")" + "from trulens.core import Provider\n", + "\n", + "THRESHOLD = 0.5 # for passage retrieval annotation, we consider a score of 0.5 or above as relevant\n", + "\n", + "\n", + "class CustomTermFeedback(Provider):\n", + " def true_positive(self, output: str) -> float:\n", + " feedback_score, gt_score = (\n", + " float(output.split(\";\")[0]),\n", + " float(output.split(\";\")[1]),\n", + " )\n", + " binary_score = 1 if feedback_score >= 0.5 else 0\n", + " binary_gt_score = 1 if gt_score >= THRESHOLD else 0\n", + " return 1.0 if binary_score == 1 and binary_gt_score == 1 else 0.0\n", + "\n", + " def true_negative(self, output: str) -> float:\n", + " feedback_score, gt_score = (\n", + " float(output.split(\";\")[0]),\n", + " float(output.split(\";\")[1]),\n", + " )\n", + " binary_score = 1 if feedback_score >= 0.5 else 0\n", + " binary_gt_score = 1 if gt_score >= THRESHOLD else 0\n", + " return 1.0 if binary_score == 0 and binary_gt_score == 0 else 0.0\n", + "\n", + " def false_positive(self, output: str) -> float:\n", + " feedback_score, gt_score = (\n", + " float(output.split(\";\")[0]),\n", + " float(output.split(\";\")[1]),\n", + " )\n", + " binary_score = 1 if feedback_score >= 0.5 else 0\n", + " binary_gt_score = 1 if gt_score >= THRESHOLD else 0\n", + " return 1.0 if binary_score == 1 and binary_gt_score == 0 else 0.0\n", + "\n", + " def false_negative(self, output: str) -> float:\n", + " feedback_score, gt_score = (\n", + " float(output.split(\";\")[0]),\n", + " float(output.split(\";\")[1]),\n", + " )\n", + " binary_score = 1 if feedback_score >= 0.5 else 0\n", + " binary_gt_score = 1 if gt_score >= THRESHOLD else 0\n", + " return 1.0 if binary_score == 0 and binary_gt_score == 1 else 0.0\n", + "\n", + " def term_absolute_error(self, output: str) -> float:\n", + " feedback_score, gt_score = (\n", + " float(output.split(\";\")[0]),\n", + " float(output.split(\";\")[1]),\n", + " )\n", + " return abs(feedback_score - gt_score)\n", + "\n", + " def raw_gt_score(self, output: str) -> float:\n", + " return float(output.split(\";\")[1]) * 3\n", + "\n", + " def raw_feedback_score(self, output: str) -> float:\n", + " return float(output.split(\";\")[0]) * 3\n", + "\n", + "\n", + "custom_term_feedback = CustomTermFeedback()\n", + "\n", + "f_tp = Feedback(\n", + " custom_term_feedback.true_positive,\n", + " name=\"True Positive\",\n", + " higher_is_better=True,\n", + ").on_output()\n", + "f_tn = Feedback(\n", + " custom_term_feedback.true_negative,\n", + " name=\"True Negative\",\n", + " higher_is_better=True,\n", + ").on_output()\n", + "f_fp = Feedback(\n", + " custom_term_feedback.false_positive,\n", + " name=\"False Positive\",\n", + " higher_is_better=False,\n", + ").on_output()\n", + "f_fn = Feedback(\n", + " custom_term_feedback.false_negative,\n", + " name=\"False Negative\",\n", + " higher_is_better=False,\n", + ").on_output()\n", + "f_abs_err = Feedback(\n", + " custom_term_feedback.term_absolute_error,\n", + " name=\"Absolute Error\",\n", + " higher_is_better=False,\n", + ").on_output()\n", + "f_raw_gt_score = Feedback(\n", + " custom_term_feedback.raw_gt_score,\n", + " name=\"Raw GT Score\",\n", + " higher_is_better=True,\n", + ").on_output()\n", + "f_raw_feedback_score = Feedback(\n", + " custom_term_feedback.raw_feedback_score,\n", + " name=\"Raw Feedback Score\",\n", + " higher_is_better=True,\n", + ").on_output()\n", + "\n", + "CUSTOM_FEEDBACK_FUNCS = [\n", + " f_tp,\n", + " f_tn,\n", + " f_fp,\n", + " f_fn,\n", + " f_abs_err,\n", + " f_raw_gt_score,\n", + " f_raw_feedback_score,\n", + "]" ] }, { @@ -404,22 +686,35 @@ "metadata": {}, "outputs": [], "source": [ - "avg_cost = (\n", - " ragas_summeval_scores.total_cost(\n", - " # hard-coded cost per token values for OpenAI gpt-4o-mini\n", - " cost_per_input_token=0.15 / 1e6,\n", - " cost_per_output_token=0.6 / 1e6,\n", - " )\n", - " / 200\n", - ")\n", - "avg_cost" + "# tru_wrapped_answer_relevance_app = TruBasicApp(\n", + "# mlflow_answer_relevance,\n", + "# app_name=\"competitive-analysis-mlflow-11022024\",\n", + "# app_version=\"mlflow-answer-relevance\",\n", + "# feedbacks=CUSTOM_FEEDBACK_FUNCS,\n", + "# )\n", + "\n", + "# for i in range(len(hotpotqa_subset_for_answer_relevance)):\n", + "# arg_1 = hotpotqa_subset_for_answer_relevance.iloc[i][\"query\"]\n", + "# arg_2 = hotpotqa_subset_for_answer_relevance.iloc[i][\"expected_response\"]\n", + "# arg_3 = hotpotqa_subset_for_answer_relevance_true_labels[i]\n", + "\n", + "# try:\n", + "# with tru_wrapped_answer_relevance_app as _:\n", + "# tru_wrapped_answer_relevance_app.app(arg_1, arg_2, arg_3)\n", + "\n", + "# except Exception as e:\n", + "# print(\n", + "# f\"Error {e} in run_feedback_experiment row {i} with first arg {arg_1} and second arg {arg_2}\"\n", + "# )" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "### Benchmarking with binary output scores (both TruLens' feedback scores and RAGAS scores are cast to 0 and 1)" + "ms_marco_balanced_sample_300" ] }, { @@ -428,76 +723,29 @@ "metadata": {}, "outputs": [], "source": [ - "from trulens.benchmark.benchmark_frameworks.experiments.dataset_preprocessing import (\n", - " compute_binary_classification_metrics,\n", - ")\n", - "from trulens.feedback.groundtruth import GroundTruthAggregator\n", - "\n", - "trulens_cnn_dm_scores, trulens_cnn_dm_labels, trulens_cnn_dm_latencies = (\n", - " read_results(\"results/groundedness-binary-10102024_qags-cnn-dm_results.csv\")\n", - ")\n", - "trulens_cnn_dm_scores_binary = [\n", - " 1 if score >= 0.5 else 0 for score in trulens_cnn_dm_scores\n", - "]\n", - "trulens_cnn_dm_labels_binary = [\n", - " 1 if label >= 0.5 else 0 for label in trulens_cnn_dm_labels\n", - "]\n", - "print(len(trulens_cnn_dm_scores_binary), len(trulens_cnn_dm_labels_binary))\n", - "\n", - "spearman_cor = GroundTruthAggregator(\n", - " trulens_cnn_dm_labels\n", - ").spearman_correlation(trulens_cnn_dm_scores)\n", - "\n", - "compute_binary_classification_metrics(\n", - " \"TruLens QAGS CNN/Daily Mail\",\n", - " trulens_cnn_dm_labels_binary,\n", - " trulens_cnn_dm_scores_binary,\n", - " trulens_cnn_dm_latencies,\n", - ")\n", - "print(f\"TruLens QAGS CNN/Daily Mail: {spearman_cor}\")\n", - "\n", - "\n", - "trulens_xsum_scores, xsum_labels, trulens_xsum_latencies = read_results(\n", - " \"results/groundedness-binary-10102024_qags-xsum_results.csv\"\n", - ")\n", - "trulens_xsum_scores_binary = [\n", - " 1 if score >= 0.5 else 0 for score in trulens_xsum_scores\n", - "]\n", - "trulens_xsum_labels_binary = [1 if label >= 0.5 else 0 for label in xsum_labels]\n", - "spearman_cor = GroundTruthAggregator(xsum_labels).spearman_correlation(\n", - " trulens_xsum_scores\n", - ")\n", - "\n", - "print(len(trulens_xsum_scores_binary), len(trulens_xsum_labels_binary))\n", - "\n", - "compute_binary_classification_metrics(\n", - " \"TruLens QAGS XSum\",\n", - " trulens_xsum_labels_binary,\n", - " trulens_xsum_scores_binary,\n", - " trulens_xsum_latencies,\n", - ")\n", - "print(f\"TruLens QAGS XSum: {spearman_cor}\")\n", - "\n", - "trulens_summeval_scores, summeval_labels, trulens_summeval_latencies = (\n", - " read_results(\n", - " \"results/groundedness-binary-10102024_summeval-subset_results.csv\"\n", - " )\n", - ")\n", - "trulens_summeval_binary = [\n", - " 1 if score >= 0.5 else 0 for score in trulens_summeval_scores\n", - "]\n", - "trulens_summeval_labels_binary = [\n", - " 1 if label >= 0.5 else 0 for label in summeval_labels\n", - "]\n", - "print(len(trulens_summeval_binary), len(trulens_summeval_labels_binary))\n", - "spearman_cor = GroundTruthAggregator(summeval_labels).spearman_correlation\n", - "\n", - "compute_binary_classification_metrics(\n", - " \"TruLens SummEval subset\",\n", - " trulens_summeval_labels_binary,\n", - " trulens_summeval_binary,\n", - " trulens_summeval_latencies,\n", - ")" + "# from trulens.apps.basic import TruBasicApp\n", + "\n", + "# tru_wrapped_answer_relevance_app = TruBasicApp(\n", + "# mlflow_context_relevance,\n", + "# app_name=\"competitive-analysis-mlflow-11022024\",\n", + "# app_version=\"mlflow-context-relevance\",\n", + "# feedbacks=CUSTOM_FEEDBACK_FUNCS,\n", + "# )\n", + "\n", + "# for i in range(len(ms_marco_balanced_sample_300)):\n", + "# arg_1 = ms_marco_balanced_sample_300.iloc[i][\"query\"]\n", + "# arg_2 = ms_marco_balanced_sample_300.iloc[i][\"expected_context\"]\n", + "# arg_3 = ms_marco_balanced_sample_300.iloc[i][\"expected_response\"]\n", + "# arg_4 = ms_marco_balanced_sample_300_true_labels[i]\n", + "\n", + "# try:\n", + "# with tru_wrapped_answer_relevance_app as _:\n", + "# tru_wrapped_answer_relevance_app.app(arg_1, arg_2, arg_3, arg_4)\n", + "\n", + "# except Exception as e:\n", + "# print(\n", + "# f\"Error {e} in run_feedback_experiment row {i} with first arg {arg_1} and second arg {arg_2} and third arg {arg_3}\"\n", + "# )" ] }, { @@ -506,47 +754,7 @@ "metadata": {}, "outputs": [], "source": [ - "ragas_cnn_dm_scores_binary = [\n", - " 1 if score > 0.5 else 0\n", - " for score in ragas_cnn_score.to_pandas()[\"faithfulness\"]\n", - "]\n", - "ragas_cnn_dm_labels_binary = [\n", - " 1 if label >= 0.5 else 0 for label in qags_cnn_dm_true_labels\n", - "]\n", - "print(len(ragas_cnn_dm_scores_binary), len(ragas_cnn_dm_labels_binary))\n", - "compute_binary_classification_metrics(\n", - " \"Ragas QAGS CNN/DM\",\n", - " ragas_cnn_dm_labels_binary,\n", - " ragas_cnn_dm_scores_binary,\n", - " [],\n", - ")\n", - "\n", - "ragas_xsum_scores_binary = [\n", - " 1 if score > 0.5 else 0\n", - " for score in ragas_xsum_score.to_pandas()[\"faithfulness\"]\n", - "]\n", - "ragas_xsum_labels_binary = [\n", - " 1 if label >= 0.5 else 0 for label in qags_xsum_true_labels\n", - "]\n", - "print(len(ragas_xsum_scores_binary), len(ragas_xsum_labels_binary))\n", - "compute_binary_classification_metrics(\n", - " \"Ragas QAGS XSum\", ragas_xsum_labels_binary, ragas_xsum_scores_binary, []\n", - ")\n", - "\n", - "ragas_summeval_scores_binary = [\n", - " 1 if score > 0.5 else 0\n", - " for score in ragas_summeval_scores.to_pandas()[\"faithfulness\"]\n", - "]\n", - "ragas_summeval_labels_binary = [\n", - " 1 if label >= 0.5 else 0 for label in summeval_subset_true_labels\n", - "]\n", - "print(len(ragas_summeval_scores_binary), len(ragas_summeval_labels_binary))\n", - "compute_binary_classification_metrics(\n", - " \"Ragas SummEval subset\",\n", - " ragas_summeval_labels_binary,\n", - " ragas_summeval_scores_binary,\n", - " [],\n", - ")" + "session.get_leaderboard()" ] } ], diff --git a/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/context_relevance/trec_dl_passage_relevance_judges.ipynb b/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/context_relevance/trec_dl_passage_relevance_judges.ipynb new file mode 100644 index 000000000..83369e58d --- /dev/null +++ b/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/context_relevance/trec_dl_passage_relevance_judges.ipynb @@ -0,0 +1,1011 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Evaluating context relevance on TREC DL track (2021, 2022, ...) with NIST human annotations on passage retrieval rankings.\n", + "\n", + "Note: passage level `qrels` annotations are not available at the time of writing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import ir_datasets\n", + "\n", + "trec_dl_2021 = ir_datasets.load(\n", + " \"msmarco-passage-v2/trec-dl-2021/judged\"\n", + ") # 53 queries\n", + "qrels_2021 = trec_dl_2021.qrels_dict()\n", + "\n", + "trec_dl_2022 = ir_datasets.load(\n", + " \"msmarco-passage-v2/trec-dl-2022/judged\"\n", + ") # 76 queries\n", + "qrels_2022 = trec_dl_2022.qrels_dict()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from trulens.feedback.v2.feedback import ContextRelevance\n", + "\n", + "current_criteria = \"\"\"\n", + "- CONTEXT that is IRRELEVANT to the QUESTION should score 0.\n", + "- CONTEXT that is RELEVANT to some of the QUESTION should get an intermediate score.\n", + "- CONTEXT that is RELEVANT to most of the QUESTION should get a score closer to 3.\n", + "- CONTEXT that is RELEVANT to the entirety of the QUESTION should get a score of 3, which is the full mark.\n", + "- CONTEXT must be relevant and helpful for answering the entire QUESTION to get a score of 3.\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Human annotation quality ananlysis and check the agreement with generated scores from `scoreddocs`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import ir_datasets\n", + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "\n", + "\n", + "def scoreddocs_qrels_confusion_matrix(\n", + " dataset_path=\"msmarco-passage-v2/trec-dl-2022/judged\",\n", + " aggregate=False,\n", + " normalize=False,\n", + "):\n", + " # Load the dataset\n", + " dataset = ir_datasets.load(dataset_path)\n", + " qrels = dataset.qrels_dict()\n", + " scoreddocs = list(dataset.scoreddocs_iter())\n", + "\n", + " # Prepare a DataFrame for analysis\n", + " data = []\n", + " for scored_doc in scoreddocs:\n", + " query_id = scored_doc.query_id\n", + " doc_id = scored_doc.doc_id\n", + " score = scored_doc.score\n", + " qrel_score = qrels.get(query_id, {}).get(doc_id, None)\n", + " if qrel_score is not None:\n", + " data.append({\n", + " \"query_id\": query_id,\n", + " \"doc_id\": doc_id,\n", + " \"score\": score,\n", + " \"qrel_score\": qrel_score,\n", + " })\n", + "\n", + " df = pd.DataFrame(data)\n", + "\n", + " # Analyze per query or aggregate\n", + " all_data = []\n", + " confusion_matrices = {}\n", + " for query_id, group in df.groupby(\"query_id\"):\n", + " min_score = group[\"score\"].min()\n", + " max_score = group[\"score\"].max()\n", + " interval_size = (max_score - min_score) / 4\n", + " intervals = [\n", + " min_score + i * interval_size for i in range(5)\n", + " ] # 4 intervals\n", + "\n", + " # Assign each passage to an interval\n", + " group[\"interval\"] = pd.cut(\n", + " group[\"score\"],\n", + " bins=intervals,\n", + " include_lowest=True,\n", + " labels=[0, 1, 2, 3],\n", + " )\n", + "\n", + " if aggregate:\n", + " # Append all data for aggregation\n", + " all_data.append(group)\n", + " else:\n", + " # Create confusion matrix for each query\n", + " confusion_matrix = pd.crosstab(\n", + " group[\"qrel_score\"], group[\"interval\"]\n", + " )\n", + "\n", + " # Normalize across rows (qrels scores)\n", + " if normalize:\n", + " confusion_matrix = confusion_matrix.div(\n", + " confusion_matrix.sum(axis=1), axis=0\n", + " )\n", + "\n", + " confusion_matrices[query_id] = confusion_matrix\n", + "\n", + " # Visualize the confusion matrix\n", + " plt.figure(figsize=(8, 6))\n", + " sns.heatmap(\n", + " confusion_matrix, annot=True, fmt=\".2f\", cmap=\"Blues\", cbar=True\n", + " )\n", + " plt.title(f\"Confusion Matrix for Query {query_id}\")\n", + " plt.xlabel(\"Scoreddocs Intervals\")\n", + " plt.ylabel(\"Qrels Scores\")\n", + " plt.show()\n", + "\n", + " if aggregate:\n", + " # Combine all groups into a single DataFrame\n", + " aggregated_df = pd.concat(all_data, ignore_index=True)\n", + "\n", + " # Create an aggregate confusion matrix\n", + " aggregate_confusion_matrix = pd.crosstab(\n", + " aggregated_df[\"qrel_score\"], aggregated_df[\"interval\"]\n", + " )\n", + "\n", + " # Normalize across rows (qrels scores)\n", + " if normalize:\n", + " aggregate_confusion_matrix = aggregate_confusion_matrix.div(\n", + " aggregate_confusion_matrix.sum(axis=1), axis=0\n", + " )\n", + "\n", + " # Visualize the aggregate confusion matrix\n", + " plt.figure(figsize=(10, 8))\n", + " sns.heatmap(\n", + " aggregate_confusion_matrix,\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"Blues\",\n", + " cbar=True,\n", + " )\n", + " plt.title(\"Aggregate Confusion Matrix Across All Queries\")\n", + " plt.xlabel(\"Scoreddocs Intervals\")\n", + " plt.ylabel(\"Qrels Scores\")\n", + " plt.show()\n", + "\n", + " return aggregate_confusion_matrix\n", + "\n", + " return confusion_matrices\n", + "\n", + "\n", + "# Run the analysis for individual queries\n", + "# confusion_matrices = scoreddocs_qrels_confusion_matrix(aggregate=False)\n", + "\n", + "# Run the analysis for aggregate across all queries\n", + "aggregate_confusion_matrix = scoreddocs_qrels_confusion_matrix(aggregate=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Analysis: scoreddocs scores vs qrels annotations\n", + "\n", + "The motivation is that we oberseve dubious annotations in `qrels` in both TREC DL 2021 and 2022, and we are curious if the scoreddocs submitted by participants of " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from trulens.benchmark.benchmark_frameworks.experiments.dataset_preprocessing import (\n", + " generate_trec_dl_passage_benchmark,\n", + ")\n", + "\n", + "trec_2021_samples = list(\n", + " generate_trec_dl_passage_benchmark(\n", + " max_samples_per_query_per_score=4,\n", + " dataset_path=\"msmarco-passage-v2/trec-dl-2021/judged\",\n", + " )\n", + ")\n", + "trec_2022_samples = list(\n", + " generate_trec_dl_passage_benchmark(\n", + " max_samples_per_query_per_score=4,\n", + " dataset_path=\"msmarco-passage-v2/trec-dl-2022/judged\",\n", + " )\n", + ")\n", + "trec_combined = trec_2021_samples + trec_2022_samples\n", + "\n", + "\n", + "trec_combined_df = pd.DataFrame(trec_combined)\n", + "\n", + "print(f\"Totoal number of samples: {len(trec_combined_df)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(len(qrels_2021), len(qrels_2022))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from trulens.benchmark.benchmark_frameworks.experiments.dataset_preprocessing import (\n", + " visualize_expected_score_distribution,\n", + ")\n", + "\n", + "trec_combined_relevance_scores = [\n", + " entry[\"expected_score\"] * 3 for _, entry in trec_combined_df.iterrows()\n", + "]\n", + "visualize_expected_score_distribution(trec_combined_relevance_scores)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "trec_combined_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "from trulens.core.session import TruSession\n", + "from trulens.providers.openai import OpenAI\n", + "\n", + "# os.environ[\"OPENAI_API_KEY\"] = \"sk-...\"\n", + "\n", + "connection_params = {\n", + " \"account\": os.environ.get(\"SNOWFLAKE_ACCOUNT\"),\n", + " \"user\": os.environ.get(\"SNOWFLAKE_USER\"),\n", + " \"password\": os.environ.get(\"SNOWFLAKE_USER_PASSWORD\"),\n", + " \"database\": os.environ.get(\"SNOWFLAKE_DATABASE\"),\n", + " \"schema\": os.environ.get(\"SNOWFLAKE_SCHEMA\"),\n", + " \"warehouse\": os.environ.get(\"SNOWFLAKE_WAREHOUSE\"),\n", + " \"role\": os.environ.get(\"SNOWFLAKE_ROLE\"),\n", + " \"init_server_side\": False, # Set to True to enable server side feedback functions\n", + "}\n", + "\n", + "# connector = SnowflakeConnector(**connection_params)\n", + "# session = TruSession(connector=connector)\n", + "\n", + "session = TruSession()\n", + "session.reset_database()\n", + "\n", + "\n", + "# snowpark_session = Session.builder.configs(connection_params).create()\n", + "\n", + "gpt_4o = OpenAI(model_engine=\"gpt-4o\")\n", + "gpt_4o_mini = OpenAI(model_engine=\"gpt-4o-mini\")\n", + "# llama3_405b = Cortex(snowflake.connector.connect(**connection_params), model_engine=\"llama3.1-405b\")\n", + "# mistral_large = Cortex(snowflake.connector.connect(**connection_params), model_engine=\"mistral-large\")\n", + "# llama3_1_8b = Cortex(snowflake.connector.connect(**connection_params), model_engine=\"llama3.1-8b\")\n", + "\n", + "\n", + "PROVIDERS = [\n", + " gpt_4o,\n", + " gpt_4o_mini,\n", + "]\n", + "\n", + "\n", + "# criteria without explicit rubrics\n", + "current_criteria = \"\"\"\n", + "- CONTEXT that is IRRELEVANT to the QUESTION should score 0.\n", + "- CONTEXT that is RELEVANT to some of the QUESTION should get an intermediate score.\n", + "- CONTEXT that is RELEVANT to most of the QUESTION should get a score closer to 3.\n", + "- CONTEXT that is RELEVANT to the entirety of the QUESTION should get a score of 3, which is the full mark.\n", + "- CONTEXT must be relevant and helpful for answering the entire QUESTION to get a score of 3.\n", + "\"\"\"\n", + "\n", + "\n", + "def trulens_context_relevance(\n", + " provider, query: str, context: str, gt_score: float\n", + ") -> str:\n", + " trulens_context_relevance_res = provider.context_relevance_with_cot_reasons(\n", + " question=query, context=context\n", + " )\n", + " return f\"{trulens_context_relevance_res[0]};{gt_score};{trulens_context_relevance_res[1]}\"\n", + "\n", + "\n", + "def trulens_context_relevance_no_rubric(\n", + " provider, query: str, context: str, gt_score: float\n", + ") -> str:\n", + " trulens_context_relevance_res = provider.context_relevance_with_cot_reasons(\n", + " question=query, context=context, criteria=current_criteria\n", + " )\n", + " return f\"{trulens_context_relevance_res[0]};{gt_score};{trulens_context_relevance_res[1]}\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ContextRelevance.criteria" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from trulens.apps.basic import TruBasicApp\n", + "from trulens.core import Feedback\n", + "from trulens.core import Provider\n", + "\n", + "THRESHOLD = 0.5 # for passage retrieval annotation, we consider a score of 0.5 or above as relevant\n", + "\n", + "\n", + "class CustomTermFeedback(Provider):\n", + " def true_positive(self, output: str) -> float:\n", + " feedback_score, gt_score = (\n", + " float(output.split(\";\")[0]),\n", + " float(output.split(\";\")[1]),\n", + " )\n", + " binary_score = 1 if feedback_score >= 0.5 else 0\n", + " binary_gt_score = 1 if gt_score >= THRESHOLD else 0\n", + " return 1.0 if binary_score == 1 and binary_gt_score == 1 else 0.0\n", + "\n", + " def true_negative(self, output: str) -> float:\n", + " feedback_score, gt_score = (\n", + " float(output.split(\";\")[0]),\n", + " float(output.split(\";\")[1]),\n", + " )\n", + " binary_score = 1 if feedback_score >= 0.5 else 0\n", + " binary_gt_score = 1 if gt_score >= THRESHOLD else 0\n", + " return 1.0 if binary_score == 0 and binary_gt_score == 0 else 0.0\n", + "\n", + " def false_positive(self, output: str) -> float:\n", + " feedback_score, gt_score = (\n", + " float(output.split(\";\")[0]),\n", + " float(output.split(\";\")[1]),\n", + " )\n", + " binary_score = 1 if feedback_score >= 0.5 else 0\n", + " binary_gt_score = 1 if gt_score >= THRESHOLD else 0\n", + " return 1.0 if binary_score == 1 and binary_gt_score == 0 else 0.0\n", + "\n", + " def false_negative(self, output: str) -> float:\n", + " feedback_score, gt_score = (\n", + " float(output.split(\";\")[0]),\n", + " float(output.split(\";\")[1]),\n", + " )\n", + " binary_score = 1 if feedback_score >= 0.5 else 0\n", + " binary_gt_score = 1 if gt_score >= THRESHOLD else 0\n", + " return 1.0 if binary_score == 0 and binary_gt_score == 1 else 0.0\n", + "\n", + " def term_absolute_error(self, output: str) -> float:\n", + " feedback_score, gt_score = (\n", + " float(output.split(\";\")[0]),\n", + " float(output.split(\";\")[1]),\n", + " )\n", + " return abs(feedback_score - gt_score)\n", + "\n", + " def raw_gt_score(self, output: str) -> float:\n", + " return float(output.split(\";\")[1]) * 3\n", + "\n", + " def raw_feedback_score(self, output: str) -> float:\n", + " return float(output.split(\";\")[0]) * 3\n", + "\n", + "\n", + "custom_term_feedback = CustomTermFeedback()\n", + "\n", + "f_tp = Feedback(\n", + " custom_term_feedback.true_positive,\n", + " name=\"True Positive\",\n", + " higher_is_better=True,\n", + ").on_output()\n", + "f_tn = Feedback(\n", + " custom_term_feedback.true_negative,\n", + " name=\"True Negative\",\n", + " higher_is_better=True,\n", + ").on_output()\n", + "f_fp = Feedback(\n", + " custom_term_feedback.false_positive,\n", + " name=\"False Positive\",\n", + " higher_is_better=False,\n", + ").on_output()\n", + "f_fn = Feedback(\n", + " custom_term_feedback.false_negative,\n", + " name=\"False Negative\",\n", + " higher_is_better=False,\n", + ").on_output()\n", + "f_abs_err = Feedback(\n", + " custom_term_feedback.term_absolute_error,\n", + " name=\"Absolute Error\",\n", + " higher_is_better=False,\n", + ").on_output()\n", + "f_raw_gt_score = Feedback(\n", + " custom_term_feedback.raw_gt_score,\n", + " name=\"Raw GT Score\",\n", + " higher_is_better=True,\n", + ").on_output()\n", + "f_raw_feedback_score = Feedback(\n", + " custom_term_feedback.raw_feedback_score,\n", + " name=\"Raw Feedback Score\",\n", + " higher_is_better=True,\n", + ").on_output()\n", + "\n", + "CUSTOM_FEEDBACK_FUNCS = [\n", + " f_tp,\n", + " f_tn,\n", + " f_fp,\n", + " f_fn,\n", + " f_abs_err,\n", + " f_raw_gt_score,\n", + " f_raw_feedback_score,\n", + "]\n", + "\n", + "\n", + "def run_experiment_for_provider(provider, func_wrapper, dataset_df, app_name):\n", + " tru_wrapped_app = TruBasicApp(\n", + " func_wrapper,\n", + " app_name=app_name,\n", + " app_version=f\"{provider.model_engine}-context-relevance\",\n", + " feedbacks=CUSTOM_FEEDBACK_FUNCS,\n", + " )\n", + "\n", + " for i, row in dataset_df.iterrows():\n", + " arg_1 = row[\"query\"]\n", + " arg_2 = row[\"expected_response\"]\n", + " arg_3 = row[\"expected_score\"]\n", + "\n", + " try:\n", + " with tru_wrapped_app as _:\n", + " tru_wrapped_app.app(provider, arg_1, arg_2, arg_3)\n", + "\n", + " except Exception as e:\n", + " print(\n", + " f\"Error {e} in run_feedback_experiment row {i} with first arg {arg_1} and second arg {arg_2}\"\n", + " )\n", + "\n", + "\n", + "# with concurrent.futures.ThreadPoolExecutor() as executor:\n", + "# futures = [executor.submit(run_experiment_for_provider, provider, trec_doc_2022) for provider in PROVIDERS]\n", + "# concurrent.futures.wait(futures)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Run experiments" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for provider in PROVIDERS:\n", + " print(f\"Running provider: {provider.model_engine}\")\n", + " run_experiment_for_provider(\n", + " provider,\n", + " trulens_context_relevance,\n", + " trec_combined_df,\n", + " \"trec_dl_2021_2022_combined\",\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Evaluate Gaurav's prompt, UMBRELA prompt, and zero-shot categorical prompt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "internal_prompt = \"\"\"\n", + "You are an expert search result rater. You are given a user query and a search result. Your task is to rate the search result based on its relevance to the user query. You should rate the search result on a scale of 0 to 3, where:\n", + " 0: The search result has no relevance to the user query.\n", + " 1: The search result has low relevance to the user query. In this case the search result may contain some information which seems very slightly related to the user query but not enough information to answer the user query. The search result contains some references or very limited information about some entities present in the user query. In case the query is a statement on a topic, the search result should be tangentially related to it.\n", + " 2: The search result has medium relevance to the user query. If the user query is a question, the search result may contain some information that is relevant to the user query but not enough information to answer the user query. If the user query is a search phrase/sentence, either the search result is centered around about most but not all entities present in the user query, or if all the entities are present in the result, the search result while not being centered around it has medium level of relevance. In case the query is a statement on a topic, the search result should be related to the topic.\n", + " 3: The search result has high relevance to the user query. If the user query is a question, the search result contains information that can answer the user query. Otherwise if the search query is a search phrase/sentence, it provides relevant information about all entities that are present in the user query and the search result is centered around the entities mentioned in the query. In case the query is a statement on a topic, the search result should be either be directly addressing it or be on the same topic.\n", + " \n", + " You should think step by step about the user query and the search result and rate the search result. You should also provide a reasoning for your rating.\n", + " \n", + " Use the following format:\n", + " Rating: Example Rating\n", + " Reasoning: Example Reasoning\n", + " \n", + " ### Examples\n", + " Example:\n", + " Example 1:\n", + " INPUT:\n", + " User Query: What is the definition of an accordion?\n", + " Search Result: Accordion definition, Also called piano accordion. a portable wind instrument having a large bellows for forcing air through small metal reeds, a keyboard for the right hand, and buttons for sounding single bass notes or chords for the left hand. a similar instrument having single-note buttons instead of a keyboard.\n", + " OUTPUT:\n", + " Rating: 3\n", + " Reasoning: In this case the search query is a question. The search result directly answers the user question for the definition of an accordion, hence it has high relevance to the user query.\n", + " \n", + " Example 2:\n", + " INPUT:\n", + " User Query: dark horse\n", + " Search Result: Darkhorse is a person who everyone expects to be last in a race. Think of it this way. The person who looks like he can never get laid defies the odds and gets any girl he can by being sly,shy and cunning. Although he\\'s not a player, he can really charm the ladies.\n", + " OUTPUT:\n", + " Rating: 3\n", + " Reasoning: In this case the search query is a search phrase mentioning \\'dark horse\\'. The search result contains information about the term \\'dark horse\\' and provides a definition for it and is centered around it. Hence it has high relevance to the user query.\n", + " \n", + " Example 3:\n", + " INPUT:\n", + " User Query: Global warming and polar bears\n", + " Search Result: Polar bear The polar bear is a carnivorous bear whose native range lies largely within the Arctic Circle, encompassing the Arctic Ocean, its surrounding seas and surrounding land masses. It is a large bear, approximately the same size as the omnivorous Kodiak bear (Ursus arctos middendorffi).\n", + " OUTPUT:\n", + " Rating: 2\n", + " Reasoning: In this case the search query is a search phrase mentioning two entities \\'Global warming\\' and \\'polar bears\\'. The search result contains is centered around the polar bear which is one of the two entities in the search query. Therefore it addresses most of the entities present and hence has medium relevance. \n", + " \n", + " Example 4:\n", + " INPUT:\n", + " User Query: Snowflake synapse private link\n", + " Search Result: \"This site can\\'t be reached\" error when connecting to Snowflake via Private Connectivity\\nThis KB article addresses an issue that prevents connections to Snowflake failing with: \"This site can\\'t be reached\" ISSUE: Attempting to reach Snowflake via Private Connectivity fails with the \"This site can\\'t be reached\" error\n", + " OUTPUT:\n", + " Rating: 1\n", + " Reasoning: In this case the search result is a search query mentioning \\'Snowflake synapse private link\\'. However the search result doesn\\'t contain information about it. However it shows an error message for a generic private link which is tangentially related to the query, since snowflake synapse private link is a type of private link. Hence it has low relevance to the user query.\n", + " \n", + " Example 5:\n", + " INPUT:\n", + " User Query: The Punisher is American.\n", + " Search Result: The Rev(Samuel Smith) is a fictional character, a supervillain appearing in American comic books published by Marvel Comics. Created by Mike Baron and Klaus Janson, the character made his first appearance in The Punisher Vol. 2, #4 (November 1987). He is an enemy of the Punisher.\n", + " OUTPUT:\n", + " Rating: 1\n", + " Reasoning: In this case the search query is a statement concerning the Punisher. However the search result is about a character called Rev, who is an enemy of the Punisher. The search result is tangentially related to the user query but does not address topic about Punisher being an American. Hence it has low relevance to the user query.\n", + "\n", + " Example 6:\n", + " INPUT:\n", + " User Query: query_history\n", + " Search Result: The function task_history() is not enough for the purposes when the required result set is more than 10k.If we perform UNION between information_schema and account_usage , then we will get more than 10k records along with recent records as from information_schema.query_history to snowflake.account_usage.query_history is 45 mins behind.\n", + " OUTPUT:\n", + " Rating: 1\n", + " Reasoning: In this case the search query mentioning one entity \\'query_history\\'. The search result is neither centered around it and neither has medium relevance, it only contains an unimportant reference to it. Hence it has low relevance to the user query.\n", + " \n", + " Example 7:\n", + " INPUT:\n", + " User Query: Who directed pulp fiction?\n", + " Search Result: Life on Earth first appeared as early as 4.28 billion years ago, soon after ocean formation 4.41 billion years ago, and not long after the formation of the Earth 4.54 billion years ago.\n", + " OUTPUT:\n", + " Rating: 0\n", + " Reasoning: In the case the search query is a question. However the search result does is completely unrelated to it. Hence the search result is completely irrelevant to the movie pulp fiction. \n", + " ###\n", + " \n", + " Now given the user query and search result below, rate the search result based on its relevance to the user query and provide a reasoning for your rating.\n", + " \n", + "\n", + "\"\"\"\n", + "\n", + "\n", + "umbrela_prompt = \"\"\"\n", + "Given a query and a passage, you must provide a score on an\n", + "integer scale of 0 to 3 with the following meanings:\n", + "0 = represent that the passage has nothing to do with the query,\n", + "1 = represents that the passage seems related to the query but\n", + "does not answer it,\n", + "2 = represents that the passage has some answer for the query,\n", + "but the answer may be a bit unclear, or hidden amongst extraneous\n", + "information and\n", + "3 = represents that the passage is dedicated to the query and\n", + "contains the exact answer.\n", + "Important Instruction: Assign category 1 if the passage is\n", + "somewhat related to the topic but not completely, category 2 if\n", + "passage presents something very important related to the entire\n", + "topic but also has some extra information and category 3 if the\n", + "passage only and entirely refers to the topic. If none of the\n", + "above satisfies give it category 0.\n", + "Query: {query}\n", + "Passage: {passage}\n", + "Split this problem into steps:\n", + "Consider the underlying intent of the search.\n", + "Measure how well the content matches a likely intent of the query\n", + "(M).\n", + "Measure how trustworthy the passage is (T).\n", + "Consider the aspects above and the relative importance of each,\n", + "and decide on a final score (O). Final score must be an integer\n", + "value only.\n", + "Do not provide any code in result. Provide each score in the\n", + "format of: ##final score: score without providing any reasoning.\n", + "Always provide an output of the final category score described above (the final score\n", + "on a scale of 0 to 3).\n", + "\n", + "\"\"\"\n", + "\n", + "\n", + "zero_shot_categorical_prompt = \"\"\"\n", + "Given a query and a passage, you just categorize the passage based on how well it answers the query. The categories that can be assigned are the following:\n", + "\n", + "IRRELEVANT -- if a passage is categorized as irrelevant to a query, this means that the passage has nothing to do with the query.\n", + "FAIR -- if a passage is categorized as fair to a query, this means that the passage has low relevance to the query. The passage contains some information which seems very slightly related to the query but not enough information to answer the query. The passage contains some references or very limited information about some entities present in the query. In case the query is a statement on a topic, the passage should be tangentially related to it.\n", + "GOOD -- if a passage is categorized as good to a query, this means that the passage has medium relevance to the query. If the query is a question, the passage may contain some information that is relevant to the query but not enough information to answer the query. If the query is a phrase/sentence, either the result is centered around most but not all entities present in the query, or if all the entities are present in the passage, the passage, while not being centered around it, has a medium level of relevance. In case the query is a statement on a topic, the passage should be related to the topic.\n", + "EXCELLENT -- if a passage is categorized as excellent to a query, this means that the passage has a high relevance to the query. If the query is a question, the passage should contain information that can answer the query. Otherwise if the query is a phrase/sentence, it provides relevant information about all entities that are present in the query and the passage is centered around the entities mentioned in the query. In case the query is a statement on a topic, the passage should be either directly addressing it or be on the same topic.\n", + "\n", + "You should think step by step about the query and the passage and provide a categorization. You should also provide a reasoning for your categorization. If you absolutely cannot figure out a categorization, assign IRRELEVANT.\n", + "\n", + "\n", + "Query: {query}\n", + "Passage: {passage}\n", + "\n", + "Provide the output in the format of: ##Categorization: \n", + "Always provide an output of the final categoriy described above.\n", + "\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from trulens.feedback.v2.feedback import ContextRelevance\n", + "\n", + "trulens_prompt = (\n", + " ContextRelevance.system_prompt + \"\\n\\n\" + ContextRelevance.user_prompt\n", + ")\n", + "print(f\"TruLens prompt: \\n\\n {trulens_prompt}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from openai import OpenAI\n", + "\n", + "client = OpenAI()\n", + "\n", + "\n", + "# Function to rate context relevance\n", + "def internal_prompt_relevance(\n", + " query: str, passage: str, model_engine=\"gpt-4o\"\n", + ") -> dict:\n", + " # Prepare the prompt\n", + " response = client.chat.completions.create(\n", + " model=model_engine,\n", + " messages=[\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": internal_prompt,\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": f\"\"\" INPUT:\n", + " User Query: {query}\n", + " Search Result: {passage}\n", + " OUTPUT:\\n\"\"\",\n", + " },\n", + " ],\n", + " )\n", + "\n", + " # Parse the response\n", + " output = response.choices[0].message.content.strip()\n", + "\n", + " # Extract the rating and reasoning from the output\n", + " rating = None\n", + " reasoning = None\n", + " try:\n", + " for line in output.split(\"\\n\"):\n", + " if line.startswith(\"Rating:\"):\n", + " rating = int(line.split(\":\")[1].strip())\n", + " elif line.startswith(\"Reasoning:\"):\n", + " reasoning = line.split(\":\")[1].strip()\n", + " except Exception as e:\n", + " print(f\"Error parsing response: {e}\")\n", + "\n", + " return {\"rating\": rating, \"reasoning\": reasoning, \"raw_response\": output}\n", + "\n", + "\n", + "def umbrela_prompt_relevance(\n", + " query: str, passage: str, model_engine=\"gpt-4o\"\n", + ") -> dict:\n", + " # Prepare the prompt\n", + " response = client.chat.completions.create(\n", + " model=model_engine,\n", + " messages=[\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": umbrela_prompt.format(query=query, passage=passage),\n", + " },\n", + " ],\n", + " )\n", + "\n", + " # Parse the response\n", + " output = response.choices[0].message.content.strip()\n", + "\n", + " # Extract the rating and reasoning from the output\n", + " rating = None\n", + " reasoning = None\n", + " try:\n", + " for line in output.split(\"\\n\"):\n", + " if line.startswith(\"##final score:\"):\n", + " rating = int(line.split(\":\")[1].strip())\n", + " elif line.startswith(\"Final score:\"):\n", + " rating = int(line.split(\":\")[1].strip())\n", + " except Exception as e:\n", + " print(f\"Error parsing response: {e}\")\n", + "\n", + " return {\"rating\": rating, \"reasoning\": reasoning, \"raw_response\": output}\n", + "\n", + "\n", + "def categorical_prompt_relevance(\n", + " query: str, passage: str, model_engine=\"gpt-4o\"\n", + ") -> dict:\n", + " # Prepare the prompt\n", + " response = client.chat.completions.create(\n", + " model=model_engine,\n", + " messages=[\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": zero_shot_categorical_prompt.format(\n", + " query=query, passage=passage\n", + " ),\n", + " },\n", + " ],\n", + " )\n", + "\n", + " # Parse the response\n", + " output = response.choices[0].message.content.strip()\n", + "\n", + " # Extract the rating and reasoning from the output\n", + " category = None\n", + " reasoning = None\n", + " try:\n", + " for line in output.split(\"\\n\"):\n", + " if line.startswith(\"##Categorization:\"):\n", + " category = line.split(\":\")[1].strip()\n", + " elif line.startswith(\"Reasoning:\"):\n", + " reasoning = line.split(\":\")[1].strip()\n", + " except Exception as e:\n", + " print(f\"Error parsing response: {e}\")\n", + "\n", + " CATEGORY_TO_RATING = {\n", + " \"IRRELEVANT\": 0,\n", + " \"FAIR\": 1,\n", + " \"GOOD\": 2,\n", + " \"EXCELLENT\": 3,\n", + " }\n", + " if category in CATEGORY_TO_RATING:\n", + " rating = CATEGORY_TO_RATING[category]\n", + " else:\n", + " rating = None\n", + "\n", + " return {\"rating\": rating, \"reasoning\": reasoning, \"raw_response\": output}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "trec_combined_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "# Initialize an empty list to store results\n", + "for model in [\"gpt-4o\", \"gpt-4o-mini\"]:\n", + " results = []\n", + "\n", + " # Iterate over the DataFrame rows\n", + " for i, row in trec_combined_df.iterrows():\n", + " query = row[\"query\"]\n", + " passage = row[\"expected_response\"]\n", + " ground_truth = (\n", + " row[\"expected_score\"] * 3\n", + " ) # recover raw score {0, 1, 2, 3}\n", + "\n", + " # print(f\"Query: {query}\")\n", + " # print(f\"Passage: {passage}\")\n", + "\n", + " # Snowflake internal prompt\n", + " internal_result = internal_prompt_relevance(\n", + " query, passage, model_engine=model\n", + " )\n", + " internal_rating = internal_result[\"rating\"]\n", + "\n", + " # Umbrela Prompt\n", + " umbrela_result = umbrela_prompt_relevance(\n", + " query, passage, model_engine=model\n", + " )\n", + " umbrela_rating = umbrela_result[\"rating\"]\n", + "\n", + " # Categorical Prompt\n", + " categorical_result = categorical_prompt_relevance(\n", + " query, passage, model_engine=model\n", + " )\n", + " categorical_rating = categorical_result[\"rating\"]\n", + "\n", + " # Append results to the list\n", + " results.append({\n", + " \"query_id\": row[\n", + " \"query_id\"\n", + " ], # Assuming 'query_id' column exists in trec_combined_df\n", + " \"query\": query,\n", + " \"passage\": passage,\n", + " \"ground_truth\": ground_truth,\n", + " \"internal_rating\": internal_rating,\n", + " \"umbrela_rating\": umbrela_rating,\n", + " \"categorical_rating\": categorical_rating,\n", + " })\n", + "\n", + " # Convert results into a DataFrame\n", + " results_df = pd.DataFrame(results)\n", + "\n", + " # Save results to CSV for further analysis\n", + " results_df.to_csv(f\"{model}_3_prompts_results.csv\", index=False)\n", + "\n", + " # Inspect the DataFrame\n", + " print(results_df.head())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from sklearn.metrics import f1_score\n", + "from sklearn.metrics import precision_score\n", + "from sklearn.metrics import recall_score\n", + "\n", + "\n", + "def plot_confusion_matrix_with_metrics(\n", + " csv_path, rating_column, title_prefix=\"\"\n", + "):\n", + " data = pd.read_csv(csv_path)\n", + "\n", + " # Define the full range of possible ground truth and predicted scores\n", + " all_scores = [0, 1, 2, 3]\n", + "\n", + " # Create a confusion matrix with all scores explicitly defined\n", + " confusion_matrix = pd.crosstab(\n", + " data[\"ground_truth\"], data[rating_column], dropna=True\n", + " ).reindex(index=all_scores, columns=all_scores, fill_value=0)\n", + "\n", + " # Skip plotting if all rows for rating_column are empty\n", + " if confusion_matrix.sum().sum() == 0:\n", + " print(f\"Skipping {rating_column}: no data available.\")\n", + " return\n", + "\n", + " # Plot the confusion matrix\n", + " plt.figure(figsize=(8, 6))\n", + " sns.heatmap(\n", + " confusion_matrix, annot=True, fmt=\".0f\", cmap=\"Blues\", cbar=True\n", + " )\n", + " plt.title(f\"{title_prefix}Confusion Matrix\")\n", + " plt.xlabel(\"Predicted Score\")\n", + " plt.ylabel(\"Ground Truth\")\n", + " plt.show()\n", + "\n", + " # Flatten the confusion matrix for metrics calculation\n", + " ground_truth = data[\"ground_truth\"].apply(lambda x: 1 if x >= 2 else 0)\n", + " predictions = data[rating_column].apply(lambda x: 1 if x >= 2 else 0)\n", + "\n", + " # Calculate metrics\n", + " precision = precision_score(ground_truth, predictions, zero_division=0)\n", + " recall = recall_score(ground_truth, predictions, zero_division=0)\n", + " f1 = f1_score(ground_truth, predictions, zero_division=0)\n", + " # Calculate off-by-1 accuracy\n", + " off_by_1_correct = data.apply(\n", + " lambda row: abs(row[\"ground_truth\"] - row[rating_column]) <= 1, axis=1\n", + " ).sum()\n", + " off_by_1_accuracy = off_by_1_correct / len(data)\n", + "\n", + " # Print the metrics\n", + " print(f\"{title_prefix}Metrics:\")\n", + " print(f\"Precision: {precision:.4f}\")\n", + " print(f\"Recall: {recall:.4f}\")\n", + " print(f\"F1 Score: {f1:.4f}\")\n", + " print(f\"Off-by-1 Accuracy: {off_by_1_accuracy:.4f}\")\n", + "\n", + "\n", + "# Example usage\n", + "csv_file = \"gpt-4o_3_prompts_results.csv\"\n", + "plot_confusion_matrix_with_metrics(\n", + " csv_file, \"internal_rating\", \"Internal Ratings: \"\n", + ")\n", + "plot_confusion_matrix_with_metrics(\n", + " csv_file, \"umbrela_rating\", \"Umbrela Ratings: \"\n", + ")\n", + "plot_confusion_matrix_with_metrics(\n", + " csv_file, \"categorical_rating\", \"Categorical Ratings\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "# Step 1: Load the CSV file\n", + "csv_file = \"/Users/dhuang/Documents/git/trulens/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/data/TREC_no_rubric.csv\"\n", + "data = pd.read_csv(csv_file)\n", + "\n", + "# Step 2: Inspect the data\n", + "print(data.head())\n", + "\n", + "# Ensure your CSV has columns: 'APP_VERSION', 'RAW_GT_SCORE', 'RAW_FEEDBACK_SCORE', and 'COUNT'\n", + "\n", + "# Step 3: Group data by 'APP_VERSION' and create a confusion matrix for each version\n", + "app_versions = data[\"APP_VERSION\"].unique() # Get unique app versions\n", + "\n", + "for app_version in app_versions:\n", + " # Filter data for the current app version\n", + " app_data = data[data[\"APP_VERSION\"] == app_version]\n", + "\n", + " # Pivot the data to create a confusion matrix\n", + " confusion_matrix = app_data.pivot(\n", + " index=\"RAW_GT_SCORE\", columns=\"RAW_FEEDBACK_SCORE\", values=\"COUNT\"\n", + " ).fillna(0)\n", + "\n", + " # Normalize the confusion matrix (optional)\n", + " confusion_matrix_normalized = confusion_matrix.div(\n", + " confusion_matrix.sum(axis=1), axis=0\n", + " )\n", + "\n", + " # Step 4: Plot the confusion matrix for the current app version\n", + " plt.figure(figsize=(8, 6))\n", + " sns.heatmap(confusion_matrix, annot=True, fmt=\".0f\", cmap=\"Blues\")\n", + " plt.title(f\"Confusion Matrix {app_version}\")\n", + " plt.xlabel(\"Feedback Score\")\n", + " plt.ylabel(\"Ground Truth\")\n", + " plt.show()\n", + "\n", + " # Step 5: Plot the normalized confusion matrix for the current app version\n", + " plt.figure(figsize=(8, 6))\n", + " sns.heatmap(\n", + " confusion_matrix_normalized, annot=True, fmt=\".2f\", cmap=\"Blues\"\n", + " )\n", + " plt.title(f\"Normalized Confusion Matrix {app_version}\")\n", + " plt.xlabel(\"Feedback Score\")\n", + " plt.ylabel(\"Ground Truth\")\n", + " plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "trulens", + "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" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/dataset_preprocessing.py b/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/dataset_preprocessing.py index 931eba6ad..14159a2d4 100644 --- a/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/dataset_preprocessing.py +++ b/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/dataset_preprocessing.py @@ -1,9 +1,12 @@ import ast +from collections import defaultdict import csv import json import random from typing import Any, List, Tuple +from datasets import load_dataset +import ir_datasets import matplotlib.pyplot as plt import pandas as pd import seaborn as sns @@ -11,6 +14,43 @@ from trulens.feedback import GroundTruthAggregator +def generate_balanced_llm_aggrefact_benchmark(split="test", random_seed=42): + llm_aggrefact_dataset = load_dataset("lytang/LLM-AggreFact") + + # Convert to pandas DataFrame + df = pd.DataFrame(llm_aggrefact_dataset[split]) + + # Initialize an empty list to store balanced DataFrames + balanced_dfs = [] + + # Iterate over each unique dataset + for dataset_name in df["dataset"].unique(): + # Filter the DataFrame for the current dataset + df_subset = df[df["dataset"] == dataset_name] + + # Count the number of instances for each class + class_counts = df_subset["label"].value_counts() + + # Determine the minimum count between the two classes + min_count = class_counts.min() + + # Sample min_count instances from each class + df_balanced = ( + df_subset.groupby("label") + .apply(lambda x: x.sample(min_count, random_state=random_seed)) + .reset_index(drop=True) + ) + + # Append the balanced DataFrame to the list + balanced_dfs.append(df_balanced) + + # Concatenate all balanced DataFrames into a final DataFrame + final_balanced_df = pd.concat(balanced_dfs, ignore_index=True) + + # Display the balanced DataFrame + return final_balanced_df + + def generate_summeval_groundedness_golden_set( file_path: str, max_samples_per_bucket: int = 200 ): @@ -362,6 +402,116 @@ def generate_balanced_ms_marco_hard_negatives_dataset( }) +def generate_trec_dl_passage_benchmark( + max_samples_per_query_per_score: int = 3, + dataset_path: str = "msmarco-passage-v2/trec-dl-2021/judged", +): + # Combine queries and qrels from multiple datasets + queries = {} + qrels = defaultdict(dict) + docs_store = None + + dataset = ir_datasets.load(dataset_path) + # Merge queries + queries.update({q.query_id: q for q in dataset.queries_iter()}) + # Merge qrels + for qid, docs in dataset.qrels_dict().items(): + qrels[qid].update(docs) + # Get docs_store + if docs_store is None: + docs_store = dataset.docs_store() + + print("Total number of queries:", len(queries)) + print("Total number of qrels:", len(qrels)) + + # Sampling + for query_id, query in queries.items(): + if query_id not in qrels: + print("query_id not found in qrels") + continue # Skip queries without relevance judgments + + # Get documents by relevance scores + relevant_docs = defaultdict(list) + for doc_id, score in qrels[query_id].items(): + relevant_docs[score].append(doc_id) + + # Determine scoreddocs intervals for this query + scored_docs = [ + scored_doc + for scored_doc in ir_datasets.load(dataset_path).scoreddocs_iter() + if scored_doc.query_id == query_id + ] + if not scored_docs: + continue + + min_score = min(scored_doc.score for scored_doc in scored_docs) + max_score = max(scored_doc.score for scored_doc in scored_docs) + interval_size = (max_score - min_score) / 4 + intervals = [ + (min_score + i * interval_size, min_score + (i + 1) * interval_size) + for i in range(4) + ] + + # Initialize sampling counts + sampled_docs = [] + + # Use scoreddocs for all scores (0, 1, 2, and 3) + for score in [0, 1, 2, 3]: + if score in relevant_docs: + # Get ranked documents using scoreddocs + ranked_docs = [] + for scored_doc in scored_docs: + if scored_doc.doc_id in relevant_docs[score]: + ranked_docs.append(( + scored_doc.doc_id, + scored_doc.score, + )) + + # Filter documents based on interval alignment (-1, 0, +1) + allowed_intervals = [ + intervals[max(0, score - 1)], + intervals[score], + intervals[min(3, score + 1)], + ] + interval_docs = [ + (doc_id, doc_score) + for doc_id, doc_score in ranked_docs + if any( + low <= doc_score <= high + for low, high in allowed_intervals + ) + ] + + # Sort by score (descending) and select top documents + interval_docs.sort(key=lambda x: x[1], reverse=True) + top_docs = [ + doc_id + for doc_id, _ in interval_docs[ + :max_samples_per_query_per_score + ] + ] + + # Add to sampled documents + sampled_docs.extend(top_docs) + + doc_text_seen = set() # deduplication of identical passages + # Yield the sampled data + for doc_id in sampled_docs: + doc = docs_store.get(doc_id) + if doc and doc.text not in doc_text_seen: + doc_text_seen.add(doc.text) + yield { + "query_id": query_id, + "query": query.text, + "doc_id": doc_id, + "expected_response": doc.text + if hasattr(doc, "text") + else doc.body, + "expected_score": qrels[query_id][doc_id] + / 3, # Normalize to [0, 1] + } + + def write_results( feedback_scores: List[float], labels: List[Any], diff --git a/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/groundedness/llm_aggrefact_groundedness_benchmark.ipynb b/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/groundedness/llm_aggrefact_groundedness_benchmark.ipynb new file mode 100644 index 000000000..bf00e1f56 --- /dev/null +++ b/src/benchmark/trulens/benchmark/benchmark_frameworks/experiments/groundedness/llm_aggrefact_groundedness_benchmark.ipynb @@ -0,0 +1,268 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Large-scale meta evaluation on groundedness feedback function with [LLM-AggreFact](https://huggingface.co/datasets/lytang/LLM-AggreFact) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from trulens.benchmark.benchmark_frameworks.experiments.dataset_preprocessing import (\n", + " generate_balanced_llm_aggrefact_benchmark,\n", + ")\n", + "\n", + "llm_aggrefact_df = generate_balanced_llm_aggrefact_benchmark(split=\"test\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "llm_aggrefact_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for dataset_name in llm_aggrefact_df[\"dataset\"].unique():\n", + " print(dataset_name)\n", + " print(\n", + " llm_aggrefact_df[\n", + " llm_aggrefact_df[\"dataset\"] == dataset_name\n", + " ].label.value_counts()\n", + " )" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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Zp999jDjjDNmx/3vf/8bzjnnnPC9730vrL/++ll5GQtvvPFGuPHGG8Nbb70VFl100bDiiiuGCSecsIymh24bMGq6OAKOgCMwGBA4//zzox7AUXd0+4hWOe68885xueWWi+OMM06UchGPPPLIKMWja4crpcH6yxjWWWed+Nvf/jZecsklccEFF4wTTTSRjeFnP/tZpN58882XjfV3v/tdU2PSQzqKGdL2o81OC/054ogj4thjjx3HG2+8+IMf/CAuv/zy8eSTT4777bdfnHPOOeO3v/3tKOWq1K5KMYuTTjqp4XDiiSfa79prr13qMYZiY2EoDtrH7Ag4AoMXgdNPPz170C611FLZQG+55RZ7OPGwnn/++eMnn3ySbeuWhT/96U/xu9/9rvV/vfXWi998803Wtf/85z/xpz/9qW1DqUBOPfXUbKzNKhXsN/3009t+SyyxBKsdlWOPPdb68q1vfSvefffdUVaDKKtEPPzww+Pll19uSiKKYdmy1VZb2XGnnHLKeN9999kySuhXX31V9qGGVHvuUzF0jVQ+ckdgUCKQN18z9ZFklVVWCXo42eoTTzwRdtppp7SpK3715Anbb799+PTTT60/BxxwQBhrrP+7ReuhG84+++wghSjrr97us+XeLNx7773hyiuvDDfddFNvdiu9LmM95JBDrF0Sdi299NJhsskmC9NNN104+OCDgywX4a9//Ws49NBDSz/2K6+8Ym3KghUWX3zxIAUtXHvtteE73/lO6ccaSg26T8VQOts+VkdgiCOw6aabBpm6DYWrr746/PrXvw4/+tGPbP3FF180P4OXXnopzDHHHDZ/jx9GXpiD52H83HPPhREjRgSZy8Mss8ySr9Ln5TvuuCPcc889tj+Jq+add96qtoYPHx70Zh/0Zl21LRV8/vnntl1v/fZAXmihhYIsNgFfBeQ3v/mNlbOsqZWw7bbbVpRNPvnkYZlllgkXXXRRePXVVwO+Gtttt13485//HDS9FHgY49tQhn8Dyt0XX3xBV8Iee+xhvzfccIP19euvvw577713OOigg8yfwjb24qvR+Rw9enR4/fXXrTVZrMKoUaPCCiusEDSd1IsjeNWaCAwpu4wP1hFwBAY9AnoYmilbN7yoN9+K8TKdwPw82/hIsbDt+Cwwny9nvfjkk09GPYjNf0Fv9Nn+1113XZQVJC622GLxgQcesGkK/ADKmuvH1yP1S06Z2XEbLZx11lnZPkx/4Csi5cH6/thjj8VTTjnFtjNmfDMQObNmGFAXufPOO83nhOPjZyBLQWRaIPVHVp0o5cv8HVLZBRdcYPv25wtMaY9ph3//+99RCkaUIhflpGo+FTPMMEP817/+1etD9HQ+jz/+eJti4dhMN+2///7xoYce6vVxfIdqBNynohoTL3EEHIEBjEAjpYJh4QiYHownnHCCOTyOP/74VoajJ6JpBltH0VBUQvzLX/4SlaXSymgfGTlypK0z91+GbLjhhtYefVtzzTWbarKoVKAcpLH98Y9/tDaScpBXsFAaqJeUCiqyTBlYvPzyy+ZboKkAK+PBKwtF/Mc//mEOldRbffXVm+pjo0p///vfTVGjPVmNIj4wmuqIH3/8sT30kyLEOHG2VfRLPPPMMxs12dT5pAFZo2xs+Je4lIeAT3/oanZxBByBoYOAHB6zweqBG5gGYcoASaGM6RfTPFMS7733XtCDzuow7YEcffTRQQ/xsM0229h6f790W8+a0Nt5ttybBaZtCD+VYhB++MMfWngtPgPIhx9+mDWV9zVJhamM6Y80pUMoLlM+tDXTTDNZVXwepGSF999/P+3a51/SiT/44IM2DcV0xe677x4U8RJ+8YtfhB//+MdBzqphk002CVdccUWQYhNkzQnHHXechX7KilHzuM2cT9p1aQ0CrlS0Bldv1RFwBLoQAR7W8CEkQUHAlyEJjoGIzPGpKODUmH/Ip4f0SiutFPiUJXpjzprKKwBZYRMLssIERZCEMWPGhK233tp8K4q8HU00k1VJikZWoIVaZfntvV2GJ+Oyyy7LdnvttdeCrBGGO/4fKBQITqobbbSR+UIwxnpKxfPPP5+1Ve98ulKRQVT6wv+5FpfetDfoCDgCjkB3IQChVBKsEbyR5x9OyVoA4VIS3vp5O0+SogbSelm/OH0mwVm0L8qAfEbCWmutFYh0+eijjwJv/9NOO21qdkD87rvvvmHdddcNCyywgJFe0WlNzYQNNtjA+q+pGXOSrTeYZs5nvX29vP8IuKWi/xhWtDBYGP0qBuUrdRF45513wvXXX29e8rzd4mmPCRoTrJy/6u5X3HDXXXcFvNARmAPx1kfazXzYzHja3ScDoqSvc88911oiPFOOhoFfES1ZhAEb/vnPf9r2FNbJCg83mDiJFEGIgFhttdVsmS/qYprvr8CYKT+FIIdLi4jgGtpqq62qmiXs8eKLLw5ycqzadswxxxhDJBt+/vOfB6YyBpLIATbceuutAaUKBY8oGwQlg/BaolGIQmHaqp40cz7r7evlJSBQnnuGtwQCrWb0U5hVPO+889oOdqeO2/aB9uKAurlbxABOdYr3j3jD4yGvv2UUhXIvWorxtNNOs/3YF2ImpBHzYSvORzPjadSnXg24hZXFb5BhKUuEHYmoAqIrIFjC6TD/H4JUiogOsKcO8stf/tLWYZwkYuTLL7+0qATq8Nlll12ifC2M8ZHlsoQICPkQ2DFwElV4pV0HtC/lJSq80qIzRM9th8xHjOBAKp4L25c+ioLbCKSIUGEdB9W0H+RSlMGsmQS2UcrYlkS03xX1OP9EwFAvYZvq9veXtsH7wAMPzJpKzrA4Z+IkynYp4Nn2WgvNnE/2S+N1wqtaKPa9zKM/+o5d3T1byegnB6Y4zTTT1D12qzZ06ritGk9/2yV0j9A7qJ/xYE9CpACe9b1VKtg/3eiTUkFZPebDss9Hb8ZTr0/0t9OiOfeYIhZ48PEhaoMHKpEF4kKIcjCs6iZKA9EX0GDDWsmDk+iGDz74IKvLeSaCIrXLQ188CtlDP6vYzwUeriK+suuIY3FdQFXNtaY39gjrJkIIZHrAU48xooTQL9ZRoGDe3GKLLbI+E6my8cYbZ+vU41ji76goY1y77bZbRRkPe/FVVJSh5JQlhIEyBlmLsiYZD2Pkwc95JBS0GenpfMJWytjTZ9ZZZ41yGG2maa/TAwKuVPQAUF82Nwpp46aWLmT+yL0R3oTZt91KRaeO2xts2l33kUcesXPBjVuOZRWHv+aaa/qkVHBD5fzmlQooi0W2VEEp3Yrz0Zvx1OpTBQADeEV+CPY2n1cUi8Mh54ZIm4xXobit7HUUIPgnRGRVUxmqdTze6DmfiYYcSwu8D++++26t6l1TBuaE7hZFjJp2TtJ4itsbrTdzPhvt79t6j8AwdtGNzKVEBJjv1NuBtag3m6AbQtY6DHLM0SIipDF2Ohj9emLBk7k27LDDDgFHLOZvlWjH2N9ggetpX45FpkMy/UF5i7e1bjxBZlsLFWM7HvA333yzOXcxtwtdMOx9jY7LfkNVCIOD2hfRm2RQ8iMLfcMznpBFPNbJAAn7IiF5CA5/MrOHCy+8MOgGaqFzzBUnYZ6YUD1omB9//PEKlkOOAfNhq85Hs+PJszGmPuG4KEUqDaPil2td/AJWVu8aq9jBVxwBR2BgI9B7PcT36AmBRpYK3hqKjH6YniGewfRajwVPD6KMfAdzIAxwzOM3s69CrMwkuuyyy8bf//73NteqqzbK4c6GIu59e0NmbpikS8zBynvcttU7bk8YDPbt+DQwNw+O6TNi7pERKwXm6yTMYad6WDWYw8asnvbJm4+LlopazIetOh/NjqdWn0j6xDWz6667Rq79NA/PGLGqII2uMavgX46AIzAoEPDpjxacxkZKBYdLDw9uujD6NcuCx0OLffLTH83sqxAt2480yig1CHPDKBWw7iUl59lnn7VtzC9yHB4gSK3j2oYh/gXFcJq/Bq/0geIZs2uS5AQIzgrxs2IlT7L6lDGdgKTrIj/9UYv5sFXno9nxFPskC1jcc889bQyy0GQ4zDPPPHa9NXON2c7+5Qg4AgMeAeep0JOg3VJk9EssePJ0bsiCV6ufzeyrB5ftSggaCXMwQxOuxr433nhjkMe5bSeMi9BGXdW2LkewWof0sv8hAK8AjIrE0Ofl0Ucfzaa/KE+ZJgk5TQmq0tQJ2CuKIL97xXLZREMVjRdWmh1PsU+EQTIdB/skCaCSnHTSSTZ2v8YSIv7rCAx+BFypaPM5rsXopzdUY8EjDh4WPMhq5FTVVM+a2Ze5fZmkrb2nn37aKG7J/MfDIU/kIwuL+QKQlZD5+0TL21RHhlgl4uXxT8H/hFh6fCfyygX+KY1ojBU5kiEGN0SnpT/jwReE6wuOhLffftuGQgZLriPErzGDwb8cgSGBgCsVbT7NtRj9cL7sKwteM/vCGsjb86qrrpqNVgl6gvwngsz3WRlkOZADpQ/KiEttBK666qoAhgiWCIUjBk0fmTKW9sA5tp7IhyHb1A0ERf0dj6ZwLCU3g8IiQ3puLF4K7fNrLDvTvuAIDH4EnFGzzee4FqMfFgpMxEgzLHgoEghvwqNHj+5x3x133NEY6Xh7xtS+5ZZbBh4CciIMin+3tviiD8lTn+RJRKoQXZIkf9xGjHap/mD/JYoDs3+aXpIjpkXUEKGBkBCpnrz++uvZJmVezJZ7s1D2+ejPePbZZx+b/qD/XMPyuzCr13333Rfy4+vpGuvN+GvVJU9HPrdHqoP1j6iagSyDeWxY/e6///7s9EwwwQRVeVV4CUJJTcK9Sc7tadV/uwWBAe8V0oUD6C2jX7MseJD36LoxUhuFMMYlllgiapoic4yrx6AH2Q3Og1999ZWhpQeh7YNDKTHtkOvQLh78hx12WJSiYmQ7l156qdWvdVxY64ayJCZD0ShX8BXoDd2whFwnCecJfPlIqTTHTKJAWGcbApMiKacpU+6CtGt2bvLMh604H70ZT7peUp+kOGTjk7Jp5EU4Z8IuyvXUzDWWDbifC6TKhnUx4c2vlGqLeupn0x3ffTCPDQ4NTSVWnDccgPPCPS8Rr0HM1Rfeinx7vtwaBDz6o2Rc+8LoR9hhiiKox4JHNwndS2yBeODDrNfMvigV3Ox5GBB1wMOLh15SDIgCUXKl7A8tc3yEFjdJreOmbUP1l4cwD1XCReXwauyDyjlgrIdKhW2UygmbvFKRZ2Tk4ZcIiZQsKcOfByGhprWYD2mzFeej2fHU6hNRRekhTrgz0UmJGjo9GHq6xhJWZfwqd0TWH1gYB5MM5rGhfKJQp2uJe52sFxWnjxBlotNcuhcBJ7/SFdwNQiIj5uCJDoDcSlwHNkfPfLs46rMuijY4MDWRogjY0NO+pAnGHE3iI5zmaI/1vOgSDc8884wRXhEVUvTwr3Xc/P5DbZnsj3qABikWRm5FumVMsUx5JKfYhAkOi5h2Oa+cO84BUybFc5DqN/Nb9vnozXia6V+tOj1dY7X26UuZ2CTNgZZ9OT/JebQvbXXbPoN5bGDN9Ku4dDLYuf8xDStF1cqISCPCCLI2l+5EwJWK7jwv3qtBhEBSKnCKRQFMIaaDaIhdNZS+PHjrsX0WGVFl4bPspkT8rLjiikF5Qto69t6ODSUWHx+ivvCDgukXHxd8GGBHTbLyyisH0Y9bhlR8g5TnI3uQpzrt+EWpIMvoEUcckflPzDvvvIHspTgA4we21157VSgV9caY+su4GCvKvCxolkk4KfTK0RPykVhpH//tBwLda0TxnjkCAx+BDz/80KZJ9Bc1s66cZQf+oLp8BEwJJryT30ejLjdi+6QtmG5pj4ReZOZkejC1LyfrRk2Xvq03YxM9vCUlY4pOyohNfTLNKmdt83shcVoaB1N4JMhL06tMG4n+v/T+99RgYv2FOTb1jV8ytyIkUVt00UWzZhqNkUowCHPemI5T+oSKKUWmWhQVl7XlC+Ug4D4V5eDorTgCNRHANwL/lfyHG7xL6xDozYO3GbZPnJx5sKU5fijN8R2hDL+YdkpvxoZ/F30ksymCLw7rOEQief8M8YoY5f/RRx9tdagHZX+7JSkVHFcWiawv9Ie+FZWKnsZItmD2Tc7PpE1nnQ+J2lzKR8BDSnV1uTgCrUIAM65L9yJQZPtkWkC3Wesw8/dMcST/InxoEhOqohDM5+m9997rysHhk6XcQNY3CPdgyk1hzHKaDfCkpHFRSRFFlvAOTpsknR7bqFGjAr5KUn6sS4qqC0o5kLpnfmc9jRHfIyT5OZEELwk+ZKuttlpa9d+SEHCloiQgvRlHwBEYOAiQJZZMvUW2Txhq8YHh04hRdljoXt5AxobjLbTpyJNPPmmcISzDlIvk+R6s4H9feUUjX96JZXyPZF0J+D2QQgBF6Fe/+lXQ9Id1BybansaoaKUAD1BSqF577bVsKHn+lKzQF/qNgCsV/YbQG3AEHIGBhsChhx4aFEZdxfaZyN8G2njy/WVsU0wxRVYk07+x5GYFA2iBiCmsSZqCssipfNfzbMD1xohTJyzGY8aMMQfQl19+2SKvKCdnjUv5CHSvul3+WL1FR8ARcARs2uL888+3KIgio2yCh4gCIkIGmkAVz9h4m8fqgjDdkaYBWL/99tuDiKNY7EpJCQ5T52aeeWaztCTm2lTOVEZPY6QtollQSghFFYGYsQmLlyU1478lI+BKRcmAenOOgCPQWQSSqZteMBWgKIasQ+Q4IXwSsznm78022yykeXYRvoXDDz88QFfO9Icid2w/pkkQ9kkZhv/xz0+tjBDhdkpvxibWSeuamHTtrZypBB6siVo+jYtKaTn9UvbZZ5/x0zbBDwSunjxddzo4vi0krCtKT2MUW3EgPQFTJ3LKDY8//rj5aDAlxPFcWoBA+b6f3qIj4Ag4Ap1BQA/NLDJDt0vz8odJVhaJinIRwGUdbMT2qTwmWbQA7cEomkJQU/vQgLdDejs25YaJu+66axYmqjf9qOmdKAfMqGmAitBYwmZvuOGGqDf/bLxyboxEx7RDiOqA9TdhWi+qhjDYfEhpozHS72WWWSZrM7WdfuWk2Y6hDbljOPmVrjAXR8ARGNoI6M7fkFF2IKNDgjVYdWefffYw8cQTD+ShBKYzFFZr0Sr5gdQbIwntSDymcGBjC2YfnFSx3iBMF80111y27F/lIOBKRTk4eiuOgCPgCDgCXYQAobSkJBCRl4WmolggKCZMizDNRTQITp4u5SHg0R/lYektOQKOgCPgCHQJAsOHDzelgoiP5LyKRQq/DdKoE17rCkX5J8stFeVj6i06Ao6AI+AIdAECTItceumlpkiwTNI/rBfK1mz8F13QxUHXBVcqBt0p9QE5Ao6AI+AIOAKdQcBDSjuDux/VEXAEHAFHwBEYdAi4UjHoTqkPyBFwBBwBR8AR6AwCrlR0Bnc/qiPgCDgCjoAjMOgQcKVi0J1SH5Aj4Ag4Ao6AI9AZBNoaUorHLTz0Lo6AI+AIOAKOwEBCgGeXWD8HUpc70te2Rn/A6pbn4e/IiP2gjoAj4Ag4Ao5ALxEg+dzYY4/dy72GXvW2KhVDD14fsSPgCDgCjoAjMHQQcJ+KoXOufaSOgCPgCDgCjkBLEXCloqXweuOOgCPgCDgCjsDQQcCViqFzrn2kjoAj4Ag4Ao5ASxFwpaKl8HrjjoAj4Ag4Ao7A0EHAlYqhc659pI6AI+AIOAKOQEsRcKWipfB6446AI+AIOAKOwNBBwJWKoXOufaQdQgB+lltvvbVDR+//Yd98883w6KOP1mzo73//e0gfUktfeeWVFfW++eab8Oyzz4abbrop/OUvf6nY1o6VL7/8Musf/XzxxRfDww8/XHHoZup89NFH4fe//3145JFHAmPqVknngt9a5yPf7zfeeCPccMMN4bbbbssXd3yZvr/yyis1+/Hf//43PPXUU2HMmDGBc9JIOE//+te/qqpwLf/5z3+uKveCkhCILo6AI9ASBN577704//zzR/1V42qrrdaSY7S60a+++iqOmHtkXG655aoOdc8999jYGF/6bLzxxlk9PcCjCIPi6quvHvfdd9/4/e9/336zCm1YWHrppbO+0cdvfetbkX7lpac6xx57bJxmmmnijjvuGDfccMP4gx/8IF500UX5JrpiuafzkTr5u9/9Ls4zzzxx4YUXjueff3788MMP06aO/n788cfx4IMPjhNNNFEcNWpUVV+kBMX55psvO5+cyyOOOKKqnpSpyHX4ox/9yM7VL37xi/jHP/4x3nffffGnP/1pHGeccaKUlqr9vKAcBNpK060/tYsjMGQQgNL39ttvD5NOOumAHfOBBx4Ynnn26SClomoMxxxzTNhoo43C1FNPbduGDRsWtttuO1v++uuvwzrrrBNmmGEGs1JQuNhii4U111wz6KEcfv7zn1u9Vn49/vjj4fXXXw96qGSHmW666cJss82WrfdUB6vG3nvvHa655pqw7rrr2n677bZb2H777cN6660XxhtvvKytTi80Oh+pb1LuwvHHHx9+9atfhX322SeMNVZ3GKuxFh111FFmQfjHP/6Rulvxy7W2+eabh5tvvtmsFVtssUU49NBDg5S9MNlkk1ndzz77LCy00EJmoXjyySeDFIiwxOJLhgknnNC2Y2n62c9+FmaaaaaKtn2lRATK0U28FUfAEaiFgEyw9mY1EC0Vd911V1xiiSXsLb1oqXjuuefiVFNNFf/973/XGna89tprbdynnXZatl2ma3tzlLJVd7+scgkL66+/fjz11FMbttRTneOOO87GgRUgySWXXGJlmtZKRR3/7el80MEDDjjA+i1louP9rdcBKQzWx6KlgvFJaarYDQuEHoVROTmycimAVnb99ddnZWuvvbYt08b3vve9qGmTbJsvlI9Ad6ipJSpJ3pQj0GkE/vnPf9rb+VlnnRVeffXVmt2RyTlcccUV4fTTTw/PP/+81WEuGctG+qR5X3wyUpmmI2q2V3ahTNFh5513DqNHjw7Dh1cbNDUlEDS9EzSlYW/sRT8F/CgQmbKzrmHJmHvuucP7778fXn755ay8FQuvvfaa+QtgEeGYvJnzNpyXZuqQ7wFh/y+++MKW8Q/BAjPzzDPbejd89XQ+8J+QghQ0JRCOPPLIbuhyzT5wjdQSzgMWo7xwPmaZZZaQzhHbODdYzjTlZlWxXHz729+25b322ivsv//+A9pyaAPp8i9XKrr8BHn3BhYCzzzzjD3E9GYb/vOf/4S11lqragDc+DSPHzC9X3755WHEiBHhxBNPDNxQNccdVlpppcANUHPG2b6YbC+++OKg94qsrJULHI8+8PCsJfRt9tlntwe1rBJhqaWWsgdvqpumBR577LFUZL/JTJ0UpoqNJa7QPtMtk0wySdAbatBcveH81ltvZUdppg7nSX4x4c477wxLLrmkTXvg6Hf11Vdn7XTDQk/ngykPWZVsmoBs0Zj/mZ5iemggCv+hyy67zJSIpDQwDpyK5SuS/XdOOOEEm7bCsRMFf5dddhmIwx1YfS7f+OEtOgJDEwGmAvT2GjGpJ1HEgJlj0/THu+++G7/73e9GphYQvUlFPYDNeeyvf/1r1HyybZ988smzKQKcJZlqwAGtHXLhhRfGZDLmeNNPP31NR022yepgzpfK3mhOkGlcUq5s3HPNNRfVMtGDzMr1kM7KWrnAlMstt9wS6YfuzFHKT9XheqoD7vPOO6/tTxuyMFW10S0F9c4HDrP0HUdTPZCjlNnINca1xzXaLcK5op/F6Y/UP1m44sorr2zXGvXkH1Pxv1h22WXtXElZilKkovxgopT7OMccc8Tf/va39p/69a9/bdN6iy66aHzooYdS0/5bEgK8+bg4Ao5ACQhcddVVdkM888wzs9aKPhVs42bIw01vwfbhxk4ZXvkIc96scxNEeADIKc2WW/3FzRjFKB8R0EipSP05+eSTrc+ycKSiKIuLlW299dZRb5Vxgw02sHXGprfGrF47FjQlZdEAHJsHby2pV4fIgYQB+xN1cO6559ZqomvKiudj/PHHNwWCB2yS5L8g59pU1PHfnpQKFHdZm+y/gVLE+dhjjz2yfqO0y5kzykoVNWVlSoSmIW0d5RwfIZR6OWxGfCz4D7qUi4ArFeXi6a0NYQQUKWE3ubzjWFGp4AFLaKXm96s+6YZP6Bxv/ssvv7yhueKKK8YHHnigLcjypocCgxKQPopesTc91vNjy3dI/iDxO9/5ToVFAwsAjpr0f7PNNotnnHFGHHfccePIkSPzu7ZtOTn23X///XWPWaxDWDAPIfkh2D7ygbFzw/mR30jddjq9oXg+cFDkkxfODwot4bLdIj0pFfl+ogBzHhZccMF8ccUylj9CgFEiDjvsMPt/ch0mWWWVVdKi/5aEwFjS9FwcAUegBASSI98nn3xStzXmvnHIxBGScLf8BwdPZDqFPcrEG+6+++5w7733mmMj/gHtEJxCxcEQNt100+xDf3EmpYxttQTfBXxDUngpdfARwdkTciVFTARCBXGWbEc4aa0+prDYfB+L9Yp1cKT99NNPA+GLyE477RQI3SRkVpak4u5ds148Hzg0cs3R7yScH3xcig6saXu3/8p6ZNccJFf1RFMdAb8Ywky5Bgln3mabbaw6xFgTTDBBvV29vI8IuFLRR+B8t+YR4E//0ksvBZn3zWkusdzpjdFucjyEeXDxSdvyrePBnbbz+/nnn4e+7JNvsxXLesu3ZmEpLIpeAqwIBznw0FtTRRWcMIkWScLDmHo4eqabYNrWyl8cGfUGW/EhyoGHLeUnnXRSzcPjBCgLS1h88cVrbn/iiSeMUwAnVJSTTggRJygU0047bd3DF+vgbIskhZFl+czw09XMmsXzwYOV60kWL+s7X/yHiOCRv0FWNpAWODdcr+l/V+w722SVCCgW4IFTqvwosmgQhRuHFVZYobibr/cXgZIsHt6MI1CFAHOYzGuKeMacwnBWXGaZZWx9xhlnNFPkBx98EA855BAzMetaNqY/3cAr2sJXARMn2xWNEPFL6Ms+FY22YIU5ecYKY5+UBPNLgPGPfmNiluUhvvPOOzYFQBnTDDhFyiM9KrLAHMpStzBN49uAeVqKVCruyC/9yPNUKLw1iogo8puEqR8c3/TgSkXZL3P3zH8zxuK5zSqVvLDVVlvFww8/PPMNUaSHnQP6kqSZOsnRlvElYRqI88f57AZp5nzAzQBTJU6OaZpNyq+NI49Jp8dzyimnWJ/yeNMn/jeKRqqYBuQ88L/CwbmWSHk1/6S0DWdNEZbZqkKgI1Mf/M9cykXAfSrKxdNb+x8CsiYYvTM33/3226/iYcNcKBTBbNPbre1BNADrfGo5JSpvhG3Le6r3ZZ9WnyC80xOVMA590AIzJpQpFAgEh0zmeSnnRs94Ew75/ikcLm655Zb5oo4s42GfVyp4GCXnUs4jzm/QcOMnkkRmdqOyVvhilHXAFEHK2iE8KOgT+OIPgTKLQx4PkiTN1El1edChFMmEHjfZZBNbVghw2tzx32bOB5188MEHo6bWzGlRU1DmuJp3Ku70QA466CC7Vjhv/D+4bySHYZwq0zWH8ipm1ihWU1M2avVbYb92nmSNyTZD081LiXhLLAqGe4pL+Qi4UlE+pt6iEMAhkZsDv7WEtwscx/CsR3gY4+inmHPbD+/1omAFwLs7SV/2Sfu28peHJ33TXLwdptbNi4cajIz5B3GxT5oKqgiXK27v5Dpe+DhtkkOhlnUCK5WorSMWgk4JTpY8XNJ5qNWPZuqk/V544YX49NNPRxTmbpOezkfqb7rulJQrcn0NJOF/Jept+2/1pKAS4dNNjKcDCef+9nUYDejm7+IIlIbA22+/bcx98swOOP7p7ahm2+QegMsfxkPqkRcCXwJyK0Boc8cddxjhUNoZ9kY9rDNGvL7sk9ryX0fAEXAEHIHyEXBHzfIxHfItaq7ZMCChVj2Fggp40aNQ5GXXXXcNmus2xyrxGgTNpeY311zuyz41G/JCR8ARcAQcgX4h4EpFv+DznWshgKc/QshXX0TzvEGOmUFTJJZXolZESLHdvuxTbMPXHQFHwBFwBPqHgCsV/cPP966BgHwjrJRQ0L4I3A2kmiamnNwRTIn0JH3Zp6c2fbsj4Ag4Ao5A7xBwpaJ3eHntJhBQtIDVwuehrwKfAORCKCgk2cpzONRrsy/71GvLyx0BR8ARcAR6j4ArFb3HzPfoAYEFFljAasAQKW/5HmrX3wyREtk7EVgYldipfuX/benLPj026hUcAUfAEXAEmkLAlYqmYPJKvUEA50ucLBGmLuoFGCmjZVCImNVTiJg5Z9pK7mvHHXcM2267bU2mzb7sk2vaF3tAIM9iikJ35ZVXVu3RUx3OvXJkBOV0MB+ZqgZaXAAFdb6PL774YhBfRd2jii8kwIgKtXhe8O8RyVRQKKYxi+a3ddNyfqy1zplIsIK4XoJyYXQtIyhjUKhyXVixgHJ+RJxXtw4bYBCt5Y9F6nqFOjfc1zf2AwFCSl0cgbIRIJPgrLPOapwTJJPKczWQShp2PNj9dAOxQycCH1gpi0I8/SKLLGJtwQyYpC/7pH39tzEC99xzj+GtW0v2u/HGG1fs1FOdN99809JQk6SMRF3KP2EkYHlCoooGW7AC6VV+DBCSSbGoOhKEZPPMM4+Rsmm6LSNdoqKilDIWVNqCDVYPpao2Ol3Q0/k49thjjYFSirqRP0EwpVwune52dnzlJokHH3ywEcLVSn0O98naa68dSeNOcrDZZ589isK+iieF+wvX6o9+9CMj0eLagw8H8ivI6GC8hV/FpTUIOPlVa3D1VoUACgLMfdy8ILWC7pkbMjeDQ0TNneiC99xzz0gmTG7Yc801V7zxxhur8IOkSCGqMSkVfdmnqtEWFUApXC+bZ18OWXZ7zfRh1VVXNSpubsh8UAIh9MpLT3XITsr5TAIlO9dBkYI5bS/7V06+9mBJY+BX+R6qDkOqeZQN5YioekDddNNNpmjAxin+lUiacK5ThTFXtdPpgkbn46GHHrJ+Q0iWhDHwgO0GMi/o2/fee+8oC6f1s5ZSQaZYCPBQVpFXX33VWDb333//NCS753CPgcUVgj2ylI6Ye2Q89NBD7cO9Z/fdd8/q+0L5CLhSUT6m3mIBARgXodnlxtaI3bCwW9UqbJpJEanaWKegL/vUaaqpYpgNoYgu6w2w7PaaGQTnaqqppoocu540U4cHAJaCvKBYkpOhHaLEXzWViPyxDzjgAHuIoVjUEsrzVjYsayhG0I93k/R0Po477jgbJ9aMJMraaWWaTkhFHf8lDwlKW1GpQCEdf/zx4zrrrFPRRyWoMyp2RZpZOYoJ+19//fVZPawbCBjB4pteTLIKvlAqAq5UlAqnNzaUEcA8i9mVmxoWGs37ViTQUobIeNpppxl9dboJJrx4W5TPQrziiissRwVWnp7aS/uW/UsuEsZA3ox1113XlMHiMZqpQ14QLABjxoyx3aG5pt2yFK5in/LrvMWK0dWOj7WExG7FZGbkoEFBwEzeE+1zahv6Z8Z0wQUXpKKu+O3pfHAOwH755ZfPLBMkhSMXRjeJfG+sn0Wl4rrrrrNylKO8kDSOcfG/QchTg5UivXzwP9pwww1tGwrI8ccfb8v+1ToE3FFTV6SLI1AGAjiQJW4OHMGUwCnopmbOYkpqZSmYSQGved2gpGNBb8B2WJzSZLI1x7KUyhk68nrtldHXRm3ooRlkJg44OV577bVhqaWWCso2W7FLM3U0ZWL7QL+uKY+g6RCjYJePTUVbrVgB/8UWWyxMMskkQW+oQXP1YcSIEZYqOx1PDxhzDp5sssmCLA+BtPR6E7YU2alO/lem9KAEb8b4CutrN0lP54PU5/PPP39QEj6jvlcyroDD4tVXX91Nw6jbF/lE2DZYevMii5qtvvbaa/arqZEgZTaAB6KkfEGKcZBSFaRoBmUEtnL/aiECrdNXvGVHYOghkNJi59/GMckyJZIEfxL9peMee+xhRVg19ABMm82ZDKsGUqu9rGKLF3grJ/toeuNXtE7VEXuqwxs9Y+XD3DZz3O0UEmjx9ou1gj5IQcoOj8MfZbzJ4jtx+eWXW2ZLsmHms+GyA2/O+AZRXw+sHqdVsoO0eaHR+cCBcd5557UxMI70dt/mLjY8XD1LBVNm9BmH2ryIy8bKd9hhByvGKZgxYoXCKoGlDasFac+py5QevjP8H8l2ypSsS7kI+PRHuXh6a0McgVpKAA8jfBTwL+CDsxg3SL05Glo8uFnHcY6HLpEzOJkhtdqzDW38ImMs/fvZz35W96i16vBAxyeBB3p6IJN2OkX81G2sBRswgzPNwTh48CLM0aNAJFM5ZWlOH4fMvPBAZk4+TTOwX97XIl+3G5ZrnQ8iIESdb2nswQHl6Nxzz+2G7mZ9qKdUkOacPnN+8pKUinS+8KFSkkJT0mVdMyVCxHm2znQiygTTegqptfNZ9PnJt+3LfUPAlYq+4eZ7OQI1ESgqAXiqczPkJk+a8/yHmxxCdEdSNIhwyTuZFduredAWF6IEkJZ+ueWWq3ukWnVQllCmUJB4kI8cOdKwwMO/E0L0B+fi/vvvt8PjtMcnLyhCKAzTTDNNvrhieeutt7Z2eAB2qxTPB9FTPEyJoEBOP/10s0BhhRKPSNcMo55SgaWIc8f/IS/nnXeelZ900kn54mwZJR2FFiWCMFTaOOOMM7Ltq6yySrbsC+Ug4D4VuspcHIFWIZDmduWkGMhPkv/IFGt+FD/84Q+DpjuM5EtvxJZEbfTo0a3qUq/bxS8BfwRo0OtJsQ7+GLrRB3GRBFLW68YeFHkQZC0wcimIy9otUorskGkc4s0I4kYI+b4MGzYs4GNB/+vJeuutZ5sgV+pWKZ4PKRFBkVdBlhbr8k477WRZghk7dPjdLvi7IMkPKfU3rcsalooqfjXVEWSNCAsttFBQtItdh+K2sDoQY00wwQQV9X2l/wh0vVKheP/+j7ILWhDhTwWzn94kqtb507sMDgQSkx+OZHrzDZqvN8fLNDocODWXH3D+w6FxookmCjJFB9LGyyxvy6kuv6m9fFm7llF+YJqEAr2eFOvwwNV7T1BUS7aL3pTDCiusYOudeCDj/IpCMe2001ofeNjQDxS6JPxP9VYfNAefiqp+NV8fFDUSZEqv2tYtBcXzoSke65oiYLIuKuTWljtxLrJONLmwzDLLhHHHHbfiXLEr507WppBSA+Sbw+lZVglzkAYPzpv8KOzcUU+cJdn1mN/Pl/uJQDkGj9a0AuEMpkhMeQNdmN/DtK3TZWFsOInhuMZ883TTTWflMA66DGwEIFziHMMiKo/0COunqMqtjPNMSBxTITiTJaczvfnGq666Khs4Tpsptr5We1nFFiyIitpIr/hNAlkVTm16+FhRM3WouOSSSxpZEUyJSWBZzTtLpvKyfxWdEQk3/PDDD61pGDCZ0sjPycNXIGXOmF2TXwXni/OX6mFe53ylMRCWyjQOzn7dIs2cDxxPGVeeeCxNrUmR7ZahxFNOOaWqn6lzu+22m/nB4ISJQMbG8+Hss89OVSp+ce7M84/grMl/DeHZwtQH010u5SLQ1T4V3Jj5Ixx99NHljrpDraV5QZgGi8Kfvttixot99PWeEYDvIPkO4CfBXDZOgvgRwInA9QwdNM5jSSBpYr6bGx60w8TTJxrhWu2l/Vrxm6jP6Sc8Ezi24RuBL0iSZupQl7GjWMgUH/FD4KaOwtRqimseFPSbMYCrwnnNQZYHSVEU9mtKPf0iCgdnzjPPPDOrlhwzGQPnh/9ut0VNNHs+eGBPPvnkUVMBcZNNNrFlJezLxtrphYMOOsg4Jjhv+EHst99+mVJI3/BBwiETAjUYdblfQjmelN18/xUua+PLU8JD080+OAsT8dPNjrb5sQy05WF0WCex64RkMboAAuY6TJaYX4cPH163n9K6g94uLBaZOVFdeGZaJkaZGPS8PPPMM+Gcc84J/GLGZJ6XeW1M0ZjEEPHkh/zUCyZpYvd1k6wwtSkULXDsejDKMco4CGiTmHASbYlO1/pKWV6I5ad+Xoivl8YdfvzjH+eLs2XdQMNvfvMbS9gkz2ebvyb1OHH6ckwyM65CGAOmX4R+Mm+cfikDI0zxLuUgALaYXpOZPbWKaZ1rjOstL8zfY9plfph9i7H49drLt1HmMvPscDswJcN/cKyxqmdJm6mT+sSY8Snhf5z8GdK2Vv7KOTSIWjvwf2As9QR84TBgqob/OPeEvHAv4v/EvD73lm6U3pwPkqoxHcA9kqm5gSb4wXA/g9sFf51awn+JKUbG6NJmBPSH6krBdIlWCgOcIKn7doD2Cuc9Gjgau/4sxo4npcF47TFf5gXuf0xmmAGTSROtFiY23hDzgpmWY0NjS4x+spwU28QUSj1i8nUDNSpqGP3oO29CSVL4E29OeeHNCjbFokBpDdVxvVA+3oB568CsKyc4C42DqZGx0Z/EdbDggguaCZc+kbCHbZh3YTjkzRgeBRdHwBFwBBwBR6C/CPBm1HWCyVdvNPHpp5+28Doegphia0l6SIoprmoz0w35BEJKs20maGKei4LiAHFKXpiX5djJvIYSgkKS+AVS3aQsQKCTF5JK6Q0nK0r1ikoFc5ppDj2rrAXMlZhvOWYtvnqx+1msuSwu+d1smW1pXjzFcLMBcydjUgpnq8eY8vOsVuhfjoAj4Ag4Ao5AHxCotmvqidNpgRoY0zFhbKuvvnqQg1tQnLF98n3DoxmqXc1RhxQult8OJSvUwEmY0sDsJ+edVJT9YiajrbwwTZAXTIVMwTTjLQ1tLJ+iCZz2FCdvNM1QNeNlLgtJ/jC2rHMZZPkwmmSmgOSMVFEH0x4RBXiwa46wYhsrmo8MsmBYOVM99WTiiSeuomCuV9fLHQFHwBFwBByBRgjUd1JotFeLtynpUpDHvB2FOH+Z/4PS21rcu5yksqMzr8YDtxijzByurBxZPRQB5obxoUAxYDkvKCwoGwh8+MQ054VQJDjljznmmIAiIwtIfnO2LNKiQB4H2sLXAl+IWiLP/6ApFNuk6Ztw4YUX2n75unfccYcpHrKeWBgUoVGapsj8SuR0ZsdhDriWMI/s4gg4Ao6AI+AItBOBrrNU8ODnTZ4ERiNHzGOf9JauTHXmeJUAElOfLfK2nRccy3Cskk9EgOQlxfhTH4etogWCfUnyRH2cHYsi7/cg/whzssP6kGLti/Ug+EFhwRmtkWMYTp84GfHBUiH/kcyqkNrMK1ZYXMS6WEFSgzKFJHKltJ//OgKOgCPgCDgCnUKg6ywVRF/svvvuQeFdFZgoL0JQXH+AGU4hprYNRjyEB31eYEmDOU6+BBatkSInmOJQ3L9ZN7BYJCGrHeQpkE8RCVEUGOd+8pOfWJSHHCKD0lsXq9g67TBdg2DtwGrRjMCyKP+JrCqRLgoxtf5QiOUDj3QYChUKZvWSJYJMli6OgCPgCDgCjkA3INBVlgpCt/ATQIHAjyL/UVyy4YV/QHpLJwwUfwpYCHmTLwoWiXw4HKGl+ENcfPHFxapWL1+3WIHjYlWA4lVOjsXNVeuEn4lcpYIZET8JJP1W7fS/AhQrpjvuvfde+zDVgbUChYhlBAUJSwdWHRgAawnhpi6OgCPgCDgCjkC7EOgqSwUcDTyMeVgWBYdE6FjJjcDUQHK2ZGoEJ01FOwT8LVLcMpwAxYe3EgqZ46NIVkxByNMOQ5tdFEVcWBEWDLj0cSBV5EdQpEZ4/PHHg8JYbTvHQooOnFg4xJRoFhO2i92Pn4wzwlYKX4wPxarIV7HtttuGE044IRx11FHmr8G0B5YLEfJY++yTplzwKWGsWFSKDqy0j6Q+Fw5fc/XWW28NrqDUhMYLHQFHYAAjwDMA+niX8hDoGqUCJ0TeznGqxFLB23oSlAMsBDwsEcicxMdgvghMW0DUIwpXe+DjBIkCwEMfvviUQIf9mEIQb0Q44ogjbBoB5YUpFIhveODTbhIS0WABQZj64AFOXYimILDiYhTzXsDRUtTLVo8pG5QclAscO3EkTVM1jC8liWK6Zs011zRyKiwtSSDrUbipJTniOMlZle0oJwhTQER20C5TLbfddlvA5wNlTKyAlhwJZ1LGWOTDZ+oIp1CEffDlqBV5YhVyX2J/NAfVXJEvOgKOgCMw4BEQbbwrFSWfxa5l1OzLOHmY48cAOyGshbUcMvPtMm3AGzvKhVI75zcNuGUY5LBCMC0y0Mcy4MD3DjsCjoAj4AgYAoNKqfBz6gg4Ao6AI+AIOAKdQ6CrHDU7B4Mf2RFwBBwBR8ARcAT6i4ArFf1F0Pd3BBwBR8ARcAQcAUPAlQq/EBwBR8ARcAQcAUegFARcqSgFRm/EEXAEHAFHwBFwBFyp8GvAEXAEHAFHwBFwBEpBoGt4KkoZjTfiCHQhAlCpw00Cw+pAEDLgfv311zW7Oumkk1p5WXVqHqTEQvL9kFwQUjyyHudZcwlBh9iulhCWzqeWjBkzxpL8JbK5WnU6UQY/zfPPP2+h5Ysuumjd/qe+kQ7g2WefDaQJaIavJu3Xjl94fgiTLyZ35JwxRrbDw0O+pXpCXTAphtiTNHKKKaYwxuZ6+3p5PxAQsZSLI+AItAAB8aBEMbDCzR5FataCI5TfpJSJOOWUU1qf6Xfxw5jKqlN+7ytbVFbhKMUgG4P4aKISDWaVxMybbSuOU5mRs3r5BbH22j6ix88Xd3z5xRdfjHPPPXc2HuU2imIOrtkvEehFke5F5SqK559/fhTxX816nSoUoWAcMffIKDbgii4wxjnnnDOK9C+KvC9KUbTfikpaEV9PFJtwFFdRlNIRxS4c//jHP8b77rsvKnFklBIVxWdU3M3XS0LALRW6m7g4Aq1AQA/ncPvtt4f0dt+KY5Td5k033WSZb/faa6+Mhp5jXHbZZfaWz5jIFgxNfH/rlN33fHswz0KrT2I+sgbDHnvuueeG448/PkveRz4fKPcXXHBBY/Jlf6j5R40aZcy2+fZYfvvtt8NWW21VLO74OlmYGceSSy4ZDjjgAGPZvfLKKy3TM4y9+SSJMOmCAVmgSXWQt9x0fCD/68CBBx4Ynnn26YoUA1jO1llnHcsCzTWKwCAMMzHWipSAEqZlrBtg8uSTT5oVZonFlwwTTjih7fPII48EKYzGQGwF/lU+AiUpJ96MI+AI1EBAJlh7exwolgrdnCNvhHlR3pc4zTTTROWjseKy6uSPUfayHphR5vOsWeX2iaLpj0oqaGWi5o+iwc+2p4Xzzjsv6gEUeVvOC+dRtP9xo4026jpLxfXXXx+VpiDf3agHs/VT6Q2ycikcVgY23Sp33XVXXGKJJex6y1sqpCBa37EuJeG6xBKBZU2ZnK1Y6RCsHpgkkcJli0rnEJU/KkpxTJv8twUIkHTLxRFwBEpEQDlq4o033hiVGyYq/4vd5IpKheb6o5LARW6SmGYRbnbK5ZJ9NOdt5bSRyr/88ksra+eXMuPaGOhHPSmrTr32+1uuvDpR1pV4wQUXNGxKvgVmOi9WYiplxx13jMqdY1h00/SHrGEVChR9l6+E9ZM+I6+//ropVUwJMH3VjYLiN9tss0X5H8Xpp5++Yvrj0EMPtfFcdNFFFV1fccUVrRyFAWF/WaaifClsXb4/ccMNN7Rlzq2sNLbsX61DwKM/yjf+eItDGIFnnnkmaG473HPPPeYkttZaa1WhgfmWrLskvSO7LA6EJ554ouWq0Ry3Oc0xtcAUQxJMthdffHFV5t20vZW/ZNudY445LKFeveOUVade+/0pJxEhWYyZuuBTT8hUzHkj829ecPQE+5Q4ML+tG5ZXWGEFczzM90W+I7a67LLL2i9THnqbD5NNNlmQtcbM/0wnSNnI79bRZa5xrvsZZpihqh/yEbGyxx57rGIb40HSeHHglK9I9t8hszPTPzjXkjhyl112qdjfV1qAQOv0FW/ZERhaCGCCVUK3uP7662cD15y+vUklS8W7774blWo5YuZFNAcccarDeQzrBVYOtk8++eSZSRdT/FRTTWUOaFnDbVrAxMzb7S9/+cu6RyyrTt0D9GOD/CPMRK5bp1kqlP24bms4LXIuOCdJvvjiC3OAlAJoRd1oqUh9zf8ytcO1mMaCgyMY8NYupdasZFxjjJdrtNMCrmmagr4ULRVS1q3/c801V0VXpRhZ+Z133mnlUqKiMlWbZQarhBQKs1pIKY5SfO0/pQzUNsWiCJn40EMPVbTnK/1HwKc/+o+ht+AIGAJKT283OKY9khR9KtjGzX2ppZaKslbYhxs7ZXjlI8x5s85NEGGaZIsttrDldn/Jsc36wk29npRVp177/SknEgDTOPiBKVjnfS3yba+88sqRh1Re9GYbjzjiiKxoICgVTz31lCmmsrBk/R5//PFt7GlagA0333yzYbLddttl9TqxwNQMClA+CqWoVNAvpi84h1tvvXWU43DcYIMNbJ0yfGQQlPbNN988yokzyhnVlIizzjrL1lHO8ddAaeea5brgP+hSLgKuVJSLp7c2hBFIznF/+MMfMhSKSgU3RELh8I0oftINH1+KscceOy6//PLWDvPGDzzwQNZmOxcIx+OG30jKqtPoGGVsA3seQLfccktVc8zni88gXnLJJdm2e++91x5AmvqwhxgPsu23397aOOSQQ6wsOQhmO3V44fPPP4+zzz57HD16dEVPcFDkkxcsTChZOOF2UrAuoPSBb/ooYipiXWA9/Z/oLz5I/B8222yzeMYZZ1jI8MiRI+t2H8sfzpwoEYcddpidO/ZLIu6YtOi/JSHgSkVJQHozjsAee+xhN600tQEiRaVi2223NTM8fA9F+fjjj7MiohRwLNQcfyyafLNKbViYbrrpanIB5A9dVp18m61YxhKEUoH5vyg4cDIF9cknn2SbklWCfep98ucs27FDC1xrTG/IP6eqB5j6uZ6KShAKRVHZqNq5xQU4VtbDl/Ldd9+9Zg+OPvpo26+oQOUr77///pnjLcoxCobCTa0KlgusHS7lIuCOmrpqXfqHAOyKOLnlPzjHJdGNt2Kb/sxpk/0q+iHo7TG88847tq43k6A3roo6A2ElOcXdcMMNVd3V34t8IcAAAEAASURBVNbKZppppqCbf9BbU0UdHAFlps3KNCdu9XD0VFhgVt7OBZzicIArOi7m+1BWnXybrVrGKVFhpUEm8KpDaOoqcP5kGs+26e056O244iNLhm0XkZKVTzzxxFn9Ti/g6IiTcOJsoD9vvfWW8XPgGMx1J4tX1k0pUEHKrTnhZoUdWKCPRZylABhPBeUnnXRSVa+eeOKJoIgQc2redNNNq7ZTQLuySgT5UJiTKucfplGuAUT+NQEnV5eSEShXR/HWhiICvClgctWlaR/eXOUpn0HB3CZvQ2znjYmYc4TQNuZJ4Q+AA4A2eGvhjVE3jWz/gbJA+BocB/QfkzlzxMzHM27eCO++++4oxSljecTky9sw8/YiLsrC4Bgvpl7erDBPY5rvhMgT35w0Gx27rDqNjtGXbfBNnHzyyTFZEnC4xEyOk15R0tQHjpo9yaWXXmrns5tCSunznnvuaVM18FWkD74SONnSV8KVRSse8RtJ02xSfm0s+FZ0m3Dt53kq8v2jvziZ8p/hvNYTKRvmn5S2M50iBdlWCYFm6oP/mUu5CPj0R7l4DtnW8DIXM6HdpDDX5/+smJSJXjj44IMr8Enm5eS5zUa9lVgb3PAGosDlMN9889kYMDdDC4xSgdLEeBHM8JhhKedGj3LxhvwoiqJwuKhQyGJx29ZRDiG6aiRl1Wl0jL5sA1PwnWSSSexBwjw8FNu1BKUYxRanzp6kG2m6zz77bBsr4y1+eJAmefDBByPnCydGzisKR96pONXrhl/4JvJKBS8gcFQwLciLB/1uxLeh/B6meOSns6DpVriqRfMwTVTPYbcbxj+Q+zCMzutCdHEE+o0ANMZ6G7SpjtNPPz3stNNOZtaEQlg396CHasUxFllkkSAHKjOxTzvttNk2OdQZ1e4OO+yQlQ2kBb0JWvy/FIdA0qkPPvigikeAvx1x87JgGJVwrfHBK8DUUorFr1WnlWVMfXDsRHFc61hl1anVdn/LwJ3+MeXUCEOm6pi60wO3v4fs+v3Tdcf0oiyD2VRAt3cc2m1ZKIIU9pC/V9TrN8nI+O8wjeLSXgRcqWgv3oP+aORbYA6eBxFEUDJDWy4C5nI1LVAxflEeB+ayN9lkEyMXSmRPkA299NJLQUmBLHcDD2kyRjIXzkOCrJ+I3rSC3mhsmRsIpFIQ3eCbQc4HbijMJSPM/eOroRh2I8exQv9yBBwBR8ARKBcBLBUujkCZCBAnrqvU/AiY+5TDVM3mlZgqM9fiawG1cFGuvvrqjF6YbVD4MldM+yl3w7HHHmu+B5Thn4BvBtMtrB911FFGqgMhDrH6hGo64U0RZV93BBwBR6AcBDz6Q08el3IRwKta856W1VEhW2bir3UEpkWIesAKoQd9UJpwy5yYjw7B6iEinGx3KHyh8s0L62KxtCLqPv/880GpjYOcHC1rI17xWCk0pxw0Dxvkw5Hf3ZcdAUfAEXAESkLAlYqSgPRm/g8BHtxJSDdd5OtP2/iVVSPIEzvgX4EPgawOlsaZOdQkw4cPT4v2W1ynEJ8NZPXVV7dfFArmjGWdCPJ4tzI5rQURHDXsj1X0L0fAEXAEHIE+IeBKRZ9g853qIYBCgXWCmH8sBCgKP/nJT4JCv+rtYgm18Lkg6RF+FcrIWcXjUHfnBhuwgOQFZYTPp59+mi/2ZUfAEXAEHIGSEHCloiQgvZn/j4DY74y4SmFultWR6QgcKxVHXwGRKJBDIhJiw1hjjWV1EikUnt4ujoAj4Ag4AgMLAVcqBtb56urewghJCmw5YFqkxwQTTBBI5Y2gZIifIes/20ShG8RvkZWxoERbtp5Y79JG5clIixb+l634QssQyDOkisMhXHnllVXH6qmOXL+CHHCNMVVZWKv2b3UBx7z99tuDkmxZeHP+eDBM5vufX85fb+xDdBEsmuI/MGbKfDvdskyUFBFXookPxf6nPlKeH+eLL75o049pe7f8ksIcrIvCOeN6ItKLsNFGQt38NGqqS7tEkbm0CIFy/D29laGOAIROEAiRAKgopB/W5WusmpBDIZDSULbqqqtGTUdYGYRZoqS2ckiwkijk1MpOOeUUSwYFkx77LrTQQsZQSb1EdpTPpgkJF9EeiQAHrn/6CDmVS2MEyDkCxvmPQnwrduqpjh4MloZaU2GRpGOzzDKLkYCl81HRWAtWjjnmmIy9lHHMOOOMUQ+T7Egkp8qPL7+sqbusHgyOJIEj2kjcKUaq1G2Mr1IOjNQpjQEm1oMOOigbQ1pQiHXFmCFoY99uEv6nI+YeWUF+Rf/oJync5Tdl+Wg4J/vuu29V1yEx41qF3AuSOa49pQKIkF9BRgfjrRy5q/bzgnIQcEbNcnAc0q3wQCfDIzc0HvR6M8zwGDVqlLH4pZsd2QcJ80S4KcDCCSWvIkEsBFV+EMa8mWfklKOnsejRBvvojdmUA2h2CUuFepl0xmwntfGTTz4ZeSigUFBGtk/SQHMzYh3FguRfrRKouFNmxTKOUXZ7zfQJZU88InZD5qYMHXdSCNP+PdWBxTKfDE1kVIY92VxbLSQNW3jhhSN0zCJly8KQd9111+zQypNh1x3XIwoIHx5SXCM33nij1UMB4prL70dSOJg6u4WRkYfwrLPOamOE8ZNsrCgVjOOaa67Jxsv/iAct5zN9FKmVbe+WBfpG3/OMmiRCg2WTay4J54h6+QRqsiiZ8gjrpqxUkSylKCjKE2Ifws3rJShL7fpv/xBwpaJ/+Pne/UBAoZ+2NwqE/C4s3wepm2sJ5TzUoOalPrkMulG4+aHYQClchpTdXjN9eu6554zng2PXk2bqkAeFN+O8oECSk6HVss8++1Q89GXyN4UGmmdEbKYZz0m+L+QMod88qBGUKR5ceQsYigpl5HXpBrn++ust30e+Lyhu9BHLXxKFXcduVCJS//glwy//H3Ll5JUK8gUxHqxLSbgPYImYcsops+yre++9t9UDkyS8sCBcs+Qg6tZ7R+rvQP91pWKgn0Hvf9cgwIMIsys3P3IrKIqlIuGRIlzspsjbI7lS8oLShAWGN00eWrxx9dRefv8yl9NUEtYfpq5qkYU1UwdLAeb1MWPGWPdeeOEFw6Yshas3Y37//fetL6Q4byQkuMtP8/CWS36WvOUMZQtLAG/O3SBYBotWE4jkuA533HFH6yJKFJY7zgfWIxSiRsm4OjEuFD8wheBODt4VSgWWBsZTvHawhlGOwoCwP1aKlDSN/xF5PhDOrSLMbNm/WoeAO2rqinRxBMpAgCiX5HiKIxhkWzj44Sy22mqrWQpm6Mc1r2s5DJKjGURdmu83B0DSNROOK6uMRc3Uaq+MvjZqg7BeOD5w6oN2HedZZZqt2KWZOomkbM011wx6cw56AARl0AybbbZZRVutXiG3x5Zbbhm22mor+9Q7Hg6M8hPJUr3j+PinV162vC3Dhg3LdtPDOWgaL+BMqFtzVt6pBdJ3TzHFFBWHT46IXEsI60okZnwuegAHJfezUG6ut24RQtC5ZiC4Kwq8M0iR8ybldEnj5ZxImbXQdOorKZ9R90uxtVw7Ytyl2KWVCLROX/GWHYGhhwCOqvq/VrxRYZLFpJvkkEMOsTrJrwOrBpkjk+BMhlUDqdVeqtfqX97u8TFIb7iYpovSUx0sA+DBh7d+5rjbKfj0pIywvKU3Mv+T+hwLRLIiMSVHv8X0WtVlsn+yrWghqKrYoQKcSplqSmNJ3cDicsstt5i1gv5LYUybOvpLBt80TUFHipYKpp/ob95Hh3rrrLOOladMxzgFQ8n/+uuvm1UCSxtWC86XItNsmgQfLP6PpAaoZYWjXZe+I+DTH33Hzvd0BKoQqKUE8FAjFwn+BXxwFss/rJJzIM6APHTJlYKTGVKrvaqDtrjg5JNPtv7mIyKKh6xVhwcYvg08CNKDHedIzNztEiIBMI2n6RqUhnqKgJhX7SGV+vbee+/ZuHEmLkpSKt59993ipo6vK3zWHJdxTq4nTAvgtMl1iGLYSUEBQAH68MMPs24UlQo2MH1Bf3FE5X8hkj1bp4zpHYTzQe4hlHRZ10yJUKi7rTOdiDLBtJ6yI9t1UfT5sUb8q18IuFLRL/h8Z0egEoGiEkBYJTc9HrqaTqj4JGdAojuSooHTWd7JrNhe5dHas4YSQHRP3nGueORadVCWUKZQkHhwjRw50rDgYdAJ4WHEueBNvSip/yJkyzahFKGEEApbFObteTh1m+Cbw7U0evToHruWoizuv//+Huu2sgLWBZQ+rvX0IUoMxY31FEnF+cBREz8KTaHFM844w0KGua7qCUo6Ci1KhIj17PyzXxIiyFzKRcCVinLx9NaGOAJFJQCFgQdZrbd8bnjJoYyHGqGKaaohORQW2+sUvLytyy+h4eHzdXACRBFhKicJ4Zm8HRPS2yiyJNUv+xcuFc4F4aZFAW/4C4ocGlhZUB54oCUhAgllIz+llbZ18ldkT+aUmA+xbNQflCvweOONNxpVa/k2FDT6Ue9TLwT06KOPtn0aKVAi2Mscb7GGoGDIx8nGhFLfKQW35aB28ADuqKkr2cURKBuBxOSnN3XLlnr55Zeb42U6Dg6c8koPUizMOU0RBoHka3fffbclQWM5L6m9fFm7lqUABD14wuKLL173kMU6sBnqvmaU7WknPZwDToUI29stMrMHKTRBykDVoa+66ipzkKWPedGbrOWKEXlSVkzGW3LZsK2bBEdHTS8F+ehk3cIRs3gtpY04A+uBHqaddtpU1JFf+iilreIjBSDIMmZlIsKr6pfIx4IiQoKmRIJClKu2U0C7skqYgzTXJ+dffhR2DbCdbMrpemTdpSQEOqjQ+KEdgUGHAARD+muaeZbQuBtuuMH4ECibbrrp4nHHHWdTITiT8eaMKL171EMtw4L54OS0Vqu9rGILFghPhPQqT2AG5wFObbwJI83UoR7Mp3A+fPzxx6yaQNLUDudA+CaYckrHxnKCmRwnvaKkqQ8cNYuCf4sy3caddtop26QoEnMkZDqrW0S5dcyiouga46zgd7vttjPLENMb9Pnwww/P/BYULWFcELCFdqNgVag33UafJ598cru+GoXFwoeCT08SplP4ryGEbTP1kbdApXr+2z8EfPqjf/j53o5ABQKYxpPvAHPbOPvhFIeZFbM/ysU888wTcR5LAikRJnZueJAV4ZCWaIRrtZf2a8UvShCmffoJzwQmfnwj8g/QZurQN8aOYgH7JP4M3NRRmHigtVqSYybHBlfm4eEAqSWYzzk3OHXWEh7KmOhpE8p4lEMeSt0iyqtj54tzVvyAOQ9OziPbuM4U3mwOw900hiKW8E3klQr+B3BUQF7GuTjzzDONCK+4X1pXfg9TPPLTWdB0K1zV6MzhrqjnsJva8N++ITCM3XSxuTgCjkBJCPCXwvRaNCvrBmfTHfIrqDgSfBCkaYe3gn3lrFmxvV57FZVKXNENPMBlwJQMnAFkkC1KM3XSPkzxiPjKTO2Y29slogUP8BfMNNNMIfEZ1Do2/ZO1IkhZqLXZyjDPwzHCrx54Yfjw4XXrdusGOcsGUZZb/zm3A0mY/iNzsfL2VP2vao2D/xJTjEyjuLQXAVcq2ou3H80RcAQcAUfAERi0CFS/ggzaofrAHAFHwBFwBBwBR6CVCLhS0Up0vW1HwBFwBBwBR2AIIeBKxRA62T5UR8ARcAQcAUeglQi4UtFKdL1tR8ARcAQcAUdgCCHgSsUQOtk+VEfAEXAEHAFHoJUIuFLRSnS9bUfAEXAEHAFHYAgh4ErFEDrZPlRHwBFwBBwBR6CVCLSVwQVu+jyHfisH5m07Ao6AI+AIOAJlIaDsweH73/9+Wc0N2nbaqlSQ+AXmOhdHwBFwBBwBR2AgIaA8NgOpux3rqzNqdgx6P7Aj4Ag4Ao6AIzC4EHCfisF1Pn00joAj4Ag4Ao5AxxBwpaJj0PuBHQFHwBFwBByBwYWAKxWD63z6aBwBR8ARcAQcgY4h4EpFx6D3AzsCjoAj4Ag4AoMLAVcqBtf59NE4Ao6AI+AIOAIdQ8CVio5B7wd2BBwBR8ARcAQGFwKuVAyu8+mj6UIE/vSnP4Vbb721C3tW3aVHH320uvB/JR999FH4/e9/Hx555JHwzTff1Kz3z3/+M9x3332BdvpTp2bjfSikz7fffnt48MEHQ4yxZgvN1GlmXDUbb2Phf/7zn/DMM8+Eu+66K3z55ZcNj9zoPDfcsYUbm+0//6fbbrstfPDBBw17w/X3r3/9q6oOY//zn/9cVe4F5SDgSkU5OHorjkAVAu+//35YYIEFwqyzzhpOP/30qu3dVHD33XeHJZdcMiy77LI1u3XccceFeeaZJ1x99dXhxBNPDFNPPXW4+OKLK+recsstYcYZZwxXXXVVGD16dJhqqqnCH/7wh17XqdihjysoEIcffngYOXKkKUKHHnqonYcXX3wxa7GZOlRuZlxZox1aeOmll8J8881n411++eXD9773vXDwwQdX9aan81y1Q5sKmuk/CsI666wT1ltvPVNauVa33Xbb8N///reilyiJm2yySZhhhhnCdNNNF/baa6/w/PPPh/vvvz9ss802Yemllw4oMC4tQkB/LBdHwBFoEQJikOX1OK622motOkL/m7388svjr371qzjRRBPF8cYbr6rBhx56yMZwzTXXZNt23XXXOM4448TPP//cyj755JMoCuNIeRLd8OMkk0wS//KXvzRdJ+3b318pPNbnxx57zJr6+uuv40ILLRSl6MTPPvvMypqp08y4+tvX/u7/1VdfRSmucbvttotXXHFF3Hrrre08ct3lz1lP57m//ejr/s32/8gjj4xitYxvvvmmHerVV1+1ce6///7ZoWVRilJso5Te+Ne//jX+4x//iCPmHhmlVNpn9tlnj7vvvntW3xfKRwCToIsj4Ai0CAGZYLteqUhDX3DBBWsqFbJS2BjuueeeVDVecsklViZTtJXpbdDWZX7P6jz88MNWdsQRRzRdJ9u5nwtzzTVX1Nt6RStnnnmm9ee0006z8mbqNDOuioN0YEU5KeJuu+1WceQDDzzQxqo384pyVuqd56qKbSpopv+a6ojjjz9+lKWiolcrrbRS/O53v5spinvvvbeNmzaTrL322rb43HPP2TUhS0ba5L8tQMCnP1pkAfJmhy4CzL/fdNNN4ayzzgp6m6oJxIcffhj0VmnTIphmEfLiMP+fPmnelznkVKa3uprttbJwzjnntOZlzQhffPGFLTM+zMszzzyzrd9x+51Blo6gB3XWFczxsnyESy+9tOk62c79WJBVIoAZ/cnLiBEjbJUpgGbqULmZceWP0YllMD7ggAMqDr3RRhvZ+re//e2K8m5caab/spYFWcXCYostVjEE1j/99NPwu9/9zsq5LpmaW3311W1dVqmQMGAaRFaNMOmkk1a04SvlIuBKRbl4emtDHAEc5eaee+6gt3qbt11rrbWqEOHGx7zu448/HmSSDjzs8FMYNmxYOP/884Pevmwe+Fvf+la2Lxl+8WHQi0VW1q4F+jr//POHO++80/wutt9+e5vTxr8CYX76T6+8HKaYYgobQ+rX2GOPbTdwmav//0O8hzpljQ0cv/Od74TXX389/O1vf0vdCZNNNpkt059m6jQzrrL6nHWyDwsrrLCCYZ/fNSmk9Xxk8nU7vdxM/1N26ymnnLKiu/jtIK+99pr9cm4XXnjhkP47J5xwQlh33XXDmDFjTMHfZZddrJ5/tQ4BVypah623PMQQ4O13gw02sAfw8ccfH7iBnXHGGRUovPfee+EnP/lJOPXUUwN18GLnAcibJg+x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zhAwBAwBQ8AQqA4BYyqqw9rOZAgYAoaAIWAIdGkEjKno0sNrF2cIGAKGgCFgCFSHgDEV1WFtZ+qmCLz++uvunnvu6RRX/69//StXP99++2132223uWHDhtXU//HHH91XX30V/V555RX3xBNP1NSJb2S1E69TxHq96yJ2zsMPP+yo8/vvvzc83b333uu+/fbbhvU6qgL4jxkzpu7p6+FR98CSdjIG8fsmvh5OmadOqMuSsfz555/jRbrOtb/zzjstyq2gGASMqSgGR2vFEGiBwMcff+yWWGIJN++887oLLrigxf5mKnjwwQfdCius4FZZZZW63brrrrvcoosu6rbZZhv35ZdfusUWW6ym/jrrrOOmnnrq6LfQQgu5qaaaqqYOG43aaXFAGwsaXdfdd9/t5pxzTnfDDTe4K664ws0000zu2WefzTzbkCFD3Nprr+1eeOGFzDodtePrr792xxxzjJt99tndLbfcktqNRnikHlRy4W+//abPSPy+ia/zHOWpE7rJfbn11lu7OeaYw/Xq1csdcsgh7qWXXnKPPPKI23nnnd1KK62k7YX6tiwWgUrDdBfbdWvNEGhuBGaccUY3fPhw16NHj6bu6PXXX+/efPNN9/zzz9ft5+GHH+7OOOMMd+KJJ7rDDjvMjT127Zzk6aefdm+99ZY7+OCDo3Z4qc8333zRNiuN2qmp3I6NRtf1zTffuB122MFttdVW7txzz9Uz8fFaffXVHRKW6aefvubs77//vtavKWySDSREAwcO1Bl4lhSlER4ddSl33HGHG2eccfTjP91000XduPbaa/Ue4zmCSWpUhwO/++4799e//lUlFKNGjXITTjihW365Fdxkk02m7T755JNu9913d3PNNVd0HlspGAFvZAgYAqUhICJYL4+sX3fddUs7R1ENL7nkkn7iiSdOba5///56HcJMpO6nUHL7+PPOOy9zPzvytFO3gTbszLoumcHqNQkzFbUqqhotO+GEE6IyVhjHlVde2W+55Za6X2a9NfubZUMkQNq/U089NbNLWXhkHlDyjgMOOMALE1dzlj/++MPPOuus/qSTTtLyPHWoeOihh+r133rrrVF7G220ka5Lmgg/zTTTeJFkRPtspXgEXPFNWouGQPdGQGaK/vbbb/cXXXSRf+211/Qll2QqPvvsM3/dddf5888/37/44osKGC87sVGIfmJvoOW0EcplRloauFkfG5E++PHHH9/PNtts/tdff009/xtvvOHHG288L7NJLyoPz0f5hx9+qKmbp52aAwrayLqu3gv38ZNPPrnnAxbol19+UcZKpCuhSJeDBg3ye+65p7/yyiubmqkQdU6nYypqgP5zIzB33PtZlFaHcZtlllm8SJz0MLHD8FtssYWur7nmml4kbVnNWXlBCNTKLwuWglhzhkB3QwAVwsILL+weeugh1dtuuOGGLSBA3IteF3WBMBaud+/e7qyzznJjjTWWu/zyy528/FQUjLg3ECLbq6++mklAKKpsicpDPrZqJ7H++uur6HjjjTdWVUfoBIZvyy67rNpPkDjw6KOP1ut67733QhVVnTRqJ6pc8gpqjtfHvKYqDnAPJIyRqqvefffdCOvRo0cr9qeffnqoZsuSEbjxxhvdAgss4OaZZ57MM6XVYdyWWmopVZVw4Jlnnuk22WQTh3GtML5un332yWzPdhSEQEHMiTVjCHR7BJjlzj333KoGCGA88MADNZKKDz/80E8xxRT+/vvv1yqiA9aZseh+PdILpBzsF92ypz3op59+8mJA6L/44gvdLusva0a/4IIL6jUw4xOGSCUs9A9VCdcXJ2b9zJaRVsgryq+44orR7ta0Ex1UwEradYlHjvZPMk+2OIN8zHTfJ598otIWYRK9MIBazyQVLeAqvIB7CKmYGJ1mtp1VRwyNvRgSe6RiSCWEoVCpBWMqTIg+UyeffLJffvnl/TLLLOMff/zxzHPYjrYhYJKKgpgza8YQED2uuvKtuuqqERjyUY3WWRG1iMNAcMCAAU509G699dbT/cI4uKeeekoNypBKCIOhLpvsxEhttdVWU0mBVq74T9QwThgIh+Ec/cWw8R//+IcT9YZKWuLdYdaPd4S8rJ18GNzIkSOdfJy1SmvaibdZxvqkk06qzSaNTePnwiURg9TNN9/ckfbaqBoEeA6QcG266aaZJ8yqgzRv/vnnd3379nUYr2Kcetlll7kpp5zSIWXj2TzllFPcaaed5gYPHuzExifzHLajbQiY90fbcLOjDIEWCATvCZkZt9gXCngZTjvttCqODWVhiegdEt29qkN46Ynxo37AcRXsKJpooon01HF1DIwDjAZi5TTio83HGNUJYucZZpjBtaWdtLaLKKM/9B83zCTB9Im0SPvNR0rsXiLm6bHHHtPq9913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88UXX7ghQ4ak9o57NLxj4xW49nfeeSdeZOtFIiAPmVHJCPz000/+xBNP9JNNNpmfbrrp/LrrrutXXnll3Z5zzjmJBuY//fTTknthzVeNwEcffeQXX3xxHV/GvJnpgQce8Msvv7yfeOKJU7t51113+Wmnndbvvffefo899tD7+JlnnonqCnPgjz/+eC8RB/3hhx/uV1ttNT/33HP7l19+OarDyqBBg/xEE02kmHDfc//LC76mTls3/vOf//ijjz7aTz755P7UU09t0Yx8/P2iiy7qV1llFX/wwQf7eeaZR59DSR+gdSWFgJ9xxhmjvtG/+I/xTBLPdu+F+/hVV101uavS7VdeecUvvPDCUX8Zx6OOOqpFHxqNc4sDKirI2/+HHnoousYwNltttVVNL4XR8JTNNttsfoYZZtCxfvHFF70wxH6nnXbyE044oRems+YY2ygOAWYTRiUi8P333+tLhwegX79+Xrjn6GxvvfWWl9Dl+pC8/fbbUbmtdB0EZFal49vMTMV1112nTC8f4zSmgo8uDMW+++4bDcwuu+zip5pqKv/JJ59o2dVXX63X+dRTT+k2H+i//vWvfqaZZvLfffedlt1xxx16vz/xxBNeQh77XXfdVY+JtxudoJUrP/zwgz/00EP95ptvrm2mMRVrrLGGX2ihhaKWYeTHH398f+SRR2rZ0KFDlSk65JBDlPmBAeLXp08fZUaiA2MrMCc82x3JVMDYzDvvvIrn9ddf73fccUcdR/p18803R71tNM5RxYpX8vafbq2zzjp+yy23VEYB7Bmr1157LeqxSJqUUYW5FUmU//bbb/X9e9xxx3l+888/v99///2j+rZSPALGVBSPaU2LPOA83CzTiBt/mmmm8XDS0DHHHKMPDQ/ODjvskJujZlaSnBXSHh+EPffcM2qTjwEMzH333ee32WYbLR88eDBVWxCzAvrB76yzzmqx3woaIwATyfg3M1MRrmLJJZdMZSp4cXMNIloPVT2MAWUnnHCClvGx5j6O00UXXaR1zj//fC0+7LDDIiaEAhguPurrr79+/LB2rSNRoV9pTAWSwpVWWqmmfaQpPAfQAQcc4JkxxwkJzKyzzupPOumkeLGui5pBpTvs70im4tZbb/X77bdfTf9glMBh55133mDfJgAAQABJREFUrilnI2ucW1SsqCBv/0VlrEzqL7/8ktkzGEuu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NqpDAIkaklti+WQRzxIqRu5Bo2oRMKaiWrztbIaAIWAIGAKGQJdFwGwquuzQ2oUZAoaAIWAIGALVImBMRbV429kMAUPAEDAEDIEui4AxFV12aO3CDAFDwBAwBAyBahEwpqJavO1shoAhYAgYAoZAl0XAmIouO7R2YYaAIWAIGAKGQLUIGFNRLd52NkPAEDAEDAFDoMsiYExFlx1auzBDwBAwBAwBQ6BaBNKj15TUB0LiWrjnksC1Zg0BQ8AQMARKQ4Bw8xNOOGFp7XeVhitlKiTzYk1Soq4Col2HIWAIGAKGQNdGgDxOxlQ0HmOLqNkYI6thCBgChoAhYAgYAjkQMJuKHCBZFUPAEDAEDAFDwBBojIAxFY0xshqGgCFgCBgChoAhkAMBYypygGRVDAFDwBAwBAwBQ6AxAsZUNMbIahgChoAhYAgYAoZADgSMqcgBklUxBAwBQ8AQMAQMgcYIGFPRGCOrYQgYAoaAIWAIGAI5EKg0TkWO/nSLKj///LP7/vvvG17rpJNO6sYff/yG9axCcyPw+uuvuzfffNOtvfbazd1R6d2//vUvhz9+Gv3444+OX6BPP/3Uff31127ppZcORe6zzz5zo0ePdtNOO63r3bu3G3vs/81bfv/9d/fNN99EdeMrE000keNXFtW7rv/+97/uueeecxNMMIFbfPHF3TjjjNOiG3nqtDiogwq++uor9+WXX7q55567bg/uvfdet8wyy7jJJ5+8br2qdnrv3b///W/3wQcf6DhMN910LU79xx9/uOeff95x7y2xxBJu6qmnblEnFHC//fbbbzquoYwl98L000/vevXqFS+29aIQkIE0qhiBZ5991m+00UZexlB/M844o++9cB/9zTfffH6yySbT8muvvbbintnpikTgo48+8vKR0rFcd911i2y68LYeeOABv/zyy/uJJ544s+2VVlopume5d+Xj61955ZWo/qBBg7wwBlGdOeec07/zzjvR/vPPPz/aF+79sNx9992jekWuNLquu+66ywsD5Pfee2+/xx57ePmQ+WeeeaamC3nq1BzQQRsSrdgfffTRXpgEf+qpp9btxfXXX69j8cgjj9StV9XOd9991y+66KJ+lVVW8QcffLCfZ555/Morr+yFaY268Pbbb/vFFlssuoe4/0444YRof1j54osv/FZbbeVnm202P8MMM2h7L774on/44Yf9Tjvt5CWAlR8zZkyobsuCETBJhbzVqiZ5eNxNN93kpppqKscM6Oabb66Z7SHJ2HDDDd2vv/5addfsfAUiIMyiGz58uOvRo0eBrRbflHxgVJLCDDCLnn76affWW285eeFHVZjpCROs23feeacbOnSok4+4m2WWWdyAAQPcpZde6s444wx37rnnap1LLrnECTPtllxySTfuuP//6mFGLR9AJ0xX1G5RK42uC6nJDjvs4OQDFPWRmS3hmIVZ0tlsnjpF9bc97SBBGjhwoBMmzn377bd1m3r//ff1uutWqnjnrrvuqu+7+++/X8982GGHuVlnndWddtpp7sQTT9SyLbfc0v3tb39zwuSpZGm77bZzxx13nNtzzz0jicV3332nkjbeoaNGjdIImMsvt4KTiZq28eSTTzphYN1cc81V8RV2o9MVzKRYc61AYIEFFlCu+6mnnmpx1IMPPujlg1RTzqzirLPOqilLbohoz8uL0suL26+22mp+l1128QcddJCXh1Or3nPPPV4ezszfgQcemGzSttuBgIhgdYybXVLBJXLPZEkqNttsM3/eeedlIiEfAf/JJ59E+0UE70V159dff30te+ONN1QaEFX4c+Wyyy5TydxPP/2U3FXYdtZ1HXLIITo2wkxF53riiSe0LMyA89SJDm6CFaQq8vnKlFRwPyIB4B1AvWaRVCCdRRIWJ1Hf+G222UaLRC3ikYTFCYkG14DkN9Chhx6qZbfeemsoUqkwG7QxzTTTeGFko322UjwCrvgmrcW8CASmQmaBNYc89NBD/uOPP64pY4MXO+I84cJb7KPg2GOPVdGezA69SEA8L5A77rhDxbv777+/HoNYFNXLCy+84GFmeCj33XdfLzp/f/XVV3seZKP2ISAzRX/77bf7iy66yL/22muKcZKpENsDf91113lUAohmIV52w4YNi36IeyHaCOUyI9WyMv6yPr4wBOONN56qOxZaaCEVOf/www91u8D9i3ha8v3UrbfmmmuqqLpupXbuzLouVI6oCkRPH53hl19+UcYKNSSUp050cBOs3H333Xq/Zak/+DDLzN5feeWVWq9ZmIqlllpK7xex81AUX375Ze3fVVddlYkq14GaJP4+ZNxEUuZF4qTH8R7cYostdJ17jXejUbkIGFNRLr51W09jKsJMQgzHao4VkaVy2TABvBCSJOJnfQjRqSaJ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PfIOJ5988jD99NNXhPtFgxAQhx5ODULgyCOPjL169cJDSvzLX/4S55xzzthn7r5xrrnmitKANXzWWWdtUG6eTKsj8OGHH8b5559f3/sqq6zSssUdMGBAlAFIy0nbnWmmmeLbb7+dlXfgwIHZPe6nv3/84x8ar0wcItbLK8u0wSeXX365lvvBBx/MUpYJQDz88MPj1FNPHcVbYlx22WXjLLPMEv/1r39lcezknnvuiYsttlgca6yxLKilji+//HKce+65s3dDOQ866KCsjO2pa/ZQF57UKz9FKROHeMJUxQ022CBOO+20cYoppoh77rlnfPHFF+MDDzwQt9xyyzjGGGPE119/nahOTUAgNCHNkTrJY489Vj9sOqg80THNOOOM+WC/HoER+OKLL7Q9tCpTcdNNN8WFF144Pvroo/G9996L22yzjZZ35513zt4Kg9Uaa6wRjzrqKGUKYAwYhGEubrzxRo1XJk6ZvLJMG3jy7rvv6kBCeVOm4uKLL9Y6PPHEE5rbL7/8EkUKEaeccsr47bffZiW47LLLIhMGcdHckkzFjz/+GHv37q3vDubp73//u5aT+l5zzTVaj7J1zSrdhSdlyl8mDkUWj83KFMMoikQsfvPNNzqxO+ywwyK/OeaYI+66665dWLuRLytXf8iX10gSpkGTE0lFm2SXWmqpIBx0Fn7yySeHxx57LLteddVVwyabbBIefvjhcN5554UffvghTDLJJOGEE04IjzzySDjnnHNgAjU+Ij35QFQUu+SSS2rYoYceGl599dUsvfQEsfZpp52motH99tsvSKeZ3RZuPohUJZA/5xCi4gsvvFDPi/6k4w0nnnhi0S0PSxBodVWXDLLh+uuvV3EwxRamOAwePDiIpEJrgdpGZuhBJBF6bX+DBg0K4447blh++eVVtVMvDs/Vy8vSbuQRdeTmm28eVl999XDFFVdUJC3MkX5fCyywgIb37NkzbLHFFmH77bfXtr/jjjtquH2zwkAFmfFWpNEKF3yrK6ywQjjllFO0OOuvv37g++zfv38YOnRoWGuttULZunZHfcqUv0wcyn7EEUdoe6RN0+dBM8w4faBv5N3Rjg855BAN978mITDy8VHNrfFVV12ls5+imSmziDxJ56zxEbum1K9fv7jHHntExJZGMohr3LPOOived999ca+99tLrXXbZRaMQd7755lPVi3Hp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9CjMrxGB//nPf7Re33zzTZh88skL86I8jz32WPjkk0+q1qtMOo0ob2fS+PXXX8MLL7wQXnrpJa3HaKON1ia5H374IfAeOfJ7++23wxtvvBF4D61E77zzTnj11VfD1FNPXVEs2uezzz4bnnvuuTDhhBOGscYaq+J+evHbb7+FX375JfTsWemOiTYMVhNMMEEa3c8bhUB0cgQcgaYg8OGHH8b5558/yrcaV1lllabk0YhEDz/88PiXv/xFy0lZ55hjjigDTUXSt9xyS5x00knjjjvuGLfbbrs42WSTxaeeeqoiTr10ZECIxJGBIu67775x2WWXjcJoRfGyW5FOoy4GDBgQxxxzzKxeM800U5RBtCL54447LsqAGrfffvu43nrrxSmmmCJedNFFFXHKpFPxQDdcvPzyy3HuuefO6iqDbTzooIPalGTJJZfM4vCuRx111MizrUQ//vhj7DN337jMMstUFOutt96K8803X1Z+yv7Pf/6zIg4Xn332Wdxggw3itNNOq+9zzz33jC+++GJ84IEH4pZbbhnHGGOM+Prrr7d5zgMag0BoTDKeiiPgCBQh8MUXX2gn2KpMxaBBg2Lv3r3jqaeeGk855ZQ411xzaXk5Gn311VfKUIibfQuKW2+9dZSZYhSphYaVSefiiy/WtEVqo8/ILDIutNBCccopp4zffvttlnYjTm666aa48MILx0cffTS+9957cZttttG80zo88sgjGnbNNddkWXKfQee7777TsDLpZA930wmDMO+QOl5++eXx73//e4SpgGlI6wbuDLQMsvY77bTTuqnU1bOlbJQ9z1QsuOCC8aSTTtI2d+utt2qbhLGAiTASKUyEeYRxFelSFAmVMigikI/8YJh33XVXi+7HJiDgTEUTQPUkHQFDQESw2kG2KlOx6KKL6qBr5f3666+zAYnBGNprr720DiJytmg6WNPx20yxTDowKpNMMkmWBidnnnmmpj1w4MCK8M5e7LPPPhnDQ1owd0hjZKuALOnjjz9e877vvvuysCFDhmiYqKw0rEw62cPddHL99dfHXXbZpSL3Aw88UOux1VZbZeHrrLNObEUmIiugnNx9991xscUWU+lRylSIWiciMUrJmI+nn346C95777213mBitMYaa+gpadD+RN1lt/zYBAScqWgCqJ7kyI0As6Mbb7xRB0zRC2snl2cqmEVddtll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RofT+uG778LJB24fPnjrjbDZboeGBZdaocNppQ9utsRs6WW7zn/66aew9957B9rqJ598EhZffPGw7bbbhlVXXbVqOrSFDTfcMHA02mWXXcIyyyxjlyPd8cILLwz77LNPmGeeecL111+v315nQDj44IPD888/X5gE9+aff/6q9zry3B577BHefPPNijTXX3/9sNFGG1WE2QVxeSZPgwcPDhNMMEE+uO71//73vzDbbLNp37H88svXjT88RyjCulp9wJ/34DR8INB0ScXpp58edthhB/1Q7rjjjnDDDTfoNWFc33bbbeGkk07SsIsvvrgqanTedCS77rpruOuuu8Kvv/5aNe55550XDjjgAB3UyzI0VROTG7/99lu46KKL9IP/xz/+EV5//fXC6G+99VbYYostwlxzzRXoYDtLP//0Yzh8h/XDHVcPDutstVs49dqHw1EX3hz+MsaY4cqzTgjffvN1iNIRGSG4OP+4Q8K7b75qQe0+vvmv58KQ046qeO76waeH/379pTA2D4fXX3ym4l6ti6LyPPXA7eGVZ5/U9O68tvr7rpVuo+9tttlm4bTTTgvffvttuPHGG8NNN90U1l577fDZZ59VzWq00UYLZ5xxhjIhPMPvnXfeqRq/1g0kTjAx1QbCWs826t7jjz+u31Zn0jv88MPDp59+qt/1I4880pmk9Fn6iNlnn12xNYwZeOkvYFyqUUefO/DAAzVdy4vjYYcdFqpJBHn/adzvYJhPPrlDDAV1ufPOO7Vvoc8c0QmmYpZZZqnAjwngTjvtFDbYYIMw99xzh/vvv1/vv/pqx/uzER3HVqxf05mKH374ITCDe+mll8J1112nH50BwawfJoNGQ8dO3GpEJ36hDNR//etfq0XJwsnv+OOPz647e/LYY4+FUUcdNSBJqUXXXnutzm5//vnnWtFK37vr+kvCx++9HWb567xhvsWWDaP2HDWMN+FEYafDTgrz/V/bGfHQK84L999yVfjx++9K55FG/FYYh9MP2z188HblbG2amX+XAowpEpEZZq2Pv6VZVJ6ppp8ljPaXv2iU2fosaFG77fjVV1/prJoCzDHHHMpYcM5AUu89TjbZZKFfv35E7xTRVs8999zw3//+t1PpdPThzz//PKy33nrhX//6V0eT0OcYCKBxxx03zDfffHremb9evXq1YXSQDs0444z6PVZLu6PP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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Below is the statistics of the datasets in LLM-AggreFact:\n", + "![image.png](attachment:image.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.llms import Ollama\n", + "from trulens.core.session import TruSession\n", + "from trulens.providers.openai import OpenAI\n", + "\n", + "session = TruSession()\n", + "session.reset_database()\n", + "\n", + "gpt_4o = OpenAI(model_engine=\"gpt-4o\")\n", + "bespoke_minicheck_7b_provider = Ollama(\n", + " base_url=\"http://localhost:11434\", model=\"bespoke-minicheck:7b\"\n", + ")\n", + "\n", + "\n", + "def gpt_4_groundedness(doc: str, claim: str, gt_score: float):\n", + " score, cot = gpt_4o.groundedness_measure_with_cot_reasons(\n", + " source=doc,\n", + " statement=claim,\n", + " use_sent_tokenize=True,\n", + " filter_trivial_statements=True,\n", + " )\n", + " return f\"{score};{gt_score};{cot}\"\n", + "\n", + "\n", + "def bespoke_minicheck_7b(doc: str, claim: str, gt_score: float):\n", + " prompt = f\"\"\"\n", + " Document: {doc}\n", + " Claim: {claim}\n", + " \"\"\"\n", + " response = bespoke_minicheck_7b_provider(prompt)\n", + " score = 1.0 if response.lower() == \"yes\" else 0.0\n", + " return f\"{score};{gt_score};N/A\"\n", + "\n", + "\n", + "EVAL_NAME_TO_FUNC = {\n", + " \"gpt-4o\": gpt_4_groundedness,\n", + " \"bespoke-minicheck:7b\": bespoke_minicheck_7b,\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from trulens.apps.basic import TruBasicApp\n", + "from trulens.core import Feedback\n", + "from trulens.core import Provider\n", + "\n", + "\n", + "class CustomTermFeedback(Provider):\n", + " def feedback_score(self, output) -> float:\n", + " return float(output.split(\";\")[0])\n", + "\n", + " def gt_score(self, output) -> float:\n", + " return float(output.split(\";\")[1])\n", + "\n", + "\n", + "custom_term_feedback = CustomTermFeedback()\n", + "\n", + "f_gt_score = Feedback(\n", + " custom_term_feedback.gt_score,\n", + " name=\"GT Score\",\n", + " higher_is_better=True,\n", + ").on_output()\n", + "\n", + "f_feedback_score = Feedback(\n", + " custom_term_feedback.feedback_score,\n", + " name=\"Predicted/Feedback Score\",\n", + " higher_is_better=True,\n", + ").on_output()\n", + "\n", + "\n", + "CUSTOM_FEEDBACK_FUNCS = [\n", + " f_gt_score,\n", + " f_feedback_score,\n", + "]\n", + "\n", + "\n", + "def run_groundedness_experiment(\n", + " func_wrapper, dataset_df, app_name, app_version=\"dataset_name\"\n", + "):\n", + " tru_wrapped_app = TruBasicApp(\n", + " func_wrapper,\n", + " app_name=app_name,\n", + " app_version=f\"{app_version}\",\n", + " feedbacks=CUSTOM_FEEDBACK_FUNCS,\n", + " )\n", + "\n", + " for i, row in dataset_df.iterrows():\n", + " doc = row[\"doc\"]\n", + " claim = row[\"claim\"]\n", + " gt_score = row[\"label\"]\n", + "\n", + " try:\n", + " with tru_wrapped_app as _:\n", + " tru_wrapped_app.app(doc, claim, gt_score)\n", + "\n", + " except Exception as e:\n", + " print(\n", + " f\"Error {e} in run_feedback_experiment row {i} with doc {doc} and claim {claim}\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for eval_name in EVAL_NAME_TO_FUNC.keys():\n", + " eval_func = EVAL_NAME_TO_FUNC[eval_name]\n", + " for dataset_name in llm_aggrefact_df[\"dataset\"].unique():\n", + " print(f\"Running {eval_name} on {dataset_name}\")\n", + " sub_df = llm_aggrefact_df[llm_aggrefact_df[\"dataset\"] == dataset_name]\n", + " run_groundedness_experiment(\n", + " func_wrapper=eval_func,\n", + " dataset_df=sub_df,\n", + " app_name=eval_name,\n", + " app_version=dataset_name,\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "\n", + "csv_path = \"../results/LLM AggreFact groundedness.csv\"\n", + "df = pd.read_csv(csv_path)\n", + "\n", + "# Aggregate metrics by app_name\n", + "aggregated = (\n", + " df.groupby(\"APP_NAME\")\n", + " .agg(\n", + " total_tp=(\"TOTAL_TP\", \"sum\"),\n", + " total_tn=(\"TOTAL_TN\", \"sum\"),\n", + " total_fp=(\"TOTAL_FP\", \"sum\"),\n", + " total_fn=(\"TOTAL_FN\", \"sum\"),\n", + " )\n", + " .reset_index()\n", + ")\n", + "\n", + "\n", + "def plot_confusion_matrix(tp, tn, fp, fn, app_name):\n", + " matrix = [[tp, fn], [fp, tn]]\n", + "\n", + " labels = [\"Predicted Positive\", \"Predicted Negative\"]\n", + "\n", + " plt.figure(figsize=(6, 5))\n", + " sns.heatmap(\n", + " matrix,\n", + " annot=True,\n", + " fmt=\"d\",\n", + " cmap=\"Blues\",\n", + " xticklabels=labels,\n", + " yticklabels=labels,\n", + " )\n", + " plt.title(f\"Confusion Matrix for {app_name}\")\n", + " plt.xlabel(\"Predicted\")\n", + " plt.ylabel(\"Actual\")\n", + " plt.tight_layout()\n", + " plt.show()\n", + "\n", + "\n", + "for _, row in aggregated.iterrows():\n", + " tp = row[\"total_tp\"]\n", + " tn = row[\"total_tn\"]\n", + " fp = row[\"total_fp\"]\n", + " fn = row[\"total_fn\"]\n", + " app_name = row[\"APP_NAME\"]\n", + "\n", + " # Plot the aggregated confusion matrix\n", + " plot_confusion_matrix(tp, tn, fp, fn, app_name)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "trulens", + "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" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/benchmark/trulens/benchmark/benchmark_frameworks/tru_benchmark_experiment.py b/src/benchmark/trulens/benchmark/benchmark_frameworks/tru_benchmark_experiment.py index 471875c5a..eeb33f97d 100644 --- a/src/benchmark/trulens/benchmark/benchmark_frameworks/tru_benchmark_experiment.py +++ b/src/benchmark/trulens/benchmark/benchmark_frameworks/tru_benchmark_experiment.py @@ -141,9 +141,7 @@ def run_score_generation_on_single_row( log.error(f"Row generated an exception: {e}") traceback.print_exc() - return ( - 0.0 # hack to make sure we always return a value for each row - ) + return float("nan") # return NaN to indicate an invalid result @custom_app.instrument def __call__( diff --git a/src/core/trulens/core/feedback/feedback.py b/src/core/trulens/core/feedback/feedback.py index 0f4675956..1b47d7b08 100644 --- a/src/core/trulens/core/feedback/feedback.py +++ b/src/core/trulens/core/feedback/feedback.py @@ -946,7 +946,7 @@ def run( else: assert isinstance( - result_val, (int, float, list) + result_val, (int, float, list, dict) ), f"Feedback function output must be a float or an int, a list of floats, or dict but was {type(result_val)}." feedback_call = feedback_schema.FeedbackCall( args=ins, ret=result_val, meta=meta