From ea8d08acc72b67650b1f85bc6cc95ebce22f424e Mon Sep 17 00:00:00 2001 From: whitekirin <113206109@gms.tcu.edu.tw> Date: Sat, 8 Mar 2025 13:38:01 +0000 Subject: [PATCH] 20250308 Commits: K-Fold has been finish, but sampler has some question to solve --- Image_Process/Image_Generator.py | 6 +- .../Image_Generator.cpython-311.pyc | Bin 10953 -> 10982 bytes .../load_and_ImageGenerator.cpython-311.pyc | Bin 3999 -> 3848 bytes Image_Process/load_and_ImageGenerator.py | 9 +- Load_process/Load_Indepentend.py | 2 +- .../Load_Indepentend.cpython-311.pyc | Bin 4298 -> 4275 bytes Processing_image.py | 2 +- Training_Tools/PreProcess.py | 21 +- Training_Tools/Tools.py | 14 +- .../__pycache__/PreProcess.cpython-311.pyc | Bin 3430 -> 3883 bytes .../__pycache__/Tools.cpython-311.pyc | Bin 4464 -> 4007 bytes .../all_model_tools.cpython-311.pyc | Bin 3267 -> 3232 bytes all_models_tools/all_model_tools.py | 2 +- experiments/Model_All_Step.py | 241 ++++++++++++------ .../Model_All_Step.cpython-311.pyc | Bin 11523 -> 16749 bytes .../__pycache__/experiment.cpython-311.pyc | Bin 8274 -> 5886 bytes .../__pycache__/pytorch_Model.cpython-311.pyc | Bin 2372 -> 2174 bytes experiments/experiment.py | 62 +---- experiments/pytorch_Model.py | 4 - main.py | 27 +- test.ipynb | 57 ++++- 21 files changed, 251 insertions(+), 196 deletions(-) diff --git a/Image_Process/Image_Generator.py b/Image_Process/Image_Generator.py index 8b2bf5e..9080afb 100644 --- a/Image_Process/Image_Generator.py +++ b/Image_Process/Image_Generator.py @@ -3,7 +3,7 @@ from _validation.ValidationTheEnterData import validation_the_enter_data from Load_process.file_processing import Process_File from Load_process.LoadData import Load_Data_Prepare from torchvision import transforms -from Training_Tools.Tools import Tool +from Training_Tools.PreProcess import Training_Precesses import numpy as np from PIL import Image import torch @@ -51,7 +51,7 @@ class Image_generator(): ''' File = Process_File() image_processing = Read_image_and_Process_image(self.Image_Size) - tool = Tool() + tool = Training_Precesses("", "", "", "") Classes = [] Transform = self.Generator_Content(stardand) @@ -60,7 +60,7 @@ class Image_generator(): save_root = File.Make_Save_Root(label, save_roots) # 合併路徑 Classes = image_processing.make_label_list(len(image), "1") - Training_Dataset = tool.Convert_Data_To_DataSet_And_Put_To_Dataloader(image, Classes, 1, False) + Training_Dataset = tool.Combine_Signal_Dataset_To_DataLoader(image, Classes, 1, False) if File.JudgeRoot_MakeDir(save_root): # 判斷要存的資料夾存不存在,不存在則創立 print("The file is exist.This Script is not creating new fold.") diff --git a/Image_Process/__pycache__/Image_Generator.cpython-311.pyc b/Image_Process/__pycache__/Image_Generator.cpython-311.pyc index 2f067734fd823d9a9dbe308104a53aea40660240..9a96e5baf2abe9bd6ae31bc1228996167f620dd2 100644 GIT binary patch delta 549 zcmX>Z`Ye=pIWI340}wpmIg=i>kyn{fSSX|@F*7eSFFih>C^b2?xHz?VvngXGqrxwH z{qp>x?BasNen5MCCtYKzgn9fkbIC%rRE|b0?&=p1e zKthwHNEpO+1rd%Q!Usqc1AWP$00c!MAR)cY-GY3=V%k9V%Pl}clPNt744&B+g-u?s zBFPvw`J{?0TLegP4C&`H>+qQFvdv2BPJw2Kc`p^7(KvP z0L4%d2S}M2khsN^S8$6tz|*IQ6C@M}A}l}zH;5<#5n><$`gb>$g9lA$`X>FpR?JSv64~Ys|`>_zdXMvySN}RIaNQP zC_lX@F;_uX;l+~n7mN39zQZ()g=q=%o|0onNpZ1 z-{Wwfyp36KvKeP5D{Bf{3e)5xoXMq!LX)LP7{qn~5e^{28%Pwh00{*kC=vk)>26*u z$R})|1!TY60wgq<($m1;nSD_xND$W1V|oa=1U`p zA|MF_FF=aqR5vl|Y`&LakHDu=Fa=EN6oju@(rRi{f9$uwapuZdRHoe@wOy9UrQn+4y#Ca;QG#@Kw9SF5^$1laPYTYFk(IV^ocD@hDtm z6?mU_D2Ffk8EU2Z1arV-RYi#lu*T}pW=9}qWr$c^Uo#>-E=gID+*5H{ipYpE@f0+S z5-q1TEu%a+^H)JgH}{$n@)l19N+LC`;(#fRdsAAymoFqfz^2ihvxSB#k(VS_oNYv| zO^ivBYY|M6{DUZhWjb)e+|&=qvx`Scx1lC7}Th~YPl-h8MpR=o2 zO_cs16b+0vh_Gcx1vYr|jIQw=@-Gz*YV|jz9fH@sBy6y(PvfVgQRarxE<3;CcONc$ Y7sOfkWd)~CQgryAzRTLrJswi4-!oL1n*aa+ delta 708 zcmZ`#O=uHA6y9lfcV?STYW|v^k{>H2jWi|)D~dr1DvgLzZ0VtwxHM~6Om<~9(o3{@ zG6y}#y9x>lRs~UtSV6&~2f-f#hV9iuPm-cu^y17$5m6t^H{W~jdml5eow}K(cPSl` zcr3npRNH(^i}ENI>CYJ8_aHx?mtbB#UTUc=siOR9R;763?ZrfFO7T+XgyS9Xm08AiE>s|i_uV&u23U+~WwmcjI<&Agli_y7xX zaK!U6{rGx>^TLYF&N}DxWuq|1>>AS>nS5sJ&Xuj(FAB#Rdd;Zt^0MJLg}M!M%F*Or zK6FXyCU>{x4oP%lJKOSA+D+v}ItKTZ!|3ArCuJ7FcQuWMVGJh`h3g~?CvY11J$4yK z;WZwGhd2cvaRe~Q!VH;!Jc*zXSB$F{w3d1+?1@)N00lUkMiDRH None: + def __init__(self, Training_Root,Test_Root, Generator_Root, Labels, Image_Size) -> None: self.Training_Root = Training_Root self.TestRoot = Test_Root - self.ValidationRoot = Validation_Root self.GeneratoRoot = Generator_Root self.Labels = Labels self.Image_Size = Image_Size @@ -37,13 +36,9 @@ Parmeter Generator = Image_generator(self.GeneratoRoot, self.Labels, self.Image_Size) # 將測試資料獨立出來 - test_size = 0.1 + test_size = 0.2 Indepentend.IndependentData_main(self.TestRoot, test_size) - # 將驗證資料獨立出來 - test_size = 0.1 - Indepentend.IndependentData_main(self.ValidationRoot, test_size) - if not File.Judge_File_Exist(self.GeneratoRoot): # 檔案若不存在 # 確定我要多少個List Prepare.Set_Data_Content([], Data_Length) diff --git a/Load_process/Load_Indepentend.py b/Load_process/Load_Indepentend.py index 538d8e5..e96d541 100644 --- a/Load_process/Load_Indepentend.py +++ b/Load_process/Load_Indepentend.py @@ -17,7 +17,7 @@ class Load_Indepentend_Data(): self.OneHot_Encording = OneHot_Encording pass - def process_main(self, Test_data_root, Validation_data_root): + def process_main(self, Test_data_root): self.test, self.test_label = self.get_Independent_image(Test_data_root) print("\ntest_labels有" + str(len(self.test_label)) + "筆資料\n") diff --git a/Load_process/__pycache__/Load_Indepentend.cpython-311.pyc b/Load_process/__pycache__/Load_Indepentend.cpython-311.pyc index dbab7c84ed817b2c6d84d6159cd8b599213a4a65..9329125b44694d4881b40eecb2d5bd5e8e1ed5bf 100644 GIT binary patch delta 117 zcmX@5xLJ{RIWI340}xd4o=JbXkyo9Wk!iCjvo51FQxPvv_!eJCYH>+?N@7W3d{KUW zNih>paPt(FAWlZv&Chw67`Y{Z0!2a~LU!{PJ`qMKI}lp{MDPKLUmP~M`6;D2sdh!q Jla&Nk006iZ9N_=} delta 140 zcmdn2cuJ9XIWI340}%9SpHBb3kyo9Wk$JNzvo50%a}h64_!eJCYH>+?N@7W3d{KUW z$t{tv#GFhZH#0vEAzI7~RI0GKmL-UjQEu}EUM5CvDWFJ^5Qvc5e3wszQOX{~761`^ WK;jpNO>TZlX-=wLk;`OmffWGmlO`Yl diff --git a/Processing_image.py b/Processing_image.py index c1d826b..92fcad8 100644 --- a/Processing_image.py +++ b/Processing_image.py @@ -14,7 +14,7 @@ if __name__ == "__main__": tool.Set_Labels() tool.Set_Save_Roots() Labels = tool.Get_Data_Label() - Trainig_Root, Testing_Root, Validation_Root = tool.Get_Save_Roots(2) + Trainig_Root, Testing_Root = tool.Get_Save_Roots(2) load = Loding_Data_Root(Labels, Trainig_Root, "") Data_Root = load.get_Image_data_roots(Trainig_Root) diff --git a/Training_Tools/PreProcess.py b/Training_Tools/PreProcess.py index 5b0647d..165ed21 100644 --- a/Training_Tools/PreProcess.py +++ b/Training_Tools/PreProcess.py @@ -1,4 +1,4 @@ -from torch.utils.data import Dataset, DataLoader, RandomSampler +from torch.utils.data import Dataset, DataLoader, RandomSampler, WeightedRandomSampler import torchvision.transforms as transforms import torch @@ -29,6 +29,12 @@ class Training_Precesses: self.Training_Labels = Training_Labels self.Testing_Datas = Testing_Datas self.Testing_Labels = Testing_Labels + + seed = 42 # 設定任意整數作為種子 + # 產生隨機種子產生器 + self.generator = torch.Generator() + self.generator.manual_seed(seed) + pass def Total_Data_Combine_To_DataLoader(self, Batch_Size): @@ -39,15 +45,16 @@ class Training_Precesses: Testing_DataLoader = DataLoader(dataset = Testing_Dataset, batch_size = 1, num_workers = 0, pin_memory=True, shuffle = True) return Training_DataLoader, Testing_DataLoader + + def Combine_Signal_Dataset_To_DataLoader(self, datas : list, Labels : list, Batch_Size, status : bool = True): + dataset = self.Convert_Data_To_DataSet(datas, Labels, status) + sampler = WeightedRandomSampler(dataset, generator = self.generator) # 創建Sampler + Dataloader = DataLoader(dataset = dataset, batch_size = Batch_Size, num_workers = 0, pin_memory=True, sampler = sampler) + return Dataloader def Convert_Data_To_DataSet(self, Datas : list, Labels : list, status : bool = True): - seed = 42 # 設定任意整數作為種子 - # 產生隨機種子產生器 - generator = torch.Generator() - generator.manual_seed(seed) - # 創建 Dataset list_dataset = ListDataset(Datas, Labels, status) - # sampler = RandomSampler(list_dataset, generator = generator) # 創建Sampler + return list_dataset diff --git a/Training_Tools/Tools.py b/Training_Tools/Tools.py index f89d15e..b90091c 100644 --- a/Training_Tools/Tools.py +++ b/Training_Tools/Tools.py @@ -13,10 +13,6 @@ class Tool: self.__Normal_Test_Data_Root = "" self.__Comprehensive_Testing_Root = "" - self.__ICG_Validation_Data_Root = "" - self.__Normal_Validation_Data_Root = "" - self.__Comprehensive_Validation_Root = "" - self.__ICG_ImageGenerator_Data_Root = "" self.__Normal_ImageGenerator_Data_Root = "" self.__Comprehensive_Generator_Root = "" @@ -37,10 +33,6 @@ class Tool: self.__Normal_Test_Data_Root = "../Dataset/Training/Normal_TestData" self.__Comprehensive_Testing_Root = "../Dataset/Training/Comprehensive_TestData" - self.__ICG_Validation_Data_Root = "../Dataset/Training/CA_ICG_ValidationData" - self.__Normal_Validation_Data_Root = "../Dataset/Training/Normal_ValidationData" - self.__Comprehensive_Validation_Root = "../Dataset/Training/Comprehensive_ValidationData" - self.__ICG_ImageGenerator_Data_Root = "../Dataset/Training/ICG_ImageGenerator" self.__Normal_ImageGenerator_Data_Root = "../Dataset/Training/Normal_ImageGenerator" self.__Comprehensive_Generator_Root = "../Dataset/Training/Comprehensive_ImageGenerator" @@ -68,11 +60,11 @@ class Tool: 若choose != 1 || choose != 2 => 會回傳四個結果 ''' if choose == 1: - return self.__ICG_Training_Root, self.__ICG_Test_Data_Root, self.__ICG_Validation_Data_Root + return self.__ICG_Training_Root, self.__ICG_Test_Data_Root if choose == 2: - return self.__Normal_Training_Root, self.__Normal_Test_Data_Root, self.__Normal_Validation_Data_Root + return self.__Normal_Training_Root, self.__Normal_Test_Data_Root else: - return self.__Comprehensive_Training_Root, self.__Comprehensive_Testing_Root, self.__Comprehensive_Validation_Root + return self.__Comprehensive_Training_Root, self.__Comprehensive_Testing_Root def Get_Generator_Save_Roots(self, choose): '''回傳結果為Train, test, validation''' diff --git a/Training_Tools/__pycache__/PreProcess.cpython-311.pyc b/Training_Tools/__pycache__/PreProcess.cpython-311.pyc index adbd1ed42392fd772f9565a7adc3a071e5844488..c582a24fa22154b88ddc42125bd454fb85af7c16 100644 GIT binary patch delta 752 zcma)%&ubGw6vt;aJG;py8|zAh7EwzhrBYJ^nxJUFAL+#)g~m%%!lpBc3u^+iQA9Sj zhaPhCFo$~dRIBlz8P%Y5FO@0&OC-LF%<!=c;3Q(nSsxm?eERAV(jq2;9qJtX!O^tyX zrN%OvOY}dH(-?p0>$-;V%YHJN$9P68#$IKq-L}1_l_Tp`lPuh1b!U>)26 zY#<*!7g_ztDndT?6<^(iUQhPJ=#cifh7-h(P)rr7ypC+boxSnB9nIIkm3osaFjwXa zz&VBIAaPaJIyYr~S)w43myqW8S-^1BxDK}6mQ5M=q{WjzgHOnA`daIL&1tggveRhV zZdIQ3Si4$og=Hxmdz>$G+i5z@Ms63%B~D2kmbe5Ms;=X;hia|Wa`_dh=EP2X`tDOG*T&yS z(TF)hV@&8IKSE%)VnNAMmRn$uW3OB&v2PRfl-VY3Lf{&fm`~w4=5So0R kw}a7Pas;0`qxa+nzA{s3Mwt%`n8Zhr*cU7kMM6OP0Hha6dH?_b diff --git a/Training_Tools/__pycache__/Tools.cpython-311.pyc b/Training_Tools/__pycache__/Tools.cpython-311.pyc index 9f1b3a43b4665fa558a90ad105ba3635849dce2d..136a8f946046dd4e1e6b011fad2fb23a7ab2c788 100644 GIT binary patch delta 916 zcmZ{i-%Aux6vyu!ch+&|*RHd!qo%D(th<@ZCi#Qh%7~1O#SB-l7sYZj%G$bXFJT}h zBq5ZY2k9x_%!fb-qCY^0poc;BL4>0Jz>SK)FgjwPy7P#26XzO?Y;e#-=#W}{W)py7VGVe~c523cI{-(+zW*74Zh4iQ6wRc7jgy47~bu$aR!=|AdKinwhQG#8iCt2m{$Gx{KKBP zo(-$EXth4i7Tfw9tIyH;Hq=0wC$Z`&CNqweakR`w3hh{(Ds~M!*07@uyJvkAOJYtz z&4^bBlWadBKxjw&*$+H0Qv5Wm8QpGc6Lti>aW3cr_ICG_*&FJorF2HTf72?OQAdel z!KY?>vX&M!5yFH+gaqLTp_9;!SYd*GA`yb`W~AGc^%C2Q2$zR=iIvf-%44XMu^xu} zVf_M%n!HQ6=Rb%ic;Sy8h*Ex;kRtplht{@|x}G1uJ()W$df}V@=!rDvEhYAEesc9M J|M9v>e*#)G%s~JE delta 1290 zcmZ{iNlX(_7=YjFGECcE^-j)WaBL(LjEyKa180M=VBm_P#I`)CfOdtA2geSNDdC@Jwt08^TAxl& z=>+fBpUf?zT>m078(zh70Z|HYvwVKe;4Umcg99*25_w&! z_CIHsm*?P*x%fMMK7Gxf8SdAa(+Xk%ZMPs2XgdYbl9t;io&1cD&6|xY)Q3{enSE(v z)|2SU%07@T`gn^_V&6?u3opfRt`j0u;!&Z>bp#&H@bxSUk(S*n!7CJjH9E}S3s9Qw zRB3usr3wBkjXk4?y4Gqk{8Y?=XrF=Q@tEkL`Fv5Vqcwa}yhUByZ@Ql8K5)f~$vblj zufYD#lB7uNS@U;Qv4FY2FrWi$FFgqO`|$*@NTz6r-q8FkYl@6+N5L$OVt2F!^3DlE z`cB-V+p`BxBLpJ&HM7%)eljX(HUP*Odt`B29@6tW<_~QqhO^D^+02H(UNW3pW=CK% znH7-xGSpc;jSi!nBsxj>S4IWI340}zP(I-MT8k#_~7!Y?QN^8BLg;)2BFRQ-UW{Pd#4-1vaXlKi6N zjCjA)^37Kn-Pjm2Cd+V~WvXG^%*rXs#CTw`Ge@uY?_>7XoS+Ctu_c-u!_>fQj+sWJc}?xvMep7ZOr0#-v?| eNxP_;b|EwGqH5lSg3616RaXS7Hs^60F#-VRw=H7; diff --git a/all_models_tools/all_model_tools.py b/all_models_tools/all_model_tools.py index 5a08df9..f91e406 100644 --- a/all_models_tools/all_model_tools.py +++ b/all_models_tools/all_model_tools.py @@ -50,7 +50,7 @@ def call_back(model_name, index, optimizer): model_dir = '../Result/save_the_best_model/' + model_name File.JudgeRoot_MakeDir(model_dir) - modelfiles = File.Make_Save_Root('best_model( ' + str(datetime.date.today()) + " )-" + str(index) + ".pt", model_dir) + modelfiles = File.Make_Save_Root('best_model( ' + str(datetime.date.today()) + " )-" + index + ".pt", model_dir) # model_mckp = ModelCheckpoint(modelfiles, monitor='val_loss', save_best_only=True, save_weights_only = True, mode='auto') diff --git a/experiments/Model_All_Step.py b/experiments/Model_All_Step.py index 9335c3d..0b913ae 100644 --- a/experiments/Model_All_Step.py +++ b/experiments/Model_All_Step.py @@ -1,20 +1,26 @@ from tqdm import tqdm -import torch from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score -from sklearn.model_selection import KFold from torchmetrics.functional import auroc -import torch.optim as optim -import numpy as np +from sklearn.model_selection import KFold +from sklearn.metrics import confusion_matrix + from all_models_tools.all_model_tools import call_back from Model_Loss.Loss import Entropy_Loss from merge_class.merge import merge -from draw_tools.Grad_cam import GradCAM -from torch.utils.data import Subset, DataLoader +from Training_Tools.PreProcess import ListDataset +from Load_process.file_processing import Process_File +from draw_tools.draw import plot_history, draw_heatmap +from Load_process.file_processing import Process_File + import time +import torch.optim as optim +import numpy as np +import torch +import pandas as pd class All_Step: - def __init__(self, PreProcess_Classes_Data, Batch, Model, Epoch, Number_Of_Classes, Model_Name): + def __init__(self, PreProcess_Classes_Data, Batch, Model, Epoch, Number_Of_Classes, Model_Name, Experiment_Name): self.PreProcess_Classes_Data = PreProcess_Classes_Data self.Training_DataLoader, self.Test_Dataloader = self.PreProcess_Classes_Data.Total_Data_Combine_To_DataLoader(Batch) @@ -25,48 +31,67 @@ class All_Step: self.Number_Of_Classes = Number_Of_Classes self.Model_Name = Model_Name - - pass + self.Experiment_Name = Experiment_Name def Training_Step(self, model_name, counter): - # 定義優化器,並設定 weight_decay 參數來加入 L2 正則化 - Optimizer = optim.SGD(self.Model.parameters(), lr=0.045, momentum = 0.9, weight_decay=0.1) - model_path, early_stopping, scheduler = call_back(model_name, counter, Optimizer) + # Lists to store metrics across all folds + all_fold_train_losses = [] + all_fold_val_losses = [] + all_fold_train_accuracies = [] + all_fold_val_accuracies = [] - criterion = Entropy_Loss() # 使用自定義的損失函數 - Merge_Function = merge() - train_losses = [] - val_losses = [] - train_accuracies = [] - val_accuracies = [] - Total_Epoch = 0 + # Define K-fold cross-validator + K_Fold = KFold(n_splits=5, shuffle=True, random_state=42) - K_Flod = KFold(n_splits = 5, shuffle = True, random_state = 42) + File = Process_File() - for epoch in range(self.Epoch): # 訓練迴圈 - self.Model.train() # 開始訓練 - running_loss = 0.0 - all_train_preds = [] - all_train_labels = [] - processed_samples = 0 + # Get the underlying dataset from PreProcess_Classes_Data + training_dataset = ListDataset(data_list = self.PreProcess_Classes_Data.Training_Datas, labels_list = self.PreProcess_Classes_Data.Training_Labels, status = True) - # 計算每個 epoch 的起始時間 - start_time = time.time() - total_samples = len(self.Training_DataLoader) - train_subset = "" - val_subset = "" + # K-Fold loop + for fold, (train_idx, val_idx) in enumerate(K_Fold.split(training_dataset)): + print(f"\nStarting Fold {fold + 1}/5") - for fold, (train_idx, vali_idx) in enumerate( K_Flod.split(self.PreProcess_Classes_Data.Training_Datas)): - # Create training and validation subsets for this fold - train_subset = Subset(self.Training_DataLoader, train_idx) - val_subset = Subset(self.Training_DataLoader, vali_idx) + # Create training and validation subsets for this fold + train_subset = torch.utils.data.Subset(training_dataset, train_idx) + val_subset = torch.utils.data.Subset(training_dataset, val_idx) - Training_Data = DataLoader(train_subset, self.Training_DataLoader.batch_size, num_workers = 0, pin_memory=True, shuffle = True) + # Wrap subsets in DataLoaders (use same batch size as original) + batch_size = self.Training_DataLoader.batch_size + train_loader = torch.utils.data.DataLoader(train_subset, batch_size=batch_size, shuffle=True) + val_loader = torch.utils.data.DataLoader(val_subset, batch_size=batch_size, shuffle=False) - epoch_iterator = tqdm(Training_Data, desc=f"Epoch [{epoch}/{self.Epoch}]") + # Reinitialize model and optimizer for each fold + self.Model = self.Model.__class__(self.Number_Of_Classes).to(self.device) # Reinitialize model + Optimizer = optim.SGD(self.Model.parameters(), lr=0.045, momentum=0.9, weight_decay=0.1) + model_path, early_stopping, scheduler = call_back(model_name, str(counter) + f"_fold{fold}", Optimizer) + + criterion = Entropy_Loss() # Custom loss function + Merge_Function = merge() + + # Lists to store metrics for this fold + train_losses = [] + val_losses = [] + train_accuracies = [] + val_accuracies = [] + + # Epoch loop + for epoch in range(self.Epoch): + self.Model.train() # Start training + running_loss = 0.0 + all_train_preds = [] + all_train_labels = [] + processed_samples = 0 + + # Calculate epoch start time + start_time = time.time() + total_samples = len(train_subset) # Total samples in subset, not DataLoader + + # Progress bar for training batches + epoch_iterator = tqdm(train_loader, desc=f"Fold {fold + 1}/5, Epoch [{epoch + 1}/{self.Epoch}]") for inputs, labels in epoch_iterator: - inputs, labels = torch.as_tensor(inputs).to(self.device), torch.as_tensor(labels).to(self.device) + inputs, labels = inputs.to(self.device), labels.to(self.device) # Already tensors from DataLoader Optimizer.zero_grad() outputs = self.Model(inputs) @@ -75,85 +100,112 @@ class All_Step: Optimizer.step() running_loss += loss.item() - # 收集訓練預測和標籤 - Output_Values, Output_Indexs = torch.max(outputs, dim = 1) - True_Indexs = np.argmax(labels.cpu().numpy(), 1) - + # Collect training predictions and labels + Output_Values, Output_Indexs = torch.max(outputs, dim=1) + True_Indexs = np.argmax(labels.cpu().numpy(), axis=1) + all_train_preds.append(Output_Indexs.cpu().numpy()) all_train_labels.append(True_Indexs) - processed_samples += len(inputs) + processed_samples += inputs.size(0) # Use size(0) for batch size - # 計算當前進度 + # Calculate progress and timing progress = (processed_samples / total_samples) * 100 - - # 計算經過時間和剩餘時間 elapsed_time = time.time() - start_time iterations_per_second = processed_samples / elapsed_time if elapsed_time > 0 else 0 eta = (total_samples - processed_samples) / iterations_per_second if iterations_per_second > 0 else 0 time_str = f"{int(elapsed_time//60):02d}:{int(elapsed_time%60):02d}<{int(eta//60):02d}:{int(eta%60):02d}" - # 計算當前批次的精確度(這裡需要根據你的具體需求調整) + # Calculate batch accuracy batch_accuracy = (Output_Indexs.cpu().numpy() == True_Indexs).mean() - # 更新進度條顯示 - epoch_iterator.set_description(f"Epoch [{epoch}/{self.Epoch}]") + # Update progress bar epoch_iterator.set_postfix_str( - f"{processed_samples}/{total_samples} [{time_str}, {iterations_per_second:.2f}it/s, " + - f"acc={batch_accuracy:.3f}, loss={loss.item():.3f}, ]" + f"{processed_samples}/{total_samples} [{time_str}, {iterations_per_second:.2f}it/s, " + f"acc={batch_accuracy:.3f}, loss={loss.item():.3f}]" ) epoch_iterator.close() + # Merge predictions and labels all_train_preds = Merge_Function.merge_data_main(all_train_preds, 0, len(all_train_preds)) all_train_labels = Merge_Function.merge_data_main(all_train_labels, 0, len(all_train_labels)) - Training_Loss = running_loss / len(self.Training_DataLoader) + Training_Loss = running_loss / len(train_loader) train_accuracy = accuracy_score(all_train_labels, all_train_preds) train_losses.append(Training_Loss) train_accuracies.append(train_accuracy) + # Validation step self.Model.eval() val_loss = 0.0 all_val_preds = [] all_val_labels = [] with torch.no_grad(): - for inputs, labels in val_subset: - inputs, labels = torch.as_tensor(inputs).to(self.device), torch.as_tensor(labels).to(self.device) - + for inputs, labels in val_loader: + inputs, labels = inputs.to(self.device), labels.to(self.device) outputs = self.Model(inputs) loss = criterion(outputs, labels) val_loss += loss.item() - # 收集訓練預測和標籤 - Output_Values, Output_Indexs = torch.max(outputs, dim = 1) - True_Indexs = np.argmax(labels.cpu().numpy(), 1) + # Collect validation predictions and labels + Output_Values, Output_Indexs = torch.max(outputs, dim=1) + True_Indexs = np.argmax(labels.cpu().numpy(), axis=1) all_val_preds.append(Output_Indexs.cpu().numpy()) all_val_labels.append(True_Indexs) - val_loss /= len(val_subset) + # Merge predictions and labels + all_val_preds = Merge_Function.merge_data_main(all_val_preds, 0, len(all_val_preds)) + all_val_labels = Merge_Function.merge_data_main(all_val_labels, 0, len(all_val_labels)) + + val_loss /= len(val_loader) val_accuracy = accuracy_score(all_val_labels, all_val_preds) val_losses.append(val_loss) val_accuracies.append(val_accuracy) - # print(f"Val_loss: {val_loss:.4f}, Val_accuracy: {val_accuracy:0.2f}\n") + # Early stopping early_stopping(val_loss, self.Model, model_path) if early_stopping.early_stop: - print("Early stopping triggered. Training stopped.") - Total_Epoch = epoch + print(f"Early stopping triggered in Fold {fold + 1} at epoch {epoch + 1}") + Total_Epoch = epoch + 1 break - # 學習率調整 + # Learning rate adjustment scheduler.step(val_loss) - return train_losses, val_losses, train_accuracies, val_accuracies, Total_Epoch + else: # If no early stopping + Total_Epoch = self.Epoch - def Evaluate_Model(self, cnn_model, counter): - # 測試模型 + # Store fold results + all_fold_train_losses.append(train_losses) + all_fold_val_losses.append(val_losses) + all_fold_train_accuracies.append(train_accuracies) + all_fold_val_accuracies.append(val_accuracies) + + Losses = [train_losses, val_losses] + Accuracies = [train_accuracies, val_accuracies] + plot_history(Total_Epoch, Losses, Accuracies, "train" + str(fold), self.Experiment_Name) # 將訓練結果化成圖,並將化出來的圖丟出去儲存 + + # Aggregate results across folds + avg_train_losses = np.mean([losses[-1] for losses in all_fold_train_losses]) + avg_val_losses = np.mean([losses[-1] for losses in all_fold_val_losses]) + avg_train_accuracies = np.mean([acc[-1] for acc in all_fold_train_accuracies]) + avg_val_accuracies = np.mean([acc[-1] for acc in all_fold_val_accuracies]) + + print(f"\nCross-Validation Results:") + print(f"Avg Train Loss: {avg_train_losses:.4f}, Avg Val Loss: {avg_val_losses:.4f}") + print(f"Avg Train Acc: {avg_train_accuracies:.4f}, Avg Val Acc: {avg_val_accuracies:.4f}") + + File.Save_TXT_File(content = f"\nCross-Validation Results:\nAvg Train Loss: {avg_train_losses:.4f}, Avg Val Loss: {avg_val_losses:.4f}\nAvg Train Acc: {avg_train_accuracies:.4f}, Avg Val Acc: {avg_val_accuracies:.4f}\n", File_Name = "Training_Average_Result") + + pass + + def Evaluate_Model(self, cnn_model, Model_Name, counter): + # (Unchanged Evaluate_Model method) cnn_model.eval() True_Label, Predict_Label = [], [] True_Label_OneHot, Predict_Label_OneHot = [], [] @@ -162,33 +214,54 @@ class All_Step: with torch.no_grad(): for images, labels in self.Test_Dataloader: images, labels = torch.tensor(images).to(self.device), torch.tensor(labels).to(self.device) - outputs = cnn_model(images) - - # 收集訓練預測和標籤 Output_Values, Output_Indexs = torch.max(outputs, 1) True_Indexs = np.argmax(labels.cpu().numpy(), 1) True_Label.append(Output_Indexs.cpu().numpy()) Predict_Label.append(True_Indexs) - Predict_Label_OneHot.append(torch.tensor(outputs, dtype = torch.float32).cpu().numpy()[0]) - True_Label_OneHot.append(torch.tensor(labels, dtype = torch.int).cpu().numpy()[0]) - - # # 創建 GradCAM 實例 - # Layers = cnn_model.base_model.body.conv4.pointwise - # grad_cam = GradCAM(cnn_model, target_layer="base_model") - # # 可視化 Grad-CAM - # grad_cam.visualize(outputs, images, target_class = 3, File_Name = counter, model_name = self.Model_Name) + Predict_Label_OneHot.append(torch.tensor(outputs, dtype=torch.float32).cpu().numpy()[0]) + True_Label_OneHot.append(torch.tensor(labels, dtype=torch.int).cpu().numpy()[0]) loss /= len(self.Test_Dataloader) - True_Label_OneHot = torch.tensor(True_Label_OneHot, dtype = torch.int) - Predict_Label_OneHot = torch.tensor(Predict_Label_OneHot, dtype = torch.float32) + True_Label_OneHot = torch.tensor(True_Label_OneHot, dtype=torch.int) + Predict_Label_OneHot = torch.tensor(Predict_Label_OneHot, dtype=torch.float32) accuracy = accuracy_score(True_Label, Predict_Label) - precision = precision_score(True_Label, Predict_Label, average = "macro") - recall = recall_score(True_Label, Predict_Label, average = "macro") - AUC = auroc(Predict_Label_OneHot, True_Label_OneHot, num_labels = self.Number_Of_Classes, task = "multilabel", average = "macro") - f1 = f1_score(True_Label, Predict_Label, average = "macro") - return loss, accuracy, precision, recall, AUC, f1, True_Label, Predict_Label \ No newline at end of file + precision = precision_score(True_Label, Predict_Label, average="macro") + recall = recall_score(True_Label, Predict_Label, average="macro") + AUC = auroc(Predict_Label_OneHot, True_Label_OneHot, num_labels=self.Number_Of_Classes, task="multilabel", average="macro") + f1 = f1_score(True_Label, Predict_Label, average="macro") + + Matrix = self.record_matrix_image(True_Label, Predict_Label, Model_Name, counter) + print(self.record_everyTime_test_result(loss, accuracy, precision, recall, AUC, f1, counter, self.Experiment_Name, Matrix)) # 紀錄當前訓練完之後的預測結果,並輸出成csv檔 + + pass + + def record_matrix_image(self, True_Labels, Predict_Labels, model_name, index): + '''劃出混淆矩陣(熱力圖)''' + # 計算混淆矩陣 + matrix = confusion_matrix(True_Labels, Predict_Labels) + draw_heatmap(matrix, model_name, index) # 呼叫畫出confusion matrix的function + + return matrix + + def record_everyTime_test_result(self, loss, accuracy, precision, recall, auc, f, indexs, model_name, Matrix): + '''記錄我單次的訓練結果並將它輸出到檔案中''' + File = Process_File() + + Dataframe = pd.DataFrame( + { + "model_name" : str(model_name), + "loss" : "{:.2f}".format(loss), + "precision" : "{:.2f}%".format(precision * 100), + "recall" : "{:.2f}%".format(recall * 100), + "accuracy" : "{:.2f}%".format(accuracy * 100), + "f" : "{:.2f}%".format(f * 100), + "AUC" : "{:.2f}%".format(auc * 100) + }, index = [indexs]) + File.Save_CSV_File("train_result", Dataframe) + + return Dataframe \ No newline at end of file diff --git a/experiments/__pycache__/Model_All_Step.cpython-311.pyc b/experiments/__pycache__/Model_All_Step.cpython-311.pyc index 2d95cf89375ecb7087df7196710ab3e4a53985e3..6a0370cd01caa51b6036af633681d2b7154b418c 100644 GIT binary patch literal 16749 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 bW94-A-crwl=Vl9gI()*%f3-s@KkENC!L5Db literal 11523 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 diff --git a/experiments/__pycache__/pytorch_Model.cpython-311.pyc b/experiments/__pycache__/pytorch_Model.cpython-311.pyc index d6113b40d95c81583819ab4df0baf933f1b27299..c19afd8578af0b88cc01630c7954f72b90ce0693 100644 GIT binary patch delta 389 zcmX>i^iP0yIWI340}uqiJe|%mkyp~k0mzxokiw9{n8T3E7{$m4VKYTBF)_F^q%gHG zq%fy4W-)^_fxt2#Yc-q~#gf7p%%I8g5+vofam7INj9CTFt9F|uv$V0pn9 z$O)9xWGmtaQnv)s@{7t7i&Em#QWHx`i&Be=gh0aVX*r1{C8>EuB0ye|6i5Seku*q# zvEmk6erZWTX-P52S_K7#BDu*2+0+>2C%<4T1d>tgTBbZ8U8*4Eyz%kLIf=!^$*DOx z@$s6BMY2HAVn!h0P$UOZ#R4N(C+}nrNSB9kHCb?(5~l+TNG||BpH?*h delta 602 zcmY*VO-md>5bd6?o!xb0lVC&)IuH@YfG2YhBqXPtBIe@|=F$w?y>X;xMyq=h@uFaE zImr<66GD!fUm$q$w8vq7L2}DE2TApeLbki8s#mYN`&HizuI>llgP=!nb>aHM;aRZo zP9pe5IN?;1xQ#TkVvDx9ojI{{o4c78drfZ1PUgq{ZM_?JE%K6Z`!nH=u=aXq+w=2% zPT!Kq{cRrGj%e*=1s77C!=**ta>Kp}17waCUKKnYrGmd7ihZ3H`8s21o@&N=Ki@dN z=xd`k@?e0W9*he3lmKTVk?1i91rJQQGm?qcB8NFduxJk0@W?Rqu=a|v-XCjaBM!q5 zmdh{RDt%mDcn35rS2}A?jSg5f?Ezy$nJ6_BQZg1%Si-8J=$^x}>2mK}w><6a9EW!> znyFn~z;L(ro3Nhea1Y74-@*b%%WAg`51ZP@RGDctB)P(|GFA8f%iD8p4;bk%Yp(O~ zx5iR5I)0F22n}PD{q?u-f023y8wibL^%dP8n^IblnUiK$WNtET6