{
"cells": [
{
"cell_type": "markdown",
"source": [
"**이 노트북은 farm-haystack 0.9.0, torch 1.8.1 버전이 필요하며 현재 코랩 인스턴스와 호환되지 않습니다.**"
],
"metadata": {
"id": "7gOI3IlanPQU"
}
},
{
"cell_type": "markdown",
"source": [
"이 노트북을 코랩에서 실행하려면 Pro 버전이 필요할 수 있습니다."
],
"metadata": {
"id": "0yd2u-tZv357"
}
},
{
"cell_type": "markdown",
"metadata": {
"id": "MzeRO7j5z41N"
},
"source": [
"
\n",
"\n",
" |
"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "i3nPMmDHz41U",
"outputId": "97a6ebf5-fd8d-4978-f400-1f3d638c3178"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Cloning into 'nlp-with-transformers'...\n",
"remote: Enumerating objects: 563, done.\u001b[K\n",
"remote: Counting objects: 100% (297/297), done.\u001b[K\n",
"remote: Compressing objects: 100% (190/190), done.\u001b[K\n",
"remote: Total 563 (delta 179), reused 184 (delta 107), pack-reused 266\u001b[K\n",
"Receiving objects: 100% (563/563), 48.83 MiB | 10.77 MiB/s, done.\n",
"Resolving deltas: 100% (278/278), done.\n",
"/content/nlp-with-transformers\n",
"⏳ Installing base requirements ...\n",
"✅ Base requirements installed!\n",
"Using transformers v4.6.1\n",
"Using datasets v1.11.0\n",
"Using haystack\n"
]
}
],
"source": [
"# 코랩이나 캐글을 사용한다면 이 셀의 주석을 제거하고 실행하세요.\n",
"!git clone https://github.com/rickiepark/nlp-with-transformers.git\n",
"%cd nlp-with-transformers\n",
"from install import *\n",
"install_requirements(chapter=7)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8FvoJMWGz41Z",
"outputId": "6b552593-0487-4474-f569-628196bf87ca"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"env: TOKENIZERS_PARALLELISM=false\n"
]
}
],
"source": [
"%env TOKENIZERS_PARALLELISM=false"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lFMHGCzwz41a"
},
"outputs": [],
"source": [
"# haystack의 로깅을 끕니다.\n",
"import logging\n",
"for module in [\"farm.utils\", \"farm.infer\", \"haystack.reader.farm.FARMReader\",\n",
" \"farm.modeling.prediction_head\", \"elasticsearch\", \"haystack.eval\",\n",
" \"haystack.document_store.base\", \"haystack.retriever.base\",\n",
" \"farm.data_handler.dataset\"]:\n",
" module_logger = logging.getLogger(module)\n",
" module_logger.setLevel(logging.ERROR)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "2bsecm0Rz41b"
},
"source": [
"# 질문 답변"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "4e238IyQz41b"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "I2DxvBM0z41d"
},
"source": [
"## 리뷰 기반 QA 시스템 구축하기"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1-rCKMXJz41e"
},
"source": [
"### 데이터셋"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "QhStaRsGz41f"
},
"source": [
""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 99,
"referenced_widgets": [
"dd6eefee0b604dc4ad26235d6650f819",
"88e6e4bb9bad4c778884761f73abe971",
"b527fdc36a964d3091a759631ad4c076",
"747e599ed26444568eb963ae9931b639",
"f19540eca4bb4b1b98d4c714ca9575be",
"f6823486a3a84c50b59f1e76d8017f99",
"441787b1af6145ae83d72f058a160a2b",
"18abb84c6a4145f0b1bf4fa2dae96b5f",
"1381dfaa69d943deab27ca802b39910b",
"3969b4ea396e495691294eeee8c1a8ae",
"8fdb8370e9ec4307883a1b72c5eb694f",
"e3453b02063b4e4c943f685731456e71",
"b185a07760f84dcbba6eb01fb92c8b23",
"2b2f3f2f7be04309903bc5e211011801",
"7a6e5f51e7874b4f8b18afc1392315ef",
"e241b3f75d4f4af2989f946643babcf6",
"3cddbdc3dd13443b85a41fe1ccf9f76f",
"327a6d88210b492fa281630eb7b2bf08",
"8a621c01ed7e4072a6c9733792df4669",
"2696479e59804459b9501732cb11f42a",
"22e46c837abd4f91bdad7aa2077d1842",
"a758c96d91dd4adbb308bf9a342f0c8b"
]
},
"id": "tHcoy_Rtz41f",
"outputId": "2543c957-c065-42d1-d4e6-29eb675a9bf1"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"Downloading: 0%| | 0.00/2.65k [00:00, ?B/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "dd6eefee0b604dc4ad26235d6650f819"
}
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"Downloading: 0%| | 0.00/1.46k [00:00, ?B/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "e3453b02063b4e4c943f685731456e71"
}
},
"metadata": {}
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"['books', 'electronics', 'grocery', 'movies', 'restaurants', 'tripadvisor']"
]
},
"metadata": {},
"execution_count": 4
}
],
"source": [
"from datasets import get_dataset_config_names\n",
"\n",
"domains = get_dataset_config_names(\"subjqa\")\n",
"domains"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 105,
"referenced_widgets": [
"78686951edec41a6b25180eb09c5b2bc",
"48f14a0e808142679ec68037c90adb3e",
"14e5e96a996e49618780e42c84c5cf39",
"acfec96b18bb44008a138e1b3cabdced",
"584c884a5feb4cc78932df22285ed652",
"f80dc73ef35f4b7b869f5c6635dc00a4",
"cd4db1dfed9c4478b4d1bb2af1145a82",
"e5768f5dfa7e443baf7b86cabe3ebae5",
"21629098a07e40efb7a13d0ed47ad33b",
"d195a791db0844d4abae266d2f83056d",
"738749e0da6148e5ac5e0f0299e83311",
"5db206a0abee438eb1ec6999c74480bd",
"5f184d3d805048bb9e44e6e95a22f1d5",
"d5d34c415d2d447489d3ea0b5f2aee0b",
"4587035aeb354708bb763cce4b92209a",
"6205a32e652044f2979d05d404bba652",
"c085f8006b1a4925b4afa25eeb75789f",
"8694452ba3314e95ab9ac6eaaecbdd61",
"680ee1a8ae114bdab3253b7e3b154dba",
"4731f097b63746f5ae875e5fe650212f",
"6b7416c90ee04c448dd2e5dbd16f15c6",
"fef0d6f5b636494e9a183dac7132d6e8",
"b0fce2cc80ec459b9543330b5ccf1dd2",
"6705debc98f54135b64bc68e118b5dda",
"dca5c8ca2d4d4b36a4154615556d2b56",
"4ec9f57b40ca469994a315109b30b52a",
"5fec4a4510904a37a0614d7033765cfc",
"84cd7e2b989147d4a2f8c3a23fe49f9b",
"5645422ff5e947338c937e2d38e45d18",
"f7b865cb9a6c49029091839e5ff617de",
"be1d296522ec4d19a03e82db5414ea85",
"fde367713cac45af841f236092f91da8",
"4968ca28b75e4537b9fbb945227fc52c",
"adfadb17cc894fb0bf9ea985af475cd3",
"eebd0db916ea4e9abd9d173198b19956",
"4e4402cc0ab5473891c49a61b0ac0cfb",
"54f9f04ea1584edba6486eee77449235",
"93da8e233aae4a178bc3f871743c177a",
"92f812dfa94c43b093f4d841f6dd46bb",
"8dd3e5c36d864a7e81c34a5b633117a8",
"6f71202ab76d461c86eea612762e20f6",
"d7ee19d04ca34685a27b6f2857a98521",
"074a94b0f43e447a999394a65a951bbe",
"e05089ee5bff42c4977b7d3c517726be"
]
},
"id": "NeaaFZxez41g",
"outputId": "7f6c17f4-cc7f-48c3-a209-f6ef74563053"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Downloading and preparing dataset subjqa/electronics (download: 10.86 MiB, generated: 3.01 MiB, post-processed: Unknown size, total: 13.86 MiB) to /root/.cache/huggingface/datasets/subjqa/electronics/1.1.0/e5588f9298ff2d70686a00cc377e4bdccf4e32287459e3c6baf2dc5ab57fe7fd...\n"
]
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"Downloading: 0.00B [00:00, ?B/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "78686951edec41a6b25180eb09c5b2bc"
}
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"0 examples [00:00, ? examples/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "5db206a0abee438eb1ec6999c74480bd"
}
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"0 examples [00:00, ? examples/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "b0fce2cc80ec459b9543330b5ccf1dd2"
}
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"0 examples [00:00, ? examples/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "adfadb17cc894fb0bf9ea985af475cd3"
}
},
"metadata": {}
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"Dataset subjqa downloaded and prepared to /root/.cache/huggingface/datasets/subjqa/electronics/1.1.0/e5588f9298ff2d70686a00cc377e4bdccf4e32287459e3c6baf2dc5ab57fe7fd. Subsequent calls will reuse this data.\n"
]
}
],
"source": [
"from datasets import load_dataset\n",
"\n",
"subjqa = load_dataset(\"subjqa\", name=\"electronics\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "YD_bZsCXz41h",
"outputId": "5be09efd-6bbd-4d7d-ea5e-d3b1e0cfabfa"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"{'text': ['Bass is weak as expected', 'Bass is weak as expected, even with EQ\n",
"adjusted up'], 'answer_start': [1302, 1302], 'answer_subj_level': [1, 1],\n",
"'ans_subj_score': [0.5083333253860474, 0.5083333253860474], 'is_ans_subjective':\n",
"[True, True]}\n"
]
}
],
"source": [
"print(subjqa[\"train\"][\"answers\"][1])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "RAz3Z57Qz41h",
"outputId": "98a3e8f5-a64f-4089-ab47-7136991d6c53"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"train에 있는 질문 개수: 1295\n",
"test에 있는 질문 개수: 358\n",
"validation에 있는 질문 개수: 255\n"
]
}
],
"source": [
"import pandas as pd\n",
"\n",
"dfs = {split: dset.to_pandas() for split, dset in subjqa.flatten().items()}\n",
"\n",
"for split, df in dfs.items():\n",
" print(f\"{split}에 있는 질문 개수: {df['id'].nunique()}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 191
},
"id": "JX8LhEqzz41i",
"outputId": "5c46ba74-87ea-452c-df6b-2cf32ce246c8"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" title question answers.text \\\n",
"791 B005DKZTMG Does the keyboard lightweight? [this keyboard is compact] \n",
"1159 B00AAIPT76 How is the battery? [] \n",
"\n",
" answers.answer_start \\\n",
"791 [215] \n",
"1159 [] \n",
"\n",
" context \n",
"791 I really like this keyboard. I give it 4 stars because it doesn't have a CA... \n",
"1159 I bought this after the first spare gopro battery I bought wouldn't hold a c... "
],
"text/html": [
"\n",
" \n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" title | \n",
" question | \n",
" answers.text | \n",
" answers.answer_start | \n",
" context | \n",
"
\n",
" \n",
" \n",
" \n",
" 791 | \n",
" B005DKZTMG | \n",
" Does the keyboard lightweight? | \n",
" [this keyboard is compact] | \n",
" [215] | \n",
" I really like this keyboard. I give it 4 stars because it doesn't have a CA... | \n",
"
\n",
" \n",
" 1159 | \n",
" B00AAIPT76 | \n",
" How is the battery? | \n",
" [] | \n",
" [] | \n",
" I bought this after the first spare gopro battery I bought wouldn't hold a c... | \n",
"
\n",
" \n",
"
\n",
"
\n",
"
\n",
" \n",
" \n",
"\n",
" \n",
"
\n",
"
\n",
" "
]
},
"metadata": {},
"execution_count": 8
}
],
"source": [
"qa_cols = [\"title\", \"question\", \"answers.text\",\n",
" \"answers.answer_start\", \"context\"]\n",
"sample_df = dfs[\"train\"][qa_cols].sample(2, random_state=7)\n",
"sample_df"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 36
},
"id": "z2QRigbUz41i",
"outputId": "26f56f7b-23e7-4bac-d86b-ddb3eefb4cc3"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"'this keyboard is compact'"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "string"
}
},
"metadata": {},
"execution_count": 9
}
],
"source": [
"start_idx = sample_df[\"answers.answer_start\"].iloc[0][0]\n",
"end_idx = start_idx + len(sample_df[\"answers.text\"].iloc[0][0])\n",
"sample_df[\"context\"].iloc[0][start_idx:end_idx]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 378
},
"id": "KJmPL7Jiz41j",
"outputId": "f194f387-4a64-470f-8a4d-d6cc62bc090d"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
""
],
"image/svg+xml": "\n\n\n",
"application/pdf": "JVBERi0xLjQKJazcIKu6CjEgMCBvYmoKPDwgL1BhZ2VzIDIgMCBSIC9UeXBlIC9DYXRhbG9nID4+CmVuZG9iago4IDAgb2JqCjw8IC9FeHRHU3RhdGUgNCAwIFIgL0ZvbnQgMyAwIFIgL1BhdHRlcm4gNSAwIFIKL1Byb2NTZXQgWyAvUERGIC9UZXh0IC9JbWFnZUIgL0ltYWdlQyAvSW1hZ2VJIF0gL1NoYWRpbmcgNiAwIFIKL1hPYmplY3QgNyAwIFIgPj4KZW5kb2JqCjExIDAgb2JqCjw8IC9Bbm5vdHMgMTAgMCBSIC9Db250ZW50cyA5IDAgUgovTWVkaWFCb3ggWyAwIDAgMzk4LjgzMTQwNDUzMyAyNjcuMTA1NjI1IF0gL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDggMCBSCi9UeXBlIC9QYWdlID4+CmVuZG9iago5IDAgb2JqCjw8IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlIC9MZW5ndGggMTIgMCBSID4+CnN0cmVhbQp4nL1Xy3IbNxDcM74CR+uQIWbwPlp2rMQ3xazywZWDS6Fou1ZKJDlR6e/TWO4uQWcfOZFVZBFNLLo5L8xs3u7++Xqz++3qUr/5oDbH1c2TYv1NbV6z3j9po7/h/axZX+nTTQb4nbI5UbLsjMeyrZcSIrHxQTxw8+OybP6i1D249lhcgWCvvCW2EY96StiH01OkXCFthThLEgo0PjUiOPhWPegfjrPWUdLCkZzTjzv9Ud+D2WBlsU28y1jEwzcj+hG61MKvI68VCgKxPpFxkvOAtBXiAglXWod1p/Ran02rzzj2TgWmKMLcA20FREs2V0qH9bmVpkC5k+rIJxu865G2QtgY8rESOwLnVsvsiAPkRiZvLRs3QG0NSaRYh+wInF2vY7IOepFOJkSOA9JWiHdItVrtAJxdbUjkS4plR4ZDQOr0UFtDSYjrJBuBs+vNniLksssUWEQGqK0hMZmkTrUROJfeI7MIpZJtFsGaswvODlh7gtlArk64ERglb17L4d7Yo6Tj7oDg567Am6kCfxRAtqvv6hI3wrN6wKfRPxmcAYNZjpywK8OEN3fqcqs37+Bv0dvb7irZ/qE+6VeNudC/6+179fNWXauOuIqOkbKC5kkROd77kKyNmdd4uTFT3Fy8lX10ciSvsXl2FkvOuoTLwydZo5cZ+oiIiy4FW9FX2AI9KixCJouHb9wavZ2mFw4UPPoBd6SvsXl6MZ44W+MC/LTqdDdD7+NQdY/0FbZAj7vZREgNcFRYo/cz9OiDXJ/mI32FLdCXa86zpAhHxTX6ME1vbakkCLZQ9VIVNk9vcSMl2N4kOCqt0ccZ+mSIIxwY61buiC3Qo6xHk71kOGqNPU2zj31ZhrkLdSm5FTBpdcZPpcSU/PQQt0D78UIHS8mIQXnAC9Dn5mleRwjkc62jByZTL6PudP1tEDJ2RUjzpXmZ580WuV7z9sAUbyTRCfHB64y75vECOUqHP98bYDcvg7E3+1rHgEwawFPuHMGoFaUELcl52/wJOQumZ5fw5YS7RyaDYDQ+Y5TwcZV8gRiF1p4E34BMRz1aL1NGI2QIGsJl4l+X/rEYIXcSbQMyaW1H4cCby1i17vzPzfcFbhgwnETcgMyEei47UOxXou4XuPm5phX9/jCYds3F6Vg632KM46H68J/B8m5qsMS+/zGR1rv6R+dOM53uQ2PEXVu0P7EIGjvpWx2BCctzlVkcucownWXeXWg0Z4GdH0tRSU4Mc4ZtKq+skJzNQ/M3Pu+bm+al0bDmLT6vO+yp+d58BXIPZHuB9IM7gsPtW9ofHPfS/NWnmBqsf63+BZifOMUKZW5kc3RyZWFtCmVuZG9iagoxMiAwIG9iago5OTAKZW5kb2JqCjEwIDAgb2JqClsgXQplbmRvYmoKMTcgMCBvYmoKPDwgL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAyMCAwIFIgL0xlbmd0aDEgMTE3NTYgPj4Kc3RyZWFtCnic1XoLeFTVtf/aZ51zZs6Z92Qm78fkMYTwSpwY3soYAXmJAQICFptAEt4kEBAx0gCWBIQ2oUAQREgVEANiQCoJRAqaighULdBbb7VWwVcbkXqp2pDs3LXPJDxs+/+333fv9//+58zaZ+999mO99m+vPTPAAMBNiQy++4YOGw4DYDQA60W1sfflPDAhvq3b11QeASDx+yZMzN48cu94akxl+Pj+e3JHaEMyfwygiPbfPDAhPTD3u5eeAFBTqDxpxvz8Ehzkoqz6OI1RMuORxT6YHTcAwNRCZV5UMnP+wjsfmQOgURn2zcwvLQET3aA/RWXrzHnLilyX069TeRdAdMqswvwC87TXKgBS3qT3fWdRhW2naROAn4qQMmv+4kePHHPT3H4x//Z5xTPyZ+8r6UflE1TOmZ//aIm8SV0I0M1JZd+C/PmFqV/e1UTlDOLnQklx6eKdK+8NB+gu0/sVJYsKSwaZ/kLZ7kLGWSB0ZYXQJdGNkEx1KdCN8uKdDn1gMEhDh4/JBfu8/MULIBLESNDRAXAjJ1qyuYWLFoBZ5AySaQTxNIMkBURLKUdaBTbwwr99dbxPNNTIVRvpXKIjIg3VhN79b11idv4iJ3sJovJJkePn+Yv0PE1vTt7WermRrjHS8yLXEep1JDTS/yxfHe//z475T2Y6T/OcvzHj+f/1ORn5iQ3s4AAXuCEMwiECoiEG4iHJ8E871TDDv5A8SzH6qGKV0WUGzXjqnWNZyL/FeBFGj5t9RHuNWon3Yi7R0wHOzhk9AJ3+vwP2g8fw/8fyF+VPh+r8RfMXQPX0RfmzoXpG/oJSSmcVLqJ02aJ5UD2zsJjyMxcVzoXqWfkLqM2swulUMzd/QT5Uz8sv9omU1tGP5+cvngXVC+aKmuKZ+fOhetGSBdRycdGCmZTOEuP/k7Vm6Gje7Jn5t603GULrTaxf8UQiJ2mqG+UiIIogRaI0hVKhC0Zpl4x/hM8hBwZbwfSBGJrWKch5hA8XQ1OJ/K1XV5nN6sxP/BdMShqWHvkXbD811FY8b+RvGeO2+qm3lBfdzEv9Aa5XUX7wja7dScqQR4T0x2Q7qxaeo2QqW6kYH3rif0CR5KYRLCqiWZYk+UaPziunaFgBBMEHy1QP97BtpvnsUh6wjg87OhtgJ8VCyAf3U4kZZRkEevnolo1nfxgKw2EkjINceBDyYQYUwWxYAkthmWFxH2QYLUbc0qIQZsGCUIuOSx0XOk53vNlxquNEx/GOpo6XOw51HOyo79jfsa+j7nau/+EVwv3mzpLDmDFEgn/aP4jDkN8N7SQb0fBOEvoXe+bIzr7jOklsjrmdRJokvkMURpTfSWJ1zegksR8UEhUR0T5F8gFpAWifAZIUSB+0URIt7aQkomWdlMyyoAHO0H0S6mA720MlMc5CqqmVDsFq6t0Ar7MzbK3Um+r2wFU4Ty0r4QzWycBGQSbVArynSHCN5cJhGmMA87ABJpWW01j5sDxebpA/k89BP7lUPifnyaUsE59VJil7iAbgr8hXTkMCNLAPoRSO4heYiU3yUNkOH+I5rINPaBahvzNQBbugjHjxsGIol8qk8VRzSjkH2+gupvfn2A52nrg7yp6Ai/AUytII2MEuklxn4Bt4AnOlcjJLplRE/J+isc5R/21QSkB2kenApZ5UR9zTXNONNA57KxeN+yqU08y5sEttUD2mZJpFaGwPe521qBuhFs7jD3Ah/p6tlpPlvRQFVYU0gHlQRWNvE33UIraMZBd3mRhdWirnsTr4Qs4zTaexfyUkojkPS+NJoiJoIlqqOkmmQWw1riVOxds4OGcaJadTfxrBtJykBijGLJhDuTI4AIegN9ZAFY1kyKv2U76hntvlj0jmKvYT6Rs4h0MhDYrkK6Rr4UI1AEdMqiKjxKCXz1kv+UcW1AfHTfa9OSWxd6/vFX1Ok68ecupty3wNHR05k+UYZUq9EluPfnO97E/+6J+9/Kh3r9E5k3317cOGdo46LG8o1U2YTFlRomqqHzbUeCcmrVf89BmZV++bMcv3pPPJ5IFPOgsH9hZrTBLREK1tpFxlxyW5iqxjIRxODoaptW6otW5wr4/UYh3xGOuNiXS2tVxruQOcl6+1OK9ksCTJ5XRnBtwup5QaAJcTkpNEKq3b/swz9HnmmetM499ev86/ZZqSw8/xs0TnWCbdd7LMWl7KK3glL2U/YcvYY+wnAtc+ouU9lVBeh2DQm421slSrrDRBrWZOUGMREpjFeWF0vSN3ciM1Dvaf0tLcRgyltwSutVxoySAdTElihx3okKVp/RJdSpY/05XoTeRsFN/KCt9io9p21cmlIxpGtF4UeET2kkeRxLGwI5gaFR2DkbEuRQaXosjZzp+7NtlqPRtkWrfg1CWmx0Y4UY1zto2u9+aOrg/PfWh0vSf3IeIEO070n9J8oeXECZd7QCc31wxuTE7lS5PyJauPdboiBhBvwcBEeZIyyfSY/JjySExllIlWdZQcTeaNXQyPqEuiS2MWx66CiqhV0atiVsXuhb0xrmkwzU9CZPWFfnezrDu7JSeppqy7WWZA9npUkwoEJSfbxpAaM/Pvf77ih+cffezC5M+ZZ9hDUfxaXV3dUrZh4PwtI5fWZN979o7A56/9YHdJHP8zSb+d7F1K0neHkmAf8IbpFVpChS+s1mur1TaqsbW+jckb1PXe59LCY8MAPVGx3XzOWPQkaGqaUEJ4bpf8miE/KeBaC0lJGnC2XL52ucX56RWncZNWMlhQK4jPT8j3FSTKMI3FM69HTkzqlpoVT4L0Jal6sqxQ5jbxcMiG5/g7/POHT83JfXP+8VONuw+8snnHc09NOL6o9PSUT5n1p+hPaK7+4Gu///U7AjVVP968Z2lJaVlKt8M+37uHHt8nPLyArLyLfEqi3WJlMI7Z0AaItmxAi6lWYbhSY1YdYlWzbLU73x9dbyHBbIZgViHYhcHNLQGXsOvlC4NbAiSLYVj5NBn3tDBpDwv0oI1nCm0SS+FJMIWzntCN9cS+bCx7wPqAbRIrYkvYY7ia2ciUGkvETFemN9mV7ErMQpVLjGfxixdPtz+s+Nsu4bm2zL28luW9ThbaQRYqIM7j4OFgshxtclU446JrTZ5a51qbVAsrbetNu+IjYpmOsaA71XhnG7vVLk7BfudqcYrVQiZyNl8RC1isYDIPbw5ZJ4z8yyV0Dl4P3GYWYY0PMKq9ttfkXq0shV/gXz38+qypJ+a++NZbL477ea5ysY7/zOHgV/70F/5Xn+/MHRmvbN/+Soo4rVUR9zUGnqTA5GBKmAq2CivUhqu1seG7nbXWtUkbYtf7rUlabFR8WCwmJsT4CWDIiS4bEHO57fJN9wl6aE9l56RzeE4+o5xRSe5D8dI0No0lqV5PeIhX5u3DkpMk7BIk2SfgKDEQLu1as3PnGiKmjXl6zJvnHYMOzf2IKfzqx7ydX2E5LGbM0zjo6LM/P3bs588elZY1pHTjX/OvHpzGv/rzp/xPBkBNZ7vjBULtJW+aRTZRYUYwUnFJKKFLJrxQyB6oIJMZqCZn29lml1gJ6bfgABG5izDQ5Fcp1A/SYHQQJxu5+vWfEnRPlpiK0coAZYQyE+uhXjWRt5BhWDJL3Isn2j8+z3h7pnJxUutKpaeIiNaRftcZ+k2GdLg36I8k7aaqtfG9a90b4tenPpcRaU3pEetNiXVohN4E4Y7EmAxnW3PLteYWQ7Fda9UoDaBFeosy/X0Ia1IyA+ECZIzlmpyUknVn37CuBuQZ0rrq3burq/fs5rtXbYCOP3zIN6z82XP822+/5d/uGrHhiVUbN656YoP0q22VlduerqjcNsl3aMXL77zz8opDvqQ3qt77/PP3qt5g+YtXrVpMRB5zmqLfetKtmWK2PkEvbNZWss1Os+TUQYmyBSBWk93GHkScG9oVMHsoL4yRH7gyQ9b2JxrPNMY2XmNZLIF/xM/wbLaTHWI1fBbP4flK+vWlLJL1Yb1YxB6+ha/gP+I1ZAyaXU6m2TVIC7rVzbK0GVbKL5oVZqLlJes0ceBCc2hS2v0OOSw0rbFwBCWfxqntJVJOe/1bYkmMqGvvB6ExlUE0pgV6BT3mzdKLMqzUVRpQ6a8xGtUqRqUPDTv4MmUyDuXYxLC0bbkyBULQwG9Jf3jrrfYkGrd9u1TQ2lM61T6gc2y2kcZG6HMEXpLEcLIAZqdY72DsjoJbgl5bhhJUcpQ8pUrZqahidBqVxmvtKfCxlH+nvGf4URyMD/ag3dzBrDarndls1mxHvFXd7IbNkRQI2OJtMQ4ralExmRjldRLctLQJUwhwdDYbbjSgCx5D/m7seUZQkGkECGEsOdXOOtelSCVMfZ+3M3z/fcZ4xxCmX/sgMdnJf8UrackNYgPZo+8qY3gD/4R/yhvYCBbNYtiI1rf5B19JEtvN8sWy5A/xHbyN/5TU0dFKNvyCdGKCUUG7aliQBcl8QcXsvECIYqzIQAatQl2sQrOxCs1g7lqFYaAlgJM5pQSTUwtqJdpOTZuGhoFdiar8VfuVM+1XyMCtF8UaZOIMYtpD81lZWXCkEq0qmq7J0bqG0bpFl6KZZLHoqstkNikEEmazSXKhZKXWdCaxZuuKhCrCSxaz1aJr5lDgaDGBzXnhbIRwb9puAhG3KNTcScrNZyg7JekQ2Mlvgl+rkqpI4mSpu/XuSoru0++W7lbu1DP0MdL9SrYe1KdIc6S5ykw9Ty+TyqXHlXJlhV4jbVbiTKBJZgRZVcSXEcwkk15MGmiyrlvBHo1e2WuOsjrtPjlR8ak+k8+crKXofovP7rMPlgZilpypZJj7agMsQ6wZ9uEwnI2SgvIwcr1sNduUbQ6ag9pQ/X5r0B60T5YmmadYc+xF0kzMl6creWqeKc9coBXoBZal8Agrkx7FpfJiZZm6zLTUXGJ+1FpuLbdXSJW4Rl6rrNaetFTZt8g77S/ZHxIomakx8WHJGkseepbcZsAlkZzjazn50mtcuXjdLV8R1NpTcbZeJa8vI/TsTacHHfzQRNFfgiVCs8MLEWqj3eWrSDga25jc4FofYYUIjLRpZksCmj3DupHLn71AVgmBO/l8G3n9GwaWuoTvBxdkxGXEZyRk+DISM5KGpAbjgvHBhKAvmBhMyonLic9JyPHlJOYk5aSWpK6Oq4yvTKj0VSauTqpOrU29mhrf1bWrU1eHvPi8hDxfXmJJfElCia8kcUX8ioQVvhWJkbfugHexfq7kLFpeSd0IpzMTb42lwqXjH+5fWby1saFhSNOa/WfarzPp+S15r+QWHp/6X1elzKKy6aXvHU4b076yrij/5LOvnnCXr+vTpy41tU14+cKOS/gZ6SoKhgRjoIKtke0VtjV6o0tujCAlRZvcNhjhGRbtbLsc6Dof8GtXnH+9khG0OGKcMStiqmNqYxRi1tiiOxnu5xXMdu7R+NnYZ3JefuONl3OeGXv/7mnt/LesN1MnPitn7e/Z89K5c5d69qxLSWF3Mztzs4HJZEHiSi4nrjwQQxFsCniZVmFeo3hfYEqjlR2LbHQ3WNfHxngls9cMoyW3Y1issXk0G1G6YDIUYFwLRRhpQ+JK4mrj3om7GqcMgSFsiDTEOyRG6WVKN6drvfRiKGbFUrG3OEabtlAIkmiESIYMvk6EMxnCmeTytkPWc0fmnJo+4525/Bo/xdLaPmamBmn3mm2NdunhqcdP3XnngR69WH+mszB2L/+gecvhAzuEptMJkL9TPRAGU4KxipNZzS+orBK22NUmXQqjcEFTzDaHZYxHAL0ugN4igH50vd3Ii4BvcHPb4OZmt+GgYktxXqGYlfb2V4LeHG+tF4l1YjKOhUAtOStTOIv0Xf2M+1k6f7exvv7Aq6pna86sGVVt6fhu1dhj+4ivo4SrBQZfdwajUAO0M7XS7mqwbtGZZIaxYoUM94jNTBwQCbgoxHC5CbsO5XmN3TnZZXijlzKZRqQZLhc0PP745v2NjdkvLzn5hrSr/QfSjp07ju9qr1Q97TsKC74Se9NJUsoymhcJ0XsSoh+XD0KTpDCzDMPNzrbBxs55mfbNoEXgdY6WR5itGBtosgiyTzbQJeddr1U9X0CXHOQzYdD3djma/rEcl7vkOJznfdsrfV8S7/9FEjnvgBAk5KtLaF5xth5FZ+tGNzRaG8TZ2u0Yh27vsO+drYPJQ6LKoEwtN5Wby7VyvdxSZi23ldvLHeXOcleZuzbqapTr9uj3tiN46ab9+zZv3L9/41Xm5leu/oV/xVz44WenT3/2+ZunvtjO3+Qt/EtyzAHkfx7Wnzg8yifJu4hDJ52G7w7GRDeC3dOomBvs69mr2BTnclvui5DBLA2PE9oJhHi9LPRDR4qMoJYXvyK+Nv6P8TKb5r+hGrHDExyxkMYMTllpY+PAg2VnoaPjbNlBqf/zP/vZ84L2th9Q9bqCfN7Ev6O7KZ/9+cxnn50hEn6wkLibaujP4A4brQ6tMdLb4Fgf82pUU1ykVTVH3wdu97A4Q4+BwE3u3vged+yWAJYJAJKMxRsekUU+w9KJl717iR+pdODBx890QMeZxw8ObGiQ0ju5aT9QkM+GMjPdQ/ML6v72TcircBRx5wI6qKi0g7ssWGlv0JpMukqb6HC3CLoNTyX0uXBWwM3hnLCdYcKfQnh405kicFTCyF7bnyctHV0d1icWD7tdZ463HyJXKpqhKDRbMaHxKZotFT4LDrZZJbtlQkK8WZNM+oSEhPhs3RKfIHsJpdfKngrv2kiB0n5C6e7xuiUhxgTjY8x2k9mTNKy74OpCy2Vix4imQ7D9VwHb7q6ow/4lnehNRipijFQRY8yP1WMtsdY+BIq9LL2sg7RB+iDLIKvFBz6WInXXu1t6hKV70r09wrvHd09I86UlpqRW6BWWCmuFTXz/yiRJ1VULWtGGdnSgE6MwGmMwVo7TUtPThqT9MK08bUVadVpt2tW0SNreF97cNRKMbw7U5FuPqOlMHFX6ku5w3di9U9eunb5pSPPub3839fV5RW/kr1pfuC+476k//rrosDzkQPfuubnBkYn2HlvXbn8lOfl4VtaUcaNz/I6Uzat27DfOdxS2S18rOwgh+gej7IrZgS+AizWZK3UL6ZhWgNNtFwhhwGyg8xQS+oqA0O6lENoJbPWEDxJI2y1LYKyLLWVlfPXo0ldfvfhsZaWyg79W1V67duy2nb+R8qrY3cLHDxBGTDawyQODgrE30Wm9zpo8DVbCJo9lLKHUcK9w8gEhj7ocuAFRxd4TAqLCCGFDPi6OEKGAgB0QEPViQ8O9B5ecfJO9zY5Ke9rzd+48vksqu167v2jGVdwrpJ8EoGbJeRSh/pni2YmheHYixbMTRTw78V+KZ3/5D+JZsVmNrneJ78zcIgkTicX4lsI4qVBAbg197SLOL0a12Mv+7TCYBTsUKVwKV5L0LH2kNFIZThHvQ9JDykQ9R18gLVCK9GUU9S6jqLdS2io9pWzSm6Qm5dfSKXxbiVMkDVXZouhmi0YPq1eKwnA5Wokxx2gei9fqBz9LllIxUfYrSWqSyW9OpQg40ZJsHYB95b7mASLulUbgcDkoZytBNWgKmodSzDvUImLeSTCJTZJy5HHKeHW8Kcc8QcvVJ1pmQAErlOZgoTxHmaPOMS3Q8i0zrcX2JbCELZOW46PycuUxtVx9zFRuetS8TCvXyvRHLMutldIahWJg2MI2SRtxu/y08pT6lGmrOZheY91p3wN72C5pF+6T9ykvqC+Y9pl3WV+y/0I6iK/Kx5QG7Zf2Zul1PCu/pSwz4ucYJj4s2cKSJzV8+sl7n37SwH//3l++fk/Oa6vBOYKu12JN2xzykbsIi8vJRxxsXfBek1nSXODQXRYdwGF3OcBhc1ltIB52GzmN1UUuk22zaE6wKJX4qt3S5LTbrLpGnmJ2yA6Ls8s7zIbdO+MZz414prnZFWGgU0Cc+123nTC/5wl04AwIH7iqgmJWNbSF6xE2py3ZlmUbqT+gj7VN1abqc/RK2wrbRpubzkiaSla22C2OCOaVnLJTidA9Fo812h7tSIUUQjOf7FPSzN01v55iSbGm2nrYezh8rn6QxbKkDDlD6a/3tfS19rcNsA9wZLjugSALSkEMysFO62drw/T7bCPtIx1BVy6MY+OkiZgj5yiT1ImmSeYHtQfJAyZap9inOHJcRaxImqXPts925LnKzI/aH3WshSe11ZbV1rW2tfa1jq3aZstm6zb7Nscuyy7rPvs+R73rbdeHrg5XIdlQsbPQV6hDmHEWkjaO3fT4xnljcjMT+aDX2cPs4ddnvfnYthEVufLYtk04rzPaVOooukqBEcGwbkZwaU2MtMWbXdZEp2eMX6BcQOCcc7CIKZvvgKBLs7lecEvRlRC5RU1wN1kc6YM/DQT44CsBCjTpZH1rcHkzwDSg0CReCKRW6rqiTW4yAs4D9TNSu7G/3RZ5dkWfW7t3nzVDRKGS4FceRfx66SQyPuiKGQ4R5nCHRzabMVxXx0Tf5JcPpvgk6DYTeDsr7ZHHww/at2jQpDDB7RVufK8YoKCxg44l1XQ8cRqHk79nmThmFEbKo0Kcvvhyo+D8b42NIqbs4vHIS4JpdugLCPGothGPadAbpgYj04dH9DT3cMZ4zdE9NEhQzSnxWlK3MX1ustocEGmbwXBETELyCykuivh7H+9x0Albwk0pTVFxiemDB18OBMQKcLYE6BPSc6c++/Xtd4PZLq3fEtorxL8I74WCH4xNHfsEKft+6ZAQqFP7SPKQ4kN6nhgblirE6RKvywzSF6HfnaUpW6X3frzoh47Bf4UEs/FD7bs/sl/uen7727Yx9ima+D+G+cbvutTPNJ/HAdj5t79tHWef8ne/BafK54zfSUGqI1pHfhkBlUQfEdUQbScqINpBVEW0l2idmgan5W1wWpXhtPQDeo6BUvlSR6vpCxgqfwZlchEslFtgofQupCtuOCoNgJPiKX8CCxUPHCVaiKOo3BOKMRn60bsD6jqYJDfBXcoT1EeHdFOTsOiNKxuWwXdsHjstdZc2Sr/De3AF1uHvsE2eLm9Tlqo2dbL6msluGmVaZDpg6jCPNT9jvqA9oZ3QJYvH8jfrOOtzFAMJ6VMxF3rCLLCSzzhhq9CW7JXC6Sl+nzXBVPErvayR8jKM379FnkE4lUJ5CcxseGceb6mXb8krEMnGduZV8LAiuBeKoYRkWASzYSbNvhh80B1mkLf6IAAZdGdSbjq18JGss+l9KdEiKIR8mA+9qHYkLKD2fSh3D8yj2wfjb4xVapQK6VlIfR6htIBa6v/CrH1vzJpLMz1Cc4lfYRdQa8FHPvX592YcSrk51G8SLKEWM6htvjFaodEj35DIR6MsoLSE2kyncWdTOx/1L6bZ84133x9ngjFKKXFUTPdcqhWzllLbYmOkAM2dCVm39erqI4UcqONHxn9C/v5KNdaJ+L+biP+8xj+MIgnnxL+MUklTPUn7d1J0OrDzHxgjYTSMgXEk/QTS2USa60GYTGP/gElwgqFpyYLZw7MzMjqfmQ3SimDHdY6tHvybH78L4Lc1+I0d/8rxGsf/8uPXdvxLDV7141dP3qN8xfFKDX5Zgy2t+OdW/BPHLwbi59n4GcdPA/jJ5QnKJzV4mRpenoCXPk5XLrXix+n4Ecc/cvwwgH/w4Ac1+D7H37vxP5fje8fwdxx/S81/uxwvXrhPubgcL9yH538To5zn+JsYfJfjOxzf5vhrjudq8OyZeOUsxzPx+FYAT3N8Y7VLeSMWfxWOzRxf5/gax5McT3D8JcfjHF/l2MTxGMejLmys8CuNHBuOUIzD8cgr05Qjx/DICvmVX/iVV6YFO/CVoPwLPx7m+HINHuJ4kGM9x5c4HijAF+24f59f2V+A++rcyj4/1rnxBWL6hVbcy/F5jns47nbjLo7PPWtXngvgs3b8eQHWUpPaGtzJccczVorr8Rkrbn86StlegE9vcypPR+E2J27V8SmOW2psyhaONTbcTJ021+CmjXZlU3fcaMefteKG6mPKBo7VVdOU6mNYvUKu+qlfqZqGVUH5p378Ccf16/oo6zmu64NPkphP3oNr11iUtR5cQ4dNqqgswArSVIUfV7vwxxyfWOVSnuC4yoUrOa7gWM4x2PGj5cuVH3FcvhwfL8CyXK9S5sfHOC7j+Kgdl1rxER2XcFzciqWtuKgVF7ZiCcdijgs4zkvEuRznuLKVORNwNsdZy3EmFYo4FnIs4DiD43SO+QMxrxUftuI0jg9xnMpxymRdmdKKk3V8MDxKeTCAkzhOpJknZmOuFycwpzIhEsd7cNyoMGUcxxwLPsBx7P1OZSzH+504huNoejOa46iRTmVUGI6MsykjnTjChvdxHF6Dw2pwKMd7pd7Kva2YfQzvGY1BjkM43n2XW7nbg3cNdih3uXHwIJsyONjhwEE2HMhxAMf+/TxK/1bs19ep9PNg3yyL0teJWRa8Mx4zbRi4w6IEON5hwYx0i5Jhw3QL9umtKX2c2FvDXgHs2cOv9CzAHmlupYcf09zYPdWvdL8HU/3YzW9RujnQb8EUjskckxyYSHImutFXgAmtGE8ixBdgnA1jSYOxHGNaMTobo6gQxTGyACNIUxEcw6lTeBR6OXo4hnF0UwM3RxfJ6spG53J0FKCdo80artg4Wqm1NRwtHHUnahzN1MzM0eRBtQBleimTB3iRapHTwcypSL2RORE4sgZWsPonrOf/Dxf8v2bg/3jF/Te5mlpkCmVuZHN0cmVhbQplbmRvYmoKMjAgMCBvYmoKODAyNwplbmRvYmoKMTYgMCBvYmoKPDwgL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCA4NCA+PgpzdHJlYW0KeJylizkOhFAMxSwBwwDDvu/b/e/I0y8oEGgKItlFnMDLsf50G4cPLl88fAJ+D3ehiERMcimpcWac33wWohQVtdzQnqWjZ2BkYmZh1WYT+wF0pwJ0CmVuZHN0cmVhbQplbmRvYmoKMTkgMCBvYmoKPDwgL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAzNjQgPj4Kc3RyZWFtCnicXZK7boMwFIZ3nsJjOkQEEuxEQkhVujD0otJOqAPBhwipGMuQgbev7d8hUpGST+c/dzjxuXwpVT+z+MOMbUUz63olDU3jzbTELnTtVZSkTPbtHCz/3w6NjmKbXC3TTEOpujHKcxZ/Wuc0m4VtnuV4oaeIMRa/G0mmV1e2+T5XkKqb1r80kJrZLioKJqmz5V4b/dYMxGKfvC2l9ffzsrVpj4ivRRNLvZ1gpHaUNOmmJdOoK0X5zj4Fyzv7FBEp+c+fZEi7dGt86uKBGvxx8h7y/gj5biZACuyBA5ABHBD3fF/ugBiHGoSMYIcahHyEfAryanpvhiEcahAyWmShRRZaZBjEoQa9zFGEhyI8FOFYyaEGIWM3HuZ8mPBiPh7GfZjwkjdFFrwweQcV71VgGoH3KjCEONwTfR2BRURYRIRFxAlyaC5cV/vh71/Y3YA72PXA2psx9rb8VfujcufUK1oPX4/aZbnfHxL20GIKZW5kc3RyZWFtCmVuZG9iagoxNCAwIG9iago8PCAvQmFzZUZvbnQgL0JNUVFEVitEZWphVnVTYW5zCi9DSURTeXN0ZW1JbmZvIDw8IC9PcmRlcmluZyAoSWRlbnRpdHkpIC9SZWdpc3RyeSAoQWRvYmUpIC9TdXBwbGVtZW50IDAgPj4KL0NJRFRvR0lETWFwIDE2IDAgUiAvRm9udERlc2NyaXB0b3IgMTMgMCBSIC9TdWJ0eXBlIC9DSURGb250VHlwZTIKL1R5cGUgL0ZvbnQgL1cgMTggMCBSID4+CmVuZG9iagoxNSAwIG9iago8PCAvQmFzZUZvbnQgL0JNUVFEVitEZWphVnVTYW5zIC9EZXNjZW5kYW50Rm9udHMgWyAxNCAwIFIgXQovRW5jb2RpbmcgL0lkZW50aXR5LUggL1N1YnR5cGUgL1R5cGUwIC9Ub1VuaWNvZGUgMTkgMCBSIC9UeXBlIC9Gb250ID4+CmVuZG9iagoxMyAwIG9iago8PCAvQXNjZW50IDkyOSAvQ2FwSGVpZ2h0IDAgL0Rlc2NlbnQgLTIzNiAvRmxhZ3MgMzIKL0ZvbnRCQm94IFsgLTEwMjEgLTQ2MyAxNzk0IDEyMzMgXSAvRm9udEZpbGUyIDE3IDAgUgovRm9udE5hbWUgL0JNUVFEVitEZWphVnVTYW5zIC9JdGFsaWNBbmdsZSAwIC9NYXhXaWR0aCA5ODkgL1N0ZW1WIDAKL1R5cGUgL0ZvbnREZXNjcmlwdG9yIC9YSGVpZ2h0IDAgPj4KZW5kb2JqCjE4IDAgb2JqClsgMzIgWyAzMTggXSA0OCBbIDYzNiA2MzYgNjM2IDYzNiA2MzYgNjM2IDYzNiA2MzYgNjM2IF0gNjggWyA3NzAgXSA3MApbIDU3NSBdIDcyIFsgNzUyIDI5NSBdIDgxIFsgNzg3IF0gODQgWyA2MTEgXSA4NyBbIDk4OSBdIDk3IFsgNjEzIF0gOTkKWyA1NTAgXSAxMDEgWyA2MTUgMzUyIF0gMTA0IFsgNjM0IDI3OCBdIDExMApbIDYzNCA2MTIgNjM1IDYzNSA0MTEgNTIxIDM5MiA2MzQgXSAxMTkgWyA4MTggXSAxMjEgWyA1OTIgXSBdCmVuZG9iagozIDAgb2JqCjw8IC9GMSAxNSAwIFIgPj4KZW5kb2JqCjQgMCBvYmoKPDwgL0ExIDw8IC9DQSAwIC9UeXBlIC9FeHRHU3RhdGUgL2NhIDEgPj4KL0EyIDw8IC9DQSAxIC9UeXBlIC9FeHRHU3RhdGUgL2NhIDEgPj4gPj4KZW5kb2JqCjUgMCBvYmoKPDwgPj4KZW5kb2JqCjYgMCBvYmoKPDwgPj4KZW5kb2JqCjcgMCBvYmoKPDwgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL0NvdW50IDEgL0tpZHMgWyAxMSAwIFIgXSAvVHlwZSAvUGFnZXMgPj4KZW5kb2JqCjIxIDAgb2JqCjw8IC9DcmVhdGlvbkRhdGUgKEQ6MjAyMzAzMDYwNjQyNTJaKQovQ3JlYXRvciAoTWF0cGxvdGxpYiB2My41LjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcpCi9Qcm9kdWNlciAoTWF0cGxvdGxpYiBwZGYgYmFja2VuZCB2My41LjMpID4+CmVuZG9iagp4cmVmCjAgMjIKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDE2IDAwMDAwIG4gCjAwMDAwMTEyMjQgMDAwMDAgbiAKMDAwMDAxMTAzMCAwMDAwMCBuIAowMDAwMDExMDYyIDAwMDAwIG4gCjAwMDAwMTExNjEgMDAwMDAgbiAKMDAwMDAxMTE4MiAwMDAwMCBuIAowMDAwMDExMjAzIDAwMDAwIG4gCjAwMDAwMDAwNjUgMDAwMDAgbiAKMDAwMDAwMDM0NyAwMDAwMCBuIAowMDAwMDAxNDMyIDAwMDAwIG4gCjAwMDAwMDAyMDggMDAwMDAgbiAKMDAwMDAwMTQxMiAwMDAwMCBuIAowMDAwMDEwNTQ0IDAwMDAwIG4gCjAwMDAwMTAxODQgMDAwMDAgbiAKMDAwMDAxMDM5NyAwMDAwMCBuIAowMDAwMDA5NTkxIDAwMDAwIG4gCjAwMDAwMDE0NTIgMDAwMDAgbiAKMDAwMDAxMDc2OCAwMDAwMCBuIAowMDAwMDA5NzQ3IDAwMDAwIG4gCjAwMDAwMDk1NzAgMDAwMDAgbiAKMDAwMDAxMTI4NCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9JbmZvIDIxIDAgUiAvUm9vdCAxIDAgUiAvU2l6ZSAyMiA+PgpzdGFydHhyZWYKMTE0MzUKJSVFT0YK\n"
},
"metadata": {
"needs_background": "light"
}
}
],
"source": [
"counts = {}\n",
"question_types = [\"What\", \"How\", \"Is\", \"Does\", \"Do\", \"Was\", \"Where\", \"Why\"]\n",
"\n",
"for q in question_types:\n",
" counts[q] = dfs[\"train\"][\"question\"].str.startswith(q).value_counts()[True]\n",
"\n",
"pd.Series(counts).sort_values().plot.barh()\n",
"plt.title(\"Frequency of Question Types\")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MkcPl64xz41k",
"outputId": "4a0fdde0-21ef-4773-e1c6-2e7a82856f76"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"How is the camera?\n",
"How do you like the control?\n",
"How fast is the charger?\n",
"What is direction?\n",
"What is the quality of the construction of the bag?\n",
"What is your impression of the product?\n",
"Is this how zoom works?\n",
"Is sound clear?\n",
"Is it a wireless keyboard?\n"
]
}
],
"source": [
"for question_type in [\"How\", \"What\", \"Is\"]:\n",
" for question in (\n",
" dfs[\"train\"][dfs[\"train\"].question.str.startswith(question_type)]\n",
" .sample(n=3, random_state=42)['question']):\n",
" print(question)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "dLTCyg6Uz41l"
},
"source": [
"### 사이드바: 스탠포드 질문 답변 데이터셋"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "IbKi9yYyz41l"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "V56fOUQRz41l"
},
"source": [
"### 사이드바 끝"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "WWtK_6STz41m"
},
"source": [
"### 텍스트에서 답 추출하기"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "JKaueCUUz41m"
},
"source": [
"#### 범위 분류"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "w7FgPqwtz41m"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "VGWPDO8Dz41n"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "4Wj8cnXJz41n"
},
"source": [
"#### QA를 위한 텍스트 토큰화"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 145,
"referenced_widgets": [
"a5aa206de3b243ec9ed2a6e914a448fa",
"b8536ec5c895460ebfa32a103fd80591",
"6d5046a2cb704b3ca5758c10a86288bf",
"5307c50f07cd421db587496c39e4d175",
"6d9e00830be4431bb2bbeeff660dd6eb",
"b5afa237918a4f7e918730dd78f23724",
"1d8743ebb1664e818055d55f846725fa",
"00c99c2a8fd94b9a8d992fdcf11f6e61",
"50939b3e6f914edc94c7568b5cc47e22",
"58aa92721d354129a8d31ae34f2cf855",
"a86b2402ffbc46fd9d92325cf1cfe3aa",
"06e3d8ab6e374e5ba9f4c4f0f0424b04",
"7d0fed82d1db4d558c67c75c8378b412",
"fb64a118ff924db68c44208bb1e1f7bb",
"7f635a3e72cf4298b1ff4dbdfbb634c3",
"5c5590848528421ab7c081610f8dfc58",
"cb8a67217c974ad9a04690da613cdda7",
"066df9e253f042e2ae242fa1d5a03596",
"9628c68b4f2041a8ae8e56a59930359f",
"5940bb21f0cf496f9ddb7b40c3b6e353",
"64224a316b1348a1803cd793e4f27cb7",
"4c326dcae0ca4ebc8b19008ceae6a93c",
"f709228b2006482da1050f30604bbb11",
"6d606e63dae34cc9820a345f969b4ff4",
"daf33cfaaa604cdaa44d60690068555f",
"1fa630961cdb4f83a96b08e3db2e1ce3",
"5fbd5d0edc6d41678a5c3c155cde5279",
"fc1aa6d56f004f6fb2265225c8517f65",
"3079624f39d3437489e46aa5e7783301",
"847cb3ec626e4c18b3fd93af01736368",
"5bb6c9761c034d50b967c22edbddb736",
"268e2d65ee0d4675b364e514cc6039a1",
"f2b73e98882e477daff3a56798012368",
"e20d8ade0bd347d39f0eaedffbd10ba0",
"018a5325476c45b28613895fd0df9d0d",
"ac1d74729df34a1fac1f530c3c6b39cb",
"f4d64cf610cd4c3fb62124908a8c791d",
"b5893539ee084860ae1cdda6debd8dd6",
"0edd8fc74cb34fcd9a92480b87bd8244",
"687a73a209a942a5b1bba2e0490f7c1d",
"6cdab1e4b4204a8286d4c210b76144b1",
"d997fc3e56a3461790bee7b7a589d95d",
"b63d8d35559c47099546d9ebfce22783",
"58531126fa0f48f090de938365ee83bd"
]
},
"id": "9qGdwgLQz41o",
"outputId": "254517bb-3b5d-4e18-98cc-5c32befe555c"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"Downloading: 0%| | 0.00/477 [00:00, ?B/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "a5aa206de3b243ec9ed2a6e914a448fa"
}
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"Downloading: 0%| | 0.00/232k [00:00, ?B/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "06e3d8ab6e374e5ba9f4c4f0f0424b04"
}
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"Downloading: 0%| | 0.00/112 [00:00, ?B/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "f709228b2006482da1050f30604bbb11"
}
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"Downloading: 0%| | 0.00/107 [00:00, ?B/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "e20d8ade0bd347d39f0eaedffbd10ba0"
}
},
"metadata": {}
}
],
"source": [
"from transformers import AutoTokenizer\n",
"\n",
"model_ckpt = \"deepset/minilm-uncased-squad2\"\n",
"tokenizer = AutoTokenizer.from_pretrained(model_ckpt)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7rmgk-eMz41p"
},
"outputs": [],
"source": [
"question = \"How much music can this hold?\"\n",
"context = \"\"\"An MP3 is about 1 MB/minute, so about 6000 hours depending on \\\n",
"file size.\"\"\"\n",
"inputs = tokenizer(question, context, return_tensors=\"pt\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 173
},
"id": "wxixFF02z41p",
"outputId": "14688e61-8b9e-4e72-bb59-6d181a7e7ff4"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" 0 1 2 3 4 5 6 7 8 9 ... \\\n",
"input_ids 101 2129 2172 2189 2064 2023 2907 1029 102 2019 ... \n",
"token_type_ids 0 0 0 0 0 0 0 0 0 1 ... \n",
"attention_mask 1 1 1 1 1 1 1 1 1 1 ... \n",
"\n",
" 18 19 20 21 22 23 24 25 26 27 \n",
"input_ids 2061 2055 25961 2847 5834 2006 5371 2946 1012 102 \n",
"token_type_ids 1 1 1 1 1 1 1 1 1 1 \n",
"attention_mask 1 1 1 1 1 1 1 1 1 1 \n",
"\n",
"[3 rows x 28 columns]"
],
"text/html": [
"\n",
" \n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 0 | \n",
" 1 | \n",
" 2 | \n",
" 3 | \n",
" 4 | \n",
" 5 | \n",
" 6 | \n",
" 7 | \n",
" 8 | \n",
" 9 | \n",
" ... | \n",
" 18 | \n",
" 19 | \n",
" 20 | \n",
" 21 | \n",
" 22 | \n",
" 23 | \n",
" 24 | \n",
" 25 | \n",
" 26 | \n",
" 27 | \n",
"
\n",
" \n",
" \n",
" \n",
" input_ids | \n",
" 101 | \n",
" 2129 | \n",
" 2172 | \n",
" 2189 | \n",
" 2064 | \n",
" 2023 | \n",
" 2907 | \n",
" 1029 | \n",
" 102 | \n",
" 2019 | \n",
" ... | \n",
" 2061 | \n",
" 2055 | \n",
" 25961 | \n",
" 2847 | \n",
" 5834 | \n",
" 2006 | \n",
" 5371 | \n",
" 2946 | \n",
" 1012 | \n",
" 102 | \n",
"
\n",
" \n",
" token_type_ids | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 1 | \n",
" ... | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
"
\n",
" \n",
" attention_mask | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" ... | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
" 1 | \n",
"
\n",
" \n",
"
\n",
"
3 rows × 28 columns
\n",
"
\n",
"
\n",
" \n",
" \n",
"\n",
" \n",
"
\n",
"
\n",
" "
]
},
"metadata": {},
"execution_count": 14
}
],
"source": [
"input_df = pd.DataFrame.from_dict(tokenizer(question, context), orient=\"index\")\n",
"input_df"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "nLLHfM4kz41q",
"outputId": "dab12499-28e4-4283-960f-aefca104ff36"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"[CLS] how much music can this hold? [SEP] an mp3 is about 1 mb / minute, so\n",
"about 6000 hours depending on file size. [SEP]\n"
]
}
],
"source": [
"print(tokenizer.decode(inputs[\"input_ids\"][0]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 227,
"referenced_widgets": [
"f4b32bc8d7ab4a5cb06299a244563cd2",
"4b564b527b714d16a8fc7ecdd72b9a07",
"643d8588ebe4468da769ee6ce999c5a0",
"46630d148ba84cdaa060d412cb5fb404",
"0904d3a7594541d2bc562905bc406dbf",
"c046141e86194b0f812d62e3d198b7ce",
"fa29e2ade5d84c659d26e373dff96206",
"c6ca86b04665411f8f3b884450c90f48",
"7c4676d723874fb99b8fd208e7979f9a",
"af89f79780214eb4bb9bb8c14cf77e41",
"7ccb044924da45678d2980d0c5ac0131"
]
},
"id": "M3ItsK1fz41q",
"outputId": "b790e1c9-1630-4aeb-faf2-ca9abc74420f"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"Downloading: 0%| | 0.00/133M [00:00, ?B/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "f4b32bc8d7ab4a5cb06299a244563cd2"
}
},
"metadata": {}
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"QuestionAnsweringModelOutput(loss=None, start_logits=tensor([[-0.9862, -4.7750,\n",
"-5.4025, -5.2378, -5.2863, -5.5117, -4.9819, -6.1880,\n",
" -0.9862, 0.2596, -0.2144, -1.7136, 3.7806, 4.8561, -1.0546, -3.9097,\n",
" -1.7374, -4.5944, -1.4278, 3.9949, 5.0391, -0.2018, -3.0193, -4.8549,\n",
" -2.3108, -3.5110, -3.5713, -0.9862]]), end_logits=tensor([[-0.9623,\n",
"-5.4733, -5.0326, -5.1639, -5.4278, -5.5151, -5.1749, -4.6233,\n",
" -0.9623, -3.7855, -0.8715, -3.7745, -3.0161, -1.1780, 0.1758, -2.7365,\n",
" 4.8934, 0.3046, -3.1761, -3.2762, 0.8937, 5.6606, -0.3623, -4.9554,\n",
" -3.2531, -0.0914, 1.6211, -0.9623]]), hidden_states=None,\n",
"attentions=None)\n"
]
}
],
"source": [
"import torch\n",
"from transformers import AutoModelForQuestionAnswering\n",
"\n",
"model = AutoModelForQuestionAnswering.from_pretrained(model_ckpt)\n",
"\n",
"with torch.no_grad():\n",
" outputs = model(**inputs)\n",
"print(outputs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "69-ON3WFz41q"
},
"outputs": [],
"source": [
"start_logits = outputs.start_logits\n",
"end_logits = outputs.end_logits"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "P1rqgx9qz41r",
"outputId": "4383e8fe-8515-449c-b643-93b9a2717f79"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"입력 ID 크기: torch.Size([1, 28])\n",
"시작 로짓 크기: torch.Size([1, 28])\n",
"종료 로짓 크기: torch.Size([1, 28])\n"
]
}
],
"source": [
"print(f\"입력 ID 크기: {inputs.input_ids.size()}\")\n",
"print(f\"시작 로짓 크기: {start_logits.size()}\")\n",
"print(f\"종료 로짓 크기: {end_logits.size()}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 425
},
"id": "xxQGLWylz41r",
"outputId": "aa9784f6-2187-4481-e9e8-2bec3deb1342"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"