728x90
반응형

반응형
728x90
반응형

학습된 모델을 이용하여 Video Detection 수행하기

classes 만 바뀜

%cd /content
!mkdir /content/data
!wget -O /content/data/the_rock_chase.mp4 https://github.com/chulminkw/DLCV/blob/master/data/video/the_rock_chase.mp4?raw=true

 

CLASSES = ('Car', 'Truck', 'Pedestrian', 'Cyclist')
labels_to_names_seq = {i:k for i, k in enumerate(CLASSES)}
labels_to_names_seq
# {0: 'Car', 1: 'Truck', 2: 'Pedestrian', 3: 'Cyclist'}

 

CLASSES = ('Car', 'Truck', 'Pedestrian', 'Cyclist')
cat2label = {k:i for i, k in enumerate(CLASSES)}

def get_detected_img(model, img_array,  score_threshold=0.3, is_print=True):
  # 인자로 들어온 image_array를 복사. 
  draw_img = img_array.copy()
  bbox_color=(0, 255, 0)
  text_color=(0, 0, 255)

  # model과 image array를 입력 인자로 inference detection 수행하고 결과를 results로 받음. 
  # results는 80개의 2차원 array(shape=(오브젝트갯수, 5))를 가지는 list. 
  results = inference_detector(model, img_array)

  # 80개의 array원소를 가지는 results 리스트를 loop를 돌면서 개별 2차원 array들을 추출하고 이를 기반으로 이미지 시각화 
  # results 리스트의 위치 index가 바로 COCO 매핑된 Class id. 여기서는 result_ind가 class id
  # 개별 2차원 array에 오브젝트별 좌표와 class confidence score 값을 가짐. 
  for result_ind, result in enumerate(results):
    # 개별 2차원 array의 row size가 0 이면 해당 Class id로 값이 없으므로 다음 loop로 진행. 
    if len(result) == 0:
      continue
    
    # 2차원 array에서 5번째 컬럼에 해당하는 값이 score threshold이며 이 값이 함수 인자로 들어온 score_threshold 보다 낮은 경우는 제외. 
    result_filtered = result[np.where(result[:, 4] > score_threshold)]
    
    # 해당 클래스 별로 Detect된 여러개의 오브젝트 정보가 2차원 array에 담겨 있으며, 이 2차원 array를 row수만큼 iteration해서 개별 오브젝트의 좌표값 추출. 
    for i in range(len(result_filtered)):
      # 좌상단, 우하단 좌표 추출. 
      left = int(result_filtered[i, 0])
      top = int(result_filtered[i, 1])
      right = int(result_filtered[i, 2])
      bottom = int(result_filtered[i, 3])
      caption = "{}: {:.4f}".format(labels_to_names_seq[result_ind], result_filtered[i, 4])
      cv2.rectangle(draw_img, (left, top), (right, bottom), color=bbox_color, thickness=2)
      cv2.putText(draw_img, caption, (int(left), int(top - 7)), cv2.FONT_HERSHEY_SIMPLEX, 0.37, text_color, 1)
      if is_print:
        print(caption)

  return draw_img
import time

def do_detected_video(model, input_path, output_path, score_threshold, do_print=True):
    
    cap = cv2.VideoCapture(input_path)

    codec = cv2.VideoWriter_fourcc(*'XVID')

    vid_size = (round(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    vid_fps = cap.get(cv2.CAP_PROP_FPS)

    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)
    btime = time.time()
    while True:
        hasFrame, img_frame = cap.read()
        if not hasFrame:
            print('더 이상 처리할 frame이 없습니다.')
            break
        stime = time.time()
        img_frame = get_detected_img(model, img_frame,  score_threshold=score_threshold, is_print=False)
        if do_print:
          print('frame별 detection 수행 시간:', round(time.time() - stime, 4))
        vid_writer.write(img_frame)
    # end of while loop

    vid_writer.release()
    cap.release()

    print('최종 detection 완료 수행 시간:', round(time.time() - btime, 4))
do_detected_video(model, '/content/data/the_rock_chase.mp4', '/content/data/the_rock_chase_out1.mp4', score_threshold=0.4, do_print=True)

# 총 Frame 갯수: 503
frame별 detection 수행 시간: 0.1158
frame별 detection 수행 시간: 0.0974
frame별 detection 수행 시간: 0.0929
frame별 detection 수행 시간: 0.102
frame별 detection 수행 시간: 0.1017
frame별 detection 수행 시간: 0.1063
frame별 detection 수행 시간: 0.0948
frame별 detection 수행 시간: 0.1055
frame별 detection 수행 시간: 0.0973
frame별 detection 수행 시간: 0.1025
frame별 detection 수행 시간: 0.096
frame별 detection 수행 시간: 0.0997
frame별 detection 수행 시간: 0.0982
frame별 detection 수행 시간: 0.1127
frame별 detection 수행 시간: 0.0943
frame별 detection 수행 시간: 0.0982
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.0966
frame별 detection 수행 시간: 0.0955
frame별 detection 수행 시간: 0.0945
frame별 detection 수행 시간: 0.0959
frame별 detection 수행 시간: 0.1024
frame별 detection 수행 시간: 0.0985
frame별 detection 수행 시간: 0.095
frame별 detection 수행 시간: 0.1022
frame별 detection 수행 시간: 0.0937
frame별 detection 수행 시간: 0.096
frame별 detection 수행 시간: 0.0951
frame별 detection 수행 시간: 0.0958
frame별 detection 수행 시간: 0.1023
frame별 detection 수행 시간: 0.0971
frame별 detection 수행 시간: 0.0946
frame별 detection 수행 시간: 0.0951
frame별 detection 수행 시간: 0.0938
frame별 detection 수행 시간: 0.0946
frame별 detection 수행 시간: 0.0938
frame별 detection 수행 시간: 0.0965
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.0954
frame별 detection 수행 시간: 0.0955
frame별 detection 수행 시간: 0.0991
frame별 detection 수행 시간: 0.0997
frame별 detection 수행 시간: 0.0964
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0965
frame별 detection 수행 시간: 0.0943
frame별 detection 수행 시간: 0.0968
frame별 detection 수행 시간: 0.0928
frame별 detection 수행 시간: 0.0995
frame별 detection 수행 시간: 0.0998
frame별 detection 수행 시간: 0.0933
frame별 detection 수행 시간: 0.0931
frame별 detection 수행 시간: 0.095
frame별 detection 수행 시간: 0.103
frame별 detection 수행 시간: 0.1082
frame별 detection 수행 시간: 0.091
frame별 detection 수행 시간: 0.0943
frame별 detection 수행 시간: 0.0926
frame별 detection 수행 시간: 0.0929
frame별 detection 수행 시간: 0.092
frame별 detection 수행 시간: 0.094
frame별 detection 수행 시간: 0.0917
frame별 detection 수행 시간: 0.0964
frame별 detection 수행 시간: 0.092
frame별 detection 수행 시간: 0.0937
frame별 detection 수행 시간: 0.0936
frame별 detection 수행 시간: 0.1009
frame별 detection 수행 시간: 0.0951
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.0985
frame별 detection 수행 시간: 0.0968
frame별 detection 수행 시간: 0.092
frame별 detection 수행 시간: 0.0959
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0946
frame별 detection 수행 시간: 0.0926
frame별 detection 수행 시간: 0.0954
frame별 detection 수행 시간: 0.0925
frame별 detection 수행 시간: 0.0987
frame별 detection 수행 시간: 0.0951
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.0927
frame별 detection 수행 시간: 0.0974
frame별 detection 수행 시간: 0.0932
frame별 detection 수행 시간: 0.1043
frame별 detection 수행 시간: 0.0947
frame별 detection 수행 시간: 0.1006
frame별 detection 수행 시간: 0.0955
frame별 detection 수행 시간: 0.1049
frame별 detection 수행 시간: 0.0924
frame별 detection 수행 시간: 0.0951
frame별 detection 수행 시간: 0.0959
frame별 detection 수행 시간: 0.0939
frame별 detection 수행 시간: 0.094
frame별 detection 수행 시간: 0.0949
frame별 detection 수행 시간: 0.0943
frame별 detection 수행 시간: 0.0952
frame별 detection 수행 시간: 0.0974
frame별 detection 수행 시간: 0.1047
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.0977
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.0965
frame별 detection 수행 시간: 0.0927
frame별 detection 수행 시간: 0.0957
frame별 detection 수행 시간: 0.0938
frame별 detection 수행 시간: 0.0997
frame별 detection 수행 시간: 0.0979
frame별 detection 수행 시간: 0.0972
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.0992
frame별 detection 수행 시간: 0.1034
frame별 detection 수행 시간: 0.1029
frame별 detection 수행 시간: 0.0943
frame별 detection 수행 시간: 0.0946
frame별 detection 수행 시간: 0.0934
frame별 detection 수행 시간: 0.0966
frame별 detection 수행 시간: 0.0917
frame별 detection 수행 시간: 0.1
frame별 detection 수행 시간: 0.0979
frame별 detection 수행 시간: 0.0953
frame별 detection 수행 시간: 0.0932
frame별 detection 수행 시간: 0.0946
frame별 detection 수행 시간: 0.0906
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.094
frame별 detection 수행 시간: 0.0969
frame별 detection 수행 시간: 0.0925
frame별 detection 수행 시간: 0.0967
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0934
frame별 detection 수행 시간: 0.0924
frame별 detection 수행 시간: 0.0924
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0965
frame별 detection 수행 시간: 0.1
frame별 detection 수행 시간: 0.092
frame별 detection 수행 시간: 0.0928
frame별 detection 수행 시간: 0.0921
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.092
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0954
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0937
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0961
frame별 detection 수행 시간: 0.0928
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.0905
frame별 detection 수행 시간: 0.0912
frame별 detection 수행 시간: 0.0927
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0958
frame별 detection 수행 시간: 0.0936
frame별 detection 수행 시간: 0.0922
frame별 detection 수행 시간: 0.0926
frame별 detection 수행 시간: 0.0928
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.0954
frame별 detection 수행 시간: 0.0939
frame별 detection 수행 시간: 0.0924
frame별 detection 수행 시간: 0.0951
frame별 detection 수행 시간: 0.0972
frame별 detection 수행 시간: 0.0925
frame별 detection 수행 시간: 0.0948
frame별 detection 수행 시간: 0.0924
frame별 detection 수행 시간: 0.0932
frame별 detection 수행 시간: 0.0925
frame별 detection 수행 시간: 0.09
frame별 detection 수행 시간: 0.097
frame별 detection 수행 시간: 0.0927
frame별 detection 수행 시간: 0.0955
frame별 detection 수행 시간: 0.0926
frame별 detection 수행 시간: 0.0947
frame별 detection 수행 시간: 0.0917
frame별 detection 수행 시간: 0.1029
frame별 detection 수행 시간: 0.0912
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.0921
frame별 detection 수행 시간: 0.0967
frame별 detection 수행 시간: 0.0906
frame별 detection 수행 시간: 0.0945
frame별 detection 수행 시간: 0.0954
frame별 detection 수행 시간: 0.0952
frame별 detection 수행 시간: 0.0904
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.0905
frame별 detection 수행 시간: 0.092
frame별 detection 수행 시간: 0.0902
frame별 detection 수행 시간: 0.0927
frame별 detection 수행 시간: 0.0963
frame별 detection 수행 시간: 0.0989
frame별 detection 수행 시간: 0.0917
frame별 detection 수행 시간: 0.0952
frame별 detection 수행 시간: 0.0965
frame별 detection 수행 시간: 0.0905
frame별 detection 수행 시간: 0.0933
frame별 detection 수행 시간: 0.0906
frame별 detection 수행 시간: 0.0981
frame별 detection 수행 시간: 0.0928
frame별 detection 수행 시간: 0.0951
frame별 detection 수행 시간: 0.0904
frame별 detection 수행 시간: 0.094
frame별 detection 수행 시간: 0.0909
frame별 detection 수행 시간: 0.0961
frame별 detection 수행 시간: 0.0936
frame별 detection 수행 시간: 0.0978
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0939
frame별 detection 수행 시간: 0.0961
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0955
frame별 detection 수행 시간: 0.0954
frame별 detection 수행 시간: 0.0906
frame별 detection 수행 시간: 0.0933
frame별 detection 수행 시간: 0.0939
frame별 detection 수행 시간: 0.0898
frame별 detection 수행 시간: 0.0893
frame별 detection 수행 시간: 0.0923
frame별 detection 수행 시간: 0.0999
frame별 detection 수행 시간: 0.0909
frame별 detection 수행 시간: 0.1059
frame별 detection 수행 시간: 0.0957
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.0931
frame별 detection 수행 시간: 0.1005
frame별 detection 수행 시간: 0.0927
frame별 detection 수행 시간: 0.0943
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0951
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.0967
frame별 detection 수행 시간: 0.0912
frame별 detection 수행 시간: 0.097
frame별 detection 수행 시간: 0.0902
frame별 detection 수행 시간: 0.0934
frame별 detection 수행 시간: 0.0907
frame별 detection 수행 시간: 0.0956
frame별 detection 수행 시간: 0.0933
frame별 detection 수행 시간: 0.0953
frame별 detection 수행 시간: 0.0946
frame별 detection 수행 시간: 0.0965
frame별 detection 수행 시간: 0.0934
frame별 detection 수행 시간: 0.0965
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.0994
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0974
frame별 detection 수행 시간: 0.097
frame별 detection 수행 시간: 0.0927
frame별 detection 수행 시간: 0.0999
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0943
frame별 detection 수행 시간: 0.0939
frame별 detection 수행 시간: 0.0933
frame별 detection 수행 시간: 0.0974
frame별 detection 수행 시간: 0.0938
frame별 detection 수행 시간: 0.1012
frame별 detection 수행 시간: 0.0964
frame별 detection 수행 시간: 0.0978
frame별 detection 수행 시간: 0.0947
frame별 detection 수행 시간: 0.0949
frame별 detection 수행 시간: 0.0926
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0955
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0963
frame별 detection 수행 시간: 0.0936
frame별 detection 수행 시간: 0.096
frame별 detection 수행 시간: 0.1008
frame별 detection 수행 시간: 0.0964
frame별 detection 수행 시간: 0.0937
frame별 detection 수행 시간: 0.0947
frame별 detection 수행 시간: 0.094
frame별 detection 수행 시간: 0.095
frame별 detection 수행 시간: 0.0929
frame별 detection 수행 시간: 0.0951
frame별 detection 수행 시간: 0.0943
frame별 detection 수행 시간: 0.1009
frame별 detection 수행 시간: 0.0948
frame별 detection 수행 시간: 0.0917
frame별 detection 수행 시간: 0.0931
frame별 detection 수행 시간: 0.0954
frame별 detection 수행 시간: 0.0934
frame별 detection 수행 시간: 0.0932
frame별 detection 수행 시간: 0.0961
frame별 detection 수행 시간: 0.0972
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0939
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.1005
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.0954
frame별 detection 수행 시간: 0.0967
frame별 detection 수행 시간: 0.0998
frame별 detection 수행 시간: 0.0939
frame별 detection 수행 시간: 0.0947
frame별 detection 수행 시간: 0.0921
frame별 detection 수행 시간: 0.0945
frame별 detection 수행 시간: 0.0932
frame별 detection 수행 시간: 0.0934
frame별 detection 수행 시간: 0.0913
frame별 detection 수행 시간: 0.0918
frame별 detection 수행 시간: 0.0949
frame별 detection 수행 시간: 0.0956
frame별 detection 수행 시간: 0.0991
frame별 detection 수행 시간: 0.096
frame별 detection 수행 시간: 0.1012
frame별 detection 수행 시간: 0.0939
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.095
frame별 detection 수행 시간: 0.0947
frame별 detection 수행 시간: 0.0949
frame별 detection 수행 시간: 0.0959
frame별 detection 수행 시간: 0.0977
frame별 detection 수행 시간: 0.0962
frame별 detection 수행 시간: 0.1024
frame별 detection 수행 시간: 0.0923
frame별 detection 수행 시간: 0.0971
frame별 detection 수행 시간: 0.0973
frame별 detection 수행 시간: 0.0992
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0991
frame별 detection 수행 시간: 0.0937
frame별 detection 수행 시간: 0.0988
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.0993
frame별 detection 수행 시간: 0.0968
frame별 detection 수행 시간: 0.1021
frame별 detection 수행 시간: 0.0939
frame별 detection 수행 시간: 0.0995
frame별 detection 수행 시간: 0.0964
frame별 detection 수행 시간: 0.1024
frame별 detection 수행 시간: 0.0987
frame별 detection 수행 시간: 0.1017
frame별 detection 수행 시간: 0.0925
frame별 detection 수행 시간: 0.0965
frame별 detection 수행 시간: 0.0926
frame별 detection 수행 시간: 0.1026
frame별 detection 수행 시간: 0.096
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.09
frame별 detection 수행 시간: 0.0969
frame별 detection 수행 시간: 0.0927
frame별 detection 수행 시간: 0.1002
frame별 detection 수행 시간: 0.0901
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0915
frame별 detection 수행 시간: 0.0916
frame별 detection 수행 시간: 0.0924
frame별 detection 수행 시간: 0.0936
frame별 detection 수행 시간: 0.0928
frame별 detection 수행 시간: 0.0996
frame별 detection 수행 시간: 0.0977
frame별 detection 수행 시간: 0.095
frame별 detection 수행 시간: 0.0898
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0925
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.0925
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.0926
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0987
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.0945
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0923
frame별 detection 수행 시간: 0.0902
frame별 detection 수행 시간: 0.0915
frame별 detection 수행 시간: 0.0931
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0948
frame별 detection 수행 시간: 0.0928
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0945
frame별 detection 수행 시간: 0.091
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.0919
frame별 detection 수행 시간: 0.0974
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0985
frame별 detection 수행 시간: 0.0918
frame별 detection 수행 시간: 0.0916
frame별 detection 수행 시간: 0.0901
frame별 detection 수행 시간: 0.0938
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0909
frame별 detection 수행 시간: 0.0931
frame별 detection 수행 시간: 0.1007
frame별 detection 수행 시간: 0.0966
frame별 detection 수행 시간: 0.0917
frame별 detection 수행 시간: 0.0912
frame별 detection 수행 시간: 0.0926
frame별 detection 수행 시간: 0.092
frame별 detection 수행 시간: 0.0937
frame별 detection 수행 시간: 0.0898
frame별 detection 수행 시간: 0.0884
frame별 detection 수행 시간: 0.0916
frame별 detection 수행 시간: 0.0936
frame별 detection 수행 시간: 0.0885
frame별 detection 수행 시간: 0.0902
frame별 detection 수행 시간: 0.089
frame별 detection 수행 시간: 0.0985
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.0959
frame별 detection 수행 시간: 0.0947
frame별 detection 수행 시간: 0.0982
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0959
frame별 detection 수행 시간: 0.0922
frame별 detection 수행 시간: 0.0925
frame별 detection 수행 시간: 0.0932
frame별 detection 수행 시간: 0.0955
frame별 detection 수행 시간: 0.0912
frame별 detection 수행 시간: 0.096
frame별 detection 수행 시간: 0.0933
frame별 detection 수행 시간: 0.1
frame별 detection 수행 시간: 0.0987
frame별 detection 수행 시간: 0.1007
frame별 detection 수행 시간: 0.097
frame별 detection 수행 시간: 0.098
frame별 detection 수행 시간: 0.0934
frame별 detection 수행 시간: 0.0985
frame별 detection 수행 시간: 0.0926
frame별 detection 수행 시간: 0.0973
frame별 detection 수행 시간: 0.0918
frame별 detection 수행 시간: 0.0914
frame별 detection 수행 시간: 0.0931
frame별 detection 수행 시간: 0.0991
frame별 detection 수행 시간: 0.0922
frame별 detection 수행 시간: 0.095
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0954
frame별 detection 수행 시간: 0.0908
frame별 detection 수행 시간: 0.0938
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0921
frame별 detection 수행 시간: 0.0967
frame별 detection 수행 시간: 0.0933
frame별 detection 수행 시간: 0.0896
frame별 detection 수행 시간: 0.0989
frame별 detection 수행 시간: 0.092
frame별 detection 수행 시간: 0.097
frame별 detection 수행 시간: 0.0936
frame별 detection 수행 시간: 0.0992
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0937
frame별 detection 수행 시간: 0.0952
frame별 detection 수행 시간: 0.0937
frame별 detection 수행 시간: 0.0906
frame별 detection 수행 시간: 0.1034
frame별 detection 수행 시간: 0.0936
frame별 detection 수행 시간: 0.0929
frame별 detection 수행 시간: 0.09
frame별 detection 수행 시간: 0.0968
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0939
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.0921
frame별 detection 수행 시간: 0.0952
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.0943
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.095
frame별 detection 수행 시간: 0.0945
frame별 detection 수행 시간: 0.0929
frame별 detection 수행 시간: 0.0965
frame별 detection 수행 시간: 0.0962
frame별 detection 수행 시간: 0.0951
frame별 detection 수행 시간: 0.0935
frame별 detection 수행 시간: 0.0958
frame별 detection 수행 시간: 0.0943
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0979
frame별 detection 수행 시간: 0.093
frame별 detection 수행 시간: 0.0941
frame별 detection 수행 시간: 0.0983
frame별 detection 수행 시간: 0.0967
frame별 detection 수행 시간: 0.0925
frame별 detection 수행 시간: 0.0944
frame별 detection 수행 시간: 0.0933
frame별 detection 수행 시간: 0.0942
frame별 detection 수행 시간: 0.0961
frame별 detection 수행 시간: 0.1017
frame별 detection 수행 시간: 0.096
frame별 detection 수행 시간: 0.0971
frame별 detection 수행 시간: 0.0948
frame별 detection 수행 시간: 0.095
frame별 detection 수행 시간: 0.0933
frame별 detection 수행 시간: 0.0952
frame별 detection 수행 시간: 0.0907
더 이상 처리할 frame이 없습니다.
최종 detection 완료 수행 시간: 53.1923

 

 

 

 

 

반응형
728x90
반응형

kitti Dataset을 중립 데이터형태로 변환하여 메모리 로드

# 원본 kitti Dataset는 10개의 Class로 되어 있음. 'Car Van Truck Pedestrian Person_sitting Cyclist Tram Misc DontCare'
CLASSES = ('Car', 'Truck', 'Pedestrian', 'Cyclist')
cat2label = {k:i for i, k in enumerate(CLASSES)}
print(cat2label)
cat2label['Car']

# {'Car': 0, 'Truck': 1, 'Pedestrian': 2, 'Cyclist': 3}
# 0
# data_anno {label}에 넣기 위한것
image_list = mmcv.list_from_file('/content/kitti_tiny/train.txt')

lines = mmcv.list_from_file('/content/kitti_tiny/training/label_2/000064.txt')
#print(lines)
content = [line.strip().split(' ') for line in lines]
bbox_names = [x[0] for x in content]
#print(bbox_names)
# bounding box 읽기
bboxes = [ [float(info) for info in x[4:8]] for x in content]
print(bboxes)

# [[657.65, 179.93, 709.86, 219.92], [731.51, 180.39, 882.28, 275.8], [715.18, 175.63, 762.77, 203.9], [816.58, 59.74, 1112.51, 266.07], [626.78, 174.27, 647.77, 192.18], [546.19, 168.97, 554.01, 177.09]]
import copy
import os.path as osp
import cv2

import mmcv
import numpy as np

from mmdet.datasets.builder import DATASETS
from mmdet.datasets.custom import CustomDataset

# 반드시 아래 Decorator 설정 할것.@DATASETS.register_module() 설정 시 force=True를 입력하지 않으면 Dataset 재등록 불가. 
@DATASETS.register_module(force=True)
class KittyTinyDataset(CustomDataset):
  CLASSES = ('Car', 'Truck', 'Pedestrian', 'Cyclist')
  # __init__ 가 없는것은 customdataset것을 이용
  ##### self.data_root: /content/kitti_tiny/ self.ann_file: /content/kitti_tiny/train.txt self.img_prefix: /content/kitti_tiny/training/image_2
  #### ann_file: /content/kitti_tiny/train.txt
  # annotation에 대한 모든 파일명을 가지고 있는 텍스트 파일을 __init__(self, ann_file)로 입력 받고, 이 self.ann_file이 load_annotations()의 인자로 입력
  def load_annotations(self, ann_file):
    print('##### self.data_root:', self.data_root, 'self.ann_file:', self.ann_file, 'self.img_prefix:', self.img_prefix)
    print('#### ann_file:', ann_file)
    cat2label = {k:i for i, k in enumerate(self.CLASSES)}
    image_list = mmcv.list_from_file(self.ann_file)
    # 포맷 중립 데이터를 담을 list 객체
    data_infos = []
    
    for image_id in image_list: # 000000
      filename = '{0:}/{1:}.jpeg'.format(self.img_prefix, image_id)
      # 원본 이미지의 너비, 높이를 image를 직접 로드하여 구함. 
      image = cv2.imread(filename)
      height, width = image.shape[:2]
      # 개별 image의 annotation 정보 저장용 Dict 생성. key값 filename 에는 image의 파일명만 들어감(디렉토리는 제외)
      data_info = {'filename': str(image_id) + '.jpeg',
                   'width': width, 'height': height}
      # 개별 annotation이 있는 서브 디렉토리의 prefix 변환. 
      label_prefix = self.img_prefix.replace('image_2', 'label_2')
      # 개별 annotation 파일을 1개 line 씩 읽어서 list 로드 
      lines = mmcv.list_from_file(osp.join(label_prefix, str(image_id)+'.txt'))

      # 전체 lines를 개별 line별 공백 레벨로 parsing 하여 다시 list로 저장. content는 list의 list형태임.
      # ann 정보는 numpy array로 저장되나 텍스트 처리나 데이터 가공이 list 가 편하므로 일차적으로 list로 변환 수행.   
      content = [line.strip().split(' ') for line in lines]
      # 오브젝트의 클래스명은 bbox_names로 저장. 
      bbox_names = [x[0] for x in content]
      # bbox 좌표를 저장
      bboxes = [ [float(info) for info in x[4:8]] for x in content]

      # 클래스명이 해당 사항이 없는 대상 Filtering out, 'DontCare'sms ignore로 별도 저장.
      gt_bboxes = []
      gt_labels = []
      gt_bboxes_ignore = []
      gt_labels_ignore = []
	  
      # 파일 내용을 읽는 loop
      for bbox_name, bbox in zip(bbox_names, bboxes):
        # 만약 bbox_name이 클래스명에 해당 되면, gt_bboxes와 gt_labels에 추가, 그렇지 않으면 gt_bboxes_ignore, gt_labels_ignore에 추가
        if bbox_name in cat2label:
          gt_bboxes.append(bbox)
          # gt_labels에는 class id를 입력
          gt_labels.append(cat2label[bbox_name])
        else:
          gt_bboxes_ignore.append(bbox)
          gt_labels_ignore.append(-1)
      # 개별 image별 annotation 정보를 가지는 Dict 생성. 해당 Dict의 value값은 모두 np.array임. 
      data_anno = {
          'bboxes': np.array(gt_bboxes, dtype=np.float32).reshape(-1, 4),
          'labels': np.array(gt_labels, dtype=np.long),
          'bboxes_ignore': np.array(gt_bboxes_ignore, dtype=np.float32).reshape(-1, 4),
          'labels_ignore': np.array(gt_labels_ignore, dtype=np.long)
      }
      # image에 대한 메타 정보를 가지는 data_info Dict에 'ann' key값으로 data_anno를 value로 저장. 
      data_info.update(ann=data_anno)
      # 전체 annotation 파일들에 대한 정보를 가지는 data_infos에 data_info Dict를 추가
      data_infos.append(data_info)

    return data_infos

 

### Config 설정하고 Pretrained 모델 다운로드
config_file = '/content/mmdetection/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py'
checkpoint_file = '/content/mmdetection/checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
!cd mmdetection; mkdir checkpoints
!wget -O /content/mmdetection/checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth

 

from mmcv import Config

cfg = Config.fromfile(config_file)
print(cfg.pretty_text)

# model = dict(
    type='FasterRCNN',
    pretrained='torchvision://resnet50',
    backbone=dict(
        type='ResNet',
        depth=50,
        num_stages=4,
        out_indices=(0, 1, 2, 3),
        frozen_stages=1,
        norm_cfg=dict(type='BN', requires_grad=True),
        norm_eval=True,
        style='pytorch'),
    neck=dict(
        type='FPN',
        in_channels=[256, 512, 1024, 2048],
        out_channels=256,
        num_outs=5),
    rpn_head=dict(
        type='RPNHead',
        in_channels=256,
        feat_channels=256,
        anchor_generator=dict(
            type='AnchorGenerator',
            scales=[8],
            ratios=[0.5, 1.0, 2.0],
            strides=[4, 8, 16, 32, 64]),
        bbox_coder=dict(
            type='DeltaXYWHBBoxCoder',
            target_means=[0.0, 0.0, 0.0, 0.0],
            target_stds=[1.0, 1.0, 1.0, 1.0]),
        loss_cls=dict(
            type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
        loss_bbox=dict(type='L1Loss', loss_weight=1.0)),
    roi_head=dict(
        type='StandardRoIHead',
        bbox_roi_extractor=dict(
            type='SingleRoIExtractor',
            roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0),
            out_channels=256,
            featmap_strides=[4, 8, 16, 32]),
        bbox_head=dict(
            type='Shared2FCBBoxHead',
            in_channels=256,
            fc_out_channels=1024,
            roi_feat_size=7,
            num_classes=80,
            bbox_coder=dict(
                type='DeltaXYWHBBoxCoder',
                target_means=[0.0, 0.0, 0.0, 0.0],
                target_stds=[0.1, 0.1, 0.2, 0.2]),
            reg_class_agnostic=False,
            loss_cls=dict(
                type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0),
            loss_bbox=dict(type='L1Loss', loss_weight=1.0))),
    train_cfg=dict(
        rpn=dict(
            assigner=dict(
                type='MaxIoUAssigner',
                pos_iou_thr=0.7,
                neg_iou_thr=0.3,
                min_pos_iou=0.3,
                match_low_quality=True,
                ignore_iof_thr=-1),
            sampler=dict(
                type='RandomSampler',
                num=256,
                pos_fraction=0.5,
                neg_pos_ub=-1,
                add_gt_as_proposals=False),
            allowed_border=-1,
            pos_weight=-1,
            debug=False),
        rpn_proposal=dict(
            nms_pre=2000,
            max_per_img=1000,
            nms=dict(type='nms', iou_threshold=0.7),
            min_bbox_size=0),
        rcnn=dict(
            assigner=dict(
                type='MaxIoUAssigner',
                pos_iou_thr=0.5,
                neg_iou_thr=0.5,
                min_pos_iou=0.5,
                match_low_quality=False,
                ignore_iof_thr=-1),
            sampler=dict(
                type='RandomSampler',
                num=512,
                pos_fraction=0.25,
                neg_pos_ub=-1,
                add_gt_as_proposals=True),
            pos_weight=-1,
            debug=False)),
    test_cfg=dict(
        rpn=dict(
            nms_pre=1000,
            max_per_img=1000,
            nms=dict(type='nms', iou_threshold=0.7),
            min_bbox_size=0),
        rcnn=dict(
            score_thr=0.05,
            nms=dict(type='nms', iou_threshold=0.5),
            max_per_img=100)))
