def resize_aspect_ratio(img, final_h, final_w):
    height, width, channel = img.shape
    ratio = 0
    # height = 8914
    # width = 6457
    target_w_size = final_w
    target_h_size = final_h

    h_ratio = target_h_size / height
    target_h, target_w = int(height * h_ratio), int(width * h_ratio)
    diff = target_w_size - target_w
    if diff > 0:
        resized = cv2.resize(img, (target_w, target_h), interpolation=interpolation)
        pad_array = np.ones(shape=(target_h_size, diff, 3), dtype=np.uint8)
        # pad_array = np.full(shape=(target_h_size, diff, 3), 255)
        resized = np.append(resized, pad_array, axis=1)
        ratio = h_ratio
    else:
        w_ratio = target_w_size / width
        target_h, target_w = int(height * w_ratio), int(width * w_ratio)
        diff = target_h_size - target_h
        resized = cv2.resize(img, (target_w, target_h), interpolation=interpolation)
        pad_array = np.ones(shape=(diff, target_w_size, 3), dtype=np.uint8)
        resized = np.append(resized, pad_array, axis=0)
        ratio = w_ratio

    cv2.imshow('test', resized)
    cv2.waitKey(0)

여기서

target_w_size, target_h_size가 원하는 이미지의 크기이고,

이미지가 비율을 일정하게 유지하면서 padding을 붙여서 원하는 크기의 이미지로 resize하는 코드

Python은 인터프리터 언어로서 C/C++과 같은 컴파일 언어보다 속도가 느립니다.

하지만 numba 라이브러리를 사용하면 컴파일 언어로 바꿔서 사용할 수 있습니다.

 

import math
import numpy as np
import time
from numba import njit


def std(xs):
    mean = 0
    for x in xs:
        mean += x
    mean /= len(xs)
    ms = 0
    for x in xs:
        ms += (x-mean)**2
    variance = ms / len(xs)
    std = math.sqrt(variance)
    return std


if __name__ == '__main__':
    a = np.random.normal(0, 1, 10000000)
    start = time.time()
    std(a)
    end = time.time()
    print('njit (X) TIME : {}'.format(end-start))

    c_std = njit(std)
    start = time.time()
    c_std(a)
    end = time.time()
    print('njit (O) TIME : {}'.format(end-start))

Fast-RCNN

 

Fast-RCNN은 SPP-Net을 보완해서 나온 object detection model입니다.

 

SPP-Net의 단점

 1. SVM 학습으로 인한 많은 저장공간 필요

 2. end to end 방식의 학습 방식이 아니다.

 

이를 극복하기 위해 Fast-RCNN은

 1. SVM 대신 softmax를 사용하여 학습

 2. 하나의 loss function을 이용하여 학습. 즉, end-to-end 방식의 학습 가능


Fast R-CNN 의 학습 과정

 

1. Selective Search 알고리즘을 이용하여 RoI를 추려줍니다.

2. 전체 이미지를 CNN Layer를 통과시켜 Feature Map을 얻습니다.

3. 1번에서 추려낸 RoI들을 2번에서 구한 Feature Map에 맞게 Projection 시켜줍니다.

4. RoI에 맞게 Crop된 Feature Map을 RoI Pooling을 통과시켜 고정된 Vector로 변경시켜줍니다.

5. 고정된 크기의 Vector를 softmax에 통과시켜 Object Id 값을 구합니다.

6. 고정된 크기의 Vector를 Bounding Box Regression을 통해 box 좌표값들을 조정해 줍니다.

 

 


RoI Pooling

SPP-Net에서는 크기가 다른 Feature들을 SPP Layer (Spatial Pyramid Pooling Layer)로 통과시켜 줬지만

Fast R-CNN은 RoI Pooling을 사용합니다.

이름만 바뀌었을뿐 SPP Layer에서는 3개의 고정 Vector를 만들었지만

RoI Pooling은 1개의 고정 Vector로 만들어 주는 것입니다. - SPP 방식과는 약간 다릅니다.

SPP Layer

위 그림은 SPP Layer에서의 계산 방식입니다.

 

RoI Pooling

SPP와는 다르게 조금더 심플해진 느낌입니다.

1. 일단 원하는 크기의 H와 W를 정해줍니다.

2. Feature Map에 Projection 시켜준 RoI 부분을 Crop하여 h/H = a, w/W = b를 계산해주고

   RoI부분은 a와 b만큼의 영역으로 나눕니다.

3. 나눈 부분에서 max pooling을 사용해 줍니다.

 

위와 같은 로직을 걸치면 최종적으로 사용자가 원하는 고정된 크기를 얻을 수 있습니다.

 

 


end-to-end

SPP Net은 Selective Search, SVM, bounding box regression 총 3단계의 파이프 라인입니다.

