Data Augmentation 적용해보겠습니다. Data Augmentation 어떻게 Overfitting 방지하면서 분류 정확도를 높일 있는지 확인해보겠습니다.  새 파일을 열고 이름을 minivggnet_flowers17_data_aug.py 지정한 다음 작업을 시작해 보겠습니다.

 

필요한 라이브러리를 로드합니다.

from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from libs.nn.conv.minivggnet import MiniVGGNet
from preprocessing.aspectawarepreprocessor import AspectAwarePreprocessor
from preprocessing.imagetoarraypreprocessor import ImageToArrayPreprocessor
from preprocessing.simpledatasetloader import SimpleDatasetLoader
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import SGD
import matplotlib.pyplot as plt
import argparse
from imutils import paths
import numpy as np
import os

 

필요한 argument를 세팅합니다.

다음으로 명령 인수를 기준으로 이미지 경로에서 클래스 이름을 추출해 보겠습니다.

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True, help="path to input dataset")
args = vars(ap.parse_args())

# grab the list of images that we'll be describing, then extract
# the class label names from the image paths
print("[INFO] loading images...")
imagePaths = list(paths.list_images(args["dataset"]))
classNames = [pt.split(os.path.sep)[-2] for pt in imagePaths]
classNames = [str(x) for x in np.unique(classNames)]

 

디스크에서 데이터 세트를로드하고, 훈련 / 테스트 분할을 구성하고, 레이블을 인코딩합니다.

# initialize the image preprocessors
aap = AspectAwarePreprocessor(64, 64)
iap = ImageToArrayPreprocessor()

# load the dataset from disk then scale the raw pixel intensities
# to the range [0, 1]
sdl = SimpleDatasetLoader(preprocessors=[aap, iap])
(data, labels) = sdl.load(imagePaths, verbose=500)
data = data.astype("float") / 255.0

# partition the data into training and testing splits using 75% of
# the data for training and the remaining 25% for testing
(trainX, testX, trainY, testY) = train_test_split(
    data, labels, test_size=0.25, random_state=42
)

# convert the labels from integers to vectors
trainY = LabelBinarizer().fit_transform(trainY)
testY = LabelBinarizer().fit_transform(testY)

 

다음 코드 블록은 ImageDataGenerator 초기화하므로 매우 중요합니다.

aug = ImageDataGenerator(
    rotation_range=30,
    width_shift_range=0.1,
    height_shift_range=0.1,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode="nearest",
)

 

여기에서 이미지는 다음과 같습니다.

 

1. 무작위로 ± 30도 회전

2. 0.1의 비율로 수평 및 수직 이동

3. 0.2만큼 전단

4. [0.8, 1.2] 범위에서 균일하게 샘플링하여 확대

5. 무작위로 수평으로 플리핑 정확한 데이터 세트에 따라 이러한 데이터 증가 값을 조정하고 싶을 것입니다.

응용 프로그램에 따라 [10,30] 사이의 회전 범위를 보는 것이 일반적입니다. 수평 및 수직 이동은 일반적으로 [0.1, 0.2] 범위에 속합니다 (확대 / 축소 값도 동일). 이미지를 수평으로 훑어 보는 것이 클래스 레이블을 변경하지 않는 한, 항상 수평 훑어보기도 포함해야합니다.

 

# initialize the optimizer and model
print("[INFO] compiling model...")
opt = SGD(lr=0.05)
model = MiniVGGNet.build(width=64, height=64, depth=3, classes=len(classNames))
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])

 

그러나 네트워크를 훈련시키는 사용되는 코드는 현재 이미지 생성기를 사용하고 있으므로 약간 변경해야합니다.

# train the network
print("[INFO] training network...")
H = model.fit(
    aug.flow(trainX, trainY, batch_size=32),
    validation_data=(testX, testY),
    steps_per_epoch=len(trainX) // 32,
    epochs=100,
    verbose=1,
)

모델의 .fit 메서드를 호출하는 합니다. 이제 첫 번째 매개 변수는 학습 데이터에서 새로운 학습 샘플을 생성하는 데 사용되는 데이터 증가 함수 인 aug.flow입니다. aug.flow에서는 학습 데이터와 해당 레이블을 전달해야합니다. 또한 생성기가 네트워크를 훈련 할 때 적절한 배치를 구성 할 수 있도록 배치 크기를 제공해야합니다.

 