dataset_type = 'CocoDataset'
data_root = 'data/coco/'
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='LoadAnnotations', with_bbox=True),
    dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
    dict(type='RandomFlip', flip_ratio=0.5),
    dict(
        type='Normalize',
        mean=[123.675, 116.28, 103.53],
        std=[58.395, 57.12, 57.375],
        to_rgb=True),
    dict(type='Pad', size_divisor=32),
    dict(type='DefaultFormatBundle'),
    dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])
]
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(
        type='MultiScaleFlipAug',
        img_scale=(1333, 800),
        flip=False,
        transforms=[
            dict(type='Resize', keep_ratio=True),
            dict(type='RandomFlip'),
            dict(
                type='Normalize',
                mean=[123.675, 116.28, 103.53],
                std=[58.395, 57.12, 57.375],
                to_rgb=True),
            dict(type='Pad', size_divisor=32),
            dict(type='ImageToTensor', keys=['img']),
            dict(type='Collect', keys=['img'])
        ])
]
data = dict(
    samples_per_gpu=2,
    workers_per_gpu=2,
    train=dict(
        type='CocoDataset',
        ann_file='data/coco/annotations/instances_train2017.json',
        img_prefix='data/coco/train2017/',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(type='LoadAnnotations', with_bbox=True),
            dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
            dict(type='RandomFlip', flip_ratio=0.5),
            dict(
                type='Normalize',
                mean=[123.675, 116.28, 103.53],
                std=[58.395, 57.12, 57.375],
                to_rgb=True),
            dict(type='Pad', size_divisor=32),
            dict(type='DefaultFormatBundle'),
            dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])
        ]),
    val=dict(
        type='CocoDataset',
        ann_file='data/coco/annotations/instances_val2017.json',
        img_prefix='data/coco/val2017/',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(
                type='MultiScaleFlipAug',
                img_scale=(1333, 800),
                flip=False,
                transforms=[
                    dict(type='Resize', keep_ratio=True),
                    dict(type='RandomFlip'),
                    dict(
                        type='Normalize',
                        mean=[123.675, 116.28, 103.53],
                        std=[58.395, 57.12, 57.375],
                        to_rgb=True),
                    dict(type='Pad', size_divisor=32),
                    dict(type='ImageToTensor', keys=['img']),
                    dict(type='Collect', keys=['img'])
                ])
        ]),
    test=dict(
        type='CocoDataset',
        ann_file='data/coco/annotations/instances_val2017.json',
        img_prefix='data/coco/val2017/',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(
                type='MultiScaleFlipAug',
                img_scale=(1333, 800),
                flip=False,
                transforms=[
                    dict(type='Resize', keep_ratio=True),
                    dict(type='RandomFlip'),
                    dict(
                        type='Normalize',
                        mean=[123.675, 116.28, 103.53],
                        std=[58.395, 57.12, 57.375],
                        to_rgb=True),
                    dict(type='Pad', size_divisor=32),
                    dict(type='ImageToTensor', keys=['img']),
                    dict(type='Collect', keys=['img'])
                ])
        ]))
evaluation = dict(interval=1, metric='bbox')
optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001)
optimizer_config = dict(grad_clip=None)
lr_config = dict(
    policy='step',
    warmup='linear',
    warmup_iters=500,
    warmup_ratio=0.001,
    step=[8, 11])
runner = dict(type='EpochBasedRunner', max_epochs=12)
checkpoint_config = dict(interval=1)
log_config = dict(interval=50, hooks=[dict(type='TextLoggerHook')])
custom_hooks = [dict(type='NumClassCheckHook')]
dist_params = dict(backend='nccl')
log_level = 'INFO'
load_from = None
resume_from = None
workflow = [('train', 1)]

 

from mmdet.apis import set_random_seed

# dataset에 대한 환경 파라미터 수정. 
cfg.dataset_type = 'KittyTinyDataset'
cfg.data_root = '/content/kitti_tiny/'

# train, val, test dataset에 대한 type, data_root, ann_file, img_prefix 환경 파라미터 수정. 
cfg.data.train.type = 'KittyTinyDataset'
cfg.data.train.data_root = '/content/kitti_tiny/'
cfg.data.train.ann_file = 'train.txt'
cfg.data.train.img_prefix = 'training/image_2'

cfg.data.val.type = 'KittyTinyDataset'
cfg.data.val.data_root = '/content/kitti_tiny/'
cfg.data.val.ann_file = 'val.txt'
cfg.data.val.img_prefix = 'training/image_2'

cfg.data.test.type = 'KittyTinyDataset'
cfg.data.test.data_root = '/content/kitti_tiny/'
cfg.data.test.ann_file = 'val.txt'
cfg.data.test.img_prefix = 'training/image_2'

# class의 갯수 수정. 
cfg.model.roi_head.bbox_head.num_classes = 4
# pretrained 모델
cfg.load_from = 'checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'

# 학습 weight 파일로 로그를 저장하기 위한 디렉토리 설정. 
cfg.work_dir = './tutorial_exps'

# 학습율 변경 환경 파라미터 설정. 
cfg.optimizer.lr = 0.02 / 8

cfg.lr_config.warmup = None
cfg.log_config.interval = 10

# config 수행 시마다 policy값이 없어지는 bug로 인하여 설정. 
cfg.lr_config.policy = 'step'

# Change the evaluation metric since we use customized dataset.
cfg.evaluation.metric = 'mAP'
# We can set the evaluation interval to reduce the evaluation times
cfg.evaluation.interval = 12
# We can set the checkpoint saving interval to reduce the storage cost
cfg.checkpoint_config.interval = 12

# Set seed thus the results are more reproducible
cfg.seed = 0
set_random_seed(0, deterministic=False)
cfg.gpu_ids = range(1)


# We can initialize the logger for training and have a look
# at the final config used for training
print(f'Config:\n{cfg.pretty_text}')



