├── Model.py ├── README.md ├── models └── weights.pt ├── test.py └── train.py /Model.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import numpy as np 3 | import torch.nn.functional as F 4 | 5 | # çıktı boyutunu otomatik olarak hesaplamak 6 | def findConv2dOutShape(H_in,W_in,conv,pool=2): 7 | 8 | # aldığı argümanlar 9 | kernel_size=conv.kernel_size 10 | stride=conv.stride 11 | padding=conv.padding 12 | dilation=conv.dilation 13 | 14 | 15 | H_out=np.floor((H_in+2*padding[0]-dilation[0]*(kernel_size[0]-1)-1)/stride[0]+1) 16 | 17 | W_out=np.floor((W_in+2*padding[1]-dilation[1]*(kernel_size[1]-1)-1)/stride[1]+1) 18 | 19 | if pool: 20 | H_out/=pool 21 | W_out/=pool 22 | 23 | return int(H_out),int(W_out) # verilerin yüksekliğini ve genişliğinin geri döndürür. 24 | 25 | class Net(nn.Module): 26 | 27 | def __init__(self, params): 28 | 29 | super(Net, self).__init__() 30 | 31 | C_in,H_in,W_in=params["input_shape"] # verilerin tensör boyutu 32 | init_f=params["initial_filters"] # filitre boyutu 33 | num_fc1=params["num_fc1"] # tam bağlı katmandaki birimler 34 | num_classes=params["num_classes"] # sınıflandırma türü 35 | self.dropout_rate=params["dropout_rate"] # iletim sönümü oranı 36 | self.boyut = params["size"] # filitre boyutu 37 | 38 | # CNN katmanlarımız 39 | # parametreler: 1-) aldığı resmin tensör boyutu 40 | # 2-) filitre sayısı 41 | # 3-) filitre boyutu 42 | self.conv1 = nn.Conv2d(C_in, init_f, kernel_size=self.boyut) 43 | h,w=findConv2dOutShape(H_in,W_in,self.conv1) 44 | self.conv2 = nn.Conv2d(init_f, 2*init_f, kernel_size=self.boyut) 45 | h,w=findConv2dOutShape(h,w,self.conv2) 46 | self.conv3 = nn.Conv2d(2*init_f, 4*init_f, kernel_size=self.boyut) 47 | h,w=findConv2dOutShape(h,w,self.conv3) 48 | self.conv4 = nn.Conv2d(4*init_f, 8*init_f, kernel_size=self.boyut) 49 | h,w=findConv2dOutShape(h,w,self.conv4) 50 | # tamamen bağlı katmanlar 51 | self.num_flatten=h*w*8*init_f 52 | self.fc1 = nn.Linear(self.num_flatten, num_fc1) 53 | self.fc2 = nn.Linear(num_fc1, num_classes) 54 | 55 | 56 | def forward(self, x): 57 | 58 | # katmanların aktivasyon fonksiyonları 59 | x = F.relu(self.conv1(x)) 60 | # En büyükleri birktirme 61 | # Parametre sayısını azaltmak için max pooling kullanırız. 62 | # en büyükleri biriktirmek. 63 | # her MaxPooling katmanından sonra nitelik haritalarının boyutu yarıya düşer. 64 | # girdi nitelik haritasından pencereler çıkarıp her kanalın en büyük değerini almaktır. 65 | # Her aktivasyon haritası için ayrı ayrı uygularız (Derinliği etkilemez.) 66 | # Filitrelemedeki en büyük değeri alır. 67 | x = F.max_pool2d(x, 2, 2) 68 | x = F.relu(self.conv2(x)) 69 | x = F.max_pool2d(x, 2, 2) 70 | x = F.relu(self.conv3(x)) 71 | x = F.max_pool2d(x, 2, 2) 72 | x = F.relu(self.conv4(x)) 73 | x = F.max_pool2d(x, 2, 2) 74 | x = x.view(-1, self.num_flatten) 75 | x = F.relu(self.fc1(x)) 76 | 77 | # iletim sönümü : 78 | # modelin aşırı uydurma yapmasını engeller. 79 | # Sinir ağlarının düzleştirilmesinde kullanılır. 80 | # verdiğimiz orana göre elemanları sıfırlar. 81 | x=F.dropout(x, self.dropout_rate, training= self.training) 82 | x = self.fc2(x) 83 | 84 | # ikili sınıflandırma yapan son katman 85 | return F.log_softmax(x, dim=1) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![demir](https://img.shields.io/badge/PyTorch-V1.2.0-red) 2 | ![licence](https://img.shields.io/badge/demir-ai-blueviolet) 3 | ![licence](https://img.shields.io/badge/Ahmet%20Furkan-DEM%C4%B0R-blue) 4 | 5 | # Deep-Learning-with-PyTorch-V3 6 | 7 | * Görüntü sınıflandırması (görüntü tanıma olarak da bilinir) bilgisayardaki önemli bir görevdir. 8 | * Bu görevde, görüntülerin bir ana nesne içerdiğini varsayıyoruz. İşte amacımız 9 | ana nesneyi sınıflandırmak. 10 | * İki tür görüntü sınıflandırması vardır: ikili sınıflandırma 11 | ve çok sınıflı sınıflandırma. 12 | * Bu projede, metastatik(Göğüs) kanseri tanımlamak için bir algoritmanın nasıl oluşturulacağını öğreneceğiz. 13 | 14 | 15 | # Adımlarımız 16 | 17 | * Veri kümesini keşfetme 18 | * Özel bir veri kümesi oluşturma 19 | * Veri kümesini bölme ve Verileri dönüştürme 20 | * Veri yükleyici oluşturma 21 | * Sınıflandırma modelinin oluşturulması 22 | * Kayıp fonksiyonunun tanımlanması, Optimize ediciyi tanımlama 23 | * Modelin eğitimi ve değerlendirilmesi 24 | * Modelin testi 25 | 26 | 27 | # Veri seti 28 | 29 | * Histopatolojik Kanser Tespiti yarışmasında verilen veri setini kullanacağız. Bu yarışmanın amacı, görüntü yamalarını normal veya kötü huylu olarak sınıflandırmaktır. 30 | * Veri seti: 7.2 Gb, 277485 veri 31 | * Veri seti (Histopathologic Cancer Detection) = https://www.kaggle.com/c/histopathologic-cancer-detection 32 | 33 | 34 | # Modelimiz 35 | 36 | ![rhtrh](https://user-images.githubusercontent.com/54184905/81787781-3afb9800-950a-11ea-839b-8b83447c2db6.png) 37 | 38 | 39 | # Modelimizin Kaybı ve Başarımı 40 | 41 | ![Screenshot_2020-05-13_03-09-14](https://user-images.githubusercontent.com/54184905/81787922-67171900-950a-11ea-9f66-3353382a37ed.png) 42 | 43 | ![Screenshot_2020-05-13_03-09-30](https://user-images.githubusercontent.com/54184905/81787926-67afaf80-950a-11ea-9def-b229ab0b095f.png) 44 | 45 | 46 | # Modelimizin Testi 47 | 48 | ![Screenshot_2020-05-13_10-34-56](https://user-images.githubusercontent.com/54184905/81788025-8f067c80-950a-11ea-8ae1-65d3855442c1.png) 49 | ![Screenshot_2020-05-13_10-47-38](https://user-images.githubusercontent.com/54184905/81788030-9037a980-950a-11ea-8152-327db36c7dd7.png) 50 | 51 | # Kaynak 52 | 53 | * PyTorch documentation = https://pytorch.org/docs/stable/index.html 54 | * PyTorch Computer Vision book = https://www.packtpub.com/data/pytorch-computer-vision-cookbook 55 | -------------------------------------------------------------------------------- /models/weights.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmetFurkanDEMIR/Deep-Learning-with-PyTorch-V3/4a5f6a8e173d61565a73fd7ae72443f8b6d2c459/models/weights.pt -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import numpy as np 3 | import torch 4 | from PIL import Image 5 | from torch.utils.data import Dataset 6 | import pandas as pd 7 | import torchvision.transforms as transforms 8 | import os 9 | import torchvision.transforms as transforms 10 | import Model 11 | import time 12 | from torchvision import utils 13 | import numpy as np 14 | import matplotlib.pyplot as plt 15 | 16 | np.random.seed(0) 17 | 18 | # modelin girdileri, açıklamalar modelde mevcuttr. 19 | params_model={ 20 | "input_shape": (3,96,96), 21 | "initial_filters": 8, 22 | "num_fc1": 100, 23 | "dropout_rate": 0.25, 24 | "num_classes": 2, 25 | "size": 3 26 | } 27 | 28 | #modelimiz 29 | cnn_model = Model.Net(params_model) 30 | 31 | 32 | path2weights="./models/weights.pt" 33 | # öğrenmiş ağırlıklar modele aktarılır 34 | cnn_model.load_state_dict(torch.load(path2weights)) 35 | 36 | print(cnn_model.eval()) 37 | 38 | # test cpu üzerinden gerçekleşecek 39 | device = torch.device("cpu") 40 | cnn_model=cnn_model.to(device) 41 | 42 | 43 | torch.manual_seed(0) 44 | 45 | class histoCancerDataset(Dataset): 46 | 47 | def __init__(self, data_dir, transform,data_type="test"): 48 | 49 | # eğitim verilerini tanımladık 50 | path2data=os.path.join(data_dir,data_type) 51 | 52 | # verilerin listesi 53 | filenames = os.listdir(path2data) 54 | 55 | # verilerin tamamı 56 | self.full_filenames = [os.path.join(path2data, f) for f in filenames] 57 | 58 | # etiketler 59 | path2csvLabels=os.path.join(data_dir,"test_labels.csv") 60 | labels_df=pd.read_csv(path2csvLabels) 61 | 62 | # veri indexleri 63 | labels_df.set_index("id", inplace=True) 64 | 65 | # etiketleri alıyoruz 66 | self.labels = [labels_df.loc[filename[:-4]].values[0] for filename in filenames] 67 | 68 | self.transform = transform 69 | 70 | def __len__(self): 71 | # return veriseti boyutu 72 | return len(self.full_filenames) 73 | 74 | def __getitem__(self, idx): 75 | # veriler ve etiketleri 76 | image = Image.open(self.full_filenames[idx]) # PIL image 77 | image = self.transform(image) 78 | return image, self.labels[idx] 79 | 80 | 81 | def deploy_model(model,dataset,device, num_classes=2,sanity_check=False): 82 | 83 | len_data=len(dataset) 84 | 85 | 86 | y_out=torch.zeros(len_data,num_classes) 87 | 88 | 89 | y_gt=np.zeros((len_data),dtype="uint8") 90 | 91 | 92 | model=model.to(device) 93 | 94 | elapsed_times=[] 95 | with torch.no_grad(): 96 | for i in range(len_data): 97 | x,y=dataset[i] 98 | y_gt[i]=y 99 | start=time.time() 100 | y_out[i]=model(x.unsqueeze(0).to(device)) 101 | elapsed=time.time()-start 102 | elapsed_times.append(elapsed) 103 | 104 | if sanity_check is True: 105 | break 106 | 107 | inference_time=np.mean(elapsed_times)*1000 108 | print("average inference time per image on %s: %.2f ms " %(device,inference_time)) 109 | return y_out.numpy(),y_gt 110 | 111 | 112 | # test verileri için 113 | data_transformer = transforms.Compose([transforms.ToTensor()]) 114 | 115 | path2csv="test_labels.csv" 116 | labels_df=pd.read_csv(path2csv) 117 | labels_df.head() 118 | 119 | data_dir = "" 120 | # veriler 121 | histo_test = histoCancerDataset(data_dir, data_transformer,data_type="test") 122 | print(len(histo_test)) 123 | 124 | 125 | y_test_out,_=deploy_model(cnn_model,histo_test, device, sanity_check=False) 126 | 127 | 128 | y_test_pred=np.argmax(y_test_out,axis=1) 129 | print(y_test_pred.shape) 130 | 131 | 132 | np.random.seed(0) 133 | 134 | # görselleştirme 135 | def show(img,y,color=True): 136 | 137 | npimg = img.numpy() 138 | 139 | 140 | npimg_tr=np.transpose(npimg, (1,2,0)) 141 | 142 | if color==False: 143 | npimg_tr=npimg_tr[:,:,0] 144 | plt.imshow(npimg_tr,interpolation='nearest',cmap="gray") 145 | else: 146 | 147 | plt.imshow(npimg_tr,interpolation='nearest') 148 | plt.title("label: "+str(y)) 149 | 150 | grid_size=4 151 | rnd_inds=np.random.randint(0,len(histo_test),grid_size) 152 | print("image indices:",rnd_inds) 153 | 154 | x_grid_test=[histo_test[i][0] for i in range(grid_size)] 155 | y_grid_test=[y_test_pred[i] for i in range(grid_size)] 156 | 157 | x_grid_test=utils.make_grid(x_grid_test, nrow=4, padding=2) 158 | print(x_grid_test.shape) 159 | 160 | plt.rcParams['figure.figsize'] = (10.0, 5) 161 | show(x_grid_test,y_grid_test) 162 | 163 | -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | #%% --- Veri ön inceleme --- 2 | 3 | import pandas as pd 4 | import Model 5 | 6 | # eğitim setinin etiketleri yolu 7 | path2csv="./train_labels.csv" 8 | 9 | # etiketler okunur 10 | labels_df=pd.read_csv(path2csv) 11 | 12 | # ilk bes etiket 13 | print(labels_df.head()) 14 | 15 | # etiketlerde 0 ve 1 olan veri sayısı 16 | print(labels_df['label'].value_counts()) 17 | 18 | import matplotlib.pylab as plt 19 | from PIL import Image, ImageDraw 20 | import numpy as np 21 | import os 22 | 23 | # eğitim verilerinin yolu 24 | path2train="./train/" 25 | 26 | # inceleyeceğimiz verilerin siyah beyaz olmasını sağlıyoruz 27 | color=False 28 | 29 | # etiket değeri 1 olan veriler. 30 | malignantIds = labels_df.loc[labels_df['label']==1]['id'].values 31 | 32 | # bilgi sahibi olmak için verileri inceliyoruz. 33 | plt.rcParams['figure.figsize'] = (10.0, 10.0) 34 | plt.subplots_adjust(wspace=0, hspace=0) 35 | nrows,ncols=3,3 36 | for i,id_ in enumerate(malignantIds[:nrows*ncols]): 37 | full_filenames = os.path.join(path2train , id_ +'.tif') 38 | 39 | # resimler yüklenir. 40 | img = Image.open(full_filenames) 41 | 42 | draw = ImageDraw.Draw(img) 43 | draw.rectangle(((32, 32), (64, 64)),outline="green") 44 | 45 | plt.subplot(nrows, ncols, i+1) 46 | if color is True: 47 | plt.imshow(np.array(img)) 48 | else: 49 | plt.imshow(np.array(img)[:,:,0],cmap="gray") 50 | plt.axis('off') 51 | 52 | 53 | # resim tensör boyutu 54 | print("image shape:", np.array(img).shape) 55 | 56 | #%% --- Veri parçalama ve tensörlere aktarma 57 | 58 | import torch 59 | from PIL import Image 60 | from torch.utils.data import Dataset 61 | import pandas as pd 62 | import torchvision.transforms as transforms 63 | import os 64 | 65 | # çıkışları sabit tutuyoruz 66 | torch.manual_seed(0) 67 | 68 | # verileri çekiyoruz 69 | class histoCancerDataset(Dataset): 70 | 71 | def __init__(self, data_dir, transform,data_type="train"): 72 | 73 | # eğitim verilerini tanımladık 74 | path2data=os.path.join(data_dir,data_type) 75 | 76 | # verilerin listesi 77 | filenames = os.listdir(path2data) 78 | 79 | # verilerin tamamı 80 | self.full_filenames = [os.path.join(path2data, f) for f in filenames] 81 | 82 | # etiketler 83 | path2csvLabels=os.path.join(data_dir,"train_labels.csv") 84 | labels_df=pd.read_csv(path2csvLabels) 85 | 86 | # veri indexleri 87 | labels_df.set_index("id", inplace=True) 88 | 89 | # etiketleri alıyoruz 90 | self.labels = [labels_df.loc[filename[:-4]].values[0] for filename in filenames] 91 | 92 | self.transform = transform 93 | 94 | def __len__(self): 95 | # return veriseti boyutu 96 | return len(self.full_filenames) 97 | 98 | def __getitem__(self, idx): 99 | # veriler ve etiketleri 100 | image = Image.open(self.full_filenames[idx]) # PIL image 101 | image = self.transform(image) 102 | return image, self.labels[idx] 103 | 104 | 105 | 106 | # veri tensörleri oluşturmak için 107 | import torchvision.transforms as transforms 108 | # transformer 109 | data_transformer = transforms.Compose([transforms.ToTensor()]) 110 | 111 | data_dir = "" 112 | # oluşturduğumuz sınıf ile verileri alıyoruz 113 | histo_dataset = histoCancerDataset(data_dir, data_transformer, "train") 114 | # kaç adet veri ? 115 | print(len(histo_dataset)) 116 | 117 | # 9. veri ve etiketi 118 | img,label=histo_dataset[9] 119 | print(img.shape,torch.min(img),torch.max(img)) 120 | 121 | 122 | # verileri random bir şekilde eğitim ve doğrulama verisi olarak ayırmak için. 123 | from torch.utils.data import random_split 124 | 125 | len_histo=len(histo_dataset) 126 | # %80 eğitim 127 | len_train=int(0.8*len_histo) 128 | # %20 test 129 | len_val=len_histo-len_train 130 | 131 | # rastgele ayırma işlemi 132 | train_ds,val_ds=random_split(histo_dataset,[len_train,len_val]) 133 | 134 | # adetleri 135 | print("train dataset length:", len(train_ds)) 136 | print("validation dataset length:", len(val_ds)) 137 | 138 | 139 | # eğitim verisi 140 | for x,y in train_ds: 141 | print(x.shape,y) 142 | break 143 | 144 | # doğrulama verisi 145 | for x,y in val_ds: 146 | print(x.shape,y) 147 | break 148 | 149 | 150 | from torchvision import utils 151 | import numpy as np 152 | 153 | np.random.seed(0) 154 | 155 | # eğitim verisinde çeşitlendirme yaparak, verisetinde artış sağlıyoruz. 156 | train_transformer = transforms.Compose([ 157 | 158 | # verinin yatayda döndürülme açısı. 159 | transforms.RandomHorizontalFlip(p=0.5), 160 | 161 | # verinin dikeyde döndürülme açısı 162 | transforms.RandomVerticalFlip(p=0.5), 163 | # -45, 45 derece arasında döndürme işlemi 164 | transforms.RandomRotation(45), 165 | 166 | # görüntüyü 96,96 olarak yeniden boyutlandırır. 167 | transforms.RandomResizedCrop(96,scale=(0.8,1.0),ratio=(1.0,1.0)), 168 | 169 | # veriler tensör haline getirilir 170 | transforms.ToTensor()]) 171 | 172 | # doğrulama verilerini sadece tensör haline getiriyoruz. 173 | val_transformer = transforms.Compose([transforms.ToTensor()]) 174 | 175 | 176 | # dönüştürme işlevlerinin üzerine yaz 177 | train_ds.transform=train_transformer 178 | val_ds.transform=val_transformer 179 | 180 | from torch.utils.data import DataLoader 181 | 182 | # 32 lik yığınlarla veriyi karıştırarak bir veri tensörü oluşturuyoruz. 183 | train_dl = DataLoader(train_ds, batch_size=32, shuffle=True) 184 | 185 | # veriyi karıştırmadan 64 lük yığınlarla veri tensörü 186 | val_dl = DataLoader(val_ds, batch_size=64, shuffle=False) 187 | 188 | 189 | for x, y in train_dl: 190 | print(x.shape) # veri tensör noyutu 191 | print(y.shape) # etiketi 192 | break 193 | 194 | 195 | for x, y in val_dl: 196 | print(x.shape) # tensör 197 | print(y.shape) # etiket 198 | break 199 | 200 | 201 | 202 | # doğrulama veri kümesinin etiketleri 203 | y_val=[y for _,y in val_ds] 204 | 205 | 206 | #%% --- Modelimiz ve parametreleri --- 207 | 208 | 209 | # aldığı parametreler 210 | params_model={ 211 | "input_shape": (3,96,96), # aldığı tensör boyutu 212 | "initial_filters": 8, # filitre sayısı, 2 katına çıkarak artacaktır 213 | "num_fc1": 100, # tam bağlı katmandaki birimler 214 | "dropout_rate": 0.50, # iletim sönümü oranı 215 | "num_classes": 2, # 2 sınıf far 216 | "size": 3 # filitre boyutu 217 | } 218 | 219 | # modelimi Model.py adlı dosyadaki Net adlı class dan yaratıyoruz. 220 | cnn_model = Model.Net(params_model) 221 | 222 | 223 | # modelin hangi donanımdan eğitileceğine karar veriyoruz. 224 | device = torch.device("cpu") 225 | cnn_model=cnn_model.to(device) 226 | 227 | # model katmanları hakkında bilgiler 228 | print(cnn_model) 229 | 230 | # modelin eğitileceği donanım 231 | print(next(cnn_model.parameters()).device) 232 | 233 | #%% --- Modeli eğitme ve yardımcı fonksiyonlar 234 | 235 | from torchsummary import summary 236 | 237 | # modelimizin daha detaylı resmi 238 | summary(cnn_model, input_size=(3, 96, 96)) 239 | 240 | # eniyileme: 241 | # ağımızın girdisi olan veri ile oluşturduğu kaybı göz önünde 242 | # bulundurarak kendisini güncelleme mekanizması 243 | from torch import optim 244 | opt = optim.Adam(cnn_model.parameters(), lr=3e-4) 245 | 246 | # modelin eğitileceği donanım 247 | device = torch.device("cpu") 248 | 249 | from torch.optim.lr_scheduler import ReduceLROnPlateau 250 | 251 | # öğrenme hızı, zamanlayıcı vb. tanımlamalar. 252 | lr_scheduler = ReduceLROnPlateau(opt, mode='min',factor=0.5, patience=20,verbose=1) 253 | 254 | 255 | # İlk olarak, doğru tahmin sayısını saymak için bir yardımcı işlev geliştirelim 256 | def metrics_batch(output, target): 257 | # çıktı sınıfı 258 | pred = output.argmax(dim=1, keepdim=True) 259 | 260 | # çıktı sınıfını hedef sınıfla karşılaştır 261 | corrects=pred.eq(target.view_as(pred)).sum().item() 262 | return corrects 263 | 264 | # öğrenme oranı al 265 | def get_lr(opt): 266 | for param_group in opt.param_groups: 267 | return param_group['lr'] 268 | 269 | # Ardından, toplu iş başına kayıp değerini hesaplamak için bir yardımcı işlev geliştireceğiz 270 | def loss_batch(loss_func, output, target, opt=None): 271 | 272 | # kayıp 273 | loss = loss_func(output, target) 274 | 275 | # performans metriği 276 | metric_b = metrics_batch(output,target) 277 | 278 | if opt is not None: 279 | opt.zero_grad() 280 | loss.backward() 281 | opt.step() 282 | 283 | return loss.item(), metric_b 284 | 285 | 286 | # tüm veri kümesi için kayıp değeri 287 | def loss_epoch(model,loss_func,dataset_dl,sanity_check=False,opt=None): 288 | 289 | running_loss=0.0 290 | running_metric=0.0 291 | len_data=len(dataset_dl.dataset) 292 | 293 | for xb, yb in dataset_dl: 294 | 295 | # toplu işi donanımda yapmak 296 | xb=xb.to(device) 297 | yb=yb.to(device) 298 | 299 | # model çıktısı 300 | output=model(xb) 301 | 302 | # parti başına kayıp 303 | loss_b,metric_b=loss_batch(loss_func, output, yb, opt) 304 | 305 | # kaybı güncelleme 306 | running_loss+=loss_b 307 | 308 | # çalışan metriği güncelle 309 | if metric_b is not None: 310 | running_metric+=metric_b 311 | 312 | if sanity_check is True: 313 | break 314 | 315 | # ortalama kayıp değeri 316 | loss=running_loss/float(len_data) 317 | 318 | # ortalama metrik değer 319 | metric=running_metric/float(len_data) 320 | 321 | return loss, metric 322 | 323 | 324 | # --- eğitim fonksiyonu --- 325 | 326 | def train_val(model, params): 327 | 328 | # modelin aldığı parametreler. 329 | num_epochs=params["num_epochs"] # döngü sayısı 330 | loss_func=params["loss_func"] # kayıp fonksiyonu 331 | opt=params["optimizer"] # eniyileme fonksiyonu 332 | train_dl=params["train_dl"] # eğitim verisi 333 | val_dl=params["val_dl"] # doğrulama verisi 334 | sanity_check=params["sanity_check"] # akıllı kontrol 335 | lr_scheduler=params["lr_scheduler"] # öğrenme hızı, zamanlayıcı vb. tanımlamalar. 336 | path2weights=params["path2weights"] # en iyi modelin kaydedileceği yer 337 | 338 | # kayıp geçmişi 339 | loss_history={ 340 | "train": [], 341 | "val": [], 342 | } 343 | 344 | # metrik geçmişi 345 | metric_history={ 346 | "train": [], 347 | "val": [], 348 | } 349 | 350 | # en iyi performans gösteren model için ağırlıkların kopyası 351 | best_model_wts = copy.deepcopy(model.state_dict()) 352 | 353 | best_loss=float('inf') 354 | 355 | # döngü 356 | for epoch in range(num_epochs): 357 | 358 | # mevcut öğrenme oranı 359 | current_lr=get_lr(opt) 360 | print('Epoch {}/{}, current lr={}'.format(epoch, num_epochs - 1, current_lr)) 361 | 362 | # eğitim veri kümesi üzerinde eğitim modeli 363 | model.train() 364 | train_loss, train_metric=loss_epoch(model,loss_func,train_dl,sanity_check,opt) 365 | 366 | # collect loss and metric for training dataset 367 | loss_history["train"].append(train_loss) 368 | metric_history["train"].append(train_metric) 369 | 370 | # doğrulama veri kümesi üzerinde doğrulama modeli 371 | model.eval() 372 | with torch.no_grad(): 373 | val_loss, val_metric=loss_epoch(model,loss_func,val_dl,sanity_check) 374 | 375 | 376 | # en iyi model 377 | if val_loss < best_loss: 378 | best_loss = val_loss 379 | best_model_wts = copy.deepcopy(model.state_dict()) 380 | 381 | # ağırlıkların saklandığı dosya 382 | torch.save(model.state_dict(), path2weights) 383 | print("Copied best model weights!") 384 | 385 | # doğrulama veri kümesi için kayıp ve metriği toplamak 386 | loss_history["val"].append(val_loss) 387 | metric_history["val"].append(val_metric) 388 | 389 | 390 | lr_scheduler.step(val_loss) 391 | if current_lr != get_lr(opt): 392 | print("Loading best model weights!") 393 | model.load_state_dict(best_model_wts) 394 | 395 | print("train loss: %.6f, dev loss: %.6f, accuracy: %.2f" %(train_loss,val_loss,100*val_metric)) 396 | print("-"*10) 397 | 398 | # en iyi modelin ağırlığı yüklenir. 399 | model.load_state_dict(best_model_wts) 400 | 401 | return model, loss_history, metric_history 402 | 403 | 404 | 405 | import torch.nn as nn 406 | import copy 407 | 408 | loss_func = nn.NLLLoss(reduction="sum") 409 | opt = optim.Adam(cnn_model.parameters(), lr=3e-4) 410 | lr_scheduler = ReduceLROnPlateau(opt, mode='min',factor=0.5, patience=20,verbose=1) 411 | 412 | params_train={ 413 | "num_epochs": 30, 414 | "optimizer": opt, 415 | "loss_func": loss_func, 416 | "train_dl": train_dl, 417 | "val_dl": val_dl, 418 | "sanity_check": False, 419 | "lr_scheduler": lr_scheduler, 420 | "path2weights": "./models/weights.pt", 421 | } 422 | 423 | # modelin eğitimi 424 | cnn_model,loss_hist,metric_hist=train_val(cnn_model,params_train) 425 | 426 | num_epochs=params_train["num_epochs"] 427 | 428 | #%% --- Eğitimin başarımını ve kaybını görüntüleme 429 | 430 | plt.title("Train-Val Loss") 431 | plt.plot(range(1,num_epochs+1),loss_hist["train"],label="train") 432 | plt.plot(range(1,num_epochs+1),loss_hist["val"],label="val") 433 | plt.ylabel("Loss") 434 | plt.xlabel("Training Epochs") 435 | plt.legend() 436 | plt.show() 437 | 438 | # plot accuracy progress 439 | plt.title("Train-Val Accuracy") 440 | plt.plot(range(1,num_epochs+1),metric_hist["train"],label="train") 441 | plt.plot(range(1,num_epochs+1),metric_hist["val"],label="val") 442 | plt.ylabel("Accuracy") 443 | plt.xlabel("Training Epochs") 444 | plt.legend() 445 | plt.show() 446 | --------------------------------------------------------------------------------