그런 다음 validation_data를 (testX, testY)의 튜플로 제공합니다.이 데이터는 모든 generation이 끝날 때까지 유효성 검사에 사용됩니다. steps_per_epoch 매개 변수는 epoch 당 배치 수를 제어합니다. 총 훈련 샘플 수를 배치 크기로 나누고 정수로 변환하여 적절한 steps_per_epoch 값을 프로그래밍 방식으로 결정할 수 있습니다. 마지막으로 epochs는 네트워크가 훈련되어야하는 총 epoch 수를 제어합니다 (이 경우 100 epoch).

 

네트워크를 훈련 평가하고 해당 정확도 / 손실 플롯을 플로팅합니다.

# evaluate the network
print("[INFO] evaluating network...")
predictions = model.predict(testX, batch_size=32)
print(
    classification_report(
        testY.argmax(axis=1), predictions.argmax(axis=1), target_names=classNames
    )
)

# plot the training loss and accuracy
plt.style.use("ggplot")
plt.figure()
plt.plot(np.arange(0, 100), H.history["loss"], label="train_loss")
plt.plot(np.arange(0, 100), H.history["val_loss"], label="val_loss")
plt.plot(np.arange(0, 100), H.history["accuracy"], label="train_acc")
plt.plot(np.arange(0, 100), H.history["val_accuracy"], label="val_acc")
plt.title("Training Loss and Accuracy")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.show()

 

위코드는 아래 명령어로 실행시킬 수 있습니다.

 python minivggnet_flowers17_data_aug.py --dataset dataset/flowers17/images/

 

Data Augmentation을 통한 Flower-17 학습과정 및 loss&accuracy plot

Data Augmentation는 훈련 데이터에서 사용하는 정규화 기술의 한 유형입니다. 이름에서 알 수 있듯이 Data Augmentation은 일련의 무작위 변환, 회전, 전단 등을 적용하여 훈련 데이터를 무작위로 생성합니다. 이러한 단순 변환을 적용해도 입력 이미지의 클래스 레이블은 변경되지 않습니다. 그러나 각 증강 이미지는 학습 알고리즘이 이전에 보지 못한 "새로운"이미지로 간주 될 수 있습니다. 따라서 우리의 훈련 알고리즘은 새로운 훈련 샘플과 함께 지속적으로 제공되어 더 강력하고 차별적인 패턴을 학습 할 수 있습니다.

 

"자연스러운"교육 샘플을 수집하는 것이 항상 더 좋지만, 데이터 확대는 작은 데이터 세트 제한을 극복하는 데 사용할 수 있습니다. 자체 훈련의 경우 실행하는 거의 모든 실험에 데이터 증가를 적용해야합니다. CPU가 이제 입력을 무작위로 변환하는 책임이 있기 때문에 약간의 성능 저하를 가져야합니다. 그러나 이러한 성능 저하는 스레드를 사용하고 네트워크 훈련을 담당하는 스레드로 전달되기 전에 백그라운드에서 데이터를 보강하여 완화됩니다.

 

Data_Augmenation.tar.gz
0.44MB

'keras > 1.Data Augmentation' 카테고리의 다른 글

2. Flower-17  (0) 2020.08.20
1. Data Augmentation  (0) 2020.08.20

Flowers-17 데이터 세트

17 개의 서로 다른 꽃의 품종을 인식하는 세분화 된 분류 과제입니다. 이미지 데이터 세트는 매우 작으며 총 1,360개의 이미지에 대해 클래스 당 80개의 이미지 만 있습니다. 컴퓨터 비전 작업에 딥러닝을 적용 할 때 일반적인 경우는 클래스당 1,000 ~ 5,000개의 데이터를 갖는 것이므로 여기서는 확실히 큰 부족함이 있습니다.

모든 범주가 매우 유사하기 때문에 Flowers-17을 세분화 된 분류 작업이라고 부릅니다 (즉, 꽃의 품종). 사실, 우리는 이러한 각 범주를 하위 범주로 생각할 수 있습니다. 범주는 확실히 다르지만 상당한 양의 공통 구조를 공유합니다.

Flowers-17 데이터 세트의 5 개 (총 17 개 중) 클래스 샘플. 각 클래스는 특정 꽃의 종을 나타냅니다. (pyimagesearch)

세분화 된 분류 작업은 우리의 기계 학습 모델이 매우 유사한 클래스를 구별하기 위해 극도로 구별되는 기능을 학습해야 함을 의미하기 때문에 딥러닝 실무자에게 가장 어려운 경향이 있습니다. 이 세분화된 분류 작업은 제한된 훈련 데이터를 고려할 때 더욱 문제가됩니다.

 

