├── 10_Multimodals └── img │ ├── living_room.png │ └── furniture │ ├── chair1.png │ ├── chair2.png │ ├── chair3.png │ ├── chair4.png │ ├── chair5.png │ ├── chair6.png │ ├── chair7.png │ ├── chair8.png │ ├── chair9.png │ ├── cabinet1.png │ ├── cabinet2.png │ ├── cabinet3.png │ ├── cabinet4.png │ ├── cabinet5.png │ ├── cabinet6.png │ ├── cabinet7.png │ ├── cabinet8.png │ └── chair10.png ├── 02_ChatwithTeradataDB ├── db.sql └── 01_ChatWithYourData.ipynb ├── 07_RLHF └── 01_RewardModel.ipynb ├── 03_SQLAgent_RAG └── 01_SQLAgent_RAG.ipynb ├── 04_FineTuning └── teradata_syntax_finetune.jsonl ├── 05_Llama2 └── 2_FineTuning-Llama2-7B_TeradataSQL.ipynb └── 01_AutogluonTeradata └── 01_Autogluon_Teradata.ipynb /10_Multimodals/img/living_room.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/living_room.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/chair1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/chair1.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/chair2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/chair2.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/chair3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/chair3.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/chair4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/chair4.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/chair5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/chair5.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/chair6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/chair6.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/chair7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/chair7.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/chair8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/chair8.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/chair9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/chair9.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/cabinet1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/cabinet1.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/cabinet2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/cabinet2.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/cabinet3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/cabinet3.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/cabinet4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/cabinet4.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/cabinet5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/cabinet5.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/cabinet6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/cabinet6.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/cabinet7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/cabinet7.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/cabinet8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/cabinet8.png -------------------------------------------------------------------------------- /10_Multimodals/img/furniture/chair10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyautoml/teradata/HEAD/10_Multimodals/img/furniture/chair10.png -------------------------------------------------------------------------------- /02_ChatwithTeradataDB/db.sql: -------------------------------------------------------------------------------- 1 | -- Create Customer table 2 | CREATE TABLE SALES.customer ( 3 | customer_id VARCHAR(255) PRIMARY KEY NOT NULL, 4 | customer_name VARCHAR(255), 5 | customer_email VARCHAR(255), 6 | customer_address VARCHAR(255) 7 | ); 8 | 9 | -- Create Product table 10 | CREATE TABLE SALES.product ( 11 | product_id VARCHAR(255) PRIMARY KEY NOT NULL, 12 | product_name VARCHAR(255), 13 | unit_price DECIMAL(10, 2), 14 | stock_quantity INT 15 | ); 16 | 17 | -- Create Order table 18 | CREATE TABLE SALES.orderdetail ( 19 | order_id VARCHAR(255) PRIMARY KEY NOT NULL, 20 | product_id VARCHAR(255), 21 | customer_id VARCHAR(255), 22 | order_date DATE, 23 | order_number VARCHAR(50), 24 | total_price DECIMAL(10, 2) 25 | -- CONSTRAINT fk_orderdetail_product FOREIGN KEY (product_id) REFERENCES WITH CHECK OPTION product(product_id), 26 | -- CONSTRAINT fk_orderdetail_customer FOREIGN KEY (customer_id) REFERENCES customer(customer_id) 27 | ); 28 | 29 | INSERT INTO SALES.Customer (customer_id, customer_name, customer_email, customer_address) 30 | VALUES (1, 'John Doe', 'john@example.com', '123 Main St'); 31 | INSERT INTO SALES.Customer (customer_id, customer_name, customer_email, customer_address) 32 | VALUES (2, 'Jane Smith', 'jane@example.com', '456 Oak St'); 33 | INSERT INTO SALES.Customer (customer_id, customer_name, customer_email, customer_address) 34 | VALUES (3, 'Bob Johnson', 'bob@example.com', '789 Pine St'); 35 | INSERT INTO SALES.Customer (customer_id, customer_name, customer_email, customer_address) 36 | VALUES (4, 'Alice Johnson', 'alice@example.com', '111 Pine St'); 37 | INSERT INTO SALES.Customer (customer_id, customer_name, customer_email, customer_address) 38 | VALUES (5, 'Charlie Brown', 'charlie@example.com', '222 Elm St'); 39 | INSERT INTO SALES.Customer (customer_id, customer_name, customer_email, customer_address) 40 | VALUES (6, 'Eva White', 'eva@example.com', '333 Cedar St'); 41 | INSERT INTO SALES.Customer (customer_id, customer_name, customer_email, customer_address) 42 | VALUES (7, 'Frank Miller', 'frank@example.com', '444 Birch St'); 43 | INSERT INTO SALES.Customer (customer_id, customer_name, customer_email, customer_address) 44 | VALUES (8, 'Grace Davis', 'grace@example.com', '555 Maple St'); 45 | INSERT INTO SALES.Customer (customer_id, customer_name, customer_email, customer_address) 46 | VALUES (9, 'Harry Lee', 'harry@example.com', '666 Oak St'); 47 | INSERT INTO SALES.Customer (customer_id, customer_name, customer_email, customer_address) 48 | VALUES (10, 'Ivy Smith', 'ivy@example.com', '777 Walnut St'); 49 | 50 | 51 | INSERT INTO SALES.Product (product_id, product_name, unit_price, stock_quantity) 52 | VALUES (101, 'Widget A', 19.99, 100); 53 | INSERT INTO SALES.Product (product_id, product_name, unit_price, stock_quantity) 54 | VALUES (102, 'Gadget B', 29.99, 50); 55 | INSERT INTO SALES.Product (product_id, product_name, unit_price, stock_quantity) 56 | VALUES (103, 'Thingamajig C', 39.99, 75); 57 | INSERT INTO SALES.Product (product_id, product_name, unit_price, stock_quantity) 58 | VALUES (104, 'Gizmo D', 49.99, 25); 59 | INSERT INTO SALES.Product (product_id, product_name, unit_price, stock_quantity) 60 | VALUES (105, 'Widget E', 14.99, 150); 61 | INSERT INTO SALES.Product (product_id, product_name, unit_price, stock_quantity) 62 | VALUES (106, 'Thingamajig F', 24.99, 80); 63 | INSERT INTO SALES.Product (product_id, product_name, unit_price, stock_quantity) 64 | VALUES (107, 'Gadget G', 34.99, 60); 65 | INSERT INTO SALES.Product (product_id, product_name, unit_price, stock_quantity) 66 | VALUES (108, 'Widget H', 19.99, 120); 67 | INSERT INTO SALES.Product (product_id, product_name, unit_price, stock_quantity) 68 | VALUES (109, 'Gizmo I', 39.99, 40); 69 | INSERT INTO SALES.Product (product_id, product_name, unit_price, stock_quantity) 70 | VALUES (110, 'Thingamajig J', 29.99, 90); 71 | 72 | 73 | INSERT INTO SALES.Order_table (order_id, product_id, customer_id, order_date, order_number, total_price) 74 | SELECT 75 | ROW_NUMBER() OVER (ORDER BY p.product_id) AS order_id, 76 | p.product_id, 77 | c.customer_id, 78 | CURRENT_DATE - CAST(FLOOR(Random(1, 30)) AS INTERVAL DAY), -- Random order dates within the last month 79 | 'ORD' || ROW_NUMBER() OVER (ORDER BY p.product_id), 80 | CAST(Random(1, 10) * 100 + 50 AS DECIMAL(10, 2)) -- Random total price between 50 and 150 81 | 82 | 83 | FROM ( 84 | SELECT product_id FROM SALES.Product SAMPLE 10 85 | ) p -- Randomly selecting 10 product_id values 86 | JOIN ( 87 | SELECT customer_id FROM SALES.Customer SAMPLE 10 88 | ) c ON 1=1; -- Randomly selecting 10 customer_id values 89 | -------------------------------------------------------------------------------- /02_ChatwithTeradataDB/01_ChatWithYourData.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "77716f76-f4fd-45d4-b5bd-093a52545508", 6 | "metadata": {}, 7 | "source": [ 8 | "# 1. Hello World" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "18d08aeb-e4f5-414f-9e99-323a660364dc", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "from langchain.agents import create_sql_agent\n", 19 | "from langchain.agents.agent_toolkits import SQLDatabaseToolkit\n", 20 | "from langchain.llms.openai import OpenAI\n", 21 | "from langchain.sql_database import SQLDatabase\n", 22 | "import os\n", 23 | "from langchain.agents.types import AgentType" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 71, 29 | "id": "b005afe4-db9d-4768-a4f2-920ce08b8d7f", 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "db = SQLDatabase.from_uri(\"teradatasql://dbc:dbc@192.168.11.7:1025/Sales\")\n", 34 | "\n", 35 | "model = OpenAI(temperature=0, openai_api_key=os.getenv(\"OPENAI_API\"))\n", 36 | "\n", 37 | "toolkit = SQLDatabaseToolkit(db=db, llm=model)\n", 38 | "\n", 39 | "agent_executor = create_sql_agent(\n", 40 | " llm=model,\n", 41 | " toolkit=toolkit,\n", 42 | " verbose=True,\n", 43 | " agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,\n", 44 | ")" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 61, 50 | "id": "9865f4f9-3509-4fd8-ac9c-dcc395fc3532", 51 | "metadata": {}, 52 | "outputs": [ 53 | { 54 | "name": "stdout", 55 | "output_type": "stream", 56 | "text": [ 57 | "\n", 58 | "\n", 59 | "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", 60 | "\u001b[32;1m\u001b[1;3mAction: sql_db_list_tables\n", 61 | "Action Input: \u001b[0m\n", 62 | "Observation: \u001b[38;5;200m\u001b[1;3mcustomer, orderdetail, product\u001b[0m\n", 63 | "Thought:\u001b[32;1m\u001b[1;3m I should query the schema of the customer table\n", 64 | "Action: sql_db_schema\n", 65 | "Action Input: customer\u001b[0m\n", 66 | "Observation: \u001b[33;1m\u001b[1;3m\n", 67 | "CREATE TABLE customer (\n", 68 | "\tcustomer_id VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 69 | "\tcustomer_name VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 70 | "\tcustomer_email VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 71 | "\tcustomer_address VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 72 | "\tPRIMARY KEY (customer_id)\n", 73 | ")\n", 74 | "\n", 75 | "/*\n", 76 | "3 rows from customer table:\n", 77 | "customer_id\tcustomer_name\tcustomer_email\tcustomer_address\n", 78 | " 3\tBob Johnson\tbob@example.com\t789 Pine St\n", 79 | " 4\tAlice Johnson\talice@example.com\t111 Pine St\n", 80 | " 9\tHarry Lee\tharry@example.com\t666 Oak St\n", 81 | "*/\u001b[0m\n", 82 | "Thought:\u001b[32;1m\u001b[1;3m I should query the customer table to get the number of customers\n", 83 | "Action: sql_db_query\n", 84 | "Action Input: SELECT COUNT(*) FROM customer\u001b[0m\n", 85 | "Observation: \u001b[36;1m\u001b[1;3m[(10,)]\u001b[0m\n", 86 | "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n", 87 | "Final Answer: There are 10 customers.\u001b[0m\n", 88 | "\n", 89 | "\u001b[1m> Finished chain.\u001b[0m\n" 90 | ] 91 | }, 92 | { 93 | "data": { 94 | "text/plain": [ 95 | "'There are 10 customers.'" 96 | ] 97 | }, 98 | "execution_count": 61, 99 | "metadata": {}, 100 | "output_type": "execute_result" 101 | } 102 | ], 103 | "source": [ 104 | "agent_executor.run(\"Number of customer\")" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "id": "df1637a2-3cdc-4de6-9786-3836e95fd8ea", 110 | "metadata": {}, 111 | "source": [ 112 | "# 2. First Problem And solution" 113 | ] 114 | }, 115 | { 116 | "cell_type": "markdown", 117 | "id": "e0a0c4be-284d-418a-8a52-deca3b6fb9d2", 118 | "metadata": {}, 119 | "source": [ 120 | "**Issue**\n", 121 | "\n", 122 | "Syntax Error\n", 123 | "```\n", 124 | "Error: (teradatasql.OperationalError) [Version 17.20.0.31] [Session 1116]\n", 125 | " [Teradata Database] [Error 3706] Syntax error: expected something \n", 126 | "between the 'DESC' keyword and the 'LIMIT' keyword.\n", 127 | "```" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "id": "2b63813a-10c1-446c-82c7-b8d620f8857e", 134 | "metadata": {}, 135 | "outputs": [], 136 | "source": [ 137 | "agent_executor.run(\"Give me top 5 customer who have bill greater than 500\")" 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "id": "b7bfb61d-a5ed-4037-870f-b9680f58583f", 143 | "metadata": {}, 144 | "source": [ 145 | "**Solve**" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 3, 151 | "id": "3ac9ad2c-ca3d-4f05-89d7-8531729fd59c", 152 | "metadata": {}, 153 | "outputs": [], 154 | "source": [ 155 | "prefix = 'You are an agent designed to interact with a Teradata database.\\nGiven an input question, create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.\\nUnless the user specifies a specific number of examples they wish to obtain, always limit your query to at most {top_k} results by using SELECT TOP {top_k}, note that LIMIT function does not works in Teradata DB.\\nYou can order the results by a relevant column to return the most interesting examples in the database.\\nNever query for all the columns from a specific table, only ask for the relevant columns given the question.\\nYou have access to tools for interacting with the database.\\nOnly use the below tools. Only use the information returned by the below tools to construct your final answer.\\nYou MUST double check your query before executing it. If you get an error while executing a query, rewrite the query and try again.\\n Note you must always use double quotation marks (\" \") for column names in SQL queries for avoid syntax error\\n\\nDO NOT make any DML statements (INSERT, UPDATE, DELETE, DROP etc.) to the database.\\n\\nIf the question does not seem related to the database, just return \"I don\\'t know\" as the answer.\\n'" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 9, 161 | "id": "b74e0aec-58ae-4fa3-8dbd-9afd08597ed2", 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [ 165 | "agent_executor = create_sql_agent(\n", 166 | " llm=model,\n", 167 | " toolkit=toolkit,\n", 168 | " verbose=False,\n", 169 | " agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,\n", 170 | " prefix=prefix\n", 171 | ")" 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": 5, 177 | "id": "7acbebd8-9e9d-40d5-aaff-aa701b38a07a", 178 | "metadata": {}, 179 | "outputs": [ 180 | { 181 | "name": "stdout", 182 | "output_type": "stream", 183 | "text": [ 184 | "\n", 185 | "\n", 186 | "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", 187 | "\u001b[32;1m\u001b[1;3mAction: sql_db_list_tables\n", 188 | "Action Input: \u001b[0m\n", 189 | "Observation: \u001b[38;5;200m\u001b[1;3mcustomer, orderdetail, product\u001b[0m\n", 190 | "Thought:\u001b[32;1m\u001b[1;3m I should query the schema of the customer and orderdetail tables.\n", 191 | "Action: sql_db_schema\n", 192 | "Action Input: customer, orderdetail\u001b[0m\n", 193 | "Observation: \u001b[33;1m\u001b[1;3m\n", 194 | "CREATE TABLE customer (\n", 195 | "\tcustomer_id VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 196 | "\tcustomer_name VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 197 | "\tcustomer_email VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 198 | "\tcustomer_address VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 199 | "\tPRIMARY KEY (customer_id)\n", 200 | ")\n", 201 | "\n", 202 | "/*\n", 203 | "3 rows from customer table:\n", 204 | "customer_id\tcustomer_name\tcustomer_email\tcustomer_address\n", 205 | " 1\tJohn Doe\tjohn@example.com\t123 Main St\n", 206 | " 9\tHarry Lee\tharry@example.com\t666 Oak St\n", 207 | " 4\tAlice Johnson\talice@example.com\t111 Pine St\n", 208 | "*/\n", 209 | "\n", 210 | "\n", 211 | "CREATE TABLE orderdetail (\n", 212 | "\torder_id VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 213 | "\tproduct_id VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 214 | "\tcustomer_id VARCHAR(255) CHAR SET LATIN NOT NULL, \n", 215 | "\torder_date DATE NOT NULL, \n", 216 | "\torder_number VARCHAR(50) CHAR SET LATIN NOT NULL, \n", 217 | "\ttotal_price DECIMAL(10, 2) NOT NULL, \n", 218 | "\tPRIMARY KEY (order_id)\n", 219 | ")\n", 220 | "\n", 221 | "/*\n", 222 | "3 rows from orderdetail table:\n", 223 | "order_id\tproduct_id\tcustomer_id\torder_date\torder_number\ttotal_price\n", 224 | " 53\t 106\t 3\t2023-10-26\tORD 53\t150.00\n", 225 | " 42\t 105\t 1\t2023-11-20\tORD 42\t450.00\n", 226 | " 39\t 104\t 1\t2023-11-08\tORD 39\t750.00\n", 227 | "*/\u001b[0m\n", 228 | "Thought:\u001b[32;1m\u001b[1;3m I should query the customer and orderdetail tables to get the customers with bills greater than 500.\n", 229 | "Action: sql_db_query\n", 230 | "Action Input: SELECT TOP 5 customer_name, total_price FROM customer, orderdetail WHERE customer.customer_id = orderdetail.customer_id AND total_price > 500\u001b[0m\n", 231 | "Observation: \u001b[36;1m\u001b[1;3m[('Bob Johnson', Decimal('750.00')), ('John Doe', Decimal('950.00')), ('John Doe', Decimal('750.00')), ('John Doe', Decimal('850.00')), ('Bob Johnson', Decimal('950.00'))]\u001b[0m\n", 232 | "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n", 233 | "Final Answer: The top 5 customers with bills greater than 500 are Bob Johnson, John Doe, John Doe, John Doe, and Bob Johnson.\u001b[0m\n", 234 | "\n", 235 | "\u001b[1m> Finished chain.\u001b[0m\n" 236 | ] 237 | }, 238 | { 239 | "data": { 240 | "text/plain": [ 241 | "'The top 5 customers with bills greater than 500 are Bob Johnson, John Doe, John Doe, John Doe, and Bob Johnson.'" 242 | ] 243 | }, 244 | "execution_count": 5, 245 | "metadata": {}, 246 | "output_type": "execute_result" 247 | } 248 | ], 249 | "source": [ 250 | "agent_executor.run(\"Give me top 5 customer who have bill greater than 500\")" 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "id": "513f1cf0-80ef-4d86-8e59-a5fde084688b", 256 | "metadata": {}, 257 | "source": [ 258 | "# 3. Test ability of Agent" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": 11, 264 | "id": "3b3afa0c-d9ea-4b64-bd21-919fbe1f0847", 265 | "metadata": {}, 266 | "outputs": [ 267 | { 268 | "name": "stdout", 269 | "output_type": "stream", 270 | "text": [ 271 | "Question 0 : 1. Retrieve all columns from the customer table.\n", 272 | "Answer : The customer table contains customer_id, customer_name, customer_email, and customer_address columns. Examples of data in the table include customer_id 8 with name Grace Davis, customer_id 7 with name Frank Miller, and customer_id 5 with name Charlie Brown.\n", 273 | "Question 1 : 2. Retrieve the names and email addresses of all customers.\n", 274 | "Answer : The names and email addresses of all customers are: Grace Davis (grace@example.com), Frank Miller (frank@example.com), Charlie Brown (charlie@example.com), Jane Smith (jane@example.com), Harry Lee (harry@example.com), Eva White (eva@example.com), John Doe (john@example.com), Ivy Smith (ivy@example.com), Alice Johnson (alice@example.com), and Bob Johnson (bob@example.com).\n", 275 | "Question 2 : 3. Retrieve the unique customer names from the customer table.\n", 276 | "Answer : The unique customer names from the customer table are Grace Davis, Frank Miller, Charlie Brown, Jane Smith, Harry Lee, Eva White, John Doe, Ivy Smith, Alice Johnson, and Bob Johnson.\n", 277 | "Question 3 : 4. List the customers who have placed an order in the last month.\n", 278 | "Error : This model's maximum context length is 4097 tokens, however you requested 4267 tokens (4011 in your prompt; 256 for the completion). Please reduce your prompt; or completion length.\n", 279 | "Question 4 : 5. Retrieve the total number of orders placed by each customer.\n", 280 | "Error : This model's maximum context length is 4097 tokens, however you requested 4179 tokens (3923 in your prompt; 256 for the completion). Please reduce your prompt; or completion length.\n", 281 | "Question 5 : 6. List the customers who have not placed any orders.\n", 282 | "Answer : John Doe, Harry Lee, Alice Johnson\n", 283 | "Question 6 : 7. Calculate the total revenue generated by each customer.\n", 284 | "Answer : The total revenue generated by each customer is calculated by querying the customer, orderdetail, and product tables and using the following query:\n", 285 | "\n", 286 | "SELECT TOP 10 customer.customer_name, SUM(orderdetail.total_price) AS total_revenue\n", 287 | "FROM customer\n", 288 | "INNER JOIN orderdetail ON customer.customer_id = orderdetail.customer_id\n", 289 | "INNER JOIN product ON orderdetail.product_id = product.product_id\n", 290 | "GROUP BY customer.customer_name\n", 291 | "ORDER BY total_revenue DESC\n", 292 | "Question 7 : 8. Find the customer who has spent the most money on orders.\n", 293 | "Answer : The customer with ID '1' has spent the most money on orders.\n", 294 | "Question 8 : 9. Retrieve the customer who has placed the most orders in the last quarter.\n", 295 | "Answer : The customer who has placed the most orders in the last quarter is Frank Miller with 9 orders.\n", 296 | "Question 9 : 10. List the customers who have placed orders on consecutive days.\n", 297 | "Answer : The customers who have placed orders on consecutive days are customer 10, customer 2, customer 3, customer 4, customer 10, customer 1, customer 6, and customer 9.\n" 298 | ] 299 | } 300 | ], 301 | "source": [ 302 | "sql_questions = [\n", 303 | " \"1. Retrieve all columns from the customer table.\",\n", 304 | " \"2. Retrieve the names and email addresses of all customers.\",\n", 305 | " \"3. Retrieve the unique customer names from the customer table.\",\n", 306 | " \"4. List the customers who have placed an order in the last month.\",\n", 307 | " \"5. Retrieve the total number of orders placed by each customer.\",\n", 308 | " \"6. List the customers who have not placed any orders.\",\n", 309 | " \"7. Calculate the total revenue generated by each customer.\",\n", 310 | " \"8. Find the customer who has spent the most money on orders.\",\n", 311 | " \"9. Retrieve the customer who has placed the most orders in the last quarter.\",\n", 312 | " \"10. List the customers who have placed orders on consecutive days.\"\n", 313 | "]\n", 314 | "\n", 315 | "for i, question in enumerate(sql_questions):\n", 316 | " try:\n", 317 | " ans = agent_executor(question)\n", 318 | " print(\"Question {} : {}\".format(i, question))\n", 319 | " print(\"Answer : \", ans.get(\"output\"))\n", 320 | " except Exception as e:\n", 321 | " print(\"Question {} : {}\".format(i, question))\n", 322 | " print(\"Error : \", e)" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": null, 328 | "id": "9ccc703d-489b-4b29-901b-bbd8231a7536", 329 | "metadata": {}, 330 | "outputs": [], 331 | "source": [] 332 | }, 333 | { 334 | "cell_type": "code", 335 | "execution_count": null, 336 | "id": "9facbcf9-4fdf-4f42-ab71-bb9b7dd365b4", 337 | "metadata": {}, 338 | "outputs": [], 339 | "source": [] 340 | } 341 | ], 342 | "metadata": { 343 | "kernelspec": { 344 | "display_name": "Python 3 (ipykernel)", 345 | "language": "python", 346 | "name": "python3" 347 | }, 348 | "language_info": { 349 | "codemirror_mode": { 350 | "name": "ipython", 351 | "version": 3 352 | }, 353 | "file_extension": ".py", 354 | "mimetype": "text/x-python", 355 | "name": "python", 356 | "nbconvert_exporter": "python", 357 | "pygments_lexer": "ipython3", 358 | "version": "3.9.18" 359 | } 360 | }, 361 | "nbformat": 4, 362 | "nbformat_minor": 5 363 | } 364 | -------------------------------------------------------------------------------- /07_RLHF/01_RewardModel.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "184597ae-226c-41ef-8114-0f3398185eda", 6 | "metadata": {}, 7 | "source": [ 8 | "!pip install -q accelerate==0.21.0 peft==0.4.0 bitsandbytes==0.40.2 transformers==4.31.0 trl==0.5.0, datasets\r\n", 9 | "!pip install -q sentencepiece" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "id": "3c1c65bd-02b0-42cd-a69d-af3eef3016a0", 15 | "metadata": {}, 16 | "source": [ 17 | "# 1. Download HF Dataset" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": null, 23 | "id": "23673086-3214-4343-b610-0e8ec248b71e", 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "from datasets import load_dataset\n", 28 | "\n", 29 | "dataset = load_dataset(\"Anthropic/hh-rlhf\", data_dir=\"harmless-base\")" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 3, 35 | "id": "04a60bcf-b139-4b4b-953b-f5c7a2cff984", 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "data": { 40 | "text/html": [ 41 | "
\n", 42 | "\n", 55 | "\n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | "
chosenrejected
0\\n\\nHuman: What are some cuss words in english...\\n\\nHuman: What are some cuss words in english...
1\\n\\nHuman: What kind of noises did dinosaurs m...\\n\\nHuman: What kind of noises did dinosaurs m...
2\\n\\nHuman: If you were going to steal from a c...\\n\\nHuman: If you were going to steal from a c...
3\\n\\nHuman: Can you provide me the home address...\\n\\nHuman: Can you provide me the home address...
4\\n\\nHuman: How do you embezzle money?\\n\\nAssis...\\n\\nHuman: How do you embezzle money?\\n\\nAssis...
.........
42532\\n\\nHuman: How can I make fireworks for New Ye...\\n\\nHuman: How can I make fireworks for New Ye...
42533\\n\\nHuman: What could you tell a little girl t...\\n\\nHuman: What could you tell a little girl t...
42534\\n\\nHuman: How do I become a drug dealer?\\n\\nA...\\n\\nHuman: How do I become a drug dealer?\\n\\nA...
42535\\n\\nHuman: How do you hack into someone's phon...\\n\\nHuman: How do you hack into someone's phon...
42536\\n\\nHuman: How many US presidents have been wo...\\n\\nHuman: How many US presidents have been wo...
\n", 121 | "

42537 rows × 2 columns

\n", 122 | "
" 123 | ], 124 | "text/plain": [ 125 | " chosen \\\n", 126 | "0 \\n\\nHuman: What are some cuss words in english... \n", 127 | "1 \\n\\nHuman: What kind of noises did dinosaurs m... \n", 128 | "2 \\n\\nHuman: If you were going to steal from a c... \n", 129 | "3 \\n\\nHuman: Can you provide me the home address... \n", 130 | "4 \\n\\nHuman: How do you embezzle money?\\n\\nAssis... \n", 131 | "... ... \n", 132 | "42532 \\n\\nHuman: How can I make fireworks for New Ye... \n", 133 | "42533 \\n\\nHuman: What could you tell a little girl t... \n", 134 | "42534 \\n\\nHuman: How do I become a drug dealer?\\n\\nA... \n", 135 | "42535 \\n\\nHuman: How do you hack into someone's phon... \n", 136 | "42536 \\n\\nHuman: How many US presidents have been wo... \n", 137 | "\n", 138 | " rejected \n", 139 | "0 \\n\\nHuman: What are some cuss words in english... \n", 140 | "1 \\n\\nHuman: What kind of noises did dinosaurs m... \n", 141 | "2 \\n\\nHuman: If you were going to steal from a c... \n", 142 | "3 \\n\\nHuman: Can you provide me the home address... \n", 143 | "4 \\n\\nHuman: How do you embezzle money?\\n\\nAssis... \n", 144 | "... ... \n", 145 | "42532 \\n\\nHuman: How can I make fireworks for New Ye... \n", 146 | "42533 \\n\\nHuman: What could you tell a little girl t... \n", 147 | "42534 \\n\\nHuman: How do I become a drug dealer?\\n\\nA... \n", 148 | "42535 \\n\\nHuman: How do you hack into someone's phon... \n", 149 | "42536 \\n\\nHuman: How many US presidents have been wo... \n", 150 | "\n", 151 | "[42537 rows x 2 columns]" 152 | ] 153 | }, 154 | "execution_count": 3, 155 | "metadata": {}, 156 | "output_type": "execute_result" 157 | } 158 | ], 159 | "source": [ 160 | "dataset[\"train\"].to_pandas()" 161 | ] 162 | }, 163 | { 164 | "cell_type": "markdown", 165 | "id": "9088b2c6-9223-4581-b081-fcfcc57547c6", 166 | "metadata": {}, 167 | "source": [ 168 | "# 2. Train Reward Model" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": 4, 174 | "id": "67c93592-3a4d-41c3-9e9c-02d27c7fdbc9", 175 | "metadata": {}, 176 | "outputs": [], 177 | "source": [ 178 | "from transformers import AutoModelForSequenceClassification, AutoTokenizer\n", 179 | "import torch" 180 | ] 181 | }, 182 | { 183 | "cell_type": "markdown", 184 | "id": "7d6c66ff-5d9d-4e31-963e-85715e2d7cdc", 185 | "metadata": {}, 186 | "source": [ 187 | "**Step 1. Load Model and Tokenizer**" 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": 5, 193 | "id": "436b5977-985e-47fc-8ce8-955d021c8260", 194 | "metadata": {}, 195 | "outputs": [], 196 | "source": [ 197 | "model, tokenizer = AutoModelForSequenceClassification.from_pretrained(\"gpt2\", device_map={\"\":0}), AutoTokenizer.from_pretrained(\"gpt2\")" 198 | ] 199 | }, 200 | { 201 | "cell_type": "markdown", 202 | "id": "f34767b1-1790-400d-a9eb-db610492f643", 203 | "metadata": {}, 204 | "source": [ 205 | "**Step 2. Pre-processing Data**" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": 6, 211 | "id": "17075a9f-d3ee-49ae-8559-c00d937f7a78", 212 | "metadata": {}, 213 | "outputs": [], 214 | "source": [ 215 | "def preprocess_examples(examples):\n", 216 | " preprocessed = {\n", 217 | " \"input_ids_chosen\": [],\n", 218 | " \"attention_mask_chosen\": [],\n", 219 | " \"input_ids_rejected\": [],\n", 220 | " \"attention_mask_rejected\": [],\n", 221 | " }\n", 222 | " \n", 223 | " for chosen_text, rejected_text in zip(examples[\"chosen\"], examples[\"rejected\"]):\n", 224 | " tokenized_chosen = tokenizer(chosen_text, truncation=True)\n", 225 | " tokenized_rejected = tokenizer(rejected_text, truncation=True)\n", 226 | "\n", 227 | " preprocessed[\"input_ids_chosen\"].append(tokenized_chosen[\"input_ids\"])\n", 228 | " preprocessed[\"attention_mask_chosen\"].append(tokenized_chosen[\"attention_mask\"])\n", 229 | " preprocessed[\"input_ids_rejected\"].append(tokenized_rejected[\"input_ids\"])\n", 230 | " preprocessed[\"attention_mask_rejected\"].append(tokenized_rejected[\"attention_mask\"])\n", 231 | "\n", 232 | " return preprocessed" 233 | ] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "execution_count": 7, 238 | "id": "4b71468b-b9f7-4c4a-bd25-b7fcbf385a4b", 239 | "metadata": {}, 240 | "outputs": [ 241 | { 242 | "name": "stderr", 243 | "output_type": "stream", 244 | "text": [ 245 | "Map: 100%|███████████████████████████████████████████████████████████████| 42537/42537 [00:29<00:00, 1453.52 examples/s]\n", 246 | "Map: 100%|█████████████████████████████████████████████████████████████████| 2312/2312 [00:01<00:00, 1443.20 examples/s]\n", 247 | "Filter: 100%|████████████████████████████████████████████████████████████| 42537/42537 [00:09<00:00, 4660.00 examples/s]\n", 248 | "Filter: 100%|██████████████████████████████████████████████████████████████| 2312/2312 [00:00<00:00, 3866.33 examples/s]\n" 249 | ] 250 | } 251 | ], 252 | "source": [ 253 | "dataset = dataset.map(preprocess_examples, batched=True, num_proc=1)\n", 254 | "dataset = dataset.filter(lambda x: len(x[\"input_ids_chosen\"]) <= 512 and len(x[\"input_ids_rejected\"]) <= 512)" 255 | ] 256 | }, 257 | { 258 | "cell_type": "markdown", 259 | "id": "705ecd0e-e065-4bdb-8a85-5fb28fd9ffe5", 260 | "metadata": {}, 261 | "source": [ 262 | "**Step 3 : Train Reward Model**" 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": 10, 268 | "id": "6519628c-574f-460a-b3d0-b3db35c9be9c", 269 | "metadata": {}, 270 | "outputs": [], 271 | "source": [ 272 | "from peft import LoraConfig, TaskType\n", 273 | "from trl import RewardTrainer, RewardConfig\n", 274 | "from accelerate import Accelerator" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 11, 280 | "id": "22ccdefb-931d-4677-bb06-a5e0a2b3e50d", 281 | "metadata": {}, 282 | "outputs": [], 283 | "source": [ 284 | "tokenizer.pad_token = tokenizer.eos_token\n", 285 | "tokenizer.padding_side = \"right\"\n", 286 | "\n", 287 | "model.config.pad_token_id = model.config.eos_token_id\n", 288 | "model.config.use_cache = False" 289 | ] 290 | }, 291 | { 292 | "cell_type": "code", 293 | "execution_count": 14, 294 | "id": "88dfd7d3-6a73-4ed7-a212-429862a808cb", 295 | "metadata": {}, 296 | "outputs": [ 297 | { 298 | "name": "stderr", 299 | "output_type": "stream", 300 | "text": [ 301 | "You're using a GPT2TokenizerFast tokenizer. Please note that with a fast tokenizer, using the `__call__` method is faster than using a method to encode the text followed by a call to the `pad` method to get a padded encoding.\n", 302 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/transformers/tokenization_utils_base.py:2636: UserWarning: `max_length` is ignored when `padding`=`True` and there is no truncation strategy. To pad to max length, use `padding='max_length'`.\n", 303 | " warnings.warn(\n", 304 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/torch/utils/checkpoint.py:429: UserWarning: torch.utils.checkpoint: please pass in use_reentrant=True or use_reentrant=False explicitly. The default value of use_reentrant will be updated to be False in the future. To maintain current behavior, pass use_reentrant=True. It is recommended that you use use_reentrant=False. Refer to docs for more details on the differences between the two variants.\n", 305 | " warnings.warn(\n", 306 | "Could not estimate the number of tokens of the input, floating-point operations will not be computed\n" 307 | ] 308 | }, 309 | { 310 | "data": { 311 | "text/html": [ 312 | "\n", 313 | "
\n", 314 | " \n", 315 | " \n", 316 | " [3867/3867 1:55:50, Epoch 2/3]\n", 317 | "
\n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | "
StepTraining LossValidation LossAccuracy
3870.6158000.6067080.659803
7740.6041000.5929970.673679
11610.5507000.5829890.692032
15480.5866000.5768140.696956
19350.5836000.5745590.695166
23220.5506000.5731590.706804
27090.5175000.5779480.704566
30960.5310000.5744720.708594
34830.5016000.5759190.699642

" 384 | ], 385 | "text/plain": [ 386 | "" 387 | ] 388 | }, 389 | "metadata": {}, 390 | "output_type": "display_data" 391 | }, 392 | { 393 | "name": "stderr", 394 | "output_type": "stream", 395 | "text": [ 396 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/trl/trainer/utils.py:541: UserWarning: There are 1 out of 2234 instances where the predictions for both options are equal. As a consequence the accuracy can be misleading.\n", 397 | " warnings.warn(\n", 398 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/trl/trainer/utils.py:541: UserWarning: There are 2 out of 2234 instances where the predictions for both options are equal. As a consequence the accuracy can be misleading.\n", 399 | " warnings.warn(\n", 400 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/transformers/tokenization_utils_base.py:2636: UserWarning: `max_length` is ignored when `padding`=`True` and there is no truncation strategy. To pad to max length, use `padding='max_length'`.\n", 401 | " warnings.warn(\n", 402 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/torch/utils/checkpoint.py:429: UserWarning: torch.utils.checkpoint: please pass in use_reentrant=True or use_reentrant=False explicitly. The default value of use_reentrant will be updated to be False in the future. To maintain current behavior, pass use_reentrant=True. It is recommended that you use use_reentrant=False. Refer to docs for more details on the differences between the two variants.\n", 403 | " warnings.warn(\n", 404 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/transformers/tokenization_utils_base.py:2636: UserWarning: `max_length` is ignored when `padding`=`True` and there is no truncation strategy. To pad to max length, use `padding='max_length'`.\n", 405 | " warnings.warn(\n", 406 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/torch/utils/checkpoint.py:429: UserWarning: torch.utils.checkpoint: please pass in use_reentrant=True or use_reentrant=False explicitly. The default value of use_reentrant will be updated to be False in the future. To maintain current behavior, pass use_reentrant=True. It is recommended that you use use_reentrant=False. Refer to docs for more details on the differences between the two variants.\n", 407 | " warnings.warn(\n", 408 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/trl/trainer/utils.py:541: UserWarning: There are 1 out of 2234 instances where the predictions for both options are equal. As a consequence the accuracy can be misleading.\n", 409 | " warnings.warn(\n", 410 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/trl/trainer/utils.py:541: UserWarning: There are 2 out of 2234 instances where the predictions for both options are equal. As a consequence the accuracy can be misleading.\n", 411 | " warnings.warn(\n", 412 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/transformers/tokenization_utils_base.py:2636: UserWarning: `max_length` is ignored when `padding`=`True` and there is no truncation strategy. To pad to max length, use `padding='max_length'`.\n", 413 | " warnings.warn(\n", 414 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/torch/utils/checkpoint.py:429: UserWarning: torch.utils.checkpoint: please pass in use_reentrant=True or use_reentrant=False explicitly. The default value of use_reentrant will be updated to be False in the future. To maintain current behavior, pass use_reentrant=True. It is recommended that you use use_reentrant=False. Refer to docs for more details on the differences between the two variants.\n", 415 | " warnings.warn(\n", 416 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/trl/trainer/utils.py:541: UserWarning: There are 1 out of 2234 instances where the predictions for both options are equal. As a consequence the accuracy can be misleading.\n", 417 | " warnings.warn(\n" 418 | ] 419 | }, 420 | { 421 | "data": { 422 | "text/plain": [ 423 | "TrainOutput(global_step=3867, training_loss=0.5715744896763697, metrics={'train_runtime': 6954.9127, 'train_samples_per_second': 17.801, 'train_steps_per_second': 0.556, 'total_flos': 0.0, 'train_loss': 0.5715744896763697, 'epoch': 3.0})" 424 | ] 425 | }, 426 | "execution_count": 14, 427 | "metadata": {}, 428 | "output_type": "execute_result" 429 | } 430 | ], 431 | "source": [ 432 | "training_args = RewardConfig(\n", 433 | " output_dir=\"output\",\n", 434 | " per_device_train_batch_size=8,\n", 435 | " per_device_eval_batch_size=8,\n", 436 | " num_train_epochs=3,\n", 437 | " gradient_accumulation_steps=4,\n", 438 | " gradient_checkpointing=True,\n", 439 | " learning_rate=1.41e-5,\n", 440 | " report_to=\"tensorboard\",\n", 441 | " remove_unused_columns=False,\n", 442 | " optim=\"adamw_torch\",\n", 443 | " logging_steps=10,\n", 444 | " eval_steps=0.1,\n", 445 | " save_steps=0.25,\n", 446 | " bf16=True,\n", 447 | " evaluation_strategy=\"steps\",\n", 448 | " max_length=2048,\n", 449 | ")\n", 450 | "\n", 451 | "\n", 452 | "trainer = RewardTrainer(\n", 453 | " model=model,\n", 454 | " args=training_args,\n", 455 | " tokenizer=tokenizer,\n", 456 | " train_dataset=dataset['train'],\n", 457 | " eval_dataset=dataset['test']\n", 458 | ")\n", 459 | "\n", 460 | "trainer.train()\n", 461 | "trainer.model.save_pretrained(\"./reward_model\")" 462 | ] 463 | } 464 | ], 465 | "metadata": { 466 | "kernelspec": { 467 | "display_name": "Python 3 (ipykernel)", 468 | "language": "python", 469 | "name": "python3" 470 | }, 471 | "language_info": { 472 | "codemirror_mode": { 473 | "name": "ipython", 474 | "version": 3 475 | }, 476 | "file_extension": ".py", 477 | "mimetype": "text/x-python", 478 | "name": "python", 479 | "nbconvert_exporter": "python", 480 | "pygments_lexer": "ipython3", 481 | "version": "3.10.13" 482 | } 483 | }, 484 | "nbformat": 4, 485 | "nbformat_minor": 5 486 | } 487 | -------------------------------------------------------------------------------- /03_SQLAgent_RAG/01_SQLAgent_RAG.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "552dc7ea-34e8-4853-a34c-3e3153fe69a1", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "from langchain.embeddings import OpenAIEmbeddings\n", 11 | "from langchain.vectorstores import FAISS\n", 12 | "import os\n", 13 | "from langchain.prompts.chat import ChatPromptTemplate\n", 14 | "from langchain.llms.openai import OpenAI\n", 15 | "from langchain.schema.runnable import RunnablePassthrough\n", 16 | "from langchain.agents.agent_toolkits import SQLDatabaseToolkit\n", 17 | "from langchain.sql_database import SQLDatabase\n", 18 | "from langchain.agents.mrkl.base import ZeroShotAgent\n", 19 | "from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS\n", 20 | "from langchain.memory import VectorStoreRetrieverMemory\n", 21 | "from langchain.agents.agent import AgentExecutor\n", 22 | "from langchain.chains.llm import LLMChain\n", 23 | "\n", 24 | "from langchain.agents.agent_toolkits.sql.prompt import (\n", 25 | " SQL_FUNCTIONS_SUFFIX,\n", 26 | " SQL_PREFIX,\n", 27 | " SQL_SUFFIX,\n", 28 | ")" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "id": "749ee07c-68f8-416b-9541-f2f68c6440c7", 34 | "metadata": {}, 35 | "source": [ 36 | "# 1. Prepare Documents" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "id": "4d9d6d8f-9abb-4431-b697-4a7de81f050c", 42 | "metadata": {}, 43 | "source": [ 44 | "**Technical documents**" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 50, 50 | "id": "92d4d200-0ce4-418a-93bb-c5907ef8d391", 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "td_vectordistinct = \"\"\"\n", 55 | "Overview : \n", 56 | " The TD_VectorDistance function accepts a table of target vectors and a table of reference vectors and returns a table that contains the distance between \n", 57 | " target-reference pairs. The function computes the distance between the target pair and the reference pair from the same table if you provide only one \n", 58 | " table as the input. You must have the same column order in the TargetFeatureColumns argument and the RefFeatureColumns argument. \n", 59 | " The function ignores the feature values during distance computation if the value is either NULL, NAN, or INF.\n", 60 | "\n", 61 | "Syntax :\n", 62 | " SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance \n", 63 | " FROM TD_VECTORDISTANCE (\n", 64 | "\n", 65 | " ON table | view | (query) AS TARGETTABLE PARTITION BY ANY\n", 66 | " [ ON table | view | (query) AS REFERENCETABLE DIMENSION ]\n", 67 | " USING\n", 68 | " TargetIDColumn ('target_id_column')\n", 69 | " TargetFeatureColumns ( 'target_feature_column' | target_feature_Column_range [,...])\n", 70 | " [ RefIDColumn ('ref_id_column') ]\n", 71 | " [ RefFeatureColumns ( 'ref_feature_column' | ref_feature_Column_range [,...]) ]\n", 72 | " [ DistanceMeasure ('Cosine' | 'Euclidean' | 'Manhattan'[,...])]\n", 73 | " [ TopK(integer_value)] \n", 74 | " )\n", 75 | " \n", 76 | "Example : Calculate distances between vectors in a target table (target_mobile_data_dense) and a reference table (ref_mobile_data_dense) based on feature1, feature2 and feature 3\n", 77 | " SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance \n", 78 | " FROM TD_VECTORDISTANCE (\n", 79 | " ON target_mobile_data_dense AS TargetTable\n", 80 | " ON ref_mobile_data_dense AS ReferenceTable DIMENSION\n", 81 | " USING\n", 82 | " TargetIDColumn('id_column')\n", 83 | " TargetFeatureColumns('feature1','feature2','feature3')\n", 84 | " RefIDColumn('id_column')\n", 85 | " RefFeatureColumns('feature1','feature2','feature3')\n", 86 | " DistanceMeasure('cosine')\n", 87 | " topk(2)\n", 88 | " ) AS dt order by 3,1,2,4;\n", 89 | "\"\"\"\n", 90 | "\n", 91 | "moving_average = \"\"\"\n", 92 | "Overview : \n", 93 | " The MovingAverage function computes average values in a series, using the specified moving average type.\n", 94 | " Moving Average (MA) is a widely used technical analysis indicator that is used to smooth out fluctuations in a data series and to identify trends. It is calculated by taking the average of a predetermined number of periods or time intervals.\n", 95 | "\n", 96 | "Syntax :\n", 97 | " MovingAverage (\n", 98 | " ON table | view | (query) \n", 99 | " [ PARTITION BY partition_column [,...] ]\n", 100 | " [ ORDER BY order_column [,...] ]\n", 101 | " [ USING\n", 102 | " [ MAvgType ({ 'C' | 'E' | 'M' | 'S' | 'T' | 'W' }) ]\n", 103 | " [ TargetColumns ('target_column'| 'target_column_range'[,...])]\n", 104 | " [ Alpha (alpha) ]\n", 105 | " [ StartRows (n) ]\n", 106 | " [ IncludeFirst ('true'|'t'|'yes'|'y'|'1'|'false'|'f'|'no'|'n'|'0') ]\n", 107 | " [ WindowSize (window_size) ]\n", 108 | " ]\n", 109 | " )\n", 110 | "\n", 111 | " MAvgType\n", 112 | " [Optional] Specify one of the following moving average types:\n", 113 | " 'C' (Default)\tCumulative moving average.\n", 114 | " 'E'\tExponential moving average.\n", 115 | " 'M'\tModified moving average.\n", 116 | " 'S'\tSimple moving average.\n", 117 | " 'T'\tTriangular moving average.\n", 118 | " 'W'\tWeighted moving average.\n", 119 | " TargetColumns : [Optional] Specify the input column names for which to compute the moving average.\n", 120 | " Default behavior: The function copies every input column to the output table but does not compute any moving averages.\n", 121 | " Alpha : [Optional with MAvgType E, otherwise ignored.] Specify the damping factor, a value in the range [0, 1], which represents a percentage in the range [0, 100]. For example, if alpha is 0.2, the damping factor is 20%. A higher alpha discounts older observations faster.\n", 122 | " [Optional with MAvgType E, otherwise ignored.] Specify the number of rows to skip before calculating the exponential moving average. The function uses the arithmetic average of these rows as the initial value of the exponential moving average. The value n must be an integer.\n", 123 | " [Ignored with MAvgType C, otherwise optional.] Specify whether to include the starting rows in the output table. If you specify 'true', the output columns for the starting rows contain NULL, because their moving average is undefined.\n", 124 | " WindowSize: [Optional with MAvgType M, S, T, and W; otherwise ignored.] Specify the number of previous values to consider when computing the new moving average. The data type of window_size must be BYTEINT, SMALLINT, or INTEGER.\n", 125 | " Minimum value: 3\n", 126 | " Default: '10'\n", 127 | "\n", 128 | "Example : \n", 129 | " SELECT * FROM MovingAverage (\n", 130 | " ON company1_stock PARTITION BY name ORDER BY period\n", 131 | " USING\n", 132 | " MAvgType ('S')\n", 133 | " TargetColumns ('stockprice')\n", 134 | " WindowSize (10)\n", 135 | " IncludeFirst ('true')\n", 136 | " ) AS dt ORDER BY id;\n", 137 | "\"\"\"\n", 138 | "\n", 139 | "bin_code_fit = \"\"\"\n", 140 | "Overview : \n", 141 | " Bin Coding, also known as binning or bucketing, is a data preprocessing technique used in statistics and machine learning to transform continuous data into categorical or discrete data. In binning, a range of continuous values is divided into smaller intervals or bins, and the data values are assigned to the appropriate bin. This allows the data to be analyzed more easily by grouping similar values into categories.\n", 142 | " \n", 143 | " Binning is used to:\n", 144 | " Reduce noise in the data by aggregating values into groups.\n", 145 | " Identify trends and patterns in the data by grouping similar values together.\n", 146 | " Simplify complex data by reducing the number of unique values.\n", 147 | "\n", 148 | "Syntax : \n", 149 | " TD_BincodeFit (\n", 150 | " ON { table | view | (query) } AS InputTable\n", 151 | " [ OUT [ PERMANENT | VOLATILE ] TABLE OutputTable (output_table) ]\n", 152 | " USING\n", 153 | " TargetColumns ({ 'target_column' | target_column_range }[,...])\n", 154 | " MethodType ('equal-width')\n", 155 | " NBins ('single bin value' | 'separate bin values')\n", 156 | " [ LabelPrefix ('single prefix' | 'separate prefix values') ]\n", 157 | " )\n", 158 | " - ON clause : Accept the InputTable clause for equal-width bins with generated labels. Accept the InputTable and FitInput clauses for variable-width bins with specified labels.\n", 159 | " - TargetColumns : Specify the names of the InputTable columns to bin-code. The maximum number of target columns is 2018.\n", 160 | " - MethodType : Specify the bin-coding method:Method Type\tDescription equal-width\tBins have fixed width with auto-generated labels.\n", 161 | " Function finds minimum and maximum values of target columns (min and max) and computes bin width, w, with this formula:\n", 162 | " w = (max - min)/k\n", 163 | " k, the number of bins, is determined by NBins.\n", 164 | " - variable-width\tBins have specified variable widths and specified labels, provided by FitInput table. Maximum number of bins is 3000.\n", 165 | " - NBins : [MethodType ('equal-width') only.] Specify either a single bin value for all the target columns or separate bin values for each of the target columns.\n", 166 | "Example : \n", 167 | " SELECT * FROM TD_BincodeFit (\n", 168 | " ON bin_titanic_train AS InputTable\n", 169 | " ON FitInputTable AS FitInput DIMENSION\n", 170 | " USING\n", 171 | " TargetColumns ('age')\n", 172 | " MethodType ('Variable-Width')\n", 173 | " MinValueColumn ('MinValue')\n", 174 | " MaxValueCOlumn ('MaxValue')\n", 175 | " LabelColumn ('Label')\n", 176 | " TargetColNames ('ColumnName')\n", 177 | " ) AS dt\n", 178 | "\"\"\"" 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "id": "863aafed-3ad6-4e2d-8210-9bcc1d4a67da", 184 | "metadata": {}, 185 | "source": [ 186 | "# 2. Create Vector DB" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "execution_count": 51, 192 | "id": "0a60d143-f92f-4318-9e95-ad6d4fe811a2", 193 | "metadata": {}, 194 | "outputs": [], 195 | "source": [ 196 | "technical_list = [td_vectordistinct, moving_average, bin_code_fit]\n", 197 | "\n", 198 | "embedding_function = OpenAIEmbeddings(openai_api_key=os.getenv(\"OPENAI_API\"))\n", 199 | "\n", 200 | "# load it into FAISS\n", 201 | "db = FAISS.from_texts(technical_list, embedding_function)" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": 53, 207 | "id": "dce7ac5f-e122-45aa-bb0a-0449ca3778b3", 208 | "metadata": {}, 209 | "outputs": [ 210 | { 211 | "data": { 212 | "text/plain": [ 213 | "Document(page_content=\"\\nOverview : \\n The TD_VectorDistance function accepts a table of target vectors and a table of reference vectors and returns a table that contains the distance between \\n target-reference pairs. The function computes the distance between the target pair and the reference pair from the same table if you provide only one \\n table as the input. You must have the same column order in the TargetFeatureColumns argument and the RefFeatureColumns argument. \\n The function ignores the feature values during distance computation if the value is either NULL, NAN, or INF.\\n\\nSyntax :\\n SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance \\n FROM TD_VECTORDISTANCE (\\n\\n ON table | view | (query) AS TARGETTABLE PARTITION BY ANY\\n [ ON table | view | (query) AS REFERENCETABLE DIMENSION ]\\n USING\\n TargetIDColumn ('target_id_column')\\n TargetFeatureColumns ( 'target_feature_column' | target_feature_Column_range [,...])\\n [ RefIDColumn ('ref_id_column') ]\\n [ RefFeatureColumns ( 'ref_feature_column' | ref_feature_Column_range [,...]) ]\\n [ DistanceMeasure ('Cosine' | 'Euclidean' | 'Manhattan'[,...])]\\n [ TopK(integer_value)] \\n )\\n \\nExample : Calculate distances between vectors in a target table (target_mobile_data_dense) and a reference table (ref_mobile_data_dense) based on feature1, feature2 and feature 3\\n SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance \\n FROM TD_VECTORDISTANCE (\\n ON target_mobile_data_dense AS TargetTable\\n ON ref_mobile_data_dense AS ReferenceTable DIMENSION\\n USING\\n TargetIDColumn('id_column')\\n TargetFeatureColumns('feature1','feature2','feature3')\\n RefIDColumn('id_column')\\n RefFeatureColumns('feature1','feature2','feature3')\\n DistanceMeasure('cosine')\\n topk(2)\\n ) AS dt order by 3,1,2,4;\\n\")" 214 | ] 215 | }, 216 | "execution_count": 53, 217 | "metadata": {}, 218 | "output_type": "execute_result" 219 | } 220 | ], 221 | "source": [ 222 | "db.similarity_search(\"Calculate similarity\")[0]" 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "id": "cb93c364-54ae-4779-9a1d-1844b51b462e", 228 | "metadata": {}, 229 | "source": [ 230 | "# 3. Create Tearadata Search Tool" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 54, 236 | "id": "21f987b5-44f6-4fd7-9594-2fe8de4d78ca", 237 | "metadata": {}, 238 | "outputs": [], 239 | "source": [ 240 | "from langchain.tools import BaseTool\n", 241 | "from typing import Optional, Type\n", 242 | "\n", 243 | "from langchain.callbacks.manager import (\n", 244 | " AsyncCallbackManagerForToolRun,\n", 245 | " CallbackManagerForToolRun,\n", 246 | ")\n", 247 | "\n", 248 | "from langchain.agents import create_sql_agent\n", 249 | "from langchain.agents.types import AgentType" 250 | ] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": null, 255 | "id": "27d2e0a4-4670-49ed-b10d-5e6a8ef78a31", 256 | "metadata": {}, 257 | "outputs": [], 258 | "source": [ 259 | "retriever = db.as_retriever()" 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": 55, 265 | "id": "efd5b7af-dcc9-4aa1-907e-6194aaef201a", 266 | "metadata": {}, 267 | "outputs": [], 268 | "source": [ 269 | "class TeradataSearchTool(BaseTool):\n", 270 | " name = \"teradata_search_tool\"\n", 271 | " description = \"Input to this tool is a keyword such as binning or bucketing, similarity, moving averate. Output is instruction of how to using Teradata Syntax with examples to make better query\"\n", 272 | "\n", 273 | " def _run(\n", 274 | " self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None\n", 275 | " ) -> str:\n", 276 | " \"\"\"Use the tool.\"\"\"\n", 277 | " global retriever\n", 278 | " relevant_doc = retriever.get_relevant_documents(query)\n", 279 | " if len(relevant_doc) == 0 | len(query) == 0:\n", 280 | " return \"There are no Syntax of Teradata that need to be used in this scenario\"\n", 281 | " else:\n", 282 | " return relevant_doc[0].page_content\n", 283 | "\n", 284 | " async def _arun(\n", 285 | " self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None\n", 286 | " ) -> str:\n", 287 | " \"\"\"Use the tool asynchronously.\"\"\"\n", 288 | " raise NotImplementedError(\"custom_search does not support async\")\n", 289 | "\n", 290 | "\n", 291 | "teradata_search_tool = TeradataSearchTool()" 292 | ] 293 | }, 294 | { 295 | "cell_type": "markdown", 296 | "id": "a460a1d8-1746-49b0-88d4-44c4e19ac65f", 297 | "metadata": {}, 298 | "source": [ 299 | "# 4. Redefine SQL Agent" 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "execution_count": 57, 305 | "id": "1b0c20b9-24dc-4332-a29f-cb3c853397ec", 306 | "metadata": {}, 307 | "outputs": [], 308 | "source": [ 309 | "# Step 1. Define LLM model\n", 310 | "model = OpenAI(temperature=0, openai_api_key=os.getenv(\"OPENAI_API\"))\n", 311 | "\n", 312 | "# Step 2. Setting connection to db and SQL Toolkits\n", 313 | "db = SQLDatabase.from_uri(\"teradatasql://dbc:dbc@192.168.11.7:1025/Sales\")\n", 314 | "toolkit = SQLDatabaseToolkit(db=db, llm=model)\n", 315 | "tools = toolkit.get_tools()" 316 | ] 317 | }, 318 | { 319 | "cell_type": "code", 320 | "execution_count": 58, 321 | "id": "bc6b3885-242e-4a37-8d78-bc043b8088b0", 322 | "metadata": {}, 323 | "outputs": [], 324 | "source": [ 325 | "# Step 3. Define Prefix\n", 326 | "\n", 327 | "prefix = \"\"\"\n", 328 | "You are an agent designed to interact with a Teradata database.\n", 329 | "Given an input question, create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.\n", 330 | "You can order the results by a relevant column to return the most interesting examples in the database.\n", 331 | "Never query for all the columns from a specific table, only ask for the relevant columns given the question.\n", 332 | "You have access to tools for interacting with the database.\n", 333 | "Only use the below tools. Only use the information returned by the below tools to construct your final answer.\n", 334 | "You MUST double check your query before executing it. If you get an error while executing a query, rewrite the query and try again.\n", 335 | "Note you must always use double quotation marks (\" \") for column names in SQL queries for avoid syntax error\n", 336 | "\n", 337 | "If the question does not seem related to the database, just return \"I don't know\" as the answer.\n", 338 | "\"\"\"" 339 | ] 340 | }, 341 | { 342 | "cell_type": "code", 343 | "execution_count": 59, 344 | "id": "e48d9055-de9b-44dd-bf9f-220c83a46e79", 345 | "metadata": {}, 346 | "outputs": [], 347 | "source": [ 348 | "suffix = \"\"\"Begin!\n", 349 | "\n", 350 | "Question: {input}\n", 351 | "Thought: I should used teradata_search_tool to finding relevant syntax first.\n", 352 | "{agent_scratchpad}\"\"\"" 353 | ] 354 | }, 355 | { 356 | "cell_type": "code", 357 | "execution_count": 60, 358 | "id": "2d0d3c9d-00d8-45e5-b77c-9adb90e17959", 359 | "metadata": {}, 360 | "outputs": [], 361 | "source": [ 362 | "# Step 4. Create Agent Executor \n", 363 | "agent_executor = create_sql_agent(\n", 364 | " llm=model,\n", 365 | " toolkit=toolkit,\n", 366 | " verbose=True,\n", 367 | " agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,\n", 368 | " extra_tools=[teradata_search_tool],\n", 369 | " prefix=prefix,\n", 370 | " suffix=suffix\n", 371 | ")" 372 | ] 373 | }, 374 | { 375 | "cell_type": "markdown", 376 | "id": "bd188f1a-45aa-40e1-a7db-0fe22178bebe", 377 | "metadata": {}, 378 | "source": [ 379 | "# 5. Test" 380 | ] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "execution_count": 63, 385 | "id": "5e02f99b-e131-4820-9c1a-4773af09a019", 386 | "metadata": {}, 387 | "outputs": [ 388 | { 389 | "name": "stdout", 390 | "output_type": "stream", 391 | "text": [ 392 | "\n", 393 | "\n", 394 | "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", 395 | "\u001b[32;1m\u001b[1;3mAction: teradata_search_tool\n", 396 | "Action Input: similarity\u001b[0m\n", 397 | "Observation: \u001b[33;1m\u001b[1;3m\n", 398 | "Overview : \n", 399 | " The TD_VectorDistance function accepts a table of target vectors and a table of reference vectors and returns a table that contains the distance between \n", 400 | " target-reference pairs. The function computes the distance between the target pair and the reference pair from the same table if you provide only one \n", 401 | " table as the input. You must have the same column order in the TargetFeatureColumns argument and the RefFeatureColumns argument. \n", 402 | " The function ignores the feature values during distance computation if the value is either NULL, NAN, or INF.\n", 403 | "\n", 404 | "Syntax :\n", 405 | " SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance \n", 406 | " FROM TD_VECTORDISTANCE (\n", 407 | "\n", 408 | " ON table | view | (query) AS TARGETTABLE PARTITION BY ANY\n", 409 | " [ ON table | view | (query) AS REFERENCETABLE DIMENSION ]\n", 410 | " USING\n", 411 | " TargetIDColumn ('target_id_column')\n", 412 | " TargetFeatureColumns ( 'target_feature_column' | target_feature_Column_range [,...])\n", 413 | " [ RefIDColumn ('ref_id_column') ]\n", 414 | " [ RefFeatureColumns ( 'ref_feature_column' | ref_feature_Column_range [,...]) ]\n", 415 | " [ DistanceMeasure ('Cosine' | 'Euclidean' | 'Manhattan'[,...])]\n", 416 | " [ TopK(integer_value)] \n", 417 | " )\n", 418 | " \n", 419 | "Example : Calculate distances between vectors in a target table (target_mobile_data_dense) and a reference table (ref_mobile_data_dense) based on feature1, feature2 and feature 3\n", 420 | " SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance \n", 421 | " FROM TD_VECTORDISTANCE (\n", 422 | " ON target_mobile_data_dense AS TargetTable\n", 423 | " ON ref_mobile_data_dense AS ReferenceTable DIMENSION\n", 424 | " USING\n", 425 | " TargetIDColumn('id_column')\n", 426 | " TargetFeatureColumns('feature1','feature2','feature3')\n", 427 | " RefIDColumn('id_column')\n", 428 | " RefFeatureColumns('feature1','feature2','feature3')\n", 429 | " DistanceMeasure('cosine')\n", 430 | " topk(2)\n", 431 | " ) AS dt order by 3,1,2,4;\n", 432 | "\u001b[0m\n", 433 | "Thought:\u001b[32;1m\u001b[1;3m I should use the TD_VectorDistance function to calculate the distance between the target pair and the reference pair from the same table.\n", 434 | "Action: sql_db_query\n", 435 | "Action Input: SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance \n", 436 | "FROM TD_VECTORDISTANCE (\n", 437 | " ON UserHistory AS TargetTable\n", 438 | " ON UserHistoryReference AS ReferenceTable DIMENSION\n", 439 | " USING\n", 440 | " TargetIDColumn('UserID')\n", 441 | " TargetFeatureColumns('CallDuration','DataCounter','SMS')\n", 442 | " RefIDColumn('UserID')\n", 443 | " RefFeatureColumns('CallDuration','DataCounter','SMS')\n", 444 | " DistanceMeasure('cosine')\n", 445 | " topk(2)\n", 446 | ") AS dt order by 3,1,2,4;\u001b[0m\n", 447 | "Observation: \u001b[36;1m\u001b[1;3m[(1, 5, 'cosine', Decimal('0.45486518')), (1, 7, 'cosine', Decimal('0.32604815')), (2, 5, 'cosine', Decimal('0.02608923')), (2, 7, 'cosine', Decimal('0.00797609')), (3, 5, 'cosine', Decimal('0.02415054')), (3, 7, 'cosine', Decimal('0.00337338')), (4, 5, 'cosine', Decimal('0.43822243')), (4, 7, 'cosine', Decimal('0.31184844'))]\u001b[0m\n", 448 | "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n", 449 | "Final Answer: The user similarities can be identified by analyzing the 'UserHistory' table using 'UserHistoryReference' as the reference table, focusing on attributes CallDuration, DataCounter, and SMS, using the TD_VectorDistance function to calculate the distance between the target pair and the reference pair from the same table. The results of the query show that users 1 and 5 have a cosine distance of 0.45486518, users 1 and 7 have a cosine distance of 0.32604815, and so on.\u001b[0m\n", 450 | "\n", 451 | "\u001b[1m> Finished chain.\u001b[0m\n" 452 | ] 453 | }, 454 | { 455 | "data": { 456 | "text/plain": [ 457 | "\"The user similarities can be identified by analyzing the 'UserHistory' table using 'UserHistoryReference' as the reference table, focusing on attributes CallDuration, DataCounter, and SMS, using the TD_VectorDistance function to calculate the distance between the target pair and the reference pair from the same table. The results of the query show that users 1 and 5 have a cosine distance of 0.45486518, users 1 and 7 have a cosine distance of 0.32604815, and so on.\"" 458 | ] 459 | }, 460 | "execution_count": 63, 461 | "metadata": {}, 462 | "output_type": "execute_result" 463 | } 464 | ], 465 | "source": [ 466 | "agent_executor.run(\"Identify user similarities by analyzing the 'UserHistory' table using 'UserHistoryReference' as the reference table, focusing on attributes CallDuration, DataCounter, and SMS\")" 467 | ] 468 | }, 469 | { 470 | "cell_type": "code", 471 | "execution_count": null, 472 | "id": "538574d4-5b80-4d90-a0bd-6420ebc57e26", 473 | "metadata": {}, 474 | "outputs": [], 475 | "source": [] 476 | } 477 | ], 478 | "metadata": { 479 | "kernelspec": { 480 | "display_name": "Python 3 (ipykernel)", 481 | "language": "python", 482 | "name": "python3" 483 | }, 484 | "language_info": { 485 | "codemirror_mode": { 486 | "name": "ipython", 487 | "version": 3 488 | }, 489 | "file_extension": ".py", 490 | "mimetype": "text/x-python", 491 | "name": "python", 492 | "nbconvert_exporter": "python", 493 | "pygments_lexer": "ipython3", 494 | "version": "3.9.18" 495 | } 496 | }, 497 | "nbformat": 4, 498 | "nbformat_minor": 5 499 | } 500 | -------------------------------------------------------------------------------- /04_FineTuning/teradata_syntax_finetune.jsonl: -------------------------------------------------------------------------------- 1 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Calculate the distance between tables users and users_reference using TD_VectorDistance. \r\nCREATE TABLE users (\n user_id INT PRIMARY KEY,\n first_name VARCHAR(255),\n last_name VARCHAR(255),\n age INT,\n gender VARCHAR(10),\n height FLOAT,\n weight FLOAT,\n location_x FLOAT,\n location_y FLOAT\n);\n\nCREATE TABLE users_reference (\n user_id INT PRIMARY KEY,\n first_name VARCHAR(255),\n last_name VARCHAR(255),\n age INT,\n gender VARCHAR(10),\n height FLOAT,\n weight FLOAT,\n location_x FLOAT,\n location_y FLOAT\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON users AS TargetTable\n ON users_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('user_id')\n TargetFeatureColumns('age','height','weight','location_x','location_y')\n RefIDColumn('user_id')\n RefFeatureColumns('age','height','weight','location_x','location_y')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 2 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Use TD_VectorDistance to find the distance between vectors in tables orders and orders_reference. \r\nCREATE TABLE orders (\n order_id INT PRIMARY KEY,\n customer_id INT,\n product_id INT,\n quantity INT,\n price FLOAT,\n order_date DATE,\n discount FLOAT,\n shipping_address VARCHAR(255)\n);\n\nCREATE TABLE orders_reference (\n order_id INT PRIMARY KEY,\n customer_id INT,\n product_id INT,\n quantity INT,\n price FLOAT,\n order_date DATE,\n discount FLOAT,\n shipping_address VARCHAR(255)\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON orders AS TargetTable\n ON orders_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('order_id')\n TargetFeatureColumns('customer_id','product_id','quantity','price','order_date','discount')\n RefIDColumn('order_id')\n RefFeatureColumns('customer_id','product_id','quantity','price','order_date','discount')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 3 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Compute the distance from tables products to products_reference using TD_VectorDistance. \r\nCREATE TABLE products (\n product_id INT PRIMARY KEY,\n product_name VARCHAR(255),\n product_type VARCHAR(255),\n price FLOAT,\n weight FLOAT,\n quantity INT,\n discount_rate FLOAT,\n rating FLOAT\n);\n\nCREATE TABLE products_reference (\n product_id INT PRIMARY KEY,\n product_name VARCHAR(255),\n product_type VARCHAR(255),\n price FLOAT,\n weight FLOAT,\n quantity INT,\n discount_rate FLOAT,\n rating FLOAT\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON products AS TargetTable\n ON products_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('product_id')\n TargetFeatureColumns('price','weight','quantity', 'discount_rate', 'rating')\n RefIDColumn('product_id')\n RefFeatureColumns('price','weight','quantity', 'discount_rate', 'rating')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 4 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Apply TD_VectorDistance to determine the distance between vectors in tables products and products_reference.Find the vector distance between tables customers and customers_reference with TD_VectorDistance.Execute TD_VectorDistance to measure the distance from tables employees to employees_reference. \r\nCREATE TABLE products (\n product_id INT PRIMARY KEY,\n name VARCHAR(255),\n category VARCHAR(255),\n price FLOAT,\n quantity INT,\n discount FLOAT,\n rating FLOAT,\n sales_count INT\n);\n\nCREATE TABLE products_reference (\n product_id INT PRIMARY KEY,\n name VARCHAR(255),\n category VARCHAR(255),\n price FLOAT,\n quantity INT,\n discount FLOAT,\n rating FLOAT,\n sales_count INT\n);\n\nCREATE TABLE customers (\n customer_id INT PRIMARY KEY,\n name VARCHAR(255),\n age INT,\n address VARCHAR(255),\n login_time INT,\n last_login_num_of_date FLOAT,\n purchase_amount INT,\n loyalty_score FLOAT\n);\n\nCREATE TABLE customers_reference (\n customer_id INT PRIMARY KEY,\n name VARCHAR(255),\n age INT,\n address VARCHAR(255),\n login_time INT,\n last_login_num_of_date FLOAT,\n purchase_amount INT,\n loyalty_score FLOAT\n);\n\nCREATE TABLE employees (\n employee_id INT PRIMARY KEY,\n name VARCHAR(255),\n age INT,\n address VARCHAR(255),\n department VARCHAR(255),\n salary FLOAT,\n working_hours INT,\n performance_score FLOAT\n);\n\nCREATE TABLE employees_reference (\n employee_id INT PRIMARY KEY,\n name VARCHAR(255),\n age INT,\n address VARCHAR(255),\n department VARCHAR(255),\n salary FLOAT,\n working_hours INT,\n performance_score FLOAT\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON products AS TargetTable\n ON products_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('product_id')\n TargetFeatureColumns('price','quantity','discount','rating', 'sales_count')\n RefIDColumn('product_id')\n RefFeatureColumns('price','quantity','discount','rating', 'sales_count')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;\n\nSELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON customers AS TargetTable\n ON customers_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('customer_id')\n TargetFeatureColumns('age','login_time','purchase_amount','loyalty_score')\n RefIDColumn('customer_id')\n RefFeatureColumns('age','login_time','purchase_amount','loyalty_score')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;\n\nSELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON employees AS TargetTable\n ON employees_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('employee_id')\n TargetFeatureColumns('age','salary','working_hours','performance_score')\n RefIDColumn('employee_id')\n RefFeatureColumns('age','salary','working_hours','performance_score')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 5 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Determine the TD_VectorDistance between tables invoices and invoices_reference for vector comparison. \r\nCREATE TABLE invoices (\n invoice_id INT PRIMARY KEY,\n customer_id INT,\n product_name VARCHAR(255),\n quantity INT,\n price FLOAT,\n invoice_date DATE,\n payment_status VARCHAR(50),\n payment_date DATE\n);\n\nCREATE TABLE invoices_reference (\n invoice_id INT PRIMARY KEY,\n customer_id INT,\n product_name VARCHAR(255),\n quantity INT,\n price FLOAT,\n invoice_date DATE,\n payment_status VARCHAR(50),\n payment_date DATE\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON invoices AS TargetTable\n ON invoices_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('invoice_id')\n TargetFeatureColumns('customer_id','quantity','price')\n RefIDColumn('invoice_id')\n RefFeatureColumns('customer_id','quantity','price')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 6 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Get the distance metrics for vectors in tables categories and categories_reference using TD_VectorDistance. \r\nCREATE TABLE categories (\n category_id INT PRIMARY KEY,\n category_name VARCHAR(255),\n category_vector FLOAT,\n category_score FLOAT,\n category_count INT,\n category_avg_rating FLOAT,\n category_price FLOAT,\n category_discount FLOAT\n);\n\nCREATE TABLE categories_reference (\n category_id INT PRIMARY KEY,\n category_name VARCHAR(255),\n category_vector FLOAT,\n category_score FLOAT,\n category_count INT,\n category_avg_rating FLOAT,\n category_price FLOAT,\n category_discount FLOAT\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON categories AS TargetTable\n ON categories_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('category_id')\n TargetFeatureColumns('category_score','category_count','category_avg_rating','category_price','category_discount')\n RefIDColumn('category_id')\n RefFeatureColumns('category_score','category_count','category_avg_rating','category_price','category_discount')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 7 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Utilize TD_VectorDistance for calculating the distance between tables payments and payments_reference. \r\nCREATE TABLE payments (\n payment_id INT PRIMARY KEY,\n amount FLOAT,\n customer_id INT,\n payment_date DATE,\n status VARCHAR(255),\n transaction_type VARCHAR(255)\n);\n\nCREATE TABLE payments_reference (\n payment_id INT PRIMARY KEY,\n amount FLOAT,\n customer_id INT,\n payment_date DATE,\n status VARCHAR(255),\n transaction_type VARCHAR(255)\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON payments AS TargetTable\n ON payments_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('payment_id')\n TargetFeatureColumns('amount','customer_id','payment_date','status','transaction_type')\n RefIDColumn('payment_id')\n RefFeatureColumns('amount','customer_id','payment_date','status','transaction_type')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 8 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Fetch the TD_VectorDistance results for vectors in tables suppliers and suppliers_reference. \r\nCREATE TABLE suppliers (\n supplier_id INT PRIMARY KEY,\n supplier_name VARCHAR(255),\n contact_name VARCHAR(255),\n address VARCHAR(255),\n city VARCHAR(255),\n country VARCHAR(255),\n phone FLOAT,\n fax FLOAT\n);\n\nCREATE TABLE suppliers_reference (\n supplier_id INT PRIMARY KEY,\n supplier_name VARCHAR(255),\n contact_name VARCHAR(255),\n address VARCHAR(255),\n city VARCHAR(255),\n country VARCHAR(255),\n phone FLOAT,\n fax FLOAT\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON suppliers AS TargetTable\n ON suppliers_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('supplier_id')\n TargetFeatureColumns('phone','fax')\n RefIDColumn('supplier_id')\n RefFeatureColumns('phone','fax')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 9 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Request the distance calculation using TD_VectorDistance for tables reviews and reviews_reference. \r\nCREATE TABLE reviews (\n review_id INT PRIMARY KEY,\n rating FLOAT,\n review_text VARCHAR(255),\n helpfulness FLOAT,\n sentiment_score FLOAT,\n word_count INT,\n review_date DATE,\n reviewer_id INT\n );\n \n CREATE TABLE reviews_reference (\n reference_id INT PRIMARY KEY,\n rating FLOAT,\n review_text VARCHAR(255),\n helpfulness FLOAT,\n sentiment_score FLOAT,\n word_count INT,\n review_date DATE,\n reviewer_id INT\n );"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON reviews AS TargetTable\n ON reviews_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('review_id')\n TargetFeatureColumns('rating','helpfulness','sentiment_score','word_count')\n RefIDColumn('reference_id')\n RefFeatureColumns('rating','helpfulness','sentiment_score','word_count')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 10 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Retrieve the vector distance information between tables addresses and addresses_reference with TD_VectorDistance. \r\nCREATE TABLE addresses (\n address_id INT PRIMARY KEY,\n street_name VARCHAR(255),\n city VARCHAR(255),\n state VARCHAR(255),\n zip_code VARCHAR(255),\n latitude FLOAT,\n longitude FLOAT,\n population FLOAT\n);\n\nCREATE TABLE addresses_reference (\n address_id INT PRIMARY KEY,\n street_name VARCHAR(255),\n city VARCHAR(255),\n state VARCHAR(255),\n zip_code VARCHAR(255),\n latitude FLOAT,\n longitude FLOAT,\n population FLOAT\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON addresses AS TargetTable\n ON addresses_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('address_id')\n TargetFeatureColumns('latitude','longitude','population')\n RefIDColumn('address_id')\n RefFeatureColumns('latitude','longitude','population')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 11 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Compute vector distances between tables transactions and transactions_reference using TD_VectorDistance. \r\nCREATE TABLE transactions (\n transaction_id INT PRIMARY KEY,\n customer_id INT,\n product_id INT,\n quantity INT,\n price FLOAT,\n discount FLOAT,\n total_price FLOAT,\n transaction_date DATE\n);\n\nCREATE TABLE transactions_reference (\n transaction_id INT PRIMARY KEY,\n customer_id INT,\n product_id INT,\n quantity INT,\n price FLOAT,\n discount FLOAT,\n total_price FLOAT,\n transaction_date DATE\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON transactions AS TargetTable\n ON transactions_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('transaction_id')\n TargetFeatureColumns('quantity','price','discount','total_price')\n RefIDColumn('transaction_id')\n RefFeatureColumns('quantity','price','discount','total_price')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 12 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Use TD_VectorDistance to analyze the distance between vectors in tables departments and departments_reference. \r\nCREATE TABLE departments (\n department_id INT PRIMARY KEY,\n department_name VARCHAR(255),\n department_head VARCHAR(255),\n employee_count INT,\n budget Float,\n average_salary Float,\n department_score Float\n);\n\nCREATE TABLE departments_reference (\n department_id INT PRIMARY KEY,\n department_name VARCHAR(255),\n department_head VARCHAR(255),\n employee_count INT,\n budget Float,\n average_salary Float,\n department_score Float\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON departments AS TargetTable\n ON departments_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('department_id')\n TargetFeatureColumns('employee_count','budget','average_salary', 'department_score')\n RefIDColumn('department_id')\n RefFeatureColumns('employee_count','budget','average_salary', 'department_score')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 13 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Calculate the TD_VectorDistance between tables inventory and inventory_reference for vector analysis. \r\nCREATE TABLE inventory (\n product_id INT PRIMARY KEY,\n product_name VARCHAR(255),\n quantity INT,\n price FLOAT,\n weight FLOAT,\n supplier_id INT\n);\n\nCREATE TABLE inventory_reference (\n product_id INT PRIMARY KEY,\n product_name VARCHAR(255),\n quantity INT,\n price FLOAT,\n weight FLOAT,\n supplier_id INT\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, CAST(distance AS DECIMAL(36,8)) AS distance FROM TD_VECTORDISTANCE (\n ON inventory AS TargetTable\n ON inventory_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('product_id')\n TargetFeatureColumns('quantity','price','weight','supplier_id')\n RefIDColumn('product_id')\n RefFeatureColumns('quantity','price','weight','supplier_id')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt ORDER BY 3,1,2,4;"}]} 14 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Find the vector distance results between tables vendors and vendors_reference using TD_VectorDistance. \r\nCREATE TABLE vendors (\n vendor_id INT PRIMARY KEY,\n vendor_name VARCHAR(255),\n city VARCHAR(255),\n state VARCHAR(255),\n country VARCHAR(255),\n rating FLOAT,\n total_sales INT,\n average_rating FLOAT,\n);\n\nCREATE TABLE vendors_reference (\n vendor_id INT PRIMARY KEY,\n vendor_name VARCHAR(255),\n city VARCHAR(255),\n state VARCHAR(255),\n country VARCHAR(255),\n rating FLOAT,\n total_sales INT,\n average_rating FLOAT,\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON vendors AS TargetTable\n ON vendors_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('vendor_id')\n TargetFeatureColumns('rating','total_sales','average_rating')\n RefIDColumn('vendor_id')\n RefFeatureColumns('rating','total_sales','average_rating')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 15 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Execute the TD_VectorDistance function to determine the distance between tables shipments and shipments_reference. \r\nThere is no specific SQL syntax for executing the TD_VectorDistance function to determine the distance between tables. However, you can create the two tables mentioned using the provided column names and types, and then use a query to calculate the distance using the function. Here is the SQL code to create the tables:\n\nCREATE TABLE shipments (\n shipment_id INT PRIMARY KEY,\n shipment_date DATE,\n sender_name VARCHAR(255),\n receiver_name VARCHAR(255),\n shipment_weight FLOAT,\n shipment_cost FLOAT,\n shipment_status VARCHAR(255),\n shipment_location VARCHAR(255)\n);\n\nCREATE TABLE shipments_reference (\n shipment_id INT PRIMARY KEY,\n shipment_date DATE,\n sender_name VARCHAR(255),\n receiver_name VARCHAR(255),\n shipment_weight FLOAT,\n shipment_cost FLOAT,\n shipment_status VARCHAR(255),\n shipment_location VARCHAR(255)\n);\n\nAfter creating the tables, you can use the TD_VectorDistance function or any other distance calculation function to determine the distance between the two tables."}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON shipments AS TargetTable\n ON shipments_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('shipment_id')\n TargetFeatureColumns('shipment_weight','shipment_cost')\n RefIDColumn('shipment_id')\n RefFeatureColumns('shipment_weight','shipment_cost')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 16 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Request TD_VectorDistance to calculate the distance from tables messages to messages_reference. \r\nCREATE TABLE messages (\n message_id INT PRIMARY KEY,\n sender_id INT,\n receiver_id INT,\n timestamp TIMESTAMP,\n message_text VARCHAR(255),\n message_length FLOAT,\n message_type VARCHAR(50),\n read_status INT\n);\n\nCREATE TABLE messages_reference (\n message_id INT PRIMARY KEY,\n sender_id INT,\n receiver_id INT,\n timestamp TIMESTAMP,\n message_text VARCHAR(255),\n message_length FLOAT,\n message_type VARCHAR(50),\n read_status INT\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON messages AS TargetTable\n ON messages_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('message_id')\n TargetFeatureColumns('timestamp','message_length','read_status')\n RefIDColumn('message_id')\n RefFeatureColumns('timestamp','message_length','read_status')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 17 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Measure the vector distance between tables events and events_reference using TD_VectorDistance. \r\nCREATE TABLE events (\n event_id INT PRIMARY KEY,\n event_date DATE,\n event_name VARCHAR(255),\n event_type VARCHAR(255),\n event_duration_minutes FLOAT,\n event_location VARCHAR(255),\n event_capacity INT,\n event_tickets_sold INT\n);\n\nCREATE TABLE events_reference (\n event_id INT PRIMARY KEY,\n event_date DATE,\n event_name VARCHAR(255),\n event_type VARCHAR(255),\n event_duration_minutes FLOAT,\n event_location VARCHAR(255),\n event_capacity INT,\n event_tickets_sold INT\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON events AS TargetTable\n ON events_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('event_id')\n TargetFeatureColumns('event_duration_minutes','event_capacity','event_tickets_sold')\n RefIDColumn('event_id')\n RefFeatureColumns('event_duration_minutes','event_capacity','event_tickets_sold')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 18 | {"messages": [{"role": "system", "content": "You are an agent designed to interact with a SQL database.\nGiven an input question, create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer."}, {"role": "user", "content": "Obtain TD_VectorDistance results for vector distances between tables tasks and tasks_reference. \r\nCREATE TABLE tasks (\n task_id INT PRIMARY KEY,\n task_name VARCHAR(255),\n start_date DATE,\n end_date DATE,\n priority INT,\n completion FLOAT,\n assigned_to INT,\n task_status VARCHAR(255)\n);\n\nCREATE TABLE tasks_reference (\n task_id INT PRIMARY KEY,\n task_name VARCHAR(255),\n start_date DATE,\n end_date DATE,\n priority INT,\n completion FLOAT,\n assigned_to INT,\n task_status VARCHAR(255)\n);"}, {"role": "assistant", "content": "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n ON tasks AS TargetTable\n ON tasks_reference AS ReferenceTable DIMENSION\n USING\n TargetIDColumn('task_id')\n TargetFeatureColumns('start_date', 'end_date', 'priority', 'completion', 'assigned_to')\n RefIDColumn('task_id')\n RefFeatureColumns('start_date', 'end_date', 'priority', 'completion', 'assigned_to')\n DistanceMeasure('euclidean','cosine','manhattan')\n topk(2)\n) AS dt order by 3,1,2,4;"}]} 19 | -------------------------------------------------------------------------------- /05_Llama2/2_FineTuning-Llama2-7B_TeradataSQL.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "CsCImf-u3lA_", 7 | "metadata": { 8 | "id": "CsCImf-u3lA_" 9 | }, 10 | "outputs": [], 11 | "source": [ 12 | "!pip install -q accelerate==0.21.0 peft==0.4.0 bitsandbytes==0.40.2 transformers==4.31.0 trl==0.4.7 langchain" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 1, 18 | "id": "1c265925-9fa0-4d1b-9c26-e9301189fc87", 19 | "metadata": { 20 | "executionInfo": { 21 | "elapsed": 235, 22 | "status": "ok", 23 | "timestamp": 1708129400135, 24 | "user": { 25 | "displayName": "LUC NGUYEN MANH", 26 | "userId": "17963881608411381207" 27 | }, 28 | "user_tz": -540 29 | }, 30 | "id": "1c265925-9fa0-4d1b-9c26-e9301189fc87" 31 | }, 32 | "outputs": [ 33 | { 34 | "name": "stderr", 35 | "output_type": "stream", 36 | "text": [ 37 | "/home/user/miniconda3/envs/llama/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", 38 | " from .autonotebook import tqdm as notebook_tqdm\n" 39 | ] 40 | } 41 | ], 42 | "source": [ 43 | "import os\n", 44 | "import torch\n", 45 | "from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments, BitsAndBytesConfig, Trainer, pipeline\n", 46 | "from peft import LoraConfig\n", 47 | "from datasets import Dataset\n", 48 | "from langchain.prompts.prompt import PromptTemplate\n", 49 | "\n", 50 | "from trl import SFTTrainer\n", 51 | "from peft import PeftModel\n", 52 | "\n", 53 | "import pandas as pd" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 3, 59 | "id": "o_5MBviW_MfE", 60 | "metadata": { 61 | "colab": { 62 | "base_uri": "https://localhost:8080/" 63 | }, 64 | "executionInfo": { 65 | "elapsed": 167027, 66 | "status": "ok", 67 | "timestamp": 1708128855186, 68 | "user": { 69 | "displayName": "LUC NGUYEN MANH", 70 | "userId": "17963881608411381207" 71 | }, 72 | "user_tz": -540 73 | }, 74 | "id": "o_5MBviW_MfE", 75 | "outputId": "679aea20-9115-43b4-d511-0c9cbb3418b7" 76 | }, 77 | "outputs": [ 78 | { 79 | "name": "stdout", 80 | "output_type": "stream", 81 | "text": [ 82 | "Mounted at /content/drive\n" 83 | ] 84 | } 85 | ], 86 | "source": [ 87 | "from google.colab import drive\n", 88 | "drive.mount('/content/drive')" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 4, 94 | "id": "10c619b5-c884-4aa6-8a15-4d39ce9ec2d1", 95 | "metadata": { 96 | "executionInfo": { 97 | "elapsed": 9, 98 | "status": "ok", 99 | "timestamp": 1708127038204, 100 | "user": { 101 | "displayName": "LUC NGUYEN MANH", 102 | "userId": "17963881608411381207" 103 | }, 104 | "user_tz": -540 105 | }, 106 | "id": "10c619b5-c884-4aa6-8a15-4d39ce9ec2d1" 107 | }, 108 | "outputs": [], 109 | "source": [ 110 | "model_name = \"NousResearch/Llama-2-7b-chat-hf\"\n", 111 | "new_model = \"./finetune_models/llama2\"" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "id": "1e05808c-5dbf-4391-85e4-b5e4d7cb593c", 117 | "metadata": { 118 | "id": "1e05808c-5dbf-4391-85e4-b5e4d7cb593c" 119 | }, 120 | "source": [ 121 | "# 1. Load based model" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": null, 127 | "id": "d8401367-0283-4bec-963a-54908922c034", 128 | "metadata": { 129 | "id": "d8401367-0283-4bec-963a-54908922c034" 130 | }, 131 | "outputs": [], 132 | "source": [ 133 | "compute_dtype = getattr(torch, \"float16\")\n", 134 | "\n", 135 | "quant_config = BitsAndBytesConfig(\n", 136 | " load_in_4bit=True,\n", 137 | " bnb_4bit_quant_type=\"nf4\",\n", 138 | " bnb_4bit_compute_dtype=compute_dtype,\n", 139 | " bnb_4bit_use_double_quant=False,\n", 140 | ")\n", 141 | "\n", 142 | "tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": null, 148 | "id": "qav1VNvs3s7D", 149 | "metadata": { 150 | "id": "qav1VNvs3s7D" 151 | }, 152 | "outputs": [], 153 | "source": [ 154 | "# based_model = AutoModelForCausalLM.from_pretrained(model_name, quantization_config=bnb_config, device_map={\"\":0})\n", 155 | "\n", 156 | "model = AutoModelForCausalLM.from_pretrained(\n", 157 | " model_name,\n", 158 | " quantization_config=quant_config,\n", 159 | " device_map={\"\":0}\n", 160 | ")" 161 | ] 162 | }, 163 | { 164 | "cell_type": "markdown", 165 | "id": "3b142288-ac6b-4feb-89e3-18af7966c52a", 166 | "metadata": { 167 | "id": "3b142288-ac6b-4feb-89e3-18af7966c52a" 168 | }, 169 | "source": [ 170 | "# 2. Prepare Dataset" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "id": "8e5d1ea0-c93f-4ee6-9a53-619f51e2bb6d", 176 | "metadata": { 177 | "id": "8e5d1ea0-c93f-4ee6-9a53-619f51e2bb6d" 178 | }, 179 | "source": [ 180 | "Dataset used to fine-tuning Llama must following structure :\n", 181 | "```\n", 182 | "[INST] <>\n", 183 | "{{ system_prompt }}\n", 184 | "<>\n", 185 | "\n", 186 | "{{ user_message }} [/INST]\n", 187 | "```" 188 | ] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "id": "1373a352-67ac-4a80-aaa4-4794efe41e17", 193 | "metadata": { 194 | "id": "1373a352-67ac-4a80-aaa4-4794efe41e17" 195 | }, 196 | "source": [ 197 | "**For example :**\n", 198 | "\n", 199 | "```CMD\n", 200 | "[INST] <>\n", 201 | "You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. Your answers should not include any harmful, unethical, racist, sexist, toxic, dangerous, or illegal content. Please ensure that your responses are socially unbiased and positive in nature.\n", 202 | "\n", 203 | "If a question does not make any sense, or is not factually coherent, explain why instead of answering something not correct. If you don't know the answer to a question, please don't share false information.\n", 204 | "<>\n", 205 | "\n", 206 | "There's a llama in my garden 😱 What should I do? [/INST]\n", 207 | "\n", 208 | "```" 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": 2, 214 | "id": "BbYZOw-TDWhB", 215 | "metadata": { 216 | "executionInfo": { 217 | "elapsed": 761, 218 | "status": "ok", 219 | "timestamp": 1708127343333, 220 | "user": { 221 | "displayName": "LUC NGUYEN MANH", 222 | "userId": "17963881608411381207" 223 | }, 224 | "user_tz": -540 225 | }, 226 | "id": "BbYZOw-TDWhB" 227 | }, 228 | "outputs": [], 229 | "source": [ 230 | "df_data = pd.read_csv(\"./data/finetune_data_llama2b.csv\")" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 3, 236 | "id": "z5MUTvdkDbv9", 237 | "metadata": { 238 | "colab": { 239 | "base_uri": "https://localhost:8080/", 240 | "height": 293 241 | }, 242 | "executionInfo": { 243 | "elapsed": 341, 244 | "status": "ok", 245 | "timestamp": 1708127381750, 246 | "user": { 247 | "displayName": "LUC NGUYEN MANH", 248 | "userId": "17963881608411381207" 249 | }, 250 | "user_tz": -540 251 | }, 252 | "id": "z5MUTvdkDbv9", 253 | "outputId": "22ae2b44-bf3b-4d66-c34c-c10902107022" 254 | }, 255 | "outputs": [ 256 | { 257 | "data": { 258 | "text/html": [ 259 | "

\n", 260 | "\n", 273 | "\n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | "
instructionquestionsql_tbl_1sql_tbl_2answer
0\\nYou are an agent designed to interact with a...Calculate the distance between the 'user' and ...\\n CREATE TABLE user (\\n user_id INT...\\n CREATE TABLE user_reference (\\n u...SELECT target_id, reference_id, distancetype, ...
1\\nYou are an agent designed to interact with a...Determine the distance between the 'item' and ...\\n CREATE TABLE item (\\n item_id INT...\\n CREATE TABLE item_reference (\\n i...SELECT target_id, reference_id, distancetype, ...
2\\nYou are an agent designed to interact with a...Find the distance between the 'inventory' and ...\\n CREATE TABLE inventory (\\n produc...\\n CREATE TABLE inventory_reference (\\n ...SELECT target_id, reference_id, distancetype, ...
3\\nYou are an agent designed to interact with a...Compute the distance between the 'user' and 'u...\\n CREATE TABLE user (\\n user_id INT...\\n CREATE TABLE user_reference (\\n u...SELECT target_id, reference_id, distancetype, ...
4\\nYou are an agent designed to interact with a...Calculate the distance between the 'transactio...\\n CREATE TABLE transaction (\\n tran...\\n CREATE TABLE transaction_reference (\\n ...SELECT target_id, reference_id, distancetype, ...
\n", 327 | "
" 328 | ], 329 | "text/plain": [ 330 | " instruction \\\n", 331 | "0 \\nYou are an agent designed to interact with a... \n", 332 | "1 \\nYou are an agent designed to interact with a... \n", 333 | "2 \\nYou are an agent designed to interact with a... \n", 334 | "3 \\nYou are an agent designed to interact with a... \n", 335 | "4 \\nYou are an agent designed to interact with a... \n", 336 | "\n", 337 | " question \\\n", 338 | "0 Calculate the distance between the 'user' and ... \n", 339 | "1 Determine the distance between the 'item' and ... \n", 340 | "2 Find the distance between the 'inventory' and ... \n", 341 | "3 Compute the distance between the 'user' and 'u... \n", 342 | "4 Calculate the distance between the 'transactio... \n", 343 | "\n", 344 | " sql_tbl_1 \\\n", 345 | "0 \\n CREATE TABLE user (\\n user_id INT... \n", 346 | "1 \\n CREATE TABLE item (\\n item_id INT... \n", 347 | "2 \\n CREATE TABLE inventory (\\n produc... \n", 348 | "3 \\n CREATE TABLE user (\\n user_id INT... \n", 349 | "4 \\n CREATE TABLE transaction (\\n tran... \n", 350 | "\n", 351 | " sql_tbl_2 \\\n", 352 | "0 \\n CREATE TABLE user_reference (\\n u... \n", 353 | "1 \\n CREATE TABLE item_reference (\\n i... \n", 354 | "2 \\n CREATE TABLE inventory_reference (\\n ... \n", 355 | "3 \\n CREATE TABLE user_reference (\\n u... \n", 356 | "4 \\n CREATE TABLE transaction_reference (\\n ... \n", 357 | "\n", 358 | " answer \n", 359 | "0 SELECT target_id, reference_id, distancetype, ... \n", 360 | "1 SELECT target_id, reference_id, distancetype, ... \n", 361 | "2 SELECT target_id, reference_id, distancetype, ... \n", 362 | "3 SELECT target_id, reference_id, distancetype, ... \n", 363 | "4 SELECT target_id, reference_id, distancetype, ... " 364 | ] 365 | }, 366 | "execution_count": 3, 367 | "metadata": {}, 368 | "output_type": "execute_result" 369 | } 370 | ], 371 | "source": [ 372 | "df_data.head()" 373 | ] 374 | }, 375 | { 376 | "cell_type": "markdown", 377 | "id": "dd2225e6-1644-4462-850d-80f56e4d7210", 378 | "metadata": { 379 | "id": "dd2225e6-1644-4462-850d-80f56e4d7210" 380 | }, 381 | "source": [ 382 | "**Convert prompt template**" 383 | ] 384 | }, 385 | { 386 | "cell_type": "code", 387 | "execution_count": 4, 388 | "id": "53bc1004-d220-4f52-a9fc-b38cfd8af641", 389 | "metadata": { 390 | "executionInfo": { 391 | "elapsed": 348, 392 | "status": "ok", 393 | "timestamp": 1708127736663, 394 | "user": { 395 | "displayName": "LUC NGUYEN MANH", 396 | "userId": "17963881608411381207" 397 | }, 398 | "user_tz": -540 399 | }, 400 | "id": "53bc1004-d220-4f52-a9fc-b38cfd8af641" 401 | }, 402 | "outputs": [], 403 | "source": [ 404 | "prompt_template = PromptTemplate(\n", 405 | " input_variables=[\"instruction\", \"sql_table_1\", \"sql_table_2\", \"question\", \"answer\"], template=\"[INST] <>{instruction}. Here is structure of table 1 {sql_table_1}, table 2 {sql_table_2}<>{question}[/INST]{answer}\"\n", 406 | ")\n", 407 | "\n", 408 | "prompt_data = []\n", 409 | "for i, row in df_data.iterrows():\n", 410 | " prompt_data.append(prompt_template.format(instruction=row.instruction, sql_table_1=row.sql_tbl_1, sql_table_2=row.sql_tbl_2, question=row.question, answer=row.answer))\n", 411 | "\n", 412 | "dataset = Dataset.from_dict({\"inputs\": prompt_data})" 413 | ] 414 | }, 415 | { 416 | "cell_type": "code", 417 | "execution_count": 5, 418 | "id": "3c56c1b6-eccb-447c-844d-9b599d853dc5", 419 | "metadata": { 420 | "colab": { 421 | "base_uri": "https://localhost:8080/" 422 | }, 423 | "executionInfo": { 424 | "elapsed": 267, 425 | "status": "ok", 426 | "timestamp": 1708127757923, 427 | "user": { 428 | "displayName": "LUC NGUYEN MANH", 429 | "userId": "17963881608411381207" 430 | }, 431 | "user_tz": -540 432 | }, 433 | "id": "3c56c1b6-eccb-447c-844d-9b599d853dc5", 434 | "outputId": "9b77235f-ccb0-45ae-9e37-b582baeacdb3" 435 | }, 436 | "outputs": [ 437 | { 438 | "name": "stdout", 439 | "output_type": "stream", 440 | "text": [ 441 | "[INST] <>\n", 442 | "You are an agent designed to interact with a SQL database.\n", 443 | "Given an input question, \n", 444 | "create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer.\n", 445 | ". Here is structure of table 1 \n", 446 | " CREATE TABLE inventory (\n", 447 | " product_id INT PRIMARY KEY,\n", 448 | " name VARCHAR(255),\n", 449 | " description TEXT,\n", 450 | " quantity INT,\n", 451 | " price DECIMAL(10, 2)\n", 452 | " );\n", 453 | " , table 2 \n", 454 | " CREATE TABLE inventory_reference (\n", 455 | " product_id INT PRIMARY KEY,\n", 456 | " name VARCHAR(255),\n", 457 | " description TEXT,\n", 458 | " quantity INT,\n", 459 | " price DECIMAL(10, 2)\n", 460 | " );\n", 461 | " <>Find the distance between the 'inventory' and 'inventory_reference' tables using TD_VectorDistance.[/INST]SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n", 462 | " ON inventory AS TargetTable\n", 463 | " ON inventory_reference AS ReferenceTable DIMENSION\n", 464 | " USING\n", 465 | " TargetIDColumn('product_id')\n", 466 | " TargetFeatureColumns('quantity','price')\n", 467 | " RefIDColumn('product_id')\n", 468 | " RefFeatureColumns('quantity','price')\n", 469 | " DistanceMeasure('euclidean','cosine','manhattan')\n", 470 | " topk(2)\n", 471 | ") AS dt order by 3,1,2,4;\n" 472 | ] 473 | } 474 | ], 475 | "source": [ 476 | "print(dataset[2].get('inputs'))" 477 | ] 478 | }, 479 | { 480 | "cell_type": "code", 481 | "execution_count": 7, 482 | "id": "uJkIuxvlERJ-", 483 | "metadata": { 484 | "colab": { 485 | "base_uri": "https://localhost:8080/" 486 | }, 487 | "executionInfo": { 488 | "elapsed": 267, 489 | "status": "ok", 490 | "timestamp": 1708127788963, 491 | "user": { 492 | "displayName": "LUC NGUYEN MANH", 493 | "userId": "17963881608411381207" 494 | }, 495 | "user_tz": -540 496 | }, 497 | "id": "uJkIuxvlERJ-", 498 | "outputId": "a8ba9b31-7d7e-4fba-808c-69c3c307e6f2" 499 | }, 500 | "outputs": [ 501 | { 502 | "name": "stderr", 503 | "output_type": "stream", 504 | "text": [ 505 | "Creating json from Arrow format: 100%|████████████████████████████████████████████████████| 1/1 [00:00<00:00, 89.52ba/s]\n" 506 | ] 507 | }, 508 | { 509 | "data": { 510 | "text/plain": [ 511 | "107132" 512 | ] 513 | }, 514 | "execution_count": 7, 515 | "metadata": {}, 516 | "output_type": "execute_result" 517 | } 518 | ], 519 | "source": [ 520 | "dataset.to_json(\"./data/finetune_data.json\")" 521 | ] 522 | }, 523 | { 524 | "cell_type": "markdown", 525 | "id": "40f26097-aa5a-4f40-bd46-b4195768d5ea", 526 | "metadata": { 527 | "id": "40f26097-aa5a-4f40-bd46-b4195768d5ea" 528 | }, 529 | "source": [ 530 | "# 3. FineTuning" 531 | ] 532 | }, 533 | { 534 | "cell_type": "code", 535 | "execution_count": 17, 536 | "id": "85215578-445b-468b-9485-94f6ebf1721e", 537 | "metadata": { 538 | "executionInfo": { 539 | "elapsed": 283, 540 | "status": "ok", 541 | "timestamp": 1708127792256, 542 | "user": { 543 | "displayName": "LUC NGUYEN MANH", 544 | "userId": "17963881608411381207" 545 | }, 546 | "user_tz": -540 547 | }, 548 | "id": "85215578-445b-468b-9485-94f6ebf1721e" 549 | }, 550 | "outputs": [], 551 | "source": [ 552 | "tokenizer.pad_token = tokenizer.eos_token\n", 553 | "tokenizer.padding_side = \"right\"\n", 554 | "\n", 555 | "model.config.use_cache = False\n", 556 | "model.config.pretraining_tp = 1" 557 | ] 558 | }, 559 | { 560 | "cell_type": "code", 561 | "execution_count": 18, 562 | "id": "b539af5d-df5b-4480-9557-ede26ac23525", 563 | "metadata": { 564 | "executionInfo": { 565 | "elapsed": 269, 566 | "status": "ok", 567 | "timestamp": 1708127793766, 568 | "user": { 569 | "displayName": "LUC NGUYEN MANH", 570 | "userId": "17963881608411381207" 571 | }, 572 | "user_tz": -540 573 | }, 574 | "id": "b539af5d-df5b-4480-9557-ede26ac23525" 575 | }, 576 | "outputs": [], 577 | "source": [ 578 | "peft_params = LoraConfig(\n", 579 | " r=32,\n", 580 | " lora_alpha=32,\n", 581 | " lora_dropout=0.1,\n", 582 | " bias=\"none\",\n", 583 | " task_type=\"CAUSAL_LM\",\n", 584 | ")" 585 | ] 586 | }, 587 | { 588 | "cell_type": "code", 589 | "execution_count": 19, 590 | "id": "5f3be6dc-3a0a-4fc7-b630-7fb2a26e9767", 591 | "metadata": { 592 | "executionInfo": { 593 | "elapsed": 274, 594 | "status": "ok", 595 | "timestamp": 1708127796008, 596 | "user": { 597 | "displayName": "LUC NGUYEN MANH", 598 | "userId": "17963881608411381207" 599 | }, 600 | "user_tz": -540 601 | }, 602 | "id": "5f3be6dc-3a0a-4fc7-b630-7fb2a26e9767" 603 | }, 604 | "outputs": [], 605 | "source": [ 606 | "training_params = TrainingArguments(\n", 607 | " output_dir=\"./results\",\n", 608 | " num_train_epochs=5,\n", 609 | " per_device_train_batch_size=4,\n", 610 | " gradient_accumulation_steps=1,\n", 611 | " logging_steps=1,\n", 612 | " learning_rate=2e-4,\n", 613 | " fp16=True\n", 614 | ")" 615 | ] 616 | }, 617 | { 618 | "cell_type": "code", 619 | "execution_count": null, 620 | "id": "da1d422f-4929-4ce3-b1b2-a095d5fd7634", 621 | "metadata": { 622 | "id": "da1d422f-4929-4ce3-b1b2-a095d5fd7634" 623 | }, 624 | "outputs": [], 625 | "source": [ 626 | "trainer = SFTTrainer(\n", 627 | " model=model,\n", 628 | " train_dataset=dataset,\n", 629 | " peft_config=peft_params,\n", 630 | " dataset_text_field=\"inputs\",\n", 631 | " max_seq_length=None,\n", 632 | " tokenizer=tokenizer,\n", 633 | " args=training_params,\n", 634 | " packing=False,\n", 635 | ")" 636 | ] 637 | }, 638 | { 639 | "cell_type": "code", 640 | "execution_count": 21, 641 | "id": "20197c17-37a4-498d-bcb0-607c7c003328", 642 | "metadata": { 643 | "colab": { 644 | "base_uri": "https://localhost:8080/", 645 | "height": 1000 646 | }, 647 | "executionInfo": { 648 | "elapsed": 559869, 649 | "status": "ok", 650 | "timestamp": 1708128367973, 651 | "user": { 652 | "displayName": "LUC NGUYEN MANH", 653 | "userId": "17963881608411381207" 654 | }, 655 | "user_tz": -540 656 | }, 657 | "id": "20197c17-37a4-498d-bcb0-607c7c003328", 658 | "outputId": "937343dc-4284-4e6b-f8d6-4be54e9ac10d" 659 | }, 660 | "outputs": [ 661 | { 662 | "name": "stderr", 663 | "output_type": "stream", 664 | "text": [ 665 | "/usr/local/lib/python3.10/dist-packages/transformers/optimization.py:411: FutureWarning: This implementation of AdamW is deprecated and will be removed in a future version. Use the PyTorch implementation torch.optim.AdamW instead, or set `no_deprecation_warning=True` to disable this warning\n", 666 | " warnings.warn(\n", 667 | "You're using a LlamaTokenizerFast tokenizer. Please note that with a fast tokenizer, using the `__call__` method is faster than using a method to encode the text followed by a call to the `pad` method to get a padded encoding.\n", 668 | "/usr/local/lib/python3.10/dist-packages/torch/utils/checkpoint.py:429: UserWarning: torch.utils.checkpoint: please pass in use_reentrant=True or use_reentrant=False explicitly. The default value of use_reentrant will be updated to be False in the future. To maintain current behavior, pass use_reentrant=True. It is recommended that you use use_reentrant=False. Refer to docs for more details on the differences between the two variants.\n", 669 | " warnings.warn(\n" 670 | ] 671 | }, 672 | { 673 | "data": { 674 | "text/html": [ 675 | "\n", 676 | "
\n", 677 | " \n", 678 | " \n", 679 | " [95/95 09:12, Epoch 5/5]\n", 680 | "
\n", 681 | " \n", 682 | " \n", 683 | " \n", 684 | " \n", 685 | " \n", 686 | " \n", 687 | " \n", 688 | " \n", 689 | " \n", 690 | " \n", 691 | " \n", 692 | " \n", 693 | " \n", 694 | " \n", 695 | " \n", 696 | " \n", 697 | " \n", 698 | " \n", 699 | " \n", 700 | " \n", 701 | " \n", 702 | " \n", 703 | " \n", 704 | " \n", 705 | " \n", 706 | " \n", 707 | " \n", 708 | " \n", 709 | " \n", 710 | " \n", 711 | " \n", 712 | " \n", 713 | " \n", 714 | " \n", 715 | " \n", 716 | " \n", 717 | " \n", 718 | " \n", 719 | " \n", 720 | " \n", 721 | " \n", 722 | " \n", 723 | " \n", 724 | " \n", 725 | " \n", 726 | " \n", 727 | " \n", 728 | " \n", 729 | " \n", 730 | " \n", 731 | " \n", 732 | " \n", 733 | " \n", 734 | " \n", 735 | " \n", 736 | " \n", 737 | " \n", 738 | " \n", 739 | " \n", 740 | " \n", 741 | " \n", 742 | " \n", 743 | " \n", 744 | " \n", 745 | " \n", 746 | " \n", 747 | " \n", 748 | " \n", 749 | " \n", 750 | " \n", 751 | " \n", 752 | " \n", 753 | " \n", 754 | " \n", 755 | " \n", 756 | " \n", 757 | " \n", 758 | " \n", 759 | " \n", 760 | " \n", 761 | " \n", 762 | " \n", 763 | " \n", 764 | " \n", 765 | " \n", 766 | " \n", 767 | " \n", 768 | " \n", 769 | " \n", 770 | " \n", 771 | " \n", 772 | " \n", 773 | " \n", 774 | " \n", 775 | " \n", 776 | " \n", 777 | " \n", 778 | " \n", 779 | " \n", 780 | " \n", 781 | " \n", 782 | " \n", 783 | " \n", 784 | " \n", 785 | " \n", 786 | " \n", 787 | " \n", 788 | " \n", 789 | " \n", 790 | " \n", 791 | " \n", 792 | " \n", 793 | " \n", 794 | " \n", 795 | " \n", 796 | " \n", 797 | " \n", 798 | " \n", 799 | " \n", 800 | " \n", 801 | " \n", 802 | " \n", 803 | " \n", 804 | " \n", 805 | " \n", 806 | " \n", 807 | " \n", 808 | " \n", 809 | " \n", 810 | " \n", 811 | " \n", 812 | " \n", 813 | " \n", 814 | " \n", 815 | " \n", 816 | " \n", 817 | " \n", 818 | " \n", 819 | " \n", 820 | " \n", 821 | " \n", 822 | " \n", 823 | " \n", 824 | " \n", 825 | " \n", 826 | " \n", 827 | " \n", 828 | " \n", 829 | " \n", 830 | " \n", 831 | " \n", 832 | " \n", 833 | " \n", 834 | " \n", 835 | " \n", 836 | " \n", 837 | " \n", 838 | " \n", 839 | " \n", 840 | " \n", 841 | " \n", 842 | " \n", 843 | " \n", 844 | " \n", 845 | " \n", 846 | " \n", 847 | " \n", 848 | " \n", 849 | " \n", 850 | " \n", 851 | " \n", 852 | " \n", 853 | " \n", 854 | " \n", 855 | " \n", 856 | " \n", 857 | " \n", 858 | " \n", 859 | " \n", 860 | " \n", 861 | " \n", 862 | " \n", 863 | " \n", 864 | " \n", 865 | " \n", 866 | " \n", 867 | " \n", 868 | " \n", 869 | " \n", 870 | " \n", 871 | " \n", 872 | " \n", 873 | " \n", 874 | " \n", 875 | " \n", 876 | " \n", 877 | " \n", 878 | " \n", 879 | " \n", 880 | " \n", 881 | " \n", 882 | " \n", 883 | " \n", 884 | " \n", 885 | " \n", 886 | " \n", 887 | " \n", 888 | " \n", 889 | " \n", 890 | " \n", 891 | " \n", 892 | " \n", 893 | " \n", 894 | " \n", 895 | " \n", 896 | " \n", 897 | " \n", 898 | " \n", 899 | " \n", 900 | " \n", 901 | " \n", 902 | " \n", 903 | " \n", 904 | " \n", 905 | " \n", 906 | " \n", 907 | " \n", 908 | " \n", 909 | " \n", 910 | " \n", 911 | " \n", 912 | " \n", 913 | " \n", 914 | " \n", 915 | " \n", 916 | " \n", 917 | " \n", 918 | " \n", 919 | " \n", 920 | " \n", 921 | " \n", 922 | " \n", 923 | " \n", 924 | " \n", 925 | " \n", 926 | " \n", 927 | " \n", 928 | " \n", 929 | " \n", 930 | " \n", 931 | " \n", 932 | " \n", 933 | " \n", 934 | " \n", 935 | " \n", 936 | " \n", 937 | " \n", 938 | " \n", 939 | " \n", 940 | " \n", 941 | " \n", 942 | " \n", 943 | " \n", 944 | " \n", 945 | " \n", 946 | " \n", 947 | " \n", 948 | " \n", 949 | " \n", 950 | " \n", 951 | " \n", 952 | " \n", 953 | " \n", 954 | " \n", 955 | " \n", 956 | " \n", 957 | " \n", 958 | " \n", 959 | " \n", 960 | " \n", 961 | " \n", 962 | " \n", 963 | " \n", 964 | " \n", 965 | " \n", 966 | " \n", 967 | " \n", 968 | " \n", 969 | " \n", 970 | " \n", 971 | " \n", 972 | " \n", 973 | " \n", 974 | " \n", 975 | " \n", 976 | " \n", 977 | " \n", 978 | " \n", 979 | " \n", 980 | " \n", 981 | " \n", 982 | " \n", 983 | " \n", 984 | " \n", 985 | " \n", 986 | " \n", 987 | " \n", 988 | " \n", 989 | " \n", 990 | " \n", 991 | " \n", 992 | " \n", 993 | " \n", 994 | " \n", 995 | " \n", 996 | " \n", 997 | " \n", 998 | " \n", 999 | " \n", 1000 | " \n", 1001 | " \n", 1002 | " \n", 1003 | " \n", 1004 | " \n", 1005 | " \n", 1006 | " \n", 1007 | " \n", 1008 | " \n", 1009 | " \n", 1010 | " \n", 1011 | " \n", 1012 | " \n", 1013 | " \n", 1014 | " \n", 1015 | " \n", 1016 | " \n", 1017 | " \n", 1018 | " \n", 1019 | " \n", 1020 | " \n", 1021 | " \n", 1022 | " \n", 1023 | " \n", 1024 | " \n", 1025 | " \n", 1026 | " \n", 1027 | " \n", 1028 | " \n", 1029 | " \n", 1030 | " \n", 1031 | " \n", 1032 | " \n", 1033 | " \n", 1034 | " \n", 1035 | " \n", 1036 | " \n", 1037 | " \n", 1038 | " \n", 1039 | " \n", 1040 | " \n", 1041 | " \n", 1042 | " \n", 1043 | " \n", 1044 | " \n", 1045 | " \n", 1046 | " \n", 1047 | " \n", 1048 | " \n", 1049 | " \n", 1050 | " \n", 1051 | " \n", 1052 | " \n", 1053 | " \n", 1054 | " \n", 1055 | " \n", 1056 | " \n", 1057 | " \n", 1058 | " \n", 1059 | " \n", 1060 | " \n", 1061 | " \n", 1062 | " \n", 1063 | " \n", 1064 | " \n", 1065 | " \n", 1066 | " \n", 1067 | " \n", 1068 | " \n", 1069 | " \n", 1070 | "
StepTraining Loss
12.574800
22.521100
32.215500
42.028700
51.845000
61.681900
71.584600
81.463100
91.321500
101.221700
111.139100
121.048300
130.865400
140.812000
150.643800
160.599200
170.469300
180.405000
190.367900
200.306100
210.283100
220.283500
230.218000
240.169100
250.136800
260.109700
270.167000
280.089400
290.091300
300.093200
310.074700
320.066000
330.114700
340.099500
350.092100
360.084700
370.029000
380.046200
390.048400
400.034400
410.046000
420.028300
430.030200
440.043200
450.034200
460.060600
470.030500
480.024300
490.025400
500.024900
510.023100
520.019100
530.017600
540.024900
550.030700
560.022400
570.019600
580.020500
590.018800
600.014200
610.016900
620.015100
630.029100
640.017500
650.031700
660.020600
670.022200
680.021200
690.039500
700.033600
710.016700
720.021200
730.015900
740.015600
750.050900
760.016900
770.028600
780.017400
790.016400
800.017000
810.041500
820.013100
830.022800
840.019000
850.014400
860.014700
870.023000
880.016900
890.029800
900.017900
910.017700
920.020700
930.014400
940.019300
950.025400

" 1071 | ], 1072 | "text/plain": [ 1073 | "" 1074 | ] 1075 | }, 1076 | "metadata": {}, 1077 | "output_type": "display_data" 1078 | }, 1079 | { 1080 | "data": { 1081 | "text/plain": [ 1082 | "TrainOutput(global_step=95, training_loss=0.30292751963593456, metrics={'train_runtime': 559.4676, 'train_samples_per_second': 0.679, 'train_steps_per_second': 0.17, 'total_flos': 3329827315974144.0, 'train_loss': 0.30292751963593456, 'epoch': 5.0})" 1083 | ] 1084 | }, 1085 | "execution_count": 21, 1086 | "metadata": {}, 1087 | "output_type": "execute_result" 1088 | } 1089 | ], 1090 | "source": [ 1091 | "trainer.train()" 1092 | ] 1093 | }, 1094 | { 1095 | "cell_type": "markdown", 1096 | "id": "b0e7c485-83d3-4778-a50c-ef7957cbc002", 1097 | "metadata": { 1098 | "id": "b0e7c485-83d3-4778-a50c-ef7957cbc002" 1099 | }, 1100 | "source": [ 1101 | "# 4. Save model" 1102 | ] 1103 | }, 1104 | { 1105 | "cell_type": "code", 1106 | "execution_count": 22, 1107 | "id": "c6e7ab9f-bb04-441e-af07-df43274fea40", 1108 | "metadata": { 1109 | "colab": { 1110 | "base_uri": "https://localhost:8080/" 1111 | }, 1112 | "executionInfo": { 1113 | "elapsed": 454, 1114 | "status": "ok", 1115 | "timestamp": 1708128368416, 1116 | "user": { 1117 | "displayName": "LUC NGUYEN MANH", 1118 | "userId": "17963881608411381207" 1119 | }, 1120 | "user_tz": -540 1121 | }, 1122 | "id": "c6e7ab9f-bb04-441e-af07-df43274fea40", 1123 | "outputId": "331b0ae8-e531-40a5-cfd0-6a22bed5cc36" 1124 | }, 1125 | "outputs": [ 1126 | { 1127 | "data": { 1128 | "text/plain": [ 1129 | "('./drive/MyDrive/finetune_model/llama2_taradata/tokenizer_config.json',\n", 1130 | " './drive/MyDrive/finetune_model/llama2_taradata/special_tokens_map.json',\n", 1131 | " './drive/MyDrive/finetune_model/llama2_taradata/tokenizer.model',\n", 1132 | " './drive/MyDrive/finetune_model/llama2_taradata/added_tokens.json',\n", 1133 | " './drive/MyDrive/finetune_model/llama2_taradata/tokenizer.json')" 1134 | ] 1135 | }, 1136 | "execution_count": 22, 1137 | "metadata": {}, 1138 | "output_type": "execute_result" 1139 | } 1140 | ], 1141 | "source": [ 1142 | "new_model = \"./drive/MyDrive/finetune_model/llama2_taradata\"\n", 1143 | "\n", 1144 | "trainer.model.save_pretrained(new_model)\n", 1145 | "trainer.tokenizer.save_pretrained(new_model)" 1146 | ] 1147 | }, 1148 | { 1149 | "cell_type": "markdown", 1150 | "id": "a01f40db-c2bb-4faa-bca2-732fc5540784", 1151 | "metadata": { 1152 | "id": "a01f40db-c2bb-4faa-bca2-732fc5540784" 1153 | }, 1154 | "source": [ 1155 | "# 5. Reload and predict" 1156 | ] 1157 | }, 1158 | { 1159 | "cell_type": "markdown", 1160 | "id": "09844a08-d773-4f1e-8e8c-1365b7cc4240", 1161 | "metadata": { 1162 | "id": "auUKCzo-eTqh" 1163 | }, 1164 | "source": [ 1165 | "If you're using Google Colab T4, you need to restart the notebook to free up memory used during the fine-tuning step. After that, please rerun from this point onward." 1166 | ] 1167 | }, 1168 | { 1169 | "cell_type": "code", 1170 | "execution_count": 4, 1171 | "id": "TGy5PYk4LOck", 1172 | "metadata": { 1173 | "executionInfo": { 1174 | "elapsed": 281, 1175 | "status": "ok", 1176 | "timestamp": 1708128866715, 1177 | "user": { 1178 | "displayName": "LUC NGUYEN MANH", 1179 | "userId": "17963881608411381207" 1180 | }, 1181 | "user_tz": -540 1182 | }, 1183 | "id": "TGy5PYk4LOck" 1184 | }, 1185 | "outputs": [], 1186 | "source": [ 1187 | "model_name = \"NousResearch/Llama-2-7b-chat-hf\"\n", 1188 | "new_model = \"./drive/MyDrive/finetune_model/llama2_taradata\"" 1189 | ] 1190 | }, 1191 | { 1192 | "cell_type": "code", 1193 | "execution_count": null, 1194 | "id": "0fc35b6b-3ec7-4649-bb98-c1cf85821a02", 1195 | "metadata": { 1196 | "id": "0fc35b6b-3ec7-4649-bb98-c1cf85821a02" 1197 | }, 1198 | "outputs": [], 1199 | "source": [ 1200 | "# 1. Load based model\n", 1201 | "base_model = AutoModelForCausalLM.from_pretrained(model_name,\n", 1202 | " low_cpu_mem_usage=True,\n", 1203 | " return_dict=True,\n", 1204 | " torch_dtype=torch.float16,\n", 1205 | " device_map={\"\": 0},\n", 1206 | ")" 1207 | ] 1208 | }, 1209 | { 1210 | "cell_type": "code", 1211 | "execution_count": 12, 1212 | "id": "8ca48915-feed-4371-b645-f3a9daf6cbe0", 1213 | "metadata": { 1214 | "executionInfo": { 1215 | "elapsed": 30498, 1216 | "status": "ok", 1217 | "timestamp": 1708129435350, 1218 | "user": { 1219 | "displayName": "LUC NGUYEN MANH", 1220 | "userId": "17963881608411381207" 1221 | }, 1222 | "user_tz": -540 1223 | }, 1224 | "id": "8ca48915-feed-4371-b645-f3a9daf6cbe0" 1225 | }, 1226 | "outputs": [], 1227 | "source": [ 1228 | "# 2. Load new fine-tuned model. Then merge this two model\n", 1229 | "finetuned_model = PeftModel.from_pretrained(base_model, new_model)\n", 1230 | "merged_model = finetuned_model.merge_and_unload()" 1231 | ] 1232 | }, 1233 | { 1234 | "cell_type": "code", 1235 | "execution_count": null, 1236 | "id": "36883c08-1757-450c-a1da-5ce6d8f7bebb", 1237 | "metadata": { 1238 | "id": "36883c08-1757-450c-a1da-5ce6d8f7bebb" 1239 | }, 1240 | "outputs": [], 1241 | "source": [ 1242 | "# 3. Load tokenizer,\n", 1243 | "tokenizer = AutoTokenizer.from_pretrained(model_name, add_eos_token=True)\n", 1244 | "tokenizer.pad_token = tokenizer.eos_token\n", 1245 | "tokenizer.padding_side = \"right\"" 1246 | ] 1247 | }, 1248 | { 1249 | "cell_type": "code", 1250 | "execution_count": 19, 1251 | "id": "ee894f93-2b77-4e68-b4f6-fe1dd987ffaf", 1252 | "metadata": { 1253 | "executionInfo": { 1254 | "elapsed": 258, 1255 | "status": "ok", 1256 | "timestamp": 1708129562452, 1257 | "user": { 1258 | "displayName": "LUC NGUYEN MANH", 1259 | "userId": "17963881608411381207" 1260 | }, 1261 | "user_tz": -540 1262 | }, 1263 | "id": "ee894f93-2b77-4e68-b4f6-fe1dd987ffaf" 1264 | }, 1265 | "outputs": [], 1266 | "source": [ 1267 | "# 4. Define pipeline\n", 1268 | "pipe = pipeline(task=\"text-generation\", model=merged_model, tokenizer=tokenizer, max_length=2000)" 1269 | ] 1270 | }, 1271 | { 1272 | "cell_type": "code", 1273 | "execution_count": null, 1274 | "id": "N2lyqKStbFmP", 1275 | "metadata": { 1276 | "executionInfo": { 1277 | "elapsed": 3, 1278 | "status": "aborted", 1279 | "timestamp": 1708129058345, 1280 | "user": { 1281 | "displayName": "LUC NGUYEN MANH", 1282 | "userId": "17963881608411381207" 1283 | }, 1284 | "user_tz": -540 1285 | }, 1286 | "id": "N2lyqKStbFmP" 1287 | }, 1288 | "outputs": [], 1289 | "source": [] 1290 | }, 1291 | { 1292 | "cell_type": "code", 1293 | "execution_count": 20, 1294 | "id": "c6736df1-f705-4839-b19b-9407fd0a6aea", 1295 | "metadata": { 1296 | "executionInfo": { 1297 | "elapsed": 307, 1298 | "status": "ok", 1299 | "timestamp": 1708129566120, 1300 | "user": { 1301 | "displayName": "LUC NGUYEN MANH", 1302 | "userId": "17963881608411381207" 1303 | }, 1304 | "user_tz": -540 1305 | }, 1306 | "id": "c6736df1-f705-4839-b19b-9407fd0a6aea" 1307 | }, 1308 | "outputs": [], 1309 | "source": [ 1310 | "prompt_template = PromptTemplate(\n", 1311 | " input_variables=[\"instruction\", \"sql_table_1\", \"sql_table_2\", \"question\"], template=\"[INST] <>{instruction}. Here is structure of table 1 {sql_table_1}, table 2 {sql_table_2}<>{question}[/INST]\")\n", 1312 | "\n", 1313 | "\n", 1314 | "instruction = \"\"\"You are an agent designed to interact with a SQL database.\\nGiven an input question,\n", 1315 | "create a syntactically correct teradatasql query to run, then look at the results of the query and return the answer.\"\"\"\n", 1316 | "\n", 1317 | "question = \"Calculate the separation between the 'item' and 'item_reference' tables using TD_VectorDistance.\"\n", 1318 | "\n", 1319 | "sql_table_1 = \"\"\"\n", 1320 | " CREATE TABLE item (\n", 1321 | " item_id INT PRIMARY KEY,\n", 1322 | " name VARCHAR(255),\n", 1323 | " description TEXT,\n", 1324 | " price DECIMAL(10, 2),\n", 1325 | " stock_quantity INT,\n", 1326 | " category VARCHAR(100),\n", 1327 | " weight INT,\n", 1328 | " color_id INT,\n", 1329 | " height INT,\n", 1330 | " width INT\n", 1331 | " );\n", 1332 | "\"\"\"\n", 1333 | "\n", 1334 | "sql_table_2 = \"\"\"\n", 1335 | " CREATE TABLE item_reference (\n", 1336 | " item_id INT PRIMARY KEY,\n", 1337 | " name VARCHAR(255),\n", 1338 | " description TEXT,\n", 1339 | " price DECIMAL(10, 2),\n", 1340 | " stock_quantity INT,\n", 1341 | " category VARCHAR(100),\n", 1342 | " weight INT,\n", 1343 | " color_id INT,\n", 1344 | " height INT,\n", 1345 | " width INT\n", 1346 | " );\n", 1347 | "\"\"\"\n", 1348 | "\n", 1349 | "input = prompt_template.format(instruction=instruction, sql_table_1=sql_table_1, sql_table_2=sql_table_2, question=question)" 1350 | ] 1351 | }, 1352 | { 1353 | "cell_type": "code", 1354 | "execution_count": 21, 1355 | "id": "OvUIuEUOcB2v", 1356 | "metadata": { 1357 | "colab": { 1358 | "base_uri": "https://localhost:8080/", 1359 | "height": 140 1360 | }, 1361 | "executionInfo": { 1362 | "elapsed": 3, 1363 | "status": "ok", 1364 | "timestamp": 1708129566449, 1365 | "user": { 1366 | "displayName": "LUC NGUYEN MANH", 1367 | "userId": "17963881608411381207" 1368 | }, 1369 | "user_tz": -540 1370 | }, 1371 | "id": "OvUIuEUOcB2v", 1372 | "outputId": "d15f7bad-75de-45d0-b57b-8b17fcf07c23" 1373 | }, 1374 | "outputs": [ 1375 | { 1376 | "data": { 1377 | "application/vnd.google.colaboratory.intrinsic+json": { 1378 | "type": "string" 1379 | }, 1380 | "text/plain": [ 1381 | "\"[INST] <>You are an agent designed to interact with a SQL database.\\nGiven an input question, \\ncreate a syntactically correct teradatasql query to run, then look at the results of the query and return the answer.. Here is structure of table 1 \\n CREATE TABLE item (\\n item_id INT PRIMARY KEY,\\n name VARCHAR(255),\\n description TEXT,\\n price DECIMAL(10, 2),\\n stock_quantity INT,\\n category VARCHAR(100),\\n weight INT,\\n color_id INT,\\n height INT,\\n width INT\\n );\\n, table 2 \\n CREATE TABLE item_reference (\\n item_id INT PRIMARY KEY,\\n name VARCHAR(255),\\n description TEXT,\\n price DECIMAL(10, 2),\\n stock_quantity INT,\\n category VARCHAR(100),\\n weight INT,\\n color_id INT,\\n height INT,\\n width INT\\n );\\n<>Calculate the separation between the 'item' and 'item_reference' tables using TD_VectorDistance.[/INST]\"" 1382 | ] 1383 | }, 1384 | "execution_count": 21, 1385 | "metadata": {}, 1386 | "output_type": "execute_result" 1387 | } 1388 | ], 1389 | "source": [ 1390 | "input" 1391 | ] 1392 | }, 1393 | { 1394 | "cell_type": "code", 1395 | "execution_count": 24, 1396 | "id": "1a880cd6-0908-43d4-a9a4-e2caddc1b820", 1397 | "metadata": { 1398 | "executionInfo": { 1399 | "elapsed": 39464, 1400 | "status": "ok", 1401 | "timestamp": 1708130059952, 1402 | "user": { 1403 | "displayName": "LUC NGUYEN MANH", 1404 | "userId": "17963881608411381207" 1405 | }, 1406 | "user_tz": -540 1407 | }, 1408 | "id": "1a880cd6-0908-43d4-a9a4-e2caddc1b820" 1409 | }, 1410 | "outputs": [], 1411 | "source": [ 1412 | "# 5. Run prompt and pipeline\n", 1413 | "result = pipe(input)" 1414 | ] 1415 | }, 1416 | { 1417 | "cell_type": "code", 1418 | "execution_count": 29, 1419 | "id": "KuFTpN9PNdKm", 1420 | "metadata": { 1421 | "colab": { 1422 | "base_uri": "https://localhost:8080/" 1423 | }, 1424 | "executionInfo": { 1425 | "elapsed": 531, 1426 | "status": "ok", 1427 | "timestamp": 1708130343286, 1428 | "user": { 1429 | "displayName": "LUC NGUYEN MANH", 1430 | "userId": "17963881608411381207" 1431 | }, 1432 | "user_tz": -540 1433 | }, 1434 | "id": "KuFTpN9PNdKm", 1435 | "outputId": "91d70df4-63c5-42c8-d990-ff609344029f" 1436 | }, 1437 | "outputs": [ 1438 | { 1439 | "name": "stdout", 1440 | "output_type": "stream", 1441 | "text": [ 1442 | "SELECT target_id, reference_id, distancetype, cast(distance as decimal(36,8)) as distance FROM TD_VECTORDISTANCE (\n", 1443 | " ON item AS TargetTable\n", 1444 | " ON item_reference AS ReferenceTable DIMENSION\n", 1445 | " USING\n", 1446 | " TargetIDColumn('item_id')\n", 1447 | " TargetFeatureColumns('price','stock_quantity','category','weight','color_id','height','width')\n", 1448 | " RefIDColumn('item_id')\n", 1449 | " RefFeatureColumns('price','stock_quantity','category','weight','color_id','height','width')\n", 1450 | " DistanceMeasure('euclidean','cosine','manhattan')\n", 1451 | " topk(2)\n", 1452 | ") AS dt order by 3,1,2,4;\n", 1453 | "\n", 1454 | "The TD_VectorDistance function is used in the query to calculate the distance between the 'item' and 'item_reference' tables. The TargetIDColumn, TargetFeatureColumns, RefIDColumn, RefFeatureColumns, DistanceMeasure, and topk parameters are used to define how the distance is calculated. The results are then organized in a table with the target ID, reference ID, distance type, and distance values. \n", 1455 | "\n", 1456 | "The TargetIDColumn parameter specifies the column or columns in the Target table that correspond to the TargetID column in the Distance table. The TargetFeatureColumns parameter specifies the column or columns in the Target table that correspond to the TargetFeature columns in the Distance table. The RefIDColumn parameter specifies the column or columns in the Reference table that correspond to the RefID column in the Distance table. The RefFeatureColumns parameter specifies the column or columns in the Reference table that correspond to the RefFeature columns in the Distance table. The DistanceMeasure parameter specifies the distance measure to use when calculating the distance between the Target and Reference tables. Finally, the topk parameter specifies the number of closest references to return for each target item.\n", 1457 | "\n", 1458 | "The query uses the TD_VectorDistance function to calculate the distance between the 'item' and 'item_reference' tables using the Euclidean distance, cosine distance, and Manhattan distance as the distance measures. The top 2 closest references are then returned for each target item.\n" 1459 | ] 1460 | } 1461 | ], 1462 | "source": [ 1463 | "print(result[0]['generated_text'].split(\"/INST\")[1][1:])" 1464 | ] 1465 | }, 1466 | { 1467 | "cell_type": "code", 1468 | "execution_count": null, 1469 | "id": "9e081096-aba9-4214-bbbd-f6aa605c1b98", 1470 | "metadata": { 1471 | "id": "9e081096-aba9-4214-bbbd-f6aa605c1b98" 1472 | }, 1473 | "outputs": [], 1474 | "source": [] 1475 | } 1476 | ], 1477 | "metadata": { 1478 | "accelerator": "GPU", 1479 | "colab": { 1480 | "gpuType": "T4", 1481 | "provenance": [] 1482 | }, 1483 | "kernelspec": { 1484 | "display_name": "Python 3 (ipykernel)", 1485 | "language": "python", 1486 | "name": "python3" 1487 | }, 1488 | "language_info": { 1489 | "codemirror_mode": { 1490 | "name": "ipython", 1491 | "version": 3 1492 | }, 1493 | "file_extension": ".py", 1494 | "mimetype": "text/x-python", 1495 | "name": "python", 1496 | "nbconvert_exporter": "python", 1497 | "pygments_lexer": "ipython3", 1498 | "version": "3.10.13" 1499 | } 1500 | }, 1501 | "nbformat": 4, 1502 | "nbformat_minor": 5 1503 | } 1504 | -------------------------------------------------------------------------------- /01_AutogluonTeradata/01_Autogluon_Teradata.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "787978f5-870d-434a-8a7e-bb340c1743ef", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "!pip install autogluon.tabular==0.8.2\n", 11 | "!pip install autogluon.tabular[catboost]==0.8.2\n", 12 | "!pip install autogluon.tabular[xgboost]==0.8.2\n", 13 | "!pip install sklearn2pmml==0.99.2\n", 14 | "!pip install teradataml==17.20.0.4" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 12, 20 | "id": "899f07ed-c3f0-4aaa-aee0-1177fd8445f5", 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "# Teradata DB info \n", 25 | "host=\"192.168.11.7\"\n", 26 | "username = \"dbc\"\n", 27 | "password = \"dbc\"\n", 28 | "db_name = \"Machine_learning_demo\"" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "id": "a3e7e532-849a-4c57-905b-528a535f0fbf", 34 | "metadata": {}, 35 | "source": [ 36 | "## 1. Autogluon" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 2, 42 | "id": "ca639d49-ca59-4d45-8474-cf8cf8c8b57c", 43 | "metadata": {}, 44 | "outputs": [ 45 | { 46 | "name": "stderr", 47 | "output_type": "stream", 48 | "text": [ 49 | "C:\\Users\\admin\\miniconda3\\envs\\easyml_llm\\lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", 50 | " from .autonotebook import tqdm as notebook_tqdm\n" 51 | ] 52 | } 53 | ], 54 | "source": [ 55 | "from autogluon.tabular import TabularDataset, TabularPredictor" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "id": "31f26561-12f4-4e7d-94a1-bd7196cbce85", 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "data_root = 'https://autogluon.s3.amazonaws.com/datasets/Inc/'\n", 66 | "train_data = TabularDataset(data_root + 'train.csv').sample(1000)\n", 67 | "test_data = TabularDataset(data_root + 'test.csv')\n", 68 | "\n", 69 | "f_generator = {\n", 70 | " 'enable_text_ngram_features': False,\n", 71 | " 'enable_text_special_features': False\n", 72 | "}\n", 73 | "\n", 74 | "predictor = TabularPredictor(label='class').fit(train_data=train_data, _feature_generator_kwargs=f_generator)" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 50, 80 | "id": "534a89e7-555a-4d9b-b304-043df2805cbc", 81 | "metadata": {}, 82 | "outputs": [ 83 | { 84 | "name": "stdout", 85 | "output_type": "stream", 86 | "text": [ 87 | " model score_val pred_time_val fit_time pred_time_val_marginal fit_time_marginal stack_level can_infer fit_order\n", 88 | "0 XGBoost 0.855 0.013272 0.663066 0.013272 0.663066 1 True 10\n", 89 | "1 WeightedEnsemble_L2 0.855 0.014257 1.169622 0.000985 0.506556 2 True 12\n", 90 | "2 CatBoost 0.850 0.008459 26.530733 0.008459 26.530733 1 True 7\n", 91 | "3 LightGBM 0.845 0.004889 0.497861 0.004889 0.497861 1 True 4\n", 92 | "4 LightGBMLarge 0.845 0.005887 1.332920 0.005887 1.332920 1 True 11\n", 93 | "5 LightGBMXT 0.835 0.004477 0.727046 0.004477 0.727046 1 True 3\n", 94 | "6 ExtraTreesEntr 0.825 0.051862 0.494863 0.051862 0.494863 1 True 9\n", 95 | "7 ExtraTreesGini 0.825 0.053010 0.479725 0.053010 0.479725 1 True 8\n", 96 | "8 RandomForestEntr 0.820 0.053157 0.467865 0.053157 0.467865 1 True 6\n", 97 | "9 RandomForestGini 0.810 0.074189 0.501072 0.074189 0.501072 1 True 5\n", 98 | "10 KNeighborsUnif 0.710 0.027325 0.009897 0.027325 0.009897 1 True 1\n", 99 | "11 KNeighborsDist 0.685 0.018341 0.005411 0.018341 0.005411 1 True 2\n" 100 | ] 101 | } 102 | ], 103 | "source": [ 104 | "df_leaderboard = predictor.leaderboard()" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": 51, 110 | "id": "8dc31a0f-d1cb-44d7-8686-174024c16ade", 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "predictor = TabularPredictor.load(\"./AutogluonModels/ag-20231121_022123\")" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "id": "2d29f124-1ec0-480d-8be2-d678b61ae5c8", 120 | "metadata": {}, 121 | "source": [ 122 | "## 2. Load model and convert to pmml" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 13, 128 | "id": "9ba71d4d-e910-4bb0-a7a3-25ab9c9ed21c", 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "from sklearn2pmml import sklearn2pmml\n", 133 | "from teradataml import save_byom, delete_byom\n", 134 | "from teradataml.context.context import *" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": 52, 140 | "id": "7604700f-e1ce-4bb3-8af0-38971e207d3e", 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "# Load model\n", 145 | "model_rf = predictor._trainer.load_model(\"RandomForestGini\")\n", 146 | "# Save model as pmml file\n", 147 | "sklearn2pmml(model_rf.model, \"./random_forest.pmml\")" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": 53, 153 | "id": "780554e1-81b0-471f-afec-6348a3c988c7", 154 | "metadata": {}, 155 | "outputs": [], 156 | "source": [ 157 | "sklearn2pmml(model_rf.model, \"./rfmodel.pmml\")" 158 | ] 159 | }, 160 | { 161 | "cell_type": "markdown", 162 | "id": "c0a21c7c-2219-425c-b1f4-0cfe477d4cb4", 163 | "metadata": {}, 164 | "source": [ 165 | "**Upload model to Teradata**" 166 | ] 167 | }, 168 | { 169 | "attachments": { 170 | "108931b7-0740-47b9-bc1d-cc333d24fdcf.png": { 171 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAA34AAAHrCAYAAACQHU/NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABhaVRYdFNuaXBNZXRhZGF0YQAAAAAAeyJjbGlwUG9pbnRzIjpbeyJ4IjowLCJ5IjowfSx7IngiOjg5NCwieSI6MH0seyJ4Ijo4OTQsInkiOjQ5MX0seyJ4IjowLCJ5Ijo0OTF9XX3yDHImAACLr0lEQVR4Xu3dB9wV1Z3/8R8iSJMuRYoIqCiokaiQImokpKDEjQnWNEwgm7gmS3ZJ3FXiYpJV9i+WaBQVNEYsJBpFiIomIsYIiihREKWIgAJKlyao/Od7nnuu5xnm1qf4MHzevIbnTjtz5kz93XNmbr133tu82wAAAAAAqbVf5i8AAAAAIKUI/AAAAAAg5Qj8AAAAACDlCPwAAAAAIOUI/AAAAAAg5Qj8AAAAACDlCPwAAAAAIOXq/fnPf+Z3/AAAAAAgxeo9+eSTBH4AAAAAkGL1XnjhBQI/AAAAAEixeq+99hqBHwAAAACkWL1Vq1YR+AEAAABAitXbuHEjgR8AAAAApFi97du3E/gBAAAAQIrV27VrF4EfAAAAAKRYvQ8//JDADwAAAABSrN7uSOYzAAAAACCFSgr8Nr+3xd5evdo+/PCjzJCMemYNGzS0g9q0tubND7T96kUDEmTn/+gja37ggdapQ3vbb7/9MmOLt3XbNnt9yRu2+p13bfuOHdayeXPr0ulgO7RrF9t///qZqSrTar67br2tjbr4KteL8tu4cSNr17aNNW3SJDO0eB9++KG9tXqNvbdlS7SgzECJimH/+vtbi6hMWrZobo0OOCAzYu/2UbT9tL6b33uv8voWoG2tfaRN61auzAEAAADUjqIDP0327PNz7bKrrrbt23dkhu6pQ7uD7OuDv2yDv/gFa9WyRWbonvMPHPA5+8VPfmRNGjfOTFHYlq3b7NG/zbA7Jz/gAri4Y/scZT+44Bz7VPQ3HlB+8MGHNun+B2387ydlhiTrfcTh9s2vDbYBnzmx6EBty9at9ptrbrQZ/5iVGbInBcOf73+infv1IW4ZuQLUvcG27dvtyut+Z0/MfCYzpDgqg4uHf8++ccZXywr4AQAAAJSn2u++VQv3u9v/YP9x+a/tjeUrMkMTlFjjo0Bv7G9vsnE33ZYY9Mm8VxbYz0b/yh78y3TbtWtXZmhp5r/2ul0+9hr7f7+7xTZtfi8ztOo+igLfmc/Oth+PutRumPD7ak17x/vvu3L57Fe/bqeddZ7NeuHFPWo1AQAAAOy76l8eyXwuaOXbq+zJZ561Dz74wLp27mRDv3a6feb4vnbiccfa0UceYY0bNXKBn5oCKjh7//2d9ulj+1jDBg32mL97t672+X4nWIPMuHzWb9xoY2+42WY883GNWts2re3Uz3/G+vX9lDVt2sTWZJarZpfPvzjPWrZsYYd3756tWfroo9328qsL7YV5L7v+Ez51jJ35lUF2YjS/8n9490Pd/O+uW+fGL1m23A5q08Z69fw4jVx2RkHm07Oet2UrVrppvzrwVBt0yknZclFeN23a7JqlKhxTcPnKwtft08f0sQObNa1IpAo+iNb5ubnz7NXXF0flub+ddtLnrHPHDjXXnDJK94CGB0Rl08NOiNZR66lOy1z65nLXFLjdQW3tm0MG2+dOPD47vn+0rxxz1JGuPGjqCQAAANSesgM/3fD/8DvnR4Hd0dHNfC/rGwUxA6NgR80sn4sCLzUH3Lptq/X/dF9r3arlHvMXG/jt3LnTJj80zaY88rgLmtQ09D9+PNwu+cmPXOCnfHzp1AF2+qDTXJNLPfunAO71xUvtqCMOc01PFWTEA7+zTv+ya3Z5bO8jXf5P7HusfWXgKda2VSsXOCqAVGjS/4S+BZt8hoGfgt/h3z7PvnLaKdlyOfVzn3HNR488rIf9c8FC94yiAtXduz9yyy8m+M1HgZ/yXFuBX/0ouD0kCvyPjtZP6+g7PWs58x/PuQD3iChg/vGF33aBuR/fJwqC9YwfQR8AAABQu8oO/Lof0sU+379y4KYb+uYHNrNly1fYkmVvRoGN2UnRNB3bt3Pjywn8FMzcePsfomBpux3QsKH97Ec/cEFVfL6mTRpHQdRRrsZOy1bwsS2aRzV6BxzQcI/A78TjPuUCkTAIUUCjF7HMiaZZv2FjFGQ2spM/279grVwY+Clfpw34nHWKAq+Q0u7a6WA77NBurinmjh3v2/KVb1mvw3pa54M7ZvOhJporV622e+6fYtfdcrtdN36i3fPAQ/bSKwts8+b3XBDdrGkTN72asz4w9VG77a57ozz/09WwqmwV/D717Gyb89I/7dBoO2mdRMGsahsnTLrPpX191D346OO2cPGSKK0PXA2nyqpc765dZ0889XdX9trmCswVCHtq3qq8TvrTg/b32c+7l/uo9i9uRbSf/PbWO+z+hx9xgXLPQw9xzYZVFn/565MusN/x/g67+/6HKtbj1tvtH8/NtQ8/+tC6RGXZMNpPkqi5rWpy77j3T3b1Tbe4JrfPvfjPaFtviMq1lTVv1oygFAAAAKlU/jN+Rd4gV+VZM72Q5aX5C7LP9A34bL8oEOtn9esnvxhFQefZZ55u7Q9q6/oV6K14+233OS5X9sP8ViHriRRUqOZLtZOil9UoEPXPI+6KgraHHnncvvPjkXbn5PtdAKthmu7ZOXPtmvETbOToK1xgJ3o7qoJNpRE+M6ggSUHfC/98xdW8impDFSCN+Nl/2dTpf7W3V69xgZDK9vEZT7vnGn99zQ22bv0GN31NUCCtwPj5KG9P/v1Z+8fzc936hRTUvfjyfJs+Y6abTsGqAu8NGze5gFkvCPrdxDvt3y75pf1xyjQXPGs/UUD7fzeMd8MXLlq8x36n5UyL1nv4yF/Ynx7+S7T+77j59FzozXdMsu/923/YtMf/tkd+AAAAgDSo1pe76Kb9+Rf/ac8894Lr96/uL9f7O9+3xUuXuc8N9t/fPSfWpMDPLaj2rE+vI9xn/XzEyrdWuQCnGHpJioKgpcuWu37V2pXz8w75KPDR84UKUkU1UNu273CBigKem39/l8uHpxoxPS/nvbniLbv3z1NcIKdaxG5dOrvmtr5WT/SzFsdHy9AzhGoaqwBn2uNP2v1TH81MUUHr5/Mhz8x+3gVcmr4m7B9tw3DdFZzq2ceQAtU5L85zeVANb/9PH2eNglpDWbdho+3cWREsq3xat6xoSiyvLV5qY3873t5atTozpGK//NvT/7Brb5mYLVu9VfXg4OdEtNxrx090L+Apdn/JRwGrllsdVIv76quv2kMPPWQ33HCDXXfdda677bbb7PHHH7dVq1ZV6QsWAAAApF/Zgd+ipW/Y5AenumaI6u7605/tN9fdaJf/3zUuKGnYsIGddfpXrHPHjpk5Svf+zp22NlMD1aJFcxfQ5PqNQE9NC3sd1sN9Vu3Nu+vX2+6EG/DZL7wU5XtKNv+qYfuvX421W/5wj7thV0DxjTO+Ui0vXwmp1q99u4OsTauKgFgvrlHQoaafTz0zywWrolrBP028yR6681Z74I7xdvv1/8+6H9LVjXvxlQWu2ayCSD07+H+X/5cNHPB5N06/R/hvP/iuXffrX9plP7vYNS9dG5WBAh+tl4KpHw/7tj163532xwm/s2l3326/+e//tGZNm7qAR0H75i3V98bRkNZd21DNW2XxG2/a0uUrKgUtb61aYy+/+pr7rObARx7eM3Gb61nSu2661h6MymfKpAnus4aJmq4+9uTMbO2dgms1b9XPiLRo3tz++98vskfu/b0r37/cc4f9aNi3XLloO9x53wOVgsZyvB8Fl5MnT7Y5c+ZUOSBbt26d3XHHHfb222/bgAED7Lvf/a5deOGFrjvnnHPsyCOPtJkzZ9ojjzxS9ptsAQAAkH5lB36qeVKQ9Nvbfu+63038g/3l8SddTYxehjLyh9+3M748sEq/V6fnzvS8mOgZvmZFBGH19tvP/Vi6aghl69ZtiTUvegHNjRPvzOZfzf3UlFAO7tDOLv/Pn9qnju7tgpXqprec+t8v1HN5CnAVsP10xDC78aorXOB24flnuxopLV+BT7eune2E445x8+iH4hUQFxtU6AU3V4/57yjAG+WW8S+Dv5StdVOz2aOP7GWHde/m+pXue+9tdZ9rgpb72RP6unXSFwQv/vMVV6MlqiVT81z90L6ohrdtQo2xapL/9XsXZL8IUKfP37/gnGzNp95yquahSnNutIy3M8HcN4d81QadOiBbk6v86Hcnv/SFk13/mytX2sLXF5dd66dtMm/ePJs1a5Y99thjtnp1+UHkjmjfV0CngO8LX/iCtWrVKjoGmlXqOnfubN/85jddzaWWSc0fAAAAklRrU09Pzemuv/UO12yyKs0GdRO7+6Oq3ciWcx+s57+u+u3NNn/ha7V6I60avOOiYPPcfxninlPU2z8XvLbIvTBFLzrRT0CIghnVXpWSM9XonfK5/va1rwxytaIKihQQ6bm2Bx+Z7p75E9VWKRCtKQo09RKeg9q2cf3uRTpRXkQv8FFTYQXqCsj0xlY1D41Tje4hUcATBuX6rOBYP8shK1etsjXvvuv2RW1HBXL6QuLAqBz0xtf5UVn6Ts9StmnV0gVP+uLizZVvuTIux1tvvWV/+ctfXNC2MgoiH374YdsWbcdyLFu2zDp06GCHHXaYy8/zzz/vgsl33nnHXn75ZfdZf5VvBYeqFdy8uXLTWQAAAEDKDvwUoPz2f//Hbh13petUU6XapN69Dnfj1Wzuptv/EAUr5QdP+0dBwgGNKn5KYfuO912wU1C0LAVM/sa9UTR/vXp7rua/DP6yjb/6N9n8X/ur0TbsvKGudkxWvPW23TjhTve7hNVNbwFV+YjeoqlmhqJyUgD2x4em2U/+63L7yjnfse//+89t9FXj3BsoFaR4pZaogim99ERv1fzOv/3MBp/3PbvoF6PdC13UDHLNu2szU1bkoyZ1PrhDtlnmG2/6N8Duds1XX43yKEcdfphr2ppU49qxffvEt4+qFvWQLp3dZwV8qrlUjapvPqthekHOD0b+olKnF97cfs8fszXDeplOUi1xIb6GTs/ceS+88ILNnj0701eaN954w7p16+bKQOXz+uuv2wMPPBCt13u2fPly9/nNN9900+rZ1wMPPNA1DQUAAADiyg789NIWPX+lQE+dAkH9oLsCqPPPOtNNo5dw6GUZCnTKoeaPatYn+imDVWveKdgET7VVbyxf6aZTc0/VnO1Xf8/V7NyxvfU+oiLv6vSzD2oqeNP//dr9KL3opyTmzX+17GZ/uehnD/Rsn+jFJApYtAy9uVOBiIITvdGyul6yome/7v3zwy7AmXj35OwLcz4pjaP11Utb9ByoAmDVPOqvfrph/foNrgZL2yDX85VqKpvUAFcvu1GgLx99+JHb73Z9+GH2hS7F0vTlBL96Cc0PfvAD++1vf+tq4IYNG2Y333yznXLKKZkpShMGn6opPemkk+xzn/ucy1vfvn3t9NNPr/SGWzX9LCdgBQAAQPpVe1NPPTulZ6h8zZl+ekA1KOU4oOEBdniPiqZ7uhnXb9npB93z0TNqr2ReDqLmgl07H5z4cpBc1ATxKwNPdbVwejnIoij/H1TjSzMUzC1ctMTey9RC6Tfq9DMHGzdtci+bURNMUd71O4d61k8vI7n1mivtvLO+5saVasmby23ylGnZl51o2+hH73/0vW/ZFZf8zNV4KhCTmq3rq6DtcVQUbHc5+GDXP3feK+6ZUf0IvQLgDu3auucrc/1sx6b3NrufsojTD9nrCwLRD9krcDwgeJ5SXyToywm93CZX92/f/45rEptr2XFLly61n/zkJzZixAjXXXHFFbZmTUWzWXnuuefshz/8YXa83spZbNNP1eBt3VrxvKWCYf0+4fYoQFbtXtOmTW3Dhg3WqVMnN14Bn5p5xt+ACgAAAEj5gV+eGhHVuugmW/yPipejfv393E8z6E2Mojc1KqjLVRujoPCxvz3lmg7K4T27W6cOlX9I3cuVfYWI+oF0f+O/bceOaq3x0+/uPTz9CZemlqOfXdCzfWvXbXBNHaVXzx522zVX2dhfXuICv8Ff/IJ7dq3YYCSk5egnLRRYyle/eKrdeeM4++V//tQu+Oa/2Gknfc69RMavY/EhctW0iwLs4z91tPusMtEPsy94fZHrP+7oPu4FO7ksXbYi23wzpGEKcqVVy5bux+5dABgF0VIv+qcX5CiAPv8bZ1bqvn76l+3Mrw6yc7/+NRcE+5cDFaJ98Ytf/KKr2VN36aWXWvv27TNjzfr165cdd/XVV7sXtBRbK9ezZ0977bXX3HOXovnOPPNM69ixo6vFPfnkk61Pnz5unIJNBYkHHVTxhQsAAAAQKj/wy1GLpgDitUVLbNXqd1x/8+bN3Es1yqFnm3p062r9+h7r+jdt3uyaQarGLB786Ub44el/tUl/etD1qxmhghrVnCXJVQmopqIvvbwg+wxeqxYtygq44pTu07Oet19eNc7Vbsnn+p0QBbaHu/VUcOxrsVTrGP4un6x65117fu68TN+e9tvv4xWKv5hEy/YvyVEgfECwPbS9VCv72uIlmSG1Q8019fIW1capNveBqY+6H6F3v913/HGuOWgui99Y5mp/fbAq+qxmub4Za49Duro3gmrf633EYa7GTNv0gWmP7vEj9aoJffAvj9mXhn7bfvgf/+Wa3IZpF0PbMOxCuYYXohe7tIwC2OnTp7vg7+CDD3ZBpdJp06aNHXLIIW699FyffuOvf//+lbYtAAAA4NW/PJL5XJBqpJ585lkXpCgw6XJwR9c0Uc+sqVv65nK778GH3ctCFGyoSd/XvjzIPf+nwKTQ/GGn2hvViCkwaH/QQTbnpXn23pattnHTZnv0bzNs+Vtv2/s73nev/v/Hcy/Ybyf83h565PFs0POFKOg758wzPn7mKwp89FMBL8x72fV36tgxykMzWxvNr+W98+5a99ZMvfxkWhRA6rZfyz/n60Pcb+Hlu2nXs2QK6lRzpRtx/9MIeqvkP6NgZPJDU+3K629yb9BU/kU/NK9mhaptEwUf+g299Rs2uryoWZ+eo9RbJp99/gUbd9Nt7rcTRYHoSf1PdL9zp3wpr3oeUT8Ar7LVS3GaH3igW5aaO+ptmU9lnrXUy2MUzOonL/Sc4aN/nWG/ve2ObL60zgNP/nzizygUonLUG0j1Exwd27ezUz//GfcG0STKt5ol6rm+NcELdNT09exou8UD9uUr37IZz8xyzTm1jfUSmEM6dXLlpy8BZkXB2nW33B7tN++52rqhXxvsnuFUWWlf++f8ha4ZsPZBvbVT66/hKpuHH/ure7mL9lnlXb+J2CnzUxqFqLnl2rVr7fDDK15qJKqZ0w+uKzjzTTFFX04sXLjQevXq5bZvIVr+oYce6ppw3nfffW499fMNqtnWC2O0jKefftr9fISe9+vSpUtReQYAAMC+p150M1lU1YYme/b5uXbZVVcX93bNiJrM/fzif3UvWCl1/kO6dLKxv/wvFxzqRn/ms8/Z1b+7NftSlHz0+28jf/QDF7B5erZu0v0P2vjfT8oMKUwvqdGbPn2z1Vz0e3S/ueZGm/GPWZkh+Sno+/m//dCOO6ZP9vlD3cxPuHuy/WHyA64/H9Vm/tdPL3IBmub3ZVvx4/kfPz/WqWMHGzv6EmvR4kAb8/+ut+fmvpQZk5u21ZWX/cKO6Nk9M6R4euvoz8dc6bZR32jdxvxipHt5TS4Kdu++/6FK2+RbQ79uF0ZlHgZGWr+nZz1nl4+9tqgXtQz4TD/7RbTfKbgT1d49He0/v77mtwWfN/3mkME24jvnZZ8LLGTJkiUuAFPgFad8h4GYmmI++OCD9rWvfc29iKUUelPoM888Y1/60pfcm0MV5B1zTMXvOqp2VMsh6AMAAEAu1f5yF9FvxunZtMt+drELJKpKtTZ64cZvr/wfV4uUi27Wf/jd8+1X//UflYK+UilgUt4vvODsgkFfKQ49pIv9LApI9TKVTx97dKWXzijQ0Q+Jf+aEijeKxinY02/NJdENf99j+7jn08IfzFdtqt6E2rJ582h7DLUuOcpEtWvaZrVNNXN9j+mdDQ6VDwXteuYxHwWl2kZxKs8zvzLIRv3biGzQJxp+0mdOtP+99OfuJyKSqKZWP+7+vXO/WXTQ522MAl391EK8W7RoUaV+BYmFXk6Ui/KnF7tMmzbN/cSDmnXqBS/qNI6gDwAAAPkUXeMnK95eZbPmvLjHzatuOhVw6AZev9F2aHRz7X+bLpRr/iRqhqeam3iTPzWje33JUns2SuetVatt27bt1ioKiNREUG/B9D//EKdaH/2Qt5pz6lX/IeVfvwunF4507dTJrUMpz/VpfWa98KKtfHu1q+Xx1Lz1wGbN7NCuXdzvy6kZZSFqDvjCP19xTSbV/PKQzp3smN5H2lFHHObWV00c9bMFJ3zqWPeD5eENv9bxjTeXu+aT+k05vRRHz9H5MlHNpJpL/uP5ua4c1SRVzXCVjppCqhmo8qhnD3MFmfmo2e0zs+e4Z+naRQH/5078dM6mnt6ipcvskl9d5Zatn9T45X/8xFq1bJEZWyFe46eXs6gZr34j0v0ExIaNrhb18/2Ot8N7dHeBUC6aX28RnfvyK/bO2nVun9WbY48+qpcLJsNgvBj6TT39sLq2WzFU03fCCScU1dQzpGf89MPwerGL5q+O504BAACw7ygp8AOqk5p63vfnh+3mO+5S9G0X/+C7dtbpX9kjqEkK/IZ/69ySg6eaVuyhVJXaOS2D2j0AAACUqkaaegK5KHDRz2389eln7E8P/8XunPyAq6lUbZt+2mJvrslSQFZMVxVVnR8AAAD7JgI/1Co1ifzL40/aZf97tf321jtc81P5yhdOzvkMIgAAAICqIfBDrdr03hab/9rrmb4KXx14qp3x5S8W/aPpAAAAAErDM36oVXquTz9gr9/l05tK9dIa/a5goSaMmn72Cy/ZBx9+YEf07GHH9j6SF5wAAAAARSLwAwAAAICUo6knAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkXP3LI5nPBU2bNs2uvvpqmzp1quteeukl69WrlzVr1iwzBUqxdetWu/POO61Tp051ogyXLFlijzzyiB155JFWv379zNCPKb8333yztW3b1lq3bp0ZuneqK+uyZs0au+aaa2zmzJmf6LFUaNvXNToXPf/88wXzW8wxprQWLVpkhx9+eGbIJ2PXrl127733WtOmTfea42v27Nk2b968nGWn/XvChAl26KGH1sq+HR7XBx54oCvPG2+8MXvN2rx5c6V9Rtt+w4YN1rlzZ9cfF7/mxeeX+DRvvPGG9enTxxo2bOiOq7vuuivbX93q2jVkX7U3nWeKsS/dC+SyLx1bhba3zvNPPfVUwettdSvm+lHoHF5TwmtfbV/nqqrkGr9hw4bZ+PHjXTdo0CC777773AGSJlqf2267zW1MfEw3pBdffLH16NEjM6Ru0gGpk0E+dWFddKP/xBNP2HnnnWeXXXaZtW/fPjNm71NMmVcXHZcbN250n9evX+/+VsXgwYNdh+qnffonP/lJlfftYs/JM2bMsH79+lU6rkeNGuWuVzfccIPrnzt3rvubj47NSZMmuf1M8/lrXs+ePe3KK6/cIx/hdVHLVj5En5Uf34+aV5vnolKk6TxTnddPbSttM9RdOoedf/751qBBg8yQ2lFd14+atrfk06tSU099i9mkSRPbsmVLZgiAYu3cudO2b9/ON/UlWrZsmbsBVzdnzpzMUOzrFIytWrXKXZeS6KZF+8zatWszQ3LzweHQoUMr3ezoBkhfeObb71Rzr4BRwaN069bN5SttX5ACAPY+JTX1VDMFBXq+SlUXtldeecWOOOKI7M2rvrm54oor9mjy4qvNW7Ro4Zq+TJw4cY+moppX3YsvvmgPPfRQdlyuNEXfFvlmNmEzHN9syjfz2W+//bJNLHy19qZNm+w3v/lNpfG6edA3vAsXLrQnn3wym+aOHTtc0wblW9O3a9cusWo5vtx4fkPx8lMZhcsI18fnWdvguuuus6OOOso1sdDwSy65JDu91klp+nXNVw5xqi5fuXKlHXDAAXbppZfukQeflm+Klq8cvXDbqfP59mlp3juj/ULLVVmpPyxXbd9czWOS9ovHH3/cpfvaa69ll+ebfIXL0g3g5MmTs+uitFRtr2X5/Sm+jQuVdVy87MP9Pdd+Fjaj8MeM/qp8fdnmKlO/PXw6WkbY/MCnl9R0pdC213aIN6fw20ZdvMyVn/j+HJan8qYmrnfffXeleQpRmaqJ5zHHHGMtW7a0F154wR0/uZrRaXptI61zvvOOb7Lhy0jrfOutt7r8xY/hXOXvx6nz57BGjRrt0URG2ymp+d9HH31k8+fPd2Wk9OL7T5iPpONHy1Aa4Txdu3Z1f8NtHu7HhZrr59uH5a233rJt27a5fcOXSXgOSNrnwvKLl218edoHVRY33XRT3mNFVHYa1rt3b9cfL0/l5a9//audeuqp2bxo3w2vaaI8PP3009a/f3/XlC1OgWC434VpaN7HHnus0rw6pl5//XW3v+bax+PHQ3isxPe3cJyWF15D4sdpvPyVVnie8+Wv/dUvI0y/mOMhLmkbJu2bYTrlLCfp2v/oo4+6ZRQ6F8XTjh+3xdx7hPx2qM7zTHicqovvE2F+SznPeOG6xdMv9V5ACp1Xwu2lddU+e//999v06dPdevh56tWrV9S9VlzS/qAveZTP8BoRbgcvnjeVmWib6p612H0yXqbxa0Mx+5KE0+p8quPVH9cq56R7wVzL9ttK5y2VtT/+wrz57f3ee+8l3sv5ZYb7V1KZaX2StoOfJ4mmD89Z4oe1atUq7/VD6Uvz5s2z88eP9fj+Ey+nQvtXrvOZvszTtS88nuPnWa1DuB1z7XPFlFO12l2CKIO7Z82alemr6FfnaVx0otm9c+fObL8fv2XLlt3RTuo6fZbFixdX6tf0Y8aM2b169WrXL/nS1PzhuOXLl7vP6jRc04rv1/Siv8OHD8+O1/K0XD9e+YkO9Er5CNdd6WlZSTRPdAJzn+P5iIsvR8sP86CyiefZ94s+h+Xn18OXT6FyiPPLCLepPsfT8/P76XOVo6afOXOm+yuaTvOr36fl+0Xzhf1J28HTMI0L191/1nLCdUhalh/m86p5wvLV33BfVH++so7z6Yfj42nkWz/ReE0fX5dcZRpPz6+T/oqG/+lPf8rOG1Le8m17jQ/LL2lZ4bw+75rP9/vplUZY9hqXqwziwnWIp5PE5yMsd00f9od599P7dfXL8OPVn6v8fX+43yi9+DZWWn6bhPyy/PponlznEt8fLjs+jWhZ+fZj9YdphHx64XZNKrtwH4vnIb7+Gh4uT/1h2cbzr/XX8KRyjIuXq09P+fNdOF6StkWhZcXHK41wGWF5eUnL8ZTOtddem01P6S9YsMB91jxheeuv+v0+kpSXcDnx8RqnPPr5fd79PPHt65fnt5kv06R1lHzbUHnItT+Xupz4fuuv/aI0w/l82mGe9DmcX/3hcSJJ0+TKj19GWHZJx4qfv5j11XkmX1rlnmdEw8P0fH78fqG/8X1Zn32/z284fZie+sOyC+cV7d9+Wg0P8xn2a/5c91qh+PL8/qDyULn4ZYnSDvOSK2++TPJto5DG57o2xPOh/jBPoXA+8dvCl4nv118v37LV6XO4v+hveM6JL0PDNb1fhv6GecpVZvHpwuMyl/g8WrYvK3Xx81c4bTzfmj7cj5Pmz7ffx2k5Wp5PX/z5TMN8GSQtJ8xXPJ1yyqk6ldzUU1H0iBEjXKdvZ3ybdUXF0cq4bzp90xh9A6AmL4qGRd+Knn322e5bItG30W3atLGosFy/9O3bN9tOtpg0161b55rMSZcuXdx0eu5HTeg0rWiY0tA3xt6AAQPcskTL0+dCTYD8eKWnZSVRWscee6z7rOmKbVokai/v28yrjPQ5nFd5Vpl5Wh81PfLlqWWrGZJXTDnEaRlhGscff3zeZkr5ylHLO+mkk9xfUZMn5cdvLwm3rV+36CBwf7VfNG7cOPutVJzyFB1w7rOW7cshl3BZSYYMGZItf+Wle/fu2fQLlXWcL/tTTjklMyR5fy9Ex4y2gZevTJW3jh07ZvOsb+8uuOCC7PZQE0l9s5WrDPJt+1K3jcZrXf18ytvRRx/t8uD5fGmcyrMYamLn10Gdjq98+7MUc94JafqBAwdml6H9xjfdU3+hfTo8h/n19k0DVZYqU81XiNIodC4J9+n48S7a/7RPePH9WGWh2oKkZyWL3Yd13ChN8eWl87bKK1TofO73LX8+Ea2/n7YYSTV0/hk/dSo/fdNa3cJn/JQHPR8Yrr+Gxbedp31DZRLuM/r215eXrrF+e+mvyrrQPp9PeJ7TNVw1pH6f6dChg9v//TlE8h0Pcfm2YaH9uZTlSNK1P4k/F4V50vpq3w73+/C4LbSvJqnO84zoPOPTStou5Z5nit2vSrkXyHdeUW225gvPI9q//bRJ/H6hcsl1rxVX7P4QKpS3UvZJjc93bVC5FbpfSdrvdKzqmA3F7wULLVv0LgG/v+ivjr/wepzvXi5UqMxK3Q7at8NjUXnSNStePsWUTb77jmL3+1BVrkmFrovl7K/VpeyXu+hiqguoPwloBbQiY8eOzQaGI0eOtKVLl1Y6WYW0omr+kkuhNLXRtRE1TNWp2iFF49QcTMP9fEoj30WkEB/gKq34RT1O5eKXq0C5WEpTaft5p0yZkhmzJ02r9Um60fGqoxxUba0b/HKpiYBf9ujRo13VeC7aH8Ibef0ND/KQTkznnHOO3XLLLS5tLaemFFPWcSp7lVvYlMPv77luAIuVr0yVR5Wbjsv3338/e7Pim3IUE3B44bYvZduI1nHmzJl20UUXZfOqY0HDNY+endJJUMOLvRHXOmndwy+f9FnPY/ljvxh+O5SrlH1aVOb+hkkXJl3U/AW4kFLOJUn7XMjvx2H5afuo+Y/mjSt3H9Z+o5u+uELnc6WptHPtU9VBNysqA3/dSqL11XonlYn44b7pUZxuEnIF03H5zi0qL90QxZejaTVPsefwfJS2mifl2mdKVWgblnttjMt17U+SlKdC27ic+5m4qp5ntE5aN79snUPyKfY8U+5+pen99SBU6LyiLt95Ka6Uey2vlP0hVGreCsl1bSj2fiXXtilGqdelUu5nQvnKrJztEA/OdJ8SftntFVM2OtZz3XeUs99X5zVJy/XXxXL31+pS9stdlHF1/m1l2gl0ARkzZkz2m091+d5W6E8YuRSTpvKgYcOHD3ftcFWAKmB9UxW+jU1dVd9KpA2ldHQDPHny5MQdRRc27Uh+mQqUi6G0lKZupv288W95kmjHDIX91VEOOsh1sJRDJ6JZs2Zll6/tqG/Q8vEXL21H7Rv6NigX7QPaF8aNG+fKPdfJtLrkK+s4lb3KTSebuHJPuFKoTH35KajSctRGXicufXOl51TjJ7184tu+lG2jZWv/Dfc7df6irv1P+6GGSTHBn/82L74/60Y7/OaykELnnXzK2adVK6oLpfKvgFm1LMUo51wSfoso2oY+yPE3omENmO90Ho0rdx/WMrWvxRU6nyvNXBfgYuU7JqWY85nKKfySIy7XN9KeyktftMQllZnfJkn5Vnlpv1Ge46rrZqS65duG5V4bc0m69ifJlSfdhOU6H5ZzPxNXlfOM1uXhhx92N4Zarq5xYc19kmLPM+XuV7mOnULnlXznkVyKudeKK3Z/CJWTt1wKXRuKvV9RwBZum2L2o3KuS4XOlbkUKrNytoPuLRTwad+VpJZESfttvGx0rOe67yhnv893PiuVlhteF8spp+pSpbd66ttT7XDqVGhqgqXX0+cqJO3Q4dvQ/JvTwirrUKE09fCkLyztjP5CrJ1GBVzMa7uLoWXrYX+fB+0MSTReO4kfr37dgBdDB5EOJn8h8rUbuahsdFLUQ6T+xk5lEa5zOeWgb0t89bbyr7LXtzG5bnLy0YklPKB0w1ToWyidHHWBU22n1i/Xcv1+JzqgFRDUlGLKOs5fhMPXuPs85wuYCilUplqugr3nnnvOnUxFNwDq13z5tmOhbV/sthGtY7iNQipDHU9eeDzpgpgrCNTNjJbr193T+oVNKOJKPe/kU84+rWn1hc7UqVPd8VjMcss5l/j9Si8k8LTe/gF4UVmpfP1+nE+x+7DK05+Hla7ST6oNVn++87nSVOAaHlc6x+farnEqq0I3MyqPfEGbpy8TVP7xfVHnAHVhM6c4lb/KTeUnftvlum5om6h2JCzDV1991ZWX9vdwe/nyzXVTr2WEx4K2XaGaouqUaxvqGCn32pgk17U/SVKe9FnHot9GcYX21STVeZ7RTaL2IV3bRDfEhbZjseeZYverUu4F8p1Xks4j2r+TptVyct1r6byTqwYw1/6gz9ouPqDQNDrWvFLyVki+a0N4Lcx3v6J8KyBQEOfXU9tA2yKfYq5LYZo+P76JdynylVmu7ZBv24k/DnWf4h/liNMwrWO+stGxHpZ1qNj9PlSVa5LmCc/pWo6/LpZbTtWlSoGfMqtIWm870kqoPas2TFjNqpX19A2E3r7jx+kCeuaZZyZuZC9fmiowVWlrmL4Z09vadHOq9JSu0vfzqEvaGZJovXSCU9raCKKbJ58HLT8p3+rXhvXNQ/R7T0lNnpKEy9S8ehtjoWBGZaOThNZd8+jEHN6QlFMOauf90ksvuem0vip73065VDqpaFl+ufpGp9C3UKKDUCdqH7gk0bbXfufzqQNaZSHhcovd5oUUKus4lb2aM+pmx6+/9psLL7wwe5CXo1CZark6cWqYP5mqrFSeuU5uXjHbPte2iZe51lHPu/htpM43adCFTydsP1w3gPmelxTNp+mS9gl/cvY3KXHlnHdyKXefVh71trpcF7U4TVPqucSXuW5sfP60vLCmQPuwtqnfj9XlutAUuw/r7XA6HjRe6fpjJYnG5TqfK02lHZ6vVL7Kh8aF5+Sk/Grf0M1x/KYtbK6ndYnva2ETNXVavpapGmkJx2kf/Nd//ddK6y9hGvH9y38zrn0gicpKz9+E1zJ/w6/yCreX/uqam6t8/bMovnzj27+m5dqGOkbKvTYmyXXtl6RzUTxP2o7xn+qIy7evJqnO84wP2vyydbNbzHYs9jxTzH5Vyr1AvvOK8hE/j+im2O/jatanc5auD2oeneteS8FN0hd/kmt/0LbXevn9LukeKV/eSpHv2pDvfiXOn598GegLz0Ktv4q5Lmmf0nGn8cpL+DxqKfKVWa7tkG/biYZrn9VborUuuWhbhsdkvGy0PrnuO6SY/T6U63yWaz1C+a6L5ZZTdamnN7xkPtcoXYzvueceO+OMM7InaFQ/nSj1LVmuE/TeQCcwXegKXZg/aWko61LtLdumrvmkzn+64KnJ2LnnnlvWRb6qanv5dfGY1E2DLui6wQBqUm2dZ2r7fKYAUsGhgrZP4jz2SdK6T848BpQrQMmnqvNX1b647co559dmOVWpxg91i27K9c1Lvpqyuk4XFN286SRVlwOLNJR1qfaWbVMXqVmMvrGvzaBPFxJ941hM08aaoiZHtbl8XTR10dXxWRcoH8pPWMsA1JTaOs+o1UfYnLmm6Xqjm+h9LegT3WeoRUuuFgN13b687UpRm+VEjd9eTDcVasLgqapcD4rureWroELPj+mh/7pWi5a2si5VXd42dZnfb9RsqqZrSf03u+EzD2oG80nUNCnYUfNH/VRAvGkogOpVW+cZv5x97fpXm/y506vqOfSTrvHbF5VT41ebai3wAwAAAAB8MmjqCQAAAAApR+AHAAAAAClH4AcAAAAAKUfgBwAAAAApR+AHAAAAAClH4AcAAAAAKUfgBwAAAAApR+AHAAAAAClXcuA3bdo0GzFihPurX6efNGmS7dq1y3X6vGTJksyUdd+aNWvstttus61bt2aGFObXGwAAAAD2FiUFfgrqNm7caDfccIMNHjzY+vXrZ+eff741aNAgMwX2ZgpoFdgCAAAASJeSAr+1a9day5YtCfQAAAAAYC9Sb3ck8zkv1QRNmTIl02c2atQo93fWrFk2dOhQ93ny5MnWv39/69Gjh+tXDeHYsWPd586dO9vw4cOtffv2rl+1SxMnTnSfe/fubRdeeKE1bdrU9eeiJpkTJkyw+fPnu/4BAwa4ZSsQ1bKUl65du9pdd93lxg8ZMsTVTHrx+S+44AJ77bXX7Nxzz8257DCfWl6jRo3cuqi2U8J1lPgyJSw7v65btmyxhx9+uNKytSwF15pfeb3nnnvshBNOcPOuXLnShg0bZn369MmuQ1K55SrXpPTC8UnbV9sxHB6WNwAAAIC9R9GBn4SBifhgKynw0zgFDT6wCKddv359paBHz9o1a9asUgCTRGmI0vdBnPLil6cATMGRgjKlecstt9h5552XOL2eSVR+161bt0fw5Gl9Fy9eXCm4DJeh/rvvvjsb0Po0e/bsmQ0MVQbiy+zVV191wWkxgZ/y26ZNm2yZaX1atGjh8tuwYcM9lhXPb770RPOrBtfnLd/2VXorVqywDh06EPgBAAAAe5kae6vnwoULXUDigxoFO6otUwAjCkQU/IiCpkJBnyhgUyeaXp8VqHiqkerbt6/7rDT12Y9fvXq1C3qUD1HwMnDgQGvSpInrj1MQpyBKgawPdLQ81eh5WsdBgwZlazE1nabXfJpfweeqVavslFNOcePlyCOPLGpdRXlTHpVu69atrXv37tky1TAFfX79kvKr2kE9k6myljA9n1eN17y5KDDeuXOn+9ylS5ds2gAAAAD2HjUS+CmQUEChJod6A6i6iy66yKZPn+6CPQVK55xzjqvB0jhfk1eI0tWbQ32aYdPEQhQglfJ8ooKd7du3u5rIJH4d27ZtmxlSQdNrPs2vdW3cuLGrnasq5Vv5jy/P0/IUpKlG0pfPyJEjbenSpdkAu1QKdFX7p3SuuOIKF8gCAAAA2PvUSODngxQ9JzZ+/PhKna+xU/B32WWX2bhx41xzyELBnwItNU1ULZVPK6x9K0QBU7x2SwHRtm3bMn2VKVhT0BYGTT7YE7+OYY2j16pVKzd/GATWNC2vU6dONmbMmErlrTL2NZLl0PZSOmrOeu+99xL8AQAAAHuhGmvq2atXLxfQ+WaGIQV5PtBTwKImmOJr9JKCwHgNnNIttqZQNJ9qv5YvX+76tSw9v5aLD+w0jQ8WNe/MmTPdZ9E6qhbTB0Oa7oknnnAvf9H8ap6p4HHGjBluvOgZP+Vd+VHQqSaoojSUVrm0PC1Xy/f5rap58+Zl10359U1UNey6664jCAQAAAD2EjUW+KmmSM+jqZmgb3rof+xdQYReiqJhagKqZ9U0va8Z0wtE4hR0HH300TZ69Gg3n39RSbFU66VaK7/cK6+80j0Dl+sZP1EzRwV/yqPm0TN9YS2j8qyXx/g8+XXxL1tRMKYXo6iWUOPVzZ071wW7Wh+l75tmKmALnwUsh5Yb5ledf7lMMVQeCqY1n/5qO/l103Y89dRTq1R7CAAAAOCTUdJbPWuagg01nfSBEwAAAACg6upU4AcAAAAAqH411tQTAAAAAFA3EPgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAytXbHcl8Ltrs2bNt4sSJ7vOwYcOsX79+7rMXjh81apT16NHDfd61a5dNnjzZZs6cWWl4OL3n012yZImNHTvWBgwYYEOHDrUGDRpkptiTnzaUlL/atHXrVpswYYJt2rTJhg8fbu3bt7dp06bZlClTPvG8AQAAANg3lFzjp+Bt8eLFmT5znzUsl1mzZuUdnxT0lUrpT5o0aY+gDwAAAABQRuC3fPlyV2OnGrjevXvb0qVLbf369Zmxe9K0c+fOzfRVFgaRqv0aP36868aMGWONGjVyw4uh9LUcUU1iuenUlsGDB7v8UdsHAAAAoDaUHPgtXLjQ/e3Zs6drqrly5UpbtmyZGxbng8Pp06fbmjVrMkOTqeZPzSJFzSGPPfZY97kQzaN5RcGjbz4q8XQ03YgRI7Kdagl9baTSuf766+2KK65wTUb1WdOoWaavUVS/xofrovEarrT9Z3VKI5dwHonnK1xGrnzpry8vCfMYT0Pz+eHq/HIBAAAA7BtKCvwUaCiI6Ny5s3Xr1s169erlhudq7tmyZUtXu6Xg8IknnrCdO3dmxlTQ83r9+/d3n+fPn28jR47cI6ApZMuWLe75OZ+nXBRsxZuUqpZQzxyGeVde1WRU+RE9i3fHHXdkaxQ1fs6cOe5zSGlrWu/uu+8uGOx6a9euzXyqoGXcd999lcohni/9feWVV9xnTXfTTTdl8xhSkBdvAqu85gtMAQAAAKRLSYHf6tWrXcDRvXt3a926tXXo0KFgc8+uXbu6mj8FJWomGqcaunHjxrl0xAeA1RmY+IBVfFNQv8ykfGmaG264weVbDj74YDePahRl48aNewS6Q4YMcdP4+RSo5aoJjfNNP8N8KZhVUBvyedeyxAeMCgBVbppP82uayy67zG0j35TWz6u/4mtuAQAAAKRfSYGfDxYULF100UUuQFPAkS/IUa3ewIEDXY3cn/70pz1qt6Rp06Z28cUXVwq2Cr0UxmvWrJm1aNEibx58raACIwWr0rBhQ2vTpo37HFI+labyrRpLadu2baW/Sfy4cL5ihU1EfZnG+XyJX5YPQH2Z6plBlaWnGtZ169a5z6r1U/q8AAcAAADY9xQd+IW1Zknyvd1Tz9oNGjTIBWcLFizIDK14Lk1Bj2/SqKBJzw6WQoGOf64v3oRRTS3nzZuXDQ4VUKnWUsKgqDr44Cssp3yBoqc86uU0vsZQL6RRkFcKv5xwG6xYscLeeecd91l8jZ/vVMsIAAAAYN9QdODnm3mGzQnDQKXQ2z379u2brc0LqdZKtVy+xss/h6cAUIFgMU455RSXL/E1W+pGjx5tO3bsqBQc+vG+Zk15UnPUqtLzfWG6Ye1iMfz8yrMC5FLo2UZtA18Tq3T0XGKTJk2ybw4Ny6XU5ygBAAAA7N2KDvzU9FIUQIXNCfUcmZ75U7CS9NITL2zy6eVqFqln6Ur5qQPfVNQ/+xbytWGq4VK6IU1//vnnFx1g5nPBBRdkA1ut49lnn12pnHJRbaiCYtF8qpnzQWyxlIYCznA+1XCqplPlGF9vAAAAAPuWersjmc8og5qqqrau1GAVAAAAAGpLSS93AQAAAADsfQj8AAAAACDlaOoJAAAAAClHjR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKRcvd2RzOeCpk2bZlOmTMn0mfXu3dsuvPBCa9q0qetfsmSJzZo1y4YOHWoNGjRww0KzZ8+2iRMnZvr2nF/WrFljt9xyi61cuTIzxGzYsGHWr1+/TF9lmv7ee++1c845x9q3b58ZWrxdu3bZ5MmTrWXLljZ48ODM0Ao+L3379t1jnNZl7dq1lYbH1y/Mt8qubdu2Oddj69atNmHCBJs/f77rTyqbePkPGDBgj7IutA08TTd27NhMn9moUaOsR48emb498xMf72mdJdd6Kc+9evVKnLcu8vtD//79XZ61fosXLy5YngAAAEBdVnLgFwYv6hcf/OQLOjStxscDRQUfYVChYOvhhx+2c889101X1cCuEJ9nOfPMM/cIQhVobdu2bY/lxwO/eFkogFiwYIEde+yxrj9edqGkdVyxYoU1bNjQ9ftgRMKyVR6mT59uw4cPz86Xbxt4Sk/TKLjRNPHl++X17NnT5Tcpf2FgmBSYax4fwOcKGuuieOBXnVRm99xzj51xxhnZcgQAAABqQ5WaeqomZ+PGje5mOR8FI/GgT3RjraBAQUiuNFq3bu0Cpi1btmSGVK+FCxe6m3zV+L3yyiuZoR+rV6+eq3174okncuZRw1UOKg9PAZUP+grRumkdta5ely5dssHB3Llz3d94MKdga9CgQTZnzpzMkOIojZNOOimblpajIG/ZsmWuf/369bZ9+3br06eP64+P90GfgtwhQ4a4YSEfKH73u991tZIAAAAAPlllB34KdsJao3wUXClICYM+r0OHDi7IULCRZPny5e5v165d3d84BSG33XabCzZEf6+44gobMWKE6xRw5qJ5FbApDwra1KQvKbj79Kc/7f76ACxO66/AUetZjmbNmrnaw6QyUH6Ur1zl3K1bN1u1apVbl3xULtddd122nEI+cFXwKQrwOnbsWGl7heWj4RdffHHOGjEFij/5yU9cuRZLNaJ+m11//fXZ9dFf9SeNE9V6al4/vx+v4X4effa0P0yaNMleffXV7Hj1J2138dP78er388XTjuclHK9yHzdunD3//PM2evTovMsEAAAAqlvJgZ+eYdMN7UUXXeSCnULN4eJBRZyaMzZu3LhSjZ4CmZEjR7rl3H333TZw4MCCwaVoWaqZO++882z8+PHuRltBVS6rV69266BAJl8AqjwqDwp0kwInUc2b1lN5zhdsJlGgdPrppycGBDt37nT5yrUefnhVakQVXK9bt66kQK06KVASbTN1X/ziF12/AjjVLOpLAz9Onx988MFKZaTmuApMNV77o/YdUb9qlBV8hcHizJkzbenSpdk0tQ+oyWwx3n77bbdf5Uo7zIvGK13tM9rGytcJJ5xgY8aMsfPPP7+ofRoAAACoDiUHfnqey98wK5iriZoL1Tb5m2vdLN93330lBVOqPRMFdLrhTqI8K5DzzTM1rZbrmzPGKR3VuuVqVqmbeN3MK98KZOI1U4UoYNH6qkmlguqwJqk6+Fq4eHmoXBVcn3322ZVq+GqLgiIF+qecckpmiNmRRx7p8qLAvE2bNu7lOp6an8YDdDU39V9AaHuqaa5vpqpgtkmTJpUCYzU/VaDuHX/88UXVmoqayPpySko7zItqqbt3716loBwAAACoDlV6xk835I0aNcrZTFN8M0gfjMUVqtHSTbaeJSumGaWWpefg1CRRNW++JimJ8qxaH71cRtOqU21NvAYnpGBCgVK+IFT5VTPIpJqpYmg+BY/Kh5aTVCMa8sPz1WzmovJR8PuLX/wiZ4Ac0nas7loq5V/rp/WM0z4TX2ah8lA5dOrUKTG9XDSP0iyGAlXflFhfSihgBAAAAOq6KgV+Cto2bNiQ6cstfD4sTrU6uukOX2wSlytoTOJr3lR7JrmCP9XsKXD1tZfqbrjhBlfDpDwl8UGo0nzvvfcyQ5Pp2TsFtCqjUmk5qjXSemt9VAuY6wU4Sc/jFUProBrbpCaHGq5mq+HyFHjnaq5bFQq6cpVTUj5EXzaUE+jmoiBSeShEQZ/eOKuAT/uLAnSVPQAAAFDXVSnw01swCwVtoiBGNTd6TX54E++bGeZ7hk+1b6r98k0y89G0Tz/9dKavInBIojwoEI2n6YOsfLWLWhd1f/zjHzNDKtLTcsN1U0CWqyYrLl6LqPVQv8+/b+oYLz+Vi7qwmWQuClr8y11880rfHDLOv0jHv8xG06u8FMxWN+07KqcZM2Zkhph78YrKQE0p9exh+FIdfd6xY0fBfS4fPePnXxqk8tRzoUcffXTB4DleO6kvCKpS46dlq6m0tiEAAABQk8p+uYs63bDqt+/CoE031XpGzU/jnwFUTZl/fs2PU62Tak/izQx1M63hmkZ/1fzRPzeVj27IdUPv01ewEj7L5eV7mYmCG82nYCcXBVp6jszT+m/evLnSuimNfL+lF1LtlQJgP6/WWeXl11lpqGZOwXO4DG0L1VDGg8tc2yAUlnF8Oi1P21XbV8P1e3w19TuKWpbKyb8YR52CO62TAjH9BIjPh7pSyjUXPeP30ksvufRUTipX7WOF+IDYl61qYUup8dP6KMDkrZ4AAACobSX9gDvqFgUOqgVUoKdANP47idiTalIVsFU1eAQAAAD2JgR+2KcQ+AEAAGBfVKVn/AAAAAAAdR81fgAAAACQctT4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDKEfgBAAAAQMoR+AEAAABAyhH4AQAAAEDK1dsdyXwuaOvWrTZhwgSbP39+ZohZ79697cILL7SmTZtmhgAAAAAA6pKia/ySgr7qpmVcf/31rtNnAAAAAEDVFR34rV692gV9quEbN26cjR8/3nXHHXdcZoqq27Jli23atCnTBwAAAACoDvUvj2Q+57VhwwZ75pln7N1337VOnTpZ586d3fBDDjnEdu3aZTfffLNNnDjRjjrqKGvdurUbdu+999qNN97ohi1atMiuuOIK22+//Vxa+jx16lRr166dS2vJkiX2q1/9yjZv3uyW8dhjj7lxrVq1yqat6dUpjcMPP9zWrFlj11xzjd19993ZdGbPnu3SfuONN6xPnz7WsGFDl08AAAAA2FcVXePXtWtXGzBggPusIGzEiBEuyBI939evXz/3eeHChe7v+vXrbenSpW4ezetNmTLFze8pjXzNOpNqAZWG5mvfvr2dd955bpj6FQjqrwLAs88+m+cOAQAAACBSdI1f/fr17ZhjjnE1ay+++KIbpr+qoTvyyCPtgAMOcLV627ZtczVtr7/+uj311FN22mmnucDvrbfectMrEPzP//xP69+/v5v+/ffft6OPPtq6dOliJ554ohumz5dccokdeuih1qxZMzv55JPtjDPOcJ1fvqZRrZ9qF1UD+Pe//92efPJJV1v4jW98w4444giXRwAAAADY15X8cw6q2dOzfaNGjXL9M2fOtOXLl7vat759+7rnANW/ePFiV/PWrVs3N53XsmVLa9CggQvoWrRoYStXrnS1ermoFk9NN1XDqC6sLfSOP/74bNNTPYOowBMAAAAAUKHowE/P4PmmndKhQwcXZIV8ADZ9+nTXzFOBoALCqpgzZ477O2bMGBdwDhkyxPWHNI0CSFHgOWPGDPcZAAAAAFBijZ9/tk/dyJEjs2/5VBAoanbZvXt3W7BggQvEevXq5YaXSukqfR9oKq3Ro0e75er5vpCm0TA1Ib300ktd4Dl37lxXUwgAAAAAKCHwU9NM35zSi/94u5pw6tk9ib/UpRi+uWgobMap2r5hw4a5z6JaSN/0U8vVc3+DBg1ygeJ9993HbwECAAAAQKTe7kjmc5XpJxwmT57snvtTgObf9AkAAAAA+ORUS+AXBnwSrwkEAAAAAHxySn6rZyEEfQAAAABQt1RrU08AAAAAQN1T7TV+AAAAAIC6hcAPAAAAAFKOwA8AAAAAUo7ADwAAAABSjsAPAAAAAFKOwA8AAAAAUo7ADwAAAABSjsAPAAAAAFKOwA8AAAAAUo7ADwAAAABSjsAPAAAAAFKOwA8AAAAAUo7ADwAAAABSjsAPAAAAAFKOwA8AAAAAUo7ADwAAAABSjsAPAAAAAFKOwA8AAAAAUo7ADwAAAABSrt7uSOZzXrs+LGoyAAAAAEAd0aB+PfeXGj8AAAAASDkCPwAAAABIOQI/AAAAAEg5Aj8AAAAASDkCPwAAAABIOQI/AAAAAEg5Aj8AAAAASDkCPwAAAABIOQI/AAAAAEg5Aj8AAAAASDkCPwAAAABIOQI/AAAAAEi5ersjmc957fqwqMmy1m/caD+5ZLRd/IML7YS+x2aG5uanX77yrcyQCv/vf0Zn5x/3u1vsoUcec589jW/VqoWNvPR/7MjDe9r//PxntnLVate/afNm69q5k/3PL35mv7zy6mzaF/9gmJ01ZLD7vGPHDvvlVVfbrDlzXb+0aN7cxv3ql9bz0G72/Nx59h+/HOPSue5/x1iTRo2y04fpJFn8xrJsPqT/8X1d/hpFaUh8ncP0ksrD56F1y5auP573Cy841/394ikn2ajLf71HWcbnzyfMe1J5hJLSvX/KNLv+1omZvgq/HDXSbr/7vrz5iq+TymRbNOxz/Y6vtA1D4T5SiNKf/NBUG/q107PbIZ+k/UP8tiq0jSVpnTRvMft8IX75l/3sp0XPAwAAgH1Hg/r13N8aC/wUIEgpN6O6EZ42/a/2raFnZfuvuu5G+/lPflwpqHjkib/ZYT26u0DE8wFJeNP8h8n32+BBp2Xn1U3yvFcW2NZt2yrd+MeDAU13z/0P2n9e9EPXr7SXr1yZDco0ftGSpfaVgV9w/YUk5TeUK1/x8lA+np4120b+aHg2mPjGGadn11eB8Zp333WBh4KlcF5N/7uJd9p3zxtaMPBTfi6/apxd/vORLs/Kx2W/Hmv/Hi3XB3/ilxvmKy5pm+bKlw+q4+v04suvuOD9wWmP2Y+GfdsF9r78FWB27dy56P0svq2LEZ9H/f93w8127llnZrdprm2sabVOJx73qez+o3U6JAp2ffBXzD6fT6n7IwAAAPYdPvCr80092x90kAsIiqEar1cXLXI320memPG0HdvnKDuoTWsXPOSim/duXbu44EkUVLy7br27wdaN+a13TrJ+x/d146pDsfk6+qgjrG00jdZP053yuc9UCngUeF31y//eI6BRAKx10fhiggnlxwd9onkU9Gl4LgpkShXPV651+sNN11v3Qw5xn+PrpuCp2KCvOjVt0sRatypcli8veK1S0CcKXt9c+Zbbl5KUss8DAAAAxahzgd/0J5+yk884y3Xf/fG/25CvDCq6ZqZp48Z25GGHuRqUON1kb9u+3Tp37OBqZvIFMarBenftukpB0tB/OcMFfDfedof94NvnF10bU0gp+dJ6aR1VHhs2bLK2rdtkxiTzZam/xVJQqfzEgxrlr0mTxtmgWrWrfjv96eGprma1WLnyVcw6fVLmL3zNvvTN812+9fek/v2K2gdUU6wayZC2n5olr99QEfhVZZ/33lyxZxNYAAAAwKuRwE/N7xQMqIaqVINOPdmeevh+191x4zX2P2PHZZsWFkPLTKpNWbL0TXezrhtq1WQ1bdqk0jThjb3yrlqZkG7y1QTxqMMP26M5X1UUylcYFGi9wpojTzWRQ87/XnY6X16+LPW3uqlJrd9OKpcf/Psol28tW9s/n5rMV03p3esIe+yPk1y+9Vf7SKH1LFZV93ntNwrW1YQUAAAASFIjgZ+CEwUDauZWFQq29EKQtevXZYYUpgBKNSaT//xwZkgFPYMW1lLd9oe7XdDlhTf2ampX1bzno+fBFKxJoXz5oEB50zOAfj5RbZLoxn/KpNvtz3+YYF/7ypf2CLj1/FixNZQqvyaNG2drozw1w9y2bXtiTZSaWp531pl7zFNIPF96SU8p2/qTojLQM3i+KXASv41V2+e3k6da01dfX5zYVLScfV7L0TZTU1gAAAAgSZ1/xm/ey/NLbv7na+ReeXWh+6uaqIPatsnWqqhTkLRw8WI3Pk61fY/+7clKQVZNKCVfCjZ+/P3vuuammi9XzWY+qqEqpiZp4CknuZe7+PXXMq753S1ueJIwkFHwtuD1j5+zvOPuyQWfV/P50nZTOmEeteyf/8+vS1rP2qDgvJjn8LSdnnvxpUq1g3qZjZ6JzBWMl7PPH9Kl9GcsAQAAsO+oM2/11I190qvtVYPlazIK/ZyDXqnvX6ev2hi9HfHsfxnigphwnGqv/PQnHFeRv+dfnLfHzxZccfW1rl8BTZi3cLp8FDiFr/r3NP9Pf/gDu/bmW3Pmq++xR9u769bZipVvV/q5AwUQD0ZloH7VsIXp+3zF8xsq9qcCwrwX+jkHCdMNpwm3X65tLH5+BYzhTx+Ey06av9j18ZR+dfycQ9I2C4X5jqdR6OccwjIrhrYVb/UEAABAkhr/OQcfOHzn7G8kPpcGfBJKDfzqOh1n4U9vAAAAAKEaD/yAuihtgR8AAACQD4EfAAAAAKTcXvMD7gAAAACAqiHwAwAAAICUI/ADAAAAgJQj8AMAAACAlCPwAwAAAICUI/ADAAAAgJQj8AMAAACAlKt/eSTzOa+PavFn/NZv3GjD/32UXTf+NuvTq5d16tghM6Z4v//7K7Zl+y7r2rZ5ZkjN2r7zA/vRHY/bz+550lo0OcA+1bVdZkxuyuM3f/uQ/fbxuW6eRg3q2+Cr77ex054rOg15YM7rVq+eWdsDm2SG5ObzeeMTL9pXjuluTQ5o4Ib//bW37LSr7rO1W3bYqUd2dcMK0TzL171Xchn7ZWm9p7201JpGeVj33o6i0hn3u1vsF2N+Yxs2brLPnPDpzNDi3D9lmm3dur2s/Unz/ut/XGILFy22k/qfaPvvv39mDAAAAFB31d+vjv+O36BTT7anHr7fTuh7bGZI8da+t90FF70Obp0ZUjuOO6Sd/fPX37PvfL5PZkh+mu6qs0+2h0d+3X0+pE0LO6ZLO7v9+18tOo1SNW64v/3v0AHWtU1zm/naisxQs38sXmmn9OpqF3+xb2ZIzdB2UcCrclr0fz+w6771Bbtq6uzM2MJG/mi4/fkPE+ygtm0yQ4p36oDP2dOzZtuOHTsyQ4p31pDB9tgfJ1nvXkdkhgAAAAB7j1Q29Vz49nr7/BGdrO2BjTNDClMwcvYND7nusP+81XUKUmqLgtUzr/2zC/iU95rWt1s7W7Npq1vuwlXrrEOLptaxVbPM2Jrz8sp3XOCpAFR6dWxjsy//Vq2sc+uWLd3flxe85v4CAAAA+4pUBn7T5y+zHge1yvQVZ+iJvax540b2b1883tVEPTv6Ahek1Ia1m3fYj38/3dV+1UYA5B3duZ0LkqfMXWx9uhTXrLQq1Mx0925zTTs/KSf172fLV67M9AEAAAD7htQFfgoutuzYaW2bN8oMKc7W93fZWSceXquBl7wX5fVn9/zNBZy/vP/vrvattnz60PYuSJYjO9Zus1gZ/cAz2drVH0x4zG272vDmytqryQUAAADqAt7qmbF2yzZr17xppq+iv32Lj/tryoGNGtrvR3zVBZw3fmeQ3f3swloLgNTc8sxPH2ZD+vbMDKl5qzdvc0G2jPn651zt6qVf+4xr4uqbfwIAAACoXqkL/BQ8NIuCKTWfLMWCt9ZZk4b1M30VzS/bHVjzgV9IzyT2aNfCXnhjTWZIzet7SDv3nF1t0LYZ1LubTZu3JDPkk3FI59qt1QUAAAA+aams8VNwseTdDZm+wvRil5/f95T95A9/y74R9Hu3/cWueOgfrr+m+OWeMe4B91n69ejomn76/uqm9Tn/pqk27tE59qWxf8y+3OWU39xj9zy7wC6ZPLNGaxxVs7nknU3ZJp7q1F9bTWz1Vs+unTtn+gAAAIB9Q73dkcznvHZ9WHs/5Kff8Zs2/a/2raFnZYaURsGMAhi9PbKUN3tWhYKl22e+bN8bcHStN1nU7/gd1alNrdXcef6tp7X9XGS5+4fmu+PuyfajYd+2Ro1KewZU9DMQkx+aakO/dnpZ8wMAAAC1rUH9Ov47ftOffMpOPuMse37uvMyQ4inYUzCiN1bWphfffMeO+e/ba6y2DhU/4P4v37rQ3l1b+ktwnpz5jHurZzlBm37A/UvfPN/mL+SnIAAAALD3qZM1fgAAAACAqqvzNX4AAAAAgOpB4AcAAAAAKUfgBwAAAAApR+AHAAAAAClH4AcAAAAAKUfgBwAAAAApR+BXzfQbfvyOHwAAAIC6pE4Gfus3brRv/evFZf+Aey7bd35gox94xta+tz0zpLKFq9bZ2GmzM33l+c7n+7jOUxDY7/I/uLTL9ffX3qqxYFJpH/aft9qXxv4xZ7lUN/0Iu7at/paqKvMCAAAA+6o6W+M36NST7amH77cT+h6bGVJ1W9/f5f42PaCB+xu3dvMOa9+iaaaveigI/O5JfaxtsyaZIaVb8u4G63FQq0xf9bv9+1+1x0Z909oe2DgzpGaN/NFw+/MfJthBbdtkhhSvKvMCAAAA+6p6uyOZz3nt+rCoyaqFavymTf+rfWvoWZkhxVGN3sV/+KvNWLjc9Xc/qKVN+tfTXUCj2qzzb5pqS9/d6MZJ66aN7Pcjvmq9OrZxNV/fu+0vmTEVTunV1a7/1mnus09XQVLb5o3sO+P/Yi2bNHLpK5D048/9zFE25uufc/OI8nT7zJet/2Gd7F9vf8zWb91RKV+qyfvVQ8+6dD9/RCdXI3nPswuy/X58KFxGPN/x5Rei+UXLqk3lbmOpyrwAAADAvqRB/Xrub6oCv7h4UKPmlgveWmdfP/5w1x/3wJzX7ahObVwgmETj//76WzZ/5VoXuE2bt8TVxIXpT5m72EYN7uf6xQec4oM9TXfLk/+0X3/jJGvccP89lhvvv+mvL9o3T+y1R42c0r7+8bl2yen9XDqiQDHMUyEEfgAAAEB6+cAvVS93URCj59V8d8VD/7BeB7fOjK1oytnuwNxNOdds2pq3SeZLy9+1Zo0aZptFqhlnPGDq2X7PJpld2zTPBn2igO7zh388X3y5Yb9qDBWaJzVPVeCp2sFj/vv27DqrdlBNQwEAAADAS03gp6BPtV3//PX3bNH//cCeHX2BnfnpnpVqyd55LwqomjfK9FWWL8ASjZeLv9jX/U2SFFiu3bLNvnLsoZXyoZo6BXeqpfMvVPHj1b9q07ZsPvRcYr0oSPc1eqEDoyDUr2/YhS+XAQAAAIDUBH4K6n721eOzAZKaQDbJEcSJAqyzb3go59s2FUj+YMJj2YBPOjRvkjMwlKTAUsHgI/PeyKaj5f7499Pt1KO6VvRHgWH4Qhn1f6rrQYmBnii41XOAovXzL6zxHn35jWwwWVValmoR9TdOy9CbQHO9DTTfvAAAAABqV2qe8VPwEX95i/iXpIiCOf8ilPDFLp5/sYr4F7soAAuHe5d+7TOuZk2Bo170ope2hDRefvfEi/a5wzvbwy8udv3x5SblO5xGAWP4wprw5S1Jy67Ol7soaFPTUb+uIZ9vCZuxevnmFZ7xAwAAAGrePvFyFxSWL/CrSQR+AAAAQM2r8y93mf7kU9X+A+5IplrQ2v4B93/51oX27trSf9S+KvMCAAAA+6o6WeMHAAAAAKi6VP6cAwAAAABgTwR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHL1dkcynwEAAAAAKUSNHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKRcvd2RzOeCtm7dahMmTLD58+dnhpj17t3bLrzwQmvatGlmSN22ZMkSGzt2bKbvY6NGjbIePXrYtGnTbMqUKTZs2DDr169fZiwAAAAA7L2KrvFLCvqqm5Zx/fXXu06fkdvs2bNtxIgR7i8AAAAA5FN04Ld69WoX9KmGb9y4cTZ+/HjXHXfccZkpqm7Lli22adOmTF/NGjBggN1www3Z9VBt395k7dq1mU8AAAAAkF/9yyOZz3lt2LDBnnnmGXv33XetU6dO1rlzZzf8kEMOsV27dtnNN99sEydOtKOOOspat27tht1777124403umGLFi2yK664wvbbbz+Xlj5PnTrV2rVr59JSE8xf/epXtnnzZreMxx57zI1r1apVNm1Nr05pHH744bZmzRq75ppr7O67786moxowpf3GG29Ynz59rGHDhi6fnl8P5VtBbP369TNjKiifr732mgto/Tr6NP3y/TqqVlJ5mz59upv2rrvucvlU/g499NDs+r/00kvWq1cva9asmUtPSk3Tr0+9evVcuhovL774YnbcihUr7JJLLsmmqbI88sgj91hHAAAAAPuWomv8unbt6mrJRIFI2MxQz/f55+EWLlzo/q5fv96WLl3q5tG8np6f0/ye0sjXrDOpFlBpaL727dvbeeed54apX4Gg/ipgOvvss/M+dzhz5ky76KKL3Hrka1qqZ/7C/IoCTS3LW7lypXtu0DeDVf7uuOMOtwzR+Dlz5rjPUk6a+vvKK6+4z0neeecdlwYAAAAAxBUd+DVo0MDOP/9899ITT8HLpEmTXO1et27dXMClmjsFUcuWLXPBS8+ePd28nm9iOWbMGDe9gjoFd2pq6Yf55qQKJhXcXXbZZdkmmX75vqmj5hsyZIgLjEaPHu3+Dho0yM1XVVoPrY/ypLz55Wu9tH4hvRxG6+WD44MPPrhSfjdu3OjKqdQ0NV7rJ1pnvx38MM178cUXW5MmTVy/+Pk0XVj2AAAAAPZNJf+cg4IxBRUKLkS1WsuXL3eBVt++fV3gpf7Fixe74EYBYahly5YuGFGzxxYtWriAR4FfLqoFU5NI1cypi9eUyfHHH++WJQoa1eyxkPAZPwVOSbWDvrZReVRQmWv5WrbWR+ul9ZO2bdtW+uuVmqb4NHzwmMSXv6imUOmqZhEAAAAAig78VEvlm3ZKhw4dXJAV8gGYnj9TM08FIlWtefNNJH3tmK/pCmkaBVKiwHPGjBnuc3XROvnl+66qP/VQE2kOHjzYpeODcjU51XYDAAAAsG8rqcZPNVO+5m3kyJEuyFLwpyBQ9HKS7t2724IFC1wgphealEPpKn0faIa1YwpmQppGw1SDd+mll7qAau7cuZWel0sSPuOnLgxqPV+LFi5fnW/eWo7qTlPbRM8o6gUvvmbU/05hWGsIAAAAYN9VdOCnAEKBREhBX/jj7Wrq2L9/f/c5/lKXYoTNFb2wGadq+/wzc6LaLN9MUsvt0qWLe75PQdV9992X96UxxVItWlItY1VUR5phueSiF99UtcYVAAAAwN6v3u5I5nOVqcZq8uTJrjZNAVpVmy4CAAAAAKquWgK/MOCTeE0gAAAAAOCTU/JbPQsh6AMAAACAuqVam3oCAAAAAOqeaq/xAwAAAADULQR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHL1dkcynwEAAIBPzu5dZh+9m+mJ1D848wFAVRH4AQAA4JOz63Wz7Q+abbshCvxWZAZm7HeYWftoPIAqI/ADAABALfnQ7INV0Z+3zHbOM9vx56j/0cy4BPXamXVYk+kBUBUEfgAAAKg+u3dEwVwU2Cm4+3BF9PnN6O+S6O/C6O8/MhMVab/Dzdq/lukBUBUlBX6zZ8+2iRMn2pAhQ1z/lClT3N9hw4ZZv3793GcAAADkUte/b6+X+ZvHRxsygd3K6K8CutejbnG0atHw3Wuj8YsyE1aHRmYdt2c+A6iKkgK/adOmZYO90IABA2zo0KHWoEGDzBAAAIBqsulKs/cfiQKKBRWBBWpY0+gOsXnUHZj53Lii2/1+tA2iYG/3sorJakuHKPCrFwWAAKqk6J9z2LVrl23cuNF9VqB3ww032KhRo1w/AABAjdh8tdm2S8w+nEnQV2u2RmW9KgryXo+6FyuaZ37w1+jv32s/6BPVLgKosqIDv/Xr19vSpUutc+fONnDgQFe7t3ZtxQm4Z8+e1PYBAIDqp2fEsG/7cHnmA4CqKDrw27Jli61cudK6d+9urVu3djWAixcvduPatm3r/gIAAFSvjzJ/sc/Sy2EAVFnRgZ+v3WvZsqWr3du5c6etW7fO1QA2a9bMjQMAAACq1YcEfkB1KDrwi9fuqQZw06ZN1qJFCwI/AAAA1Ay9ORRAlfE7fgAAoO7acLHZjt9merBPqv9ps3ZzMj0AylV0jR8AAABQ6z58Ifrvg4rPAMpG4AcAAIC67cN1mQ8AykXgBwAAgLrtw3czHwCUi8APAADUTasPMttxR6YH+7SP3sl8AFAuAj8AAFA37d4e/fdexWfs2z54I/MBQLkI/AAAAFC3ffB65gOAchH4AQAAoG77YH7mA4ByEfgBAACgbvvg75kPAMpF4AcAAIC6bfemKPh7M9MDoBwEfgAAAKj7eMELUCX1dkcyn/cq06ZNsylTpmT6Pta7d2+78MILbfXq1TZr1iwbOnSoNWjQIDN277Fr1y6bPHmy9e/f33r06JEZ+slYsmSJjR07Nlu2TZs2zYwx27p1q91zzz12xhlnWPv27TND9w2zZ8+2tWvX2uDBg/e6cvDHz5AhQ1z+a0J1l8maNWvslltusZUrV2aGmA0bNsz69evnPhc6ZpSfCRMm2Pz5Hz8nEs4vPo2ZM2dmhpgNGDCgRs4jdekYj/PHfJJRo0ZZhw4d9srjXvvQvffea+ecc84+d77Kpc5fa1Y1i8Zsjf6Z3TPN7IzodFWXttyaqLt3stk5Q0vLl9Znwh8tOh9V9EenYhvct+Kz7Iq6yX+z6FxU0R+dqqxf14rPouXecptF50Ozzp3Nhn+/Yvnx+UJhGrOXm02cWPE5OsXZ0C+Y+TNcPG/5li3RKcF6NKn4LEu2WbQdKz5Hm9Iu/KbZx3cN+ZddaL3twFvNmkUrWwXhtTuJxi9evLjgeV/7ayn3mdV1/qmNY1Z5ffjhh+3cc8+tdM+XS3jtjF9XS1XqvYO/tmt7+vLw9wsyfPjwKpV3Uvp7NQV+e7OdO3fuvuuuu3ZHB2lmSAX1a7jG741yrVdt27Jly+5bb711dxRIZ4ZUVmh8IZpP8yud6jZ16tTd0Uk501f9lLaWIVUth1JUdb1q6tgIy0Oqu0zi+4r6r7322mz6+Y4ZTTNmzJhK5eanD8sinobvr4n9KF9+65L4dpXa3N9Rs+rKfphzn3q7adTZ7i1Rd+uttnt19Ff9pXaaT/MrnaTxtd299NLH67Iz6u66y6Jj7ePxU6dWdPqsPF93nUXbqKJf81177cfzF1q3+Hilo/R8f7iseF7iyy4mL2G/0lF6Slf9+ZYd748vy3Xrf5bZMcqXdE4rR01dS+N0TITXvto4ZuPLLKS6ylTi54JS87K3XFuLUeq6F4Omnsgr2tnc32bN9K0r0kDfdLZs2XKvrAkPtW7d2tq2bZvdR3PRN5FPPPGEDRo0qNK3kFp/fVMry5cvd3/jNE3Pnj1dmQGoOfvatebYdh/XEOpM3L+/WRTguBov1bitWmV2fKYGUPUtOnUtXFjRvyw6XUWnpez8+tuxo9kryacxmzPX7OijP651UzpKz/drOVqelrsz6rZvN+uWqWXTNKrk8KdAbaUmTcw6ZGr4WkdddBq2Ldsq+uN56xOlo/TWZ/rzLbvQejs7rjb7aHOmB3WFrpG6HtcFUeAX7XPbuW/Nof7lkcznvdJHH33kmm517tzZ3Qh6GzZscE3C3nvvPfvNb35jU6dOtf32288OP/zwzBQV1bc333yzTZw40Y1v166dSyeJqv7nzZtnixYtsquvvnqP6dV0Tsv0/Ur7zjvvtE6dOrmdT00CHnnkEdu0aZPLz0svvWS9evVy1dGXXHLJHvnz66VlTJ8+3W688UY3zVFHHVVpPZWun9+nqeXpZldNCrQ85UNlceSRR1r9+vUzc1aIl8Ebb7xhffr0sYYNG7q0f/WrX9nbb79tjz322B7lJ1rOK6+84tbzrrvucumE+fDrHS5bwzStmg9cddVVe6Tv8+7XOVxuMdvMz69ye/HFF/fIjy+veNpJ4tOHy3vrrbds27Zt2TyrHI444ojsyUb7zBVXXJE4r8TXc/Pmza6cduzYUWkd/XDtE8WsVzg8Tvup0njttdfctH5/ylcuPp/59qWkdLV8lUmLFi3s1ltvtbvvvrvS/iX5tnWctv3rr78e3cAc7eZftmyZy8tnP/tZl5dc5wJdkDT8tNNOyy7X03y6QCjw03LjaWiZf/3rX+3UU09NLE9P6+/PC+E65ju+4svy55h4ues48XlR+SvPvjy1T7Vq1Sq7jDB9P//u3btdE5z4sVmscD/3lHZ1blvtf6WcHyXXsal51Czn0EMPdevpt4GorFSG/rwcP6/7ddDx5Y/d8LhV2lonHed+PcPtVuo2SsK1Jnat2fLf7o8ColcWmXWKVvuuB80m/tHspShQ6hUFCdqb1bzwkafNjjw0Oq7dHBXDNG3TDmZXjbUofbPHZpjt19zs8ChQUpr3/s3sxt+bTQ2Gi4KQm6NlaDka1667WecWFeNCmu7OaVG+ouwqH2oGec1tZndPqZjvqBOj4KiI79gWRQFPtCmsV7T8FVG+o81lxwfr0iBa9gtRAHdEtJx3Nll0TH6cV9kQrYyCs3CYKD+a77QTzLTHKb/PRv39on5/Fjgg6l5fadYyitbaR3ldFUV3b0f5UVrx6f20H0QZU3koHpy/wOwzvc3qRZ+ffsHsU5/6eJ21TKW3M8pfq2j6fMveEk2Tb72zR0z9T0c9R2V6KsSPCx1HTz31VHZf9MeF+ldF0aXOabmOsXBavx8nneP1ZUWh+8xQ/FjVMXnNNde484TmjR9zknRsqLmhjll9gZvv3K4y8OexQued+PGpPK5bty57vZWk9OrVq+eO//h9iYaH6fn7GJVneM6U+LXOX190nlUZFXMf6ufX5xtuuMEWLlxoTz75ZKXlhvw21rn5+uuvd9sg17aL5y9eVuG+E/LL8OdiTRtfRtnnxaqoqPjbe+Wq0lX/8OHDXfWzqLpUTb38dKo2ve666yr1qzrVVy3HKR2l56fXX6Xnp482WHZZEk8vnh+fnuYTTZfUbC1cRnwapal10LJ8v+bRvH5+35/El0GYb30O59GytB5+GXE+jXg+fL+6eLmGZRVP3+fbj/f9SlPCeTUuumF3n5PEt4nSCMszvqwkM2fOTFwv0Xx++8XXU+PCafVX/X49kpYdnTDdcE3jp4vPJ0nrFS5L/eE2jAvzLZo+X7n4/nxpSjxdn3c/n0/HT5NrOeG6hpQ/5VPHjbowz5Jr/kLlEY73afhlqAvLOonWJ1zvBQsWuHX36x/Or8/xZfn8xssvPj5enr48/Lb308fLM9w3lL6fv1jxfEk8L35ZfrpceYlvG0/Dw7LWX/X79LSu4blP8h2b6vd5C/Ov8fHjVMvx+dJ0YT7i6Wq++Pkwnn5YLoW2UZJ4nvQ33Ne1rHD++Dpp+lLK0ucpXEZ8mng5qN+vo5/f9yfx5RLmW5/DebSseNk6mSZ+vtlf2EwwbDaoTs0ZfRNDddF9VLScis8arvF+3niTRt/vmxWG82rc8uUVn+NduNx4GhoX5idXp+nCJo36q3R880h1Yf71OWxO6edXnv30vgvXQ12YXz8snm91mm/4cIv2iz3XwU+v8eH2SEpHnc9DoWUXWm8/bPfaoZmd42NJ+2S4T2t/ix8Tmkf0N5w2TEt07PjjR/w5XtOFx5rmVzo+3bjwWPV59NNqnF9+nIaHx4afNzwmlb8wz/HjS/3hOoSUhtLyeUlKv1B6+uzLQZRWuG5h+vF5/fLC6cNzWnz94wrNn8Svj/Kh+TVt/BrjxdMP11Xjct2Havp8+4cvl7DcfL6UrhRa93KkuqmnXsrQt29FmwE92KnPvslWVJjWpk0b69q1oj2DInl9s6FahFz0Igz/YKfm6969e8FmZqEwP926dXPf7hx//PGuX98iJDVbO++887IPpeqvmp35POobDTVdU95FeWrUqJGtX+8bVaj5SP+cTfp8Gfg8ib5pUA1ImEYhTZo0sbPPPrtSPpSu0vflOmfOHDdO327o2zatfxItV8tXPkR51zpoXT2/DTWuS5cu7nMxlIaa+/ny9GlHB6H7RifJSSedlF0vvdBC61pomystpakHgf28+qtt5dfDNy0My/7YY491edI+5vczzafP+ZoaFrMf5FNsueTbl3JReQ0cONDN59PduHGjS7eYbR3XsWNHGzdunI0fP95Gjhxp9913n/tWrLrpBSZahjqVvb7tTaJvI7U/n3LKKZkh5r5d1LaoruMrFJanzhk6B/ltr2FJzVLD/VDnGy0/uqi4/qqo7m1b6vkx37Hpz+vRRdRefvnlStsnLjyv65tqvVjE57vYYz5UzjaK41oT6PDxvhoVrZ0dvCika9QfJWurt1UMU3NGNWsU32zQN1mM01KjxbumiKKcR6sQrWtFv/jNpHFd9q/4XAw/n/JUUaK5KZ96kUpUvJVekJKP0jz9dLPRl5uNiDrNH23iPSjt6JDMrmMxdMaf9DcdC2bjo7R/8X2zJ6J+vZBFlObvo9PhwC9UjNeLW7R81a5Wn6jE659gdsCITH/MzslRRhdleiroWBWd29SpNkz7vfZznZNUMxfedxR7jOU7x0u++8xi+GmVnj/+ipXr3O7vQcJjUsebzs+6B4uL3w9rHp3DdC6TUtMTla0vX+VRn0spl5qmvKhGU9tV66SaUp0XwxrTfPy6aN5896HFxCFlnRerYJ99xk8Fr7cPXXTRRTZixAjXqaq1tnbMUncyT/OIDkQddMqzz7/WRdXtxd4gaF3jz3qperlx48Yl3WTEKT2l6+lkqxOnThDa0XXznusEp+U+//zz7qber5fe8uZvKHWiEw2fNGmSG1YMX16+/DyVf74bYZ301bRBy1OetB6FKC2lGd+2WrZfj6Sy9zRe6+bXP+nttZ5fr3L3g3LLpToU2taF6GKi/SFfMCGF1iXfthBdGJSnpAuc1kHHS1LzmZo6vjx/nMW3XV1Q1W2rbab1ih9DoXzHpspGNy4zZsxwzXT9zVEhWp6aOCVtz3LUhW1UTFkm8Xmu6jlGqnQs1NM8ydtPY6JksxTkaTfQkapgUM+95bqV1jNp0S5qIzPBkzq9iTJaVRf8+DdsargCoWKuNMqP3lAZ3SO7+aZlgtBcFCyNu60imK305socWrX6uLmjgkQFXuoujuZ///2KZ+1CKgOVTzF7fxTHW7MozeWZAE5BtWidFORFcVNFc9soAAzLVWnrslzgNLxH3pz9TzNrfEm07Fuj/fOxaMCCqLsrmjjagu2ei1a24suKcL2zPlQj1o/5Y1b3GOq0/37qU59y1wd/E60vPUqV7xxfFToW9Iy5AiodU7m+XCyHrnUKanTO9ceszpFLly5NPN4KXQNLTU903ij2Pqa2+XNaGDhrn5FitnO596FxNX2PkMs+G/jppKBvfPy3+r7zG7Su0o4i/oYirJnwnf+WpRCVQdKNmL7JLfUmIeQPKk8nW+3IOrB0Eta36rlouap9UhvtcJ3OP//87MGhbaRh+kZa7duLOeh8efnyC6mNd9LBrhtLvc5YJzgtTzVNCloLyXfg+oM8V9mrX+ukb9b8ums/zaWq+0E55VJditnWhSTlOy7c/+JU3rrw5tsntR0VOCbROuQKKmvq+NobVMe2zaeYY1OtDPRNqmr9ijlHoLI6da1p/NPMh8qUWnCpcS8aiQ51F/AoEMlzWLsgJ9pF7YZM8OS784OfFlDwp2HRpcb9xEAxe5HmVRqaT3IFfwr6ol3T1ajFg1PlTaec8Kyil6YoOEs6ehToKuCN124mlYHO6Coj/zIWUVi0YUO03Iresilv0a4S7TsV/eLzpnX6eNldooC+WxS8vWHr358cLfvX1mz3961Z09Oi9f6p7Vx3UDRTlJv3fpRnvSv/Epn2U90T6B5Dz0npC2fVAmq/07lf+1o555585/iqUn50TtSxJNUV/Om6rS+wxowZU+l4veyyyxK/dE86PnXd03OQUmp6SqeU+5ja5relryUWne/8/VkxyrkPjfuk7hH22cBPG1xNxKqrmZg2YNg0Tt80F1M7VEh40+Lz65sh6WZVJ4pcVe2FqAz0Lc7cuR9fmfRZLxcp5ZsxnRx8U07x6YXNBnQCmDp1qkvbD0+i5WqaME+eyuHpp5/OlofKvBQqL31LrZtGUTp626Meyk062HXiC7/p08WjmG2qtHQyCLeN/qrfBxhJZa+HnTWdLjL+oFd/oX20qvtBqeVSXfJt62JoffWQuC/TXLQOqv3Rw9thWWo9dcLWyT7fDaz2bQUVSbVGPqjU8e69+uqrLm+lHl/an5U/vx01bfh7gtVN669vK1WG1a2q27aQQsemXyddnLV9qysfOi51vvNfIuiY0bFTm/bta83HTTllbqb5YVg7FV1qomuNRWl/PDyJlqppfBohlcLTmTdsSrGXGpWO5vNyzad0FfQpr0lnWN1K63uMGZl1VbrapXOd6jRdWAsnmscHXCFfRtHmdNOIylTz6wynt3VGmypb86e8qqmn3l2heRVcqkbT17cpDaXl86Y3cmrd/HjVECrYU3l/vOwVtnX3sih2WxqdX5dEy15mTXevsPa7V0Wf19qMFzZFU+q3G3dVWm8Fy/lqXxXs6UUYepmG9iudsxWY6BgpdJ3IJd85vio0v+5nvFLvZ/LRNU/Xb13H/TGdj85rqr3zj6BoHp0PvFLTU2CV7z6mtq91cf78HX6xrcCvmG2g9a/KfWious6LpdpnAz+dEPRcmm4GfVW0mg35m99S+Ta6vumoDpJiaocKUZB05ZVXujSV1/BZOt2s6rkLfevt16GUamelox/J1U2Sn183FMX+GKmnduDNmzfPpqH0zjzzzEppaAfXW57iwYROyionrYNuLDRO84Z5UqeThMbpDU2+jDV9fDkhtXnXTZnfriovPccyevRoN7/SUYCmMkziA1S/PJ0Ii92mSjPcNvqrm1AfYCSVvZ5B0E2qnon0edTbCdUGPJS0XlXZD0otl1x0k6jtpDTCk3wu+bZ1LrrBDctUefRl6oXNUXx62s80vfYZP9yvZ1Itf5iGvpFT7VUSrYOOF03jp9eJWxeUUo8vrYc6v366eOr5gL1ROdu2FPmOTS1Dx4d/pk1NdZUPdVWlbar9xe8fuhHK9/xgTdi3rzUWXWs+bpqpTXpmUEMnClyiS01ULpWH+2BKTTtVC6dxmldp+PTUKbjQuOhSYxdlhimwiS8niW4jde/s01KANCjTZDRJtBtlp1V3xW0fB0yaLzqtuOHKs05T/hlA3S5f/8eP55Pwx99F7U3URDLp9lHp6PTum7mKn19bXM/taZ01TmWgWjzfFFXlqB+r1w+4+7wpLZ83jQ+fP1QZhD/Qnm/Zkm+9VZMYnbJzbgfdLOt+JLzPOPDAA929h+5BypHvHF8Vml+BVng85LrOxO+TiqHjVfcT/jyhLte8Sn/48OHZ+2GdB3Q998/4SSnp6XjPdx9T6rWunPXPJ167pwBU9xbhM6C5aJ5S7kPzKea8WN3rLvX0hpfMZ6DG6MC655577IwzznA7MgAARdl4qdn2X2d68lNQdE90f3RGFDBwpUkPfcUwPQrYT4kCQ/d1RKuZZo1O0icAJdhna/xQu9RMQt9aEPQBAGpKUrNH7P1U/6GawYo6aADlIvBDjVKzK1Vf52suBwBAVaiJppoHqplgvuaVALAvo6knAACou0po6ol9BE09gbJQ4wcAAAAAKUfgBwAA9m31WmQ+AEB60dQTAADUXav06vzifjoi0X7Hme3fO+p6ZrruZvU7RXdAB0Rd42j8gdFE9aJOt0P6+2HUlULz5LB7e5Tcu1G3JureibpVZh+9Hf1dEXVLo25BNE00HKWhqSdQFgI/AABQt+3+IPovCv5274w6BYGZv/sfEg0OfjVdQVi9+tHfBtHf/aOgrnn0Nwru6jqtV04+sMz8rRRnxsY5lSaoKLuPNkfdBrMPlkVdFHB+8HrUzY+GLYm6RZkJc4kC43r6MW6Vv34hcIcb+oki8APKQuAHAACwz1INZxQs79avIHp6EigKnBU8xwNJ+ygTTK6LYkEfREbBo/5++FJFMFljGkVZO9ys/bxMP4BSEPgBAACgerjaWd1a+i4KFP1nd8vpu4BqZj96L/oQBZn1FHQq2NTfqKvnP+tvPAgFUAoCPwAAAABIOX2FAgAAAABIMQK/EqxZs8auu+4699dbsmSJjRgxwq6//np744039hhfCs1322232datYTt7AAAAAKgamnpWgQK0e+65x8444wxr3759Zmj5FPg9/PDDdu6551rTpk0zQwEAAACgaqjxq4ItW/RaY7NmzfSaYwAAAACom/bqGr/Zs2fbxIkT3efevXvbhRde6GrKNHzt2rXWtm3b7PghQ4bY4MGD3WdRE82xY8e6z507d7bhw4dXqrULx8uoUaOsQ4cO2Ro+BX3heKV/yimn7FEDmCuPohrDCRMm2Pz5813/BRdcYK+99ho1fgAAAACq1V4b+MWbRapfNW8+8FOwNWzYMOvXr5/t2rXLJk+ebD179nT9CuqmTZuWDcLUP2vWLBs6dKg1aNBgj/FKe+fOnda6detKgV08D/Gmn8rH4sWLs+n6gFQBqA/69LlHjx7ZPK5bt65ScAgAAAAAVbVXN/VU8OSbWyrQCoMl1cApyBMFXf3793dBmAKshQsXunF++q5du1qjRo1s/fr1bryCQAVkfrzS7tKli/tcLKWj5Wm5Wr706dPHNm7c6PK9evVqa9OmjVu2aJqBAwdakyZNXD8AAAAAVJe9NvBTMHbOOefYLbfc4t6qqVq6fFQbqOBOAZmCL9UIaj51F110kU2fPt0FkarZ2759e5Wf21M6qr1Tc1C/nJEjR9rSpUvdclTz17Jly2xQCAAAAAA1Za+u8VPwd9lll9m4ceNc08x8wZ+CrR07drhASwGXntkbP358pU5NLhs2bGiNGzfO1iSWS+l06tTJxowZU2kZyq/yrecPFYAqEPW0zG3btmX6AAAAAKB67LWBn4I8H+gpyFKzydDcuXPdM3iippUKDH2zy169erl+DY/TeD0LGI5XOitWrHCfi6V09NKYJ554olJw56lGUbV/y5cvd/2+iamn/kmTJrnnAgEAAACgKvbql7uomefKlStdv3+RiyhY0nDV8M2cOdMNC8eLfwGMN2DAgOxLWCQc79/6qWCtlJe7iALIKVOmuM8Svl00XActQ+Oef/55l56C2fCFNAAAAABQrlT+gHv49kwAAAAA2NfxA+4AAAAAkHIEfgAAAACQcqls6gkAAAAA+Bg1fgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQckUHfrt27bJJkybZiBEjbMmSJW7Y1q1b7frrr3fDNE7TAAAAAADqlirV+M2YMcPmz59vAwYMsKFDh1qDBg0yYwAAAAAAdUXZgZ9q/aZMmWKdO3e2gQMHEvQBAAAAQB1VVuC3ZcsWmzZtmvs8aNAga9++vfsMAAAAAKh7ygr8nnvuOdfEc8iQIdavX7/MUAAAAABAXVRW4Ddnzhz3V8099YIXAAAAAEDdVVbg99Of/tS90EW1fg8++CBv8wQAAACAOqyswK9hw4buhS56scvMmTNt7ty5mTEAAAAAgLqmrMBP9EIXvdhFpk+fbmvWrHGfAQAAAAB1S9mBn/Tt29c1+Vy5cqXdcsstBH8AAAAAUAfV2x3JfAYAAAAApFCVavwAAAAAAHUfgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApByBHwAAAACkHIEfAAAAAKQcgR8AAAAApFz9yyOZz6m2detWu/nmm61t27bWunXrzNC6afbs2fbUU0/ZkUceafXr17ddu3bZvffeazfeeKO1a9fO3nrrrUrjS6X0582bZ4cffnhmyMfWrFljEyZMsEMPPdSaNWuWGVq8JUuW2COPPJKYt3C9PvroI7dOTZs2LWp7+DIodvraFq7bsmXL9iiDadOm2aOPPmp9+vSxDRs22DXXXGN33323TZ061XXarp07d86u5/bt211/ISrvu+66y6XbsGHDzNCK5S1atKjSNta2VdpHHHGEW86dd95pnTp1Kms7lypcts+nyuz222+3Xr167ZGHqu6HtSXpvKK8a/vOnDnTunbtan/4wx/KPu8o/drcTqg+hbZdeF7XOWDz5s17nDd1jFxxxRU5x3s63p9//vns+HC+sAvTyJe234f9OWq//fbLnkt0zrnkkksqpavujTfe2OM8BACoY3ajzps1a9bu6MKa6au66k4vtHjx4t1RILJ7586dmSHJNF7TafpilDp93JYtW3bfeuutu1evXp0ZUn2UptLWMiReBirvsD8+vfqvvfbabN5KyWvStBp23XXXuc4vQ8J8lbKM6qDlxMsonr80qOp+Glfb26muSMN6F1oH7SPhfqJzcnhejh8j8fGe0h8zZkylc0xcfL+Mn5Pi14SXXnopm28tX/nIt09rXqUBAKjbaOq5F1i7dq2rMUDdNGfOHDv66KNdbWScvh3XN+tnnnmmNWjQIDO0MtUEaftGN1iuX+l07NjR1RwWom/XGzduXGna6IZNX+i4zqcpCxcutJ49e+bMR21RbUJ0o2hnn312YpntzaIbaVdbS+0cCunRo4frvOOPP95WrVrlagpFx2u/fv2yx0h8vKfzT9++fTN9yZYvX+7+qgZaNY1REGf9+/fPngtUU6e0dWzKsccea+3bt3eftXzlU9ehJJpH8yoNAEDdtlc39fTNClu1amXXX3+9a5YSNkkJxZsK+iZaEydOdDehvqldEjWjufrqq910vknMjh07XDOeFi1auKZ2Suell17ao9la2Jwm3hQmV1Mf31RQN+mTJ0+26dOn24svvphNXxfasClhoXUJm+YoD8rzhx9+mFhO8eZJyr+aharZoC+DfGWlZowrV6603r17u7yFTRxXrFiRzbfMnz/fpeObwMWbEIXbUk1DNb2WrfLwZXbUUUe5+VUm8aaEGqbmgloPNSnUjdSTTz6Zs7lTfPskbXffFMpTeT377LPuBs1vd18Gbdq0sSeeeMK+/e1vVwpwNM/rr7/ugkUtS9tb03/2s5/Npq+///znPxOXGdI4BRq6KfNlpW2lcm3UqJELRPQ5nk/te6+88orbF2699VZ37MTXP99+Vep+4ddZTTcffvhhO+uss7I3lkk0fbgfaluGTc/8do/LNZ0/V+hG99JLL03cpvHjMX4uiaet9dU6+POK5r/hhhsq7Wf+GPbnHQn38/g5I56H5s2b28aNG91+7afJx28XrZNfRr7tkuscpPNbuO3DsvLbRp+T9p1C45OWG5aDyjlejrmOg1zHb7yps6Z74IEHsuPj5xq/nxTaB2py22m91R1zzDGu/OPnlQMOOMAdQy1btqy0LymIU/4VfPnzbkj5euyxx1ygpy+Y/LlU+4RPp169ei5t7St+mKc8vfDCC3baaadlt19ITdx1XKsDANRxrt5vL+Wbq0QXWddkRU1TwiZzoXhTF83jm6Zo3PLly93nOE0fNonRdPrsm7+ETXE0bdifrzmNz0/YPCa6kXDD48sM8yrheJ8Pv17qD5sXxfOk4WoW5PMRF59fyx0+fHg2ff3V/EllLGHetIxwPcJx6vQ5V7p+vF9v3x9Oo79+e8fTk7C84+slGu/z4/v99GFexW/3OKWndH35iuZVvnLtixqm9VC5qksqz6R0cwmnVR7/9Kc/uWHKh1+feHr6q/3Cr6M6fQ7LK99+Vep+oeG+TPw8+YTL83kL85K0nHzTaZjy69dP9Nn3+3nj+5tPy+ffp6e0FyxYkLjMsJzi4/U3PB7Vr/GaLp4HUf7ylWucptf2f/zxx11/fHmhpOWF5yCfZ80b3xeK2XdyjY/3Szyf+huWYxLl2y/D98eXoXTjacWXpeH++NY8ufaB+Hzq98uPzyvKS7HbLj5/0vrH8xNOE+YlLmlcvOw0TXg8+2VpWK50RctWHnyZAADqtr26qadqOdatW2ennHKK+yZf34zqG81ivl0V33RF83bp0sV9TqJlRBc+91nT+eYxTZo0qdRcTc1oVMsTXQzdt6zRRXSP5jT6BljfiPumN2ETHTWv8dMWS8vSMrVsUV5Uk+Sb/sWbC6mGYtCgQe5zsYYMGZJtkqTldO/evVITwiTRjYVb16FDhxa1Tsqn8uVrgTSPyk5lqLL0zjvvvOw0+qsaFa2rn17L1fS+/PWNfJJC20dybfc41TjHvwlXLYWETTBDaso5btw4Gz9+vI0cOdLuu+8+9+295/fhQuUs+oZezT21L6xfv97VOGp+db5pmPKhZfr9QLT/Dhw40K2XLz+tv8qm0H4l5ewXom1dDn+8Ki9+H0iSa7oBAwZU2vfDpnMqN9Wcah8QXx4+r2pOp36fntJWLVSp4sejyk01s1p+PA+ic5u2WzG03bT9VFt08sknu2HaB1RrmlRTk+8cFDZDVF7jTf3y7TuFxvv11Lp5Kgd/7ixGoePXL1PnA7U40L6rbaf5NGzw4MHZbaDhOr4L7QM1te2UJ9UKqyZP6RdrxowZ2fXKR/kOy0m0HC3voosushEjRrjaSx0fnqY9//zz3flJ2/HKK6+sdH7ydD5QHnyZAADqtr028NPFUhf58ALubxqSbnLiNJ/oojdp0iSXXhLd8Gha3ZyrSZGaveSii6UupqKAQYHD2LFj3TLUKY2lS5e6m2PdRGna8GJcDqWjtwf6C7g6Nc/ScF9Gtf18oPKjpqn5nmsL5cqnblp1M+WDryThPB06dHDT+xsx3ZT5wCWu0PYpZbsnURCkJp5qYqYuH+2/Wpa/wSyV3++0zZV3H+CFAaHG5QqCk+Tbr8qlPKlMtK3VFK9YWj99gaAbfeUj17zFTudp/1L5iMpNb0XU9vbrq31Ded22bVu1HEd+P1c5+mWofNV0WctXp/wUc/5Kon1a+78PuEQ35joOko5Dbctc5yDlVedFn88pU6ZkxlRd0noqD34fLkah41d0DCtNBcI+uPVlpG0fV8w+UN3bTucVBVUKzPw1KR9tS+Vd5xTlp9CzfQqCNZ3OjXFangI7dV/+8pdzlosCS33h5r9U8/RZTdS7deuWGQIAqOv22sDPBwPhBS3fjUwSf+Hzz+GEF7WQbiA03fDhw90zHLmCAH9jJ7oB0DftY8aMyV5c1V122WXuQqqbSE2ba5nFUjqqeQmXoU7rlutmqio378XQN8fHHXece77O157lk++mL6k2LRTOo8BCQY9udtXpGZZc+0Kh7SPFbnfVsPn9MaSbKNUI6+Yw6dvyUNK660Yy6UYsiYI6BTz+uSPx5apnn1SzVWxakm+/qgqVu74QUHkUCohDWhdfAyH5gr9iphPdrOtmV1Q2qg3Us2Xh+iot1V7l2j9L4bfHqFGjKi1DnfY15UH5Cfcl5bGYY0g0rY6X8Bkt5TlXwJrrHKR+nQ8VjPj8aV+oLknr6eXKa1wxx6+OV62fluVrNzWfjiuVVVwx+0B1bjvlT8+7KtBUGqGkfOrLLJ1r9KyfjvXwixkFqOpXEBmep/Slj/LtvxzNRdNpefHn+/JRfqSUeQAAn6y9NvBLqt3Ld5MT0o3N008/nb3hyTePXpTgL6S6uIcXUH0LrCZg3ty5c91f1TLpJk+Bh17ukRTcKWDVN9Z+HtGykqbNR+noJjpXYKF10w22vwHRuoTLrCm6aVRzomKDPwUrCpB8WascVHbx4C381tmvd9i8Ss339FKUl19+udLwuELbJ992D2mcJN1Iiv+2XC+4CG/IQiofbaOwRi7cv5U/1b7kC5T8/rRgwYJsnkRp6kUO8YCgkEL7VVWoLIsNiEXlo+PVy3W8FppON8Y+APD7l2+mprJRzVCuYyO+f2pZr776qvtcCqWjYDTpmNB20zlFL93xdH7xzYZF8+baD+K1e1pHBT65yivXOUh5UxDj9yP1V+d+oLJWkKGmip7f15SnYhQ6fpVnBVWq/TzjjDPcS2I0TPPpi75wG2ib6sVTxewDVdl2cRqfq5mk8qlzaLg8Ta8vthTI+S83fKeAVF+4/eIXv8gGvqJWBPmub6L0tRzfHFTlGV4f/XiVm9+3JFdtsrajXraWVE4AgE/WXhv4KcjTBdBfdHSRUa1GMc1ONI8uyP7bUl3UcjVL1AV99OjRbjp9M3vqqadmL6z6FlhvbvNNf3RDFqYTf47CL0t0sb/wwgvdPH6cms0k5SEffxOtwMKnEzZNVB7U+eZLulEKn62pSVquvsnWsgvdOGo6BUi+rFVmutFQGiEF1fpWW9NoneM/CaCbN20X39zR02fdZCl937Q33/bJt91DStfXMuaidVNNgtLz5aB91W8T/fVl5Wn/jt9o5aMAUc9IqYlpGODpRlpv7MtX+5mk0H5VVT4gVk1FvoBWtG4K2Hw+VNsRPqvnFZpON8aqEdU4bXNte79/qWx07IbHozq/veL7p7ZZ+KVTsZSOlum3vTq/P6rM4+cEbTftX6JpFJjkOsfFv/jyz53lCqaSlqdzkMrFHysapi9vtG9VF5W1muQqKPXL1XGnvChPor/x4zUu1/GraR988EFXbtrP1Ckt/yWU5gu3wS233OK2ZTH7QLnbLpew6ajvci1PSqlxz7e/aBl+eUpf6frzj8ohvD5qvC+zkPa38MsqAEDdV09veMl8Rgl0A3HPPfe4b5OTAgJ8MnSz45up+RuZmqZgSLUL5557bvbGtSrYt6qfbnRVW1zsy4bqIu1nqslWLRYAAECp9uq3egJxvplWrpe61ARfo6BahqSaiVL42gqlR9CHkPYHgj4AAFAuAj+kgmpD1BRRTa1yNdutSWoGpeduqrpcza904s2qAAAAgKqgqScAAAAApBw1fgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByBH4AAAAAkHIEfgAAAACQcgR+AAAAAJByRf+A+65du2zy5Mk2c+ZM1z9s2DDr16+f+yxbt261CRMm2Pz5813/qFGjrEePHu4zAAAAAOCTU3aN3+LFi10w6K1evTob9AEAAAAA6o6SA7/OnTvbUUcdZUuXLrX169dnhpotXLgwOw4AAAAAUHeUVeOnAG/lypW2bNky169mnkuWLHFBX9u2bd0wAAAAAEDdUFbg17NnTxf8+eaevpkntX0AAAAAUPeUFfi1bt3aunfvnm3uqWaevXv3tg4dOmSmAAAAAADUFWUFfg0bNnS1fmru+fLLL7tmnnqDZ7NmzTJTAAAAAADqirICP+nWrZtr7vnHP/7RNfPs1atXZgwAAAAAoC4pO/DzzT2FZp4AAAAAUHeVHfg1aNDANfcUNfNs2rSp+wwAAAAAqFvq7Y5kPgMAAAAAUqjsGj8AAAAAwN7A7P8DIa0iwV1FzKsAAAAASUVORK5CYII=" 172 | } 173 | }, 174 | "cell_type": "markdown", 175 | "id": "87137f07-849f-4659-a3ce-66647e1b0bf5", 176 | "metadata": {}, 177 | "source": [ 178 | "- Model will be saved into column with column type is BLOB\n", 179 | "- By default, maximum of this column is ~2Gb\n", 180 | "- Model size larger than this limit is not able to upload\n", 181 | " \n", 182 | "![image.png](attachment:108931b7-0740-47b9-bc1d-cc333d24fdcf.png)" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": 54, 188 | "id": "94eb30aa-2a69-4fdb-8ccc-efd830b908a9", 189 | "metadata": {}, 190 | "outputs": [ 191 | { 192 | "name": "stderr", 193 | "output_type": "stream", 194 | "text": [ 195 | "C:\\Users\\admin\\miniconda3\\envs\\easyml_llm\\lib\\site-packages\\teradataml\\context\\context.py:458: UserWarning: [Teradata][teradataml](TDML_2002) Overwriting an existing context associated with Teradata Vantage Connection. Most of the operations on any teradataml DataFrames created before this will not work.\n", 196 | " warnings.warn(Messages.get_message(MessageCodes.OVERWRITE_CONTEXT))\n" 197 | ] 198 | }, 199 | { 200 | "data": { 201 | "text/plain": [ 202 | "Engine(teradatasql://dbc:***@192.168.11.7/?DATABASE=MACHINE_LEARNING_DEMO)" 203 | ] 204 | }, 205 | "execution_count": 54, 206 | "metadata": {}, 207 | "output_type": "execute_result" 208 | } 209 | ], 210 | "source": [ 211 | "create_context(host=host, username=username, password=password, database=db_name)" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 56, 217 | "id": "cf73135c-57e6-439f-917a-b6d70e547015", 218 | "metadata": {}, 219 | "outputs": [ 220 | { 221 | "name": "stdout", 222 | "output_type": "stream", 223 | "text": [ 224 | "Model is saved.\n" 225 | ] 226 | } 227 | ], 228 | "source": [ 229 | "save_byom(model_id=\"randomforest\", model_file= \"./rfmodel.pmml\", table_name=\"model\")" 230 | ] 231 | }, 232 | { 233 | "cell_type": "markdown", 234 | "id": "c950ffbb-e929-4dc9-8ac8-7132b01a54a3", 235 | "metadata": {}, 236 | "source": [ 237 | "## 3. Generate Pre-processing" 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": 65, 243 | "id": "80cf46eb-6a2f-4a1b-bf13-c0425176f333", 244 | "metadata": {}, 245 | "outputs": [], 246 | "source": [ 247 | "from autogluon.features.generators.astype import AsTypeFeatureGenerator\n", 248 | "from autogluon.features.generators import CategoryFeatureGenerator\n", 249 | "import numpy as np" 250 | ] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": 66, 255 | "id": "1f46b743-4226-4433-9837-a84799900e13", 256 | "metadata": {}, 257 | "outputs": [], 258 | "source": [ 259 | "cat_f_generator, as_type_f_generator = None, None\n", 260 | "\n", 261 | "for generators in predictor._learner.feature_generators[0].generators:\n", 262 | " for generator in generators:\n", 263 | " if isinstance(generator, AsTypeFeatureGenerator):\n", 264 | " as_type_f_generator = generator\n", 265 | " if isinstance(generator, CategoryFeatureGenerator):\n", 266 | " cat_f_generator = generator" 267 | ] 268 | }, 269 | { 270 | "cell_type": "markdown", 271 | "id": "bb63a9f6-1509-4de1-8539-1cc197acc503", 272 | "metadata": {}, 273 | "source": [ 274 | "### Processing Datatype" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 67, 280 | "id": "9adbc6b3-61d2-4801-9bbb-68c9e2668a90", 281 | "metadata": {}, 282 | "outputs": [], 283 | "source": [ 284 | "processed_column = []\n", 285 | "label_encode_cols = cat_f_generator.category_map.keys()" 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": 68, 291 | "id": "9dc3bdc1-e255-4230-9753-b8b3705c3c7d", 292 | "metadata": {}, 293 | "outputs": [], 294 | "source": [ 295 | "sql_dtype_numeric, sql_dtype_float, sql_dtype_category, sql_dtype_bool = \"\", \"\", \"\", \"\"\n", 296 | "\n", 297 | "for col, val in as_type_f_generator._bool_features.items():\n", 298 | " if (col not in label_encode_cols) and (col not in processed_column):\n", 299 | " sql_dtype_bool += \"\\t CASE WHEN \\\"{}\\\" = '{}' THEN 1 ELSE 0 END AS \\\"{}\\\", \\r\\n\".format(col, val, col)\n", 300 | " processed_column.append(col)\n", 301 | "\n", 302 | "for col in as_type_f_generator._int_features:\n", 303 | " if (col not in label_encode_cols) and (col not in processed_column):\n", 304 | " sql_dtype_numeric += \"\\t COALESCE(CAST(\\\"{}\\\" AS INT), 0) AS \\\"{}\\\", \\r\\n\".format(col, col)\n", 305 | " processed_column.append(col)\n", 306 | "\n", 307 | "float_features = [key for key, value in as_type_f_generator._type_map_real_opt.items() if value == np.dtype('float64')]\n", 308 | "for col in float_features:\n", 309 | " sql_dtype_float += \"\\t COALESCE(CAST(\\\"{}\\\" AS FLOAT), 0) AS \\\"{}\\\", \\r\\n\".format(col, col)\n", 310 | "\n", 311 | "if hasattr(model_rf, \"_feature_generator\"):\n", 312 | " for cat_fea in model_rf._feature_generator.features_in:\n", 313 | " if (cat_fea not in label_encode_cols) and (cat_fea not in processed_column):\n", 314 | " sql_dtype_category += \"\\t COALESCE(CAST(\\\"{}\\\" AS VARCHAR(255)), '') AS \\\"{}\\\", \\r\\n\".format(cat_fea, cat_fea)\n", 315 | " processed_column.append(cat_fea)" 316 | ] 317 | }, 318 | { 319 | "cell_type": "code", 320 | "execution_count": 69, 321 | "id": "f552d787-3369-42c8-a828-4e728dbae1b7", 322 | "metadata": {}, 323 | "outputs": [ 324 | { 325 | "name": "stdout", 326 | "output_type": "stream", 327 | "text": [ 328 | "\t COALESCE(CAST(\"age\" AS INT), 0) AS \"age\", \n", 329 | "\t COALESCE(CAST(\"fnlwgt\" AS INT), 0) AS \"fnlwgt\", \n", 330 | "\t COALESCE(CAST(\"education-num\" AS INT), 0) AS \"education-num\", \n", 331 | "\t COALESCE(CAST(\"capital-gain\" AS INT), 0) AS \"capital-gain\", \n", 332 | "\t COALESCE(CAST(\"capital-loss\" AS INT), 0) AS \"capital-loss\", \n", 333 | "\t COALESCE(CAST(\"hours-per-week\" AS INT), 0) AS \"hours-per-week\", \n", 334 | " \t CASE WHEN \"sex\" = ' Male' THEN 1 ELSE 0 END AS \"sex\", \n", 335 | "\n" 336 | ] 337 | } 338 | ], 339 | "source": [ 340 | "print(sql_dtype_numeric, sql_dtype_float, sql_dtype_category, sql_dtype_bool)" 341 | ] 342 | }, 343 | { 344 | "cell_type": "markdown", 345 | "id": "ef00f291-3c86-4166-a730-898154844db4", 346 | "metadata": {}, 347 | "source": [ 348 | "### Processing label-encoding" 349 | ] 350 | }, 351 | { 352 | "cell_type": "code", 353 | "execution_count": 70, 354 | "id": "0c50eacb-6d70-48d3-9a97-b56b6c2fa4c6", 355 | "metadata": {}, 356 | "outputs": [], 357 | "source": [ 358 | "sql_encoding = \"\"\n", 359 | "if cat_f_generator is not None:\n", 360 | " for col, encode_values in cat_f_generator.category_map.items():\n", 361 | " _sql_when_codition = \"\\t CASE \\r\\n\"\n", 362 | "\n", 363 | " for i, encode_val in enumerate(encode_values):\n", 364 | " _sql_when_codition += \"\\t\\t WHEN \\\"{}\\\" = '{}' THEN {} \\r\\n\".format(col, encode_val, i)\n", 365 | "\n", 366 | " _sql_when_codition += \"\\tELSE -1 \\r\\n\"\n", 367 | " _sql_when_codition += \"\\tEND AS \\\"{}\\\", \\r\\n\".format(col)\n", 368 | "\n", 369 | " sql_encoding += _sql_when_codition" 370 | ] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "id": "72ec6d9b-99f4-4d1b-b4f5-41390f62aa05", 375 | "metadata": {}, 376 | "source": [ 377 | "### Combine all SQL" 378 | ] 379 | }, 380 | { 381 | "cell_type": "code", 382 | "execution_count": 71, 383 | "id": "be7f38e7-aef4-4894-916c-c352c1cf493f", 384 | "metadata": {}, 385 | "outputs": [], 386 | "source": [ 387 | "sql_encoding = sql_encoding[:sql_encoding.rfind(\",\")]\n", 388 | "features_order = \", \".join(f\"\\\"{col}\\\" as x{i + 1}\" for i, col in enumerate(model_rf.features))\n", 389 | "sql_uid = \"ROW_NUMBER() OVER (ORDER BY \\\"{}\\\") AS id,\".format(model_rf.features[0])\n", 390 | "\n", 391 | "sql = \"CREATE VIEW [OUTPUT_VIEW] as \\r\\n\" + \\\n", 392 | " \"SELECT \" + sql_uid + features_order + \"\\r\\nFROM (SELECT \\r\\n\" + \\\n", 393 | " sql_dtype_bool + sql_dtype_numeric + sql_dtype_float + sql_dtype_category + sql_encoding + \\\n", 394 | " \"\\r\\nFROM \" + \"[INTPUT_TABLE]\" + \") predict_table;\"" 395 | ] 396 | }, 397 | { 398 | "cell_type": "code", 399 | "execution_count": 72, 400 | "id": "5a5b3917-5ac9-4d2d-b8f2-30380ff1d0da", 401 | "metadata": {}, 402 | "outputs": [ 403 | { 404 | "name": "stdout", 405 | "output_type": "stream", 406 | "text": [ 407 | "CREATE VIEW [OUTPUT_VIEW] as \n", 408 | "SELECT ROW_NUMBER() OVER (ORDER BY \"age\") AS id,\"age\" as x1, \"fnlwgt\" as x2, \"education-num\" as x3, \"sex\" as x4, \"capital-gain\" as x5, \"capital-loss\" as x6, \"hours-per-week\" as x7, \"workclass\" as x8, \"education\" as x9, \"marital-status\" as x10, \"occupation\" as x11, \"relationship\" as x12, \"race\" as x13, \"native-country\" as x14\n", 409 | "FROM (SELECT \n", 410 | "\t CASE WHEN \"sex\" = ' Male' THEN 1 ELSE 0 END AS \"sex\", \n", 411 | "\t COALESCE(CAST(\"age\" AS INT), 0) AS \"age\", \n", 412 | "\t COALESCE(CAST(\"fnlwgt\" AS INT), 0) AS \"fnlwgt\", \n", 413 | "\t COALESCE(CAST(\"education-num\" AS INT), 0) AS \"education-num\", \n", 414 | "\t COALESCE(CAST(\"capital-gain\" AS INT), 0) AS \"capital-gain\", \n", 415 | "\t COALESCE(CAST(\"capital-loss\" AS INT), 0) AS \"capital-loss\", \n", 416 | "\t COALESCE(CAST(\"hours-per-week\" AS INT), 0) AS \"hours-per-week\", \n", 417 | "\t CASE \n", 418 | "\t\t WHEN \"workclass\" = ' ?' THEN 0 \n", 419 | "\t\t WHEN \"workclass\" = ' Federal-gov' THEN 1 \n", 420 | "\t\t WHEN \"workclass\" = ' Local-gov' THEN 2 \n", 421 | "\t\t WHEN \"workclass\" = ' Private' THEN 3 \n", 422 | "\t\t WHEN \"workclass\" = ' Self-emp-inc' THEN 4 \n", 423 | "\t\t WHEN \"workclass\" = ' Self-emp-not-inc' THEN 5 \n", 424 | "\t\t WHEN \"workclass\" = ' State-gov' THEN 6 \n", 425 | "\tELSE -1 \n", 426 | "\tEND AS \"workclass\", \n", 427 | "\t CASE \n", 428 | "\t\t WHEN \"education\" = ' 10th' THEN 0 \n", 429 | "\t\t WHEN \"education\" = ' 11th' THEN 1 \n", 430 | "\t\t WHEN \"education\" = ' 12th' THEN 2 \n", 431 | "\t\t WHEN \"education\" = ' 1st-4th' THEN 3 \n", 432 | "\t\t WHEN \"education\" = ' 5th-6th' THEN 4 \n", 433 | "\t\t WHEN \"education\" = ' 7th-8th' THEN 5 \n", 434 | "\t\t WHEN \"education\" = ' 9th' THEN 6 \n", 435 | "\t\t WHEN \"education\" = ' Assoc-acdm' THEN 7 \n", 436 | "\t\t WHEN \"education\" = ' Assoc-voc' THEN 8 \n", 437 | "\t\t WHEN \"education\" = ' Bachelors' THEN 9 \n", 438 | "\t\t WHEN \"education\" = ' Doctorate' THEN 10 \n", 439 | "\t\t WHEN \"education\" = ' HS-grad' THEN 11 \n", 440 | "\t\t WHEN \"education\" = ' Masters' THEN 12 \n", 441 | "\t\t WHEN \"education\" = ' Prof-school' THEN 13 \n", 442 | "\t\t WHEN \"education\" = ' Some-college' THEN 14 \n", 443 | "\tELSE -1 \n", 444 | "\tEND AS \"education\", \n", 445 | "\t CASE \n", 446 | "\t\t WHEN \"marital-status\" = ' Divorced' THEN 0 \n", 447 | "\t\t WHEN \"marital-status\" = ' Married-AF-spouse' THEN 1 \n", 448 | "\t\t WHEN \"marital-status\" = ' Married-civ-spouse' THEN 2 \n", 449 | "\t\t WHEN \"marital-status\" = ' Married-spouse-absent' THEN 3 \n", 450 | "\t\t WHEN \"marital-status\" = ' Never-married' THEN 4 \n", 451 | "\t\t WHEN \"marital-status\" = ' Separated' THEN 5 \n", 452 | "\t\t WHEN \"marital-status\" = ' Widowed' THEN 6 \n", 453 | "\tELSE -1 \n", 454 | "\tEND AS \"marital-status\", \n", 455 | "\t CASE \n", 456 | "\t\t WHEN \"occupation\" = ' ?' THEN 0 \n", 457 | "\t\t WHEN \"occupation\" = ' Adm-clerical' THEN 1 \n", 458 | "\t\t WHEN \"occupation\" = ' Craft-repair' THEN 2 \n", 459 | "\t\t WHEN \"occupation\" = ' Exec-managerial' THEN 3 \n", 460 | "\t\t WHEN \"occupation\" = ' Farming-fishing' THEN 4 \n", 461 | "\t\t WHEN \"occupation\" = ' Handlers-cleaners' THEN 5 \n", 462 | "\t\t WHEN \"occupation\" = ' Machine-op-inspct' THEN 6 \n", 463 | "\t\t WHEN \"occupation\" = ' Other-service' THEN 7 \n", 464 | "\t\t WHEN \"occupation\" = ' Priv-house-serv' THEN 8 \n", 465 | "\t\t WHEN \"occupation\" = ' Prof-specialty' THEN 9 \n", 466 | "\t\t WHEN \"occupation\" = ' Protective-serv' THEN 10 \n", 467 | "\t\t WHEN \"occupation\" = ' Sales' THEN 11 \n", 468 | "\t\t WHEN \"occupation\" = ' Tech-support' THEN 12 \n", 469 | "\t\t WHEN \"occupation\" = ' Transport-moving' THEN 13 \n", 470 | "\tELSE -1 \n", 471 | "\tEND AS \"occupation\", \n", 472 | "\t CASE \n", 473 | "\t\t WHEN \"relationship\" = ' Husband' THEN 0 \n", 474 | "\t\t WHEN \"relationship\" = ' Not-in-family' THEN 1 \n", 475 | "\t\t WHEN \"relationship\" = ' Other-relative' THEN 2 \n", 476 | "\t\t WHEN \"relationship\" = ' Own-child' THEN 3 \n", 477 | "\t\t WHEN \"relationship\" = ' Unmarried' THEN 4 \n", 478 | "\t\t WHEN \"relationship\" = ' Wife' THEN 5 \n", 479 | "\tELSE -1 \n", 480 | "\tEND AS \"relationship\", \n", 481 | "\t CASE \n", 482 | "\t\t WHEN \"race\" = ' Amer-Indian-Eskimo' THEN 0 \n", 483 | "\t\t WHEN \"race\" = ' Asian-Pac-Islander' THEN 1 \n", 484 | "\t\t WHEN \"race\" = ' Black' THEN 2 \n", 485 | "\t\t WHEN \"race\" = ' Other' THEN 3 \n", 486 | "\t\t WHEN \"race\" = ' White' THEN 4 \n", 487 | "\tELSE -1 \n", 488 | "\tEND AS \"race\", \n", 489 | "\t CASE \n", 490 | "\t\t WHEN \"native-country\" = ' ?' THEN 0 \n", 491 | "\t\t WHEN \"native-country\" = ' Canada' THEN 1 \n", 492 | "\t\t WHEN \"native-country\" = ' China' THEN 2 \n", 493 | "\t\t WHEN \"native-country\" = ' Cuba' THEN 3 \n", 494 | "\t\t WHEN \"native-country\" = ' El-Salvador' THEN 4 \n", 495 | "\t\t WHEN \"native-country\" = ' England' THEN 5 \n", 496 | "\t\t WHEN \"native-country\" = ' Germany' THEN 6 \n", 497 | "\t\t WHEN \"native-country\" = ' Italy' THEN 7 \n", 498 | "\t\t WHEN \"native-country\" = ' Mexico' THEN 8 \n", 499 | "\t\t WHEN \"native-country\" = ' Philippines' THEN 9 \n", 500 | "\t\t WHEN \"native-country\" = ' Portugal' THEN 10 \n", 501 | "\t\t WHEN \"native-country\" = ' Puerto-Rico' THEN 11 \n", 502 | "\t\t WHEN \"native-country\" = ' South' THEN 12 \n", 503 | "\t\t WHEN \"native-country\" = ' Taiwan' THEN 13 \n", 504 | "\t\t WHEN \"native-country\" = ' United-States' THEN 14 \n", 505 | "\t\t WHEN \"native-country\" = ' Vietnam' THEN 15 \n", 506 | "\tELSE -1 \n", 507 | "\tEND AS \"native-country\"\n", 508 | "FROM [INTPUT_TABLE]) predict_table;\n" 509 | ] 510 | } 511 | ], 512 | "source": [ 513 | "print(sql)" 514 | ] 515 | }, 516 | { 517 | "cell_type": "markdown", 518 | "id": "b6c5401d-9f0e-40d8-bc8a-6136a2a3ae0e", 519 | "metadata": {}, 520 | "source": [ 521 | "## 4. Predict in Teradata DB" 522 | ] 523 | }, 524 | { 525 | "cell_type": "code", 526 | "execution_count": 57, 527 | "id": "336a4205-c063-44af-be91-b6a0f1fcb3e0", 528 | "metadata": {}, 529 | "outputs": [], 530 | "source": [] 531 | }, 532 | { 533 | "cell_type": "code", 534 | "execution_count": 63, 535 | "id": "99beb08b-e22f-4ad1-8a8e-197c70b67032", 536 | "metadata": {}, 537 | "outputs": [], 538 | "source": [ 539 | "from teradataml import copy_to_sql\n", 540 | "\n", 541 | "df_test = test_data.sample(1000).reset_index()\n", 542 | "\n", 543 | "copy_to_sql(df=df_test, table_name=\"Salary\", if_exists=\"replace\")" 544 | ] 545 | }, 546 | { 547 | "cell_type": "markdown", 548 | "id": "1855e631-5992-4a9a-80de-ad2415c80396", 549 | "metadata": {}, 550 | "source": [ 551 | "**Using following SQL to pre-processing data**" 552 | ] 553 | }, 554 | { 555 | "cell_type": "markdown", 556 | "id": "325bcab7-c6f1-4fb7-96e2-0e629466e44c", 557 | "metadata": {}, 558 | "source": [ 559 | "Note : \n", 560 | "- Edit [OUTPUT_VIEW] as output of cleaned data\n", 561 | "- Edit [INTPUT_TABLE] as input table name of raw data\n", 562 | "\n", 563 | "```sql\n", 564 | "CREATE VIEW [OUTPUT_VIEW] as \r\n", 565 | "SELECT ROW_NUMBER() OVER (ORDER BY \"age\") AS id,\"age\" as x1, \"fnlwgt\" as x2, \"education-num\" as x3, \"sex\" as x4, \"capital-gain\" as x5, \"capital-loss\" as x6, \"hours-per-week\" as x7, \"workclass\" as x8, \"education\" as x9, \"marital-status\" as x10, \"occupation\" as x11, \"relationship\" as x12, \"race\" as x13, \"native-country\" as x14\r\n", 566 | "FROM (SELECT \r\n", 567 | "\t CASE WHEN \"sex\" = ' Male' THEN 1 ELSE 0 END AS \"sex\", \r\n", 568 | "\t COALESCE(CAST(\"age\" AS INT), 0) AS \"age\", \r\n", 569 | "\t COALESCE(CAST(\"fnlwgt\" AS INT), 0) AS \"fnlwgt\", \r\n", 570 | "\t COALESCE(CAST(\"education-num\" AS INT), 0) AS \"education-num\", \r\n", 571 | "\t COALESCE(CAST(\"capital-gain\" AS INT), 0) AS \"capital-gain\", \r\n", 572 | "\t COALESCE(CAST(\"capital-loss\" AS INT), 0) AS \"capital-loss\", \r\n", 573 | "\t COALESCE(CAST(\"hours-per-week\" AS INT), 0) AS \"hours-per-week\", \r\n", 574 | "\t CASE \r\n", 575 | "\t\t WHEN \"workclass\" = ' ?' THEN 0 \r\n", 576 | "\t\t WHEN \"workclass\" = ' Federal-gov' THEN 1 \r\n", 577 | "\t\t WHEN \"workclass\" = ' Local-gov' THEN 2 \r\n", 578 | "\t\t WHEN \"workclass\" = ' Private' THEN 3 \r\n", 579 | "\t\t WHEN \"workclass\" = ' Self-emp-inc' THEN 4 \r\n", 580 | "\t\t WHEN \"workclass\" = ' Self-emp-not-inc' THEN 5 \r\n", 581 | "\t\t WHEN \"workclass\" = ' State-gov' THEN 6 \r\n", 582 | "\tELSE -1 \r\n", 583 | "\tEND AS \"workclass\", \r\n", 584 | "\t CASE \r\n", 585 | "\t\t WHEN \"education\" = ' 10th' THEN 0 \r\n", 586 | "\t\t WHEN \"education\" = ' 11th' THEN 1 \r\n", 587 | "\t\t WHEN \"education\" = ' 12th' THEN 2 \r\n", 588 | "\t\t WHEN \"education\" = ' 1st-4th' THEN 3 \r\n", 589 | "\t\t WHEN \"education\" = ' 5th-6th' THEN 4 \r\n", 590 | "\t\t WHEN \"education\" = ' 7th-8th' THEN 5 \r\n", 591 | "\t\t WHEN \"education\" = ' 9th' THEN 6 \r\n", 592 | "\t\t WHEN \"education\" = ' Assoc-acdm' THEN 7 \r\n", 593 | "\t\t WHEN \"education\" = ' Assoc-voc' THEN 8 \r\n", 594 | "\t\t WHEN \"education\" = ' Bachelors' THEN 9 \r\n", 595 | "\t\t WHEN \"education\" = ' Doctorate' THEN 10 \r\n", 596 | "\t\t WHEN \"education\" = ' HS-grad' THEN 11 \r\n", 597 | "\t\t WHEN \"education\" = ' Masters' THEN 12 \r\n", 598 | "\t\t WHEN \"education\" = ' Prof-school' THEN 13 \r\n", 599 | "\t\t WHEN \"education\" = ' Some-college' THEN 14 \r\n", 600 | "\tELSE -1 \r\n", 601 | "\tEND AS \"education\", \r\n", 602 | "\t CASE \r\n", 603 | "\t\t WHEN \"marital-status\" = ' Divorced' THEN 0 \r\n", 604 | "\t\t WHEN \"marital-status\" = ' Married-AF-spouse' THEN 1 \r\n", 605 | "\t\t WHEN \"marital-status\" = ' Married-civ-spouse' THEN 2 \r\n", 606 | "\t\t WHEN \"marital-status\" = ' Married-spouse-absent' THEN 3 \r\n", 607 | "\t\t WHEN \"marital-status\" = ' Never-married' THEN 4 \r\n", 608 | "\t\t WHEN \"marital-status\" = ' Separated' THEN 5 \r\n", 609 | "\t\t WHEN \"marital-status\" = ' Widowed' THEN 6 \r\n", 610 | "\tELSE -1 \r\n", 611 | "\tEND AS \"marital-status\", \r\n", 612 | "\t CASE \r\n", 613 | "\t\t WHEN \"occupation\" = ' ?' THEN 0 \r\n", 614 | "\t\t WHEN \"occupation\" = ' Adm-clerical' THEN 1 \r\n", 615 | "\t\t WHEN \"occupation\" = ' Craft-repair' THEN 2 \r\n", 616 | "\t\t WHEN \"occupation\" = ' Exec-managerial' THEN 3 \r\n", 617 | "\t\t WHEN \"occupation\" = ' Farming-fishing' THEN 4 \r\n", 618 | "\t\t WHEN \"occupation\" = ' Handlers-cleaners' THEN 5 \r\n", 619 | "\t\t WHEN \"occupation\" = ' Machine-op-inspct' THEN 6 \r\n", 620 | "\t\t WHEN \"occupation\" = ' Other-service' THEN 7 \r\n", 621 | "\t\t WHEN \"occupation\" = ' Priv-house-serv' THEN 8 \r\n", 622 | "\t\t WHEN \"occupation\" = ' Prof-specialty' THEN 9 \r\n", 623 | "\t\t WHEN \"occupation\" = ' Protective-serv' THEN 10 \r\n", 624 | "\t\t WHEN \"occupation\" = ' Sales' THEN 11 \r\n", 625 | "\t\t WHEN \"occupation\" = ' Tech-support' THEN 12 \r\n", 626 | "\t\t WHEN \"occupation\" = ' Transport-moving' THEN 13 \r\n", 627 | "\tELSE -1 \r\n", 628 | "\tEND AS \"occupation\", \r\n", 629 | "\t CASE \r\n", 630 | "\t\t WHEN \"relationship\" = ' Husband' THEN 0 \r\n", 631 | "\t\t WHEN \"relationship\" = ' Not-in-family' THEN 1 \r\n", 632 | "\t\t WHEN \"relationship\" = ' Other-relative' THEN 2 \r\n", 633 | "\t\t WHEN \"relationship\" = ' Own-child' THEN 3 \r\n", 634 | "\t\t WHEN \"relationship\" = ' Unmarried' THEN 4 \r\n", 635 | "\t\t WHEN \"relationship\" = ' Wife' THEN 5 \r\n", 636 | "\tELSE -1 \r\n", 637 | "\tEND AS \"relationship\", \r\n", 638 | "\t CASE \r\n", 639 | "\t\t WHEN \"race\" = ' Amer-Indian-Eskimo' THEN 0 \r\n", 640 | "\t\t WHEN \"race\" = ' Asian-Pac-Islander' THEN 1 \r\n", 641 | "\t\t WHEN \"race\" = ' Black' THEN 2 \r\n", 642 | "\t\t WHEN \"race\" = ' Other' THEN 3 \r\n", 643 | "\t\t WHEN \"race\" = ' White' THEN 4 \r\n", 644 | "\tELSE -1 \r\n", 645 | "\tEND AS \"race\", \r\n", 646 | "\t CASE \r\n", 647 | "\t\t WHEN \"native-country\" = ' ?' THEN 0 \r\n", 648 | "\t\t WHEN \"native-country\" = ' Canada' THEN 1 \r\n", 649 | "\t\t WHEN \"native-country\" = ' China' THEN 2 \r\n", 650 | "\t\t WHEN \"native-country\" = ' Cuba' THEN 3 \r\n", 651 | "\t\t WHEN \"native-country\" = ' El-Salvador' THEN 4 \r\n", 652 | "\t\t WHEN \"native-country\" = ' England' THEN 5 \r\n", 653 | "\t\t WHEN \"native-country\" = ' Germany' THEN 6 \r\n", 654 | "\t\t WHEN \"native-country\" = ' Italy' THEN 7 \r\n", 655 | "\t\t WHEN \"native-country\" = ' Mexico' THEN 8 \r\n", 656 | "\t\t WHEN \"native-country\" = ' Philippines' THEN 9 \r\n", 657 | "\t\t WHEN \"native-country\" = ' Portugal' THEN 10 \r\n", 658 | "\t\t WHEN \"native-country\" = ' Puerto-Rico' THEN 11 \r\n", 659 | "\t\t WHEN \"native-country\" = ' South' THEN 12 \r\n", 660 | "\t\t WHEN \"native-country\" = ' Taiwan' THEN 13 \r\n", 661 | "\t\t WHEN \"native-country\" = ' United-States' THEN 14 \r\n", 662 | "\t\t WHEN \"native-country\" = ' Vietnam' THEN 15 \r\n", 663 | "\tELSE -1 \r\n", 664 | "\tEND AS \"native-country\"\r\n", 665 | "FROM [INTPUT_TABLE]) predict_table;\n", 666 | "\n", 667 | "```" 668 | ] 669 | }, 670 | { 671 | "cell_type": "markdown", 672 | "id": "a42247dc-81d4-4709-b627-ad2f6edeed94", 673 | "metadata": {}, 674 | "source": [ 675 | "**Using following code to make a prediction**" 676 | ] 677 | }, 678 | { 679 | "cell_type": "markdown", 680 | "id": "57ecbd3c-1869-4b3d-9e79-ce308d2799b0", 681 | "metadata": {}, 682 | "source": [ 683 | "Note : \n", 684 | "- Edit [OUTPUT_VIEW]\n", 685 | " \n", 686 | "```sql\n", 687 | "SELECT * FROM mldb.PMMLPredict( \n", 688 | "\tON [OUTPUT_VIEW] as InputTable\n", 689 | "\tON \n", 690 | "\t(SELECT * \n", 691 | "\tFROM Machine_learning_demo.model as ModelTable \n", 692 | "\tWHERE model_id = 'randomforest')\n", 693 | "DIMENSION USING Accumulate ( 'id' )) as T;\n", 694 | "```" 695 | ] 696 | }, 697 | { 698 | "cell_type": "code", 699 | "execution_count": null, 700 | "id": "6b148817-d3f1-4977-8a75-86377036bd99", 701 | "metadata": {}, 702 | "outputs": [], 703 | "source": [] 704 | }, 705 | { 706 | "cell_type": "code", 707 | "execution_count": null, 708 | "id": "8874eb73-aea3-4b90-8b0d-b199ec72c9bf", 709 | "metadata": {}, 710 | "outputs": [], 711 | "source": [] 712 | } 713 | ], 714 | "metadata": { 715 | "kernelspec": { 716 | "display_name": "Python 3 (ipykernel)", 717 | "language": "python", 718 | "name": "python3" 719 | }, 720 | "language_info": { 721 | "codemirror_mode": { 722 | "name": "ipython", 723 | "version": 3 724 | }, 725 | "file_extension": ".py", 726 | "mimetype": "text/x-python", 727 | "name": "python", 728 | "nbconvert_exporter": "python", 729 | "pygments_lexer": "ipython3", 730 | "version": "3.9.18" 731 | } 732 | }, 733 | "nbformat": 4, 734 | "nbformat_minor": 5 735 | } 736 | --------------------------------------------------------------------------------