{"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":"%matplotlib inline\n#這是jupyter notebook的magic word˙\n\nimport matplotlib\nimport matplotlib.pyplot as plt\nfrom IPython import display","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-11-11T10:45:35.766104Z","iopub.execute_input":"2021-11-11T10:45:35.766723Z","iopub.status.idle":"2021-11-11T10:45:35.785652Z","shell.execute_reply.started":"2021-11-11T10:45:35.766577Z","shell.execute_reply":"2021-11-11T10:45:35.784368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 病理切片癌症檢測","metadata":{}},{"cell_type":"code","source":"import os\n#判斷是否在jupyter notebook上\ndef is_in_ipython():\n    \"Is the code running in the ipython environment (jupyter including)\"\n    program_name = os.path.basename(os.getenv('_', ''))\n\n    if ('jupyter-notebook' in program_name or # jupyter-notebook\n        'ipython'          in program_name or # ipython\n        'jupyter' in program_name or  # jupyter\n        'JPY_PARENT_PID'   in os.environ):    # ipython-notebook\n        return True\n    else:\n        return False\n\n\n#判斷是否在colab上\ndef is_in_colab():\n    if not is_in_ipython(): return False\n    try:\n        from google import colab\n        return True\n    except: return False\n\n#判斷是否在kaggke_kernal上\ndef is_in_kaggle_kernal():\n    if 'kaggle' in os.environ['PYTHONPATH']:\n        return True\n    else:\n        return False\n\nif is_in_colab():\n    from google.colab import drive\n    drive.mount('/content/gdrive')","metadata":{"execution":{"iopub.status.busy":"2021-11-11T10:45:38.579659Z","iopub.execute_input":"2021-11-11T10:45:38.580113Z","iopub.status.idle":"2021-11-11T10:45:38.592279Z","shell.execute_reply.started":"2021-11-11T10:45:38.580064Z","shell.execute_reply":"2021-11-11T10:45:38.590873Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.environ['TRIDENT_BACKEND'] = 'pytorch'\n\nif is_in_kaggle_kernal():\n    os.environ['TRIDENT_HOME'] = './trident'\nelif is_in_colab():\n    os.environ['TRIDENT_HOME'] = '/content/gdrive/My Drive/trident'\n\n#為確保安裝最新版 \n!pip uninstall tridentx -y\n!pip install ../input/trident/tridentx-0.7.3.22-py3-none-any.whl --upgrade\n\n#調用trident api\nimport trident as T\nfrom trident import *\nfrom trident.backend.opencv_backend import *\nfrom trident.models import resnet,efficientnet","metadata":{"execution":{"iopub.status.busy":"2021-11-11T10:46:15.059247Z","iopub.execute_input":"2021-11-11T10:46:15.059626Z","iopub.status.idle":"2021-11-11T10:46:36.357844Z","shell.execute_reply.started":"2021-11-11T10:46:15.059592Z","shell.execute_reply":"2021-11-11T10:46:36.356499Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import glob\n#透過glob所全部train資料夾中所有可用圖片\nimgs=glob.glob('../input/histopathologic-cancer-detection/train/*.tif')\nprint(len(imgs))\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#檢視一下圖片image2array是將圖片或圖片路徑變成numpy向量，然後我們再把向量轉回image指的是pillow的bitmap圖片\nprint(image2array(imgs[0]).shape)\narray2image(image2array(imgs[0]))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"接下來要把有帶標籤的train_labels.csv讀取一下。編碼為何是'utf-8-sig'而不是'utf-8'呢?那其實是因為微軟與linux的utf-8定義不一致，一個有帶BOM一個沒有，所以為了避免誤觸地雷，建議用'utf-8-sig'，兩邊都相容比較不會有問題。讀入後逐列切割出圖檔編號與標籤，目前標籤值只有0與1，這是一個二元預測的題目。","metadata":{}},{"cell_type":"code","source":"if os.path.exists('./sample.pkl'):\n    image_path=[]\n    labels=[]\n    test_image_path=[]\n    test_labels=[]\n    image_path,labels,test_image_path,test_labels=unpickle('./sample.pkl')\nelse:\n    #ImageDatset(imgs,symbol='image')\n    f=open('../input/histopathologic-cancer-detection/train_labels.csv','r',encoding='utf-8-sig')\n    data=f.readlines()\n    print(data[:3])\n    image_path=[]\n    labels=[]\n    test_image_path=[]\n    test_labels=[]\n    data=data[1:] #拿掉第一筆標頭\n    random.shuffle(data)#隨機洗牌\n    for row in data:\n        cols=row.strip().split(',') #移除\\n然後逗號分割\n        if random.random()<=0.3:\n            test_image_path.append('../input/histopathologic-cancer-detection/train/{0}.tif'.format(cols[0]))\n            test_labels.append(int(cols[1]))\n        else:\n            image_path.append('../input/histopathologic-cancer-detection/train/{0}.tif'.format(cols[0]))\n            labels.append(int(cols[1]))\n    print(len(image_path))\n    print(len(labels))\n    print(len(test_image_path))\n    print(len(test_labels))\n\n\n    from trident.data.utils import *\n    pickle_it('./sample.pkl',[image_path,labels,test_image_path,test_labels])","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:07:21.360630Z","iopub.execute_input":"2021-11-11T11:07:21.361164Z","iopub.status.idle":"2021-11-11T11:07:22.316097Z","shell.execute_reply.started":"2021-11-11T11:07:21.361123Z","shell.execute_reply":"2021-11-11T11:07:22.313469Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"接下來就是組裝出要使用來建模的dataset，基本上DataProvider是提供數據的接口，裡面有兩組Iterator，分別是TrainData與TestData，而Iterator控制內部的各個資料集(Dataset)如何構成批次的數據。","metadata":{}},{"cell_type":"code","source":"#資料集\nds1=ImageDataset(image_path,symbol='image')\nds2=LabelDataset(labels,symbol='label')\n\nds1_t=ImageDataset(test_image_path,symbol='image')\nds2_t=LabelDataset(test_labels,symbol='label')\n\n#與Iterator構成data provider\ndata_provider=DataProvider(traindata=Iterator(data=ds1,label=ds2),testdata=Iterator(data=ds1_t,label=ds2_t))\n\n#設定DataProvider的預處理流程\ndata_provider.image_transform_funcs=[Normalize(127.5,127.5)]\n\n#即可完成設定，可以透過next()來確認數據是否正常拋出，以及是否有正確產生輸出數據的signature\nimg_data,label_data=data_provider.next()\nprint(data_provider.signature)\nprint(img_data.shape)\nprint(label_data.shape)","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:12:50.323781Z","iopub.execute_input":"2021-11-11T11:12:50.324167Z","iopub.status.idle":"2021-11-11T11:12:50.510257Z","shell.execute_reply.started":"2021-11-11T11:12:50.324137Z","shell.execute_reply":"2021-11-11T11:12:50.509203Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"接下來示範一下兩個我個人很喜歡的小功能。","metadata":{}},{"cell_type":"code","source":"data_provider.batch_size=16\ndata_provider.preview_images()","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:14:03.362616Z","iopub.execute_input":"2021-11-11T11:14:03.362982Z","iopub.status.idle":"2021-11-11T11:14:03.627182Z","shell.execute_reply.started":"2021-11-11T11:14:03.362950Z","shell.execute_reply":"2021-11-11T11:14:03.626103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_provider.class_names['zh-TW']={0:'陰性',1:'陽性'}\ndata_provider.label_statistics()\n","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:15:17.034626Z","iopub.execute_input":"2021-11-11T11:15:17.035132Z","iopub.status.idle":"2021-11-11T11:15:17.073939Z","shell.execute_reply.started":"2021-11-11T11:15:17.035092Z","shell.execute_reply":"2021-11-11T11:15:17.072369Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"然後我們可以透過preview_images()函數來檢閱一下圖片經過數據增強步驟之後的樣子","metadata":{}},{"cell_type":"markdown","source":"我們可以在data_provider.image_transform_funcs=[Normalize(127.5,127.5)]直接加入各種視覺處理的transform，來達到數據增強的目的，例如我加入常見的明暗變化、飽和度變化以及色相變化，同時加入隨機擦除以及加入胡椒鹽噪音","metadata":{}},{"cell_type":"code","source":"data_provider.image_transform_funcs=[\n    RandomAdjustGamma(scale=(0.6,1.4)),#調整明暗\n    RandomAdjustHue(scale=(-0.2,0.2)),#調整色相\n    RandomAdjustSaturation(scale=(0.6,1.4)),#調整飽和度\n    SaltPepperNoise(0.1),#加入胡椒鹽噪音\n    RandomErasing(), #加入隨機擦去\n    Resize((112,112),True), #縮放尺寸\n    Normalize(127.5,127.5)] #標準化\nimg_data,label_data=data_provider.next()\nprint(img_data.shape)\nprint(label_data.shape)\ndata_provider.preview_images()","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:17:05.127872Z","iopub.execute_input":"2021-11-11T11:17:05.128379Z","iopub.status.idle":"2021-11-11T11:17:05.550900Z","shell.execute_reply.started":"2021-11-11T11:17:05.128331Z","shell.execute_reply":"2021-11-11T11:17:05.549772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from trident.models import efficientnet\nnet1=efficientnet.EfficientNetB0(pretrained=True,include_top=True,freeze_features=True,input_shape=(3,112,112),classes=2)\nnet1.summary()\n#在輸出添加噪音，讓機器不會做出曖昧不明的決策\nnet1.model[-1].add_noise=True\nnet1.model[-1].noise_intensity=0.12","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:32:46.231990Z","iopub.execute_input":"2021-11-11T11:32:46.232475Z","iopub.status.idle":"2021-11-11T11:32:47.292125Z","shell.execute_reply.started":"2021-11-11T11:32:46.232445Z","shell.execute_reply":"2021-11-11T11:32:47.290997Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"net2=efficientnet.EfficientNetB0(pretrained=True,include_top=True,freeze_features=True,input_shape=(3,112,112),classes=2)\nnet2.model[-1].add_noise=True\nnet2.model[-1].noise_intensity=0.12\nnet2.summary()\n\nnet3=efficientnet.EfficientNetB0(pretrained=True,include_top=True,freeze_features=True,input_shape=(3,112,112),classes=2)\nnet3.model[-1].add_noise=True\nnet3.model[-1].noise_intensity=0.12\n\n\n","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:32:47.295900Z","iopub.execute_input":"2021-11-11T11:32:47.296290Z","iopub.status.idle":"2021-11-11T11:32:48.910950Z","shell.execute_reply.started":"2021-11-11T11:32:47.296261Z","shell.execute_reply":"2021-11-11T11:32:48.909848Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import roc_curve, auc, roc_auc_score\ndef auc(output,target):\n    \n    if ndim(output)>1 and int_shape(output)[-1]>1 :\n        output_np=to_numpy(exp(output))[:,1]\n    elif ndim(output)>1 and int_shape(output)[-1]==1 :\n        output_np=to_numpy(exp(output))[:,0]\n    else:\n        output_np=to_numpy(output)\n    target_np=to_numpy(target)\n    return roc_auc_score(target_np, output_np)\n\n\n\ndef draw_roc(training_context):\n    if training_context['steps']==10 or (training_context['steps']+1)%100==0:\n        traindata=training_context['train_data']\n        data_feed=training_context['data_feed']\n        target_np=to_numpy(traindata[data_feed['target']])\n        output=traindata[data_feed['output']]\n        if ndim(output)>1 and int_shape(output)[-1]>1 :\n            output_np=to_numpy(exp(output))[:,1]\n        elif ndim(output)>1 and int_shape(output)[-1]==1 :\n            output_np=to_numpy(exp(output))[:,0]\n        else:\n            output_np=to_numpy(output)\n        \n        fpr, tpr,_=roc_curve(target_np, output_np)\n        plt.figure(1)\n        plt.plot([0, 1], [0, 1], 'k--')\n        plt.plot(fpr, tpr, label='area = {:.3f}'.format(roc_auc_score(target_np, output_np)))\n        plt.xlabel('False positive rate')\n        plt.ylabel('True positive rate')\n        plt.title('ROC curve')\n        plt.legend(loc='best')\n        plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:32:49.827140Z","iopub.execute_input":"2021-11-11T11:32:49.827599Z","iopub.status.idle":"2021-11-11T11:32:49.841626Z","shell.execute_reply.started":"2021-11-11T11:32:49.827551Z","shell.execute_reply":"2021-11-11T11:32:49.840144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#baseline\nnet1.with_optimizer(Adam,lr=1e-3)\\\n.with_loss(CrossEntropyLoss)\\\n.with_metric(accuracy,ignore_index=0)\\\n.with_metric(recall,ignore_index=0)\\\n.with_metric(auc)\\\n.with_regularizer('l2',1e-5)\\\n.with_model_save_path('./Models/eff0_1.pth')\\\n.trigger_when('on_batch_end',frequency=1,action=draw_roc)\\\n.unfreeze_model_scheduling(200,unit='batch',module_name='block7a')\n\n\n#challenger1 使用DiffGrad優化器、累積梯度\nnet2.with_optimizer(DiffGrad,lr=1e-3,gradient_centralization='all')\\\n.with_loss(CrossEntropyLoss)\\\n.with_metric(accuracy,ignore_index=0)\\\n.with_metric(recall,ignore_index=0)\\\n.with_metric(auc)\\\n.with_regularizer('l2',1e-5)\\\n.with_model_save_path('./Models/eff0_2.pth')\\\n.trigger_when('on_batch_end',frequency=1,action=draw_roc)\\\n.with_accumulate_grads(5)\\\n.unfreeze_model_scheduling(200,unit='batch',module_name='block7a')\\\n.with_automatic_mixed_precision_training()\n\n\n\n#challenger2 使用DiffGrad優化器、累積梯度、CrossEntropyLoss進階的選項以及多增加F1Score\nnet3.with_optimizer(DiffGrad,lr=1e-3,gradient_centralization='all')\\\n.with_loss(CrossEntropyLoss(auto_balance=True,label_smooth=True))\\\n.with_loss(F1ScoreLoss(auto_balance=True))\\\n.with_metric(accuracy,ignore_index=0)\\\n.with_metric(recall,ignore_index=0)\\\n.with_metric(auc)\\\n.with_regularizer('l2',1e-5)\\\n.with_model_save_path('./Models/eff0_3.pth')\\\n.trigger_when('on_batch_end',frequency=1,action=draw_roc)\\\n.unfreeze_model_scheduling(200,unit='batch',module_name='block7a')\\\n.with_accumulate_grads(5)\\\n.with_automatic_mixed_precision_training()\n\n\n\n\n#if os.path.exist('./Models/eff0_1.pth'):\n#    net1.load_model('./Models/eff0_1.pth')\n#if os.path.exist('./Models/eff0_2.pth'):\n#    net2.load_model('./Models/eff0_2.pth')\n#if os.path.exist('./Models/eff0_3.pth'):\n#    net3.load_model('./Models/eff0_3.pth')\n#if os.path.exist('./Models/eff0_4.pth'):\n#    net4.load_model('./Models/eff0_4.pth')\n","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:32:49.843282Z","iopub.execute_input":"2021-11-11T11:32:49.843821Z","iopub.status.idle":"2021-11-11T11:32:49.954750Z","shell.execute_reply.started":"2021-11-11T11:32:49.843749Z","shell.execute_reply":"2021-11-11T11:32:49.953482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nplan=TrainingPlan()\\\n    .add_training_item(net1,name='net1')\\\n    .add_training_item(net2,name='net2')\\\n    .add_training_item(net3,name='net3')\\\n    .with_data_loader(data_provider)\\\n    .with_batch_size(128)\\\n    .repeat_epochs(5)\\\n    .out_sample_evaluation_scheduling(100)\\\n    .print_gradients_scheduling(100,unit='batch')\\\n    .print_progress_scheduling(10,unit='batch')\\\n    .display_loss_metric_curve_scheduling(200)\\\n    .save_model_scheduling(50,unit='batch')\n","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:32:49.956761Z","iopub.execute_input":"2021-11-11T11:32:49.957708Z","iopub.status.idle":"2021-11-11T11:32:49.966866Z","shell.execute_reply.started":"2021-11-11T11:32:49.957659Z","shell.execute_reply":"2021-11-11T11:32:49.965243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plan.start_now()","metadata":{"execution":{"iopub.status.busy":"2021-11-11T11:32:49.968863Z","iopub.execute_input":"2021-11-11T11:32:49.969819Z"},"trusted":true},"execution_count":null,"outputs":[]}]}