Aspect-aware Preprocessing

지금까지는 영상비를 무시하고 고정 된 크기로 크기를 조정하여 이미지를 전처리했습니다. 일부 상황, 특히 기본 벤치 마크 데이터 세트의 경우 그렇게하는 것이 허용됩니다.

그러나 더 까다로운 데이터 세트의 경우 고정된 크기로 크기를 조정해야하지만 종횡비는 유지해야합니다. 

왼쪽 : 원본 입력 이미지 (410 × 310). 중간 : 가로 세로 비율을 무시하고 이미지 크기를 256 × 256 픽셀로 조정합니다. 이제 이미지가 찌그러지고 왜곡 된 것처럼 보입니다. 오른쪽 : 가로 세로 비율을 유지하면서 이미지 크기를 256 × 256으로 조정합니다.

왼쪽에는 고정 된 너비와 높이로 크기를 조정해야하는 입력 이미지가 있습니다. 가로 세로 비율을 무시하고 이미지 크기를 256 × 256 픽셀 (중간)로 조정하여 원하는 크기에 맞도록 이미지를 효과적으로 찌그러 뜨리고 왜곡합니다. 더 나은 접근 방식은 이미지의 종횡비 (오른쪽)를 고려하는 것입니다. 여기서 너비가 256 픽셀이되도록 더 짧은 치수를 따라 크기를 조정 한 다음 높이를 따라 이미지를 잘라 높이가 256 픽셀이되도록합니다.

자르는 동안 이미지의 일부를 효과적으로 버렸지 만 이미지의 원래 종횡비도 유지했습니다. 일관된 종횡비를 유지하면 Convolutional Neural Network가보다 차별적이고 일관된 기능을 학습 할 수 있습니다. 

aspect-aware 전처리가 어떻게 구현되는지 확인하기 위해 AspectAwarePreprocessor를 만들어보겠습니다.

생성자는 이미지 크기를 조정할 때 사용되는 보간 방법과 함께 두 개의 매개 변수 (대상 출력 이미지의 원하는 너비 및 높이)가 필요합니다. 

# import the necessary packages 
import imutils 
import cv2

class AspectAwarePreprocessor:
    def __init__(self, width, height, inter=cv2.INTER_AREA):
        # store the target image width, height, and interpolation
        # method used when resizing 
        self.width = width 
        self.height = height 
        self.inter = inter

 

그런 다음 아래에서 전처리 기능을 정의 할 수 있습니다.

    def preprocess(self, image):
        # grab the dimensions of the image and then initialize 
        # the deltas to use when cropping
        (h, w) = image.shape[:2] # 입력 이미지의 너비와 높이를 잡고

        # 더 큰 치수를 따라자를 때 사용할 델타 오프셋을 결정
        dW = 0
        dH = 0

즉, AspectAwarePreprocessor()는 2단계 알고리즘입니다.

1. Step # 1 : 가장 짧은 치수를 결정하고 이에 따라 크기를 조정합니다.
2. Step # 2 : 대상 너비와 높이를 얻기 위해 가장 큰 치수를 따라 이미지를 자릅니다.

다음 코드 블록은 너비가 높이보다 작은 지 확인하고, 그렇다면 너비를 따라 크기를 조정합니다.

        # if the width is smaller than the height, then resize 
        # along the width (i.e., the smaller dimension) and then 
        # update the deltas to crop the height to the desired # dimension        
        if w < h:
            image = imutils.resize(image, width=self.width, inter=self.inter)
            dH = int((image.shape[0] - self.height) / 2.0)

 

그렇지 않고 높이가 너비보다 작 으면 높이를 따라 크기를 조정합니다.

        else:
            image = imutils.resize(image, height=self.height, inter=self.inter)
            dW = int((image.shape[1] - self.width) / 2.0)

 

이제 이미지의 크기가 조정되었으므로 너비와 높이를 다시 잡고 델타를 사용하여 이미지 중앙을 잘라야합니다.

        # now that our images have been resized, we need to 
        # re-grab the width and height, followed by performing 
        # the crop
        (h, w) = image.shape[:2]
        image = image[dH:h - dH, dW:w - dW]

        # finally, resize the image to the provided spatial 
        # dimensions to ensure our output image is always a fixed 
        # size
        
        return cv2.resize(image, (self.width, self.height), interpolation=self.inter)

