{"cells":[{"metadata":{},"cell_type":"markdown","source":"สวัสดีครับ เพื่อนๆ สำหรับ Deep Learning Workshop อันดับ 7 ของ **[ThAIKeras](http://www.thaikeras.com)** นี้ เราจะว่ากันด้วยหนึ่งในเรื่องที่สำคัญสุดๆ สำหรับ Machine Learning บน Computer Vision นั่นคือเรื่องของ **Data Augmentation หรือ การเพิ่มปริมาณข้อมูลภาพสอน (จากข้อมูลภาพเดิม)** \n\nเนื่องจากประสิทธิภาพความแม่นยำของโมเดลในตระกูล Deep Learning นั้นขึ้นกับปริมาณข้อมูลเป็นปัจจัยสำคัญอันดับหนึ่ง (เทียบเท่ากับปัจจัยสถาปัตยกรรมนิวรอนที่ยอดเยี่ยม) ดังนั้นเทคนิก Data Augmentation ที่เราจะทำกันใน Workshop นี้จึงมีประโยชน์มากๆ และเพิ่มความสามารถให้กับโมเดลเราได้อย่างมาก นอกจากนี้สามารถประยุกต์ใช้กับงานด้าน Computer Vision ได้แทบทุกประเภทเลยครับ\n\nในการ Augment ที่มีประสิทธิภาพทางปฏิบัตินั้น นอกจากจะต้องฝึกใช้ library tool ที่ดีเช่น Albumentations อย่างที่แนะนำใน Workshop นี้แล้ว การเลือก Augmentation ที่เหมาะสมยังเป็นทั้งศาสตร์และศิลป์ที่เราต้องเจาะปัญหาให้เข้าใจลึกซึ้งอีกด้วย ซึ่งเราก็จะพูดถึงเรื่องเหล่านี้ใน Workshop นี้เช่นกันครับ\n\nโดย Workshop นี้แม้ัจะเป็นภาคต่อที่สองของปัญหา **การตรวจสอบเบาหวานในดวงตา (AI for Eyes ภาค 2) ที่ Kaggle ร่วมกับ Aravind Eye Hospital เพื่อแก้ปัญหาที่ทำให้ผู้คนตาบอดมากที่สุดอย่างยั่งยืน** ทว่าเพื่อนๆ ก็สามารถนำความรู้ใน Workshop นี้เข้าไปประยุกต์ได้กับงานอื่นๆ ใน Computer Vision หรือรูปภาพประเภทอื่นๆ ได้อย่างง่ายดายด้วยหลักการเดียวกัน\n\nเพื่อนๆ สามารถดู[ภาค 1 และที่มาของปัญหาได้ที่นี่ครับ](https://www.kaggle.com/ratthachat/workshop-ai-for-eyes-1) หรือ[สามารถดูและฝึกทำ AI/Data Science Workshops อื่นๆ ทั้งหมดของทีมงานได้ที่นี่ครับ](https://thaikeras.com/category/workshop/)\n\n# 1. Introduction : ว่าด้วยแก่นของ \"การเรียนรู้\"\n\nกระบวนการที่สำคัญของ Machine Learning คือ การสร้าง \"โมเดล\" จากข้อมูลสอน (Training Data) โดยโมเดลที่เรียนได้นั้น ก็เป็นตัวแทนของ \"ความรู้\" ที่ได้จาก Training Data นั่นเอง และหัวใจสำคัญของ \"ความรู้ที่แท้จริง\" นั้นคือ \"ต้องนำไปใช้ต่อได้ในอนาคต\" (ไม่ใช่สักแต่ท่อง :)\n\nตัวอย่างง่ายๆ ที่บ่งว่า**การ \"จดจำ\" Training Data ได้ 100% นั้นอาจไม่นับเป็นการเรียนรู้** อาทิ เช่น สมมติเราสร้างโมเดลให้เรียนรู้ว่าอะไรคือ \"กระรอก\" จากภาพตัวอย่างหลายภาพ โดยหนึ่งใน Training Data อาจเป็นภาพด้านล่าง (credit รูปภาพ: https://github.com/aleju/imgaug)\n![](https://raw.githubusercontent.com/aleju/imgaug-doc/master/readme_images/small_overview/noop_image.jpg)\n\nเมื่อเราสอนโมเดลของเราด้วย Training Data และโมเดลนั้นแม่นยำ 100% บน Training Data นี้ เราอาจเข้าใจไปว่าโมเดลของเรารู้แล้วว่ากระรอกหน้าตาเป็นอย่างไร \n\nทว่าความจริงอาจไม่เป็นอย่างที่คิด โดยโมเดลของเราอาจจะ \"ลักไก่\" ด้วยการจำส่วนประกอบอื่นๆ ที่ไม่สำคัญบนภาพ หรือท่องจำแบบไม่เข้าใจอะไรก็เป็นได้ เช่น ถ้าเราซูมภาพนี้เข้ามาอีกนิด\n\n![](https://i.ibb.co/KVPvjRH/AI-for-Eyes-Spurious-Squrrel.png)\n\n* จำว่าถ้ามีวัตถุสามเหลี่ยมสีดำๆ อยู่เมื่อไร ภาพนั้นคือกระรอก\n* จำว่าถ้าตรวจเจอแสงแดดกระทบขนสีขาวๆ ภาพนั้นคือกระรอก\n* จำว่ากระรอกต้องมีดวงตา ปาก จมูกแบบที่เห็นในรูปเป้ะๆ (ถ้าหน้าตาผิดเพี้ยนไปแม้นแต่ pixel เดียว ก็ไม่ใช่กระรอก)\n* และอื่นๆ อีกมากมายที่เป็นลักษณะท่องจำรายละเอียดในรูปตัวอย่างที่ไม่เกี่ยวกับ \"ความเป็นกระรอก\" จริงๆ\n\n## 1.2 ปัญหา Overfitting และทางแก้ด้วย Data Augmentation\n\nประเด็นข้างต้นนั้นเป็นตัวอย่างของปัญหา **overfitting** ที่เป็นประเด็นสำคัญที่สุด ใน Machine Learning ... **หนึ่งในวิธีการแก้ Overfitting แบบง่ายๆ แต่ได้ผล ก็คือ \"การเพิ่มจำนวน Training Data\" เข้าไป** เช่น เพิ่มรูปกระรอกอื่นๆ ไม่มีวัตถุสามเหลี่ยม ไม่มีแสงแดด หรือกระรอกหน้าตาอื่นๆ เหล่านี้จะทำให้โมเดลจดจำสิ่งที่ไม่จำเป็นได้ยากขึ้น และพยายามจดจำลักษณะอื่นๆ หรือเรียนรู้ \"ความรู้\" ที่เป็นจริงสำหรับกระรอกทุกภาพได้ดีขึ้น (เช่น \"รูปทรงของตา\" จะมีลักษณะทรงกลมหรือทรงรีสีดำ ขนาดใดก็ได้ เป็นต้น)\n\nอย่างไรก็ดีในกรณีที่เราไม่สามารถหา Training Data มาเพิ่มได้ เราอาจจะใช้เทคนิกที่สำคัญมากสำหรับ Machine Learning โดยเฉพาะ Computer Vision นั่นคือ **\"Data Augmentation\"** หรือ **การสร้างภาพใหม่ โดยการดัดแปลงภาพเดิมที่เรามี** อาทิเช่น เราอาจบิด ตัด หมุน เปลี่ยนสี ทำภาพให้มืดหรือสว่างขึ้น หรือใส่ noise ลงไปใน ถ้าเราลองทำกระบวนการเหล่านี้กับภาพข้างต้น จะได้ผลลัพธ์ทำนองนี้ (สังเกตว่ามนุษย์ยังมองออกว่าเป็นกระรอกเหมือนเดิม)\n\n![](https://imgaug.readthedocs.io/en/latest/_images/heavy.jpg)\n\nเห็นไหมครับ ไอเดียง่ายๆ นี้ทำให้เรามีภาพกระรอกเพิ่มขึ้นอย่างไม่จำกัดจำนวนเลยทีเดียว และทำให้โมเดลของเราลักไก่ยากขึ้นมากๆๆ เนื่องจากถ้าไปจำลักษณะอะไรที่ไม่ได้บ่งบอกถึงกระรอกจริงๆ ก็อาจจะไม่เป็นจริงอีกต่อไปใน Augmented Training Data (จากเดิม \"ลักไก่\" ง่ายกว่า \"เรียนความรู้\" พอเราเพิ่ม augmented data เข้าไปจะกลายเป็นว่าเรียนรู้จริงๆ ง่ายกว่าลักไก่) \n\nอย่างไรก็ตามการทำ Data Augmentation นั้นมีกุญแจสำคัญที่ต้องท่องจำขึ้นใจนั่นก็คือ **การทำ Augmentation นั้นจะต้องไม่เปลี่ยนแปลงธรรมชาติของข้อมูลต้นฉบับมากเกินไป** ตัวอย่างเช่น ภาพกระรอกข้างบน ถ้าเราไม่ระวังทำการเบลอภาพอย่างรุนแรงอาจทำให้เอกลักษณ์ของกระรอกเสียไป (มนุษย์มองออกยาก) และทำให้การเรียนรู้ด้อยประสิทธิภาพลงได้\n\nในทางปฏิบัตินั้นการทำ Data Augmentation ที่เหมาะสมกลายเป็นเครื่องมือมาตรฐานที่ช่วยเพิ่มความสามารถของโมเดลในงาน Computer Vision ได้อย่างมาก และในปัญหา **ตรวจสอบเบาหวานในดวงตา** ที่เรากำลังสนใจอยู่นี้ก็เช่นกันครับ เราจะมาเรียนรู้วิธีการทำ Data Augmentation ที่เหมาะสมต่างๆ กัน"},{"metadata":{},"cell_type":"markdown","source":"# 2. เตรียมข้อมูล ฟังก์ชันที่จำเป็น และทำความรู้จัก Augmentation Operations เบื้องต้น\n\nในปัจจุบันนั้นมี Library ที่ช่วยทำ Data Augmentation บน Python / Numpy / Keras อยู่มากมายหลายแห่ง โดย library ที่เราเลือกมาให้เพื่อนๆ นั้นมีชื่อว่า **Albumentations** เป็น Library ที่ได้ชื่อว่าทำ augmentation ได้รวดเร็วที่สุดและมีความหลากหลายครบทวน ซึ่งทีมงาน Albumentation นั้นก็เป็นเหล่าผู้เชี่ยวชาญบน Kaggle นั้นเองครับ โดยบน Kaggle นั้นเพื่อนๆ สามารถ import albumentations มาได้ทันทีครับ\n\nเพื่อนๆ ที่สนใจสามารถดู [Paper Albumentations บน ArXiv ได้ที่นี่ครับ](https://arxiv.org/abs/1809.06839)"},{"metadata":{"trusted":true},"cell_type":"code","source":"# สำหรับเพื่อนๆ ที่ไม่ได้ทำบน Kaggle สามารถ install ได้ด้วยคำสั่ง\n# pip install albumentations\n# ครับ\nfrom albumentations import * ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"นอกจากนี้เราก็โหลด libraries มาตรฐานอื่นๆ มาไว้พร้อมกันตรงนี้ครับ"},{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"import json\nimport math\nimport os\n\nimport cv2\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom tqdm import tqdm\n\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 2.1 เตรียมข้อมูลภาพ(ดวงตา) และฟังก์ชันที่จำเป็น\n\nเราจะนำวิธีการโหลดข้อมูล รวมทั้งการ Preprocessing มาจากภาค 1 เลยนะครับ เพื่อนสามารถทบทวน[ภาค 1 ได้ที่ลิงก์นี้](https://www.kaggle.com/ratthachat/workshop-ai-for-eyes-1)ครับ หรือเพื่อนๆ ที่ต้องการประยุกต์เทคนิกนี้กับภาพประเภทอื่นๆ ก็สามารถเตรียมข้อมูลได้ในลักษณะเดียวกันครับ"},{"metadata":{"trusted":true},"cell_type":"code","source":"# ภาพฝึกสอนจะอยู่ใน directory train_images\n# โดยข้อมูลชื่อภาพและระดับความรุนแรงของดวงตาจะอยู่ใน train.csv\n!ls ../input/\nprint('\\nข้างล่างคือตัวอย่างไฟล์ภาพที่เรามี ...\\n')\n!ls ../input/train_images | head","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train = pd.read_csv('../input/train.csv')\ndf_train.head() # ชื่อไฟล์ (เราต้องใส่ full path และ .png เข้าไปเองตอนโหลด) รวมทั้งระดับความรุนแรงของโรคเบาหวานในดวงตา","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"เพื่อความสะดวกเราจะเก็บชื่อไฟล์รูปไว้ในตัวแปร Numpy `x` และระดับความรุนแรงใน `y`"},{"metadata":{"trusted":true},"cell_type":"code","source":"# df_train['diagnosis'].hist() # เอา comment ออกถ้าเพื่อนๆ อยากเห็น severity distribution histogram\nx = df_train['id_code'].values\ny = df_train['diagnosis'].values","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"สร้างฟังก์ชันสำหรับ crop รูปและโหลดรูปรวมทั้ง preprocess ตาม Workshop ในภาค 1"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# model.summary()\nSIZE=(288,350)\nIMG_SIZE=SIZE\n\ndef crop_image(img,tol=7):\n    if img.ndim ==2:\n        mask = img>tol\n        return img[np.ix_(mask.any(1),mask.any(0))]\n    elif img.ndim==3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img>tol\n        \n        check_shape = img[:,:,0][np.ix_(mask.any(1),mask.any(0))].shape[0]\n        if (check_shape == 0): # image is too dark so that we crop out everything,\n            return img # return original image\n        else:\n            img1=img[:,:,0][np.ix_(mask.any(1),mask.any(0))]\n            img2=img[:,:,1][np.ix_(mask.any(1),mask.any(0))]\n            img3=img[:,:,2][np.ix_(mask.any(1),mask.any(0))]\n    #         print(img1.shape,img2.shape,img3.shape)\n            img = np.stack([img1,img2,img3],axis=-1)\n    #         print(img.shape)\n        return img\n\ndef load_image_ben_orig(path,resize=True,crop=True,norm255=True,keras=False):\n    image = cv2.imread(path)\n    \n    if crop:\n        image = crop_image(image)\n    \n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        \n    if resize:\n        image = cv2.resize(image,SIZE)\n        \n    image=cv2.addWeighted( image,4, cv2.GaussianBlur( image , (0,0) ,  10) ,-4 ,128)\n#     image=cv2.addWeighted( image,4, cv2.medianBlur( image , 10) ,-4 ,128)\n    \n    # NOTE plt.imshow can accept both int (0-255) or float (0-1), but deep net requires (0-1)\n    if norm255:\n        return image/255\n    elif keras:\n        #see https://github.com/keras-team/keras-applications/blob/master/keras_applications/imagenet_utils.py for mode\n        #see https://github.com/keras-team/keras-applications/blob/master/keras_applications/xception.py for inception,xception mode\n        #the use of tf based preprocessing (- and / by 127 respectively) will results in [-1,1] so it will not visualize correctly (directly)\n        image = np.expand_dims(image, axis=0)\n        return preprocess_input(image)[0]\n    else:\n        return image.astype(np.int16)\n    \n    return image\n\ndef show_image(image,figsize=None,title=None):\n    \n    if figsize is not None:\n        fig = plt.figure(figsize=figsize)\n#     else: # crash!!\n#         fig = plt.figure()\n        \n    if image.ndim == 2:\n        plt.imshow(image,cmap='gray')\n    else:\n        plt.imshow(image)\n        \n    if title is not None:\n        plt.title(title)\n\ndef show_Nimages(imgs,scale=1):\n\n    N=len(imgs)\n    fig = plt.figure(figsize=(25/scale, 16/scale))\n    for i, img in enumerate(imgs):\n        ax = fig.add_subplot(1, N, i + 1, xticks=[], yticks=[])\n        show_image(img)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"ทดลองโหลดรูปของดวงตาที่เป็นเบาหวานในขั้นรุนแรงที่สุดระดับ 4 เก็บไว้ 7 รูปเพื่อเป็นรูปต้นฉบับก่อนที่จะทำ Data Augmentation ครับ"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"SEED=88\nNUM=7\nfig = plt.figure(figsize=(25, 16))\nfor class_id in sorted(np.unique(y)):\n    images=[]\n    if class_id < 4:\n        continue\n    for i, (idx, row) in enumerate(df_train.loc[y == class_id].sample(NUM, random_state=SEED).iterrows()):\n        path=f\"../input/train_images/{row['id_code']}.png\"\n        images.append(load_image_ben_orig(path).astype(np.float32))\n        \n    show_Nimages(images)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 2.2 ทดลองใช้ Albumentations\n\nวิธีการใช้ `albumentations` นั้นง่ายมากครับ ก่อนอื่นเราสามารถไปดูรายชื่อ augmentation ที่ support ทั้งหมดได้ที่นี่\nhttps://albumentations.readthedocs.io/en/latest/api/augmentations.html ตัวอย่างที่เราสามารถทำได้ เช่น การปรับสีสัน\n\n![ภาพจาก official github](https://camo.githubusercontent.com/fd2405ab170ab4739c029d7251f5f7b4fac3b41c/68747470733a2f2f686162726173746f726167652e6f72672f776562742f62642f6e652f72762f62646e6572763563746b75646d73617a6e687734637273646669772e6a706567)\n\nนอกจากนี้ก็จะมี operation อื่นๆ อีกมากมาย อาทิเช่น การบิดภาพของกระรอกในหัวข้อด้านบนครับ\n\n## 2.3 เลือก Augment อย่างไร??\nและเราก็เลือก augmentation สำหรับปัญหา \"ตรวจสอบเบาหวานในดวงตา\" ที่บาดแผลต่างๆ ในตามีความสำคัญนั้น ทีมงานได้เลือก Augment Operation ที่เหมาะสมดังรายนามข้างล่าง สังเกตว่าเราใช้คำว่า \"เหมาะสม\" ก็เนื่องจากมันไม่ทำให้การประเมินของมนุษย์เปลี่ยนไปมากนักเมื่อดูภาพที่ถูกดัดแปลงนี้ (ดูภาพตัวอย่างในหัวข้อถัดไป) \n\n* `HorizontalFlip` คือการสะท้อนภาพแบบส่องกระจกในแนวนอน \n* `VerticalFlip` คือการสะท้อนภาพแบบส่องกระจกในแนวตั้ง\n* `Flip` คือการสุ่มสะท้อนภาพในแนวนอนหรือตั้ง\n* `Rotate` คือการสุ่มหมุนภาพไปตามช่วงองศาที่กำหนด\n* `RandomBrightnessContrast` คือการสุ่มปรับความสว่างของภาพ\n* `RandomSizedCrop` คือการสุ่มตัดภาพมาบางส่วน แล้ว resize ไปให้ใหญ่เท่าเดิม\n* `Cutout` คือการสุ่มเพิ่มจุดดำลงไปในภาพ\n* `RandomSunFlare` คือการสุ่มเพิ่มแสงสะท้อนของดวงอาทิตย์ลงไปในภาพ\n* นำทั้งหมดมา augment พร้อมๆ กัน (ultimate augment ขั้นสูงสุด :)\n\n### การเลือก Augmentation เป็นทั้งศาสตร์และศิลป์\n\nในการเลือก augmentation แต่ละครั้งต้องมีสาเหตุที่เหมาะสมเสมอครับ นั่นคือ **ต้องไม่ทำให้ธรรมชาติของข้อมูลเก่าเปลี่ยนไปมากนัก** ลองคิดดูครับในปัญหาดวงตานี้ ถ้าดวงตามีบาดแผล เรานำไปส่องกระจก หรือหมุน บาดแผลก็ยังคงอยู่เหมือนเดิม ภาพจะมืดหรือสว่างขึ้น(ในระดับที่เหมาะสม) ก็ไม่ทำให้บาดแผลเปลี่ยนไปเช่นกัน ในขณะที่การสุ่มตัดภาพหรือเพิ่มจุดดำที่ไม่มากจนเกินไปก็อาจทำให้มองภาพได้ยากขึ้นบ้าง แต่ส่วนใหญ่มนุษย์เรายังคงมองพวกบาดแผลต่างๆ ได้เช่นเดิมครับ\n\nการพิจารณา augmentation ที่เหมาะสมเป็นเรื่องละเอียดอ่อนครับ ในหลายๆ ครั้งการ augment ด้วยการ Flip หรือส่องกระจกมักจะไม่ทำให้ธรรมชาติข้อมูลเปลี่ยน แต่ทว่าในปัญหาบางประเภทเราอาจจะ Flip ไม่ได้ เช่น ปัญหาจดจำลายบนตัวสัตว์ ซึ่งสัตว์อาจจะมีบาดแผลเป็นอยู่ ถ้าบาดแผลอยู่ในทิศตรงกันข้าม (ซึ่งเกิดจาก Flip หรือส่องกระจก) อาจจะหมายถึง สัตว์คนละตัว ทั้งนี้เนื่องจากรูปในธรรมชาติจะมีภาพที่ส่องกระจกเกิดขึ้นเองไม่ได้ เป็นต้น \n\nในปัญหาบาดแผลบนดวงตานี้ เราควรหลีกเลี่ยงการ augment แบบ \"Blur\" เพราะจะทำให้แผลเล็กๆ เบลอหายไป หรือการใส่ \"Noise\" เพราะอาจทำให้มองภาพผิดว่าจุด noise ต่างๆ คือแผลเล็กๆ (รวมทั้งในข้อมูลต้นฉบับไม่มี noise เหล่านี้อยู่) เป็นต้น\n"},{"metadata":{},"cell_type":"markdown","source":"# 3 ทำ Data Augmentation ด้วย Albumentations Library"},{"metadata":{},"cell_type":"markdown","source":"วิธีการใช้งานง่ายมากครับ เราเพียงสร้างฟังก์ชันที่จะ apply augmentation ที่เราต้องการ โดยฟังก์ชันนี้ขอเรียกว่า `apply_augment` รับ input 2 ตัวแปรคือ รูปแบบ augment ที่เราเลือก `aug0`\n(เช่น `Flip`) กับรูปภาพที่ต้องการ augment `img` ซึ่งทำได้บรรทัดเดียวจบ"},{"metadata":{"trusted":true},"cell_type":"code","source":"'''บรรทัดเดียวจบครับ aug0 คือ augmentation operation ที่เราเลือกมาจาก Albumentation document, img คือภาพที่เราต้องการ augment '''\ndef apply_augment(aug0, img):\n    return aug0(image=img)['image']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''สร้างฟังก์ชันเพื่อทำ apply_augment เดียวกันกับ list of images หลายๆ รูปในคราวเดียวและให้ plot รูปก่อนและหลัง augment มาดูกัน'''\ndef batch_apply_augment(aug0,images):\n    augmented_images=[]\n    for ii in range(len(images)):\n        aug_img = apply_augment(aug0,images[ii])\n        augmented_images.append(aug_img)\n    \n    show_Nimages(images)\n    show_Nimages(augmented_images)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"เลือก operation ได้จาก github หรือจาก documents นี้ก็ได้ครับ https://albumentations.readthedocs.io/en/latest/api/augmentations.html\n\nในทุก Operation ของ albumentations จะอนุญาตให้เราระบุ \"ความน่าจะเป็น\" ที่จะ augment ได้ `Flip(p=0.8)` แปลว่าเราจะ flip รูปด้วยความน่าจะเป็น 80% นั่นเองครับ\n\nในตัวอย่างข้างล่างเราสั่งให้ Flip รูปที่เราเซพไว้ 7 รูปด้วยความน่าจะเป็น 80% ดังนั้นจะเห็นว่าบางรูปก็จะสลับข้าง บางรูปก็จะสลับบนล่าง หรือบางรูปก็จะเป็นรูปเดิมครับ (รันแต่ละครั้งจะได้ผลต่างกัน)"},{"metadata":{"trusted":true},"cell_type":"code","source":"'''ตัวอย่างใช้งาน Flip หรือส่องกระจก (สุ่มแนวตั้งหรือแนวนอน) ด้วยความน่าจะเป็น p=0.8 ของภาพดวงตาที่เราเซพไว้'''\naug1 = Flip(p=0.8)\nbatch_apply_augment(aug1,images)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"การทำ augmentation อื่นๆ ก็ทำแบบเดียวกันเป้ะเลยครับ เรามาลองเล่นกันดูเลยครับ"},{"metadata":{"trusted":true},"cell_type":"code","source":"'''สุ่มเปลี่ยนความมืดความสว่างของรูป : RandomBrightnessContrast'''\naug2 = RandomBrightnessContrast(brightness_limit=0.45, contrast_limit=0.45,p=1)\nbatch_apply_augment(aug2,images)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''สุ่มตัดรูปบางสว่นแล้ว resize กลับเป็นขนาดเดิม : RandomSizedCrop เป็นหนึ่งใน augmentation ที่ทรงพลังและทำให้โมเดลทำงานดีขึ้นมากๆ ในหลายปัญหาครับ'''\n'''ในกรณีของดวงตา เราจะได้เห็นบาดแผลในสเกลที่หลากหลายกว่าเดิม มีขนาดใหญ่กว่าบาดแผลของรูปต้นฉบับ'''\n\nh_min=np.round(IMG_SIZE[1]*0.72).astype(int) # ระบุว่าจะ crop ไม่น้อยกว่า 72% ของรูปเดิม\nh_max= np.round(IMG_SIZE[1]*0.9).astype(int)  # ระบุว่าจะ crop ไม่มากกว่า 90% ของรูปเดิม\n\naug3 = RandomSizedCrop((h_min, h_max),IMG_SIZE[1],IMG_SIZE[0], w2h_ratio=IMG_SIZE[0]/IMG_SIZE[1],p=1)\n\nbatch_apply_augment(aug3,images)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''สุ่มลบบางส่วนของภาพออกไป : CutOut หรือ RandomEraser ก็เป็นหนึ่งใน augmentation ที่ดังมากและพบว่าทำให้ model มีความ robust มากขึ้นครับ'''\n\nmax_hole_size = int(IMG_SIZE[1]/10) # กำหนดขนาดของจุดที่เราจะลบออก\n\naug4 = Cutout(p=1,max_h_size=max_hole_size,max_w_size=max_hole_size,num_holes=8 )#num_holes=8 คือจะสุ่มลบ 8 ส่วน\n\nbatch_apply_augment(aug4,images)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''สุ่มใส่แสงดวงอาทิตย์ ซึ่งเป็นการเลียนแสงธรรมชาติลงในภาพถ่าย RandomSunFlare : ซึ่งจะบังคับให้โมเดลเราต้องเรียนรู้ความแตกต่างระหว่าง \"จุดรอยแผล\" กับ \"จุดแสง\" ซึ่งเกิดขึ้นตามธรรมชาติในภาพถ่าย '''\naug_sun = RandomSunFlare(src_radius=max_hole_size,\n                      num_flare_circles_lower=10,\n                      num_flare_circles_upper=20,\n                      p=1)#default flare_roi=(0,0,1,0.5),\n\n'''ใน Albumentation เรายังนำ augment หลายๆ ตัวหรือตัวเดียวกันมาต่อกันหลายๆ รอบได้ เช่น ในตัวอย่างนี้เราจะใส่เส้นแสงดวงอาทิตย์ลงไป 3 เส้น '''\naug5 = Compose([aug_sun,aug_sun,aug_sun],p=1)\nbatch_apply_augment(aug5,images)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## รวมพลัง Augmentations เป็นหนึ่ีงเดียว\n\nใน Albumentation เรายังนำ augment หลายๆ ตัวหรือตัวเดียวกันมาต่อกันหลายๆ รอบได้ง่ายๆ ด้วย `Compose` โดยเราเพียงนำ augmentations ที่เราต้องการมาใส่เรียงกันใน list เท่านั้น"},{"metadata":{"trusted":true},"cell_type":"code","source":"'''ผสานพลัง augmentation เป็นหนึ่งเดียว'''\naug_ultimate = Compose([aug1,aug2,aug3,aug4,aug5],p=1)\nbatch_apply_augment(aug_ultimate,images)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"เป็นอย่างไรครับเราก็ได้ภาพใหม่ที่ดูยากขึ้น แต่ยังคงนัยสำคัญของข้อมูลไว้ในระดับที่น่าพอใจ (หรือเพื่อนๆ ปรับให้ตรงตามความต้องการได้ัเอง)\n\nนอกจากลูกเล่นต่างๆ แล้ว Albumentations ยังอนุญาตให้ผู้ใช้นำหลายๆ augmentation มารวมกันแบบสุ่มด้วยความน่าจะเป็นไม่เท่ากันได้อีกด้วย ซึ่ง Advanced options เหล่านี้เพื่อนๆ สามารถศึกษาได้จาก official document หรือถ้าเพื่อนๆ มีข้อสงสัยใดๆ ก็สามารถถามใน comments ด้านล่าง หรือใน https://www.thaikeras.com/community ได้เลยนะคร้าบ\n\nเรียนรู้ไปด้วยกันใหม่สัปดาห์หน้าคร้าบบบ :)"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","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.6.6"}},"nbformat":4,"nbformat_minor":1}