{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"#import thư viện fastai\nfrom fastai.vision.all import *","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Tạo đường dẫn tới thư mục plant-pathology-2021-fgvc8 trong input\npath = Path(\"../input/plant-pathology-2021-fgvc8\")\n\n#In danh sách thư mục con trong thư mục plant-pathology-2021-fgvc8\npath.ls()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Đọc dữ liệu file  ../input/plant-pathology-2021-fgvc8/train.csv\ntrain_df = pd.read_csv(path/\"train.csv\")\n\n#In dữ liệu\ntrain_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#In kích thước của mảng\ntrain_df.shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"ở đây chúng ta có thể thấy được có 18632 ảnh dùng để training","metadata":{}},{"cell_type":"code","source":"#lọc số lượng của mỗi label\ntrain_df[\"labels\"].value_counts()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Ở đây sử dụng [resized dataset](https://www.kaggle.com/ankursingh12/resized-plant2021) để tiết kiệm thời gian.  \nnếu không sử dụng thì sẽ mất khá nhiều thời gian để thay đổi kích thước hình ảnh...😅","metadata":{}},{"cell_type":"markdown","source":"Bây giờ nếu chúng ta sử dụng ngay ảnh nói trên để train cho model CNN Classify thì sẽ bị hiện tượng Overfit vì dữ liệu nhiều nhưng đa phần giống nhau. Dẫn đến train sẽ có chất lượng tốt nhưng khi test sẽ thấy không được chính xác.\n \n Chúng ta sẽ thực hiện augment dữ liệu để làm phong phú hơn dữ liệu, tăng tính tổng quát cho model \nbằng RandomResizedCrop vì nó sẽ chia tỷ lệ ngẫu nhiên hình ảnh và cắt nó, sau đó thay đổi kích thước nó thành kích thước yêu cầu.","metadata":{}},{"cell_type":"code","source":"#ở đây chúng ta sẽ đưa về kích thước ảnh là 128, cắt kích thước ảnh ngẫu nhiên từ 0.75 dến 1.00 và đưa về tỷ lệ 1:1 so với ảnh cũ\nitem_tfms = [RandomResizedCrop(128, min_scale=0.75, ratio=(1., 1.))]\nbatch_tfms = [*aug_transforms(size=128, max_warp=0), Normalize.from_stats(*imagenet_stats)]\n\ndls = ImageDataLoaders.from_df(\n    df = train_df,\n    folder = \"../input/resized-plant2021/img_sz_512\",\n    item_tfms = item_tfms,\n    batch_tfms = batch_tfms,\n    \n    #Dùng để phân chia dữ liệu 10% dữ liệu train và 90% dữ liệu valid\n    splitter = RandomSplitter(valid_pct=0.1),\n    label_delim = \" \",\n    bs=256\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dls.show_batch()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#tạo thư mục \"/root/.cache/torch/hub/checkpoints\"\n!mkdir -p /root/.cache/torch/hub/checkpoints\n\n# mô hình phân loại hình ảnh resnet18\n!cp ../input/resnet18/resnet18.pth /root/.cache/torch/hub/checkpoints/resnet18-5c106cde.pth\n#!cp ../input/resnet18/resnet34.pth /root/.cache/torch/hub/checkpoints/resnet34-333f7ec4.pth\n#!cp ../input/resnet50/resnet50.pth /root/.cache/torch/hub/checkpoints/resnet50-19c8e357.pth","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# xây dựng một model \nlearn = cnn_learner(\n    dls,\n    resnet18,\n    metrics=[accuracy_multi, F1ScoreMulti()]\n).to_fp16()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# biểu diễn quan hệ giữa learning_rate và loss. Mục đích để hạn chế việc phỏng đoán và tìm ra điểm khởi đầu learning_rate tốt nhất\nlearn.lr_find()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"    Chúng ta có thể thấy được 1 khoảng đốc xuống rồi đi lên, thì khi đấy tỉ lệ mất mát là nhỏ nhất và tỉ lệ học tập ở mức tương đối cao.\n    \n    Nếu tỷ lệ học tập được đặt quá thấp, quá trình đào tạo sẽ tiến triển rất chậm vì đang cập nhật rất nhỏ các trọng số trong mạng của mình. Tuy nhiên, nếu tỷ lệ học tập được đặt quá cao, nó có thể gây ra hành vi khác biệt không mong muốn trong chức năng mất mát. Vì tỷ lệ học tập tốt nhất có liên quan đến sự sụt giảm mạnh nhất\n    \n    Vì thế ở đây chúng ta sẽ đặt từ 1e-1","metadata":{}},{"cell_type":"code","source":"# tinh chỉnh lại model\nlearn.fine_tune(\n    7,\n    1e-1,\n    cbs=[\n        #lưu mô hình tốt nhất trong quá trình đào tạo và load nó vào cuối\n        SaveModelCallback(),\n        #dừng lại nếu sau 3 epochs mà k có cải thiện\n        EarlyStoppingCallback(patience=3),\n    ],\n    freeze_epochs=3\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# biểu diễn biểu đồ trainning và validation loss\nlearn.recorder.plot_loss()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#in ra kết quả dự đoán\nlearn.show_results()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# tạo một đối tượng ClassificationInterpretation để kiểm tra các giá trị \ninterp = ClassificationInterpretation.from_learner(learn)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# in ra 9 loss cao nhất\ninterp.plot_top_losses(9)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# biểu diễn xem có bao nhiêu điểm dữ liệu thực sự thuộc vào một class, và được dự đoán là rơi vào một class\ninterp.plot_confusion_matrix()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# đọc file sample_submission.csv,là dạng file chúng ta cần tạo để submit\nsubmission_df = pd.read_csv(path/\"sample_submission.csv\")\nsubmission_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# đổi path cho các item trong submission_df[\"image\"]\ntest_image_path_series = submission_df[\"image\"].apply(lambda x: f\"../input/plant-pathology-2021-fgvc8/test_images/{x}\")\ntest_image_path_series.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# đưa kết quả dự đoán (predict) từ dataset test_dl\ntest_dl = learn.dls.test_dl(test_image_path_series)\npreds, _ = learn.tta(dl=test_dl)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#in ra predictions\npreds","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# các label trong Dataloaders của model \nvocab = learn.dls.vocab\nvocab","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# hàm quyết định từ kết quả dự đoán được sẽ xếp nó là label nào, sau đó đưa vào mảng labels\nthreshold = 0.5\n\ndef pred_to_labels(pred):\n    labels = []\n    for i, probability in enumerate(pred):\n        if probability > threshold:\n            labels.append(vocab[i])\n            \n    return \" \".join(labels)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# tạo label_list chứa tất cả label mà model dự đoán được \nlabels_list = [pred_to_labels(pred) for pred in preds]\nlabels_list","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# chuyển labels_list vào thành cột labels trong submission dataframe \nsubmission_df[\"labels\"] = labels_list\nsubmission_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# chuyển submission_df sang dạng .csv để submit\nsubmission_df.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}