# Config:
model = dict(
    type='FasterRCNN',
    pretrained='torchvision://resnet50',
    backbone=dict(
        type='ResNet',
        depth=50,
        num_stages=4,
        out_indices=(0, 1, 2, 3),
        frozen_stages=1,
        norm_cfg=dict(type='BN', requires_grad=True),
        norm_eval=True,
        style='pytorch',
        pretrained='torchvision://resnet50'),
    neck=dict(
        type='FPN',
        in_channels=[256, 512, 1024, 2048],
        out_channels=256,
        num_outs=5),
    rpn_head=dict(
        type='RPNHead',
        in_channels=256,
        feat_channels=256,
        anchor_generator=dict(
            type='AnchorGenerator',
            scales=[8],
            ratios=[0.5, 1.0, 2.0],
            strides=[4, 8, 16, 32, 64]),
        bbox_coder=dict(
            type='DeltaXYWHBBoxCoder',
            target_means=[0.0, 0.0, 0.0, 0.0],
            target_stds=[1.0, 1.0, 1.0, 1.0]),
        loss_cls=dict(
            type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
        loss_bbox=dict(type='L1Loss', loss_weight=1.0)),
    roi_head=dict(
        type='StandardRoIHead',
        bbox_roi_extractor=dict(
            type='SingleRoIExtractor',
            roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0),
            out_channels=256,
            featmap_strides=[4, 8, 16, 32]),
        bbox_head=dict(
            type='Shared2FCBBoxHead',
            in_channels=256,
            fc_out_channels=1024,
            roi_feat_size=7,
            num_classes=4,
            bbox_coder=dict(
                type='DeltaXYWHBBoxCoder',
                target_means=[0.0, 0.0, 0.0, 0.0],
                target_stds=[0.1, 0.1, 0.2, 0.2]),
            reg_class_agnostic=False,
            loss_cls=dict(
                type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0),
            loss_bbox=dict(type='L1Loss', loss_weight=1.0)),
        train_cfg=dict(
            assigner=dict(
                type='MaxIoUAssigner',
                pos_iou_thr=0.5,
                neg_iou_thr=0.5,
                min_pos_iou=0.5,
                match_low_quality=False,
                ignore_iof_thr=-1),
            sampler=dict(
                type='RandomSampler',
                num=512,
                pos_fraction=0.25,
                neg_pos_ub=-1,
                add_gt_as_proposals=True),
            pos_weight=-1,
            debug=False),
        test_cfg=dict(
            score_thr=0.05,
            nms=dict(type='nms', iou_threshold=0.5),
            max_per_img=100),
        pretrained='torchvision://resnet50'),
    train_cfg=dict(
        rpn=dict(
            assigner=dict(
                type='MaxIoUAssigner',
                pos_iou_thr=0.7,
                neg_iou_thr=0.3,
                min_pos_iou=0.3,
                match_low_quality=True,
                ignore_iof_thr=-1),
            sampler=dict(
                type='RandomSampler',
                num=256,
                pos_fraction=0.5,
                neg_pos_ub=-1,
                add_gt_as_proposals=False),
            allowed_border=-1,
            pos_weight=-1,
            debug=False),
        rpn_proposal=dict(
            nms_pre=2000,
            max_per_img=1000,
            nms=dict(type='nms', iou_threshold=0.7),
            min_bbox_size=0),
        rcnn=dict(
            assigner=dict(
                type='MaxIoUAssigner',
                pos_iou_thr=0.5,
                neg_iou_thr=0.5,
                min_pos_iou=0.5,
                match_low_quality=False,
                ignore_iof_thr=-1),
            sampler=dict(
                type='RandomSampler',
                num=512,
                pos_fraction=0.25,
                neg_pos_ub=-1,
                add_gt_as_proposals=True),
            pos_weight=-1,
            debug=False)),
    test_cfg=dict(
        rpn=dict(
            nms_pre=1000,
            max_per_img=1000,
            nms=dict(type='nms', iou_threshold=0.7),
            min_bbox_size=0),
        rcnn=dict(
            score_thr=0.05,
            nms=dict(type='nms', iou_threshold=0.5),
            max_per_img=100)))
dataset_type = 'KittyTinyDataset'
data_root = '/content/kitti_tiny/'
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='LoadAnnotations', with_bbox=True),
    dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
    dict(type='RandomFlip', flip_ratio=0.5),
    dict(
        type='Normalize',
        mean=[123.675, 116.28, 103.53],
        std=[58.395, 57.12, 57.375],
        to_rgb=True),
    dict(type='Pad', size_divisor=32),
    dict(type='DefaultFormatBundle'),
    dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])
]
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(
        type='MultiScaleFlipAug',
        img_scale=(1333, 800),
        flip=False,
        transforms=[
            dict(type='Resize', keep_ratio=True),
            dict(type='RandomFlip'),
            dict(
                type='Normalize',
                mean=[123.675, 116.28, 103.53],
                std=[58.395, 57.12, 57.375],
                to_rgb=True),
            dict(type='Pad', size_divisor=32),
            dict(type='ImageToTensor', keys=['img']),
            dict(type='Collect', keys=['img'])
        ])
]
data = dict(
    samples_per_gpu=2,
    workers_per_gpu=2,
    train=dict(
        type='KittyTinyDataset',
        ann_file='train.txt',
        img_prefix='training/image_2',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(type='LoadAnnotations', with_bbox=True),
            dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
            dict(type='RandomFlip', flip_ratio=0.5),
            dict(
                type='Normalize',
                mean=[123.675, 116.28, 103.53],
                std=[58.395, 57.12, 57.375],
                to_rgb=True),
            dict(type='Pad', size_divisor=32),
            dict(type='DefaultFormatBundle'),
            dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])
        ],
        data_root='/content/kitti_tiny/'),
    val=dict(
        type='KittyTinyDataset',
        ann_file='val.txt',
        img_prefix='training/image_2',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(
                type='MultiScaleFlipAug',
                img_scale=(1333, 800),
                flip=False,
                transforms=[
                    dict(type='Resize', keep_ratio=True),
                    dict(type='RandomFlip'),
                    dict(
                        type='Normalize',
                        mean=[123.675, 116.28, 103.53],
                        std=[58.395, 57.12, 57.375],
                        to_rgb=True),
                    dict(type='Pad', size_divisor=32),
                    dict(type='ImageToTensor', keys=['img']),
                    dict(type='Collect', keys=['img'])
                ])
        ],
        data_root='/content/kitti_tiny/'),
    test=dict(
        type='KittyTinyDataset',
        ann_file='val.txt',
        img_prefix='training/image_2',
        pipeline=[
            dict(type='LoadImageFromWebcam'),
            dict(
                type='MultiScaleFlipAug',
                img_scale=(1333, 800),
                flip=False,
                transforms=[
                    dict(type='Resize', keep_ratio=True),
                    dict(type='RandomFlip'),
                    dict(
                        type='Normalize',
                        mean=[123.675, 116.28, 103.53],
                        std=[58.395, 57.12, 57.375],
                        to_rgb=True),
                    dict(type='Pad', size_divisor=32),
                    dict(type='DefaultFormatBundle'),
                    dict(type='Collect', keys=['img'])
                ])
        ],
        data_root='/content/kitti_tiny/'))
evaluation = dict(interval=12, metric='mAP', by_epoch=True)
optimizer = dict(type='SGD', lr=0.0025, momentum=0.9, weight_decay=0.0001)
optimizer_config = dict(grad_clip=None, type='OptimizerHook')
lr_config = dict(
    warmup=None,
    warmup_iters=500,
    warmup_ratio=0.001,
    step=[8, 11],
    type='StepLrUpdaterHook',
    policy='step')
runner = dict(type='EpochBasedRunner', max_epochs=12)
checkpoint_config = dict(interval=12, type='CheckpointHook')
log_config = dict(interval=10, hooks=[dict(type='TextLoggerHook')])
custom_hooks = [dict(type='NumClassCheckHook')]
dist_params = dict(backend='nccl')
log_level = 'INFO'
load_from = 'checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
resume_from = None
workflow = [('train', 1)]
work_dir = './tutorial_exps'
seed = 0
gpu_ids = range(0, 1)

Config에서 설정한 Dataset과 Model, 동적 학습율, Pipeline 설정에 따라 모델 학습 수행.

  • train용 Dataset을 생성하고 이를 이용하여 학습 수행.
from mmdet.datasets import build_dataset
from mmdet.models import build_detector
from mmdet.apis import train_detector

# train용 Dataset 생성. 
datasets = [build_dataset(cfg.data.train)]
datasets

# [
#  KittyTinyDataset Train dataset with number of images 50, and instance counts: 
#  +----------+-------+-----------+-------+----------------+-------+-------------+-------+---------------+-------+
#  | category | count | category  | count | category       | count | category    | count | category      | count |
#  +----------+-------+-----------+-------+----------------+-------+-------------+-------+---------------+-------+
#  | 0 [Car]  | 147   | 1 [Truck] | 7     | 2 [Pedestrian] | 23    | 3 [Cyclist] | 7     | -1 background | 0     |
#  +----------+-------+-----------+-------+----------------+-------+-------------+-------+---------------+-------+]
datasets[0].CLASSES
# ('Car', 'Truck', 'Pedestrian', 'Cyclist')
model = build_detector(cfg.model, train_cfg=cfg.get('train_cfg'), test_cfg=cfg.get('test_cfg'))
model.CLASSES = datasets[0].CLASSES

# /usr/local/lib/python3.7/dist-packages/mmdet-2.12.0-py3.7.egg/mmdet/models/backbones/resnet.py:400: UserWarning: DeprecationWarning: pretrained is a deprecated, please use "init_cfg" instead
#  warnings.warn('DeprecationWarning: pretrained is a deprecated, '
# 주의, config에 pretrained 모델 지정이 상대 경로로 설정됨 cfg.load_from = 'checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
# 아래와 같이 %cd mmdetection 지정 필요. 
 
%cd mmdetection 

mmcv.mkdir_or_exist(osp.abspath(cfg.work_dir))
# epochs는 config의 runner 파라미터로 지정됨. 기본 12회 
train_detector(model, datasets, cfg, distributed=False, validate=True)



/content/mmdetection
2021-05-27 02:01:03,488 - mmdet - INFO - load checkpoint from checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
2021-05-27 02:01:03,489 - mmdet - INFO - Use load_from_local loader
##### self.data_root: /content/kitti_tiny/ self.ann_file: /content/kitti_tiny/val.txt self.img_prefix: /content/kitti_tiny/training/image_2
#### ann_file: /content/kitti_tiny/val.txt
2021-05-27 02:01:03,630 - mmdet - WARNING - The model and loaded state dict do not match exactly

size mismatch for roi_head.bbox_head.fc_cls.weight: copying a param with shape torch.Size([81, 1024]) from checkpoint, the shape in current model is torch.Size([5, 1024]).
size mismatch for roi_head.bbox_head.fc_cls.bias: copying a param with shape torch.Size([81]) from checkpoint, the shape in current model is torch.Size([5]).
size mismatch for roi_head.bbox_head.fc_reg.weight: copying a param with shape torch.Size([320, 1024]) from checkpoint, the shape in current model is torch.Size([16, 1024]).
size mismatch for roi_head.bbox_head.fc_reg.bias: copying a param with shape torch.Size([320]) from checkpoint, the shape in current model is torch.Size([16]).
2021-05-27 02:01:03,639 - mmdet - INFO - Start running, host: root@d7fd648a5af0, work_dir: /content/mmdetection/tutorial_exps
2021-05-27 02:01:03,640 - mmdet - INFO - workflow: [('train', 1)], max: 12 epochs
2021-05-27 02:01:08,457 - mmdet - INFO - Epoch [1][10/25]	lr: 2.500e-03, eta: 0:02:18, time: 0.476, data_time: 0.229, memory: 2226, loss_rpn_cls: 0.0275, loss_rpn_bbox: 0.0179, loss_cls: 0.7554, acc: 73.3594, loss_bbox: 0.4131, loss: 1.2139
2021-05-27 02:01:10,877 - mmdet - INFO - Epoch [1][20/25]	lr: 2.500e-03, eta: 0:01:40, time: 0.242, data_time: 0.012, memory: 2226, loss_rpn_cls: 0.0178, loss_rpn_bbox: 0.0128, loss_cls: 0.2395, acc: 92.2559, loss_bbox: 0.3446, loss: 0.6147
2021-05-27 02:01:16,800 - mmdet - INFO - Epoch [2][10/25]	lr: 2.500e-03, eta: 0:01:29, time: 0.464, data_time: 0.228, memory: 2226, loss_rpn_cls: 0.0151, loss_rpn_bbox: 0.0156, loss_cls: 0.2097, acc: 93.5547, loss_bbox: 0.3205, loss: 0.5609
2021-05-27 02:01:19,231 - mmdet - INFO - Epoch [2][20/25]	lr: 2.500e-03, eta: 0:01:20, time: 0.243, data_time: 0.012, memory: 2226, loss_rpn_cls: 0.0133, loss_rpn_bbox: 0.0131, loss_cls: 0.1617, acc: 94.0332, loss_bbox: 0.2242, loss: 0.4123
2021-05-27 02:01:25,113 - mmdet - INFO - Epoch [3][10/25]	lr: 2.500e-03, eta: 0:01:15, time: 0.462, data_time: 0.227, memory: 2226, loss_rpn_cls: 0.0048, loss_rpn_bbox: 0.0117, loss_cls: 0.1387, acc: 95.1465, loss_bbox: 0.1990, loss: 0.3543
2021-05-27 02:01:27,568 - mmdet - INFO - Epoch [3][20/25]	lr: 2.500e-03, eta: 0:01:10, time: 0.246, data_time: 0.012, memory: 2226, loss_rpn_cls: 0.0069, loss_rpn_bbox: 0.0125, loss_cls: 0.1741, acc: 93.4863, loss_bbox: 0.2716, loss: 0.4651
2021-05-27 02:01:33,510 - mmdet - INFO - Epoch [4][10/25]	lr: 2.500e-03, eta: 0:01:05, time: 0.466, data_time: 0.225, memory: 2226, loss_rpn_cls: 0.0071, loss_rpn_bbox: 0.0151, loss_cls: 0.1503, acc: 94.2578, loss_bbox: 0.2479, loss: 0.4204
2021-05-27 02:01:35,960 - mmdet - INFO - Epoch [4][20/25]	lr: 2.500e-03, eta: 0:01:01, time: 0.245, data_time: 0.013, memory: 2226, loss_rpn_cls: 0.0028, loss_rpn_bbox: 0.0123, loss_cls: 0.1339, acc: 95.1172, loss_bbox: 0.2092, loss: 0.3582
2021-05-27 02:01:41,874 - mmdet - INFO - Epoch [5][10/25]	lr: 2.500e-03, eta: 0:00:57, time: 0.466, data_time: 0.226, memory: 2226, loss_rpn_cls: 0.0038, loss_rpn_bbox: 0.0100, loss_cls: 0.1278, acc: 94.9512, loss_bbox: 0.2143, loss: 0.3559
2021-05-27 02:01:44,334 - mmdet - INFO - Epoch [5][20/25]	lr: 2.500e-03, eta: 0:00:53, time: 0.246, data_time: 0.012, memory: 2226, loss_rpn_cls: 0.0071, loss_rpn_bbox: 0.0119, loss_cls: 0.1317, acc: 94.7852, loss_bbox: 0.2035, loss: 0.3542
2021-05-27 02:01:50,296 - mmdet - INFO - Epoch [6][10/25]	lr: 2.500e-03, eta: 0:00:49, time: 0.467, data_time: 0.228, memory: 2226, loss_rpn_cls: 0.0014, loss_rpn_bbox: 0.0094, loss_cls: 0.1039, acc: 96.0059, loss_bbox: 0.1820, loss: 0.2968
2021-05-27 02:01:52,762 - mmdet - INFO - Epoch [6][20/25]	lr: 2.500e-03, eta: 0:00:45, time: 0.247, data_time: 0.012, memory: 2226, loss_rpn_cls: 0.0039, loss_rpn_bbox: 0.0104, loss_cls: 0.1045, acc: 96.0840, loss_bbox: 0.1877, loss: 0.3065
2021-05-27 02:01:58,690 - mmdet - INFO - Epoch [7][10/25]	lr: 2.500e-03, eta: 0:00:41, time: 0.465, data_time: 0.225, memory: 2226, loss_rpn_cls: 0.0019, loss_rpn_bbox: 0.0106, loss_cls: 0.1018, acc: 96.2402, loss_bbox: 0.1835, loss: 0.2978
2021-05-27 02:02:01,159 - mmdet - INFO - Epoch [7][20/25]	lr: 2.500e-03, eta: 0:00:38, time: 0.247, data_time: 0.011, memory: 2226, loss_rpn_cls: 0.0039, loss_rpn_bbox: 0.0125, loss_cls: 0.0970, acc: 96.2500, loss_bbox: 0.1859, loss: 0.2993
2021-05-27 02:02:07,094 - mmdet - INFO - Epoch [8][10/25]	lr: 2.500e-03, eta: 0:00:33, time: 0.464, data_time: 0.225, memory: 2226, loss_rpn_cls: 0.0029, loss_rpn_bbox: 0.0088, loss_cls: 0.0875, acc: 96.6309, loss_bbox: 0.1584, loss: 0.2575
2021-05-27 02:02:09,550 - mmdet - INFO - Epoch [8][20/25]	lr: 2.500e-03, eta: 0:00:30, time: 0.246, data_time: 0.012, memory: 2226, loss_rpn_cls: 0.0020, loss_rpn_bbox: 0.0089, loss_cls: 0.0976, acc: 96.4160, loss_bbox: 0.1765, loss: 0.2850
2021-05-27 02:02:15,504 - mmdet - INFO - Epoch [9][10/25]	lr: 2.500e-04, eta: 0:00:26, time: 0.466, data_time: 0.225, memory: 2226, loss_rpn_cls: 0.0029, loss_rpn_bbox: 0.0093, loss_cls: 0.0829, acc: 96.8457, loss_bbox: 0.1472, loss: 0.2423
2021-05-27 02:02:17,968 - mmdet - INFO - Epoch [9][20/25]	lr: 2.500e-04, eta: 0:00:23, time: 0.246, data_time: 0.013, memory: 2226, loss_rpn_cls: 0.0012, loss_rpn_bbox: 0.0071, loss_cls: 0.0760, acc: 97.2168, loss_bbox: 0.1358, loss: 0.2201
2021-05-27 02:02:23,924 - mmdet - INFO - Epoch [10][10/25]	lr: 2.500e-04, eta: 0:00:19, time: 0.466, data_time: 0.226, memory: 2226, loss_rpn_cls: 0.0027, loss_rpn_bbox: 0.0095, loss_cls: 0.0899, acc: 96.4160, loss_bbox: 0.1554, loss: 0.2575
2021-05-27 02:02:26,391 - mmdet - INFO - Epoch [10][20/25]	lr: 2.500e-04, eta: 0:00:15, time: 0.247, data_time: 0.012, memory: 2226, loss_rpn_cls: 0.0013, loss_rpn_bbox: 0.0064, loss_cls: 0.0731, acc: 97.2168, loss_bbox: 0.1324, loss: 0.2132
2021-05-27 02:02:32,334 - mmdet - INFO - Epoch [11][10/25]	lr: 2.500e-04, eta: 0:00:11, time: 0.465, data_time: 0.225, memory: 2226, loss_rpn_cls: 0.0037, loss_rpn_bbox: 0.0084, loss_cls: 0.0911, acc: 96.3965, loss_bbox: 0.1458, loss: 0.2490
2021-05-27 02:02:34,811 - mmdet - INFO - Epoch [11][20/25]	lr: 2.500e-04, eta: 0:00:08, time: 0.248, data_time: 0.012, memory: 2226, loss_rpn_cls: 0.0012, loss_rpn_bbox: 0.0087, loss_cls: 0.0703, acc: 97.3047, loss_bbox: 0.1367, loss: 0.2168
2021-05-27 02:02:40,779 - mmdet - INFO - Epoch [12][10/25]	lr: 2.500e-05, eta: 0:00:04, time: 0.469, data_time: 0.226, memory: 2226, loss_rpn_cls: 0.0016, loss_rpn_bbox: 0.0065, loss_cls: 0.0630, acc: 97.5586, loss_bbox: 0.1168, loss: 0.1879
2021-05-27 02:02:43,234 - mmdet - INFO - Epoch [12][20/25]	lr: 2.500e-05, eta: 0:00:01, time: 0.245, data_time: 0.013, memory: 2226, loss_rpn_cls: 0.0016, loss_rpn_bbox: 0.0070, loss_cls: 0.0700, acc: 97.2949, loss_bbox: 0.1068, loss: 0.1853
[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] 25/25, 13.7 task/s, elapsed: 2s, ETA:     0s
---------------iou_thr: 0.5---------------
2021-05-27 02:02:46,577 - mmdet - INFO - 
+------------+-----+------+--------+-------+
| class      | gts | dets | recall | ap    |
+------------+-----+------+--------+-------+
| Car        | 62  | 145  | 0.935  | 0.829 |
| Truck      | 3   | 16   | 1.000  | 0.600 |
| Pedestrian | 13  | 49   | 0.923  | 0.781 |
| Cyclist    | 7   | 51   | 0.714  | 0.180 |
+------------+-----+------+--------+-------+
| mAP        |     |      |        | 0.598 |
+------------+-----+------+--------+-------+
2021-05-27 02:02:46,581 - mmdet - INFO - Saving checkpoint at 12 epochs
2021-05-27 02:02:47,549 - mmdet - INFO - Epoch(val) [12][25]	AP50: 0.5980, mAP: 0.5975

