{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":4829,"databundleVersionId":44847,"sourceType":"competition"}],"dockerImageVersionId":30558,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Project Dsi 206","metadata":{}},{"cell_type":"markdown","source":"- นำเข้า Library Python ที่จำเป็น","metadata":{}},{"cell_type":"code","source":"import os\nimport time\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nfrom torch.utils.data.dataset import Dataset\nfrom tqdm import tqdm\nfrom torchvision import transforms\nfrom torchvision import models\nimport torch\nfrom torch.utils.tensorboard import SummaryWriter\nfrom sklearn.metrics import precision_score, recall_score, f1_score\nfrom torch import nn\nfrom torch.utils.data.dataloader import DataLoader\nfrom matplotlib import pyplot as plt\nfrom numpy import printoptions\nimport requests\nimport tarfile\nimport random\nimport json\nfrom shutil import copyfile","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","execution":{"iopub.status.busy":"2023-11-27T15:23:44.799861Z","iopub.execute_input":"2023-11-27T15:23:44.800225Z","iopub.status.idle":"2023-11-27T15:23:44.807110Z","shell.execute_reply.started":"2023-11-27T15:23:44.800196Z","shell.execute_reply":"2023-11-27T15:23:44.806175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- ใช้ฟังก์ชัน os.walk เพื่อสำรวจ directory /kaggle/input และส่งคืน tuple ที่ประกอบด้วย path directory ปัจจุบัน (dirname), list ของ subdirectories (ซึ่งถูกละเว้นโดยใช้ _) และ list ของ file names (filenames) ใน directory ปัจจุบัน\n- input list ไฟล์และ path ของไฟล์อย่างครบถ้วนภายใน Directory ที่ระบุและ Sub Directory ของ Directory นั้น","metadata":{}},{"cell_type":"code","source":"for dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:23:44.808928Z","iopub.execute_input":"2023-11-27T15:23:44.809591Z","iopub.status.idle":"2023-11-27T15:23:44.819435Z","shell.execute_reply.started":"2023-11-27T15:23:44.809566Z","shell.execute_reply":"2023-11-27T15:23:44.818569Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- การตั้งค่าเริ่มต้น","metadata":{}},{"cell_type":"code","source":"torch.manual_seed(2020)\ntorch.cuda.manual_seed(2020)\nnp.random.seed(2020)\nrandom.seed(2020)\ntorch.backends.cudnn.deterministic = True","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:23:44.820508Z","iopub.execute_input":"2023-11-27T15:23:44.820845Z","iopub.status.idle":"2023-11-27T15:23:44.828813Z","shell.execute_reply.started":"2023-11-27T15:23:44.820814Z","shell.execute_reply":"2023-11-27T15:23:44.827914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- กำหนดฟังก์ชัน Utility extract contents ของไฟล์เก็บถาวร tar โดยจัดการกับไฟล์เก็บถาวร tar ที่ซ้อนกัน การแยกจะแสดงโดยใช้ไลบรารี tqdm ","metadata":{}},{"cell_type":"code","source":"import os, sys, tarfile # คำสั่งนำเข้า: os, sys, tarfile: โมดูล Library มาตรฐานของ Python สำหรับการโต้ตอบกับระบบปฏิบัติการและการทำงานกับไฟล์เก็บถาวร tar\nfrom tqdm import tqdm # tqdm: Library สำหรับแสดงแถบความคืบหน้าระหว่างการวนซ้ำ\ndef extract(tar_url, extract_path='.'): # ฟังก์ชันนี้ใช้พารามิเตอร์สองตัว: tar_url: URL หรือเส้นทางไปยังไฟล์เก็บถาวร tar ที่ต้องการแยก , extract_path (ไม่จำเป็น): ไดเร็กทอรีที่ควรแยกเนื้อหาของไฟล์เก็บถาวร tar โดยค่าเริ่มต้นคือไดเร็กทอรีปัจจุบัน ('.')\n    print(tar_url)\n    tar = tarfile.open(tar_url, 'r') # เปิดไฟล์เก็บถาวร tar ที่ระบุในโหมดอ่าน ('r') โดยใช้โมดูล tarfile\n    for item in tqdm(tar): # วนซ้ำผ่านแต่ละรายการ (ไฟล์หรือไดเร็กทอรี) ในไฟล์เก็บถาวร tar แสดงแถบความคืบหน้าโดยใช้ tqdm\n        tar.extract(item, extract_path) # แยกไอเท็มปัจจุบันจากไฟล์เก็บถาวร tar ไปยังเส้นทางแยกที่ระบุ\n        if item.name.find(\".tgz\") != -1 or item.name.find(\".tar\") != -1: #หากรายการปัจจุบันเป็นไฟล์เก็บถาวร tar เอง (ระบุโดยการมี \".tgz\" หรือ \".tar\" ในชื่อของมัน) ให้เรียกฟังก์ชันแยกซ้ำบนรายการนั้นโดยตรง ขั้นตอนนี้ใช้สำหรับไฟล์เก็บถาวร tar แบบฝังซ้อน\n            extract(item.name, \"./\" + item.name[:item.name.rfind('/')])\n            ","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:23:44.830165Z","iopub.execute_input":"2023-11-27T15:23:44.830481Z","iopub.status.idle":"2023-11-27T15:23:44.838401Z","shell.execute_reply.started":"2023-11-27T15:23:44.830457Z","shell.execute_reply":"2023-11-27T15:23:44.837515Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- ส่วนนี้จะ try เพื่อแยกไฟล์บีบอัดหลายไฟล์โดยใช้ฟังก์ชันชื่อ extract มีการระบุเส้นทางไปยังไฟล์บีบอัด\n- try block ดำเนินการกระบวนการแยกข้อมูล และถ้าสำเร็จ ระบบจะพิมพ์ว่า 'เสร็จสิ้น'\n- หากมีข้อยกเว้นเกิดขึ้นระหว่างการแตกไฟล์ (เช่น ไม่พบไฟล์ ข้อผิดพลาดในการแตกไฟล์) บล็อกยกเว้นจะถูกทริกเกอร์ โดยพิมพ์ 'ข้อผิดพลาด'","metadata":{}},{"cell_type":"code","source":"from tqdm import tqdm \ntry: \n    extract('../input/yelp-restaurant-photo-classification/train_photos.tgz')\n    extract('../input/yelp-restaurant-photo-classification/test_photos.tgz')\n    extract('../input/yelp-restaurant-photo-classification/train.csv.tgz')\n    extract('../input/yelp-restaurant-photo-classification/train_photo_to_biz_ids.csv.tgz')\n    extract('../input/yelp-restaurant-photo-classification/test_photo_to_biz.csv.tgz')\n    extract('../input/yelp-restaurant-photo-classification/sample_submission.csv.tgz')\n    print ('Done.')\nexcept:\n    #name = os.path.basename(sys.argv[0])\n    print('error')","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:23:44.840421Z","iopub.execute_input":"2023-11-27T15:23:44.840708Z","iopub.status.idle":"2023-11-27T15:29:51.440049Z","shell.execute_reply.started":"2023-11-27T15:23:44.840665Z","shell.execute_reply":"2023-11-27T15:29:51.438907Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- การโหลดข้อมูลจากไฟล์ CSV การเลือกคอลัมน์ของแถวโดยใช้ head() และการจัดเก็บผลลัพธ์ใน DataFrames ต่างๆ (train_csvids, test_csvids, train และ sub)","metadata":{}},{"cell_type":"code","source":"import pandas as pd\ntrain_csvids=pd.read_csv('./train_photo_to_biz_ids.csv')\ntrain_csvids=train_csvids.head(5000)\ntest_csvids=pd.read_csv('./test_photo_to_biz.csv')\ntest_csvids=test_csvids.head(1000)\ntrain=pd.read_csv('./train.csv')\ntrain=train.head(1000)\nsub=pd.read_csv('./sample_submission.csv')\ntrain_csvids.head()","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:51.441602Z","iopub.execute_input":"2023-11-27T15:29:51.441975Z","iopub.status.idle":"2023-11-27T15:29:51.859633Z","shell.execute_reply.started":"2023-11-27T15:29:51.441942Z","shell.execute_reply":"2023-11-27T15:29:51.858721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"-  รวม DataFrames เมื่อรวมส่วนข้อมูลต่างๆ โดยใช้คีย์ที่ใช้ร่วมกัน (ในกรณีนี้คือ 'business_id') จำกัดจำนวนแถวด้วย head(5000)","metadata":{}},{"cell_type":"code","source":"data=pd.merge(train_csvids,train, on='business_id',how='left')\ndata=data.head(5000)","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:51.861004Z","iopub.execute_input":"2023-11-27T15:29:51.861392Z","iopub.status.idle":"2023-11-27T15:29:51.881552Z","shell.execute_reply.started":"2023-11-27T15:29:51.861357Z","shell.execute_reply":"2023-11-27T15:29:51.880825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_test=pd.merge(test_csvids,sub, on='business_id',how='left') \ndata_test.head()","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:51.882606Z","iopub.execute_input":"2023-11-27T15:29:51.882896Z","iopub.status.idle":"2023-11-27T15:29:52.323752Z","shell.execute_reply.started":"2023-11-27T15:29:51.882865Z","shell.execute_reply":"2023-11-27T15:29:52.322750Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- โค้ดนี้เพื่อจัดการกับค่าที่หายไปในคอลัมน์ 'labels' ของ DataFrame (data) ","metadata":{}},{"cell_type":"code","source":"data=data.dropna(subset=['labels'])\ndata.head()","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.324976Z","iopub.execute_input":"2023-11-27T15:29:52.325378Z","iopub.status.idle":"2023-11-27T15:29:52.337965Z","shell.execute_reply.started":"2023-11-27T15:29:52.325341Z","shell.execute_reply":"2023-11-27T15:29:52.337071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- แปลงคอลัมน์ 'labels' ซึ่งคาดว่ามีค่าสตริงที่คั่นด้วยช่องว่าง(\" \") ให้เป็นคอลัมน์ 'labs' ใหม่ที่มีรายการสตริง ","metadata":{}},{"cell_type":"code","source":"data['labs']=data['labels'].apply(lambda x:str(x).split(' '))\ndata","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.342159Z","iopub.execute_input":"2023-11-27T15:29:52.342496Z","iopub.status.idle":"2023-11-27T15:29:52.362648Z","shell.execute_reply.started":"2023-11-27T15:29:52.342459Z","shell.execute_reply":"2023-11-27T15:29:52.361732Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- labelsint = data.labs.tolist(): ดึงเอา labels จาก object 'data' และแปลงเป็น list ที่ซ้อนกันชื่อ 'labelsint'\n- for i in tqdm(labelsint):: วนซ้ำ list ด้านนอกของ label โดยใช้ library tqdm เพื่อแสดงแถบความคืบหน้า\n- for j in range(len(i)):: วนซ้ำ sublist ของ labels ภายใน และ ภายนอก list\n- i[j] = int(i[j]): แปลงแต่ละ Label แต่ละList ใน sublist เป็นจำนวนเต็ม\n\n- labels ถูกเก็บเป็นสตริงในตอนแรกและ ต้องแปลงเป็นค่าจำนวนเต็มเพื่อการประมวลผลตัวเลขหรือการ train model","metadata":{}},{"cell_type":"code","source":"labelsint=data.labs.tolist()\nfor i in tqdm(labelsint):\n    for j in range(len(i)):\n        #print(j)\n        #break\n        i[j]=int(i[j])\n    ","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.363878Z","iopub.execute_input":"2023-11-27T15:29:52.364155Z","iopub.status.idle":"2023-11-27T15:29:52.382418Z","shell.execute_reply.started":"2023-11-27T15:29:52.364131Z","shell.execute_reply":"2023-11-27T15:29:52.381544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- เพิ่มคอลัมน์ใหม่ 'labsint' ลงใน DataFrame ","metadata":{}},{"cell_type":"code","source":"data['labsint']=labelsint\ndata","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.383577Z","iopub.execute_input":"2023-11-27T15:29:52.384169Z","iopub.status.idle":"2023-11-27T15:29:52.405453Z","shell.execute_reply.started":"2023-11-27T15:29:52.384135Z","shell.execute_reply":"2023-11-27T15:29:52.404541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- สร้างชุดข้อมูลแยกกัน2ชุดสำหรับการ train และ test ความถูกต้องของโมเดล ","metadata":{}},{"cell_type":"code","source":"from sklearn import metrics, model_selection, preprocessing\nTrain_df, Valid_df = model_selection.train_test_split(\n        data, test_size=0.1, random_state=42\n)","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.406675Z","iopub.execute_input":"2023-11-27T15:29:52.406990Z","iopub.status.idle":"2023-11-27T15:29:52.442569Z","shell.execute_reply.started":"2023-11-27T15:29:52.406964Z","shell.execute_reply":"2023-11-27T15:29:52.441740Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- __init__: เริ่มต้น dataset โดยการโหลดข้อมูล sample และ labels และแปลง labels เป็น vector binary\n\n- __getitem__: ดึงlist จากdataset โหลดรูปภาพ และใช้การแปลง\n\n- __len__: Return total number ของ items ใน dataset","metadata":{}},{"cell_type":"code","source":"class TimeDataset(Dataset):\n    def __init__(self, data_path, data, transforms):\n        self.transforms = transforms\n        data=data\n        samples = data['photo_id'].tolist()\n        labs=data['labsint'].tolist()\n        self.classes = [0,1,2,3,4,5,6,7,8]\n\n        self.imgs = []\n        self.annos = []\n        self.data_path = data_path\n        #print('loading', anno_path)\n        for sample in samples:\n            self.imgs.append(sample)\n        for lab in labs:\n            self.annos.append(lab)\n            \n        for item_id in range(len(self.annos)):\n            item = self.annos[item_id]\n            vector = [cls in item for cls in self.classes]\n            self.annos[item_id] = np.array(vector, dtype=float)\n\n    def __getitem__(self, item):\n        anno = self.annos[item]\n        img_path = os.path.join(self.data_path, str(self.imgs[item])+'.jpg')\n        img = Image.open(img_path)\n        if self.transforms is not None:\n            img = self.transforms(img)\n        return img, anno\n\n        \n\n    def __len__(self):\n        return len(self.imgs)","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.443860Z","iopub.execute_input":"2023-11-27T15:29:52.444183Z","iopub.status.idle":"2023-11-27T15:29:52.454632Z","shell.execute_reply.started":"2023-11-27T15:29:52.444155Z","shell.execute_reply":"2023-11-27T15:29:52.453885Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- กำหนด Network Model ที่กำหนดเองชื่อ Resnext50 โดยใช้ nn.Module ของ PyTorch โมเดลนี้ใช้ architecture resnext50_32x4d จาก torchvision พร้อมด้วย layer ปรับเปลี่ยนสำหรับจำนวนคลาส output ที่ระบุไว้","metadata":{}},{"cell_type":"code","source":"Valid_Dataset = TimeDataset('./train_photos', Valid_df, None)\nTrain_Dataset = TimeDataset('./train_photos', Train_df, None)\n\n\nclass ARH_R50(nn.Module):\n    def __init__(self, n_classes):\n        super().__init__()\n        resnet = models.resnext50_32x4d(pretrained=True)\n        resnet.fc = nn.Sequential(\n            nn.Dropout(p=0.2),\n            nn.Linear(in_features=resnet.fc.in_features, out_features=n_classes)\n        )\n        self.base_model = resnet\n        self.sigm = nn.Sigmoid()\n\n    def forward(self, x):\n        return self.sigm(self.base_model(x))","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.455972Z","iopub.execute_input":"2023-11-27T15:29:52.456248Z","iopub.status.idle":"2023-11-27T15:29:52.477432Z","shell.execute_reply.started":"2023-11-27T15:29:52.456225Z","shell.execute_reply":"2023-11-27T15:29:52.476507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- calculate_metrics: ฟังก์ชันนี้รับเอาต์พุต (pred), (target) และค่าเกณฑ์เสริมสำหรับการแปลง Binary ของการ predict มันคำนวณเมตริกการจัดประเภทต่างๆ รวมถึง accuracy แบบ Micro, Macro และ Sample, return และ score F1 ผลลัพธ์จะถูกส่งคืนเป็น dictionary\n\n- เมตริกเหล่านี้ใช้กันทั่วไปสำหรับการประเมิน Model Classification","metadata":{}},{"cell_type":"code","source":"def Model_Evaluate(pred, target, threshold=0.5):\n    pred = np.array(pred > threshold, dtype=float)\n    return {'micro/precision': precision_score(y_true=target, y_pred=pred, average='micro'),\n            'micro/recall': recall_score(y_true=target, y_pred=pred, average='micro'),\n            'micro/f1': f1_score(y_true=target, y_pred=pred, average='micro'),\n            'macro/precision': precision_score(y_true=target, y_pred=pred, average='macro'),\n            'macro/recall': recall_score(y_true=target, y_pred=pred, average='macro'),\n            'macro/f1': f1_score(y_true=target, y_pred=pred, average='macro'),\n            'samples/precision': precision_score(y_true=target, y_pred=pred, average='samples'),\n            'samples/recall': recall_score(y_true=target, y_pred=pred, average='samples'),\n            'samples/f1': f1_score(y_true=target, y_pred=pred, average='samples'),\n            }","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.478727Z","iopub.execute_input":"2023-11-27T15:29:52.479201Z","iopub.status.idle":"2023-11-27T15:29:52.488174Z","shell.execute_reply.started":"2023-11-27T15:29:52.479168Z","shell.execute_reply":"2023-11-27T15:29:52.487247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Hyperparameter และการ setting เหล่านี้จำเป็นสำหรับการกำหนดค่ากระบวนการ train การปรับเปลี่ยนอาจขึ้นอยู่กับ Dataset และ Model behavior รอบการ train จะใช้ parameter เหล่านี้ในระหว่างการวนซ้ำ","metadata":{}},{"cell_type":"code","source":"\n# Initialize the training parameters.\nnum_workers = 8 \nlr = 1e-4 # Learning rate\nbatch_size = 64\nsave_freq = 35 # checkpoint frequency (epochs)\ntest_freq = 200 # Test model frequency (iterations)\nmax_epoch_number = 15 # Number of epochs for training \n\n\nmean = [0.485, 0.456, 0.406]\nstd = [0.229, 0.224, 0.225]\n\ndevice = torch.device('cuda')\n# Save path for checkpoints\nsave_path = 'chekpoints/'\n# Save path for logs\nlogdir = 'logs/'\n","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.489303Z","iopub.execute_input":"2023-11-27T15:29:52.489573Z","iopub.status.idle":"2023-11-27T15:29:52.501874Z","shell.execute_reply.started":"2023-11-27T15:29:52.489549Z","shell.execute_reply":"2023-11-27T15:29:52.500965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- ฟังก์ชันนี้ออกแบบมาเพื่อบันทึก Check point ของโมเดล PyTorch ในระหว่างการ train ","metadata":{}},{"cell_type":"code","source":"def Save_Checkpoints(model, save_path, epoch):\n    f = os.path.join(save_path, 'checkpoint-{:06d}.pth'.format(epoch))\n    if 'module' in dir(model):\n        torch.save(model.module.state_dict(), f)\n    else:\n        torch.save(model.state_dict(), f)\n    print('Save Checkpoint:', f)","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.503067Z","iopub.execute_input":"2023-11-27T15:29:52.503329Z","iopub.status.idle":"2023-11-27T15:29:52.511713Z","shell.execute_reply.started":"2023-11-27T15:29:52.503307Z","shell.execute_reply":"2023-11-27T15:29:52.510731Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- การแปลงนี้จะนำไปใช้กับรูปภาพ input ในระหว่างขั้นตอนการ train และ check ช่วยให้แบบ Model สรุปได้ดีขึ้นโดยแนะนำรูปแบบต่างๆ ในชุดการ train และรับรองความเข้ากันในการประมวลผลล่วงหน้าระหว่าง train และ test ","metadata":{}},{"cell_type":"code","source":"val_transform = transforms.Compose([\n    transforms.Resize((256, 256)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean, std)\n])\nprint(tuple(np.array(np.array(mean)*255).tolist()))\n\n# Train preprocessing\ntrain_transform = transforms.Compose([\n    transforms.Resize((256, 256)),\n    transforms.RandomHorizontalFlip(),\n    transforms.ColorJitter(),\n    transforms.RandomAffine(degrees=20, translate=(0.2, 0.2), scale=(0.5, 1.5),\n                            shear=None, interpolation=False, \n                            fill=tuple(np.array(np.array(mean)*255).astype(int).tolist())),\n    transforms.ToTensor(),\n    transforms.Normalize(mean, std)\n])","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.513017Z","iopub.execute_input":"2023-11-27T15:29:52.513293Z","iopub.status.idle":"2023-11-27T15:29:52.522467Z","shell.execute_reply.started":"2023-11-27T15:29:52.513262Z","shell.execute_reply":"2023-11-27T15:29:52.521628Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Hyperparameter และ Achitecture Model สามารถเปลี่ยนแปลงได้ตามความคืบหน้าในการ train สังเกตได้ จากloopการ train และ Tensorboard logger ช่วยให้เห็นภาพและติดตามกระบวนการ train","metadata":{}},{"cell_type":"code","source":"#test_annotations = os.path.join(img_folder, 'small_test.json')\n#train_annotations = os.path.join(img_folder, 'small_train.json')\n\nTest_Dataset = TimeDataset('./train_photos', Valid_df, val_transform)\nTrain_Dataset = TimeDataset('./train_photos', Train_df, train_transform)\n\n\n\nTrain_dataloader = DataLoader(Train_Dataset, batch_size=batch_size, num_workers=num_workers, shuffle=True,\n                              drop_last=True)\nTest_dataloader = DataLoader(Test_Dataset, batch_size=batch_size, num_workers=num_workers)\n\nnum_train_batches = int(np.ceil(len(Train_Dataset) / batch_size))\n\n# Initialize the model\nmodel = ARH_R50(len(Train_Dataset.classes))\n# Switch model to the training mode and move it to GPU.\nmodel.train()\nmodel = model.to(device)\n\noptimizer = torch.optim.Adam(model.parameters(), lr=lr)\n\n\nif torch.cuda.device_count() > 1:\n    model = nn.DataParallel(model)\n\nos.makedirs(save_path, exist_ok=True)\n\n# Loss function\ncriterion = nn.BCELoss()\n# Tensoboard logger\nlogger = SummaryWriter(logdir)","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:29:52.523522Z","iopub.execute_input":"2023-11-27T15:29:52.523811Z","iopub.status.idle":"2023-11-27T15:30:01.333753Z","shell.execute_reply.started":"2023-11-27T15:29:52.523787Z","shell.execute_reply":"2023-11-27T15:30:01.332985Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- โค้ดนี้แสดงถึงลูปการ typical training loop สำหรับการ train model network\n- โดยจะ loop ใน epoch และ bath ดำเนิน forward and backward passes logs training loss และ metrics evaluates model ใน test set ที่ระบุความถี่ และบันทึกcheckpoint\n- การloop จะดำเนินต่อไปจนกว่าจะถึง maximum number ของ epoch.\n","metadata":{}},{"cell_type":"code","source":"epoch = 0\niteration = 0\nbest = [0,0,0]\nwhile True:\n    batch_losses = []\n    for imgs, targets in tqdm(Train_dataloader):\n        imgs, targets = imgs.to(device), targets.to(device)\n\n        optimizer.zero_grad()\n\n        model_result = model(imgs)\n        loss = criterion(model_result, targets.type(torch.float))\n\n        batch_loss_value = loss.item()\n        loss.backward()\n        optimizer.step()\n\n        logger.add_scalar('train_loss', batch_loss_value, iteration)\n        batch_losses.append(batch_loss_value)\n        with torch.no_grad():\n            result = Model_Evaluate(model_result.cpu().numpy(), targets.cpu().numpy())\n            for metric in result:\n                logger.add_scalar('train/' + metric, result[metric], iteration)\n\n        if iteration % test_freq == 0:\n            model.eval()\n            with torch.no_grad():\n                model_result = []\n                targets = []\n                for imgs, batch_targets in tqdm(Test_dataloader):\n                    imgs = imgs.to(device)\n                    model_batch_result = model(imgs)\n                    model_result.extend(model_batch_result.cpu().numpy())\n                    targets.extend(batch_targets.cpu().numpy())\n\n            result = Model_Evaluate(np.array(model_result), np.array(targets))\n            for metric in result:\n                logger.add_scalar('test/' + metric, result[metric], iteration)\n#             print(\"epoch:{:2d} iter:{:3d} test: \"\n#                   \"micro f1: {:.3f} \"\n#                   \"macro f1: {:.3f} \"\n#                   \"samples f1: {:.3f}\".format(epoch, iteration,\n#                                               result['micro/f1'],\n#                                               result['macro/f1'],\n#                                               result['samples/f1']))\n            \n            best[0]= max([best[0],result['micro/f1']])\n            best[1]= max([best[1],result['macro/f1']])\n            best[2]= max([best[2],result['samples/f1']])\n            model.train()\n        iteration += 1\n\n    loss_value = np.mean(batch_losses)\n    print(\"epoch:{:2d} iter:{:3d} train: loss:{:.3f}\".format(epoch, iteration, loss_value))\n    if epoch % save_freq == 0:\n        Save_Checkpoints(model, save_path, epoch)\n    epoch += 1\n    if max_epoch_number < epoch:\n        break","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:30:01.335144Z","iopub.execute_input":"2023-11-27T15:30:01.335514Z","iopub.status.idle":"2023-11-27T15:47:56.020420Z","shell.execute_reply.started":"2023-11-27T15:30:01.335480Z","shell.execute_reply":"2023-11-27T15:47:56.019263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- โค้ดนี้สร้างตัวอย่างสุ่ม 10 ตัวอย่าง (res) จากช่วง 0 ถึง 251\n- print score F1 ที่ดีที่สุดของ Micro, Macro และ Samples\n- Model ถูกตั้งค่าเป็นโหมดการประเมินและมีการกำหนดคำอธิบายภาพสำหรับการอ่านที่ง่ายขึ้น\n- จากนั้นจะวนซ้ำผ่านตัวอย่างที่เลือกแบบสุ่ม ทำการอนุมาน และแสดงภาพทดสอบพร้อมป้ายกำกับที่คาดการณ์ไว้","metadata":{}},{"cell_type":"code","source":"import random\n\nres = random.sample(range(0, 251), 10)\n\nprint(\"Micro F1 : \"+str(best[0])+\"  Macro F1 : \"+str(best[1])+ \"     Samples F1 : \"+str(best[2]))\n\nmodel.eval()\nlabel_notation = {0: 'good_for_lunch', 1: 'good_for_dinner', 2: 'takes_reservations',  3: 'outdoor_seating',\n                  4: 'restaurant_is_expensive', 5: 'has_alcohol', 6: 'has_table_service', 7: 'ambience_is_classy',\n                  8: 'good_for_kids'}\nif torch.cuda.is_available():\n    model.cuda()\nfor sample_id in res:\n    test_img, test_labels = Test_Dataset[sample_id]\n    print(type(test_img))\n    test_img = test_img.cuda()\n    test_img_path = os.path.join('./train_photos', str(Test_Dataset.imgs[sample_id])+'.jpg')\n    with torch.no_grad():\n        raw_pred = model(test_img.unsqueeze(0)).cpu().numpy()[0]\n        raw_pred = np.array(raw_pred > 0.5, dtype=float)\n\n    predicted_labels = np.array(Valid_Dataset.classes)[np.argwhere(raw_pred > 0)[:, 0]]\n    if not len(predicted_labels):\n        predicted_labels = ['no predictions']\n    img_labels = np.array(Valid_Dataset.classes)[np.argwhere(test_labels > 0)[:, 0]]\n    \n    result = [label_notation[p] for p in predicted_labels]\n    expected = [label_notation[p] for p in img_labels]\n    plt.imshow(Image.open(test_img_path))\n    print(\"result =\", result)\n    print(\"expected =\", expected)\n    plt.axis('off')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-27T15:47:56.022383Z","iopub.execute_input":"2023-11-27T15:47:56.023146Z","iopub.status.idle":"2023-11-27T15:47:58.426676Z","shell.execute_reply.started":"2023-11-27T15:47:56.023103Z","shell.execute_reply":"2023-11-27T15:47:58.425742Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Test model\n","metadata":{}},{"cell_type":"code","source":"def to_device(data, device):\n    \"\"\"Move tensor(s) to chosen device\"\"\"\n    if isinstance(data, (list,tuple)):\n        return [to_device(x, device) for x in data]\n    return data.to(device, non_blocking=True)\nprint(\"pass\")","metadata":{"execution":{"iopub.status.busy":"2023-11-27T16:10:36.011668Z","iopub.execute_input":"2023-11-27T16:10:36.012396Z","iopub.status.idle":"2023-11-27T16:10:36.018238Z","shell.execute_reply.started":"2023-11-27T16:10:36.012358Z","shell.execute_reply":"2023-11-27T16:10:36.017229Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def decode_target(target, text_labels=False, threshold=0.5):\n    result = []\n    for i, x in enumerate(target):\n        if (x >= threshold):\n            if text_labels:\n                result.append(label_notation[i] + \"(\" + str(i) + \")\")\n            else:\n                result.append(str(i))\n    return ' '.join(result)\nprint(\"pass\")","metadata":{"execution":{"iopub.status.busy":"2023-11-27T16:19:26.302047Z","iopub.execute_input":"2023-11-27T16:19:26.303003Z","iopub.status.idle":"2023-11-27T16:19:26.309625Z","shell.execute_reply.started":"2023-11-27T16:19:26.302965Z","shell.execute_reply":"2023-11-27T16:19:26.308575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_sample(test_img_tensor, target, invert=False):\n    img = test_img_tensor.cpu().numpy().transpose((1, 2, 0))  # Convert to NumPy array\n    if invert:\n        img = 1 - img\n    plt.imshow(img)\n    print('Labels:', decode_target(target, text_labels=True))\n","metadata":{"execution":{"iopub.status.busy":"2023-11-27T16:19:27.777377Z","iopub.execute_input":"2023-11-27T16:19:27.778391Z","iopub.status.idle":"2023-11-27T16:19:27.785659Z","shell.execute_reply.started":"2023-11-27T16:19:27.778346Z","shell.execute_reply":"2023-11-27T16:19:27.784378Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict_img(test_img_tensor):\n    pat = test_img_tensor.unsqueeze(0)\n    pat = to_device(pat, device)\n    preds = model(pat)\n    prediction = preds[0]\n    print(\"Prediction: \", prediction)\n    print(\"result =\", result)\n    print(\"expected =\", expected)\n    show_sample(test_img_tensor, prediction)\n\nprint(\"pass\")","metadata":{"execution":{"iopub.status.busy":"2023-11-27T16:23:21.705726Z","iopub.execute_input":"2023-11-27T16:23:21.706102Z","iopub.status.idle":"2023-11-27T16:23:21.712620Z","shell.execute_reply.started":"2023-11-27T16:23:21.706072Z","shell.execute_reply":"2023-11-27T16:23:21.711489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predict_img(Test_Dataset[49][0])","metadata":{"execution":{"iopub.status.busy":"2023-11-27T16:23:50.770729Z","iopub.execute_input":"2023-11-27T16:23:50.771103Z","iopub.status.idle":"2023-11-27T16:23:51.079031Z","shell.execute_reply.started":"2023-11-27T16:23:50.771075Z","shell.execute_reply":"2023-11-27T16:23:51.077872Z"},"trusted":true},"execution_count":null,"outputs":[]}]}