diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afed1e7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +Chapter03/cifar10/ +Chapter03/save/ +Chapter03/runs/ + +Chapter04/__pycache__/ +Chapter04/dataset/ +Chapter04/final_result/ +Chapter04/runs/ +Chapter04/save/ +*.pyc \ 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 0000000..ec3ff55 Binary files /dev/null and b/Chapter03/data_loaders/__pycache__/data_loaders.cpython-36.pyc differ diff --git a/Chapter03/data_loaders/data_loaders.py b/Chapter03/data_loaders/data_loaders.py new file mode 100644 index 0000000..7fad018 --- /dev/null +++ b/Chapter03/data_loaders/data_loaders.py @@ -0,0 +1,100 @@ +''' + 이미지 데이터는 촬영된 환경에 따라 명도나 채도 등이 서로 모두 다르기 때문에 + 영상 기반 딥러닝 모델을 학습시키기 전에 모든 이미지들을 동일한 환경으로 맞춰주는 게 중요! + >> 전체 이미지에 대한 화소 값의 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 0000000..f896479 Binary files /dev/null and b/Chapter03/model/__pycache__/models.cpython-36.pyc differ diff --git a/Chapter03/model/models.py b/Chapter03/model/models.py new file mode 100644 index 0000000..80eb327 --- /dev/null +++ b/Chapter03/model/models.py @@ -0,0 +1,259 @@ +''' + 1. CNN LAYER는 보통 conv -> 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 0000000..9a65675 Binary files /dev/null and b/Chapter03/optimizers/__pycache__/loss.cpython-36.pyc differ diff --git a/Chapter03/optimizers/__pycache__/optimizer.cpython-36.pyc b/Chapter03/optimizers/__pycache__/optimizer.cpython-36.pyc new file mode 100644 index 0000000..6a5db1e Binary files /dev/null and b/Chapter03/optimizers/__pycache__/optimizer.cpython-36.pyc differ diff --git a/Chapter03/optimizers/__pycache__/scheduler.cpython-36.pyc b/Chapter03/optimizers/__pycache__/scheduler.cpython-36.pyc new file mode 100644 index 0000000..682f4fa Binary files /dev/null and b/Chapter03/optimizers/__pycache__/scheduler.cpython-36.pyc differ diff --git a/Chapter03/optimizers/loss.py b/Chapter03/optimizers/loss.py new file mode 100644 index 0000000..f8c8bce --- /dev/null +++ b/Chapter03/optimizers/loss.py @@ -0,0 +1,9 @@ +import torch.nn as nn + +def get_loss_function(name, params = None): + if name == 'MSELoss': + return nn.MSELoss() + elif name =='CrossEntropyLoss': + return nn.CrossEntropyLoss() + else: + print("There is no name in loss_functions") diff --git a/Chapter03/optimizers/optimizer.py b/Chapter03/optimizers/optimizer.py new file mode 100644 index 0000000..9c6517b --- /dev/null +++ b/Chapter03/optimizers/optimizer.py @@ -0,0 +1,20 @@ +import torch.optim as optimizer + + +def get_optimizer(model_parameter, config): + optimizer_name = config['optimizer'] + if optimizer_name == 'Adam': + return optimizer.Adam(params = model_parameter, + lr = config['learning_rate'], + weight_decay = config['weight_decay'] + ) + elif optimizer_name == 'SGD': + return optimizer.SGD(params = model_parameter, + lr = config['learning_rate'], + momentum=config['momentum'], + weight_decay=config['weight_decay'] + ) + else: + print("There is no name in Optimizers") + + \ No newline at end of file diff --git a/Chapter03/optimizers/scheduler.py b/Chapter03/optimizers/scheduler.py new file mode 100644 index 0000000..da7f42b --- /dev/null +++ b/Chapter03/optimizers/scheduler.py @@ -0,0 +1,29 @@ +import torch.optim.lr_scheduler as scheduler + + + +def get_scheduler(optimizer, config): + scheduler_name = config['scheduler_name'] + + if scheduler_name == 'LambdaLR': + return scheduler.LambdaLR(optimizer = optimizer, + lr_lambda = lambda epoch : 0.95 ** epoch + ) + # elif scheduler_name == '': + # return scheduler.MultiplicativeLR() + elif scheduler_name == 'StepLR': + return scheduler.StepLR(optimizer = optimizer, + step_size = 10, + gamma = 0.5) + elif scheduler_name == 'MultiStepLR': + return scheduler.MultiStepLR(optimizer=optimizer, + milestones=[30,80], + gamma = 0.5) + elif scheduler_name == 'ExponentialLR': + return scheduler.ExponentialLR(optimizer=optimizer, + gamma = 0.5) + elif scheduler_name == 'CosineAnnealingLR': + return scheduler.CosineAnnealingLR(optimizer=optimizer, + T_max = 50, + eta_min = 0) + \ No newline at end of file diff --git a/Chapter03/test.py b/Chapter03/test.py new file mode 100644 index 0000000..b473bc1 --- /dev/null +++ b/Chapter03/test.py @@ -0,0 +1,50 @@ +import torch +import yaml +import data_loaders.data_loaders as dataloader +import model.models as vgg + +def predict(model, test_loader, config): + model.eval() + + total = 0 + correct = 0 + + DEVICE = torch.device("cuda" if config['use_cuda'] 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("/data/Github_Management/StartDeepLearningWithPytorch/Chapter03/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, test_data, _ = dataloader.data_load(config) + + # Use cuda + DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + # create learned model + print("Creating learned model...") + model = vgg.get_cnn_model(config).to(DEVICE) + + # load weights >> 디렉토리에서 가중치 파일 불러오기 + 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)) 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)) + +