하지만 Fast R-CNN은 무거웠던 SVM을 softmax로 바꾸고

하나의 loss function에 대해 동시에 훈련 가능하게 수정하였습니다.

 

 

Loss Function

여기서 Classification loss는 softmax, Localization loss는 smooth L1을 사용합니다.

※ smooth L1 Loss

더보기

 

위의 사진은 smooth L1 Loss입니다.

식 오른쪽을 보면 L1, L2 loss가 보이는데,

smooth L1 Loss는 L1, L2를 합친것과 같다고 보시면 되겠습니다.

outlier에 민감하지 않고 Loss 값이 충분히 작은 경우 최대한 0값에 수렴하려는 특징이 있습니다.

 

다음에는 Faster R-CNN을 알아보는걸로!

아직 블로그에 올릴 논문이 많다!

 

Faster R-CNN, Mask R-CNN, YOLO 계열, Vit, 그리고 좋은 기회로 알게된 wav2lip...

'Deep Learning > Vision' 카테고리의 다른 글

06. Vision Transform (작성중)  (0) 2022.05.13
05. Yolo 버전별 비교  (0) 2022.05.13
04. Faster RCNN [Vision, Object Detection]  (0) 2022.02.09
02. SPP-Net [Vision, Object Detection]  (0) 2021.11.17
01. R-CNN [Vision, Object Detection]  (0) 2021.11.11

https://zzsza.github.io/mlops/2021/01/03/python-ray/

 

1. 가상환경 조회하기

 conda info --envs

 

 

 

2. 가상환경 변경하기

 activate 가상환경명칭

envscraping 이라는 가상환경으로 파이썬 환경을 변경한다

* 표시가 envscraping 이라는 환경으로 변경되어서 표시되고 있음

 

 

 

3. 가상환경 만들기

 conda create -n 가상환경명칭 python=3.8

가상환경을 새로 만들기 python=3.8 는 파이썬 3.8 환경으로 만드는 옵션

 

 

 

4. 가상환경 해제하기

 deactivate 가상환경명칭

 

 

 

5. 가상환경 지우기

 conda env remove -n 가상환경명칭

 

 

 

6. 만들어 놓은 가상환경을 복사하기

※ conda env export -n 가상환경명칭 > environment.yml

가상환경의 환경설정 상태를 environment.yml 파일로 만들어준다

 

 

 

7. 환경파일로 가상환경을 생성하기

environment.yml 내부의 name을 바꿔주고

prefix 경로를 바꿔준다.

 

 conda env create -f environment..yml

 

 

 

※ 참고: https://blog.naver.com/skykbc/221259281873

std::vector<double> row1;
row1.push_back(1.0); row1.push_back(2.0); row1.push_back(3.0);

std::vector<double> row2;
row2.push_back(4.0); row2.push_back(5.0); row2.push_back(6.0);

std::vector<std::vector<double> > vector_of_rows;
vector_of_rows.push_back(row1);
vector_of_rows.push_back(row2);

// make sure the size of of row1 and row2 are the same, else you'll have serious problems!
cv::Mat my_mat(vector_of_rows.size(), row1.size(), CV_64F);

for (size_t i = 0; i < vector_of_rows.size(); i++)
{   
    for (size_t j = 0; j < row1.size(); j++)
    {   
        my_mat.at<double>(i,j) = vector_of_rows[i][j];
    }   
}   

std::cout << my_mat << std::endl;


////////////////////////////////// 이것도 된다. ////////////////////////////////////
for (int i = 0; i < img_rows; ++i)
{
	comb_img.row(i) = Mat(text_score_comb[i]).t();
}

////////////////////////////////// 이것도 된다. ////////////////////////////////////
Mat comb_img(img_rows, img_cols, CV_8U);
for (int i = 0; i < img_rows; ++i)
	for (int j = 0; j < img_cols; ++j)
		comb_img.at<uchar>(i, j) = (uchar)(text_score_comb.at(i).at(j));

https://stackoverflow.com/questions/10898591/convert-a-stdvectorstdvector-double-representing-a-2d-array-to-cvmat

'Language > C++' 카테고리의 다른 글

C++ 시간 재기  (0) 2022.03.14
Mat 형식 Binary file로 저장 및 Binary file 불러오기  (0) 2022.02.22
Image to Base64, Base64 to Image  (0) 2021.11.18
파일 랜덤 추출  (0) 2021.10.14
C++ 폴더 존재유무 및 생성  (0) 2021.10.08

Dataset

from glob import glob
from torch.utils.data import Dataset, DataLoader
from PIL import Image
import torchvision.transforms as T


