출력층 등을 변경한 모델을 학습된 모델을 기반으로 구축한 후, 직접 준비한 데이터로 신경망 모델의 결합 파라미터 학습

결합 파라미터의 초깃값은 학습된 모델의 파라미터 사용한다. 전이학습과 달리 파라미터 재학습한다.

fine tuning 은  트랜스퍼 러닝을 한 상태에서 수행하는 방법이다

base_model.trainable = True

베이스 모델의 전체 레이어를 학습 가능토록 먼저 바꿔준다.

end_layer = 100
for layer in base_model.layers[0: end_layer]:
    layer.trainable = False

베이스모델의 첫번째 레이어부터, 우리가 정한 레이어까지는 학습이 안되도록 설정해준다.

이후 컴파일과 fit을 통해 훈련하면 된다.

이 글에서는 사전 훈련된 네트워크에서 Transfer Learning(전이 학습)을 사용하여 이미지를 분류하는 방법을 다룬다.

IMG_SHAPE = (128, 128, 3)
base_model = tf.keras.applications.MobileNetV2(input_shape = IMG_SHAPE, include_top = False)
 

이미 만들어져서 학습이 완료된 모델을 가져오되, 헤드모델은 제외한 베이스모델만 가져온다.

base_model.trainable = False

우리가 가져온 모델의 베이스모델 부분은특징을 잡아내는 역활을 하므로, 학습이 되지 않도록 한다.

head_model = base_model.output
head_model = tf.keras.layers.GlobalAveragePooling2D()(head_model)
head_model = tf.keras.layers.Dense(128, 'relu')(head_model)
head_model = tf.keras.layers.Dense(1, 'sigmoid')(head_model)

head_model을 정의해준다.

model = tf.keras.models.Model(inputs = base_model.input, outputs = head_model)
model.compile(tf.keras.optimizers.RMSprop(0.0001), 'binary_crossentropy', ['accuracy'])
 

베이스 모델과 헤드모델을 합쳐서, 하나의 모델으로 변수로 만들어 준다.

이후 model.fit을 하면 된다.

# os.listdir(DIRECTORY) 디렉토리에 있는 파일 리스팅
# os.path.getsize(PATH) 파일 사이즈 확인
# copyfile(source, destination) 원하는 디렉토리로 파일 복사
# random.sample(list, len(list)) 리스트를 섞는다.(파일명 섞기)



def split_data(SOURCE, TRAINING, TESTING, SPLIT_SIZE):
# YOUR CODE STARTS HERE
    # 1. 원본 디렉토리에서, 파일명을 모두 가져온다.
    filename_list = os.listdir(SOURCE)

    # 2. 잘 섞어준다.
    shuffled_list = random.sample(filename_list, len(filename_list))

    # 3. 트레이닝과 테스팅으로 분리하기 위해서 인덱스를 잡아준다.
    index = int(len(shuffled_list) * SPLIT_SIZE)

    # 4. 섞여있는 리스트에서, 위의 인덱스로, 학습용과 테스트용 파일을 분리한다.
    training = shuffled_list[0:index]
    testing = shuffled_list[index:]

    # 5. 각각의 분리된 파일을, 해당 디렉토리로 복사해 준다.
    for filename in training:
        if os.path.getsize(SOURCE + filename) > 0:
            copyfile(SOURCE+filename, TRAINING + filename)

    for filename in testing:
        if os.path.getsize(SOURCE + filename) > 0:
            copyfile(SOURCE + filename, TESTING + filename)


# YOUR CODE ENDS HERE


CAT_SOURCE_DIR = "/tmp/PetImages/Cat/"
TRAINING_CATS_DIR = "/tmp/cats-v-dogs/training/cats/"
TESTING_CATS_DIR = "/tmp/cats-v-dogs/testing/cats/"
DOG_SOURCE_DIR = "/tmp/PetImages/Dog/"
TRAINING_DOGS_DIR = "/tmp/cats-v-dogs/training/dogs/"
TESTING_DOGS_DIR = "/tmp/cats-v-dogs/testing/dogs/"

split_size = .9
split_data(CAT_SOURCE_DIR, TRAINING_CATS_DIR, TESTING_CATS_DIR, split_size)
split_data(DOG_SOURCE_DIR, TRAINING_DOGS_DIR, TESTING_DOGS_DIR, split_size)

 

먼저 파일들을 잘 섞은 후,  트레이닝은 90%, 테스트는 10%로 파일을 나눕니다. 그리고 파일의 사이즈가 0이 아니면, 
 그 파일을 트레이닝 또는 테스트 디렉토리에 실제로 저장을 합니다.

