임의의 이미지 데이터세트에서 특징을 추출하는데 사용할수있는 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 7
인 512개
의 필터가 있음을 의미합니다. 이러한 값을 특성 벡터로 취급하려면, 모양 (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환경에서 하는 것을 추천합니다.
'keras > 2. Feature Extractors' 카테고리의 다른 글
4. Training a Classifier on Extracted Features (0) | 2020.08.28 |
---|---|
2. Writing Features to an HDF5 Dataset (0) | 2020.08.22 |
1. Networks as Feature Extractors (0) | 2020.08.22 |