학습된 model을 이용하여 inference 수행.

from mmdet.apis import inference_detector, init_detector, show_result_pyplot

# BGR Image 사용 
img = cv2.imread('/content/kitti_tiny/training/image_2/000068.jpeg')

model.cfg = cfg

result = inference_detector(model, img)
show_result_pyplot(model, img, result)

 

 

반응형
728x90
반응형
# https://github.com/open-mmlab/mmdetection/blob/master/demo/MMDet_Tutorial.ipynb 에서 발췌
# mmcv를 위해서 mmcv-full을 먼저 설치해야 함. 
!pip install mmcv-full
# mmdetection 설치 
!git clone https://github.com/open-mmlab/mmdetection.git
!cd mmdetection; python setup.py install
# 아래를 수행하기 전에 kernel을 restart 해야 함. 
from mmdet.apis import init_detector, inference_detector
import mmcv

KITTI Dataset 다운로드

  • 작은 용량의 KITTI Dataset을 다운로드하고 /content 밑에 압축 해제
# 튜토리얼용 dataset
!wget https://download.openmmlab.com/mmdetection/data/kitti_tiny.zip
!unzip kitti_tiny.zip > /dev/null
import matplotlib.pyplot as plt
import cv2

img = cv2.cvtColor(cv2.imread('/content/kitti_tiny/training/image_2/000068.jpeg'), cv2.COLOR_BGR2RGB)
plt.figure(figsize=(15, 10))
plt.imshow(img)

KITTI DATA FORMAT 확인

  • 첫번째 컬럼은 해당 오브젝트의 클래스 명.
  • 5번째~8번째가 BOUNDING BOX 정보임. 좌상단(xmin, ymin), 우하단(xmax, ymax) 좌표 임.
!cat /content/kitti_tiny/training/label_2/000068.txt

# Car 0.25 0 1.94 69.26 200.28 435.08 374.00 1.46 1.62 4.04 -3.00 1.79 6.98 1.55
# Car 0.80 1 2.26 0.00 209.20 198.59 374.00 1.46 1.58 3.72 -5.44 1.85 6.22 1.56
# Cyclist 0.97 0 2.34 1210.28 199.77 1241.00 374.00 1.55 0.57 1.73 4.04 1.69 3.57 -3.14
# Car 0.00 2 1.68 478.18 187.68 549.54 249.43 1.57 1.60 3.99 -2.73 2.03 20.96 1.55
# Car 0.00 1 1.66 530.03 187.79 573.10 226.09 1.52 1.54 3.68 -2.53 2.20 31.50 1.58
# Van 0.00 1 1.63 547.61 171.12 584.05 212.41 2.47 1.98 5.81 -2.79 2.41 46.44 1.57
# Car 0.00 1 -0.16 667.74 182.35 790.82 230.38 1.62 1.65 4.14 4.19 1.99 25.95 0.00
# Car 0.00 2 -0.11 657.37 184.48 763.34 221.64 1.55 1.66 4.47 4.35 2.10 32.00 0.02
# Car 0.00 1 -0.01 637.45 180.34 714.44 212.34 1.69 1.76 4.12 3.59 2.12 39.79 0.08
# Van 0.00 1 1.61 572.52 175.02 596.26 199.95 2.13 1.91 6.40 -2.28 2.36 65.43 1.57
# Van 0.00 1 1.77 380.78 167.69 523.29 288.56 1.95 1.75 4.63 -2.89 1.90 14.05 1.57
# Cyclist 0.00 1 1.09 958.95 167.55 1036.88 254.43 1.68 0.53 1.96 7.95 1.59 14.95 1.57

KITTI annotation 파일들의 리스트들을 가지는 파일 확인.

!cat /content/kitti_tiny/train.txt
000000
000001
000002
000003
000004
000005
000006
000007
000008
000009
000010
000011
000012
000013
000014
000015
000016
000017
000018
000019
000020
000021
000022
000023
000024
000025
000026
000027
000028
000029
000030
000031
000032
000033
000034
000035
000036
000037
000038
000039
000040
000041
000042
000043
000044
000045
000046
000047
000048
000049

mmdetection의 중립 annotation 포맷 변환. 해당 포맷은 텍스트로 변환하지 않음. 바로 메모리 상의 list로 생성됨.

filename, width, height, ann을 Key로 가지는 Dictionary를 이미지 개수대로 가지는 list 생성.

  • filename: 이미지 파일명(디렉토리는 포함하지 않음)
  • width: 이미지 너비
  • height: 이미지 높이
  • ann: bbounding box와 label에 대한 정보를 가지는 Dictionary
    • bboxes: 하나의 이미지에 있는 여러 Object 들의 numpy array. 4개의 좌표값(좌상단, 우하단)을 가지고, 해당 이미지에 n개의 Object들이 있을 경우 array의 shape는 (n, 4)
    • labels: 하나의 이미지에 있는 여러 Object들의 numpy array. shape는 (n, )
    • bboxes_ignore: 학습에 사용되지 않고 무시하는 bboxes. 무시하는 bboxes의 개수가 k개이면 shape는 (k, 4)
    • labels_ignore: 학습에 사용되지 않고 무시하는 labels. 무시하는 bboxes의 개수가 k개이면 shape는 (k,)

kitti Dataset을 중립 데이터형태로 변환하여 메모리 로드

 

# 원본 kitti Dataset는 10개의 Class로 되어 있음. 'Car Van Truck Pedestrian Person_sitting Cyclist Tram Misc DontCare'
CLASSES = ('Car', 'Truck', 'Pedestrian', 'Cyclist')
cat2label = {k:i for i, k in enumerate(CLASSES)}
print(cat2label)
cat2label['Car']

# {'Car': 0, 'Truck': 1, 'Pedestrian': 2, 'Cyclist': 3}
# 0
image_list = mmcv.list_from_file('/content/kitti_tiny/train.txt')

lines = mmcv.list_from_file('/content/kitti_tiny/training/label_2/000064.txt')
#print(lines)
content = [line.strip().split(' ') for line in lines]
bbox_names = [x[0] for x in content]
#print(bbox_names)
bboxes = [ [float(info) for info in x[4:8]] for x in content]
print(bboxes)

# [[657.65, 179.93, 709.86, 219.92], [731.51, 180.39, 882.28, 275.8], [715.18, 175.63, 762.77, 203.9], [816.58, 59.74, 1112.51, 266.07], [626.78, 174.27, 647.77, 192.18], [546.19, 168.97, 554.01, 177.09]]

dataset, config의 관계를 이해하는 것이 가장 중요하다.

custom dataset 생성 주요 로직

0. dataset을 위한 config 설정(data_root, ann_file, img_prefix)

- build_dataset()으로 아래 작업해줌

1. customdataset객체를 mmdetection framework에 등록

- @DATASETS.register_module(force=True) customdataset을 상속한 클래스 생성

- load_annotations()을 재정의 하여 middle format으로 원본 소스 변환

2. config에 설정된 주요값으로 customdataset 객체 생성

import copy
import os.path as osp
import cv2

import mmcv
import numpy as np

from mmdet.datasets.builder import DATASETS
from mmdet.datasets.custom import CustomDataset

# 반드시 아래 Decorator 설정 할것.@DATASETS.register_module() 설정 시 force=True를 입력하지 않으면 Dataset 재등록 불가. 
@DATASETS.register_module(force=True)
class KittyTinyDataset(CustomDataset):
  CLASSES = ('Car', 'Truck', 'Pedestrian', 'Cyclist')
  
  ##### self.data_root: /content/kitti_tiny/ self.ann_file: /content/kitti_tiny/train.txt self.img_prefix: /content/kitti_tiny/training/image_2
  #### ann_file: /content/kitti_tiny/train.txt
  # annotation에 대한 모든 파일명을 가지고 있는 텍스트 파일을 __init__(self, ann_file)로 입력 받고, 이 self.ann_file이 load_annotations()의 인자로 입력
  def load_annotations(self, ann_file):
    print('##### self.data_root:', self.data_root, 'self.ann_file:', self.ann_file, 'self.img_prefix:', self.img_prefix)
    print('#### ann_file:', ann_file)
    cat2label = {k:i for i, k in enumerate(self.CLASSES)}
    image_list = mmcv.list_from_file(self.ann_file)
    # 포맷 중립 데이터를 담을 list 객체
    data_infos = []
    
    for image_id in image_list:
      filename = '{0:}/{1:}.jpeg'.format(self.img_prefix, image_id)
      # 원본 이미지의 너비, 높이를 image를 직접 로드하여 구함. 
      image = cv2.imread(filename)
      height, width = image.shape[:2]
      # 개별 image의 annotation 정보 저장용 Dict 생성. key값 filename 에는 image의 파일명만 들어감(디렉토리는 제외)
      data_info = {'filename': str(image_id) + '.jpeg',
                   'width': width, 'height': height}
      # 개별 annotation이 있는 서브 디렉토리의 prefix 변환. 
      label_prefix = self.img_prefix.replace('image_2', 'label_2')
      # 개별 annotation 파일을 1개 line 씩 읽어서 list 로드 
      lines = mmcv.list_from_file(osp.join(label_prefix, str(image_id)+'.txt'))

      # 전체 lines를 개별 line별 공백 레벨로 parsing 하여 다시 list로 저장. content는 list의 list형태임.
      # ann 정보는 numpy array로 저장되나 텍스트 처리나 데이터 가공이 list 가 편하므로 일차적으로 list로 변환 수행.   
      content = [line.strip().split(' ') for line in lines]
      # 오브젝트의 클래스명은 bbox_names로 저장. 
      bbox_names = [x[0] for x in content]
      # bbox 좌표를 저장
      bboxes = [ [float(info) for info in x[4:8]] for x in content]

      # 클래스명이 해당 사항이 없는 대상 Filtering out, 'DontCare'sms ignore로 별도 저장.
      gt_bboxes = []
      gt_labels = []
      gt_bboxes_ignore = []
      gt_labels_ignore = []

      for bbox_name, bbox in zip(bbox_names, bboxes):
        # 만약 bbox_name이 클래스명에 해당 되면, gt_bboxes와 gt_labels에 추가, 그렇지 않으면 gt_bboxes_ignore, gt_labels_ignore에 추가
        if bbox_name in cat2label:
          gt_bboxes.append(bbox)
          # gt_labels에는 class id를 입력
          gt_labels.append(cat2label[bbox_name])
        else:
          gt_bboxes_ignore.append(bbox)
          gt_labels_ignore.append(-1)
      # 개별 image별 annotation 정보를 가지는 Dict 생성. 해당 Dict의 value값은 모두 np.array임. 
      data_anno = {
          'bboxes': np.array(gt_bboxes, dtype=np.float32).reshape(-1, 4),
          'labels': np.array(gt_labels, dtype=np.long),
          'bboxes_ignore': np.array(gt_bboxes_ignore, dtype=np.float32).reshape(-1, 4),
          'labels_ignore': np.array(gt_labels_ignore, dtype=np.long)
      }
      # image에 대한 메타 정보를 가지는 data_info Dict에 'ann' key값으로 data_anno를 value로 저장. 
      data_info.update(ann=data_anno)
      # 전체 annotation 파일들에 대한 정보를 가지는 data_infos에 data_info Dict를 추가
      data_infos.append(data_info)

    return data_infos

data_root, ann_file, img_prefix의 활용

- 학습용, 검증용, 테스트용으로 dataset이 만들어져야한다.

소스 데이터들의 학습용, 검증용, 테스트용 분리유형

- image 들과 annotation파일이 학습용, 검증용, 테스트용 디렉토리에 별도로 분리

- 별도의 메타 파일에서 각 image, annotation 지정

- image들 각 용도에 맞게 디렉토리별 분리, annotation은 각 용도별 하나만 가짐(3개 json)

* img_prefix는 여러개의 image들을 포함할 수 있는 디렉토리 형태로 지정되지만, ann_file은 단하나만 지정할 수 있음

# 학습 data config 셋팅
train.data_root=/content/kitti_tiny
train.ann_file='train.txt'
train.img_prefix='training/image_2'

# 학습 kitti data config 셋팅

train_dataset = kittiYinydataset(ann_file = train.data_root,
				data_root = train.ann_file,
				img_prefix = train.img_prefix )

 

 

 

 

 

 

 

반응형
728x90
반응형

mmdetection의 주요구성요소

dataset을 model에 입력시켜야 함.

model을 weight값을 갱신하면서 고도화시켜야함

dataset에는 image, detection을 위한 annotation이 있고, dataset config file에 저장이 되어있음.

 전체적으로 config 파일에 의해서 통제가 됨.

 

dataset의 변환도 중요함

pv, coco 등 많은 dataset이 있는데 이것을 mmdetection이 받아들이기 쉽게 transformation해야 함.

 

mmdetection dataset 지원

=> mmdetection은 다양한 유형의 dataset을 변환 클래스를 통해서 지원함

custom dataset, cocodataset, vocdataset, widerfaceDataset, XMLdataset 중

customdataset, cocodataset이 쉽게 적용될 수 있는 dataset임

 

pascal voc 데이터 세트 특징

ds_name = 'voc07'으로 pascal 형식을 그대로 따름

VOCdevkit - voc2012 - annotations, imageset, jpegimage, segmentationclass, segmentationobject

=> 디렉토리 의 구조를 맞춰줘야함. 차라리 custom dataset 을 parsing 하는게 나음

 

ms-coco 데이터 세트 특징

모든 이미지들에 대해 단 1개의 annotation 파일을 가짐

train, val, test전부 json 포맷인 한개의 파일, 한 라인으로 구성됨

json { info, license,

images {id, file_name, width, height},

annotations {image, object id, segmentation, bounding box, pixel area},

categories (80개 object categories 에 대한 id, names, group)

}

 

custom dataset에 사용되는 포멧

- 모든 이미지에 대한 annotation정보들을 list객체로 가짐

- list 내 개별 원소는 dict로 구성되면 개별 dict는 1개 이미지에 대한 annotation 정보를 가짐

- 1개 이미지는 여러개의 object bbox와 labels annotation 정보들을 개별 dict로 가짐

- 1개 이미지의 object bbox와 2차원 array로 , label은 1차원 array로 구성됨.

 

반응형
728x90
반응형

Video Inference 수행

  • mmdetection의 video_demo.py 대로 Video inference 수행시 image 처리 시간이 상대적으로 오래 걸림.
  • 이미지 처리 로직을 변경하여 적용
!wget -O /content/data/John_Wick_small.mp4 https://github.com/chulminkw/DLCV/blob/master/data/video/John_Wick_small.mp4?raw=true
from mmdet.apis import init_detector, inference_detector
import mmcv

config_file = '/content/mmdetection/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py'
checkpoint_file = '/content/mmdetection/checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
model = init_detector(config_file, checkpoint_file, device='cuda:0')
# https://github.com/open-mmlab/mmdetection/blob/master/demo/video_demo.py 대로 video detection 수행. 

import cv2

video_reader = mmcv.VideoReader('/content/data/John_Wick_small.mp4')
video_writer = None
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
video_writer = cv2.VideoWriter('/content/data/John_Wick_small_out1.mp4', fourcc, video_reader.fps,(video_reader.width, video_reader.height))

for frame in mmcv.track_iter_progress(video_reader):
  result = inference_detector(model, frame)
  frame = model.show_result(frame, result, score_thr=0.4)

  video_writer.write(frame)

if video_writer:
        video_writer.release()

Custom된 frame처리 로직을 적용하여 Video Inference 수행.

  • 기존에 사용한 get_detected_img()를 그대로 사용함.
# model과 원본 이미지 array, filtering할 기준 class confidence score를 인자로 가지는 inference 시각화용 함수 생성. 
import numpy as np

# 0부터 순차적으로 클래스 매핑된 label 적용. 
labels_to_names_seq = {0:'person',1:'bicycle',2:'car',3:'motorbike',4:'aeroplane',5:'bus',6:'train',7:'truck',8:'boat',9:'traffic light',10:'fire hydrant',
                        11:'stop sign',12:'parking meter',13:'bench',14:'bird',15:'cat',16:'dog',17:'horse',18:'sheep',19:'cow',20:'elephant',
                        21:'bear',22:'zebra',23:'giraffe',24:'backpack',25:'umbrella',26:'handbag',27:'tie',28:'suitcase',29:'frisbee',30:'skis',
                        31:'snowboard',32:'sports ball',33:'kite',34:'baseball bat',35:'baseball glove',36:'skateboard',37:'surfboard',38:'tennis racket',39:'bottle',40:'wine glass',
                        41:'cup',42:'fork',43:'knife',44:'spoon',45:'bowl',46:'banana',47:'apple',48:'sandwich',49:'orange',50:'broccoli',
                        51:'carrot',52:'hot dog',53:'pizza',54:'donut',55:'cake',56:'chair',57:'sofa',58:'pottedplant',59:'bed',60:'diningtable',
                        61:'toilet',62:'tvmonitor',63:'laptop',64:'mouse',65:'remote',66:'keyboard',67:'cell phone',68:'microwave',69:'oven',70:'toaster',
                        71:'sink',72:'refrigerator',73:'book',74:'clock',75:'vase',76:'scissors',77:'teddy bear',78:'hair drier',79:'toothbrush' }