잘라낼 (반올림 오류로 인해) 이미지 대상 이미지 크기가 ± 1 픽셀만큼 벗어날 있습니다. 따라서 출력 이미지가 원하는 너비와 높이를 갖도록 cv2.resize 호출합니다. 그런 다음 전처리 이미지가 호출 함수로 반환됩니다. AspectAwarePreprocessor() 구현 했으므로 이제 Flowers-17 데이터 세트에서 MiniVGGNet 아키텍처를 학습 작동하도록하겠습니다.

 

aspectawarepreprocessor.py
0.00MB

 

 

'keras > 1.Data Augmentation' 카테고리의 다른 글

3. Flowers-17: With Data Augmentation  (0) 2020.08.21
1. Data Augmentation  (0) 2020.08.20

Goodfellow et al.에 따르면, 정규화는“일반화 오류를 줄이기위한 학습 알고리즘에 대한 모든 수정이지만 훈련 오류는 아닙니다" 다시 말해정규화는 훈련 오류를 약간 증가시키는 대신 테스트 오류를 ​​줄이려는 목적이 강합니다.

실무적으로는 다음과 같은 다른 유형의 정규화가 있습니다.

  1. 네트워크 아키텍처 자체를 수정합니다.
  2. 훈련을 위해 네트워크로 전달되는 데이터를 확장합니다.

 

드롭 아웃은 일반화 가능성을 높여 네트워크 아키텍처를 수정하는 좋은 예입니다. 여기에 이전 계층에서 다음 계층으로 노드를 무작위로 연결 해제하는 계층을 삽입하여 단일 노드가 주어진 클래스를 표현하는 방법을 모르게 합니다.

 

What is Data Augmentation?

 

Data Augmentation은 클래스 레이블이 변경되지 않도록 임의의 jitter 및 perturbation을 적용하여 원본에서 새로운 훈련 샘플을 생성하는 데 사용되는 광범위한 기술을 말합니다. Data Augmentation를 적용 할 때 우리의 목표는 모델의 일반화 가능성을 높이는 것입니다. 네트워크가 지속적으로 약간 수정 된 새 버전의 입력 데이터 포인트를 보고 있다는 점은 강력한 더 파워풀한 모델을 얻을 수 있음을 암시합니다. 테스트시에는 데이터 증대를 적용하지 않고 훈련 된 네트워크를 평가하지 않습니다. 대부분의 경우 훈련 정확도가 약간 떨어지더라도 테스트 정확도가 향상되는 것을 확인할 수 있습니다.

왼쪽 : 정확히 정규 분포를 따르는 250 개의 데이터 포인트 샘플. 오른쪽 : 소량의 무작위 "jitter"를 분포에 추가 이러한 유형의 데이터 증가는 네트워크의 일반화 가능성을 높일 수 있습니다. (pyimagesearch)

평균이 0이고 단위 분산이있는 정규 분포의 그림(왼쪽)을 생각해보겠습니다. 이 데이터에 대한 기계 학습 모델을 학습하면 분포를 정확하게 모델링 할 수 있지만 실제 애플리케이션에서는 데이터가 이러한 깔끔한 분포를 거의 따르지 않습니다.

대신 분류기의 일반화 가능성을 높이기 위해 무작위 분포 (오른쪽)에서 가져온 일부 값 ε을 추가하여 분포를 따라 무작위로 jitter 지점을 찾을 수 있습니다. 컴퓨터 비전에서 무작위와 같은 간단한 기하학적 변환을 적용하여 원본 이미지에서 추가 훈련 데이터를 얻을 수 있습니다.

 

1. Translations
2. Rotations
3. Changes in scale
4. Shearing
5. Horizontal (and in some cases, vertical) flips

 

이러한 변환의 (작은) 양을 입력 이미지에 적용하면 모양이 약간 변경되지만 클래스 레이블은 변경되지 않으므로 데이터 확장이 매우 자연스럽고 쉬운 방법이됩니다. 이런 방법은 컴퓨터 비전 작업을위한 딥 러닝에 적용합니다. 컴퓨터 비전에 적용되는 데이터 증대를위한보다 진보 된 기술에는 주어진 색 공간에서 색상의 randomized perturbation, nonlinear geometric distortions이 있습니다.

 

Visualizing Data Augmentation

# import the necessary packages
from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing.image import img_to_array
from keras.preprocessing.image import load_img
from imutils import paths
import argparse
import numpy as np

 

argparse() 모듈은 terminal에서 실행할 때 argument를 쉽게 parsing하는 모듈입니다. 일반적인 tool(ex. Pycharm, jupyter notebook)에서 직접적으로 실행하게 되면 error가 발생하게 됩니다.

