임의의 이미지 데이터세트에서 특징을 추출하는데 사용할수있는 Python스크립트를 정의해보겠습니다(입력데이터세트가 특정디렉토리구조를 따르는경우). 새파일을 열고 이름을 extract_features.py로지정하여 작업을 시작하겠습니다.

 

사전 훈련 된 VGG16 네트워크의 Keras 구현을 가져와 기능 추출기로 사용하겠습니다. LabelEncoder() 클래스는 클래스 레이블을 문자열에서 정수로 변환하는 데 사용됩니다. 또한 7 행에서 HDF5DatasetWriter를 가져 와서 CNN에서 추출한 기능을 HDF5 데이터 세트에 쓸 수 있습니다.

 

tqdm 모듈을 이용하여 진행 표시줄을 추가하겠습니다.

# USAGE
# python extract_features.py --dataset datasets/animals/images \
#     --output datasets/animals/hdf5/features.hdf5
# python extract_features.py --dataset datasets/caltech-101/images \
#     --output datasets/caltech-101/hdf5/features.hdf5
# python extract_features.py --dataset datasets/flowers17/images \
#     --output datasets/flowers17/hdf5/features.hdf5

# import the necessary packages
from keras.applications import VGG16
from keras.applications import imagenet_utils
from keras.preprocessing.image import img_to_array
from keras.preprocessing.image import load_img
from sklearn.preprocessing import LabelEncoder
from inout.hdf5datasetwriter import HDF5DatasetWriter
from imutils import paths
from tqdm import tqdm
import numpy as np
import argparse
import random
import os

extract_features.py 스크립트에는 두 개의 명령 줄 인수와 두 개의 선택적 인수가 필요합니다. --dataset argument는 기능을 추출하려는 이미지의 입력 디렉토리 경로를 제어합니다. --output argument는 출력 HDF5 데이터 파일의 경로를 결정합니다.

 

그런 다음 --batch-size를 제공할 수 있습니다. 이것은 한 번에 VGG16을 통해 전달되는 배치의 이미지 수입니다. 여기에서는 32의 값이 합리적이지만 시스템에 충분한 메모리가 있으면 값을 늘릴 수 있습니다. --buffer-size 스위치는 HDF5 데이터 세트용 버퍼를 쓰기 전에 메모리에 저장할 추출 된 특징의 수를 제어합니다. 다시 말하지만, 컴퓨터에 충분한 메모리가 있으면 버퍼 크기를 늘릴 수 있습니다.

 

다음 단계는 디스크에서 이미지 경로를 가져 와서 정리하고 레이블을 인코딩하는 것입니다.

# store the batch size in a convenience variable
bs = args["batch_size"]

# grab the list of images that we'll be describing then randomly
# shuffle them to allow for easy training and testing splits via
# array slicing during training time
print("[INFO] loading images...")
imagePaths = list(paths.list_images(args["dataset"]))
random.shuffle(imagePaths)

# extract the class labels from the image paths then encode the
# labels
labels = [p.split(os.path.sep)[-2] for p in imagePaths]
le = LabelEncoder()
labels = le.fit_transform(labels)

데이터 세트의 모든 이미지에 대한 파일인 imagePaths를 가져옵니다. 그런 다음 이 데이터셋을 셔플합니다. 파일 경로가 디렉토리 구조를 갖는다 고 가정하고 파일 경로에서 클래스 레이블 이름을 추출합니다.

# load the VGG16 network
print("[INFO] loading network...")
model = VGG16(weights="imagenet", include_top=False)

# initialize the HDF5 dataset writer, then store the class label
# names in the dataset
dataset = HDF5DatasetWriter(
    (len(imagePaths), 512 * 7 * 7),
    args["output"],
    dataKey="features",
    bufSize=args["buffer_size"],
)
dataset.storeClassLabels(le.classes_)

우리의 데이터 셋이 이 디렉토리 구조를 따르는 경우, 구분 기호 (Unix 컴퓨터에서는 '/', Windows에서는 '')를 기반으로 경로를 배열로 분할 한 다음 배열의 마지막에서 두 번째 항목(이 작업은 특정 이미지의 클래스 레이블을 생성)합니다. 레이블이 주어지면 정수로 인코딩합니다 (학습 프로세스 중에 원-핫 인코딩을 수행합니다).

 

이제 VGG16 네트워크 가중치를 로드하고 HDF5DatasetWriter를 인스턴스화 할 수 있습니다.

 