train_datagen = ImageDataGenerator(rescale = 1 / 255.0, rotation_range = 30, width_shift_range = 0.2, height_shift_range = 0.2, shear_range = 0.2, zoom_range = 0.2, horizontal_flip = True)

rotation_range is a value in degrees (0–180), a range within which to randomly rotate pictures.
width_shift and height_shift are ranges (as a fraction of total width or height) within which to randomly translate pictures vertically or horizontally.
shear_range is for randomly applying shearing transformations.
zoom_range is for randomly zooming inside pictures.
horizontal_flip is for randomly flipping half of the images horizontally. This is relevant when there are no assumptions of horizontal assymmetry (e.g. real-world pictures).
위 설명들을 참조해서 ImageDataGenerator의 파라미터에 대입해 주면 이미지 데이터 증강이 된다.

from tensorflow.keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale = 1 / 255.0)
validation_datagen = ImageDataGenerator(rescale = 1 / 255.0)

train_generator = train_datagen.flow_from_directory('/tmp/horse-or-human', target_size = (300, 300), class_mode = 'binary')
validation_generator = validation_datagen.flow_from_directory('/tmp/validation-horse-or-human', target_size = (300,300), class_mode = 'binary')

epoch_history = model.fit(train_generator, epochs = 20, validation_data = (validation_generator))

학습시킬 데이터는 넘파이 어레이 인데, 현재 우리는 png 파일로만 준비가 되어있다. 따라서 이미지파일을 넘파이로 바꿔주는 라이브러리를, 텐서플로우가 제공해준다.

 

ImageDataGenerator를 import 하고 rescale 에다 1 / 255.0을 대입한다. 0 ~ 255 로 표현된 rgb값을 0 ~ 1로 만들기 위해서다.

 

변수로 만들어 줬으면, 그다음 할일은, 이미지가 들어있는 디렉토리의 정보, 이미지 사이즈 정보, 분류할 갯수 정보를 알려줘야 한다. 이것들을 flow_from_dirctory에 대입해 준다.
 

 

아래 train_generater는, 넘파이어레이와, 해당 이미지의 정답지도 가지고 있는 변수다. 즉, X_train과 y_train을 모두 한꺼번에 가지고 있다! fit에 학습데이터로 넣어 준뒤 validation_data에는 (validation_generator)를 대입해서 테스트한다.

import zipfile
zip_ref = zipfile.ZipFile('/tmp/horse-or-human.zip')
zip_ref.extractall('/tmp/horse-or-human')

코랩환경에서 했다. 먼저 zipfile을 import한다. zipfile.ZipFile에 압축파일이 있는 경로를 대입해준다.

이것을 변수 zip_ref로 저장한뒤 exttractall에 압축풀 경로를 지정해주면 경로에다 압축 파일이 풀어진다.

!wget --no-check-certificate \
    https://storage.googleapis.com/laurencemoroney-blog.appspot.com/horse-or-human.zip \
    -O /tmp/horse-or-human.zip

!를 통해 리눅스 명령어 wget을 이용한다.

다운로드 할 주소와 -O 뒤에 경로를 써준다.

이미지의 사이즈에 kernal 사이즈를 빼고 패딩의 2배 값을 더해준 것을 Stride로 나누고 1을 더해주면 된다.

CNN은 이미지 전체를 작은 단위로 쪼개어 각 부분을 분석하는 것이 핵심입니다.

CNN은 이미지를 인식하기 위해 패턴을 찾는 데 유용합니다. 데이터를 통해 특징을 스스로 학습하고, 패턴을 사용하여 이미지를 분류하고 특징을 수동으로 추출할 필요가 없습니다. 또한 기존 네트워크를 바탕으로 새로운 인식 작업을 위해 CNN을 재학습하여 사용하는 것이 가능합니다.

그림과 같이 convolution kernel로 합성곱을 통해 feature Map을 만든다.

pooling은 특징은 가지되, 컴퓨팅 효율을 높게 해준다.

그림과 같이 2 * 2 의 사이즈로 2 칸씩 띄어서 Pooling을 해주면 크기가 줄어든다.

아래는 코드 예시다.

model = tf.keras.models.Sequential([
  tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(28, 28, 1)),
  tf.keras.layers.MaxPooling2D(2, 2)])

 

 

 

model.compile('adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])

2개 분류의 문제일때는, 로스 펑션을 binary_crossentropy
3개 이상의 분류의 문제일때는? 2가지 경우가 있다!
첫번째 경우, y의 값이 레이블 인코딩으로 되어있는 경우 : sparse_categorical_crossentropy
두번째 경우, y의 값이 원핫 인코딩으로 되어있는 경우 : categorical_crossentropy

+ Recent posts