# construct the argument parse ad parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True)
ap.add_argument("-o", "--output", required=True)
ap.add_argument("-p", "--prefix", type=str, default="image")
args = vars(ap.parse_args())

 

 

image를 불러오는 코드입니다.

print("[INFO] loading example image...")
image = load_img(args["image"])
image = img_to_array(image)
image = np.expand_dims(image, axis=0)  # 맨 앞 1차원 추가

 

 

애플리케이션에서 가장 많이 사용할 증가 매개 변수에 초점을 맞추겠습니다.
# rotation_range 매개 변수는 임의 회전의 각도 범위를 제어합니다. 여기에서 입력 이미지를 무작위로 ± 30도 회전 할 수 있습니다.
# width_shift_range 및 height_shift_range는 각각 수평 및 수직 이동에 사용됩니다. 매개 변수 값은 주어진 차원의 일부입니다 (이 경우 10 %).
# shear_range는 이미지를 기울일 수있는 라디안으로 시계 반대 방향의 각도를 제어합니다.
# 그런 다음 [1-zoom_range, 1 + zoom_range] 값의 균일 한 분포에 따라 이미지를 "확대" 또는 "축소"할 수 있는 포인트 값인 zoom_range가 있습니다.
# 마지막으로 horizontal_flip 논리값은 주어진 입력이 훈련 프로세스 동안 수평으로 전환될 여부를 체크합니다.
# 대부분의 컴퓨터 비전 응용 프로그램의 경우 이미지의 수평 플랩은 결과 클래스 레이블을 변경하지 않습니다.
# 우리의 목표는 입력 이미지를 약간 수정하여 클래스 레이블 자체를 변경하지 않고 새 학습 샘플을 생성하는 것이므로 이러한 유형의 데이터 증가를 적용 할 때 주의해야 합니다.

aug = ImageDataGenerator(
    rotation_range=30,
    width_shift_range=0.1,
    height_shift_range=0.1,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode="nearest",
)

 

 

생성된 Iterator로 이미지를 생성할 수 있습니다.

print("[INFO] generating images...")
imageGen = aug.flow(
    image,
    batch_size=1,
    save_to_dir=args["output"],
    save_prefix=args["prefix"],
    save_format="jpg",
)

total = 0
# 그런 다음 imageGen 생성기의 각 이미지를 반복하기 시작합니다. 
# 내부적으로 imageGen은 루프를 통해 요청 될 때마다 새로운 학습 샘플을 자동으로 생성합니다.
# 그런 다음 디스크에 기록 된 총 데이터 증가 예제 수를 늘리고 
# 예제 10 개에 도달하면 스크립트 실행을 중지합니다.
# loop over examples from our image data augmentation generator
for image in imageGen:
    # increment our counter
    total += 1

    # if we have reached 10 examples, break from the loop
    if total == 10:
        break

 

 

실행코드는 다음과 같습니다.

python augmentation.py -i jemma.png -o output -p image

데이터를 증폭할 원본 이미지
증폭된 강아지 이미지 사진 10개

각 이미지가 어떻게 무작위로 회전하고, 기울이고, 확대되고, 수평으로 튕겨져 있는지 확인합니다. 각각의 경우 이미지는 원래 클래스 레이블을 유지합니다.(dog); 그러나 각 이미지가 약간 수정되어 훈련 할 때 배울 수있는 새로운 패턴을 신경망에 제공합니다. 입력 이미지는 지속적으로 변경되기 때문에 (클래스 레이블은 동일하게 유지됨) 데이터 보강이없는 학습과 비교할 때 학습 정확도가 감소하는 것이 일반적입니다.

또한 Data Augmentation는 Overfitting을 줄이는 데 도움이 될 수 있으며, 동시에 모델이 새로운 입력 샘플에 더 잘 일반화되도록 보장합니다. 또한 딥러닝을 적용하기에는 예제가 너무 적은 데이터 세트로 작업 할 때 Data Augmentation을 활용하여 추가 훈련 데이터를 생성 할 수 있으므로 딥러닝 네트워크를 훈련하는 데 필요한 수동 레이블 데이터의 양을 줄일 수 있습니다.

augmentation.py
0.00MB
jemma.png
0.26MB

'keras > 1.Data Augmentation' 카테고리의 다른 글

3. Flowers-17: With Data Augmentation  (0) 2020.08.21
2. Flower-17  (0) 2020.08.20

+ Recent posts