Stomach_Cancer_Pytorch/experiments/experiment.py
2024-12-07 01:51:50 +08:00

260 lines
11 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from all_models_tools.all_model_tools import call_back
from Read_and_process_image.ReadAndProcess import Read_image_and_Process_image
from draw_tools.draw import plot_history, Confusion_Matrix_of_Two_Classification
from Load_process.Load_Indepentend import Load_Indepentend_Data
from _validation.ValidationTheEnterData import validation_the_enter_data
from Load_process.file_processing import Process_File
from merge_class.merge import merge
from draw_tools.Grad_cam import Grad_CAM
from sklearn.metrics import confusion_matrix
from Image_Process.Image_Generator import Image_generator
import pandas as pd
import time
import torch.optim as optim
from experiments.pytorch_Model import ModifiedXception
from Load_process.LoadData import Loding_Data_Root, Load_Data_Tools
import torch
from Model_Loss.Loss import Entropy_Loss
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from torchmetrics.functional import auroc
import torch.nn as nn
from torchinfo import summary
import numpy as np
from tqdm import tqdm
from torch.nn import functional
class experiments():
def __init__(self, tools, Targets, status, Number_Of_Classes):
'''
# 實驗物件
## 說明:
* 用於開始訓練pytorch的物件裡面分為數個方法負責處理實驗過程的種種
## parmeter:
* Topic_Tool: 讀取訓練、驗證、測試的資料集與Label等等的內容
* cut_image: 呼叫切割影像物件
* merge: 合併的物件
* model_name: 模型名稱,告訴我我是用哪個模型(可能是預處理模型/自己設計的模型)
* experiment_name: 實驗名稱
* epoch: 訓練次數
* train_batch_size: 訓練資料的batch
* convolution_name: Grad-CAM的最後一層的名稱
* Number_Of_Classes: Label的類別
* Status: 選擇現在資料集的狀態
* device: 決定使用GPU或CPU
## Method:
* processing_main: 實驗物件的進入點
* construct_model: 決定實驗用的Model
* Training_Step: 訓練步驟,開始進行訓練驗證的部分
* Evaluate_Model: 驗證模型的準確度
* record_matrix_image: 劃出混淆矩陣(熱力圖)
* record_everyTime_test_result: 記錄我單次的訓練結果並將它輸出到檔案中
'''
self.Topic_Tool = tools
self.cut_image = Load_Indepentend_Data(self.Topic_Tool.Get_Data_Label(), self.Topic_Tool.Get_OneHot_Encording_Label())
self.image_processing = Read_image_and_Process_image()
self.merge = merge()
self.model_name = "Xception"
self.experiment_name = "Xception Skin to train Normal stomach cancer"
self.generator_batch_size = 50
self.epoch = 10000
self.train_batch_size = 64
self.layers = 1
self.convolution_name = "block14_sepconv2"
self.Number_Of_Classes = Number_Of_Classes
self.Grad = ""
self.Status = status
self.Tragets = Targets
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
pass
def processing_main(self, Training_Data, counter):
Train, Test, Validation = self.Topic_Tool.Get_Save_Roots(self.Status) # 要換不同資料集就要改
Load_Tools = Load_Data_Tools()
Training_Data = Load_Tools.DataLoad_Image_Root(Training_Data, self.train_batch_size)
test = Load_Tools.Load_ImageFolder_Data(Test, "transform")
validation = Load_Tools.Load_ImageFolder_Data(Validation, "transform")
self.test = Load_Tools.DataLoad_Image_Root(test, 1)
self.Validation = Load_Tools.DataLoad_Image_Root(validation, 1)
# self.Grad = Grad_CAM(self.Topic_Tool.Get_Data_Label(), Test_labels, self.experiment_name, self.convolution_name)
cnn_model = self.construct_model() # 呼叫讀取模型的function
print(summary(cnn_model, input_size=(int(self.train_batch_size / 2), 3, 512, 512)))
print("訓練開始")
train_losses, val_losses, train_accuracies, val_accuracies = self.Training_Step(cnn_model, Training_Data, counter)
print("訓練完成!")
loss, accuracy, precision, recall, AUC, f1, True_Label, Predict_Label = self.Evaluate_Model(cnn_model)
self.record_matrix_image(True_Label, Predict_Label, self.model_name, counter)
print(self.record_everyTime_test_result(loss, accuracy, precision, recall, AUC, f1, counter, self.experiment_name)) # 紀錄當前訓練完之後的預測結果並輸出成csv檔
Losses = [train_losses, val_losses]
Accuracyes = [train_accuracies, val_accuracies]
plot_history(self.epoch, Losses, Accuracyes, "train" + str(counter), self.experiment_name) # 將訓練結果化成圖,並將化出來的圖丟出去儲存
# self.Grad.process_main(cnn_model, counter, self.test)
return loss, accuracy, precision, recall, AUC, f1
def construct_model(self):
'''決定我這次訓練要用哪個model'''
cnn_model = ModifiedXception()
if torch.cuda.device_count() > 1:
cnn_model = nn.DataParallel(cnn_model)
cnn_model = cnn_model.to(self.device)
return cnn_model
def Training_Step(self, model, Training, counter):
# 定義優化器,並設定 weight_decay 參數來加入 L2 正則化
Optimizer = optim.SGD(model.parameters(), lr=0.045, momentum = 0.9, weight_decay=0.1)
model_path, early_stopping, scheduler = call_back(self.model_name, counter, Optimizer)
criterion = Entropy_Loss() # 使用自定義的損失函數
train_losses = []
val_losses = []
train_accuracies = []
val_accuracies = []
for epoch in range(self.epoch):
model.train()
running_loss = 0.0
all_train_preds = []
all_train_labels = []
epoch_iterator = tqdm(Training, desc= "Training (Epoch %d)" % epoch)
for inputs, labels in epoch_iterator:
OneHot_labels = functional.one_hot(labels, self.Number_Of_Classes)
# labels = np.reshape(labels, (int(labels.shape[0]), 1))
inputs, OneHot_labels = inputs.to(self.device), OneHot_labels.to(self.device)
# inputs, labels = inputs.cuda(), labels.cuda()
Optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, OneHot_labels)
loss.backward()
Optimizer.step()
running_loss += loss.item()
# 收集訓練預測和標籤
_, preds = torch.max(outputs, 1)
all_train_preds.extend(preds.cpu().numpy())
all_train_labels.extend(labels.cpu().numpy())
Training_Loss = running_loss/len(Training)
# all_train_labels = torch.FloatTensor(all_train_labels)
# all_train_labels = torch.argmax(all_train_labels, 1)
train_accuracy = accuracy_score(all_train_labels, all_train_preds)
train_losses.append(Training_Loss)
train_accuracies.append(train_accuracy)
print(f"Epoch [{epoch+1}/{self.epoch}], Loss: {Training_Loss:.4f}, Accuracy: {train_accuracy:0.2f}", end = ' ')
model.eval()
val_loss = 0.0
all_val_preds = []
all_val_labels = []
with torch.no_grad():
for inputs, labels in self.Validation:
OneHot_labels = functional.one_hot(labels, self.Number_Of_Classes)
inputs, OneHot_labels = inputs.to(self.device), OneHot_labels.to(self.device)
outputs = model(inputs)
loss = criterion(outputs, OneHot_labels)
val_loss += loss.item()
# 驗證預測與標籤
_, preds = torch.max(outputs, 1)
all_val_preds.extend(preds.cpu().numpy())
all_val_labels.extend(labels.cpu().numpy())
# 計算驗證損失與準確率
val_loss /= len(self.Validation)
val_accuracy = accuracy_score(all_val_labels, all_val_preds)
val_losses.append(val_loss)
val_accuracies.append(val_accuracy)
print(f"Epoch [{epoch+1}/{self.epoch}], Loss: {val_loss:.4f}, Accuracy: {val_accuracy:0.2f}")
early_stopping(val_loss, model, model_path)
if early_stopping.early_stop:
print("Early stopping triggered. Training stopped.")
break
# 學習率調整
scheduler.step(val_loss)
return train_losses, val_losses, train_accuracies, val_accuracies
def Evaluate_Model(self, cnn_model):
# 測試模型
cnn_model.eval()
True_Label, Predict_Label = [], []
loss = 0.0
with torch.no_grad():
for images, labels in self.test:
OneHot_labels = functional.one_hot(labels, self.Number_Of_Classes)
images, OneHot_labels = images.to(self.device), OneHot_labels.to(self.device)
outputs = cnn_model(images)
_, predicted = torch.max(outputs, 1)
Predict_Label.extend(predicted.cpu().numpy())
True_Label.extend(labels.cpu().numpy())
loss /= len(self.test)
accuracy = accuracy_score(True_Label, Predict_Label)
precision = precision_score(True_Label, Predict_Label)
recall = recall_score(True_Label, Predict_Label)
AUC = auroc(True_Label, Predict_Label, task = ["Stomatch_Cancer", "Normal"])
f1 = f1_score(True_Label, Predict_Label)
return loss, accuracy, precision, recall, AUC, f1, True_Label, Predict_Label
def record_matrix_image(self, True_Labels, Predict_Labels, model_name, index):
'''劃出混淆矩陣(熱力圖)'''
# 計算混淆矩陣
matrix = confusion_matrix(True_Labels, Predict_Labels)
Confusion_Matrix_of_Two_Classification(model_name, matrix, index) # 呼叫畫出confusion matrix的function
return matrix.real
def record_everyTime_test_result(self, loss, accuracy, precision, recall, auc, f, indexs, model_name):
'''記錄我單次的訓練結果並將它輸出到檔案中'''
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)
# File.Save_TXT_File("Matrix_Result : " + str(Matrix), model_name + "_train" + str(indexs))
return Dataframe