class my_dataset(Dataset):
    def __init__(self, image_path, classes, transform=None):
        self.image_path = image_path
        self.labels = self.get_labels(image_path, classes)
        self.transform = transform
        self.classes = classes

    def get_labels(self, image_path, classes):
        label_list = []
        for path in image_path:
            temp = path.split('/')[-1]
            temp = temp.split('\\')[-2]
            num = classes.index(temp)
            label_list.append(num)
        return label_list

    def __len__(self):
        return len(self.image_path)

    def __getitem__(self, idx):
        img = Image.open(self.image_path[idx])
        
        if self.transform is None:
            return img, self.labels[idx]
        else:
            return self.transform(img), self.labels[idx]



train_data_path = glob('./data/CIFAR-10-images-master/train/*/*.jpg')
test_data_path = glob('./data/CIFAR-10-images-master/test/*/*.jpg')
my_mean = [0.485, 0.456, 0.406]
my_std = [0.229, 0.224, 0.225]

my_transforms = T.Compose([
    T.Resize((100, 100)),
    T.Normalize(mean=my_mean, std=my_std)
])

train_loader = DataLoader(custom_dataset(train_data_path, classes, my_transforms),
                          batch_size=10,
                          shuffle=True,
                          drop_last=True)
test_loader = DataLoader(custom_dataset(test_data_path, classes, my_transforms),
                         batch_size=10,
                         shuffle=True,
                         drop_last=True)