디스크에서 사전 훈련된 VGG16 네트워크를 로드합니다. 그러나 include_top = False 매개 변수는 최종 완전 연결 계층이 아키텍처에 포함되지 않아야 함을 나타냅니다. 따라서 네트워크를 통해 이미지를 순방향 전파 할 때 FC 계층의 소프트 맥스 분류기에 의해 생성된 확률보다는 최종 POOL 계층 이후의 특성 값을 얻습니다.

 

HDF5DatasetWriter를 인스턴스화합니다. 첫 번째 매개 변수는 데이터 세트의 차원으로, 각각 512x7x7 = 25,088크기의 특징 벡터를 갖는 총 이미지 len(imagePaths)이 있습니다. 그런 다음 레이블 인코더에 따라 클래스 레이블의 문자열 이름을 저장합니다.

이제 실제 특징 추출을 시작하겠습니다.

image_iter = np.arange(0, len(imagePaths), bs)
# loop over the images in batches
for i in tqdm(
    image_iter, total=len(image_iter), desc="Extracting Features"
):
    # extract the batch of images and labels, then initialize the
    # list of actual images that will be passed through the network
    # for feature extraction
    batchPaths = imagePaths[i : i + bs]
    batchLabels = labels[i : i + bs]
    batchImages = []

--batch-size 배치로 imagePaths를 반복하기 시작합니다. 해당 배치에 대한 이미지 경로와 레이블을 추출하고, VGG16에로드 및 공급 될 이미지를 저장하는 목록을 초기화합니다.

특징 추출을 위해 이미지를 준비하는 것은 CNN을 통해 분류 할 이미지를 준비하는 것과 정확히 동일합니다.

    for (j, imagePath) in enumerate(batchPaths):
        # load the input image using the Keras helper utility
        # while ensuring the image is resized to 224x224 pixels
        image = load_img(imagePath, target_size=(224, 224))
        image = img_to_array(image)

        # preprocess the image by (1) expanding the dimensions and
        # (2) subtracting the mean RGB pixel intensity from the
        # ImageNet dataset
        image = np.expand_dims(image, axis=0)
        image = imagenet_utils.preprocess_input(image)

        # add the image to the batch
        batchImages.append(image)

배치의 각 이미지 경로를 반복합니다. 각 이미지는 디스크에서 로드되고 Keras 호환 어레이로 변환됩니다. 그런 다음 이미지를 전처리 한 다음 batchImages에 추가합니다.

 

batchImages의 이미지에 대한 특징 벡터를 얻으려면 모델의 .predict 메서드를 호출하기 만하면됩니다.

    # pass the images through the network and use the outputs as
    # our actual features
    batchImages = np.vstack(batchImages)
    features = model.predict(batchImages, batch_size=bs)

    # reshape the features so that each image is represented by
    # a flattened feature vector of the `MaxPooling2D` outputs
    features = features.reshape((features.shape[0], 512 * 7 * 7))

    # add the features and labels to our HDF5 dataset
    dataset.add(features, batchLabels)


# close the dataset
dataset.close()

NumPy.vstack 방법을 사용하여 이미지가 모양 (N, 224, 224, 3)을 갖도록 이미지를 "수직으로 스택"합니다. 여기서 N은 배치의 크기입니다.

 

네트워크를 통해 batchImages를 전달하면 실제 특성 벡터가 생성됩니다. VGG16의 헤드에서 완전히 연결된 레이어를 잘라 냈으므로 이제 최종 최대 풀링 작업 후에 값이 남습니다. 그러나 POOL의 출력은 모양 (N, 512, 7, 7)을 가지며, 이는 각각 크기가 7 x 7512개의 필터가 있음을 의미합니다. 이러한 값을 특성 벡터로 취급하려면, 모양 (N, 25088)을 가진 배열로 변환해야합니다. HDF5 데이터 세트에 기능과 batchLabels를 추가합니다.

 

최종 코드 블록은 HDF5 데이터 세트 닫기를 처리합니다.

python extract_features.py --dataset ~/data/animals/images/ \
--output datasets/animals/hdfs/features.hdf5

python extract_features.py --dataset ~/data/caltech-101/images/ \
--output datasets/caltech-101/hdfs/features.hdf5

python extract_features.py --dataset ~/data/flowers17/images/ \
--output datasets/flowers17/hdfs/features.hdf5

이작업은 cpu환경에서는 매우 오래 걸리므로 gpu환경에서 하는 것을 추천합니다.

 

feature extractor가 진행되는 과정

feature_extractors.tar.gz
0.18MB

 

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