def get_detected_img(model, img_array,  score_threshold=0.3, is_print=True):
  # 인자로 들어온 image_array를 복사. 
  draw_img = img_array.copy()
  bbox_color=(0, 255, 0)
  text_color=(0, 0, 255)

  # model과 image array를 입력 인자로 inference detection 수행하고 결과를 results로 받음. 
  # results는 80개의 2차원 array(shape=(오브젝트갯수, 5))를 가지는 list. 
  results = inference_detector(model, img_array)

  # 80개의 array원소를 가지는 results 리스트를 loop를 돌면서 개별 2차원 array들을 추출하고 이를 기반으로 이미지 시각화 
  # results 리스트의 위치 index가 바로 COCO 매핑된 Class id. 여기서는 result_ind가 class id
  # 개별 2차원 array에 오브젝트별 좌표와 class confidence score 값을 가짐. 
  for result_ind, result in enumerate(results):
    # 개별 2차원 array의 row size가 0 이면 해당 Class id로 값이 없으므로 다음 loop로 진행. 
    if len(result) == 0:
      continue
    
    # 2차원 array에서 5번째 컬럼에 해당하는 값이 score threshold이며 이 값이 함수 인자로 들어온 score_threshold 보다 낮은 경우는 제외. 
    result_filtered = result[np.where(result[:, 4] > score_threshold)]
    
    # 해당 클래스 별로 Detect된 여러개의 오브젝트 정보가 2차원 array에 담겨 있으며, 이 2차원 array를 row수만큼 iteration해서 개별 오브젝트의 좌표값 추출. 
    for i in range(len(result_filtered)):
      # 좌상단, 우하단 좌표 추출. 
      left = int(result_filtered[i, 0])
      top = int(result_filtered[i, 1])
      right = int(result_filtered[i, 2])
      bottom = int(result_filtered[i, 3])
      caption = "{}: {:.4f}".format(labels_to_names_seq[result_ind], result_filtered[i, 4])
      cv2.rectangle(draw_img, (left, top), (right, bottom), color=bbox_color, thickness=2)
      cv2.putText(draw_img, caption, (int(left), int(top - 7)), cv2.FONT_HERSHEY_SIMPLEX, 0.37, text_color, 1)
      if is_print:
        print(caption)

  return draw_img
import time

def do_detected_video(model, input_path, output_path, score_threshold, do_print=True):
    
    cap = cv2.VideoCapture(input_path)

    codec = cv2.VideoWriter_fourcc(*'XVID')

    vid_size = (round(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    vid_fps = cap.get(cv2.CAP_PROP_FPS)

    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)
    btime = time.time()
    while True:
        hasFrame, img_frame = cap.read()
        if not hasFrame:
            print('더 이상 처리할 frame이 없습니다.')
            break
        stime = time.time()
        img_frame = get_detected_img(model, img_frame,  score_threshold=score_threshold, is_print=False)
        if do_print:
          print('frame별 detection 수행 시간:', round(time.time() - stime, 4))
        vid_writer.write(img_frame)
    # end of while loop

    vid_writer.release()
    cap.release()

    print('최종 detection 완료 수행 시간:', round(time.time() - btime, 4))
do_detected_video(model, '/content/data/John_Wick_small.mp4', '/content/data/John_Wick_small_out2.mp4', score_threshold=0.4, do_print=True)

frame별 detection 수행 시간: 0.304
frame별 detection 수행 시간: 0.3139
frame별 detection 수행 시간: 0.2853
frame별 detection 수행 시간: 0.2918
frame별 detection 수행 시간: 0.2905
frame별 detection 수행 시간: 0.299
frame별 detection 수행 시간: 0.3006
frame별 detection 수행 시간: 0.2887
frame별 detection 수행 시간: 0.295
frame별 detection 수행 시간: 0.2932
frame별 detection 수행 시간: 0.2991
frame별 detection 수행 시간: 0.303
frame별 detection 수행 시간: 0.2913
frame별 detection 수행 시간: 0.2953
frame별 detection 수행 시간: 0.3003
frame별 detection 수행 시간: 0.3022
frame별 detection 수행 시간: 0.3018
frame별 detection 수행 시간: 0.2954
frame별 detection 수행 시간: 0.2975
frame별 detection 수행 시간: 0.3034
frame별 detection 수행 시간: 0.292
frame별 detection 수행 시간: 0.288
frame별 detection 수행 시간: 0.2939
frame별 detection 수행 시간: 0.2911
frame별 detection 수행 시간: 0.2969
frame별 detection 수행 시간: 0.2903
frame별 detection 수행 시간: 0.2912
frame별 detection 수행 시간: 0.2906
frame별 detection 수행 시간: 0.2947
frame별 detection 수행 시간: 0.2956
frame별 detection 수행 시간: 0.2936
frame별 detection 수행 시간: 0.2939
frame별 detection 수행 시간: 0.2925
frame별 detection 수행 시간: 0.2939
frame별 detection 수행 시간: 0.3
frame별 detection 수행 시간: 0.2862
frame별 detection 수행 시간: 0.2961
frame별 detection 수행 시간: 0.2958
frame별 detection 수행 시간: 0.2943
frame별 detection 수행 시간: 0.2931
frame별 detection 수행 시간: 0.2856
frame별 detection 수행 시간: 0.2911
frame별 detection 수행 시간: 0.2967
frame별 detection 수행 시간: 0.2944
frame별 detection 수행 시간: 0.2933
frame별 detection 수행 시간: 0.2886
frame별 detection 수행 시간: 0.2926
frame별 detection 수행 시간: 0.2991
frame별 detection 수행 시간: 0.2963
frame별 detection 수행 시간: 0.2885
frame별 detection 수행 시간: 0.2917
frame별 detection 수행 시간: 0.292
frame별 detection 수행 시간: 0.3013
frame별 detection 수행 시간: 0.2963
frame별 detection 수행 시간: 0.2903
더 이상 처리할 frame이 없습니다.
최종 detection 완료 수행 시간: 17.738

 

 

 

 

반응형
728x90
반응형
# 버전 확인
import torch
print(torch.__version__)
# mmcv를 위해서 mmcv-full을 설치해야 함. 
!pip install mmcv-full
from google.colab import drive
drive.mount('/content/drive')
!git clone https://github.com/open-mmlab/mmdetection.git
!cd mmdetection; python setup.py install
# 아래를 수행하기 전에 kernel을 restart 해야 함. 
# 런타임 초기화하면 설치한 파일 날라감
from mmdet.apis import init_detector, inference_detector
import mmcv

MS-COCO 데이터 기반으로 Faster RCNN Pretrained 모델을 활용하여 Inference 수행

  • Faster RCNN Pretrained 모델 다운로드
  • Faster RCNN용 Config 파일 설정.
  • Inference 용 모델을 생성하고, Inference 적용
# pretrained weight 모델을 다운로드 받기 위해서 mmdetection/checkpoints 디렉토리를 만듬. 
!cd mmdetection; mkdir checkpoints
# pretrained model faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth 설치
!wget -O /content/mmdetection/checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
# pretrained model 경로 확인
!ls -lia /content/mmdetection/checkpoints
# total 163376
# 3951436 drwxr-xr-x  2 root root      4096 Oct 10 13:13 .
# 3932841 drwxr-xr-x 19 root root      4096 Oct 10 13:13 ..
# 3951438 -rw-r--r--  1 root root 167287506 Aug 28  2020 faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth

 

 

# config 파일을 설정하고, 다운로드 받은 pretrained 모델을 checkpoint로 설정. 
config_file = '/content/mmdetection/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py'
checkpoint_file = '/content/mmdetection/checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
# config 파일과 pretrained 모델을 기반으로 Detector 모델을 생성. 
from mmdet.apis import init_detector, inference_detector

model = init_detector(config_file, checkpoint_file, device='cuda:0') # gpu 지정
# /usr/local/lib/python3.7/dist-packages/mmdet-2.17.0-py3.7.egg/mmdet/core/anchor/builder.py:17: UserWarning: ``build_anchor_generator`` would be deprecated soon, please use ``build_prior_generator`` 
#   '``build_anchor_generator`` would be deprecated soon, please use '
# Use load_from_local loader
# mmdetection은 상대 경로를 인자로 주면 무조건 mmdetection 디렉토리를 기준으로 함. 
%cd mmdetection

from mmdet.apis import init_detector, inference_detector

# init_detector() 인자로 config와 checkpoint를 입력함. 
model = init_detector(config='configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py', checkpoint='checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth')

# /content/mmdetection
# /usr/local/lib/python3.7/dist-packages/mmdet-2.17.0-py3.7.egg/mmdet/core/anchor/builder.py:17: UserWarning: ``build_anchor_generator`` would be deprecated soon, please use ``build_prior_generator`` 
#   '``build_anchor_generator`` would be deprecated soon, please use '
# Use load_from_local loader

# mmdetection/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py - _base_

=> 모델 별로 각각 다른 config를 가지는게 아니라 공통의 config를 지님

mmdetection/configs/_base_/models/fast_rcnn_r50_fpn.py에 neck=dict에 type=fpn으로 되어있음

참고로 나중에 커스컴 할 때 num_classes = n을 바꿔야함, coco dataset이 n개라서

%cd /content
# /content
import cv2
import matplotlib.pyplot as plt
img = '/content/mmdetection/demo/demo.jpg'

img_arr  = cv2.cvtColor(cv2.imread(img), cv2.COLOR_BGR2RGB)
plt.figure(figsize=(12, 12))
plt.imshow(img_arr)

 

img = '/content/mmdetection/demo/demo.jpg'
# inference_detector의 인자로 string(file경로), ndarray가 단일 또는 list형태로 입력 될 수 있음. 
results = inference_detector(model, img)

# /usr/local/lib/python3.7/dist-packages/mmdet-2.17.0-py3.7.egg/mmdet/datasets/utils.py:69: UserWarning: "ImageToTensor" pipeline is replaced by "DefaultFormatBundle" for batch inference. It is recommended to manually replace it in the test data pipeline in your config file.
#   'data pipeline in your config file.', UserWarning)
# /usr/local/lib/python3.7/dist-packages/torch/nn/functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at  /pytorch/c10/core/TensorImpl.h:1156.)
#   return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)
# /usr/local/lib/python3.7/dist-packages/mmdet-2.17.0-py3.7.egg/mmdet/core/anchor/anchor_generator.py:324: UserWarning: ``grid_anchors`` would be deprecated soon. Please use ``grid_priors`` 
#   warnings.warn('``grid_anchors`` would be deprecated soon. '
# /usr/local/lib/python3.7/dist-packages/mmdet-2.17.0-py3.7.egg/mmdet/core/anchor/anchor_generator.py:361: UserWarning: ``single_level_grid_anchors`` would be deprecated soon. Please use ``single_level_grid_priors`` 
#   '``single_level_grid_anchors`` would be deprecated soon. '
type(results), len(results)
# (list, 80)
# len이 80개인데, detected 가 80개가 아니라 cocodataset이 80개임

MS-COCO pretrained model의 inference 반환 결과

# results는 list형으로 coco class의  0부터 79까지 class_id별로 80개의 array를 가짐. 
# 개별 array들은 각 클래스별로 5개의 값(좌표값과 class별로 confidence)을 가짐. 개별 class별로 여러개의 좌표를 가지면 여러개의 array가 생성됨. 
# 좌표는 좌상단(xmin, ymin), 우하단(xmax, ymax) 기준. 
# 개별 array의 shape는 (Detection된 object들의 수, 5(좌표와 confidence)) 임

results

class)id 0:'person', 1:'bicycle, 2:'car'
[array([[3.75348572e+02, 1.19171005e+02, 3.81950867e+02, 1.34460617e+02,
         1.35454327e-01], # 좌표값 좌상단(xmin, ymin), 우하단(xmax, ymax), class confidence
        [5.32362000e+02, 1.09554726e+02, 5.40526550e+02, 1.25222633e+02,
         8.88783410e-02], # 좌표값 좌상단(xmin, ymin), 우하단(xmax, ymax), class confidence
        [3.61124298e+02, 1.09049202e+02, 3.68625610e+02, 1.22483063e+02,
         7.20723420e-02]], dtype=float32), # 좌표값 좌상단(xmin, ymin), 우하단(xmax, ymax), class confidence
# class id는 별도로 없고, results[0]이 0번임         
# 내부에서 정규화를 해버림 
 array([], shape=(0, 5), dtype=float32), # 0번 class id는 detect가 안됬다.
 array([[6.09650024e+02, 1.13805893e+02, 6.34511658e+02, 1.36951904e+02,
         9.88766134e-01],
        [4.81773712e+02, 1.10480980e+02, 5.22459717e+02, 1.30407104e+02,
         9.87157285e-01],
        [1.01822114e+00, 1.12144730e+02, 6.04374733e+01, 1.44173752e+02,
         9.83206093e-01],
        [2.94623718e+02, 1.17035240e+02, 3.78022705e+02, 1.50550873e+02,
         9.71326768e-01],
        [3.96328979e+02, 1.11203323e+02, 4.32490540e+02, 1.32729263e+02,
         9.67802167e-01],
        [5.90976257e+02, 1.10802658e+02, 6.15401794e+02, 1.26493553e+02,
         9.59414959e-01],
        [2.67582001e+02, 1.05686005e+02, 3.28818756e+02, 1.28226547e+02,
         9.59253132e-01],
        [1.66856735e+02, 1.08006607e+02, 2.19100693e+02, 1.40194809e+02,
         9.56841350e-01],
        [1.89769577e+02, 1.09801109e+02, 3.00310852e+02, 1.53781891e+02,
         9.51012135e-01],
        [4.29822540e+02, 1.05655380e+02, 4.82741516e+02, 1.32376724e+02,
         9.45849955e-01],
        [5.55000916e+02, 1.09785004e+02, 5.92761780e+02, 1.27808495e+02,
         9.43992615e-01],
        [5.96790352e+01, 9.31828003e+01, 8.34545441e+01, 1.06242912e+02,
         9.33143973e-01],
        [9.78446579e+01, 8.96542969e+01, 1.18172356e+02, 1.01011108e+02,
         8.66323531e-01],
        [1.43898987e+02, 9.61869888e+01, 1.64599792e+02, 1.04979256e+02,
         8.26784551e-01],
        [8.55894241e+01, 8.99445801e+01, 9.88920746e+01, 9.85285416e+01,
         7.53480315e-01],
        [9.78282700e+01, 9.07443695e+01, 1.10298050e+02, 9.97373276e+01,
         7.16600597e-01],
        [2.23579224e+02, 9.85184631e+01, 2.49845108e+02, 1.07509857e+02,
         6.00782037e-01],
        [1.68928635e+02, 9.59468994e+01, 1.82843445e+02, 1.05694962e+02,
         5.91998756e-01],
        [1.35021347e+02, 9.08739395e+01, 1.50607025e+02, 1.02798874e+02,
         5.54030240e-01],
        [0.00000000e+00, 1.11521950e+02, 1.45326691e+01, 1.25850288e+02,
         5.43519914e-01],
        [5.53896606e+02, 1.16170540e+02, 5.62602295e+02, 1.26390923e+02,
         4.76758897e-01],
        [3.75809753e+02, 1.19579056e+02, 3.82376495e+02, 1.32113892e+02,
         4.61191744e-01],
        [1.37924118e+02, 9.37975311e+01, 1.54497177e+02, 1.04659683e+02,
         4.00998443e-01],
        [5.55009033e+02, 1.10952698e+02, 5.74925659e+02, 1.26912033e+02,
         3.43850523e-01],
        [5.54043152e+02, 1.00959076e+02, 5.61297913e+02, 1.10927711e+02,
         2.87963450e-01],
        [6.14741028e+02, 1.01987068e+02, 6.35481628e+02, 1.12593704e+02,
         2.61200219e-01],
        [5.70760315e+02, 1.09679398e+02, 5.90286133e+02, 1.27248878e+02,
         2.58404434e-01],
        [4.78544116e-01, 1.11568169e+02, 2.25040989e+01, 1.42623535e+02,
         2.56050110e-01],
        [3.75093140e+02, 1.11696442e+02, 4.20536804e+02, 1.33691055e+02,
         2.55963236e-01],
        [2.62747284e+02, 1.07565620e+02, 3.26765930e+02, 1.43925293e+02,
         2.09969625e-01],
        [7.91312714e+01, 9.03788834e+01, 1.00247879e+02, 1.01080894e+02,
         2.03962341e-01],
        [6.09313477e+02, 1.13308510e+02, 6.25961975e+02, 1.25342514e+02,
         1.97422847e-01],
        [1.35304840e+02, 9.23771439e+01, 1.64080185e+02, 1.04992455e+02,
         1.49973527e-01],
        [6.73540573e+01, 8.85008087e+01, 8.29853592e+01, 9.73942108e+01,
         1.48383990e-01],
        [5.40852417e+02, 1.13848946e+02, 5.61855530e+02, 1.26198776e+02,
         1.47629887e-01],
        [3.51735046e+02, 1.09432655e+02, 4.39310089e+02, 1.34819733e+02,
         1.41735107e-01],
        [9.63179016e+01, 8.98780594e+01, 1.53287781e+02, 1.01776367e+02,
         1.32707968e-01],
        [4.54495049e+01, 1.17444977e+02, 6.18955803e+01, 1.44275055e+02,
         1.25890508e-01],
        [6.06407532e+02, 1.12215973e+02, 6.18935669e+02, 1.24957237e+02,
         1.10722415e-01],
        [1.02152626e+02, 9.36143646e+01, 1.41081863e+02, 1.01598961e+02,
         8.13643038e-02],
        [3.98364838e+02, 1.12081459e+02, 4.09389862e+02, 1.32897766e+02,
         7.64543191e-02],
        [5.39245911e+02, 1.12394836e+02, 5.48756714e+02, 1.21964462e+02,
         7.32642636e-02],
        [6.09156555e+02, 1.04017456e+02, 6.35472107e+02, 1.26777176e+02,
         6.47417754e-02],
        [3.75894284e+00, 9.85745239e+01, 7.45848312e+01, 1.35154999e+02,
         6.32166639e-02],
        [1.68166473e+02, 9.14260483e+01, 2.20303146e+02, 1.07955681e+02,
         5.16179129e-02],
        [7.09724045e+01, 9.02684860e+01, 1.05398132e+02, 1.03825508e+02,
         5.15376776e-02]], dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([[1.8820007e+02, 1.0994706e+02, 3.0047137e+02, 1.5633583e+02,
         9.7509645e-02],
        [4.2774915e+02, 1.0511559e+02, 4.8345541e+02, 1.3294328e+02,
         9.6882291e-02],
        [2.9450479e+02, 1.1764229e+02, 3.7863284e+02, 1.5046356e+02,
         7.4364766e-02]], dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([[2.1920888e+02, 1.7456262e+02, 4.6010886e+02, 3.7704660e+02,
         9.7778010e-01],
        [3.7206638e+02, 1.3631432e+02, 4.3219531e+02, 1.8717290e+02,
         4.1699746e-01]], dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([[9.13259964e+01, 1.07155769e+02, 1.06029366e+02, 1.19777306e+02,
         1.15152948e-01]], dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([[3.72651917e+02, 1.36143082e+02, 4.32053833e+02, 1.88446472e+02,
         7.77875960e-01],
        [2.18404114e+02, 1.75137848e+02, 4.62107605e+02, 3.65541260e+02,
         1.01236075e-01]], dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32),
 array([], shape=(0, 5), dtype=float32)]

요약

# 2차원 배열로 표현됨
# 사람,    자전거,  차,     
results[0].shape, results[1].shape, results[2].shape, results[3].shape
# ((3, 5), (0, 5), (46, 5), (0, 5))
# 3건,      0건,    46건,    0건

결과 직접 확인

from mmdet.apis import show_result_pyplot
# inference 된 결과를 원본 이미지에 적용하여 새로운 image로 생성(bbox 처리된 image)
# Default로 score threshold가 0.3 이상인 Object들만 시각화 적용. show_result_pyplot은 model.show_result()를 호출. 
show_result_pyplot(model, img, results)

 

Model의 Config 설정 확인하기

# configs 파일로 모델을 만들었는데 모델 객체안의 변수 확인
model.__dict__

# 80개 class
{'CLASSES': ('person',
  'bicycle',
  'car',
  'motorcycle',
  'airplane',
  'bus',
  'train',
  'truck',
  'boat',
  'traffic_light',
  'fire_hydrant',
  'stop_sign',
  'parking_meter',
  'bench',
  'bird',
  'cat',
  'dog',
  'horse',
  'sheep',
  'cow',
  'elephant',
  'bear',
  'zebra',
  'giraffe',
  'backpack',
  'umbrella',
  'handbag',
  'tie',
  'suitcase',
  'frisbee',
  'skis',
  'snowboard',
  'sports_ball',
  'kite',
  'baseball_bat',
  'baseball_glove',
  'skateboard',
  'surfboard',
  'tennis_racket',
  'bottle',
  'wine_glass',
  'cup',
  'fork',
  'knife',
  'spoon',
  'bowl',
  'banana',
  'apple',
  'sandwich',
  'orange',
  'broccoli',
  'carrot',
  'hot_dog',
  'pizza',
  'donut',
  'cake',
  'chair',
  'couch',
  'potted_plant',
  'bed',
  'dining_table',
  'toilet',
  'tv',
  'laptop',
  'mouse',
  'remote',
  'keyboard',
  'cell_phone',
  'microwave',
  'oven',
  'toaster',
  'sink',
  'refrigerator',
  'book',
  'clock',
  'vase',
  'scissors',
  'teddy_bear',
  'hair_drier',
  'toothbrush'),
  '_modules': OrderedDict([('backbone', ResNet(
  # 모듈은 pytorch, backbone : resnet
  'cfg': Config (path: configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py)
#print(model.cfg) # 안이쁘게 나옴
print(model.cfg.pretty_text)

model = dict(
    type='FasterRCNN',
    backbone=dict(
        type='ResNet',
        depth=50,
        num_stages=4,
        out_indices=(0, 1, 2, 3),
        frozen_stages=1,
        norm_cfg=dict(type='BN', requires_grad=True),
        norm_eval=True,
        style='pytorch',
        init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')),
    neck=dict(
        type='FPN',
        in_channels=[256, 512, 1024, 2048],
        out_channels=256,
        num_outs=5),
    rpn_head=dict(
        type='RPNHead',
        in_channels=256,
        feat_channels=256,
        anchor_generator=dict(
            type='AnchorGenerator',
            scales=[8],
            ratios=[0.5, 1.0, 2.0],
            strides=[4, 8, 16, 32, 64]),
        bbox_coder=dict(
            type='DeltaXYWHBBoxCoder',
            target_means=[0.0, 0.0, 0.0, 0.0],
            target_stds=[1.0, 1.0, 1.0, 1.0]),
        loss_cls=dict(
            type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
        loss_bbox=dict(type='L1Loss', loss_weight=1.0)),
    roi_head=dict(
        type='StandardRoIHead',
        bbox_roi_extractor=dict(
            type='SingleRoIExtractor',
            roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0),
            out_channels=256,
            featmap_strides=[4, 8, 16, 32]),
        bbox_head=dict(
            type='Shared2FCBBoxHead',
            in_channels=256,
            fc_out_channels=1024,
            roi_feat_size=7,
            num_classes=80,
            bbox_coder=dict(
                type='DeltaXYWHBBoxCoder',
                target_means=[0.0, 0.0, 0.0, 0.0],
                target_stds=[0.1, 0.1, 0.2, 0.2]),
            reg_class_agnostic=False,
            loss_cls=dict(
                type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0),
            loss_bbox=dict(type='L1Loss', loss_weight=1.0)),
        train_cfg=None,
        test_cfg=dict(
            score_thr=0.05,
            nms=dict(type='nms', iou_threshold=0.5),
            max_per_img=100),
        pretrained=None),
    train_cfg=None,
    test_cfg=dict(
        rpn=dict(
            nms_pre=1000,
            max_per_img=1000,
            nms=dict(type='nms', iou_threshold=0.7),
            min_bbox_size=0),
        rcnn=dict(
            score_thr=0.05,
            nms=dict(type='nms', iou_threshold=0.5),
            max_per_img=100)),
    pretrained=None)
dataset_type = 'CocoDataset'
data_root = 'data/coco/'
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='LoadAnnotations', with_bbox=True),
    dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
    dict(type='RandomFlip', flip_ratio=0.5),
    dict(
        type='Normalize',
        mean=[123.675, 116.28, 103.53],
        std=[58.395, 57.12, 57.375],
        to_rgb=True),
    dict(type='Pad', size_divisor=32),
    dict(type='DefaultFormatBundle'),
    dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])
]
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(
        type='MultiScaleFlipAug',
        img_scale=(1333, 800),
        flip=False,
        transforms=[
            dict(type='Resize', keep_ratio=True),
            dict(type='RandomFlip'),
            dict(
                type='Normalize',
                mean=[123.675, 116.28, 103.53],
                std=[58.395, 57.12, 57.375],
                to_rgb=True),
            dict(type='Pad', size_divisor=32),
            dict(type='ImageToTensor', keys=['img']),
            dict(type='Collect', keys=['img'])
        ])
]
data = dict(
    samples_per_gpu=2,
    workers_per_gpu=2,
    train=dict(
        type='CocoDataset',
        ann_file='data/coco/annotations/instances_train2017.json',
        img_prefix='data/coco/train2017/',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(type='LoadAnnotations', with_bbox=True),
            dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
            dict(type='RandomFlip', flip_ratio=0.5),
            dict(
                type='Normalize',
                mean=[123.675, 116.28, 103.53],
                std=[58.395, 57.12, 57.375],
                to_rgb=True),
            dict(type='Pad', size_divisor=32),
            dict(type='DefaultFormatBundle'),
            dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])
        ]),
    val=dict(
        type='CocoDataset',
        ann_file='data/coco/annotations/instances_val2017.json',
        img_prefix='data/coco/val2017/',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(
                type='MultiScaleFlipAug',
                img_scale=(1333, 800),
                flip=False,
                transforms=[
                    dict(type='Resize', keep_ratio=True),
                    dict(type='RandomFlip'),
                    dict(
                        type='Normalize',
                        mean=[123.675, 116.28, 103.53],
                        std=[58.395, 57.12, 57.375],
                        to_rgb=True),
                    dict(type='Pad', size_divisor=32),
                    dict(type='ImageToTensor', keys=['img']),
                    dict(type='Collect', keys=['img'])
                ])
        ]),
    test=dict(
        type='CocoDataset',
        ann_file='data/coco/annotations/instances_val2017.json',
        img_prefix='data/coco/val2017/',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(
                type='MultiScaleFlipAug',
                img_scale=(1333, 800),
                flip=False,
                transforms=[
                    dict(type='Resize', keep_ratio=True),
                    dict(type='RandomFlip'),
                    dict(
                        type='Normalize',
                        mean=[123.675, 116.28, 103.53],
                        std=[58.395, 57.12, 57.375],
                        to_rgb=True),
                    dict(type='Pad', size_divisor=32),
                    dict(type='DefaultFormatBundle'),
                    dict(type='Collect', keys=['img'])
                ])
        ]))
