From 1709887b9285e93c04ddaab3f6e47a2f70bccf4c Mon Sep 17 00:00:00 2001 From: dIronmanb Date: Tue, 29 Mar 2022 15:10:21 +0000 Subject: [PATCH 1/2] please --- .gitignore | 3 + Chapter03/config.yaml | 54 ++++ .../__pycache__/data_loaders.cpython-36.pyc | Bin 0 -> 2415 bytes Chapter03/data_loaders/data_loaders.py | 100 +++++++ Chapter03/metric.py | 15 + .../model/__pycache__/models.cpython-36.pyc | Bin 0 -> 7209 bytes Chapter03/model/models.py | 259 ++++++++++++++++++ .../__pycache__/loss.cpython-36.pyc | Bin 0 -> 444 bytes .../__pycache__/optimizer.cpython-36.pyc | Bin 0 -> 607 bytes .../__pycache__/scheduler.cpython-36.pyc | Bin 0 -> 905 bytes Chapter03/optimizers/loss.py | 9 + Chapter03/optimizers/optimizer.py | 20 ++ Chapter03/optimizers/scheduler.py | 29 ++ Chapter03/test.py | 50 ++++ Chapter03/train.py | 158 +++++++++++ 15 files changed, 697 insertions(+) create mode 100644 .gitignore create mode 100644 Chapter03/config.yaml create mode 100644 Chapter03/data_loaders/__pycache__/data_loaders.cpython-36.pyc create mode 100644 Chapter03/data_loaders/data_loaders.py create mode 100644 Chapter03/metric.py create mode 100644 Chapter03/model/__pycache__/models.cpython-36.pyc create mode 100644 Chapter03/model/models.py create mode 100644 Chapter03/optimizers/__pycache__/loss.cpython-36.pyc create mode 100644 Chapter03/optimizers/__pycache__/optimizer.cpython-36.pyc create mode 100644 Chapter03/optimizers/__pycache__/scheduler.cpython-36.pyc create mode 100644 Chapter03/optimizers/loss.py create mode 100644 Chapter03/optimizers/optimizer.py create mode 100644 Chapter03/optimizers/scheduler.py create mode 100644 Chapter03/test.py create mode 100644 Chapter03/train.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..97de107 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +Chapter03/cifar10/ +Chapter03/save/ +Chapter03/runs/ \ No newline at end of file diff --git a/Chapter03/config.yaml b/Chapter03/config.yaml new file mode 100644 index 0000000..c039741 --- /dev/null +++ b/Chapter03/config.yaml @@ -0,0 +1,54 @@ +# config 파일에 대하여 +# config 파일에는 +# 딥러닝 모델 +# 손실 함수 +# 옵티마이저 +# 하이퍼파라미터 +# 에폭 +# 등 모든 것들이 담겨져 있다. +# 뭔가 모델을 바꾸거나 에폭을 바꾸고 싶을 때는 여기서 해당 이름에 대응하는 +# 값만 조정하면 된다. + +# 단, 모델, 손실 함수, 옵티마이저의 경우 +# 내가 원하는 것의 이름으로 변경 해당 모델, 손실함수, 옵티마이저 파일에 +# 정의되어 있어야 한다. + +--- + file_name: "scheduler" + + use_cuda: true + epoch: 100 + train_batch_size: 64 + test_batch_size: 64 + learning_rate: 0.001 + dataset_name: "CIFAR10" + + # train_dataset + # test_dataset + # 은 CIFAR10 Dataloader에서만 작업할 것이므로 pass + + num_workers: 2 + train_dataset_shuffle: True + test_dataset_shuffle: False + data_loader_name: 'data_load_normalizing_and_agumentation' + + model: "VGG11" + model_layer: 3 # [3, 5, 9, 12] + loss_function: "CrossEntropyLoss" + optimizer: "Adam" + scheduler_name: 'ExponentialLR' + momentum: 0.9 + weight_decay : 0.01 + metrics: "accuracy_score" + + VGG_types: { + 'VGG11' : [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], + 'VGG13' : [64,64, 'M', 128, 128, 'M', 256, 256, 'M', 512,512, 'M', 512,512,'M'], + 'VGG16' : [64,64, 'M', 128, 128, 'M', 256, 256,256, 'M', 512,512,512, 'M',512,512,512,'M'], + 'VGG19' : [64,64, 'M', 128, 128, 'M', 256, 256,256,256, 'M', 512,512,512,512, 'M',512,512,512,512,'M'] + } + + + + # momentum이랑 weight_decay 정의하기 + \ No newline at end of file diff --git a/Chapter03/data_loaders/__pycache__/data_loaders.cpython-36.pyc b/Chapter03/data_loaders/__pycache__/data_loaders.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec3ff551465410ee5d0486990a8ac3ec6cccd683 GIT binary patch literal 2415 zcmbtV-ES0C6rZpC=CR+8^APiDMf2oU;GE;$%oOXiBIg@jZZ$vljq(kOXG_V%w*2oIrpC5 zIp=rIy|ZJ@8vU=KUA+%ql%zkU6_*0zJ@9z%g20j?VHqp7Tu=-}=3~`X3!0%7Vn$4S zYj)g7;24gVB_oNoBT_0+x~EE#j#zau{AP*WK83>Z8hkX%weZ{(#1`jSWjLIeLe1-y z#=;Nm+5`%()WT{VgDd%x22MHGp28 zc@}JVd6usZFJ5QWdULWBZ&SO$Cg0gZ9M7e1rFNno^xl7Th!Z_MhuHM#aApozL_M4WUzo7z ziSX7K#LaHjP;+=OoUX8QvxtpWS^3^m^k^wZXIB@)tFs83z8TKdmoYfI8Mk=iZ3HPd zD@%w?e!&S8lmV&N&hWb5<)aB++mSmu0%&SlPTC_r&(0^F&&N@paN{B+MU%FeWw*=C zt7m~+(TCMVHZ`+TM{xDzNd#p%IRrHkP<+f|L|)!4*%*}^OlZzUJ}mak0*NM9xPW?+ zq6bmIXk0Tuf}#Z`n3-Tptz8K7axGNM~fxleaw486H@gzA$%6g69Ym3g*XwuNW;$qLZ|*1_Pdml z1AQOle9$!^*_0CK;KK31X~7GUoDFc`9m>djFsuPlZyQwc2FQ8iW(ihq zf>kllX)WD)p^M`!Ly5uIV0M{)3yen zIJqNNw_GTF{(E=s(fv>V{yzAvJNM+|vATcx*Y2ElbnQC})t|a^KObdX58s5r>%aU1 zlaIQgdKy1z0@d@e@y0Xw707AmiL{w36`&);HpxLD;rgQ+IzcWz=Cw6Co|*FP*6a2U zY=s>|3F-NuN&S6<6b}-U zI*{Qfu;k+t;uz}Mn>UL-q1$$JWvr}8w{Po7X@N#v*AHT%;o(2y_B))rpsm%O`ycOt zSc6rtWzzjF?IYAnse#^W`k8#%vjzxV!{-xTzLd?{B#0Gl(;PQ*&qOnToqmLkw zu}#k--d%~l0{Blpd(MKk8VRZ+pq6)l*I7Ifw6$hAb>2Y`lAMHFljHJgd4rNvG+9@Y zT0DkSuGQtF0^?Xxjmrw$@D;t=Gkl> 전체 이미지에 대한 화소 값의 mean과 standard deviation을 구하여 일괄 적용해야 함. + >> Imagenet 데이터 세트에서 계산된 평균과 표준 편차 사용 + + + torch.Tensor(): T = torch.Tensor() 문장 입력시 T는 tensor자료구조 클래스 생성 + torch.tensor(): 어떤 data를 tensor로 copy, 괄호 안에 값이 없다면 에러남 + + train_set과 test_set모두에 preparation을 진행하는 이유: + The training and testing data should undergo the same data preparation steps + or the predictive model will not make sense. + This means that the number of features for both the training and test set + should be the same and represent the same thing. +''' + +from torch.utils.data import DataLoader +from torchvision import transforms, datasets +import numpy as np + + +def data_load(config): + name = config['data_loader_name'] + if name == 'data_load_only_normalizing': + data_transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize(mean = [0.4913, 0.4821, 0.4465], + std = [0.2470, 0.2434, 0.2615]) + ]) + elif name == 'data_load_normalizing_and_agumentation': + + data_transform = transforms.Compose([ + transforms.RandomHorizontalFlip(p=0.5), # 이미지를 좌우반전 + # transforms.RandomVerticalFlip(p=0.5), # 이미지를 상하반전 + transforms.RandomRotation(10), # 이미지를 -90 ~ 90에서 랜덤하게 rotate + # transforms.RandomResizedCrop(size = (32,32)) # 이미지의 임의의 부분을 확대하여 Resize + # transforms.ToPILImage(mode = None): # PILImage로 변환 + + transforms.ToTensor(), # 이미지를 tensor_type로 변환 + # transforms.RandomApply(transforms = data_transform, p = 1.0), # agumentation을 전체 데이터에서 임의적으로 골라서 취함. + # 왜 0.5, 0.5, 0.5를 넣어야 하는가? + # >> 직접 mean과 std를 구하면 mean = [0.49139968 0.48215841 0.44653091], std = [0.24703223 0.24348513 0.26158784] + # channel은 3개 + transforms.Normalize(mean = [0.4913, 0.4821, 0.4465], std = [0.2470, 0.2434, 0.2615]) # tensor의 데이터 수치를 정규화한다. + # transforms.Normalize((0.5), (0.5))) -> -1 ~ 1 사이의 값으로 normalized # output[channel] = (input[channel] - mean[channel]) / std[channel] + ]) + elif name == 'data_load_rainbow': + data_transform = transforms.Compose([ + transforms.RandomHorizontalFlip(p=0.5), # 이미지를 좌우반전 + transforms.RandomRotation(10), # 이미지를 -90 ~ 90에서 랜덤하게 rotate + + transforms.ToTensor(), # 이미지를 tensor_type로 변환 + # transforms.RandomApply(transforms = data_transform, p = 1.0), # agumentation을 전체 데이터에서 임의적으로 골라서 취함. + # 왜 0.5, 0.5, 0.5를 넣어야 하는가? + # >> 직접 mean과 std를 구하면 mean = [0.49139968 0.48215841 0.44653091], std = [0.24703223 0.24348513 0.26158784] + # channel은 3개 + transforms.Normalize(mean = [0.4913, 0.4821, 0.4465], std = [0.2470, 0.2434, 0.2615]) # tensor의 데이터 수치를 정규화한다. + # transforms.Normalize((0.5), (0.5))) -> -1 ~ 1 사이의 값으로 normalized # output[channel] = (input[channel] - mean[channel]) / std[channel] + ]) + + else: + print("There was no name in DataLoader_Name") + + + train_set = datasets.CIFAR10(root = '/data/Github_Management/StartDeepLearningWithPytorch/Chapter03/cifar10', + train = True, + download = True, # If true, downloads the dataset from the internet and puts it in root directory. If dataset is already downloaded, it is not downloaded again. + transform = data_transform) + + test_set = datasets.CIFAR10(root = '/data/Github_Management/StartDeepLearningWithPytorch/Chapter03/cifar10', + train = False, + download = True, + transform = data_transform + ) + + # print(train_set.data.mean(axis = (0,1,2)) / 255) + # print(train_set.data.std(axis = (0,1,2)) / 255) + + # print(test_set.data.mean(axis = (0,1,2)) / 255) + # print(test_set.data.std(axis = (0,1,2)) / 255) + + train_loader = DataLoader(train_set, + batch_size= 64, #['train_batch_size'], + num_workers = config['num_workers'], + shuffle = True)#config['train_dataset_shuffle']) + + test_loader = DataLoader(test_set, + batch_size = 64, #config['test_batch_size'], + num_workers = config['num_workers'], + shuffle = False) #config['test_dataset_shuffle']) + + + classes = ('plane', 'car', 'bird', 'cat', 'deer', + 'dog', 'frog', 'horse', 'ship', 'truck') + + return train_loader, test_loader, classes # train + + + \ No newline at end of file diff --git a/Chapter03/metric.py b/Chapter03/metric.py new file mode 100644 index 0000000..ccc58d0 --- /dev/null +++ b/Chapter03/metric.py @@ -0,0 +1,15 @@ +from sklearn.metrics import accuracy_score, recall_score, precision_score, f1_score + + +def get_metrics(test, predicted, config): + name = config['metrics'] + if name == "accuracy_score": + return accuracy_score(test, predicted) + elif name == "recall_score": + return recall_score(test, predicted) + elif name == "precision_score": + return precision_score(test, predicted) + elif name == "f1_score": + return f1_score(test, predicted) + else: + print("There is no metrics in metrics_name") \ No newline at end of file diff --git a/Chapter03/model/__pycache__/models.cpython-36.pyc b/Chapter03/model/__pycache__/models.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f896479c73915383b4d5870b75fa115d46c3fc4a GIT binary patch literal 7209 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 relu , conv -> relu , ... 이다. + 2. 끝단에 maxpooling등을 넣어만들어서 다음과 같은 형태가 되면 + nn.Sequential( + nn.conv + nn.relu + + nn.conv + nn.relu + ) + maxpooling + -->> 이를 BLOCK이라고 부른다. + 3. batch_size는 점점 크게 한다. + (ex) 3 -> 8 -> 16 -> 32 -> 64 ... + + 4. 같은 이름을 사용하여 객체가 서로 공유되지 아니하도록 조심하기 +''' +import torch +import torch.nn as nn +import torch.nn.functional as F + +def get_cnn_model(config): + name = config['model'] + if name == 'CNN_3': + return CNN_3() + elif name == 'CNN_5': + return CNN_5() + elif name == 'CNN_9': + return CNN_9() + elif name == 'CNN_12': + return CNN_12() + elif name == 'VGG11': + vgg_types = config['VGG_types'] + return VGGnet(vgg_types[name], init_weights=True) + else: + print("There is no name in models") + +class CNN_5(nn.Module): + def __init__(self): + super(CNN_5, self).__init__() + # Output = (Input - Kernel_size + 2*Padding_size) / Stride + 1 + self.conv_in = nn.Conv2d(in_channels = 3, out_channels = 8, kernel_size = 3, padding = 1) + self.conv_hidden_1 = nn.Conv2d(in_channels = 8, out_channels = 8, kernel_size = 3, padding = 1) + self.conv_hidden_2 = nn.Conv2d(in_channels = 8, out_channels = 8, kernel_size = 3, padding = 1) + self.conv_hidden_3 = nn.Conv2d(in_channels = 8, out_channels = 8, kernel_size = 3, padding = 1) + self.conv_out = nn.Conv2d(in_channels = 8, out_channels = 16, kernel_size = 3, padding = 1) + + # Output = (Input - kernel_size) / stride + 1 + self.pool = nn.MaxPool2d(kernel_size = 2, stride = 2) + + self.fc1 = nn.Linear(8 * 8 * 16, 64) + self.fc2 = nn.Linear(64, 32) + self.fc3 = nn.Linear(32, 10) + + + def forward(self,x): + x = self.pool(F.relu(self.conv_in(x))) # 16 * 16 * 8 + + x = F.relu(self.conv_hidden_1(x)) # 16 * 16 * 8 + x = F.relu(self.conv_hidden_2(x)) # 16 * 16 * 8 + x = F.relu(self.conv_hidden_3(x)) # 16 * 16 * 8 + + x = self.pool(F.relu(self.conv_out(x))) # 8 * 8 * 16 + + x = x.view(-1, 8 * 8 * 16) # flatten + x = self.fc1(x) + x = F.relu(x) + x = self.fc2(x) + x = F.relu(x) + x = self.fc3(x) + x = F.log_softmax(x) + return x +class CNN_9(nn.Module): + def __init__(self): + super(CNN_9, self).__init__() + # Output = (Input - Kernel_size + 2*Padding_size) / Stride + 1 + self.conv_in = nn.Conv2d(in_channels = 3, out_channels = 8, kernel_size = 3, padding = 1) + self.conv_hidden_1 = nn.Conv2d(in_channels = 8, out_channels = 8, kernel_size = 3, padding = 1) + self.conv_hidden_2 = nn.Conv2d(in_channels = 8, out_channels = 16, kernel_size = 3, padding = 1) + self.conv_hidden_3 = nn.Conv2d(in_channels = 16, out_channels = 16, kernel_size = 3, padding = 1) + self.conv_hidden_4 = nn.Conv2d(in_channels = 16, out_channels = 32, kernel_size = 3, padding = 1) + self.conv_hidden_5 = nn.Conv2d(in_channels = 32, out_channels = 32, kernel_size = 3, padding = 1) + self.conv_hidden_6 = nn.Conv2d(in_channels = 32, out_channels = 64, kernel_size = 3, padding = 1) + self.conv_hidden_7 = nn.Conv2d(in_channels = 64, out_channels = 64, kernel_size = 3, padding = 1) + self.conv_out = nn.Conv2d(in_channels = 64, out_channels = 128, kernel_size = 3, padding = 1) + + # Output = (Input - kernel_size) / stride + 1 + self.pool = nn.MaxPool2d(kernel_size = 2, stride = 2) + + self.fc1 = nn.Linear(8 * 8 * 128, 64) + self.fc2 = nn.Linear(64, 32) + self.fc3 = nn.Linear(32, 10) + + + + def forward(self,x): + x = self.conv_in(x) # 32 * 32 * 8 + x = F.relu(x) + x = self.pool(x) # 16 * 16 * 8 + + + x = F.relu(self.conv_hidden_1(x)) # 16 * 16 * 8 + x = F.relu(self.conv_hidden_2(x)) # 16 * 16 * 8 + x = F.relu(self.conv_hidden_3(x)) # 16 * 16 * 8 + x = F.relu(self.conv_hidden_4(x)) # 16 * 16 * 8 + x = F.relu(self.conv_hidden_5(x)) # 16 * 16 * 8 + x = F.relu(self.conv_hidden_6(x)) # 16 * 16 * 8 + x = F.relu(self.conv_hidden_7(x)) # 16 * 16 * 64 + + x = self.conv_out(x) # 16 * 16 * 128 + x = F.relu(x) + x = self.pool(x) # 8 * 8 * 128 + + + + x = x.view(-1, 8 * 8 * 128) # flatten + x = self.fc1(x) + x = F.relu(x) + x = self.fc2(x) + x = F.relu(x) + x = self.fc3(x) + x = F.log_softmax(x) + return x +class CNN_12(nn.Module): + + def __init__(self): + super(CNN_12, self).__init__() + # Output = (Input - Kernel_size + 2*Padding_size) / Stride + 1 + self.conv_in = nn.Conv2d(in_channels = 3, out_channels = 8, kernel_size = 3, padding = 1) + self.conv_hidden = nn.Conv2d(in_channels = 8, out_channels = 8, kernel_size = 3, padding = 1) + self.conv_out = nn.Conv2d(in_channels = 8, out_channels = 16, kernel_size = 3, padding = 1) + + # Output = (Input - kernel_size) / stride + 1 + self.pool = nn.MaxPool2d(kernel_size = 2, stride = 2) + + self.fc1 = nn.Linear(8 * 8 * 16, 64) + self.fc2 = nn.Linear(64, 32) + self.fc3 = nn.Linear(32, 10) + + + + def forward(self,x): + x = self.conv_in(x) # 32 * 32 * 8 + x = self.pool(x) # 16 * 16 * 8 + x = F.relu(x) + + for _ in range(10): + x = F.relu(self.conv_hidden(x)) # 16 * 16 * 8 + + # x = F.relu(self.conv_hidden(x)) # 16 * 16 * 8 + + x = self.conv_out(x) # 16 * 16 * 16 + x = self.pool(x) # 8 * 8 * 16 + x = F.relu(x) + + + x = x.view(-1, 8 * 8 * 16) # flatten + x = self.fc1(x) + x = F.relu(x) + x = self.fc2(x) + x = F.relu(x) + x = self.fc3(x) + x = F.log_softmax(x) + return x +class CNN_3(nn.Module): + def __init__(self): + super(CNN_3, self).__init__() + + # # Output = (Input - Kernel_size + 2*Padding_size) / Stride + 1 + # self.conv_in = nn.Conv2d(in_channels = 3, out_channels = 8, kernel_size = 3, padding = 1) + #input = 3, output = 6, kernal = 5 + self.conv1 = nn.Conv2d(3, 6, 5) # 32 * 32 * 6 + + + # # Output = (Input - kernel_size) / stride + 1 + # self.pool = nn.MaxPool2d(kernel_size = 2, stride = 2) + #kernal = 2, stride = 2, padding = 0 (default) + self.pool = nn.MaxPool2d(2, 2) + self.conv2 = nn.Conv2d(6, 16, 5) + #input feature, output feature + self.fc1 = nn.Linear(16 * 5 * 5, 120) + self.fc2 = nn.Linear(120, 84) + self.fc3 = nn.Linear(84, 10) + + + # 값 계산 + def forward(self, x): + x = self.pool(F.relu(self.conv1(x))) + x = self.pool(F.relu(self.conv2(x))) + x = x.view(-1, 16 * 5 * 5) + x = F.relu(self.fc1(x)) + x = F.relu(self.fc2(x)) + x = self.fc3(x) + return x +class VGGnet(nn.Module): + def __init__(self, model, in_channels = 3, num_classes = 10, init_weights = True): + super(VGGnet, self).__init__() + self.in_channels = in_channels + + self.conv_layers = self.create_conv_layers(model) + + self.fcs = nn.Sequential( + nn.Linear(512, 4096), + nn.ReLU(), + nn.Dropout(p = 0.5), + nn.Linear(4096, 4096), + nn.ReLU(), + nn.Dropout(p = 0.5), + nn.Linear(4096, num_classes) + ) + + if init_weights: + self._initialize_weights() + + + def forward(self, x): + x = self.conv_layers(x) + x = x.view(-1, 512) + x = self.fcs(x) + return x + + + def _initialize_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode = 'fan_out', nonlinearity='relu') + if m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.BatchNorm2d): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.Linear): + nn.init.normal_(m.weight, 0, 0.01) + nn.init.constant_(m.bias, 0) + + def create_conv_layers(self, architecture): + layers = [] + in_channels = self.in_channels + + for x in architecture: + if type(x) == int: + out_channels = x + layers += [nn.Conv2d(in_channels = in_channels, out_channels = out_channels, + kernel_size = (3,3), stride = (1,1), padding = (1,1)), + nn.BatchNorm2d(x), + nn.ReLU()] + in_channels = x + elif x == 'M': + layers += [nn.MaxPool2d(kernel_size = (2,2), stride = (2,2))] + + return nn.Sequential(*layers) + +if __name__ == '__main__': + print('Quick Test...') + input = torch.zeros([1,3,32,32], dtype = torch.float32) + model = CNN_3() + output = model(input) + + print('input_shape: {}, output_size: {}' + .format(input.shape, output.shape)) diff --git a/Chapter03/optimizers/__pycache__/loss.cpython-36.pyc b/Chapter03/optimizers/__pycache__/loss.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a6567573e790800b76005d77fea2f5d3578f7b0 GIT binary patch literal 444 zcmY*W%}N6?5KgjNT?>VJ^SF2r7NjfmDk9Y4rCpR2gkDP8#BQ{k4U_cH;;p`nPvLvy z>Pa8LlaqR>3G?&KmzjJa{Z6O-{c$!Ul#oxdw<651(d-F2K?GfrXF8!G7EDBMbixEJ zN!I#8mK1Xq0xLcVbFEhy(MM93~`E>1?(abZ7IbYa9UjW!*MwrHP-s> z05A--gT|~wWpnyaNsy_sscuruYfN>zL}vQ5(sQR8ZL`=jtsy9Y@BrU3ptQ@Fk3)k$ zFdTSo-w7nh{@mw+JD%SvSFL8#G1q({YpGpcIu7neN;8riw9<=5JaV^o4a}>2P;uiV zT=etCI902S1e*sPJ+t=53+bl+Lh@G}QcZ7sb SF6&0DmhuY!iP-SKHv0v=TW~V~ literal 0 HcmV?d00001 diff --git a/Chapter03/optimizers/__pycache__/optimizer.cpython-36.pyc b/Chapter03/optimizers/__pycache__/optimizer.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6a5db1eac7dfe1382b12ddc6c9bd110dcb3e6b06 GIT binary patch literal 607 zcmYjOy-wsX5VqrN2+M}+PTB@-g-An?Xio?P63ww71%Z?%GHa8BOPpxp)oIaELCb^O zQ`~#Fr2!s+igAEtZOvzAzWMu{-5}_{{@=WMb_jVQOAEirK3e+|K@dSpazhhGID$Qp zgb5mx(0xIUj3+kME{5iz9ip`f!kh{^BzMjn^Zq!nrLo4`dfCvTJ0zm_$YO%Lhx{0M zXNg}~MEQ?yOf(a#_mtu^*t4#dmh2Mb-BEy4}o7kV%~`NGq!Q zsf7BtJ=_E5OhQ5nR01}w)J3J)B&h5v6k5@$n-HO-q7|Ew8Jo$_c|^7&0irt= z-S8om`bAz<>WWQ2psOBF9#D_&nVEC$y*j@3Uc24=vbB5m(<9_Jd9*0L-y+mDfD`WI zsy6k2<(twGD7dC)@sWZvm1*junZ*mb_a zH*Gd2aQbXu)>JYUe3}axm#h#b?6cyGv;Ht~;M6Yrwp$q?R0!ZOyJ^emAU&_wpMxJH za*Qt~RWg>C8mZy$NtZLtx*sz=o}R@=tYoPuM5((Y&7^)W#H25nEVDBGjFjUmUCCtJ zJsh)%7IJs5TTOIUWY4z` zTqs?YLdmvm(Ee~a!C$E}miLDdt=rC|^}|YKrFd7Cg5?+iJiJDUwDVr{^FPG}yEH38 zv$)90D1f8Ic}aV(q_r*AENocV1T2b!q$> 디렉토리에서 가중치 파일 불러오기 + model.load_state_dict(torch.load('save/VGG11/2022-03-24_23:20:09/saved_weights_100')) + + acc = predict(model, test_data, config) + print("The accuracy is {:.1f}%".format(acc)) diff --git a/Chapter03/train.py b/Chapter03/train.py new file mode 100644 index 0000000..efcc99d --- /dev/null +++ b/Chapter03/train.py @@ -0,0 +1,158 @@ +''' + train.py + 모든 .py파일을 import하는 곳이다. + 데이터를 로드하는 것부터 모델 생성, 손실함수 및 옵티마이저까지. + 먼저 각 data_loader.py, model.py, loss.py, optimizer.py를 독립적으로 구현하고 여기로 다시 오자. + + - model.py에서만 class불러오고 나머지는 함수만 사용 + +''' + +import os +import yaml +import torch.nn.functional as F +import torch +import numpy as np +import datetime +from pytz import timezone +from torch.utils.tensorboard import SummaryWriter + +import optimizers.loss as loss_function +import optimizers.optimizer as optim +import optimizers.scheduler as scheduler +import data_loaders.data_loaders as data_loader +import model.models as models +import torchvision +import test +import metric + +# +current_time = datetime.datetime.now(timezone('Asia/Seoul')).strftime('%Y-%m-%d_%H:%M:%S') + +# Open config file +with open("config.yaml", 'r', encoding = 'utf-8') as stream: + try: + config = yaml.safe_load(stream) # return into Dict + except yaml.YAMLError as exc: + print(exc) + +# Load data +train_data, test_data, classes = data_loader.data_load(config) + + +# Use cuda +DEVICE = torch.device("cuda" if config['use_cuda'] else "cpu") + +# make model +model = models.get_cnn_model(config).to(DEVICE) +# model = model.to(DEVICE) +print(model) + + +# set epoch +epoch= config["epoch"] + +# set loss and optimizer +criterion = loss_function.get_loss_function(config['loss_function']) +optimizer = optim.get_optimizer(model.parameters(), config) +schedule = scheduler.get_scheduler(optimizer, config) + +# convert model to train_mode +model.train() + +writer = SummaryWriter('runs/' + config['file_name'] + '_' + config['model'] + '_' + current_time) +dataiter = iter(train_data) +images, labels = dataiter.next() +img_grid = torchvision.utils.make_grid(images) +writer.add_image('32_CIFAR10_images', img_grid) + +# train model +running_loss_history = [] +running_correct_history = [] +validation_running_loss_history = [] +validation_running_correct_history = [] + +for i in range(1, epoch + 1): + running_loss = 0.0 + running_correct = 0.0 + validation_running_loss = 0.0 + validation_running_correct = 0.0 + + total_loss = 0.0 # 배치에서의 loss + total_length = 0.0 # 현재 길이 + for batch_idx, (data, targets) in enumerate(train_data): + + data = data.to(DEVICE) + targets = targets.to(DEVICE, dtype = torch.int64) + outputs = model(data) + los = criterion(outputs, targets) + + optimizer.zero_grad() + los.backward() + optimizer.step() + + _ , preds = torch.max(outputs, 1) + + running_correct += torch.sum(preds == targets.data) + running_loss += los.item() + + total_loss += los.item() * len(data) + total_length += len(data) + + if batch_idx % 100 == 0: + writer.add_scalar("Loss/train_step",los.item(), batch_idx + len(data) * (i)) + print("Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}".format( + i + 1, batch_idx * len(data), len(train_data.dataset), 100. * batch_idx / len(train_data), los.item() + )) + + else: + + with torch.no_grad(): + + for val_input, val_label in test_data: + + val_input = val_input.to(DEVICE) + val_label = val_label.to(DEVICE) + val_outputs = model(val_input) + val_loss = criterion(val_outputs, val_label) + + _ , val_preds = torch.max(val_outputs, 1) + validation_running_loss += val_loss.item() + validation_running_correct += torch.sum(val_preds == val_label.data) + + + epoch_loss = running_loss / len(train_data) + epoch_acc = running_correct.float() / len(train_data) + running_loss_history.append(epoch_loss) + running_correct_history.append(epoch_acc) + + val_epoch_loss = validation_running_loss / len(test_data) + val_epoch_acc = validation_running_correct.float() / len(test_data) + validation_running_loss_history.append(val_epoch_loss) + validation_running_correct_history.append(val_epoch_acc) + + + print("===================================================") + print("epoch: ", i + 1) + print("training loss: {:.5f}, acc: {:5f}".format(epoch_loss, epoch_acc)) + print("test loss: {:.5f}, acc: {:5f}".format(val_epoch_loss, val_epoch_acc)) + + writer.add_scalar("Loss/train_epoch", epoch_loss, i) + writer.add_scalar("Accuracy/train_epcoh", epoch_acc, i) + writer.add_scalar("Loss/test_epoch", val_epoch_loss , i) + writer.add_scalar("Accuracy/test_epoch",val_epoch_acc, i) + + if i % 10 == 0: + if os.path.exists('save/' + config['model'] + '/' + current_time): + pass + else: + os.makedirs('save/' + config['model'] + '/' + current_time) + + torch.save(model.state_dict(), 'save/' + config['model'] + '/' + current_time + '/saved_weights_' + str(i)) + + +# test and metric +accuracy = test.predict(model, test_data, config) +print('The test accuracy: {0:.3f}%'.format(accuracy)) +# met = metric.get_metrics(test_data[1], np.squeeze(predicted_list), config) +# print('The test accuracy: {}%'.format(met * 100)) From 345b439a38d0bb3813ebe6146a56c495429328b4 Mon Sep 17 00:00:00 2001 From: dIronmanb Date: Tue, 29 Mar 2022 15:22:21 +0000 Subject: [PATCH 2/2] No.2 please --- .gitignore | 9 +- Chapter04/config/config.yaml | 54 ++++++++ Chapter04/predict_images.py | 66 +++++++++ Chapter04/src/dataloader/dataloader.py | 54 ++++++++ Chapter04/src/dataloader/preprocessing.py | 31 +++++ Chapter04/src/metrics/metrics.py | 26 ++++ Chapter04/src/models/model.py | 106 +++++++++++++++ Chapter04/src/optimizers/loss.py | 12 ++ Chapter04/src/optimizers/optimizer.py | 19 +++ Chapter04/src/optimizers/scheduler.py | 29 ++++ Chapter04/test.py | 56 ++++++++ Chapter04/train.py | 159 ++++++++++++++++++++++ 12 files changed, 620 insertions(+), 1 deletion(-) create mode 100644 Chapter04/config/config.yaml create mode 100644 Chapter04/predict_images.py create mode 100644 Chapter04/src/dataloader/dataloader.py create mode 100644 Chapter04/src/dataloader/preprocessing.py create mode 100644 Chapter04/src/metrics/metrics.py create mode 100644 Chapter04/src/models/model.py create mode 100644 Chapter04/src/optimizers/loss.py create mode 100644 Chapter04/src/optimizers/optimizer.py create mode 100644 Chapter04/src/optimizers/scheduler.py create mode 100644 Chapter04/test.py create mode 100644 Chapter04/train.py diff --git a/.gitignore b/.gitignore index 97de107..afed1e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ Chapter03/cifar10/ Chapter03/save/ -Chapter03/runs/ \ No newline at end of file +Chapter03/runs/ + +Chapter04/__pycache__/ +Chapter04/dataset/ +Chapter04/final_result/ +Chapter04/runs/ +Chapter04/save/ +*.pyc \ No newline at end of file diff --git a/Chapter04/config/config.yaml b/Chapter04/config/config.yaml new file mode 100644 index 0000000..6a888fd --- /dev/null +++ b/Chapter04/config/config.yaml @@ -0,0 +1,54 @@ +# config 파일에 대하여 +# config 파일에는 +# 딥러닝 모델 +# 손실 함수 +# 옵티마이저 +# 하이퍼파라미터 +# 에폭 +# 등 모든 것들이 담겨져 있다. +# 뭔가 모델을 바꾸거나 에폭을 바꾸고 싶을 때는 여기서 해당 이름에 대응하는 +# 값만 조정하면 된다. + +# 단, 모델, 손실 함수, 옵티마이저의 경우 +# 내가 원하는 것의 이름으로 변경 해당 모델, 손실함수, 옵티마이저 파일에 +# 정의되어 있어야 한다. + +--- + + use_cuda: true + epoch: 100 + train_batch_size: 64 + test_batch_size: 64 + learning_rate: 0.001 + dataset_name: "CIFAR10" + is_trained: false + + # train_dataset + # test_dataset + # 은 CIFAR10 Dataloader에서만 작업할 것이므로 pass + + num_workers: 2 + train_dataset_shuffle: True + test_dataset_shuffle: False + data_loader_name: 'data_load_only_normalizing' + + model: "VGG11" + loss: "CrossEntropyLoss" + optimizer: "Adam" + scheduler: 'ExponentialLR' + momentum: 0.9 + weight_decay : 0.01 + metrics: "accuracy_score" + + + VGG_types: { + 'VGG11' : [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], + 'VGG13' : [64,64, 'M', 128, 128, 'M', 256, 256, 'M', 512,512, 'M', 512,512,'M'], + 'VGG16' : [64,64, 'M', 128, 128, 'M', 256, 256,256, 'M', 512,512,512, 'M',512,512,512,'M'], + 'VGG19' : [64,64, 'M', 128, 128, 'M', 256, 256,256,256, 'M', 512,512,512,512, 'M',512,512,512,512,'M'] + } + + + + # momentum이랑 weight_decay 정의하기 + \ No newline at end of file diff --git a/Chapter04/predict_images.py b/Chapter04/predict_images.py new file mode 100644 index 0000000..000ee1f --- /dev/null +++ b/Chapter04/predict_images.py @@ -0,0 +1,66 @@ +import torch +import yaml +import src.models.model as vgg +import src.dataloader.dataloader as dataloader +import os +from torch.utils.tensorboard import SummaryWriter +import torchvision.utils +def predict(model, test_loader): + model.eval() + + DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + # get classes + train_dir = '/data/Github_Management/StartDeepLearningWithPytorch/Chapter04/dataset/train/' + classes = os.listdir(train_dir) + + # get tensorboard + writer = SummaryWriter('final_result/test_01') + + + with torch.no_grad(): # 그래디언트를 구하지 않겠다 = 가중치값을 변화하지 않겠다 + dataiter = iter(test_loader) + images, labels = dataiter.next() + + images, labels = images.to(DEVICE), labels.to(DEVICE) + outputs = model(images) + + _ , index = torch.max(outputs.data, 1) + img_grid = torchvision.utils.make_grid(images) + + for i in range(len(index.tolist())): + result = classes[index[i]] + writer.add_image('The predicted result is ' + result, img_grid) + + +if __name__ == '__main__': + + # get config file + print("Get config file...") + with open("config/config.yaml", 'r', encoding = 'utf-8') as stream: + try: + config = yaml.safe_load(stream) # return into Dict + except yaml.YAMLError as exc: + print(exc) + + + # load data + print("Loading data...") + train_data, valid_data, test_data = dataloader.get_data() + + # Use cuda + DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + # create learned model + print("Creating learned model...") + model = vgg.get_VGG(config).to(DEVICE) + + # load weights >> 디렉토리에서 가중치 파일 불러오기 + model.load_state_dict(torch.load('save/VGG11/2022-03-24_13:32:10/saved_weights_297')) + + predict(model, test_data) + + + + + \ No newline at end of file diff --git a/Chapter04/src/dataloader/dataloader.py b/Chapter04/src/dataloader/dataloader.py new file mode 100644 index 0000000..5dbf4d3 --- /dev/null +++ b/Chapter04/src/dataloader/dataloader.py @@ -0,0 +1,54 @@ +import os +from torchvision import datasets, transforms, models +from torchvision.datasets import ImageFolder +from torch.utils.data import DataLoader + +import numpy as np +from PIL import Image +# 전체 과일 종류 개수 출력하기 +# file_list = os.listdir(path + 'train') +# print('total number of type of fruits:',len(file_list)) + + +def get_data(): + train_dir = '/data/Github_Management/StartDeepLearningWithPytorch/Chapter04/dataset/train/' + val_dir = '/data/Github_Management/StartDeepLearningWithPytorch/Chapter04/dataset/validation' + test_dir = '/data/Github_Management/StartDeepLearningWithPytorch/Chapter04/dataset/test' + + # 과일 이름을 담은 리스트 + classes = os.listdir(train_dir) + # print(classes) + + train_transform = transforms.Compose([ + transforms.RandomRotation(10), # +/- 10 degrees + transforms.RandomHorizontalFlip(), # reverse 50% of images -> 위아로 filp은 X + transforms.Resize(40), # (40, 40) + transforms.CenterCrop(40), #(40, 40) + transforms.ToTensor(), # 텐서로 변환 + transforms.Normalize(mean = [0.5, 0.5, 0.5], \ + std = [0.5, 0.5, 0.5]) # mu와 std는 나중에 구해보기 + ]) + + train_set = ImageFolder(train_dir, transform = train_transform) + valid_set = ImageFolder(val_dir, transform = train_transform) + test_set = ImageFolder(test_dir, transform = train_transform) + + # Train, Valid, Test + # num_data = [len(train_set), len(valid_set), len(test_set)] + # print(num_data) + print(type(train_set)) + print(type(valid_set)) + + train_loader = DataLoader(train_set, batch_size = 64, num_workers = 2, shuffle = True) + valid_loader = DataLoader(valid_set, batch_size = 64, num_workers = 2, shuffle = True) + test_loader = DataLoader(test_set, batch_size = 64, num_workers = 2, shuffle = False) + + return train_loader, valid_loader, test_loader + + +if __name__ == '__main__': + # 전체 과일 종류 개수 출력하기 + file_list = os.listdir('/data/Github_Management/StartDeepLearningWithPytorch/Chapter04/dataset/train/') + print('total number of type of fruits:',len(file_list)) + + a = get_data() diff --git a/Chapter04/src/dataloader/preprocessing.py b/Chapter04/src/dataloader/preprocessing.py new file mode 100644 index 0000000..29bc939 --- /dev/null +++ b/Chapter04/src/dataloader/preprocessing.py @@ -0,0 +1,31 @@ +import os +from torchvision.datasets import ImageFolder +from torchvision import transforms + +train_dir = '/data/Github_Management/StartDeepLearningWithPytorch/Chapter04/dataset/train/' +val_dir = '/data/Github_Management/StartDeepLearningWithPytorch/Chapter04/dataset/validation' +test_dir = '/data/Github_Management/StartDeepLearningWithPytorch/Chapter04/dataset/test' + +# 과일 이름을 담은 리스트 +classes = os.listdir(train_dir) +# print(classes) + +train_transform = transforms.Compose([ + transforms.RandomRotation(10), # +/- 10 degrees + transforms.RandomHorizontalFlip(), # reverse 50% of images -> 위아로 filp은 X + transforms.Resize(40), # (40, 40) + transforms.CenterCrop(40), #(40, 40) + transforms.ToTensor(), # 텐서로 변환 + transforms.Normalize(mean = [0.5, 0.5, 0.5], \ + std = [0.5, 0.5, 0.5]) # mu와 std는 나중에 구해보기 + ]) + +train_set = ImageFolder(train_dir, transform = train_transform) +valid_set = ImageFolder(val_dir, transform = train_transform) +test_set = ImageFolder(test_dir, transform = train_transform) + +# Train, Valid, Test +num_data = [len(train_set), len(valid_set), len(test_set)] +print(num_data) +print(type(train_set)) +print(type(valid_set)) diff --git a/Chapter04/src/metrics/metrics.py b/Chapter04/src/metrics/metrics.py new file mode 100644 index 0000000..38ef152 --- /dev/null +++ b/Chapter04/src/metrics/metrics.py @@ -0,0 +1,26 @@ +from sklearn.metrics import accuracy_score, recall_score, precision_score, f1_score, confusion_matrix + + +def get_metrics(targets, predicted, config): + name = config['metrics'] + if name == "accuracy_score": + return accuracy_score(targets, predicted) + elif name == "recall_score": + return recall_score(targets, predicted) + elif name == "precision_score": + return precision_score(targets, predicted) + elif name == "f1_score": + return f1_score(targets, predicted) + else: + print("There is no metrics in metrics_name") + + +def get_confusion_metric(targets, predicted): + return confusion_matrix(targets, predicted) + +def get_recall_score(targets, predicted): + return recall_score(targets, predicted) + +def get_precision_score(targets, predicted): + return precision_score(targets, predicted) + diff --git a/Chapter04/src/models/model.py b/Chapter04/src/models/model.py new file mode 100644 index 0000000..5d5dbbe --- /dev/null +++ b/Chapter04/src/models/model.py @@ -0,0 +1,106 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import yaml + +def get_VGG(config): + name = config['model'] + model_list = config['VGG_types'] + + if name == 'VGG11': + return VGGnet(model_list[name]) + elif name == 'VGG13': + return VGGnet(model_list[name]) + elif name == 'VGG16': + return VGGnet(model_list[name]) + elif name == 'VGG19': + return VGGnet(model_list[name]) + else: + print("There is no name in models") + + + +class VGGnet(nn.Module): + def __init__(self, model, in_channels = 3, num_classes = 36, init_weights = True): + super(VGGnet, self).__init__() + self.in_channels = in_channels + + self.conv_layers = self.create_conv_layers(model) + + self.fcs = nn.Sequential( + nn.Linear(512, 4096), + nn.ReLU(), + nn.Dropout(p = 0.5), + nn.Linear(4096, 4096), + nn.ReLU(), + nn.Dropout(p = 0.5), + nn.Linear(4096, num_classes) + ) + + if init_weights: + self._initialize_weights() + + + def forward(self, x): + x = self.conv_layers(x) + x = x.view(-1, 512) + x = self.fcs(x) + return x + + + def _initialize_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode = 'fan_out', nonlinearity='relu') + if m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.BatchNorm2d): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.Linear): + nn.init.normal_(m.weight, 0, 0.01) + nn.init.constant_(m.bias, 0) + + def create_conv_layers(self, architecture): + layers = [] + in_channels = self.in_channels + + for x in architecture: + if type(x) == int: + out_channels = x + layers += [nn.Conv2d(in_channels = in_channels, out_channels = out_channels, + kernel_size = (3,3), stride = (1,1), padding = (1,1)), + nn.BatchNorm2d(x), + nn.ReLU()] + in_channels = x + elif x == 'M': + layers += [nn.MaxPool2d(kernel_size = (2,2), stride = (2,2))] + + return nn.Sequential(*layers) + + +# Open config file -> quick test +def open_config_file(): + with open("/data/Github_Management/StartDeepLearningWithPytorch/Chapter04/config/config.yaml", 'r', encoding = 'utf-8') as stream: + try: + config = yaml.safe_load(stream) # return into Dict + except yaml.YAMLError as exc: + print(exc) + return config['VGG_types'] + + + +if __name__ == '__main__': + print('Quick Test...') + + models = open_config_file() + model = VGGnet(models['VGG19']) + print(model) + + input = torch.zeros([1,3,32,32], dtype = torch.float32) + # model = VGG_19(32, 3) + output = model(input) + + print('input_shape: {}, output_size: {}' + .format(input.shape, output.shape)) + \ No newline at end of file diff --git a/Chapter04/src/optimizers/loss.py b/Chapter04/src/optimizers/loss.py new file mode 100644 index 0000000..ba4ddb9 --- /dev/null +++ b/Chapter04/src/optimizers/loss.py @@ -0,0 +1,12 @@ +import torch.nn as nn + +def get_loss(config, params = None): + name = config['loss'] + if name == 'MSELoss': + return nn.MSELoss() + elif name == 'CrossEntropyLoss': + return nn.CrossEntropyLoss() + elif name == 'Softmax': + return nn.Softmax() + else: + print("There is no name in loss") \ No newline at end of file diff --git a/Chapter04/src/optimizers/optimizer.py b/Chapter04/src/optimizers/optimizer.py new file mode 100644 index 0000000..cc9a44a --- /dev/null +++ b/Chapter04/src/optimizers/optimizer.py @@ -0,0 +1,19 @@ +import torch.optim as optimizer + + +def get_optimizer(model_paramter, config): + name = config['optimizer'] + + if name == 'Adam': + return optimizer.Adam(params = model_paramter, + lr = config['learning_rate'], + weight_decay = config['weight_decay']) + + elif name == 'SGD': + return optimizer.SGD(params = model_paramter, + lr = config['learning_rate'], + momentum = config['momentum'], + weight_decay = config['weight_decay']) + + else: + print("There is no name in optimizer") \ No newline at end of file diff --git a/Chapter04/src/optimizers/scheduler.py b/Chapter04/src/optimizers/scheduler.py new file mode 100644 index 0000000..c768824 --- /dev/null +++ b/Chapter04/src/optimizers/scheduler.py @@ -0,0 +1,29 @@ +import torch.optim.lr_scheduler as scheduler + +def get_scheduler(optimizer, config): + name = config['scheduler'] + + if name == 'LamdbaLR': + return scheduler.LambdaLR(optimizer = optimizer, + lr_lambda = lambda epoch : 0.95 ** epoch ) + elif name == 'StepLR': + return scheduler.StepLR(optimizer = optimizer, + step_size = 10, + gamma = 0.5) + elif name == 'MultiStepLR': + return scheduler.MultiStepLR(optimizer = optimizer, + milestones = [30, 80], + gamma = 0.5) + elif name == 'ExponentialLR': + return scheduler.ExponentialLR(optimizer = optimizer, + gamma = 0.5) + elif name == 'CosineAnnealingLR': + return scheduler.CosineAnnealingWarmRestarts(optimizer = optimizer, + T_max = 50, + eta_min = 0) + else: + print("There was no name in scheduler") + + + + \ No newline at end of file diff --git a/Chapter04/test.py b/Chapter04/test.py new file mode 100644 index 0000000..9eca8c1 --- /dev/null +++ b/Chapter04/test.py @@ -0,0 +1,56 @@ +import torch +import yaml +import src.models.model as vgg +import src.dataloader.dataloader as dataloader + +def predict(model, test_loader): + model.eval() + + total = 0 + correct = 0 + + DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + + with torch.no_grad(): # 그래디언트를 구하지 않겠다 = 가중치값을 변화하지 않겠다 + for (images, labels) in test_loader: + images, labels = images.to(DEVICE), labels.to(DEVICE) + outputs = model(images) + _ , predicted = torch.max(outputs.data, 1) + total += labels.size(0) + correct += (predicted == labels).sum().item() + return 100 * correct / total + + + +if __name__ == '__main__': + + # get config file + print("Get config file...") + with open("config/config.yaml", 'r', encoding = 'utf-8') as stream: + try: + config = yaml.safe_load(stream) # return into Dict + except yaml.YAMLError as exc: + print(exc) + + # load data + print("Loading data...") + train_data, valid_data, test_data = dataloader.get_data() + + # Use cuda + DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + # create learned model + print("Creating learned model...") + model = vgg.get_VGG(config).to(DEVICE) + + # load weights >> 디렉토리에서 가중치 파일 불러오기 + model.load_state_dict(torch.load('save/VGG11/2022-03-24_13:32:10/saved_weights_297')) + + acc = predict(model, test_data) + print("The accuracy is {:.1f}%".format(acc)) + + + + + \ No newline at end of file diff --git a/Chapter04/train.py b/Chapter04/train.py new file mode 100644 index 0000000..276b1dc --- /dev/null +++ b/Chapter04/train.py @@ -0,0 +1,159 @@ +import os +import yaml +import torch.nn.functional as F +import torch +import numpy as np +import datetime +from pytz import timezone + +from torch.utils.tensorboard import SummaryWriter +import torchvision + +import src.optimizers.loss as loss +import src.optimizers.scheduler as scheduler +import src.optimizers.optimizer as optim +import src.dataloader.dataloader as dataloader +import src.models.model as model +import src.metrics.metrics as metric # 정확도 판단 +import test + + +import os +os.environ['CUDA_LAUNCH_BLOCKING'] = "1" +os.environ["CUDA_VISIBLE_DEVICES"] = "0" + +# +current_time = datetime.datetime.now(timezone('Asia/Seoul')).strftime('%Y-%m-%d_%H:%M:%S') + +# Open config file +with open("config/config.yaml", 'r', encoding = 'utf-8') as stream: + try: + config = yaml.safe_load(stream) # return into Dict + except yaml.YAMLError as exc: + print(exc) + +# Load data +train_data, valid_data, test_data = dataloader.get_data() + +# Use cuda +DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") + +# make model +vgg = model.get_VGG(config).to(DEVICE) +if(config['is_trained']): + vgg.load_state_dict(torch.load('save/VGG11/2022-03-24_11:02:16/saved_weights_198')) + +# print model +print(vgg) + +# set epoch +epoch = config["epoch"] + +# set loss and optimizer +criterion = loss.get_loss(config) +optimizer = optim.get_optimizer(vgg.parameters(), config) +schedule = scheduler.get_scheduler(optimizer, config) + + +# convert vgg to train_mode +vgg.train() + +# show images in tensorboard (as batch size) +writer = SummaryWriter('runs/' + config['model'] + '_' + current_time) +dataiter = iter(train_data) +images, labels = dataiter.next() +img_grid = torchvision.utils.make_grid(images) +writer.add_image('Fruit_images', img_grid) + + +# train model +running_loss_history = [] +running_correct_history = [] +validation_running_loss_history = [] +validation_running_correct_history = [] + +for i in range(1, epoch + 1): + running_loss = 0.0 + running_correct = 0.0 + validation_running_loss = 0.0 + validation_running_correct = 0.0 + + total_loss = 0.0 # 배치에서의 loss + total_length = 0.0 # 현재 길이 + for batch_idx, (data, targets) in enumerate(train_data): + + data = data.to(DEVICE) + targets = targets.to(DEVICE, dtype = torch.int64) + outputs = vgg(data) + los = criterion(outputs, targets) + + optimizer.zero_grad() + los.backward() + optimizer.step() + + _ , preds = torch.max(outputs, 1) + + running_correct += torch.sum(preds == targets.data) + running_loss += los.item() + + total_loss += los.item() * len(data) + total_length += len(data) + + if batch_idx % 100 == 0: + writer.add_scalar("Loss/train_step",los.item(), batch_idx + len(data) * (i)) + print("Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}".format( + i + 1, batch_idx * len(data), len(train_data.dataset), 100. * batch_idx / len(train_data), los.item() + )) + + else: + + with torch.no_grad(): + + for val_input, val_label in valid_data: + + val_input = val_input.to(DEVICE) + val_label = val_label.to(DEVICE) + val_outputs = vgg(val_input) + val_loss = criterion(val_outputs, val_label) + + _ , val_preds = torch.max(val_outputs, 1) + validation_running_loss += val_loss.item() + validation_running_correct += torch.sum(val_preds == val_label.data) + + + epoch_loss = running_loss / len(train_data) + epoch_acc = running_correct.float() / len(train_data) + running_loss_history.append(epoch_loss) + running_correct_history.append(epoch_acc) + + val_epoch_loss = validation_running_loss / len(valid_data) + val_epoch_acc = validation_running_correct.float() / len(valid_data) + validation_running_loss_history.append(val_epoch_loss) + validation_running_correct_history.append(val_epoch_acc) + + + print("===================================================") + print("epoch: ", i + 1) + print("training loss: {:.5f}, acc: {:5f}".format(epoch_loss, epoch_acc)) + print("validation loss: {:.5f}, acc: {:5f}".format(val_epoch_loss, val_epoch_acc)) + + writer.add_scalar("Loss/train_epoch", epoch_loss, i) + writer.add_scalar("Accuracy/train_epcoh", epoch_acc, i) + writer.add_scalar("Loss/valid_epoch", val_epoch_loss , i) + writer.add_scalar("Accuracy/valid_epoch",val_epoch_acc, i) + + if i % 10 == 0: + if os.path.exists('save/' + config['model'] + '/' + current_time): + pass + else: + os.makedirs('save/' + config['model'] + '/' + current_time) + + torch.save(vgg.state_dict(), 'save/' + config['model'] + '/' + current_time + '/saved_weights_' + str(i)) + + + +# test and metric +# accuracy = test.predict(vgg, test_data, config) +# print('The test accuracy: {0:.3f}%'.format(accuracy)) + +