{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "150\n" ] } ], "source": [ "import json\n", "ctrl = json.load(open('./ctrl_toolcall_train_v1.6_ch.json'))+json.load(open('./ctrl_toolcall_train_eng_v1.6_update2.json'))\n", "nav = json.load(open('./nav_toolcall_train_v1.6_ch.json'))+json.load(open('./nav_toolcall_train_eng_v1.6_update2.json'))\n", "multi_ctrl = json.load(open('./multi_toolcall_train_v1.6_ch.json'))+json.load(open('./multi_toolcall_train_eng_v1.6_update2.json'))\n", "from collections import defaultdict\n", "import numpy as np\n", "funcs = defaultdict(set)\n", "normal_seat = set([\"SEAT_ROW_1_LEFT\",\"SEAT_ROW_1_RIGHT\",\"SEAT_ROW_2_LEFT\",\"SEAT_ROW_2_RIGHT\",\"SEAT_ROW_3_LEFT\",\n", "\"SEAT_ROW_3_RIGHT\",\"SEAT_ALL\",\"SEAT_ROW_1\",\"SEAT_ROW_2\",\"SEAT_ROW_3\"])\n", "for tmp in ctrl:\n", " for idx,conv in enumerate(tmp['conversations']):\n", " if conv['from']=='function_call':\n", " tmp_js = json.loads(conv['value'])[0]\n", " try:\n", " if 'areaId' in tmp_js[\"arguments\"] and tmp_js[\"arguments\"]['areaId'] in normal_seat:\n", " tmp_js[\"arguments\"]['areaId']=\"\"\n", " if 'areaId' in tmp_js[\"arguments\"]:\n", " func_type_name = tmp_js[\"arguments\"][\"propertyId\"] if tmp_js[\"arguments\"]['areaId']==\"\" else tmp_js[\"arguments\"][\"propertyId\"]+'%'+tmp_js[\"arguments\"]['areaId']\n", " if 'value' in tmp_js[\"arguments\"] and not str(tmp_js[\"arguments\"]['value']).isdigit():\n", " funcs[func_type_name+'%'+tmp_js[\"arguments\"]['value']].add(tmp['conversations'][idx-1]['value'])\n", " elif 'operation' in tmp_js[\"arguments\"] and tmp_js[\"arguments\"]['operation'] in ['increase','decrease'] and not tmp_js[\"arguments\"][\"propertyId\"] in ['WINDOW_POS']:\n", " funcs[func_type_name+'%'+tmp_js[\"arguments\"]['operation']].add(tmp['conversations'][idx-1]['value'])\n", " elif tmp_js[\"arguments\"][\"propertyId\"] in ['POWER_SUNSHADE','WINDOW_POS']:\n", " func_tmp = func_type_name+\"%\"+tmp_js[\"arguments\"][\"operation\"]\n", " if 'value' in tmp_js[\"arguments\"]:\n", " func_tmp+='%'+str(tmp_js[\"arguments\"]['value'])\n", " funcs[func_tmp].add(tmp['conversations'][idx-1]['value'])\n", " else:\n", " funcs[func_type_name].add(tmp['conversations'][idx-1]['value'])\n", " except:\n", " if tmp_js['name']==\"set_seat_mode\":\n", " funcs[tmp_js['name']+'%'+tmp_js[\"arguments\"][\"value\"]].add(tmp['conversations'][idx-1]['value'])\n", " else:\n", " funcs[tmp_js['name']].add(tmp_js[\"arguments\"][\"query\"])\n", "print(len(funcs))" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "multi_ctrl_case = []\n", "cnt = 0\n", "ctrl_act = 2\n", "np.random.shuffle(multi_ctrl)\n", "for tmp in multi_ctrl:\n", " for idx,conv in enumerate(tmp['conversations']):\n", " if conv['from']=='human':\n", " multi_ctrl_case.append(','.join(conv['value'].split(',')[:ctrl_act]).replace('\"','').replace('Sure! Let me help you with that. ',''))\n", " cnt+=1\n", " if cnt+1%100==0: ctrl_act+=1\n", " if len(multi_ctrl_case)>1500:break" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'dfzsad' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[3], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdfzsad\u001b[49m\n", "\u001b[0;31mNameError\u001b[0m: name 'dfzsad' is not defined" ] } ], "source": [ "dfzsad" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "id2label = {i:k for i,k in enumerate(sorted(list(funcs.keys()))+['others','multi_ctrl_cases'])}\n", "label2id = {v: k for k, v in id2label.items()}\n", "dataset = [{'text':t,\"label\":label2id[k]} for k in funcs for t in funcs[k]]\n", "other_case = []\n", "cnt=0\n", "np.random.shuffle(nav)\n", "for tmp in nav:\n", " for idx,conv in enumerate(tmp['conversations']):\n", " if conv['from']=='human':\n", " other_case.append(conv['value'])\n", " cnt+=1\n", " if cnt>800:break\n", "other_case+=['窗戶','窗戶好髒','窗戶有髒汙','陽光灑進窗戶。', '窗外風景優美。', '微風吹拂窗簾。', '雨滴打在窗上。', '窗戶倒影清晰。', '打開窗戶通風。', '車窗外景色飛逝。', '車窗結滿霧氣。', '擦拭乾淨車窗。', '搖下車窗吹風。', '窗內光線柔和。', '窗外喧囂吵雜。', '月光透過窗戶。', '窗戶玻璃反光。', '推開窗戶探頭。', '車窗映出人影。', '窗外一片黑暗。', '凝視窗外發呆。', '窗戶結霜模糊。', '窗外雪花飄落。']\n", "other_case+=['座椅','座位上','座位下','座位','坐在椅子上休息。', '這把椅子很舒適。', '椅子被太陽曬熱。', '這張座椅很寬敞。', '請坐好您的椅子。', '椅子搖晃不穩。', '她拉開了椅子。', '把椅子移過來。', '椅子發出嘎吱聲。', '我坐在辦公椅上。', '這張椅子很重。', '座椅彈性很好。', '請回到您的座位。', '椅子排成一列。', '這張椅子是木製的。', '椅子上鋪著毯子。', '我的座椅很冰冷。', '這張椅子是我的。', '椅子被重新油漆。', '請讓座給老人。']\n", "other_case+=['風向','冷氣','電風扇正在轉動。', '風扇吹來涼風。', '風扇發出噪音。', '冷氣機滴水。', '風扇吹向我。', '冷氣遙控器不見了。', '風扇吹得很舒服。', '冷氣機壞掉了。', '冷氣口對著我。', '冷氣運轉中。', '冷氣口髒了。', '風扇轉速變慢。', '冷氣濾網很髒。', '冷氣需要清洗。', '風扇的風很涼。']\n", "other_case+=['墊高','用書本墊高螢幕。', '用枕頭支撐腰部。', '這根柱子支撐屋頂。', '用木塊墊高桌子。', '這塊海綿很支撐。', '請支撐住這個東西。', '用墊子墊高椅子。', '這個架子很支撐。', '用磚塊墊高。', '用手支撐頭部。', '墊高以利通風。', '用椅子墊高雙腳。', '這個床墊很支撐。', '用支架支撐植物。', '用石頭墊高。', '墊高可以看得更清楚。', '這根棍子是支撐。', '用墊子支撐脖子。', '墊高方便取物。']\n", "other_case+=['生活陷入了循環。', '這個模式很有效。', '打破舊有模式。', '這是個惡性循環。', '建立新的模式。', '每天都在循環。', '這個模式很穩定。', '陷入了疲勞循環。', '學習新的模式。', '這是一種運作模式。', '循環播放音樂。', '這個模式無法更改。', '他習慣了這個模式。', '保持良好循環。', '跳出這個循環。', '找到了新的模式。', '不斷重複的循環。', '這個模式很簡單。']\n", "other_case+=['電動車非常安靜。', '打開除霜功能。', '電動門緩緩開啟。', '除霜後視野清晰。', '這扇窗戶是電動的。', '電動牙刷很方便。', '除霜需要一些時間。', '電動滑板車。', '電動螺絲起子。', '除霜裝置故障。', '電動百葉窗。', '這輛車是電動的。', '啟動電動功能。', '電動吸塵器。', '電動按摩椅。', '除霜按鈕亮了。', '電動自行車。', '除霜效果很好。']\n", "other_case+=['再高一點','再低一點']\n", "other_case+=['fan','air conditioner','AC','sliding door','door','left','right','fuck','window','heat','seat','row','ottoman','second seat','first row']\n", "other_case+=['window','the window is dirty','the window has dirt','Sunlight streams through the window.', 'The scenery outside the window is beautiful.', 'The breeze rustles the curtains.', 'Raindrops hit the window.', 'The window reflection is clear.', 'Open the window for ventilation.', 'The scenery outside the car window flashes past.', 'The car window is completely fogged up.', 'Wipe the car window clean.', 'Roll down the car window for air.', 'The light inside the window is soft.', 'The outside is noisy.', 'Moonlight through the window.', 'The window glass reflects light.', 'Push open the window and peer out.', 'A reflection of a person appears on the car window.', 'Outside the window is completely dark.', 'Gazing blankly out the window.', 'The window is frosted and blurry.', 'Snowflakes are falling outside the window.']\n", "other_case+=['seat','on the seat','under the seat','seating','Sitting on a chair to rest.', 'This chair is very comfortable.', 'The chair was heated by the sun.', 'This seat is very spacious.', 'Please sit properly in your chair.', 'The chair is shaky and unstable.', 'She pulled out the chair.', 'Move the chair over.', 'The chair makes a creaking sound.', 'I sit on an office chair.', 'This chair is very heavy.', 'The seat has good elasticity.', 'Please return to your seat.', 'The chairs are lined up in a row.', 'This chair is made of wood.', 'A blanket is spread on the chair.', 'My seat is very cold.', 'This chair is mine.', 'The chair was repainted.', 'Please offer your seat to an elderly person.']\n", "other_case+=['air direction','air conditioning','The electric fan is turning.', 'The fan is blowing cool air.', 'The fan makes noise.', 'The air conditioner is dripping water.', 'The fan is blowing towards me.', 'The air conditioner remote is missing.', 'The fan is blowing very comfortably.', 'The air conditioner is broken.', 'The air vent is pointed at me.', 'The air conditioner is running.', 'The air vent is dirty.', 'The fan speed slows down.', 'The air conditioner filter is very dirty.', 'The air conditioner needs cleaning.', \"The fan's breeze is very cool.\"]\n", "other_case+=['raise up','Use books to raise the monitor.', 'Use a pillow to support the lower back.', 'This pillar supports the roof.', 'Use wooden blocks to raise the table.', 'This sponge is very supportive.', 'Please support this item.', 'Use a cushion to raise the chair.', 'This shelf is very supportive.', 'Use bricks to raise up.', 'Use your hand to support your head.', 'Raise up for better ventilation.', 'Use a chair to raise your feet.', 'This mattress is very supportive.', 'Use a stand to support the plant.', 'Use stones to raise up.', 'Raising up allows for clearer viewing.', 'This stick is a support.', 'Use a cushion to support the neck.', 'Raise up for easy access to items.']\n", "other_case+=['Life has fallen into a loop.', 'This pattern is very effective.', 'Break the old pattern.', 'This is a vicious cycle.', 'Establish a new pattern.', 'It cycles every day.', 'This pattern is very stable.', 'Fell into a cycle of fatigue.', 'Learn a new pattern.', 'This is a mode of operation.', 'Loop playback of music.', 'This pattern cannot be changed.', 'He is used to this pattern.', 'Maintain a good cycle.', 'Jump out of this cycle.', 'Found a new pattern.', 'A constantly repeating cycle.', 'This pattern is very simple.']\n", "other_case+=['The electric car is very quiet.', 'Turn on the defrost function.', 'The electric door opens slowly.', 'The view is clear after defrosting.', 'This window is electric.', 'Electric toothbrushes are very convenient.', 'Defrosting takes some time.', 'Electric scooter.', 'Electric screwdriver.', 'The defrost device is faulty.', 'Electric blinds.', 'This car is electric.', 'Activate the electric function.', 'Electric vacuum cleaner.', 'Electric massage chair.', 'The defrost button is lit.', 'Electric bicycle.', 'The defrost effect is very good.']\n", "other_case+=['a little higher','Please turn on the second row on','Please turn on','Please provide the original sentence','I can assist you with paraphrasing it in a more fluent manner','Please provide the original sentence so I can assist you with paraphrasing it in a more fluent manner','a little lower','please','Please provide the sentence you would like me to paraphrase.','sentence you would like me to paraphrase.','ask me to paraphrase.']\n", "cnt=0\n", "for tmp in other_case:\n", " dataset.append({'text':tmp,'label':label2id['others']})\n", "for tmp in multi_ctrl_case:\n", " dataset.append({'text':tmp,'label':label2id['multi_ctrl_cases']})\n", "\n", "dataset.append({'text':'關閉車窗並開啟辦公模式','label':label2id['multi_ctrl_cases']})\n", "dataset.append({'text':'開啟空調另外HHTD怎麼報名','label':label2id['multi_ctrl_cases']})\n", "dataset.append({'text':'結束辦公模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'1排結束辦公模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'2排結束辦公模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'3排結束辦公模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'第3排結束辦公模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'第2排結束辦公模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'第1排結束辦公模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'結束休憩模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'3排結束休憩模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'2排結束休憩模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'1排結束休憩模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'第1排結束休憩模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'第2排結束休憩模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'第3排結束休憩模式','label':label2id[\"set_seat_mode%OFF\"]})\n", "dataset.append({'text':'冷氣不要吹腳','label':label2id[\"HVAC_FAN_DIRECTION%OFF\"]})\n", "dataset.append({'text':'冷氣不要吹頭','label':label2id[\"HVAC_FAN_DIRECTION%OFF\"]})\n", "dataset.append({'text':'冷氣不要吹臉','label':label2id[\"HVAC_FAN_DIRECTION%OFF\"]})\n", "dataset.append({'text':'冷氣不要吹身體','label':label2id[\"HVAC_FAN_DIRECTION%OFF\"]})\n", "dataset.append({'text':'冷氣不要吹','label':label2id[\"HVAC_FAN_DIRECTION%OFF\"]})\n", "dataset.append({'text':'冷氣不要吹我','label':label2id[\"HVAC_FAN_DIRECTION%OFF\"]})\n", "dataset.append({'text':'冷氣出風不要掃風了','label':label2id[\"HVAC_FAN_OUTPUT_MODE%OFF\"]})\n", "dataset.append({'text':'按摩強度開弱','label':label2id[\"SEAT_MASSAGE_INTENSITY%LOW\"]})\n", "dataset.append({'text':'按摩強度開低','label':label2id[\"SEAT_MASSAGE_INTENSITY%LOW\"]})\n", "dataset.append({'text':'按摩強度開中等','label':label2id[\"SEAT_MASSAGE_INTENSITY%MEDIUM\"]})\n", "dataset.append({'text':'打開内循環','label':label2id[\"HVAC_RECIRC_MODE%INTERNAL\"]})\n", "dataset.append({'text':'窗戶關小30 percentage','label':label2id[\"WINDOW_POS%decrease%30\"]})\n", "dataset.append({'text':'溫度有點低','label':label2id[\"HVAC_TEMPERATURE_SET%increase\"]})\n", "dataset.append({'text':'我溫度有點高','label':label2id[\"HVAC_TEMPERATURE_SET%decrease\"]})\n", "dataset.append({'text':'冷氣風太小','label':label2id[\"HVAC_FAN_SPEED%increase\"]})\n", "dataset.append({'text':'風太大吹得不舒服,調小','label':label2id[\"HVAC_FAN_SPEED%decrease\"]})\n", "dataset.append({'text':'steering wheel heater should be turned off.','label':label2id[\"HVAC_STEERING_WHEEL_HEAT%false\"]})\n", "dataset.append({'text':'please adjust the car window to about 90 percent open?','label':label2id[\"WINDOW_POS%set%90\"]})\n", "dataset.append({'text':'Could you please adjust the car window to about 80 percent open?','label':label2id[\"WINDOW_POS%set%80\"]})\n", "dataset.append({'text':'please adjust the window to about 70 percent open?','label':label2id[\"WINDOW_POS%set%70\"]})\n", "dataset.append({'text':'Could you please adjust the car window to about 60 percent open?','label':label2id[\"WINDOW_POS%set%60\"]})\n", "dataset.append({'text':'adjust the window to about 50 percent open?','label':label2id[\"WINDOW_POS%set%50\"]})\n", "dataset.append({'text':'please adjust the window to about 40 percent open?','label':label2id[\"WINDOW_POS%set%40\"]})\n", "dataset.append({'text':'Could you please adjust the car window to about 30 percent open?','label':label2id[\"WINDOW_POS%set%30\"]})\n", "dataset.append({'text':'Could you please adjust the car window to about 20 percent open?','label':label2id[\"WINDOW_POS%set%20\"]})\n", "dataset.append({'text':'please adjust the window to about 10 percent open?','label':label2id[\"WINDOW_POS%set%10\"]})\n", "\n", "dataset.append({'text':'adjust the window to about 90 percent close?','label':label2id[\"WINDOW_POS%set%10\"]})\n", "dataset.append({'text':'Could you please adjust the car window to about 80 percent close?','label':label2id[\"WINDOW_POS%set%20\"]})\n", "dataset.append({'text':'Could you please adjust the window to about 70 percent close?','label':label2id[\"WINDOW_POS%set%30\"]})\n", "dataset.append({'text':'adjust the car window to about 60 percent close?','label':label2id[\"WINDOW_POS%set%40\"]})\n", "dataset.append({'text':'please adjust the window to about 50 percent close?','label':label2id[\"WINDOW_POS%set%50\"]})\n", "dataset.append({'text':'Could you please adjust the car window to about 40 percent close?','label':label2id[\"WINDOW_POS%set%60\"]})\n", "dataset.append({'text':'adjust the car window to about 30 percent close?','label':label2id[\"WINDOW_POS%set%70\"]})\n", "dataset.append({'text':'please adjust the window to about 20 percent close?','label':label2id[\"WINDOW_POS%set%80\"]})\n", "dataset.append({'text':'please adjust the window to about 10 percent close?','label':label2id[\"WINDOW_POS%set%90\"]})\n", "\n", "\n", "useful_dataset = []\n", "for tmp in dataset:\n", " tmp['text'] = tmp['text'].replace(',','').replace('\"','').replace('Sure! Let me help you with that. ','')\n", " if len(tmp['text']) < 5 or 'paraphras' in tmp['text'] or 'rephras' in tmp['text'] or 'sentence' in tmp['text']:continue\n", " useful_dataset.append(tmp)\n", "json.dump(useful_dataset,open('classifier_data.jsonl','w'),indent=2,ensure_ascii=False)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2025-10-21 06:09:58,395] [INFO] [real_accelerator.py:219:get_accelerator] Setting ds_accelerator to cuda (auto detect)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/usr/bin/ld: cannot find -laio: No such file or directory\n", "collect2: error: ld returned 1 exit status\n", "/usr/bin/ld: cannot find -laio: No such file or directory\n", "collect2: error: ld returned 1 exit status\n" ] } ], "source": [ "\n", "\n", "import torch\n", "from datasets import load_dataset\n", "from transformers import AutoTokenizer, AutoModelForSequenceClassification, TrainingArguments, Trainer\n", "\n", "def train_bert_classifier():\n", " num_labels = len(id2label)\n", " model_name = \"/mnt/jeff/InCar/bert/ModernBERT-base\"\n", " tokenizer = AutoTokenizer.from_pretrained(model_name)\n", " model = AutoModelForSequenceClassification.from_pretrained(\n", " model_name,\n", " num_labels=num_labels,\n", " id2label=id2label,\n", " label2id=label2id\n", " )\n", "\n", " def preprocess_function(examples):\n", " return tokenizer(examples[\"text\"], truncation=True, padding=True)\n", "\n", " print(\"資料前處理中...\")\n", " dataset = load_dataset('json', data_files='classifier_data.jsonl')\n", " tokenized_dataset = dataset.map(preprocess_function, batched=True)\n", "\n", " split_dataset = tokenized_dataset['train'].train_test_split(test_size=0.1)\n", " train_dataset = tokenized_dataset['train']\n", " eval_dataset = split_dataset['test']\n", "\n", " training_args = TrainingArguments(\n", " output_dir=\"./results_classifier3\", # 訓練結果儲存目錄\n", " learning_rate=2e-5, # 學習率\n", " per_device_train_batch_size=8, # 訓練批次大小\n", " per_device_eval_batch_size=8, # 評估批次大小\n", " num_train_epochs=3, # 訓練 epochs 數\n", " weight_decay=0.01, # 權重衰減\n", " save_strategy=\"epoch\", # 每個 epoch 結束後儲存檢查點\n", " report_to='none',\n", " )\n", "\n", " trainer = Trainer(\n", " model=model,\n", " args=training_args,\n", " train_dataset=train_dataset,\n", " eval_dataset=eval_dataset,\n", " tokenizer=tokenizer,\n", " )\n", "\n", " print(\"開始訓練模型...\")\n", " trainer.train()\n", " print(\"模型訓練完成!\")\n", " from tqdm import tqdm\n", " model.eval()\n", " total,corr = 0,0\n", " for i in tqdm(range(len(eval_dataset))):\n", " inputs = tokenizer(eval_dataset[i]['text'], padding=True, truncation=True, return_tensors=\"pt\").to('cuda')\n", " with torch.no_grad():\n", " outputs = model(**inputs)\n", " logits = outputs.logits\n", " predictions = torch.argmax(logits, dim=-1)\n", " res = eval_dataset[i]['label']==predictions.cpu().numpy()[0]\n", " if not res:\n", " if predictions.cpu().numpy()[0] in [num_labels-1,num_labels-2] and eval_dataset[i]['label'] in [num_labels-1,num_labels-2]:continue\n", " print(eval_dataset[i]['text'],eval_dataset[i]['label'],predictions.cpu().numpy()[0],\"lab\",id2label[eval_dataset[i]['label']],'pred',id2label[predictions.cpu().numpy()[0]])\n", " total+=1\n", " corr+=res\n", " print(corr,total,corr/total)\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Some weights of ModernBertForSequenceClassification were not initialized from the model checkpoint at /mnt/jeff/InCar/bert/ModernBERT-base and are newly initialized: ['classifier.bias', 'classifier.weight']\n", "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "資料前處理中...\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "25703a5df3454fbcbf9a12aead9dc88e", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Generating train split: 0 examples [00:00, ? examples/s]" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "dbf0848a1d48493b9d4464033d9a5b54", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Map: 0%| | 0/77962 [00:00\n", " \n", " \n", " [29238/29238 21:47, Epoch 3/3]\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
StepTraining Loss
5003.443300
10001.308000
15000.635400
20000.438400
25000.325100
30000.283200
35000.257200
40000.229000
45000.235800
50000.168500
55000.204100
60000.172100
65000.160800
70000.163500
75000.179900
80000.149900
85000.170100
90000.148300
95000.146900
100000.129400
105000.103000
110000.098400
115000.117700
120000.099000
125000.115500
130000.123600
135000.120800
140000.106900
145000.098400
150000.073900
155000.106000
160000.095900
165000.107000
170000.108800
175000.108000
180000.094400
185000.094300
190000.086100
195000.094200
200000.059700
205000.061400
210000.070900
215000.055600
220000.049200
225000.047100
230000.062100
235000.058300
240000.038500
245000.063800
250000.052600
255000.058600
260000.053900
265000.050200
270000.054500
275000.037400
280000.046200
285000.048300
290000.045000

" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "模型訓練完成!\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 2%|▏ | 148/7797 [00:02<01:52, 68.09it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please leave the window slightly ajar. 133 138 lab WINDOW_POS%set%10 pred WINDOW_POS%set%50\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 2%|▏ | 179/7797 [00:03<01:49, 69.61it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please remember the seat located in the last row on the left side. 98 97 lab SEAT_POSITION_MEMORY_SET pred SEAT_POSITION_MEMORY_SAVE\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 3%|▎ | 224/7797 [00:03<01:48, 69.59it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Could you please open the car window just a little bit? 133 120 lab WINDOW_POS%set%10 pred WINDOW_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 4%|▍ | 313/7797 [00:04<01:46, 70.14it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please open the front row car window to about 70 percent. 136 140 lab WINDOW_POS%set%30 pred WINDOW_POS%set%70\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 10%|█ | 817/7797 [00:12<01:39, 69.81it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please adjust the height of the right headrest on the third row. 72 73 lab SEAT_HEADREST_HEIGHT_POS%decrease pred SEAT_HEADREST_HEIGHT_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 12%|█▏ | 937/7797 [00:13<01:37, 70.19it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please adjust the length of the right footrest on the third row. 76 77 lab SEAT_LEGREST_FORE_AFT_POS%decrease pred SEAT_LEGREST_FORE_AFT_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 14%|█▍ | 1089/7797 [00:15<01:34, 70.68it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please assist me in activating the middle row on the right side. 29 34 lab HVAC_RECIRC_MODE% pred HVAC_SCENARIO_MODE%\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 15%|█▍ | 1161/7797 [00:16<01:33, 70.86it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please adjust the height of the third-row footrest accordingly. 78 79 lab SEAT_LEGREST_HEIGHT_POS%decrease pred SEAT_LEGREST_HEIGHT_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 17%|█▋ | 1296/7797 [00:18<01:34, 68.55it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Would you mind opening the car window just a little bit? 133 120 lab WINDOW_POS%set%10 pred WINDOW_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 18%|█▊ | 1433/7797 [00:20<01:31, 69.59it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please activate the heating function for the cushion located in the second row on the left side. 39 40 lab HVAC_SEAT_TEMPERATURE_POWER_ON%false pred HVAC_SEAT_TEMPERATURE_POWER_ON%true\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 20%|██ | 1560/7797 [00:22<01:29, 69.53it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please adjust the lumbar cushion to ensure proper support and comfort. 80 83 lab SEAT_LUMBAR_FORE_AFT_POS%decrease pred SEAT_LUMBAR_HEIGHT_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 21%|██ | 1604/7797 [00:23<01:30, 68.66it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please put second row right seating back 101 100 lab SEAT_STOW_MODE%STOW pred SEAT_STOW_MODE%RESTORE\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 21%|██ | 1646/7797 [00:23<01:28, 69.34it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please open the car window to about 80 percent. 141 130 lab WINDOW_POS%set%80 pred WINDOW_POS%increase%80\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 22%|██▏ | 1708/7797 [00:24<01:27, 69.72it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please assist me in adjusting the car window to about 70 percent of its maximum opening position. 136 129 lab WINDOW_POS%set%30 pred WINDOW_POS%increase%70\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 24%|██▍ | 1860/7797 [00:27<01:24, 70.02it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Could you please open the car window a bit? 134 120 lab WINDOW_POS%set%100 pred WINDOW_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 24%|██▍ | 1904/7797 [00:27<01:25, 69.24it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please reduce the height of the first row's window by about 10 percent. 133 110 lab WINDOW_POS%set%10 pred WINDOW_POS%decrease%10\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 25%|██▍ | 1926/7797 [00:27<01:24, 69.52it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please assist in turning on the automatic air circulation for the third row on the right side. 33 30 lab HVAC_RECIRC_MODE%OFF pred HVAC_RECIRC_MODE%AUTO\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 25%|██▌ | 1954/7797 [00:28<01:25, 68.30it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please assist me in lowering the right-side window of the second row by approximately 20 percent. 141 135 lab WINDOW_POS%set%80 pred WINDOW_POS%set%20\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 29%|██▉ | 2263/7797 [00:32<01:18, 70.07it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please ensure the proper operation of the middle row lumbar cushion adjustment mechanism. 81 80 lab SEAT_LUMBAR_FORE_AFT_POS%increase pred SEAT_LUMBAR_FORE_AFT_POS%decrease\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 33%|███▎ | 2567/7797 [00:37<01:15, 69.57it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Could you please lower the window a bit? 134 108 lab WINDOW_POS%set%100 pred WINDOW_POS%decrease\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 36%|███▌ | 2817/7797 [00:40<01:11, 69.90it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please open the window fully. 132 134 lab WINDOW_POS%set%0 pred WINDOW_POS%set%100\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 49%|████▉ | 3815/7797 [00:55<00:57, 69.48it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Could you please lower the car window a bit? 120 108 lab WINDOW_POS%increase pred WINDOW_POS%decrease\n", "The wind is a bit weak. 23 24 lab HVAC_FAN_SPEED%decrease pred HVAC_FAN_SPEED%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 57%|█████▋ | 4416/7797 [01:03<00:48, 69.62it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please open the car window just a little bit. 133 120 lab WINDOW_POS%set%10 pred WINDOW_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 66%|██████▌ | 5122/7797 [01:13<00:38, 69.76it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please assist me with performing the seatback adjustment process. 67 66 lab SEAT_BACKREST_ANGLE_POS%increase pred SEAT_BACKREST_ANGLE_POS%decrease\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 67%|██████▋ | 5254/7797 [01:15<00:36, 69.70it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please assist me in adjusting the height of the middle row seat. 75 74 lab SEAT_HEIGHT_POS%increase pred SEAT_HEIGHT_POS%decrease\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 72%|███████▏ | 5608/7797 [01:20<00:31, 69.49it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Could you please lower the window of the car in the front row a little bit? 120 108 lab WINDOW_POS%increase pred WINDOW_POS%decrease\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 75%|███████▌ | 5862/7797 [01:24<00:27, 69.90it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please assist me in adjusting and finishing the installation of the headrest support in the front row seat. 72 73 lab SEAT_HEADREST_HEIGHT_POS%decrease pred SEAT_HEADREST_HEIGHT_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 79%|███████▉ | 6194/7797 [01:29<00:22, 69.91it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please adjust the legrest on the left side of the first row to its proper position. 78 79 lab SEAT_LEGREST_HEIGHT_POS%decrease pred SEAT_LEGREST_HEIGHT_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 82%|████████▏ | 6356/7797 [01:31<00:20, 68.65it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Could you please turn on the automatic air circulation for the third row? 33 30 lab HVAC_RECIRC_MODE%OFF pred HVAC_RECIRC_MODE%AUTO\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 83%|████████▎ | 6448/7797 [01:32<00:19, 70.49it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please arrange the seats promptly. 99 101 lab SEAT_STOW_MODE%FOLD pred SEAT_STOW_MODE%STOW\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 83%|████████▎ | 6487/7797 [01:33<00:18, 69.59it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please move the first row of seats to the right. 70 99 lab SEAT_FORE_AFT_POS%decrease pred SEAT_STOW_MODE%FOLD\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 88%|████████▊ | 6879/7797 [01:39<00:13, 70.52it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please assist me in turning on the fresh air mode for the middle row first. 33 31 lab HVAC_RECIRC_MODE%OFF pred HVAC_RECIRC_MODE%EXTERNAL\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 90%|████████▉ | 6999/7797 [01:40<00:11, 69.33it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "The breeze is rather gentle. 23 24 lab HVAC_FAN_SPEED%decrease pred HVAC_FAN_SPEED%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 90%|█████████ | 7038/7797 [01:41<00:10, 70.22it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please pause the electric charging process for a brief moment. 1 0 lab EV_CHARGE_PORT_OPEN%true pred EV_CHARGE_PORT_OPEN%false\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 93%|█████████▎| 7236/7797 [01:44<00:07, 70.59it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please adjust the position of the lumbar cushion on the third row to make it more comfortable. 81 80 lab SEAT_LUMBAR_FORE_AFT_POS%increase pred SEAT_LUMBAR_FORE_AFT_POS%decrease\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 93%|█████████▎| 7260/7797 [01:44<00:07, 70.92it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ " To adjust the height of the seat cushion in the first-row seats, you need to extend it. 68 69 lab SEAT_CUSHION_SIDE_SUPPORT_POS%decrease pred SEAT_CUSHION_SIDE_SUPPORT_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 95%|█████████▌| 7444/7797 [01:47<00:04, 71.19it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please act quickly to fix the issue with the roof sunshade. 59 58 lab POWER_SUNSHADE%SUNROOF%true pred POWER_SUNSHADE%SUNROOF%false\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 96%|█████████▌| 7484/7797 [01:47<00:04, 70.87it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please move the ottoman in the first row to the left. 76 77 lab SEAT_LEGREST_FORE_AFT_POS%decrease pred SEAT_LEGREST_FORE_AFT_POS%increase\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ " 98%|█████████▊| 7659/7797 [01:50<00:01, 70.19it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Please assist me in closing the window to about 90 percent of its full size. 133 119 lab WINDOW_POS%set%10 pred WINDOW_POS%decrease%90\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 7797/7797 [01:52<00:00, 69.57it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "7722 7762 0.994846688997681\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "train_bert_classifier()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "['Could you please make sure to adjust the position of the lumbar cushion properly?',\n", " 'Could you please adjust the height of this lumbar cushion to make it more comfortable?',\n", " 'Could you kindly adjust the position of the backrest on the second row, specifically the seat located on the right?',\n", " ]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('WINDOW_POS%increase', 'HVAC_SEAT_VENTILATION_SET%increase')" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "id2label[57],id2label[49]" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "資料前處理中...\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "b1e23d9dbc5341f4b1e4ce1f4c578b7a", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Generating train split: 0 examples [00:00, ? examples/s]" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e12e5c4e9403475c89e90dea5bd9a07b", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Map: 0%| | 0/55022 [00:00=2:\n", " tmp_s = []\n", " for a in tmp_funcs[k]:\n", " tmp_js = json.loads(a.replace(\"'\",'\"'))\n", " if 'value' in tmp_js and str(tmp_js['value']).isdigit():\n", " tmp_js['value'] = str(tmp_js['value'])\n", " if not 'WINDOW_POS' in k or not 'POWER_SUNSHADE' in k: tmp_js['value'] = \"\"\n", " tmp_s.append(json.dumps(tmp_js))\n", " tmp_funcs[k] = set(tmp_s)\n", "for k in tmp_funcs:\n", " if len(tmp_funcs[k])==1 or 'WINDOW_POS' in k:\n", " cls_map[k] = json.dumps(json.loads(list(tmp_funcs[k])[0].replace(\"'\",'\"')))\n", " else:\n", " print(k, len(tmp_funcs[k]),tmp_funcs[k])" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "json.dump(cls_map,open('response_template.json','w'),ensure_ascii=False,indent=2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "HVAC_FAN_SPEED\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/tmp/ipykernel_1860429/3952825593.py:155: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.\n", " confidence = max(torch.nn.functional.softmax(logits[0]))\n" ] }, { "data": { "text/plain": [ "'[{\"name\": \"control_car_properties\", \"arguments\": {\"propertyId\": \"HVAC_FAN_SPEED\", \"areaId\": \"SEAT_ALL\", \"operation\": \"set\", \"value\": \"1\"}}]'" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# import re\n", "# import json\n", "# import cn2an\n", "\n", "# cls_map = json.load(open('response_template.json'))\n", "\n", "# switch_keywords = ['開啟', '開', '打開','啟動','啓動', '關閉', '關', '關掉','停止','停']\n", "# level_keywords = ['最大','最熱','最高','最低', '最小','最冷']\n", "\n", "# area2NL = {\n", "# \"SEAT_ROW_1_LEFT\": [\"主駕\", \"駕駛座\", \"主駕駛座\", \"第1排左邊\", \"第1排左座\", \"第1排左側\"],\n", "# \"SEAT_ROW_1_RIGHT\": [\"副駕\", \"副駕駛座\", \"第1排右座\", \"第1排右邊\", \"第1排右側\"],\n", "# \"SEAT_ROW_2_LEFT\": [\"第2排左側\", \"第2排左座\", \"中間這排左邊\", \"第2排左邊\"],\n", "# \"SEAT_ROW_2_RIGHT\": [\"第2排右側\", \"第2排右座\", \"中間這排右邊\", \"第2排右邊\"],\n", "# \"SEAT_ROW_3_LEFT\": [\"第3排左側\", \"第3排左座\", \"最後面這排左邊\", \"最後排左邊\", \"第3排左邊\"],\n", "# \"SEAT_ROW_3_RIGHT\": [\"第3排右側\", \"第3排右座\", \"最後面這排右邊\", \"最後排右邊\", \"第3排右邊\"],\n", "# \"SEAT_ALL\": [\"全車\", \"整台車\", \"整部車\"],\n", "# \"SEAT_ROW_1\": [\"第1排\", \"最前面那排\"],\n", "# \"SEAT_ROW_2\": [\"第2排\", \"中間那排\"],\n", "# \"SEAT_ROW_3\": [\"第3排\", \"最後面那排\"],\n", "# \"SUNROOF\": ['頂棚'],\n", "# \"SLIDING_DOOR_LEFT\": ['左邊', '左側', '左'],\n", "# \"SLIDING_DOOR_RIGHT\": ['右邊', '右側', '右'],\n", "# 'FRONT_WINDSHIELD':['前除霜'],\n", "# 'REAR_WINDSHIELD':['後除霜'],\n", "# }\n", "# NL2area = {nl:k for k in area2NL for nl in area2NL[k]}\n", "# maxmin_val_map = {\n", "# 'HVAC_SEAT_VENTILATION_SET':{'max':'3','min':'1'},\n", "# 'HVAC_SEAT_TEMPERATURE_SET':{'max':'4','min':'1'},\n", "# 'HVAC_FAN_SPEED':{'max':'8','min':'1'},\n", "# 'HVAC_TEMPERATURE_SET':{'max':'32','min':'17'},\n", "# }\n", "# uncommon_area_NL = set(['頂棚','左邊', '左側', '左','右邊', '右側', '右','前除霜','後除霜'])\n", "# st_open = set(['開啟', '開', '打開','啟動','啓動'])\n", "# st_close = set(['關閉', '關', '關掉','停止','停'])\n", "# default_value = {\n", "# 'HVAC_TEMPERATURE_SET':'26'\n", "# }\n", "\n", "# def extract_numbers_from_string(text : str):\n", "# exclude_pattern = r'第\\s*\\d+\\s*排|\\d+\\s*排|1\\s*下|快\\s*1\\s*點|1\\s*團|1\\s*口\\s*氣|1\\s*直'\n", "# excluded_matches = re.findall(exclude_pattern, text)\n", "# cleaned_text = text\n", "# for match in excluded_matches:\n", "# cleaned_text = cleaned_text.replace(match, '', 1)\n", "# numbers = re.findall(r'\\d+', cleaned_text)\n", "# return numbers\n", "# def get_keywords(text : str):\n", "\n", "# tokens = [c for c in text]\n", " \n", "# tags = [\"O\"] * len(tokens)\n", "# keywords = {\"switch\":[],'level':[],'num':[],'area_id':[]}\n", "# for keyword in switch_keywords:\n", "# for match in re.finditer(re.escape(keyword), text):\n", "# start, end = match.span()\n", "# keywords[\"switch\"].append(text[start:end])\n", " \n", "# for keyword in level_keywords:\n", "# for match in re.finditer(re.escape(keyword), text):\n", "# start, end = match.span()\n", "# keywords['level'].append(text[start:end])\n", " \n", "# keywords['num'] = extract_numbers_from_string(text)\n", "\n", "# for keyword in NL2area.keys():\n", "# for match in re.finditer(re.escape(keyword), text):\n", "# start, end = match.span()\n", "# keywords['area_id'].append(text[start:end])\n", "# if '副駕駛座' in keywords['area_id'] and not ('前除霜' in keywords['area_id'] or '後除霜' in keywords['area_id']): \n", "# keywords['area_id']=['副駕駛座']\n", "# return keywords\n", "\n", "\n", "\n", "\n", "\n", "# def postprocess(query : str,pred_class : str):\n", "# ori_func_name = pred_class.split('%')[0]\n", "# func_tmp = cls_map[pred_class]\n", "# ori_query = query\n", "# query = cn2an.transform(query)\n", "# keywords = get_keywords(query)\n", "# func_tmp = json.loads(func_tmp)\n", "# if len(keywords['area_id'])!=0:\n", "# if 'SLIDING_DOOR' in pred_class:\n", "# for lr in area2NL[\"SLIDING_DOOR_LEFT\"]+area2NL[\"SLIDING_DOOR_RIGHT\"]:\n", "# if lr in keywords['area_id']:\n", "# func_tmp['areaId'] = NL2area[lr]\n", "# elif 'HVAC_DEFROSTER' in pred_class:\n", "# for fb in ['前除霜','後除霜']: \n", "# if fb in keywords['area_id']: \n", "# func_tmp['areaId'] = NL2area[fb]\n", "# elif 'POWER_SUNSHADE' in pred_class:\n", "# if '頂棚' in keywords['area_id']:\n", "# func_tmp['areaId'] = NL2area['頂棚']\n", "# elif any([right in keywords['area_id'] for right in ['右邊', '右側', '右']]):\n", "# func_tmp['areaId'] = \"SEAT_ROW_2_RIGHT\"\n", "# elif any([right in keywords['area_id'] for right in ['左邊', '左側', '左']]):\n", "# func_tmp['areaId'] = \"SEAT_ROW_2_LEFT\"\n", "# else:\n", "# if not keywords['area_id'][0] in uncommon_area_NL:\n", "# func_tmp['areaId'] = NL2area[keywords['area_id'][0]]\n", "# if len(keywords['num'])!=0 and 'value' in func_tmp and str(keywords['num'][0]).isdigit() and func_tmp['value'] == '':\n", "# func_tmp['value'] = str(keywords['num'][0])\n", "# elif len(keywords[\"level\"])!=0 and 'value' in func_tmp and func_tmp['value'] == '' and ori_func_name in maxmin_val_map:\n", "# if keywords[\"level\"][0] in ['最大','最熱','最高']:\n", "# func_tmp['value'] = maxmin_val_map[ori_func_name]['max']\n", "# elif keywords[\"level\"][0] in ['最低', '最小','最冷']:\n", "# func_tmp['value'] = maxmin_val_map[ori_func_name]['min']\n", "# elif len(keywords[\"switch\"])!=0 and ori_func_name in ['POWER_SUNSHADE'] and 'value' in func_tmp and func_tmp['value'] == '':\n", "# for op in keywords[\"switch\"]:\n", "# if op in st_open and not '開大' in query: func_tmp['value']='100'\n", "# elif op in st_close and not '關小' in query: func_tmp['value']='0'\n", "\n", " \n", "# if 'value' in func_tmp and func_tmp['value']=='':\n", "# if 'increase' in pred_class or 'decrease' in pred_class:func_tmp['value']='1'\n", "# elif ori_func_name == 'HVAC_TEMPERATURE_SET':\n", "# if '熱' in query: func_tmp['value'] = maxmin_val_map[ori_func_name]['min']\n", "# elif '冷' in query or '凍' in query: func_tmp['value'] = maxmin_val_map[ori_func_name]['max']\n", "# elif ori_func_name in default_value:func_tmp['value']=default_value[ori_func_name]\n", "\n", "\n", "# if ori_func_name in ['set_seat_mode']:\n", "# func_tmp = [{\"name\":ori_func_name,\"arguments\":func_tmp}]\n", "# elif ori_func_name in ['get_hhtd_info','get_vehicle_info']:\n", "# func_tmp['query'] = ori_query\n", "# func_tmp = [{\"name\":ori_func_name,\"arguments\":func_tmp}]\n", "# else:\n", "# func_tmp = [{\"name\":\"control_car_properties\",\"arguments\":func_tmp}]\n", "# return json.dumps(func_tmp, ensure_ascii=False)\n", "\n", "# ### Examples\n", "\n", "# output1 = postprocess(\"請打開副駕駛座前除霜\",'HVAC_DEFROSTER%true')\n", "# # outout1 = '[{\"name\": \"control_car_properties\", \"arguments\": {\"propertyId\": \"HVAC_DEFROSTER\", \"areaId\": \"FRONT_WINDSHIELD\", \"operation\": \"set\", \"value\": \"true\"}}]'\n", "\n", "# output2 = postprocess(\"冷到一直打噴嚏\",'HVAC_TEMPERATURE_SET')\n", "# # output2 = '[{\"name\": \"control_car_properties\", \"arguments\": {\"propertyId\": \"HVAC_TEMPERATURE_SET\", \"areaId\": \"\", \"operation\": \"set\", \"value\": \"32\"}}]'\n", "\n", "# output3 = postprocess(\"麻煩您將整部車風量調到最小\",'HVAC_FAN_SPEED')\n", "# # output3 = '[{\"name\": \"control_car_properties\", \"arguments\": {\"propertyId\": \"HVAC_FAN_SPEED\", \"areaId\": \"SEAT_ALL\", \"operation\": \"set\", \"value\": \"1\"}}]'\n", "\n", "# # for q in ['風再弱些謝謝','出風別那麼強','溫度有點高','風小一點謝謝','讓陽光多一些','陽光有點刺眼']:\n", "# # inference(q)\n", "# dic = {'兩':'2'}\n", "# def inference(query):\n", "# for k in dic:query=query.replace(k,dic[k])\n", "# inputs = tokenizer(query, padding=True, truncation=True, return_tensors=\"pt\").to('cuda')\n", "# with torch.no_grad():\n", "# outputs = model(**inputs)\n", "# logits = outputs.logits\n", "# confidence = max(torch.nn.functional.softmax(logits[0]))\n", "# predictions = torch.argmax(logits, dim=-1)\n", "# pred_class = id2label[predictions.cpu().numpy()[0]]\n", "# print(pred_class)\n", "# if pred_class=='others':return {},{},pred_class\n", "# return postprocess(query,pred_class)\n", "# inference(\"麻煩您將整部車風量調到最小\")" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "HVAC_POWER_ON%true\n", "[{'arguments': {'areaId': '', 'operation': 'set', 'propertyId': 'HVAC_POWER_ON', 'value': 'true'}, 'name': 'control_car_properties'}]\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/tmp/ipykernel_244741/687995418.py:36: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.\n", " confidence = max(torch.nn.functional.softmax(logits[0]))\n", "[ERROR] keywords_data.json file not found. Please ensure it's in the same directory.\n" ] } ], "source": [ "import ctypes\n", "import json\n", "\n", "\n", "lib_path = './cpp_postprocess/postprocess.so'\n", "lib = ctypes.CDLL(lib_path)\n", "\n", "\n", "# 設定函式參數和回傳值的資料型別\n", "# postprocess_c 函式接收兩個 C 字串並回傳一個 C 字串\n", "lib.postprocess_c.argtypes = [ctypes.c_char_p, ctypes.c_char_p]\n", "lib.postprocess_c.restype = ctypes.c_char_p\n", "\n", "def process_cpp(query, pred_class):\n", " # 將 Python 字串編碼為 bytes,以符合 C++ 的 char* 參數要求\n", " query_bytes = query.encode('utf-8')\n", " pred_class_bytes = pred_class.encode('utf-8')\n", " \n", " # 呼叫 C++ 函式\n", " result_ptr = lib.postprocess_c(query_bytes, pred_class_bytes)\n", " \n", " # 將回傳的 C 字串解碼為 Python 字串\n", " if result_ptr:\n", " result_str = result_ptr.decode('utf-8')\n", " # 釋放 C++ 函式動態分配的記憶體\n", " return result_str\n", " else:\n", " return None\n", "dic = {'兩':'2'}\n", "def inference_cpp(query):\n", " for k in dic:query=query.replace(k,dic[k])\n", " inputs = tokenizer(query, padding=True, truncation=True, return_tensors=\"pt\").to('cuda')\n", " with torch.no_grad():\n", " outputs = model(**inputs)\n", " logits = outputs.logits\n", " confidence = max(torch.nn.functional.softmax(logits[0]))\n", " predictions = torch.argmax(logits, dim=-1)\n", " pred_class = id2label[predictions.cpu().numpy()[0]]\n", " print(pred_class)\n", " if pred_class=='others':return {},{},pred_class\n", " return process_cpp(query,pred_class),pred_class\n", "# a = json.loads(inference_cpp(\"幫我完成第三排右側椅背往後操作\")[0])\n", "a = json.loads(inference_cpp(\"Could you please turn on the air conditioner in the last row?\")[0])\n", "\n", "# b = json.loads(inference(\"幫我完成第三排右側椅背往後操作\"))\n", "print(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "SEAT_BACKREST_ANGLE_POS%decrease\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/tmp/ipykernel_1860429/3952825593.py:155: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.\n", " confidence = max(torch.nn.functional.softmax(logits[0]))\n" ] }, { "data": { "text/plain": [ "'[{\"name\": \"control_car_properties\", \"arguments\": {\"propertyId\": \"SEAT_BACKREST_ANGLE_POS\", \"areaId\": \"SEAT_ROW_3_RIGHT\", \"operation\": \"decrease\"}}]'" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " 0%| | 0/5000 [00:00 6\u001b[0m model_out \u001b[38;5;241m=\u001b[39m inference_cpp(conv[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mvalue\u001b[39m\u001b[38;5;124m'\u001b[39m])\n\u001b[1;32m 7\u001b[0m a \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mloads(model_out[\u001b[38;5;241m0\u001b[39m]) \u001b[38;5;28;01mif\u001b[39;00m model_out[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m!=\u001b[39m{} \u001b[38;5;28;01melse\u001b[39;00m {}\n\u001b[1;32m 8\u001b[0m b \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mloads(data[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mconversations\u001b[39m\u001b[38;5;124m'\u001b[39m][idx\u001b[38;5;241m+\u001b[39m\u001b[38;5;241m1\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mvalue\u001b[39m\u001b[38;5;124m'\u001b[39m]\u001b[38;5;241m.\u001b[39mreplace(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m兩\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2\u001b[39m\u001b[38;5;124m'\u001b[39m))\n", "Cell \u001b[0;32mIn[11], line 39\u001b[0m, in \u001b[0;36minference_cpp\u001b[0;34m(query)\u001b[0m\n\u001b[1;32m 37\u001b[0m outputs \u001b[38;5;241m=\u001b[39m model(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39minputs)\n\u001b[1;32m 38\u001b[0m logits \u001b[38;5;241m=\u001b[39m outputs\u001b[38;5;241m.\u001b[39mlogits\n\u001b[0;32m---> 39\u001b[0m confidence \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mmax\u001b[39m(torch\u001b[38;5;241m.\u001b[39mnn\u001b[38;5;241m.\u001b[39mfunctional\u001b[38;5;241m.\u001b[39msoftmax(logits[\u001b[38;5;241m0\u001b[39m]))\n\u001b[1;32m 40\u001b[0m predictions \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39margmax(logits, dim\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m)\n\u001b[1;32m 41\u001b[0m pred_class \u001b[38;5;241m=\u001b[39m id2label[predictions\u001b[38;5;241m.\u001b[39mcpu()\u001b[38;5;241m.\u001b[39mnumpy()[\u001b[38;5;241m0\u001b[39m]]\n", "\u001b[0;31mKeyboardInterrupt\u001b[0m: " ] } ], "source": [ "from tqdm import tqdm\n", "wrong = []\n", "for data in tqdm(ctrl):\n", " for idx,conv in enumerate(data['conversations']):\n", " if conv['from']=='human' and data['conversations'][idx+1]['from']=='function_call':\n", " model_out = inference_cpp(conv['value'])\n", " a = json.loads(model_out[0]) if model_out[0]!={} else {}\n", " b = json.loads(data['conversations'][idx+1]['value'].replace('兩','2'))\n", " if 'value' in b[0]['arguments']:b[0]['arguments']['value'] = str(b[0]['arguments']['value'])\n", " if (a!=b):\n", " wrong.append({'query':conv['value'],'model':a,'gt':b})\n", " print(conv['value'])\n", " print(a)\n", " print(b)\n", " print(model_out[1:])\n", " print('------------')\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "36" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import ctypes\n", "import json\n", "import platform\n", "\n", "lib_path = './postprocess.so'\n", "lib = ctypes.CDLL(lib_path)\n", "lib.postprocess.argtypes = [ctypes.c_char_p, ctypes.c_char_p]\n", "lib.postprocess.restype = ctypes.c_char_p\n", "\n", "lib.free_string.argtypes = [ctypes.c_char_p]\n", "\n", "def process(query,pred_class):\n", "\n", " query_bytes = query.encode('utf-8')\n", " pred_class_bytes = pred_class.encode('utf-8')\n", "\n", " result_ptr = lib.postprocess(query_bytes, pred_class_bytes)\n", "\n", " if not result_ptr:\n", " print(\"C++ return empty\")\n", " result_json = None\n", " else:\n", " # 將 C++ 回傳的 char* 轉換為 Python 字串\n", " result_str = ctypes.string_at(result_ptr).decode('utf-8')\n", " print(f\"C++ return:\")\n", " print(result_str)\n", " \n", " # 解析 JSON\n", " result_json = json.loads(result_str)\n", "\n", " return json.dumps(result_json, indent=4, ensure_ascii=False)" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 5000/5000 [00:00<00:00, 60459.13it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "風開大一點\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'increase', 'value': '1'}}\n", "-----\n", "風開大一點\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'increase', 'value': '1'}}\n", "-----\n", "幫我把風關小\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'decrease', 'value': '1'}}\n", "-----\n", "幫我把風開大\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'increase', 'value': '1'}}\n", "-----\n", "超級熱到流汗停不下來\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_TEMPERATURE_SET', 'areaId': '', 'operation': 'set', 'value': '17'}}\n", "-----\n", "把風開強點\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'increase', 'value': '1'}}\n", "-----\n", "幫我把風關小\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'decrease', 'value': '1'}}\n", "-----\n", "幫我把風關小\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'decrease', 'value': '1'}}\n", "-----\n", "幫我把風關小\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'decrease', 'value': '1'}}\n", "-----\n", "熱到冒汗不停\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_TEMPERATURE_SET', 'areaId': '', 'operation': 'set', 'value': '17'}}\n", "-----\n", "幫我把風開大\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'increase', 'value': '1'}}\n", "-----\n", "超級熱到流汗停不下來\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_TEMPERATURE_SET', 'areaId': '', 'operation': 'set', 'value': '17'}}\n", "-----\n", "冷到開暖氣都沒用\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_TEMPERATURE_SET', 'areaId': '', 'operation': 'set', 'value': '32'}}\n", "-----\n", "幫我把風開大\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'increase', 'value': '1'}}\n", "-----\n", "把風關小\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'decrease', 'value': '1'}}\n", "-----\n", "風開大一點\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'increase', 'value': '1'}}\n", "-----\n", "把風關小\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'decrease', 'value': '1'}}\n", "-----\n", "幫我把風關小\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'decrease', 'value': '1'}}\n", "-----\n", "冷到開暖氣都沒用\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_TEMPERATURE_SET', 'areaId': '', 'operation': 'set', 'value': '32'}}\n", "-----\n", "幫我把風開大\n", "{'name': 'control_car_properties', 'arguments': {'propertyId': 'HVAC_FAN_SPEED', 'areaId': '', 'operation': 'increase', 'value': '1'}}\n", "-----\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/plain": [ "{'HVAC_FAN_SPEED', 'HVAC_TEMPERATURE_SET', 'POWER_SUNSHADE', 'WINDOW_POS'}" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from tqdm import tqdm\n", "pid = set()\n", "for data in tqdm(ctrl):\n", " for idx,conv in enumerate(data['conversations']):\n", " if conv['from']=='human' and data['conversations'][idx+1]['from']=='function_call':\n", " b = json.loads(data['conversations'][idx+1]['value'].replace('兩','2'))[0]\n", " \n", " if 'value' in b['arguments'] and str(b['arguments']['value']).isdigit() and any([sk in conv['value'] for sk in switch_keywords]):\n", " pid.add(b['arguments']['propertyId'])\n", " if b['arguments']['propertyId'] in ['HVAC_FAN_SPEED', 'HVAC_TEMPERATURE_SET']:\n", " print(conv['value'])\n", " print(b)\n", " print('-----')\n", "pid" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'name': 'control_car_properties',\n", " 'arguments': {'propertyId': 'WINDOW_POS',\n", " 'areaId': 'SEAT_ROW_2_LEFT',\n", " 'operation': 'increase'}}]" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "py10", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.16" } }, "nbformat": 4, "nbformat_minor": 2 }