evaluation = dict(interval=1, metric='bbox')
optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001)
optimizer_config = dict(grad_clip=None)
lr_config = dict(
    policy='step',
    warmup='linear',
    warmup_iters=500,
    warmup_ratio=0.001,
    step=[8, 11])
runner = dict(type='EpochBasedRunner', max_epochs=12)
checkpoint_config = dict(interval=1)
log_config = dict(interval=50, hooks=[dict(type='TextLoggerHook')])
custom_hooks = [dict(type='NumClassCheckHook')]
dist_params = dict(backend='nccl')
log_level = 'INFO'
load_from = None
resume_from = None
workflow = [('train', 1)]

커스텀 할때 모델의 class 가 몇개인가, bbox_head의 num_classes 설정, dataset 설정을 지정해야 함. transforming, annotation 등 설정

 

array를 inference_detector()에 입력할 경우에는 원본 array를 BGR 형태로 입력 필요(RGB 변환은 내부에서 수행하므로 BGR로 입력 필요)

import cv2

# RGB가 아닌 BGR로 입력
img_arr = cv2.imread('/content/mmdetection/demo/demo.jpg')
results = inference_detector(model, img_arr)

show_result_pyplot(model, img_arr, results)

show_result_pyplot()을 이용하지 않고, inference 결과를 image로 표현하기

  • model과 image array를 입력하면 해당 image를 detect하고 bbox 처리해주는 get_detected_img() 함수 생성.
  • COCO 클래스 매핑은 0 부터 순차적으로 적용됨.
  • results에 들어있는 array 값이 없는 경우는 해당 list의 index에 해당하는 class id값으로 object가 Detection되지 않은 것임.
  • 개별 class의 score threshold가 낮은 값은 제외.
# 0부터 순차적으로 클래스 매핑된 label 적용. 
labels_to_names_seq = {0:'person',1:'bicycle',2:'car',3:'motorbike',4:'aeroplane',5:'bus',6:'train',7:'truck',8:'boat',9:'traffic light',10:'fire hydrant',
                        11:'stop sign',12:'parking meter',13:'bench',14:'bird',15:'cat',16:'dog',17:'horse',18:'sheep',19:'cow',20:'elephant',
                        21:'bear',22:'zebra',23:'giraffe',24:'backpack',25:'umbrella',26:'handbag',27:'tie',28:'suitcase',29:'frisbee',30:'skis',
                        31:'snowboard',32:'sports ball',33:'kite',34:'baseball bat',35:'baseball glove',36:'skateboard',37:'surfboard',38:'tennis racket',39:'bottle',40:'wine glass',
                        41:'cup',42:'fork',43:'knife',44:'spoon',45:'bowl',46:'banana',47:'apple',48:'sandwich',49:'orange',50:'broccoli',
                        51:'carrot',52:'hot dog',53:'pizza',54:'donut',55:'cake',56:'chair',57:'sofa',58:'pottedplant',59:'bed',60:'diningtable',
                        61:'toilet',62:'tvmonitor',63:'laptop',64:'mouse',65:'remote',66:'keyboard',67:'cell phone',68:'microwave',69:'oven',70:'toaster',
                        71:'sink',72:'refrigerator',73:'book',74:'clock',75:'vase',76:'scissors',77:'teddy bear',78:'hair drier',79:'toothbrush' }

labels_to_names = {1:'person',2:'bicycle',3:'car',4:'motorcycle',5:'airplane',6:'bus',7:'train',8:'truck',9:'boat',10:'traffic light',
                    11:'fire hydrant',12:'street sign',13:'stop sign',14:'parking meter',15:'bench',16:'bird',17:'cat',18:'dog',19:'horse',20:'sheep',
                    21:'cow',22:'elephant',23:'bear',24:'zebra',25:'giraffe',26:'hat',27:'backpack',28:'umbrella',29:'shoe',30:'eye glasses',
                    31:'handbag',32:'tie',33:'suitcase',34:'frisbee',35:'skis',36:'snowboard',37:'sports ball',38:'kite',39:'baseball bat',40:'baseball glove',
                    41:'skateboard',42:'surfboard',43:'tennis racket',44:'bottle',45:'plate',46:'wine glass',47:'cup',48:'fork',49:'knife',50:'spoon',
                    51:'bowl',52:'banana',53:'apple',54:'sandwich',55:'orange',56:'broccoli',57:'carrot',58:'hot dog',59:'pizza',60:'donut',
                    61:'cake',62:'chair',63:'couch',64:'potted plant',65:'bed',66:'mirror',67:'dining table',68:'window',69:'desk',70:'toilet',
                    71:'door',72:'tv',73:'laptop',74:'mouse',75:'remote',76:'keyboard',77:'cell phone',78:'microwave',79:'oven',80:'toaster',
                    81:'sink',82:'refrigerator',83:'blender',84:'book',85:'clock',86:'vase',87:'scissors',88:'teddy bear',89:'hair drier',90:'toothbrush',
                    91:'hair brush'}
import numpy as np

# np.where 사용법 예시.
arr1 = np.array([[3.75348572e+02, 1.19171005e+02, 3.81950867e+02, 1.34460617e+02,
         1.35454759e-01],
        [5.32362000e+02, 1.09554726e+02, 5.40526550e+02, 1.25222633e+02,
         8.88786465e-01],
        [3.61124298e+02, 1.09049202e+02, 3.68625610e+02, 1.22483063e+02,
         7.20717013e-02]], dtype=np.float32)
print(arr1.shape)

arr1_filtered = arr1[np.where(arr1[:, 4] > 0.1)] # 0.1 보다 큰것만 저장
print('### arr1_filtered:', arr1_filtered, arr1_filtered.shape)

(3, 5) # 2차원으로
### arr1_filtered: [[3.75348572e+02 1.19171005e+02 3.81950867e+02 1.34460617e+02
  1.35454759e-01]
 [5.32362000e+02 1.09554726e+02 5.40526550e+02 1.25222633e+02
  8.88786495e-01]] (2, 5)
np.where(arr1[:, 4] > 0.1) # row는 전부, 4:class confidence 가 0.1보다 큰 경우
# (array([0, 1]),)
# row 기준으로
# model과 원본 이미지 array, filtering할 기준 class confidence score를 인자로 가지는 inference 시각화용 함수 생성. 
def get_detected_img(model, img_array,  score_threshold=0.3, is_print=True):
  # 인자로 들어온 image_array를 복사. 
  draw_img = img_array.copy()
  bbox_color=(0, 255, 0)
  text_color=(0, 0, 255)

  # model과 image array를 입력 인자로 inference detection 수행하고 결과를 results로 받음. 
  # results는 80개의 2차원 array(shape=(오브젝트갯수, 5))를 가지는 list. 
  results = inference_detector(model, img_array)

  # 80개의 array원소를 가지는 results 리스트를 loop를 돌면서 개별 2차원 array들을 추출하고 이를 기반으로 이미지 시각화 
  # results 리스트의 위치 index가 바로 COCO 매핑된 Class id. 여기서는 result_ind가 class id
  # 개별 2차원 array에 오브젝트별 좌표와 class confidence score 값을 가짐. 
  for result_ind, result in enumerate(results):
    # 개별 2차원 array의 row size가 0 이면 해당 Class id로 값이 없으므로 다음 loop로 진행. 
    if len(result) == 0:
      continue
    
    # 2차원 array에서 5번째 컬럼에 해당하는 값이 score threshold이며 이 값이 함수 인자로 들어온 score_threshold 보다 낮은 경우는 제외. 
    result_filtered = result[np.where(result[:, 4] > score_threshold)]
    
    # 해당 클래스 별로 Detect된 여러개의 오브젝트 정보가 2차원 array에 담겨 있으며, 이 2차원 array를 row수만큼 iteration해서 개별 오브젝트의 좌표값 추출. 
    for i in range(len(result_filtered)):
      # 좌상단, 우하단 좌표 추출. 
      left = int(result_filtered[i, 0])
      top = int(result_filtered[i, 1])
      right = int(result_filtered[i, 2])
      bottom = int(result_filtered[i, 3])
      
      caption = "{}: {:.4f}".format(labels_to_names_seq[result_ind], result_filtered[i, 4])
      cv2.rectangle(draw_img, (left, top), (right, bottom), color=bbox_color, thickness=2)
      cv2.putText(draw_img, caption, (int(left), int(top - 7)), cv2.FONT_HERSHEY_SIMPLEX, 0.37, text_color, 1)
      if is_print:
        print(caption)

  return draw_img
import matplotlib.pyplot as plt

img_arr = cv2.imread('/content/mmdetection/demo/demo.jpg')
detected_img = get_detected_img(model, img_arr,  score_threshold=0.3, is_print=True)
# detect 입력된 이미지는 bgr임. 이를 최종 출력시 rgb로 변환 
detected_img = cv2.cvtColor(detected_img, cv2.COLOR_BGR2RGB)

plt.figure(figsize=(12, 12))
plt.imshow(detected_img)

