【Keras】Keras기반 Yolo3 -라쿤 데이터 학습시키기 + GPU 학습 유의사항
GPU Object Detection시 유의 사항을 간단히 알아보고, 이전 게시물에서 공부했던 Keras 기반 Yolo3를 이용해 데이터 학습을 시켜보자.
GPU 학습 유의사항/ 라쿤 데이터 학습시키기 - Keras기반 Yolo3
1. GPU 학습 시킬 떄 주의 사항
- 대량의 이미지 학습시 메모리 문제
- 알다시피 개별 이미지가 Tensor, narray로 변환해서 NeuralNet에 집어넣을떄 이미지를 Batch로 묶어 처리한다.
- 이 Batch가 그래픽 카드 메모리 사용량의 많은 부분을 좌우한다.
(1000장 - 10장 배치 * 100번 = 1 에폭) - GPU 사용 % 자주 확인하기. Image를 loading하는 것은 CPU에서 한다. Batch가 크면 GPU는 바쁘고 CPU는 논다. Batch가 작으면 GPU는 놀고 CPU는 바쁘다. 근데 Object Detection은 GPU에서 할게 너무 많아서 Batch를 작게하는게 대부분이다. (Batch = 1~16)
- Genrator와 Batch
- 특히 fit_generator를 확인해보면, Python gererator를 사용한다. gerator, next, yield에 대해서 알아보자. 코딩도장 generator 설명
- 배치 사이즈를 크게 늘린다고 학습이나 추론이 빨라지지 않는다. 100장의 이미지를 한방에 끌어오는것도 힘들지만, 그 이미지를 네트워크에 넣는다 하더라도 어딘가에서 병목이 걸릴건 당연하다. 따라서 배치 사이즈를 어떻게 설정하지는 CPU core, GPU 성능 등을 파악해서 균형있게 맞춰야 한다.(Heuristic 하게 Turning)
- 한쪽은 열심히 일하고, 한쪽은 기다리는 현상이 일어나지 않게끔. 이렇게 양쪽이 일을 쉬지 않고 균형있게 배치하는 것이 필요하다.
- 이러한 Batch를 Keras에서는 (fit_generator 함수가 사용하는) DataGenerator, flow_from_drectory 가 해준다. 알다시피 Torch는 TensorDataset, DataLoader가 해준다.
이런 generator를 사용하기 위해서 Keras와 같은 경우에 다음과 같은 코드를 사용한다.
from keras.preprocessing.image import ImageDataGenerator train_datagen = ImageDataGerator(rescale=1/255) # 이미지 정규화 train_gernator = train_datagen.flow_from_director('학습용 이미지 Directory', targer_size = (240,240), batch_size-10, class_mode='categoricl') valid_datagen = ImageDataGerator(rescale=1/255) valid_gernator = valid_datagen.flow_from_director('검증용 이미지 Directory', targer_size = (240,240), batch_size-10, class_mode='categoricl') # 모델을 구성하고 model = Sequential() model.add(Conv2D(32, kernel_size=(3,3), activation='relu', input_shape=(240,240,3))) model.add ... ... ... model.add(Dense(3, activation='softmax')) model.compile(loss='categorial_crossentropy', optimizer='adam', metrixs=['accuracy']) # 학습을 시킨다. model.fit_generator(train_generator, steps_per_epoch=100, epochs=10, validation_data=valid_generator, validation_steps=2)
- 이렇게 fit_generator을 돌리면 data pipeline이 만들어 진다. train_generator가 디렉토리에 가서 배치만큼의 파일을 읽어와서 yeild를 하여 모델에 데이터를 넣는다.
2. qqwweee/Keras-Yolo3로 Training 하기 위한 분석
주의사항{:.lead}
- 아래의 일렬의 과정들은 패키지의 있는 함수들을 전적으로 사용합니다.
- 따라서 그냥 보면 흐름을 이해하지 못할 수도 있습니다.
- 꼭 패키지의 코드들과 같이 보는 것을 추천합니다.
- 만약 케라스를 잘 모른다면, 그냥 다른 Data를 학습시킬때는 이런 일렬의 과정들이 있구나
정도의 감을 잡는 것도 아주 좋은 공부 일 수 있습니다. - 아래 전체 과정 요약
- 내가 가진 데이터 전처리(패키지가 원하는 형식으로)
- Data Genereator에 넣기(torch같은 경우 TensorDataset, DataLoader를 이용해서)
- create_model 하기. (torch.nn 모듈을 사용해서 정의한 신경망 모델 클래스로, 객체 생성하기)
- Check point, log 생성을 위한 작업하기.(Keras 같은 경우 keras.callbacks 모듈의 함수 이용)
- model을 위한 optimizer, Loss function(criterion) 설정하기.
- model.fit_generator를 이용해서 학습 및 가중치 갱신 시키기. (from keras.models import Model에 있는 맴버함수이다.)
- .h5 형식의 Inference를 위한 가중치 파일을 얻을 수 있다.
- .h5 형식 파일을 이용해서, yolo.py함수의 YOLO 클래스를 이용해 객체 생성
- YOLO.detect_image를 이용해서 객체 탐지 수행
- 지금까지는 1. Pretrained된 Weight값을 가져와서 Inference를 수행하거나(Tensorflow(SSD, Yolo), Keras-yolo3) 2. OpenCV DNN 모듈을 사용하거나 해왔다.
- 참고 : 1개의 객체만 검출한다면 100장이어도 충분하다. 근데 Class가 여러개면 수 많은 이미지 데이터가 필요하다.
- <weight 가중치 파일 형식 정리>
- keras weight(케라스 가중치) 파일은 파일 형식이 .h5파일이다.
- Tensorflow에서 Inference를 위한 파일 형식은 .pb 파일이다. .ckpt파일에는 학습에 대한check point에 대한 정보를 담고 있다.
- PyTorch에서는 .pt 파일이 torch.save(model.state_dict()를 이용해서 저장한 weight파일이다.
- qqwweee/keras-yolo3에 적힌 Training 방법 정리
- voc(xml 파일사용)을 annotation파일로 바꾸는 convert_annotation.py 파일을 살펴보면 최종적으로 ‘%s_%s.txt’%(year, image_set) 파일을 만드는 것을 확인할 수 있다.
- Readme의 내용을 따르면,
각 한줄 : image_file_path box1 box2 … boxN
boxK의 format : x_min,y_min,x_max,y_max,class_id (no space) 이다.path/to/img1.jpg 50,100,150,200,0 30,50,200,120,3 path/to/img2.jpg 120,300,250,600,2 ...
- 일단 pretrained된 weight를 가져와서 학습시키는 것이 좋으니, conver.py를 실행해서 darknet weight를 keras weight로 바꿔준다.
- train.py를 사용해서 학습을 한다. 내부 코드 적극 활용할 것.
- train.py에 들어가야하는 Option을 설정하는 방법은 원래의 default option이 무엇인지 확인하면 된다.
- train.py을 적극적으로 이용할 계획이다. 아래와 같은 방법으로. 함수는 아래와 같이 import를 해서 사용할 것이고, main함수의 내용은 소스 코드 그대로 복사해 가져와서 사용할 예정이다.
from train import get_classes, get_anchors from train import create_model, data_generator
3. 라쿤 데이터셋으로 학습시키고 Inference하기
- 참조 : /DLCV/Detection/yolo/KerasYolo_Raccoon_학습및_Detection.ipynb
- 좋은 데이터 세트 모음 : 라쿤데이터셋
3-1 데이터 전처리 하기
- Raccoon 데이터 세트 download 후
- 이미지와 annoation 디렉토리를 제외하고 모두 삭제합니다.
- images에 이미지가 있고 annoation에는 각이미지에 해당하는 xml파일 203개가 존재한다.
- 아래의 내용들은 전처리를 하기에 아주 좋은 함수들과 모듈들이 잘 사용되고 있으므로 잘 알아두고 나중에도 꼭 잘 활용하자
# annotation과 image 디렉토리 설정. annotation디렉토리에 있는 파일 확인.
import os
from pathlib import Path
HOME_DIR = str(Path.home())
ANNO_DIR = os.path.join(HOME_DIR, 'DLCV/data/raccoon/annotations')
IMAGE_DIR = os.path.join(HOME_DIR, 'DLCV/data/raccoon/images')
print(ANNO_DIR)
files = os.listdir(ANNO_DIR)
print('파일 개수는:',len(files)) # 200개
print(files) # Dicrectory에 있는 파일 이름 전부가 list 변수에 저장된다.
- 아래에서 사용할 모듈 참고 문헌 (해당 사이트만 공부하면 아래의 내용들 충분히 커버 가능)
- glob - https://wikidocs.net/83
- xml.etree.ElementTree as EF - http://egloos.zum.com/sweeper/v/3045370
import glob
import xml.etree.ElementTree as ET
def xml_to_csv(path, output_filename):
"""
path : annotation Detectory
filename : ouptut file name
"""
xml_list = []
# xml 확장자를 가진 모든 파일의 절대 경로로 xml_file할당.
with open(output_filename, "w") as train_csv_file:
for xml_file in glob.glob(path + '/*.xml'):
# path에 있는 xml파일중 하나 하나를 가져온다.
tree = ET.parse(xml_file)
root = tree.getroot()
# 파일내에 있는 모든 object Element를 찾음.
full_image_name = os.path.join(IMAGE_DIR, root.find('filename').text)
value_str_list = ' '
# find all <object>인것 다 찾는다
for obj in root.findall('object'):
xmlbox = obj.find('bndbox')
x1 = int(xmlbox.find('xmin').text)
y1 = int(xmlbox.find('ymin').text)
x2 = int(xmlbox.find('xmax').text)
y2 = int(xmlbox.find('ymax').text)
# 단 하나의 class_id raccoon
class_id = 0
value_str = ('{0},{1},{2},{3},{4}').format(x1, y1, x2, y2, class_id)
value_str_list = value_str_list+value_str+' '
# box1 box2 ......
# object별 정보를 tuple형태로 object_list에 저장.
train_csv_file.write(full_image_name+' '+ value_str_list+'\n') # image_file_path box1 box2 ... boxN \n ... image_file_path
# xml file 찾는 for loop 종료
xml_to_csv(ANNO_DIR, os.path.join(ANNO_DIR,'raccoon_anno.csv'))
print(os.path.join(ANNO_DIR,'raccoon_anno.csv'))
/home/sb020518/DLCV/data/raccoon/annotations/raccoon_anno.csv
3-2 전처리한 데이터로 학습시키기 - pretrain 모델가져오기
- 위의 파일 내부의 함수들을 import할 예정이다. import방법은 아래와 같다. 참조하자
- 사진의 model.py, utils.py, keras-yolo3의 train.py파일을 아래와 같이 import할 것이다.
import sys
LOCAL_PACKAGE_DIR = os.path.abspath("./keras-yolo3")
sys.path.append(LOCAL_PACKAGE_DIR)
from yolo3.model import preprocess_true_boxes, yolo_body, tiny_yolo_body, yolo_loss
from yolo3.utils import get_random_data
# get_random_data - Image Augmentation 하기 위한 모듈 - Augmentation을 할 때 Bounding Box 처리도 해준다.
import numpy as np
import keras.backend as K
from keras.layers import Input, Lambda
from keras.models import Model
from keras.optimizers import Adam
from keras.callbacks import TensorBoard, ModelCheckpoint, ReduceLROnPlateau, EarlyStopping
from train import get_classes, get_anchors
from train import create_model, data_generator, data_generator_wrapper
BASE_DIR = os.path.join(HOME_DIR, 'DLCV/Detection/yolo/keras-yolo3')
## 학습을 위한 기반 환경 설정. annotation 파일 위치, epochs시 저장된 모델 파일, Object클래스 파일, anchor 파일.
annotation_path = os.path.join(ANNO_DIR, 'raccoon_anno.csv')
log_dir = os.path.join(BASE_DIR, 'snapshots/000/') # tensorboard, epoch 당 weight 저장 장소로 사용할 될 예정이다.
classes_path = os.path.join(BASE_DIR, 'model_data/raccoon_class.txt') # 내가 만듬 한줄 - raccoon
# tiny yolo로 모델을 학습 원할 시 아래를 yolo_anchors.txt' -> tiny_yolo_anchors.txt'로 수정.
anchors_path = os.path.join(BASE_DIR,'model_data/yolo_anchors.txt') # 그대로 사용
class_names = get_classes(classes_path)
num_classes = len(class_names) # 1개
anchors = get_anchors(anchors_path)
# 아래는 원본 train.py에서 weights_path 변경을 위해 임의 수정. 최초 weight 모델 로딩은 coco로 pretrained된 모델 로딩.
# tiny yolo로 모델을 학습 원할 시 아래를 model_data/yolo.h5' -> model_data/tiny-yolo.h5'로 수정.
model_weights_path = os.path.join(BASE_DIR, 'model_data/yolo.h5' )
input_shape = (416,416) # yolo-3 416 을 사용하므로 이렇게 정의. 라쿤 이미지들 wh는 모두 다르다.
is_tiny_version = len(anchors)==6 # default setting
# create_tiny_model(), create_model() 함수의 인자 설정을 원본 train.py에서 수정.
if is_tiny_version:
model = create_tiny_model(input_shape, anchors, num_classes,
freeze_body=2, weights_path=model_weights_path)
else:
# create_model 은 해당 패키지의 tarin.py 내부에 있는 클래스를 사용했다. 이 함수는 keras 모듈이 많이 사용한다. 우선 모르는 건 pass하고 넘어가자.
model = create_model(input_shape, anchors, num_classes,
freeze_body=2, weights_path=model_weights_path) # make sure you know what you freeze
# epoch 마다 call back 하여 모델 파일 저장.
# 이것 또한 Keras에서 많이 사용하는 checkpoint 저장 방식인듯 하다. 우선 이것도 모르지만 넘어가자.
logging = TensorBoard(log_dir=log_dir)
checkpoint = ModelCheckpoint(log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
monitor='val_loss', save_weights_only=True, save_best_only=True, period=3)
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1)
early_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1)
Create YOLOv3 model with 9 anchors and 1 classes.
Load weights /home/sb020518/DLCV/Detection/yolo/keras-yolo3/model_data/yolo.h5.
Freeze the first 249 layers of total 252 layers.
3-3 전처리한 데이터로 학습시키기 - 학습과 검증 데이터로 나누고 학습!
- 학습 전에 GPU정리를 하자.
- P100에서 40분정도 걸린다.
- 1 epoch당 weight가 저장되는 것을 확인할 수 있다.
- 데이터가 적기 때문에, 최종 Loss값이 큰 것을 확인할 수 있다. 하지만 그래도 Inference 성능이 나쁘지 않다. Class 갯수가 1개 이므로..
val_split = 0.1 # train data : val_data = 9 : 1
with open(annotation_path) as f:
# 이러니 annotation 파일이 txt이든 csv이든 상관없었다.
lines = f.readlines()
# 랜덤 시드 생성 및 lines 셔플하기
np.random.seed(10101)
np.random.shuffle(lines)
np.random.seed(None)
# 데이터셋 나누기
num_val = int(len(lines)*val_split)
num_train = len(lines) - num_val
# 여기서 부터 진짜 학습 시작!
# create_model() 로 반환된 yolo모델에서 trainable=False로 되어 있는 layer들 제외하고 학습
if True:
# optimizer와 loss 함수 정의
# 위에서 사용한 create_model 클래스의 맴버함수를 사용한다.
model.compile(optimizer=Adam(lr=1e-3), loss={
# use custom yolo_loss Lambda layer.
'yolo_loss': lambda y_true, y_pred: y_pred})
batch_size = 2
print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
# foward -> backpropagation -> weight 갱신 -> weight 저장
# checkpoint 만드는 것은 뭔지 모르겠으니 pass...
model.fit_generator(
data_generator_wrapper(lines[:num_train], batch_size, input_shape, anchors, num_classes),
steps_per_epoch=max(1, num_train//batch_size),
validation_data=data_generator_wrapper(lines[num_train:], batch_size, input_shape, anchors, num_classes),
validation_steps=max(1, num_val//batch_size),
epochs=50,
initial_epoch=0,
callbacks=[logging, checkpoint])
model.save_weights(log_dir + 'trained_weights_stage_1.h5')
# create_model() 로 반환된 yolo모델에서 trainable=False로 되어 있는 layer들 없이, 모두 True로 만들고 다시 학습
if True:
for i in range(len(model.layers)):
model.layers[i].trainable = True
model.compile(optimizer=Adam(lr=1e-4), loss={'yolo_loss': lambda y_true, y_pred: y_pred}) # recompile to apply the change
print('Unfreeze all of the layers.')
batch_size = 4 # note that more GPU memory is required after unfreezing the body
print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
model.fit_generator(
data_generator_wrapper(lines[:num_train], batch_size, input_shape, anchors, num_classes),
steps_per_epoch=max(1, num_train//batch_size),
validation_data=data_generator_wrapper(lines[num_train:], batch_size, input_shape, anchors, num_classes),
validation_steps=max(1, num_val//batch_size),
epochs=100,
initial_epoch=50,
callbacks=[logging, checkpoint, reduce_lr, early_stopping])
model.save_weights(log_dir + 'trained_weights_final.h5')
Train on 180 samples, val on 20 samples, with batch size 2.
Epoch 1/50
90/90 [==============================] - 501s 6s/step - loss: 933.7634 - val_loss: 111.7494
Epoch 2/50
66/90 [=====================>........] - ETA: 1:58 - loss: 89.7261
KeyboardInterrupt:
# YOLO 객체 생성.
import sys
import argparse
#keras-yolo에서 image처리를 주요 PIL로 수행.
from PIL import Image
LOCAL_PACKAGE_DIR = os.path.abspath("./keras-yolo3")
sys.path.append(LOCAL_PACKAGE_DIR)
from yolo import YOLO, detect_video
raccoon_yolo = YOLO(
model_path=os.path.join(HOME_DIR,'DLCV/Detection/yolo/keras-yolo3/snapshots/000/trained_weights_final.h5'),
anchors_path='~/DLCV/Detection/yolo/keras-yolo3/model_data/yolo_anchors.txt',
classes_path='~/DLCV/Detection/yolo/keras-yolo3/model_data/raccoon_class.txt')
import matplotlib
import matplotlib.pyplot as plt
img = Image.open(os.path.join(IMAGE_DIR, 'raccoon-171.jpg'))
plt.figure(figsize=(12, 12))
plt.imshow(img)
detected_img = raccoon_yolo.detect_image(img)
plt.figure(figsize=(12, 12))
plt.imshow(detected_img)
- 이제 모델구성까지 모두 끝났다. 이제 raccoon_yolo.detect_image(img) 만 잘사용하면 밑의 내용은 끝이다.
3-4 임의의 16개의 원본 이미지를 추출하여 Object Detected된 결과 시각화
import numpy as np
np.random.seed(0)
# 랜덤하게 16개의 이미지 파일만 선택.
# 랜덤 숫자 만을 이용하지 말고 아래와 같은 방법을 이용하면, 알아서 random하게 파일을 선택해준다.
all_image_files = glob.glob(IMAGE_DIR + '/*.jpg')
all_image_files = np.array(all_image_files)
file_cnt = all_image_files.shape[0]
show_cnt = 16
show_indexes = np.random.choice(file_cnt, show_cnt)
show_files = all_image_files[show_indexes]
print(show_files)
# 16개의
fig, axs = plt.subplots(figsize=(24,24) , ncols=4 , nrows=4)
for i , filename in enumerate(show_files):
print(filename)
row = int(i/4)
col = i%4
img = Image.open(os.path.join(IMAGE_DIR, filename))
detected_image = raccoon_yolo.detect_image(img)
axs[row][col].imshow(detected_image)
4. 위의 내용들을 다시 활용 - Video Object Detection 수행.
- video frame 가져오는 것은 cv2 사용.
- 해당 프래임 이미지를 narray에서 PIL image로 변환해서, model.detect_image(image) 수행
import cv2
import time
def detect_video_yolo(model, input_path, output_path=""):
start = time.time()
cap = cv2.VideoCapture(input_path)
#codec = cv2.VideoWriter_fourcc(*'DIVX')
codec = cv2.VideoWriter_fourcc(*'XVID')
vid_fps = cap.get(cv2.CAP_PROP_FPS)
vid_size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
vid_writer = cv2.VideoWriter(output_path, codec, vid_fps, vid_size)
frame_cnt = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print('총 Frame 갯수:', frame_cnt, '원본 영상 FPS:',vid_fps, '원본 Frame 크기:', vid_size)
index = 0
while True:
hasFrame, image_frame = cap.read()
if not hasFrame:
print('프레임이 없거나 종료 되었습니다.')
break
start = time.time()
# PIL Package를 내부에서 사용하므로 cv2에서 읽은 image_frame array를 다시 PIL의 Image형태로 변환해야 함.
image = Image.fromarray(image_frame)
# 아래는 인자로 입력된 yolo객체의 detect_image()로 변환한다.
detected_image = model.detect_image(image)
# cv2의 video writer로 출력하기 위해 다시 PIL의 Image형태를 array형태로 변환
result = np.asarray(detected_image)
index +=1
print('#### frame:{0} 이미지 처리시간:{1}'.format(index, round(time.time()-start,3)))
vid_writer.write(result)
vid_writer.release()
cap.release()
print('### Video Detect 총 수행시간:', round(time.time()-start, 5))
detect_video_yolo(raccoon_yolo, '../../data/video/jack_and_raccoon.mp4', '../../data/output/jack_and_raccoon_yolo_01.avi')
5. 위의 내용들을 반복 - tiny yolo로 학습.
- 위에서 했던 내용을 통채로 함수로 만들자.
import numpy as np
import keras.backend as K
from keras.layers import Input, Lambda
from keras.models import Model
from keras.optimizers import Adam
from keras.callbacks import TensorBoard, ModelCheckpoint, ReduceLROnPlateau, EarlyStopping
from train import get_classes, get_anchors
from train import create_model, create_tiny_model, data_generator, data_generator_wrapper
def train_yolo(pretrained_path, annotation_path,classes_path, anchors_path,log_dir,trained_model_name, b_size, epochs_cnt):
print('pretrained_path:', pretrained_path)
class_names = get_classes(classes_path)
num_classes = len(class_names)
anchors = get_anchors(anchors_path)
input_shape = (416,416) # multiple of 32, hw
# tiny yolo여부를 anchor 설정 파일에서 자동으로 알 수 있음. anchor갯수가 6개이면 tiny yolo
is_tiny_version = len(anchors)==6 # default setting
# create_tiny_model(), create_model() 함수의 인자 설정을 원본 train.py에서 수정.
if is_tiny_version:
model = create_tiny_model(input_shape, anchors, num_classes,
freeze_body=2, weights_path=pretrained_path)
else:
model = create_model(input_shape, anchors, num_classes,
freeze_body=2, weights_path=pretrained_path) # make sure you know what you freeze
logging = TensorBoard(log_dir=log_dir)
checkpoint = ModelCheckpoint(log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
monitor='val_loss', save_weights_only=True, save_best_only=True, period=3)
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1)
early_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1)
val_split = 0.1
with open(annotation_path) as f:
lines = f.readlines()
np.random.seed(10101)
np.random.shuffle(lines)
np.random.seed(None)
num_val = int(len(lines)*val_split)
num_train = len(lines) - num_val
# Train with frozen layers first, to get a stable loss.
# Adjust num epochs to your dataset. This step is enough to obtain a not bad model.
if True:
model.compile(optimizer=Adam(lr=1e-3), loss={
# use custom yolo_loss Lambda layer.
'yolo_loss': lambda y_true, y_pred: y_pred})
batch_size = b_size
print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
model.fit_generator(data_generator_wrapper(lines[:num_train], batch_size, input_shape, anchors, num_classes),
steps_per_epoch=max(1, num_train//batch_size),
validation_data=data_generator_wrapper(lines[num_train:], batch_size, input_shape, anchors, num_classes),
validation_steps=max(1, num_val//batch_size),
epochs=int(epochs_cnt/2),
initial_epoch=0,
callbacks=[logging, checkpoint])
model.save_weights(log_dir + trained_model_name+'_stage_1.h5')
# Unfreeze and continue training, to fine-tune.
# Train longer if the result is not good.
if True:
for i in range(len(model.layers)):
model.layers[i].trainable = True
model.compile(optimizer=Adam(lr=1e-4), loss={'yolo_loss': lambda y_true, y_pred: y_pred}) # recompile to apply the change
print('Unfreeze all of the layers.')
batch_size = b_size # note that more GPU memory is required after unfreezing the body
print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
model.fit_generator(data_generator_wrapper(lines[:num_train], batch_size, input_shape, anchors, num_classes),
steps_per_epoch=max(1, num_train//batch_size),
validation_data=data_generator_wrapper(lines[num_train:], batch_size, input_shape, anchors, num_classes),
validation_steps=max(1, num_val//batch_size),
epochs=epochs_cnt,
initial_epoch=int(epochs_cnt/2),
callbacks=[logging, checkpoint, reduce_lr, early_stopping])
model.save_weights(log_dir + trained_model_name+'_final.h5')
BASE_DIR = os.path.join(HOME_DIR, 'DLCV/Detection/yolo/keras-yolo3')
# keras-yolo3에서 convert 된 yolo-tiny pretrained 모델을 사용해야 함.
pretrained_path = os.path.join(BASE_DIR, 'model_data/yolo-tiny.h5')
annotation_path = os.path.join(ANNO_DIR,'raccoon_anno.csv')
classes_path = os.path.join(BASE_DIR, 'model_data/raccoon_class.txt')
anchors_path = os.path.join(BASE_DIR, 'model_data/tiny_yolo_anchors.txt')
log_dir = os.path.join(BASE_DIR,'snapshots/000/')
trained_model_name = 'raccoon'
b_size=4
epochs_cnt = 100
train_yolo(pretrained_path, annotation_path,classes_path, anchors_path, log_dir,trained_model_name, b_size, epochs_cnt)
raccoon_tiny_yolo = YOLO(model_path=os.path.join(HOME_DIR,'DLCV/Detection/yolo/keras-yolo3/snapshots/000/raccoon_final.h5'),
anchors_path='~/DLCV/Detection/yolo/keras-yolo3/model_data/tiny_yolo_anchors.txt',
classes_path='~/DLCV/Detection/yolo/keras-yolo3/model_data/raccoon_class.txt')
# 16개의 이미지를 Detect해보자.
import numpy as np
np.random.seed(0)
# 모든 이미지 파일중에서 임의의 16개 파일만 설정.
all_image_files = glob.glob(IMAGE_DIR + '/*.jpg')
all_image_files = np.array(all_image_files)
file_cnt = all_image_files.shape[0]
show_cnt = 16
show_indexes = np.random.choice(file_cnt, show_cnt)
show_files = all_image_files[show_indexes]
print(show_files)
fig, axs = plt.subplots(figsize=(24,24) , ncols=4 , nrows=4)
for i , filename in enumerate(show_files):
print(filename)
row = int(i/4)
col = i%4
img = Image.open(os.path.join(IMAGE_DIR, filename))
detected_image = raccoon_tiny_yolo.detect_image(img)
axs[row][col].imshow(detected_image)
detect_video_yolo(raccoon_tiny_yolo, '../../data/video/jack_and_raccoon.mp4', '../../data/output/jack_and_raccoon_tiny_yolo_01.avi')
음… tiny yolo… 성능이 심각하게 안 좋다.