Transforms

    normalize_transform = T.Normalize(
        mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    if is_train:
        transform = T.Compose([
            T.Resize(config.image_size),
            T.RandomHorizontalFlip(p=config.prob),
            T.Pad(config.padding),
            T.RandomCrop(config.image_size),
            T.ToTensor(),
            normalize_transform,
            RandomErasing(probability=config.re_prob,
                          mean=[0.485, 0.456, 0.406])
        ])

transforms에 속한 클래스

 

1. transforms.CentrCrop(size)

- 주어진 PIL 이미지의 중앙을 기준으로 size X size 크기로 자른다.

 

2. transforms.Grayscale(num_out_channels=1)

- 주어진 이미지를 그레이스케일로 변형한다.

- parameter에 1or3을 지정할 수 있는데 1이면 싱글채널이 반환이 되고, 3이면 r==g==b인 3채널이 반환이 된다.

 

3. transforms.Pad(padding, fill=0, padding_mode='constant')

 - 이미지에 대해 컨볼루션을 거칠 때 이미지의 크기와 컨볼루션 커널의 크기가 맞지 않아 이미지의 사이드를 어떠한 수     로 채울 때 사용한다.

- padding : int, tuple 형식으로 지정할 수 있다. 만약에 int형으로 한 개의 수를 입력한다면 이미지의 모든 사이드를 그                 수로 채운다는 것이다. 그리고 튜플형식으로 (a,b)를 입력한다면 왼쪽과 오른쪽은 a로 위와 아래는 b로 채운                 다는 것이다. 마지막으로 (a,b,c,d)를 입력한다면 왼쪽, 위, 오른쪽, 아래를 각각 a,b,c,d로 채우게 된다.

- fill=0 : padding을 하기 위한 값을 입력한다. default는 0이며, R, G, B 색 공간일 때는 튜플형식으로 입력을 한다.

- padding_mode='constant' : padding_mode를 설정하게 되는데 default는 constant이다.

 

4. transforms.Resize(size, interpolation=2)

- 주어진 PIL 이미지를 입력한 size로 크기조정을 한다.

- size : 만약에 sequence 형식으로 (h,w)로 입력을 한다면 h,w로 크기가 조정이되며, int형식으로 한 개의 수가 입력이             된다면 h, w중 작은 것이 입력된 수로 조정이 된다. 예를 들어, h>w라면 (size*h/w, size) 이렇게 크기가 재조정이           된다.

 

5. transforms.Normalize(mean, std, inplace=False)

- 주어진 이미지를 mean, std의 값을 통해 정규화를 한다.

- mean : (sequence)형식으로 평균을 입력하며, 괄호 안에 들어가 있는 수의 개수가 채널의 수이다.

- std : (sequence)형식으로 표준을 입력하며, 마찬가지로 괄호 안에 들어가 있는 수의 개수가 채널의 수이다.

- inplace(bool, optional) : x

 

6. transforms.ToTensor()

- PIL 이미지 또는 numpy.ndarray 형식의 이미지를 tensor 형식으로 변환한다.

- 0~255의 범위를 갖는 (H x W x C)의 형식을 0.0~1.0의 범위를 갖는 (C x H x W)의 형식으로 변환한다.

'Deep Learning > Pytorch' 카테고리의 다른 글

25_Pytorch_GoogLeNet 1x1 Convolution  (0) 2022.03.15
30_AlexNet  (0) 2022.03.01
23_Pytorch_EfficientNet  (0) 2021.11.24
26_Pytorch_Inception-v2, v3 (미완)  (0) 2021.10.25
24_Pytorch_MobileNet - 연산량 number of operations  (0) 2021.10.12

EfficientNet

efficientnet은 CNN에서 모델 scaling을 확장하는 방법에 대한 논문입니다.

Class Activation Map

efficientnet은 모델 사이즈가 작아 Inference 속도가 빠른데도 높은 정확도를 가집니다.

기존에 Model Scaling 방법에는 3가지가 있습니다. (모델을 늘려서 성능을 끌어올리는 방법)

  • Width Scaling: 모델의 넓이를 늘리는 방법, Channel의 개수를 늘리는 방법
  • Depth Scaling: Layer의 개수를 늘리는 방법, 깊게 쌓는 방법
  • Resolution Scaling: Input resolution (Input 이미지의 해상도)를 높여서 넣는 방법

efficientnet은 위 세가지 방법을 각각 다 조절해가면서 실험한 모델입니다.

(a) 가 기준이 되는 Model 입니다.

(b) 는 width scaling Model

(c) 는 depth scaling Model

(d) 는 resolution scaling Model 입니다.

주목할 것은 efficientnet 논문에서 제시한 (e) compound scaling 입니다.

 

 

또한 세가지 scaling 기법 중에 어떤것을 조절해야 정확도가 오르는지에 대한 실험도 수행하였습니다.

이 사진을 보시면 Width(w), Depth(d), Resolution(r)의 수치중 두가지 값은 고정하고 한가지 값만 조절하여 변화량을 나타낸것입니다.

Width의 FLOPs (연산량)을 보면 3.8배 증가부터는 Accuracy가 미비하게 증가

Depth는 6.0배 증가부터 Accuracy가 미비하게 증가

Resolution은 2.5배만 증가해도 Accuracy 증가가 미비합니다.

이제 Width를 고정하고 Depth와 Resolution의 파라미터를 변경해보면

위와 같은 결과를 얻을 수 있다고 논문에 나옵니다.

위 그림을 보면 Depth보다 Resolution을 1.0 → 1.3으로 변경해주면 성능이 확 향상된다는걸 알 수 있습니다.

그리고 3가지 scaling factor를 동시에 고려하는 것이 좋다는 것을 간단하게 입증을 하였으므로

이번에는 3가지 factor의 최적의 비율을 찾아서 실제 모델에 적용을 하여 다른 모델들과 성능을 비교하는 과정을 설명드리겠습니다.

우선 본 논문에서 base model은 MnasNet과 거의 동일한 search space 하에서 AutoML을 통해 모델을 탐색하였고,

이 과정을 통해 찾은 작은 모델을 EfficientNet-B0라고 부르고 있습니다.

이제 이 모델을 기점으로 3가지 factor을 동시에 고려하는 Compound Scaling을 적용하여 실험을 수행합니다.

여기에서 width와 resolution에 제곱을 해준 이유는 depth는 2배 키워주면 FLOPs도 2배가 증가하지만

width와 resolution은 가로, 세로가 각각 증가하기 때문에 제곱을 해줍니다.

본 논문에서는 알파값은 1.2, 베타값은 1.1, 감마값은 1.15를 사용하였으며, 방금 구한 3개의 factor는 고정한뒤

파이를 키워주며 모델의 사이즈를 키워주고 있습니다.

처음단계에서 파이값은 1로 고정입니다.

1.2 x 1.1 x 1.15 = 1.518

 

기존 모델들과의 비교 표입니다.

표를 보면 성능은 비슷하면서 Parameter와 FLOPs가 굉장히 많이 절약할 수 있는 것을 알 수 있습니다.

 

efficientnet의 전체적인 구조입니다.


MBConv

 - SE_Block: SE block의 목적은 AvgPooling으로  1x1xc 컨볼루션을 통해 생성된 특성을 채널당 중요도를 고려해서 재보정하는 것입니다.

 

 - Inverted Residual: Inverted Residual에는 Residuals Block 내에서 Depthwise Separable (Depthwise Conv + Pointwise Conv)를 사용합니다.

 

 


Code

 

 

다음은 Mobilenet을...

 

아래는 태블릿 산 기념으로 작성한 정리글

EfficientNet 정리_220503_230735.pdf
7.71MB

 

 

 

 

출처:

 

 

'Deep Learning > Pytorch' 카테고리의 다른 글

30_AlexNet  (0) 2022.03.01
27_Pytorch_Custom_Dataset  (0) 2021.12.02
26_Pytorch_Inception-v2, v3 (미완)  (0) 2021.10.25
24_Pytorch_MobileNet - 연산량 number of operations  (0) 2021.10.12
22_Pytorch_RNN_Practice  (0) 2021.10.07

+ Recent posts