/usr/local/lib/python3.7/dist-packages/mmdet-2.17.0-py3.7.egg/mmdet/core/anchor/anchor_generator.py:324: UserWarning: ``grid_anchors`` would be deprecated soon. Please use ``grid_priors`` 
  warnings.warn('``grid_anchors`` would be deprecated soon. '
car: 0.9888
car: 0.9872
car: 0.9832
car: 0.9713
car: 0.9678
car: 0.9594
car: 0.9593
car: 0.9568
car: 0.9510
car: 0.9458
car: 0.9440
car: 0.9331
car: 0.8663
car: 0.8268
car: 0.7535
car: 0.7166
car: 0.6008
car: 0.5920
car: 0.5540
car: 0.5435
car: 0.4768
car: 0.4612
car: 0.4010
car: 0.3439
bench: 0.9778
bench: 0.4170
chair: 0.7779
/usr/local/lib/python3.7/dist-packages/mmdet-2.17.0-py3.7.egg/mmdet/core/anchor/anchor_generator.py:361: UserWarning: ``single_level_grid_anchors`` would be deprecated soon. Please use ``single_level_grid_priors`` 
  '``single_level_grid_anchors`` would be deprecated soon. '
<matplotlib.image.AxesImage at 0x7f7f78bc4a50>

!mkdir data
!wget -O /content/data/beatles01.jpg https://raw.githubusercontent.com/chulminkw/DLCV/master/data/image/beatles01.jpg
!ls -lia /content/data/beatles01.jpg
img_arr = cv2.imread('/content/data/beatles01.jpg')
detected_img = get_detected_img(model, img_arr,  score_threshold=0.5, is_print=True)
# detect 입력된 이미지는 bgr임. 이를 최종 출력시 rgb로 변환 
detected_img = cv2.cvtColor(detected_img, cv2.COLOR_BGR2RGB)

plt.figure(figsize=(12, 12))
plt.imshow(detected_img)

/usr/local/lib/python3.7/dist-packages/mmdet-2.17.0-py3.7.egg/mmdet/core/anchor/anchor_generator.py:324: UserWarning: ``grid_anchors`` would be deprecated soon. Please use ``grid_priors`` 
  warnings.warn('``grid_anchors`` would be deprecated soon. '
person: 0.9988
person: 0.9982
person: 0.9980
person: 0.9971
person: 0.9604
car: 0.9693
car: 0.9686
car: 0.9648
car: 0.9517
car: 0.9254
car: 0.9030
car: 0.8312
car: 0.8008
car: 0.7331
car: 0.6208
tie: 0.5924
/usr/local/lib/python3.7/dist-packages/mmdet-2.17.0-py3.7.egg/mmdet/core/anchor/anchor_generator.py:361: UserWarning: ``single_level_grid_anchors`` would be deprecated soon. Please use ``single_level_grid_priors`` 
  '``single_level_grid_anchors`` would be deprecated soon. '
<matplotlib.image.AxesImage at 0x7f7f78bf2e50>

 

반응형
728x90
반응형

Computer Vision Footprint

1998 - LeNet 5

 

2012 - AlexNet

- Gradient vanishin문제를 해결하는 ReLU를 사용 - LRN 사용 안했음

- Overlapping Pooling(영향력이 크진 않음)

- Dropout(Overfitting 방지)

 

2013 - ZFNet

- AlexNet을 Visualization통해 insight를 제공

- HyperParameter tuning 방법론 제시

- Network in Network

- 1x1 Convolution 도입 (1. 차원 조절 2. non-linear 특성 부여 3. fully connected 처럼 사용)

- Flatten 대신 사용하는 방법인 Global Average Pooling 도입

- 같은 형태를 반복하고 겹쳐서 사용하는 Stacking 도입

 

2014 - GoogLeNet v1 (1등)

- 1x1 convolution 활용

- Inception module stacking

- Global average pooling 활용

- VGG (2등)

 

2016 - GoogLeNet v4

GoogLeNet

ReLU와 같은 기법 덕에 Layer를 깊게 쌓을 수 있는 확신이 있었던 배경 때문에 Layer를 어떻게 깊게 쌓는지 여부가 중요한 포인트였다

GoogLeNet 특징

1. 1x1 convolution

- 차원 축소 효과

- nonlinearity 특징 부여

2. Inception module

- 9 inception module로 구성되어 있다

- Inception moddule은 Hebbian rule에 의해 영향력이 가장 부분이 연결성이 강화된다(weight가 커진다)

- 실제 구현에서는 차원을 조절하여 inception module을 적용하였다

3. Global average pooling

4. Auxiliary classifier

- relu로 gradient vanishing 문제를 해결한듯 했으나 layer가 기존에 8 layer였던것에 비해 22 layer로 급격하게 늘었기 때문에 gradient vanishing 가능성이 생겼다

- 따라서 네트워크 중간에 auxiliary classifier를 추가하여 중간 중간 결과를 낸다

Inception module

import tensorflow as tf 

(X_train, y_train), (X_test, y_test) = tf.keras.datasets.cifar10.load_data()

# Inception module, naive version
input_ = tf.keras.Input((32,32,3))
conv1x1 = tf.keras.layers.Conv2D(3,1, padding='same', name='1x1')(input_) 
conv3x3 = tf.keras.layers.Conv2D(3,3, padding='same', name='3x3')(input_) 
conv5x5 = tf.keras.layers.Conv2D(3,3, padding='same', name='5x5')(input_) 
maxpool = tf.keras.layers.MaxPool2D(3,1, padding='same', name='pool')(input_) # unoverlapping 
concatenate = tf.keras.layers.Concatenate()([conv1x1,conv3x3,conv5x5,maxpool]) # 합치기 위해서 구조를 맞추어야 한다 

model = tf.keras.models.Model(input_, concatenate)
model.summary()
# Model: "model_13"
# __________________________________________________________________________________________________
# Layer (type)                    Output Shape         Param #     Connected to                     
# ==================================================================================================
# input_24 (InputLayer)           [(None, 32, 32, 3)]  0                                            
# __________________________________________________________________________________________________
# 1x1 (Conv2D)                    (None, 32, 32, 3)    12          input_24[0][0]                   
# __________________________________________________________________________________________________
# 3x3 (Conv2D)                    (None, 32, 32, 3)    84          input_24[0][0]                   
# __________________________________________________________________________________________________
# 5x5 (Conv2D)                    (None, 32, 32, 3)    84          input_24[0][0]                   
# __________________________________________________________________________________________________
# pool (MaxPooling2D)             (None, 32, 32, 3)    0           input_24[0][0]                   
# __________________________________________________________________________________________________
# concatenate_15 (Concatenate)    (None, 32, 32, 12)   0           1x1[0][0]                        
#                                                                  3x3[0][0]                        
#                                                                  5x5[0][0]                        
#                                                                  pool[0][0]                       
# ==================================================================================================
# Total params: 180
# Trainable params: 180
# Non-trainable params: 0
# __________________________________________________________________________________________________
tf.keras.utils.plot_model(model, show_shapes=True)

 

 

# Inception module with dimension reductions
input_ = tf.keras.Input((32,32,3))
conv1x1 = tf.keras.layers.Conv2D(3,1, padding='same', name='1x1')(input_) 
conv1x1_reduc3x3 = tf.keras.layers.Conv2D(2,1, padding='same', name='1x1_3x3')(input_) 
conv3x3 = tf.keras.layers.Conv2D(2,3, padding='same', name='3x3')(conv1x1_reduc3x3) 
conv1x1_reduc5x5 = tf.keras.layers.Conv2D(2,1, padding='same', name='1x1_5x5')(input_) 
conv5x5 = tf.keras.layers.Conv2D(2,3, padding='same', name='5x5')(conv1x1_reduc5x5) 
maxpool = tf.keras.layers.MaxPool2D(2,1, padding='same', name='pool')(input_) 
conv1x1_reduc_mp = tf.keras.layers.Conv2D(2,1, padding='same', name='1x1_pool')(maxpool) 
concatenate = tf.keras.layers.Concatenate(axis=-1)([conv1x1,conv3x3,conv5x5,conv1x1_reduc_mp]) # 합치기 위해서 구조를 맞추어야 한다 
# concatenate = tf.keras.layers.Concatenate([conv1x1,conv3x3,conv5x5,conv1x1_reduc_mp]) # 옵션을 주지 않을때 

model = tf.keras.models.Model(input_, concatenate)
model.summary()
# Model: "model_14"
# __________________________________________________________________________________________________
# Layer (type)                    Output Shape         Param #     Connected to                     
# ==================================================================================================
# input_25 (InputLayer)           [(None, 32, 32, 3)]  0                                            
# __________________________________________________________________________________________________
# 1x1_3x3 (Conv2D)                (None, 32, 32, 2)    8           input_25[0][0]                   
# __________________________________________________________________________________________________
# 1x1_5x5 (Conv2D)                (None, 32, 32, 2)    8           input_25[0][0]                   
# __________________________________________________________________________________________________
# pool (MaxPooling2D)             (None, 32, 32, 3)    0           input_25[0][0]                   
# __________________________________________________________________________________________________
# 1x1 (Conv2D)                    (None, 32, 32, 3)    12          input_25[0][0]                   
# __________________________________________________________________________________________________
# 3x3 (Conv2D)                    (None, 32, 32, 2)    38          1x1_3x3[0][0]                    
# __________________________________________________________________________________________________
# 5x5 (Conv2D)                    (None, 32, 32, 2)    38          1x1_5x5[0][0]                    
# __________________________________________________________________________________________________
# 1x1_pool (Conv2D)               (None, 32, 32, 2)    8           pool[0][0]                       
# __________________________________________________________________________________________________
# concatenate_16 (Concatenate)    (None, 32, 32, 9)    0           1x1[0][0]                        
#                                                                  3x3[0][0]                        
#                                                                  5x5[0][0]                        
#                                                                  1x1_pool[0][0]                   
# ==================================================================================================
# Total params: 112
# Trainable params: 112
# Non-trainable params: 0
# __________________________________________________________________________________________________
tf.keras.utils.plot_model(model, show_shapes=True, rankdir="BT", show_dtype=True) # wide하게 분포되어 있기 때문에 parameter operator가 엄청 많다 / 이중에서 영향력 있는 것만 강한 연결성을 띄게 된다

in3 = tf.keras.applications.InceptionV3()

tf.keras.utils.plot_model(in3)

Visual Geometry Group

Very Deep Convolutional Networks for large-scale image recognition

Layer가 깊어지면 깊어질 수 록 성능이 좋아진다

Abliation study 방식으로 모델 성능을 비교한다

 

1. AlexNet vs AlexNet + LRN

- LRN 기법은 성능 개선은 없고 메모리 사용량 및 연산 시간만 늘어났기에 사용을 하지 않는다

2. AlexNet vs AlexNet + conv layer 2개 추가

- 성능 좋아짐

3. AlexNet + conv layer 2개 vs AlexNet + conv layer 2개 + 1x1 convolution 3개

- Nonlinearity만 추가 시켜 성능향상을 하는지 확인 => activation이 더 많아서 성능 더 좋아짐 (UAT)

4. AlexNet + conv layer 2개 + 1x1 convolution 3개 vs AlexNet + conv layer 5개

- 성능 좋아짐

5. AlexNet + conv layer 5개 vs AlexNet + conv layer 8개

- 성능 좋아짐

결국 Layer가 늘어나면 늘어날 수록 성능이 좋아졌다

 

 

 

model을 불러와 사용하는 두 가지 방식

1. applications => Computer vision 분야에서 지원되는 모델을 지원한다

2. tensorflow hub

import tensorflow as tf 

vgg16 = tf.keras.applications.VGG16() # ImageNet 대회서 2등, 학습된 모델을 그대로 사용할 수 있다  

vgg16.summary()
# Model: "vgg16"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_2 (InputLayer)         [(None, 224, 224, 3)]     0         
# _________________________________________________________________
# block1_conv1 (Conv2D)        (None, 224, 224, 64)      1792      
# _________________________________________________________________
# block1_conv2 (Conv2D)        (None, 224, 224, 64)      36928     
# _________________________________________________________________
# block1_pool (MaxPooling2D)   (None, 112, 112, 64)      0         
# _________________________________________________________________
# block2_conv1 (Conv2D)        (None, 112, 112, 128)     73856     
# _________________________________________________________________
# block2_conv2 (Conv2D)        (None, 112, 112, 128)     147584    
# _________________________________________________________________
# block2_pool (MaxPooling2D)   (None, 56, 56, 128)       0         
# _________________________________________________________________
# block3_conv1 (Conv2D)        (None, 56, 56, 256)       295168    
# _________________________________________________________________
# block3_conv2 (Conv2D)        (None, 56, 56, 256)       590080    
# _________________________________________________________________
# block3_conv3 (Conv2D)        (None, 56, 56, 256)       590080    
# _________________________________________________________________
# block3_pool (MaxPooling2D)   (None, 28, 28, 256)       0         
# _________________________________________________________________
# block4_conv1 (Conv2D)        (None, 28, 28, 512)       1180160   
# _________________________________________________________________
# block4_conv2 (Conv2D)        (None, 28, 28, 512)       2359808   
# _________________________________________________________________
# block4_conv3 (Conv2D)        (None, 28, 28, 512)       2359808   
# _________________________________________________________________
# block4_pool (MaxPooling2D)   (None, 14, 14, 512)       0         
# _________________________________________________________________
# block5_conv1 (Conv2D)        (None, 14, 14, 512)       2359808   
# _________________________________________________________________
# block5_conv2 (Conv2D)        (None, 14, 14, 512)       2359808   
# _________________________________________________________________
# block5_conv3 (Conv2D)        (None, 14, 14, 512)       2359808   
# _________________________________________________________________
# block5_pool (MaxPooling2D)   (None, 7, 7, 512)         0         
# _________________________________________________________________
# flatten (Flatten)            (None, 25088)             0         
# _________________________________________________________________
# fc1 (Dense)                  (None, 4096)              102764544 
# _________________________________________________________________
# fc2 (Dense)                  (None, 4096)              16781312  
# _________________________________________________________________
# predictions (Dense)          (None, 1000)              4097000   
# =================================================================
# Total params: 138,357,544
# Trainable params: 138,357,544
# Non-trainable params: 0
# _________________________________________________________________
vgg16.weights

vgg16.__class__
# keras.engine.functional.Functional

3x3을 쓰는 이유

(X_train, y_train), (X_test, y_test) = tf.keras.datasets.cifar10.load_data()

input_ = tf.keras.Input((32,32,3))
x = tf.keras.layers.Conv2D(2,5)(input_) # filter 2개 5x5 
model = tf.keras.models.Model(input_, x)

model.summary()
# Model: "model"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_4 (InputLayer)         [(None, 32, 32, 3)]       0         
# _________________________________________________________________
# conv2d (Conv2D)              (None, 28, 28, 2)         152       
# =================================================================
# Total params: 152
# Trainable params: 152
# Non-trainable params: 0
# _________________________________________________________________
input_ = tf.keras.Input((32,32,3))
x = tf.keras.layers.Conv2D(2,3)(input_) 
x = tf.keras.layers.Conv2D(2,3)(x) 
model = tf.keras.models.Model(input_, x)

model.summary() # 3x3이 더 좋다 / 5x5일 때와 shape은 같지만 activation을 여러개 사용했고 파라미터 수가 줄어들었기 때문에 성능이 더 좋아졌다 
# Model: "model_15"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_27 (InputLayer)        [(None, 32, 32, 3)]       0         
# _________________________________________________________________
# conv2d_221 (Conv2D)          (None, 30, 30, 2)         56        
# _________________________________________________________________
# conv2d_222 (Conv2D)          (None, 28, 28, 2)         38        
# =================================================================
# Total params: 94
# Trainable params: 94
# Non-trainable params: 0
# _________________________________________________________________
input_ = tf.keras.Input((32,32,3))
x = tf.keras.layers.Conv2D(2,3)(input_) 
x = tf.keras.layers.Conv2D(2,3)(x)
x = tf.keras.layers.Conv2D(2,3)(x) 
model = tf.keras.models.Model(input_, x)

model.summary() # 3x3으로 더 큰 receptive field를 대체 할 수 있다 

# Model: "model_24"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_36 (InputLayer)        [(None, 32, 32, 3)]       0         
# _________________________________________________________________
# conv2d_243 (Conv2D)          (None, 30, 30, 2)         56        
# _________________________________________________________________
# conv2d_244 (Conv2D)          (None, 28, 28, 2)         38        
# _________________________________________________________________
# conv2d_245 (Conv2D)          (None, 26, 26, 2)         38        
# =================================================================
# Total params: 132
# Trainable params: 132
# Non-trainable params: 0
# _________________________________________________________________

보통 첫번째 layer는 5x5 또는 7x7 filter를 사용하고

(처음부터 3x3을 사용하면 메모리를 너무 많이차지 하기 때문에 오히려 성능 저하가 될 수 있다)

그 다음 layer 부터는 3x3을 사용하면 성능이 좋다

Deep Residual Learning for Image Recognition

ResNet은 인간을 뛰어넘은 첫번째 모델
Residual => 실제값 - 예측값 (잔차)

layer가 56개로 깊어지면서 gradient vanishing문제가 다시 떠오르기 시작했다

(relu로 해결되지 못하는 문제가 발생) underfitting

처음에 학습했던 것들을 점차 잊게되면서 목표로 부터 멀어지게 되는 현상이 생겼다

그래서 해결책으로 Short cut 즉, residual block을 도입하게 되었다

 

LSTM에서 아이디어를 얻어 자신의 값을 더함으로써 값을 유지시키고 목표를 잃지 않고 지속적으로 학습하게 된다

 

기존의 신경망은 입력값 x를 타겟값 y로 매핑하는 함수 H(x)를 얻는 것이 목적이었다.

그러나 ResNet은 F(x) + x를 최소화하는 것을 목적으로 한다.

x는 현시점에서 변할 수 없는 값이므로 F(x)를 0에 가깝게 만드는 것이 목적이 된다.

F(x)가 0이 되면 출력과 입력이 모두 x로 같아지게 된다.

F(x) = H(x) - x이므로 F(x)를 최소로 해준다는 것은 H(x) - x를 최소로 해주는 것과 동일한 의미를 지닌다.

여기서 H(x) - x를 잔차(residual)라고 한다.

즉, 잔차를 최소로 해주는 것이므로 ResNet이란 이름이 붙게 된다.

 

Batch Normalization 사용 => underfitting을 막아주면서 dropout을 사용하지 않고 좋은 성능을 얻게 되었다

vgg19와 34-layer plain을 비교했을 때 34-layer는 가장 앞 layer에서 7x7 filter를 적용했고 레이어 수를 두 배 가까이 늘렸다

그리고 맨마지막에 flatten을 쓰지 않고 average pooling을 사용했더니 34-layer가 성능이 더 좋았다

더 나아가 34-layer에서 residual block을 추가한 결과 추가하지 않은 것보다 오차율이 감소한 것을 확인할 수 있었다

Residual block과 Batch Normalization의 조합으로 훨씬 더 깊은 layer가 가능해졌다

결국 총 152 layer를 쌓을 수 있게 되었다

반응형
728x90
반응형

Visualizing and Understanding Convolutional Networks

CNN을 제대로 이해하기 위한 논문
CNN을 시각화 하여 왜 성능이 향상되었는지를 탐구하는 논문
과거의 관점으로 AlexNet에 대한 '통찰'과 '진단'을 제공한다

Convolutional layer를 통과하고나서 Max pooling을 거칠때 가장 영향력 있는 값들로 축약되기 때문에 큰 특징만 남게 된다

따라서 반대로 pooling을 거치기 전으로 복원시킨다면 큰 특징만 남아 있기 때문에 Detail한 특징들은 사라지게 될 것이다

AlexNet의 네트워크 구조대로 통과시킨 데이터들을 레이어 별로 복원시키게 되면

가장 중요한 특징들만 남도록 복원된다는 것을 시각적으로 확인 있다

 

시각화된 결과를 보면 AlexNet의 구조는 처음 레이어에서 간단한 특징들을 뽑아내다가

레이어가 깊어지면 깊어질 수록 '복잡한 특징' 구분할 있도록 학습이 되는 것을 있다

기존 AlexNet의 첫번째 Layer에서 filter 11x11, stride 4를 filter 7x7, stride 2로 바꾸었다

두번째 layer에서는 stride 1, zero-padding 2에서 stride 2로 바꾸었다

=> 기존에는 filter가 컸기 때문에 작은 것들의 특징을 잘 못잡는다는 문제가 있었다

 

결과 => 파라미터가 줄어들었고, 좀 더 디테일한 특징을 알아낼 수 있도록 학습하게되었다

receptive field를 대신할 수 있다 @@@ 의미 확인

일부분을 가림으로써 어떤 부분이 가장 영향력이 있는지를 확률적으로 계산하였다 (abliation study)

특정 부분을 가렸을 때 가장 성능이 안좋다면 그 부분은 가장 영향력이 있는 부분인 것이다 (파란색 부분이 가장 영향력 있는 부분)

a와 c는 AlexNet b와 d는 ZFNet

 

Layer 1

a 그림에서는 dead feature가 꽤 있고 좀 더 흐릿하게 구분된 반면

c 그림에서는 dead feature가 굉장히 많이 줄고 특징이 좀 더 선명하게 구분되었다

filter사이즈와 stride를 줄임으로써 좀 더 특징을 잘 구분할 수 있게 학습이되었다고 할 수 있다

 

Layer 2

c 그림에서 보면 빈 공간이 많고 aliasing(계단현상)이 발견된 반면

d 그림에서는 빈 공간이 적고 특징이 더 선명하게 잘 구분되도록 학습이 되었다

Network In Network

네트워크 안에 네트워크를 넣는 방식
convolution layer사이에 mlp가 있다 (사실상 1x1 convolution을 사용한 것)

Flatten의 문제

import tensorflow as tf 

(X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()

X_train = X_train.reshape(-1,28,28,1)/255

# AlexNet
 
input_ = tf.keras.Input((224,224,3))
x = tf.keras.layers.Conv2D(96,11,4)(input_)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Conv2D(256, 5, padding='same')(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.MaxPool2D(3,2)(x)
x = tf.keras.layers.Conv2D(384,3)(x) 
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.MaxPool2D(3,2)(x)
x = tf.keras.layers.Conv2D(384,3)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Conv2D(256, 3)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.MaxPool2D(3,2)(x)
x = tf.keras.layers.Flatten()(x) # 일렬로 만들어 지기 때문에 위치 정보를 잃고 학습할 weight가 많이 생긴다 (FC만 썼을때 위치정보를 잃는다)
x = tf.keras.layers.Dense(4096)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Dropout(0.5)(x)
x = tf.keras.layers.Dense(4096, kernel_initializer=tf.keras.initializers.Constant(1))(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Dropout(0.5)(x)
x = tf.keras.layers.Dense(1000, activation='softmax')(x)

model = tf.keras.models.Model(input_,x)
model.summary()

# Model: "model_1"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_2 (InputLayer)         [(None, 224, 224, 3)]     0         
# _________________________________________________________________
# conv2d_5 (Conv2D)            (None, 54, 54, 96)        34944     
# _________________________________________________________________
# re_lu_6 (ReLU)               (None, 54, 54, 96)        0         
# _________________________________________________________________
# conv2d_6 (Conv2D)            (None, 54, 54, 256)       614656    
# _________________________________________________________________
# re_lu_7 (ReLU)               (None, 54, 54, 256)       0         
# _________________________________________________________________
# max_pooling2d_2 (MaxPooling2 (None, 26, 26, 256)       0         
# _________________________________________________________________
# conv2d_7 (Conv2D)            (None, 24, 24, 384)       885120    
# _________________________________________________________________
# re_lu_8 (ReLU)               (None, 24, 24, 384)       0         
# _________________________________________________________________
# max_pooling2d_3 (MaxPooling2 (None, 11, 11, 384)       0         
# _________________________________________________________________
# conv2d_8 (Conv2D)            (None, 9, 9, 384)         1327488   
# _________________________________________________________________
# re_lu_9 (ReLU)               (None, 9, 9, 384)         0         
# _________________________________________________________________
# conv2d_9 (Conv2D)            (None, 7, 7, 256)         884992    
# _________________________________________________________________
# re_lu_10 (ReLU)              (None, 7, 7, 256)         0         
# _________________________________________________________________
# max_pooling2d_4 (MaxPooling2 (None, 3, 3, 256)         0         
# _________________________________________________________________
# flatten_1 (Flatten)          (None, 2304)              0         
# _________________________________________________________________
# dense_3 (Dense)              (None, 4096)              9441280   
# _________________________________________________________________
# re_lu_11 (ReLU)              (None, 4096)              0         
# _________________________________________________________________
# dropout_2 (Dropout)          (None, 4096)              0         
# _________________________________________________________________
# dense_4 (Dense)              (None, 4096)              16781312  
# _________________________________________________________________
# re_lu_12 (ReLU)              (None, 4096)              0         
# _________________________________________________________________
# dropout_3 (Dropout)          (None, 4096)              0         
# _________________________________________________________________
# dense_5 (Dense)              (None, 1000)              4097000   
# =================================================================
# Total params: 34,066,792
# Trainable params: 34,066,792
# Non-trainable params: 0
# _________________________________________________________________

 

 

# AlexNet Flatten x / Global average pooling 
 
input_ = tf.keras.Input((224,224,3))
x = tf.keras.layers.Conv2D(96,11,4)(input_)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Conv2D(256, 5, padding='same')(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.MaxPool2D(3,2)(x)
x = tf.keras.layers.Conv2D(384,3)(x) 
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.MaxPool2D(3,2)(x)
x = tf.keras.layers.Conv2D(384,3)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Conv2D(256, 3)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.MaxPool2D(3,2)(x)
x = tf.keras.layers.Conv2D(1000, 3)(x) # 1x1 convolution 
x = tf.keras.layers.GlobalAveragePooling2D()(x) # 1차원으로  바뀌었기 때문에 Flatten과 똑같다. 하지만 Flatten보다 Parameter를 훨씬 줄일 수 있다 
x = tf.keras.layers.Dense(1000)(x)

model = tf.keras.models.Model(input_,x)
model.summary()

# Model: "model_6"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_8 (InputLayer)         [(None, 224, 224, 3)]     0         
# _________________________________________________________________
# conv2d_35 (Conv2D)           (None, 54, 54, 96)        34944     
# _________________________________________________________________
# re_lu_42 (ReLU)              (None, 54, 54, 96)        0         
# _________________________________________________________________
# conv2d_36 (Conv2D)           (None, 54, 54, 256)       614656    
# _________________________________________________________________
# re_lu_43 (ReLU)              (None, 54, 54, 256)       0         
# _________________________________________________________________
# max_pooling2d_20 (MaxPooling (None, 26, 26, 256)       0         
# _________________________________________________________________
# conv2d_37 (Conv2D)           (None, 24, 24, 384)       885120    
# _________________________________________________________________
# re_lu_44 (ReLU)              (None, 24, 24, 384)       0         
# _________________________________________________________________
# max_pooling2d_21 (MaxPooling (None, 11, 11, 384)       0         
# _________________________________________________________________
# conv2d_38 (Conv2D)           (None, 9, 9, 384)         1327488   
# _________________________________________________________________
# re_lu_45 (ReLU)              (None, 9, 9, 384)         0         
# _________________________________________________________________
# conv2d_39 (Conv2D)           (None, 7, 7, 256)         884992    
# _________________________________________________________________
# re_lu_46 (ReLU)              (None, 7, 7, 256)         0         
# _________________________________________________________________
# max_pooling2d_22 (MaxPooling (None, 3, 3, 256)         0         
# _________________________________________________________________
# conv2d_40 (Conv2D)           (None, 1, 1, 1000)        2305000   
# _________________________________________________________________
# global_average_pooling2d_2 ( (None, 1000)              0         
# _________________________________________________________________
# dense_13 (Dense)             (None, 1000)              1001000   
# =================================================================
# Total params: 7,053,200
# Trainable params: 7,053,200
# Non-trainable params: 0
# _________________________________________________________________

Flatten vs Global Average Pooling

Flatten은 원본 데이터 그대로 1차원으로 변화 시키지만 GAP은 최종결과에서 평균을 내어 하나의 값으로 바꾸고 그 형태가 1차원으로 변화된다

GAP는 전체 값 중에서 noise나 outlier등 학습이 안된 것들을 뭉뚱그리기 때문에 오히려 성능이 향상 되는 경우가 있다

 

GAP는 전체를 반영하기 때문에 Flatten한 것 보다 값을 더 잘 반영 하는 경우가 있지만

weight가 줄어들기 때문에 하나의 관점보다 여러개의 관점으로 파악하는 경우가 성능이 좋은 경우가 있을 수 있다

따라서 경우에 따라서 결정해야 할 문제이다

Hyperparameter처럼 데이터에 따라서 직접 정해줘야 한다

Grouped Convolution

Grouped Convolution은 입력 값의 채널들을 여러 개의 그룹으로 나누어 독립적으로 Convolution 연산을 수행하는 방식이다.

모델이 복잡할때 parameter를 줄이기 위해서 사용하는 경우가 있다

1x1 Convolution

Point-wise Convolution

1. 1x1의 depth에 따라서 차원이 바뀐다

2. Non-linear 특징을 부여한다

3. Fully connected 처럼 사용한다

GoogLeNet

1. Network in Network (1x1 convolution)

2. Stacking

3. Global average pooling

 

GoogLeNet은 3가지 내용을 참고하여 만들어졌다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
728x90
반응형

논문 구현

import tensorflow as tf 

input_ = tf.keras.Input(shape=(32,32,1))
x = tf.keras.layers.Conv2D(6, 5, activation='tanh')(input_) # filter 개수, filter 크기 / stride는 생략되었기 때문에 1이라 가정한다 / padding: valid
x = tf.keras.layers.AvgPool2D(2)(x) # 기본적으로 non-overlapping 방식이다 
x = tf.keras.layers.Conv2D(16, 5, activation='tanh')(x)
x = tf.keras.layers.MaxPool2D(6, 5)(x)
x = tf.keras.layers.Flatten()(x)
x = tf.keras.layers.Dense(120, activation='tanh')(x)
x = tf.keras.layers.Dense(84, activation='tanh')(x)
x = tf.keras.layers.Dense(10, activation='softmax')(x)

model = tf.keras.models.Model(input_, x)
# pooling 사용했을 때 
model.summary()
# Model: "model_1"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_3 (InputLayer)         [(None, 32, 32, 1)]       0         
# _________________________________________________________________
# conv2d_1 (Conv2D)            (None, 28, 28, 6)         156       
# _________________________________________________________________
# average_pooling2d (AveragePo (None, 14, 14, 6)         0         
# _________________________________________________________________
# conv2d_2 (Conv2D)            (None, 10, 10, 16)        2416      
# _________________________________________________________________
# max_pooling2d (MaxPooling2D) (None, 1, 1, 16)          0         
# _________________________________________________________________
# flatten (Flatten)            (None, 16)                0         
# _________________________________________________________________
# dense (Dense)                (None, 120)               2040      
# _________________________________________________________________
# dense_1 (Dense)              (None, 84)                10164     
# _________________________________________________________________
# dense_2 (Dense)              (None, 10)                850       
# =================================================================
# Total params: 15,626
# Trainable params: 15,626
# Non-trainable params: 0
# _________________________________________________________________
# pooling 사용하지 않았을 때 
model.summary()

# Model: "model_3"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_5 (InputLayer)         [(None, 32, 32, 1)]       0         
# _________________________________________________________________
# conv2d_5 (Conv2D)            (None, 28, 28, 6)         156       
# _________________________________________________________________
# conv2d_6 (Conv2D)            (None, 24, 24, 16)        2416      
# _________________________________________________________________
# flatten_2 (Flatten)          (None, 9216)              0         
# _________________________________________________________________
# dense_6 (Dense)              (None, 120)               1106040   
# _________________________________________________________________
# dense_7 (Dense)              (None, 84)                10164     
# _________________________________________________________________
# dense_8 (Dense)              (None, 10)                850       
# =================================================================
# Total params: 1,119,626
# Trainable params: 1,119,626
# Non-trainable params: 0
# _________________________________________________________________

ImageNet Classification with Deep Convolutional Neural Networks

ImageNet LSVRC 대회에서 ImageNet 데이터를 사용한 CNN

Relu

ReLU는 Sigmoid와 tanh가 갖는 Gradient Vanishing 문제를 해결하기 위한 함수이다

ReLU는 sigmoid, tanh 함수보다 학습이 빠르고, 연산 비용이 적고, 구현이 매우 간단하다

Dying Relu

Dying relu는 모든 0이하의 입력에 대해서 미분 값이 0이 되어 가중치에 곱해지면서 해당 노드가 통째로 죽어버리는 현상을 말한다

이러한 단점을 보완한 reaky relu가 있다

Normalization

layer가 깊어질 수록 값의 범위가 매번 바뀌고 최소값으로 수렴이 안되는 underfitting이 발생한다

이런 경우를 방지하기 위해서 값의 범위를 일정하게 맞춰주는 방법이 바로 normalization이다

 

대표적인 정규화 방법 가지

1. Min-Max Normalization (최소-최대 정규화)

- 최소값은 0, 최대값은 1, 그리고 다른 값들은 0 1 사이의 값으로 변환하는 방식

- (data - MIN) / (MAX-MIN) 2. Z-Score Normalization (Z-점수 정규화)

- 평균은 0, 표준편차는 1 정규 분포를 그리도록 데이터의 분포를 바꾸는 방식

- 이상치(outlier) 문제를 피하는 데이터 정규화 전략-

- (data - 평균) / 표준편차

Pooling

1. overlapping pooling

- 겹쳐가며 pooling을 하는 방법

- 성능에 크게 영향을 미치는 방법은 아니다

2. non overlapping pooling

- 겹치지 않고 pooling을 하는 방법

pooling을 하는 이유

1. parameter 줄여주기 때문에 연산량을 줄여준다

2. invariance한 속성을 더해준다

Data augmentation

Overfitting을 줄이기 위한 방법으로써 이미지 데이터를 변형해서 학습 데이터의 수를 늘리는 방법이다

이미지 데이터를 좌우반전, 상하반전, 회전, 자르기 등을 하여 학습하지 않은 데이터를 대처할 수 있는 일반적인 모델을 만들어주는 데에 효과적인 방법이다

예시

 

Dropout

Dropout은 특정 확률로 hidden layer의 node 출력값을 0으로 설정하는 방법이다 이렇게 dropout된 node들은 foward, backward propagation에 관여를 하지 않는다 dropout이 사용된 NN는 입력이 주어질 때마다 달라진 신경망 구조를 거치게 되고 이는 노드간의 의존성을 약화시켜 가장 영향력 있는 노드의 연결성이 강화되는 방식으로 학습을 하게된다 따라서 성능은 비슷하지만 연산 복잡도를 줄이면서 overfitting 문제를 해결하는 방법이 될 수 있다 ※ Fully connected layer 다음에 Dropuout을 사용한다

Result

Ensemble기법을 사용하고 pre-trained 모델인 경우에 에러율이 더 낮았다

※ CNNs는 Boosting기법(Ensemble)을 사용한 방법

AlexNet

논문 구현

하드웨어 메모리가 부족하여 GPU 병렬 연산을 위해 CNN 구조를 절반으로 나누어 설계되었다

# 평균은 0, 표준분포는 0.01인 정규분포 값으로 가중치를 초기화 한다 
bias = tf.keras.initializers.Constant(1) # relu 때문에 초기화 값을 1로 지정한다 (음수가 들어가면 dying relu현상이 발생하기 때문)

input_ = tf.keras.Input((224,224,3))
x = tf.keras.layers.Conv2D(96,5,4)(input_)
x = tf.keras.layers.MaxPool2D(3,2)(x) # overlapping pooling
x = tf.keras.layers.Conv2D(256,3, padding='same', bias_initializer=bias)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.MaxPool2D(3,2)(x)
x = tf.keras.layers.Conv2D(384,3, padding='same', bias_initializer='ones')(x) # ones 단축키는 버전에따라 지원하지 않을 수 있다 -
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Conv2D(384,3, padding='same', bias_initializer=bias)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Conv2D(256,3, padding='same', bias_initializer=bias)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Flatten()(x)
x = tf.keras.layers.Dense(4096, bias_initializer=bias)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Dropout(0.5)(x)
x = tf.keras.layers.Dense(4096, bias_initializer=bias)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Dropout(0.5)(x)
x = tf.keras.layers.Dense(1000, bias_initializer=bias, activation='softmax')(x)
model = tf.keras.models.Model(input_,x) # tensorflow from_logit
model.summary()
# Model: "model_3"
# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_4 (InputLayer)         [(None, 224, 224, 3)]     0         
# _________________________________________________________________
# conv2d_15 (Conv2D)           (None, 55, 55, 96)        7296      
# _________________________________________________________________
# max_pooling2d_6 (MaxPooling2 (None, 27, 27, 96)        0         
# _________________________________________________________________
# conv2d_16 (Conv2D)           (None, 27, 27, 256)       221440    
# _________________________________________________________________
# re_lu_18 (ReLU)              (None, 27, 27, 256)       0         
# _________________________________________________________________
# max_pooling2d_7 (MaxPooling2 (None, 13, 13, 256)       0         
# _________________________________________________________________
# conv2d_17 (Conv2D)           (None, 13, 13, 384)       885120    
# _________________________________________________________________
# re_lu_19 (ReLU)              (None, 13, 13, 384)       0         
# _________________________________________________________________
# conv2d_18 (Conv2D)           (None, 13, 13, 384)       1327488   
# _________________________________________________________________
# re_lu_20 (ReLU)              (None, 13, 13, 384)       0         
# _________________________________________________________________
# conv2d_19 (Conv2D)           (None, 13, 13, 256)       884992    
# _________________________________________________________________
# re_lu_21 (ReLU)              (None, 13, 13, 256)       0         
# _________________________________________________________________
# flatten_3 (Flatten)          (None, 43264)             0         
# _________________________________________________________________
# dense_9 (Dense)              (None, 4096)              177213440 
# _________________________________________________________________
# re_lu_22 (ReLU)              (None, 4096)              0         
# _________________________________________________________________
# dropout_4 (Dropout)          (None, 4096)              0         
# _________________________________________________________________
# dense_10 (Dense)             (None, 4096)              16781312  
# _________________________________________________________________
# re_lu_23 (ReLU)              (None, 4096)              0         
# _________________________________________________________________
# dropout_5 (Dropout)          (None, 4096)              0         
# _________________________________________________________________
# dense_11 (Dense)             (None, 10)                40970     
# =================================================================
# Total params: 197,362,058
# Trainable params: 197,362,058
# Non-trainable params: 0
# _________________________________________________________________

Loss 3가지

loss function 사용하는 3가지 방법

1. 객체지향 => 옵션 사용 가능

2. 함수형 => 옵션 사용 가능하지만 parital을 사용해야 한다 (Higer order function)

3. 함수형 단축 => 옵션 사용 불가

 

label encoding 방식에 따라서 loss function 방식도 달라져야 한다

- one-hot encoding (Multi label 일때)

- sparse label encoding (Multi label 아닐때) => Sparse가 붙은 loss function 사용

model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False))

tf.keras.utils.to_categorical # label에서 one-hot으로 바꿔준다
# <function tensorflow.python.keras.utils.np_utils.to_categorical(y, num_classes=None, dtype='float32')>

 

반응형

'Computer_Science > Visual Intelligence' 카테고리의 다른 글

20일차 - 논문 수업 (CNN)  (0) 2021.10.08
19일차 - 논문 수업 (CNN)  (0) 2021.10.08
17일차 - 논문 수업 (CNN)  (0) 2021.10.04
16일차 - 논문 수업 (CNN)  (0) 2021.10.04
15일차 - CNN  (0) 2021.10.04

+ Recent posts