【Python-Module】 비전 처리 라이브러리 활용 - OpenCV 뼈대 코드

다양한 비전 라이브러리를 잠시만 공부해보고, OpenCV를 집중적으로 공부해보자. 이미지 뿐만 아니라 동영상까지 다루는 방법에 대해서, 앞으로 계속 사용할 뼈대 코드들에 대해서 공부해본다.

DLCV/Detection/preliminary/OpenCV이미지와 영상처리 개요 파일 참조

1. Python 기반 주요 이미지 라이브러리

  1. PIL(Python Image Library) : 주요 이미지 처리만. 처리 성능이 상대적으로 느림. 망해가는 모듈.
  2. Scikit-Image : Scipy기반. Numpy기반.
  3. OpenCV
    • 최고 인기 컴퓨터 비전 라이브러리. 컴퓨터 비전 기능 일반화에 크게 기여. 대중화.
    • cv2.imread(“파일명”) -> numpy array로 변환해 저장 -> RGB형태가 아닌 BGR형태로 로딩!!
    • 따라서 image를 바꿔줘야 한다.

        import cv2
        import matplotlib.pyplot as plt
        bgr_img_array = cv2.imread('file Name')
        rgb_img_array = cv2.cvtColor(bgr_img_arry, cv2.COLOR.BGR2RGB)
        plt.imshow(rgb_img_array)
      
    • 근데 imwrite에서는 내부적으로 또 RGB로 바꾸기 때문에 주의해야한다.

        bgr_img_array = cv2.imread('file Name')
        rgb_img_array = cv2.cvtColor(bgr_img_arry, cv2.COLOR.BGR2RGB)
        cv2.imwirte('저장할 파일 이름', bgr_img_array)  # 따라서 bgr이미지 넣어야함
      
    • OpenCV Windows Frame 인터페이스 : 아래와 같은 기능들은 GUI 윈도우 우분투 환경에서만 쓸 수 있기 때문에 주피터 노트북 기반에서는 사용시 오류가 발생한다. 따라서 matplotlib를 사용해서 주피터 노트북 기반 이미지 시각화를 해야한다.
      1. cv2.imshow() : 윈도우 frame에 보여줌(따라서 주피터에서는 안보인다.)
      2. cv2.waitKey() : 키보드 입력이 있을때 까지 무한 대기
      3. cv2.destroyAllWindows() : 화면의 윈도우 프레임 모두 종료

2. OpenCV의 이미지 처리

  • Python에서 사용되는 여러 image라이브러리를 간단히 살펴보고 OpenCV와의 차이 이해
  • OpenCV의 단일 이미지 처리 방식 이해
  • OpenCV의 비디오 영상 처리 방식 이해

OpenCV 이미지 처리 이해 및 타 패키지 비교

PIL 패키지를 이용하여 이미지 로드하기

import matplotlib.pyplot as plt
%matplotlib inline  
# https://korbillgates.tistory.com/85 - Jupyter Line에 그림 표등이 출력될 수 있게 하는 것 

from PIL import Image

# PIL은 oepn()으로 image file을 읽어서 ImageFile객체로 생성. 
pil_image = Image.open("../../data/image/beatles01.jpg")
print('image type:', type(pil_image))

plt.figure(figsize=(10, 10))
plt.imshow(pil_image)
#plt.show()
image type: <class 'PIL.JpegImagePlugin.JpegImageFile'>

drawing

skimage(사이킷이미지)로 이미지 로드 하기

  • skimage는 imread()를 이용하여 RGB 원본 이미지를 RGB 형태의 넘파이 배열로 반환함.
from skimage import io

#skimage는 imread()를 이용하여 image를 numpy 배열로 반환함. 
sk_image = io.imread("../../data/image/beatles01.jpg")
print('sk_image type:', type(sk_image), ' sk_image shape:', sk_image.shape)

plt.figure(figsize=(10, 10))
plt.imshow(sk_image)
#plt.show()
sk_image type: <class 'numpy.ndarray'>  sk_image shape: (633, 806, 3)

drawing

OpenCV, matplotlib으로 이미지 로드하기

  • OpenCV는 imread()를 이용하여 원본 RGB 이미지를 BGR 형태의 넘파이 배열로 반환함.
  • OpenCV의 imwrite()를 이용한다면 BGR 형태의 이미지 배열을 파일에 기록할 때 다시 RGB형태로 변환하므로 사용자는 RGB->BGR->RGB 변환에 신경쓰지 않아도 됨.
import cv2

cv2_image = cv2.imread("../../data/image/beatles01.jpg")  # cv2_image 여기서는 BGR이지만
cv2.imwrite("../../data/output/beatles02_cv.jpg", cv2_image) # 여기서는 RGB로 자동으로 다시 바뀐다
print('cv_image type:', type(cv2_image), ' cv_image shape:', cv2_image.shape)  

plt.figure(figsize=(10, 10))
img = plt.imread("../../data/output/beatles02_cv.jpg")
plt.imshow(img)
#plt.show()

cv_image type: <class 'numpy.ndarray'>  cv_image shape: (633, 806, 3)

drawing

OpenCV의 imread()로 반환된 BGR 이미지 넘파이 배열을 그대로 시각화 하기

  • OpenCV의 imread()는 RGB를 BGR로 변환하므로 원하지 않는 이미지가 출력됨
cv2_image = cv2.imread("../../data/image/beatles01.jpg")

plt.figure(figsize=(10, 10))
plt.imshow(cv2_image)
plt.show()

drawing

sk_image = io.imread("../../data/image/beatles01.jpg")
print(sk_image.shape)
sk_image[:, :, 0]
(633, 806, 3)





array([[ 18,  17,  18, ...,  46,  38,  63],
       [ 18,  18,  18, ...,  72,  41,  37],
       [ 18,  18,  18, ...,  84,  56,  42],
       ...,
       [225, 226, 228, ..., 231, 228, 229],
       [225, 225, 226, ..., 229, 229, 227],
       [225, 225, 224, ..., 227, 227, 227]], dtype=uint8)
cv2_image = cv2.imread("../../data/image/beatles01.jpg")
print(type(cv2_image))
print(cv2_image.shape)
cv2_image[:, :, 0]  # BGR - R값만 print한다. (633, 806, 3) -> (633, 806, 0)
<class 'numpy.ndarray'>
(633, 806, 3)





array([[ 19,  19,  20, ...,  47,  39,  64],
       [ 20,  20,  20, ...,  71,  40,  36],
       [ 20,  20,  20, ...,  82,  54,  40],
       ...,
       [198, 199, 201, ..., 190, 189, 188],
       [198, 198, 199, ..., 188, 188, 186],
       [199, 199, 198, ..., 186, 186, 186]], dtype=uint8)
 cv2_image[:, :, 2]  # BRG - G값만 print한다. (633, 806, 3) -> (633, 806, 0)
array([[ 18,  18,  18, ...,  47,  39,  64],
       [ 19,  19,  18, ...,  72,  41,  37],
       [ 18,  18,  18, ...,  84,  56,  41],
       ...,
       [225, 226, 228, ..., 231, 230, 229],
       [225, 225, 226, ..., 229, 229, 227],
       [225, 225, 224, ..., 227, 227, 227]], dtype=uint8)
cv2_image = cv2.imread("../../data/image/beatles01.jpg")
draw_image = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)  # 이 작업에 시간 많이 안든다. 단순 메모리 포인트 변화만 하므로. 
cv2.imwrite("../../data/output/beatles02_cv.jpg", draw_image)
# 이렇게 저장된 것을 확인해보면 색이 엉망인것을 확인할 수 있다. 따라서 imwirte를 사용해서 저장한다면 반드시 BGR 이미지가 들어가게 하도록! 

plt.figure(figsize=(10, 10))
plt.imshow(draw_image)
plt.show()

drawing

3. OpenCV 영상처리

  • 뼈대 코드 이다. 나중에 Object Detection 결과를 동영상으로 저장할 때 이와 같은 방법을 사용할 것이므로, 꼭 잘 알아두어야 한다.
  • OpenCV는 간편하게 비디오 영상처리를 할 수 있는 API를 제공
  • VideoCapture 객체는 Video Streaming을 Frame 별로 Capture하여 처리할 수 있는 기능 제공
  • VideoWriter 객체는 VideoCapture로 읽어들인 Frame을 동영상으로 Write하는 기능 제공
# 일단 시각화만 해본다. 
# wget https://github.com/chulminkw/DLCV/blob/master/data/video/Night_Day_Chase.mp4?raw=true 으로 다운로드 가능. 
from IPython.display import clear_output, Image, display, Video, HTML
Video('../../data/video/Night_Day_Chase.mp4') # 소리도 있음
  • 여기서부터 Video를 사용하는 방법이다.
  • Linux에서 video output의 확장자는 반드시 avi 로 설정 필요. (mp4로 재생되긴 되더라..)

OpenCV 영상 처리 개요

  • VideoCapture클래스는 동영상을 개별 Frame으로 하나씩 읽어(wideoCapture.read()) 들이는 기능을 제공한다.
  • VideoWriter는 VideoCapture로 읽어들인 개별 Frame을 차곡차곡 쌓아서 Write 수행하며 하나의 동영상을 만든다.
  • get 메소드를 사용해서 동영상으 상세 정보를 하나하나 불러들여올 수 있다.

VideoWriter(저장위치, 코덱, 프레임, 사이즈(1x2 배열))

  • 코덱 포멧을 다양하게 Encoding할 수 있다. (DIVX, XVID, MJPG, X264, WMV1, WMV2)
  • 하지만 가상환경의 우리의 리눅스 환경에서는 XVID 코덱을 사용해야 하고, write시 동영상 인코더는 avi로 해야한다. input을 mp4를 했다고 하더라도. ㅈ
# 여기서부터 Video를 사용하는 방법이다.
import cv2

video_input_path = '../../data/video/Night_Day_Chase.mp4'
# linux에서 video output의 확장자는 반드시 avi 로 설정 필요. 
video_output_path = '../../data/output/Night_Day_Chase_output.avi'

cap = cv2.VideoCapture(video_input_path) # <- 앞으로 이 변수를 중심으로 사용할 것
# Codec은 *'XVID'로 설정. 
codec = cv2.VideoWriter_fourcc(*'XVID')  # 코덱 객체를 생성

vid_size = (round(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))) #(200, 400)
vid_fps = cap.get(cv2.CAP_PROP_FPS )
frame_cnt = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))    
    
vid_writer = cv2.VideoWriter(video_output_path, codec, vid_fps, vid_size) # 처음에는 아무것도 없는 동영상
print('총 Frame 갯수:', frame_cnt, 'FPS:', round(vid_fps), 'Frame 크기:', vid_size)
총 Frame 갯수: 1383 FPS: 28 Frame 크기: (1216, 516)
import time

green_color=(0, 255, 0)
red_color=(0, 0, 255)

start = time.time()
index=0
while True:
    hasFrame, img_frame = cap.read() 
    # cap.read가 frame 하나하나를 순서대로 뱉어준다. 한 프래임씩 읽어주는 아주 좋은 매소드함수라고 할 수 있다.
    if not hasFrame:
        print('더 이상 처리할 frame이 없습니다.')
        break
    index += 1
    print('frame :', index, '처리 완료')
    cv2.rectangle(img_frame, (300, 100, 800, 400), color=green_color, thickness=2)  # 동영상 프래임 이미지 각각에 박스 넣기
    caption = "frame:{}".format(index)
    cv2.putText(img_frame, caption, (300, 95), cv2.FONT_HERSHEY_SIMPLEX, 0.7, red_color, 1)  # 동영상 프레임 이미지 각각에 몇번째 Frame인지 적기
    
    vid_writer.write(img_frame) 
    # 동영상에 차곡차곡 동영상프래임이미지를 쌓아올린다. 

print('write 완료 시간:', round(time.time()-start,4))
vid_writer.release()  # 나중에 저장한 동영상. file.close() 와 같은 느낌
cap.release()         # 처음에 가져온 이미지. file.close() 와 같은 느낌
frame : 1 처리 완료
frame : 2 처리 완료
frame : 3 처리 완료
frame : 4 처리 완료
fr...
frame : 1381 처리 완료
frame : 1382 처리 완료
frame : 1383 처리 완료
더 이상 처리할 frame이 없습니다.
write 완료 시간: 12.3946
Video('../../data/output/Night_Day_Chase_output.avi') 
  • avi 파일은 주피터 노트북에서 실행할 수 없다. 그래서 파일을 만들었으면, 위와 같이 실행할 수 없다. mp4 파일만 실행할 수 있음을 알아두자.
  • 그래서 avi 파일은 다운을 받아서 나의 컴퓨터에 실행해봐야 한다. 다운을 받는 방법은 그냥 jupyter notebook에서 download를 하면 된다. 그리고 아래와 같이 object storage에 넣고, 다운 받는 방법 또한 있다.
  • 당연히 동영상에 소리는 없다. Detection을 위한다면 소리는 필요없다.
!gsutil cp ../../data/output/Night_Day_Chase_output.avi gs://my_bucket_dlcv/data/output/Night_Day_Chase_output.avi

【Tensorflow】Faster RCNN Inference 수행하기 + GPU 자원 주의사항

Tensorflow 1.3. Faster RCNN API로 Object Detection 수행하기
/DLCV/Detection/fast_rcnn/Tensorflow_FasterRCNN_ObjectDetection.ipynb 참조

0. Tensorflow inferece 과정

  1. 이미지 read 하기
  2. .pb 파일만 읽어오기 - tf.gfile.FastGFile, graph_def = tf.GraphDef() 사용
  3. 세션을 시작한다 - with tf.Session() as sess:
  4. 세션 내부에서 graph를 import한다 - tf.import_graph_def(graph_def, name=’’)
  5. sess.run으로 forward처리하고, 원하는 정보를 뽑아온다. out = sess.run
  6. 객체 하나하나에 대한 정보를 추출하여 시각화 한다 - for i in range(int(out[0][0])):

1. GPU 자원 주의사항

drawing

해결방안

  • $ nvidia-smi 를 주기적으로 확인하고 학습을 시작하기 전에,
    1. Jupyter - Running - 안쓰는 Notebook Shutdown 하기
    2. Notebook - Restart & Clear output 하기
    3. nvidia-smi 에서 나오는 process 중 GPU많이 사용하는 프로세서 Kill -9 <Processer ID>하기
    4. Jupyter Notebook 을 Terminal에서 kill하고 다시 키기 (~ /start_nb.sh)

2. tensorflow로 Object Detection 수행하기

1. 단일 이미지 Object Detection

import cv2
import matplotlib.pyplot as plt
%matplotlib inline

img = cv2.imread('../../data/image/john_wick01.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

print('image shape:', img.shape)
plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)
image shape: (450, 814, 3)
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'}
# !mkdir pretrained; cd pretrained
# !wget http://download.tensorflow.org/models/object_detection/faster_rcnn_resnet50_coco_2018_01_28.tar.gz
# !wget https://raw.githubusercontent.com/opencv/opencv_extra/master/testdata/dnn/faster_rcnn_resnet50_coco_2018_01_28.pbtxt
# cd faster_rcnn_resnet50_coco_2018_01_28; mv faster_rcnn_resnet50_coco_2018_01_28.pbtxt graph.pbtxt
import numpy as np
import tensorflow as tf
import cv2
import time
import matplotlib.pyplot as plt
%matplotlib inline


#inference graph를 읽음. .
with tf.gfile.FastGFile('./pretrained/faster_rcnn_resnet50_coco_2018_01_28/frozen_inference_graph.pb', 'rb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())
    
with tf.Session() as sess:
    # Session 시작하고 inference graph 모델 로딩 
    sess.graph.as_default()
    tf.import_graph_def(graph_def, name='')
    # 여기서 session 내부에 graph가 들어가게 된다. 후에 sess변수를 사용하면서 grpah 정보를 가져올 수 있다. 
    
    # 입력 이미지 생성 및 BGR을 RGB로 변경 
    img = cv2.imread('../../data/image/beatles01.jpg')
    draw_img = img.copy()
    rows = img.shape[0]
    cols = img.shape[1]
    input_img = img[:, :, [2, 1, 0]]   # BGR -> RGB
    
    start = time.time()
    # Object Detection 수행. 
    # run - graph.get을 통해서 내가 가져오고 싶은 것을 인자로 적어놓는다. 순서대로 [객체수, 신뢰도, Box위치, Class]
    out = sess.run([sess.graph.get_tensor_by_name('num_detections:0'),
                    sess.graph.get_tensor_by_name('detection_scores:0'),
                    sess.graph.get_tensor_by_name('detection_boxes:0'),
                    sess.graph.get_tensor_by_name('detection_classes:0')],
                   feed_dict={'image_tensor:0': input_img.reshape(1, input_img.shape[0], input_img.shape[1], 3) } ) # 이미지 여러게 
    print('type of out:', type(out), 'length of out:',len(out))  # list(4) = [객체수, 신뢰도, Box위치, Class]
    print(out)
    green_color=(0, 255, 0)
    red_color=(0, 0, 255)
    
    # Bounding Box 시각화 
    num_detections = int(out[0][0])
    for i in range(num_detections):
        classId = int(out[3][0][i])
        score = float(out[1][0][i])
        bbox = [float(v) for v in out[2][0][i]]
        if score > 0.5:
            left = bbox[1] * cols
            top = bbox[0] * rows
            right = bbox[3] * cols
            bottom = bbox[2] * rows
            cv2.rectangle(draw_img, (int(left), int(top)), (int(right), int(bottom)), green_color, thickness=2)
            caption = "{}: {:.4f}".format(labels_to_names[classId], score)
            print(caption)
            cv2.putText(draw_img, caption, (int(left), int(top - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.4, red_color, 1)
    
    print('Detection 수행시간:',round(time.time() - start, 2),"초")
    
img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)

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

# NMS 필터링에서 약간의 문제가 있는듯 하다... 약간 결과가 꺼림직하다. 
        
type of out: <class 'list'> length of out: 4
밑의 내용 : [객체수, 신뢰도, Box위치, Class]

[array([19.], dtype=float32), 

array([[0.99974984, 0.99930644, 0.9980475 , 0.9970795 , 0.9222008 ,
        0.8515703 , 0.8055376 , 0.7321974 , 0.7169089 , 0.6350252 ,
        0.6057731 , 0.5482028 , 0.51252437, 0.46408176, 0.43892667,
        0.41287616, 0.4075464 , 0.39610404, 0.3171757 , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        .
        ...
        .
        .

        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ]],
      dtype=float32), 
      
array([[[0.40270284, 0.2723695 , 0.8693631 , 0.46764165],
        [0.40439418, 0.06080557, 0.88185936, 0.24013077],
        [0.40899867, 0.68438506, 0.9282361 , 0.9033634 ],
        [0.42774147, 0.4751278 , 0.8887425 , 0.7367553 ],
        [0.3681334 , 0.5855469 , 0.41420895, 0.6274197 ],
        [0.36090973, 0.7612593 , 0.46531847, 0.78825235],
        [0.35362682, 0.5422665 , 0.3779468 , 0.56790847],
        [0.35872525, 0.47497243, 0.37832502, 0.4952262 ],
        [0.39067298, 0.17564818, 0.54261357, 0.31135702],
        [0.3596046 , 0.6206162 , 0.4659364 , 0.7180736 ],
        [0.36052787, 0.7542875 , 0.45949724, 0.7803741 ],
        [0.35740715, 0.55126834, 0.38326728, 0.57657194],
        [0.36718863, 0.5769864 , 0.40654665, 0.61239254],
        [0.35574582, 0.4798463 , 0.37322614, 0.4985193 ],
        [0.35036406, 0.5329462 , 0.3708444 , 0.5514975 ],
        [0.367587  , 0.39456058, 0.41583234, 0.43441534],
        [0.3562084 , 0.47724184, 0.37217227, 0.49240994],
        [0.36195153, 0.6252996 , 0.46575055, 0.72400415],
        [0.36365557, 0.5674811 , 0.39475283, 0.59136254],
        [0.        , 0.        , 0.        , 0.        ],
        [0.        , 0.        , 0.        , 0.        ],
        [0.        , 0.        , 0.        , 0.        ],
        [0.        , 0.        , 0.        , 0.        ],
        [0.        , 0.        , 0.        , 0.        ],
        [0.        , 0.        , 0.        , 0.        ],
        ...
        .
        .
        ...
        .
        [0.        , 0.        , 0.        , 0.        ],
        [0.        , 0.        , 0.        , 0.        ]]], dtype=float32), 
        
        
    array([[1., 1., 1., 1., 3., 1., 3., 3., 3., 8., 1., 3., 3., 3., 3., 3.,
        3., 3., 3., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
        1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
        1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
        1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
        1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
        1., 1., 1., 1.]], dtype=float32)]

person: 0.9997
person: 0.9993
person: 0.9980
person: 0.9971
car: 0.9222
person: 0.8516
car: 0.8055
car: 0.7322
car: 0.7169
truck: 0.6350
person: 0.6058
car: 0.5482
car: 0.5125

Detection 수행시간: 12.99 초

drawing

2. 위의 과정 함수로 def하고 활용해보기

def get_tensor_detected_image(sess, img_array, use_copied_array):
    
    rows = img_array.shape[0]
    cols = img_array.shape[1]
    if use_copied_array:
        draw_img_array = img_array.copy()
    else:
        draw_img_array = img_array
    
    input_img = img_array[:, :, [2, 1, 0]]  # BGR2RGB

    start = time.time()
    # Object Detection 수행. 
    out = sess.run([sess.graph.get_tensor_by_name('num_detections:0'),
                    sess.graph.get_tensor_by_name('detection_scores:0'),
                    sess.graph.get_tensor_by_name('detection_boxes:0'),
                    sess.graph.get_tensor_by_name('detection_classes:0')],
                   feed_dict={'image_tensor:0': input_img.reshape(1, input_img.shape[0], input_img.shape[1], 3)})
    
    green_color=(0, 255, 0)
    red_color=(0, 0, 255)
    
    # Bounding Box 시각화 
    num_detections = int(out[0][0])
    for i in range(num_detections):
        classId = int(out[3][0][i])
        score = float(out[1][0][i])
        bbox = [float(v) for v in out[2][0][i]]
        if score > 0.5:
            left = bbox[1] * cols
            top = bbox[0] * rows
            right = bbox[3] * cols
            bottom = bbox[2] * rows
            cv2.rectangle(draw_img_array, (int(left), int(top)), (int(right), int(bottom)), green_color, thickness=2)
            caption = "{}: {:.4f}".format(labels_to_names[classId], score)
            cv2.putText(draw_img_array, caption, (int(left), int(top - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.4, red_color, 1)
            #print(caption)
    print('Detection 수행시간:',round(time.time() - start, 2),"초")
    return draw_img_array
# end of function

방금 위에서 만든 함수 사용해서 Image Object Detection 수행하기

with tf.gfile.FastGFile('./pretrained/faster_rcnn_resnet50_coco_2018_01_28/frozen_inference_graph.pb', 'rb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())
    
with tf.Session() as sess:
    # Session 시작하고 inference graph 모델 로딩 
    sess.graph.as_default()
    tf.import_graph_def(graph_def, name='')
    
    # 입력 이미지 생성 및 BGR을 RGB로 변경 
    img = cv2.imread('../../data/image/john_wick01.jpg')
    draw_img = get_tensor_detected_image(sess, img, True)

img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)

plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)
Detection 수행시간: 15.58 초

drawing

3. 위에서 만든 함수로 Video Object Detection 수행

video_input_path = '../../data/video/John_Wick_small.mp4'
# linux에서 video output의 확장자는 반드시 avi 로 설정 필요. 
video_output_path = '../../data/output/John_Wick_small_tensor01.avi'

cap = cv2.VideoCapture(video_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(video_output_path, codec, vid_fps, vid_size) 

frame_cnt = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print('총 Frame 갯수:', frame_cnt)

green_color=(0, 255, 0)
red_color=(0, 0, 255)

#inference graph를 읽음. .
with tf.gfile.FastGFile('./pretrained/faster_rcnn_resnet50_coco_2018_01_28/frozen_inference_graph.pb', 'rb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())
    
with tf.Session() as sess:
    # Session 시작하고 inference graph 모델 로딩 
    sess.graph.as_default()
    tf.import_graph_def(graph_def, name='')

    while True:
        hasFrame, img_frame = cap.read()
        if not hasFrame:
            print('더 이상 처리할 frame이 없습니다.')
            break

        draw_img_frame = get_tensor_detected_image(sess, img_frame, False)
        vid_writer.write(draw_img_frame)
    # end of while loop

vid_writer.release()
cap.release()  

!gsutil cp ../../data/output/John_Wick_small_tensor01.avi gs://my_bucket_dlcv/data/output/John_Wick_small_tensor01.avi

drawing

【Vision】 Selective Search Python Module, IOU 계산 코드 만들기

Selective Search Python 모듈을 사용해보고 IOU를 적용해보자.

Selective Search Python Module 사용해보기 DLCV/Detection/preliminary/Selective_search와 IOU구하기 파일 참조

  1. conda activate tf113
  2. jupyter notebook 실행 - $ nphup jupyter notebook &

1. Selective Search 코드 실습

  • import cv2 에서 ImportError: libGL.so.1: cannot open shared object file: No such file or directory 에러가 뜬다면
    $ sudo apt-get install libgl1-mesa-glx 을 실행하기.
#!pip install selectivesearch
import selectivesearch
import cv2
import matplotlib.pyplot as plt
%matplotlib inline

### 오드리헵번 이미지를 cv2로 로드하고 matplotlib으로 시각화
img_bgr = cv2.imread('../../data/image/audrey01.jpg')
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
print('img shape:', img.shape)

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb)
plt.show()

img shape: (450, 375, 3)
  • selectivesearch.selective_search()는 이미지의 Region Proposal정보를 반환
  • 아래와 같이 selectivesearch 모듈을 사용하는 방법은 다음과 같다.
  • 매개변수는 ( 이미지, scale= object의 사이즈가 어느정도 인가? 알고리즘 조정하기, min_size보다는 넓이가 큰 bounding box를 추천해달라)
_, regions = selectivesearch.selective_search(img_rgb, scale=100, min_size=2000)
print(type(regions), len(regions))
print(regions[0])
print(regions[1])
# (x1 y1 좌상단 width hight)  (bounding box size)  (label이 1개면 독자적인 영역. 2개 이상이면 각 Label을 합친 영역이라는 것을 의미)
<class 'list'> 41
{'rect': (0, 0, 107, 167), 'size': 11166, 'labels': [0.0]}
{'rect': (15, 0, 129, 110), 'size': 8771, 'labels': [1.0]}
  • 반환된 regions 변수는 리스트 타입으로 세부 원소로 딕셔너리를 가지고 있음.
  • 개별 딕셔너리내 KEY값별 의미
    • rect 키값은 x,y 좌상단 좌표와 너비, 높이 값을 가지며 이 값이 Detected Object 후보를 나타내는 Bounding box임.
    • size는 Bounding box의 크기.
    • labels는 해당 rect로 지정된 Bounding Box내에 있는 오브젝트들의 고유 ID. 아래로 내려갈 수록 너비와 높이 값이 큰 Bounding box이며 하나의 Bounding box에 여러개의 box가 합쳐진 box이다. 여러개의 오브젝트가 있을 확률이 크다.
# rect정보(x1 y1 좌상단 width hight) 만 출력해서 보기
cand_rects = [box['rect'] for box in regions]
print(cand_rects)

bounding box를 시각화 하기

# opencv의 rectangle()을 이용하여 시각화 그림에 사각형을 그리기
# rectangle()은 이미지와 좌상단 좌표, 우하단 좌표, box컬러색, 두께등을 인자로 입력하면 원본 이미지에 box를 그려줌.

green_rgb = (125, 255, 51)
img_rgb_copy = img_rgb.copy()
for rect in cand_rects:

    left = rect[0]
    top = rect[1]
    # rect[2], rect[3]은 너비와 높이이므로 우하단 좌표를 구하기 위해 좌상단 좌표에 각각을 더함.
    right = left + rect[2]
    bottom = top + rect[3]

    img_rgb_copy = cv2.rectangle(img_rgb_copy, (left, top), (right, bottom), color=green_rgb, thickness=2)
    # 상자를 추가한 Image로 변수 변경

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb_copy)
plt.show()

image

  • bounding box의 크기가 큰 후보만 추출
    • 바로 위에 코드랑 똑같은 코드지만 size만 조금 더 고려
cand_rects = [cand['rect'] for cand in regions if cand['size'] > 10000]

green_rgb = (125, 255, 51)
img_rgb_copy = img_rgb.copy()
for rect in cand_rects:

    left = rect[0]
    top = rect[1]
    # rect[2], rect[3]은 너비와 높이이므로 우하단 좌표를 구하기 위해 좌상단 좌표에 각각을 더함.
    right = left + rect[2]
    bottom = top + rect[3]

    img_rgb_copy = cv2.rectangle(img_rgb_copy, (left, top), (right, bottom), color=green_rgb, thickness=2)

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb_copy)
plt.show()

image

2. IOU 적용해보기

  • IOU 구하기

입력인자로 후보 박스와 실제 박스를 받아서 IOU를 계산하는 함수 생성

import numpy as np

# input에는 (x1 y1 x2 x2) 이미지의 좌상단, 우하단 좌표가 들어가 있다.
def compute_iou(cand_box, gt_box):

    # Calculate intersection areas
    x1 = np.maximum(cand_box[0], gt_box[0])
    y1 = np.maximum(cand_box[1], gt_box[1])
    x2 = np.minimum(cand_box[2], gt_box[2])
    y2 = np.minimum(cand_box[3], gt_box[3])

    intersection = np.maximum(x2 - x1, 0) * np.maximum(y2 - y1, 0) # 혹시 모르게 음수가 나올 수 있으니까..

    cand_box_area = (cand_box[2] - cand_box[0]) * (cand_box[3] - cand_box[1])
    gt_box_area = (gt_box[2] - gt_box[0]) * (gt_box[3] - gt_box[1])
    union = cand_box_area + gt_box_area - intersection

    iou = intersection / union
    return iou
import cv2
import matplotlib.pyplot as plt
%matplotlib inline

# 실제 box(Ground Truth)의 좌표를 아래와 같다고 가정.
gt_box = [60, 15, 320, 420]

img = cv2.imread('../../data/image/audrey01.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

red = (255, 0 , 0)
img_rgb = cv2.rectangle(img_rgb, (gt_box[0], gt_box[1]), (gt_box[2], gt_box[3]), color=red, thickness=2)

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb)
plt.show()
import selectivesearch

#selectivesearch.selective_search()는 이미지의 Region Proposal정보를 반환
_, regions = selectivesearch.selective_search(img_rgb, scale=100, min_size=2000)

print(type(regions), len(regions))
<class 'list'> 53
cand_rects = [cand['rect'] for cand in regions if cand['size'] > 15000]
# cand_box 값도 (좌상단 x1, y1, width, hight) 를 (좌상단, 우하단)의 좌표로 바꾼다.
for index, cand_box in enumerate(cand_rects):
    cand_box = list(cand_box)
    cand_box[2] += cand_box[0]
    cand_box[3] += cand_box[1]

    # 각각의 Box 별로 IOU값을 구해본다
    iou = compute_iou(cand_box, gt_box)
    print('index:', index, "iou:", iou)
index: 0 iou: 0.5933903133903133
index: 1 iou: 0.20454890788224123
index: 2 iou: 0.5958024691358025
index: 3 iou: 0.5958024691358025
index: 4 iou: 0.1134453781512605
index: 5 iou: 0.354069104098905
index: 6 iou: 0.1134453781512605
index: 7 iou: 0.3278419532685744
index: 8 iou: 0.3837088388214905
index: 9 iou: 0.3956795484151107
index: 10 iou: 0.5008648690956052
index: 11 iou: 0.7389566501483806
index: 12 iou: 0.815085997397344
index: 13 iou: 0.6270619201314865
index: 14 iou: 0.6270619201314865
index: 15 iou: 0.6270619201314865
  • 바로 위의 코드를 적용해서 이미지와 IOU를 표현하는 이미지를 그려보자.
img = cv2.imread('../../data/image/audrey01.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print('img shape:', img.shape)

green_rgb = (125, 255, 51)
cand_rects = [cand['rect'] for cand in regions if cand['size'] > 3000]
gt_box = [60, 15, 320, 420]
img_rgb = cv2.rectangle(img_rgb, (gt_box[0], gt_box[1]), (gt_box[2], gt_box[3]), color=red, thickness=2)

for index, cand_box in enumerate(cand_rects):

    cand_box = list(cand_box)
    cand_box[2] += cand_box[0]
    cand_box[3] += cand_box[1]

    iou = compute_iou(cand_box, gt_box)

    if iou > 0.7:
        print('index:', index, "iou:", iou, 'rectangle:',(cand_box[0], cand_box[1], cand_box[2], cand_box[3]) )
        cv2.rectangle(img_rgb, (cand_box[0], cand_box[1]), (cand_box[2], cand_box[3]), color=green_rgb, thickness=1)
        text = "{}: {:.2f}".format(index, iou)
        cv2.putText(img_rgb, text, (cand_box[0]+ 100, cand_box[1]+10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, color=green_rgb, thickness=1)

plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)
plt.show()

img shape: (450, 375, 3)
index: 3 iou: 0.9874899187876287 rectangle: (59, 14, 321, 421)
index: 4 iou: 0.9748907882241216 rectangle: (62, 17, 318, 418)
index: 43 iou: 0.7389566501483806 rectangle: (63, 0, 374, 449)
index: 44 iou: 0.815085997397344 rectangle: (16, 0, 318, 418)

【Vision】 Detection과 Segmentation 다시 정리 1 - 계보 및 개요, mAP

당연하다고 생각하지만, 아직은 공부할게 많은 Detection과 Segmentation에 대한 개념을 다시 상기하고 정리해보면서 공부해볼 계획이다.

Detection과 Segmentation 다시 정리 1

1. Object Detection 계보

  1. Pascal VOC 데이터 기반에서 AlexNet을 통해서 딥러닝이 화두가 되었다.
  2. Detection을 정확히 분류하면 다음과 같이 분류할 수 있다.
    • Classification
    • Localization
    • Detection : Bounding Box Regression + Classification
    • Segmentation : Bounding Box Regression + Pixel Level Classification
  3. 계보
    • drawing
    • Traditional Detection 알고리즘 - VJ det, HOG det …
    • Deep Learning Detection 알고리즘 - 1 Stage Detection, 2 Stage Detectio (Region proposal + Classification)
    • SSD -> Yolo2, Yolo3
    • Retina-Net : 실시간성은 Yolo3보다는 아주 조금 느리지만, 정확성은 좋다.
  4. Detection은 API가 잘 정해져있지만, Train에 오류가 많이 나서 쉽지가 않다.

2. Object Detection

  • 요소
    • Region Proposal
    • Feature Extraction & Network Prediction (Deep Nueral Network)
    • IOU/ NMS/ mAP/ Anchor box
  • 난제
    • 하나의 이미지에서 여러개의 물체의 Localization + classification해야함
    • 물체의 크기가 Multi-Scale Objects 이다.
    • Real Time + Accuracy 모두를 보장해야함.
    • 물체가 가려져 있거나, 물체 부분만 나와 있거나
    • 훈련 DataSet의 부족 (Ms Coco, Google Open Image 등이 있다.)

3. Object Localization 개요

  • 아래와 같은 전체적인 흐름에서 Localizattion을생각해보자.
    • drawing
    • 위 사진의 4개의 값을 찾는다. (x1, y1, width, hight) 물체가 있을 법한 이 좌표를 찾는 것이 목적이다.
    • Object Localization 예측 결과
      • class Number, Confidence Score, x1, y1, width, hight
    • 2개 이상의 Object 검출하기
      • Sliding Window 방식 - anchor(window)를 슬라이딩 하면서 그 부분에 객체가 있는지 계속 확인하는 방법. 다양한 크기 다양한. 비율의 windows.
        또는 이미지를 조금씩 작게 만든 후 상대적으로 큰 window를 슬라이딩 하는 방식도 있다. (FPN의 기원이라고 할 수 있다.)
      • Region Proposal : 위와 같은 방법이 아니라, 일종의 알고리즘 방식으로 물체가 있을 법한 위치를 찾자.
        1. Selective Search : window방법보다는 빠르고 비교적 정확한 추천을 해줬다. Pixel by Pixel로 {컬러, 무늬, 형태} 에 따라서 유사한 영역을 찾아준다. 처음에는 하나의 이미지에 대략 200개의 Region을 제안한다. 그 각 영역들에 대해 유사한 것끼리 묶는 Grouping 과정을 반복하여 적절한 영역을 선택해 나간다. (Pixel Intensity 기반한 Graph-based segment 기법에 따라 Over Segmentation을 수행한다.)
          drawing
        2. RPN(Region Proposal Network)

4. Object Detection 필수 구성 성분

  • IOU : 2개의 Boundiong Box에 대해서 (교집합 / 합집합)

  • NMS(Non Max Suppression) : Object가 있을 만한 곳을 모든 Region을 배출한다. 따라서 비슷한 영역의 Region proposal이 나올 수 있다. 일정 IOU값 이상의 Bounding Boxs에 대해서 Confidence Score가 최대가 아닌것은 모두 눌러버린다.

    1. Confidence Score 가 0.5 이햐인 Box는 모두 제거
    2. Confidence Score에 대해서 Box를 오름차순 한다
    3. 높은 Confidence Score의 Box부터 겹치는 다른 Box를 모두 조사하여 특정 IOU 이상인 Box를 모두 제거 한다(IOU Threshold > 0.4, [주의] 이 값이 낮을 수록 많은 Box가 제거 된다. )
    4. 남아있는 Box만 선택

5. 필수 성능지표 mAP (mean Average Precision)

  1. Inference Time도 중요하지만 AP 수치도 중요하다.

  2. Precision(예측 기준)과 Recall(정답 기준)의 관계는 다음과 같다.
    drawing

  3. 또 다른 설명은 여기(참고 이전 Post)를 참고 할 것.

  4. Precision과 Recall이 적절히 둘다 좋아야 좋은 모델이다. 라고 할 수 있다.

  5. Pascal VOC - IOU:0.5 // COCO challenge - IOU:0.5 0.6 0.7 0.8 0.9

  6. TN FN FP TP 분류하는 방법
    drawing
    drawing

  7. 암인데 암이 아니라고 하고, 사기인데 사기가 아니라고 하면 심각한 문제가 발생하므로 ‘진짜를 진짜라고 판단하는 **Recall**‘이 중요하다.(FN이 심각한 문제를 야기한다.) 반대로 스팸 메일이 아닌데 스팸이라고 판단하면 심각한 문제가 발생하므로 ‘내가 진짜라고 판단한게 진짜인 **Precision**‘이 중요하다.(FP가 심각한 문제를 야기한다.)

    drawing

  8. 이러한 조절을 Confidence Threshold를 이용해서 할 수 있다.
    Ex. Confidence Threshold를 낮게 한다면 Recall(재현율)이 높아 진다. (다 Positive라고 판단해버리기)
    Confidence Threshold을 높게 한다면 Precision(정밀도)가 높아진다.(정말 확실한 경우만 Positive라고 예측하기)
    drawing
    drawing

  9. 즉 Confidence에 따른 Precison과 Recall의 변화 그래프이므로, 여기(참고 이전 Post)에서 Confidence에 대해서 내림차순 정렬을 하고, 차근차근 Recall, Precision점을 찍고 그 그래프의 넓이를 구하는 것이다.

  10. Confidence Threshold가 큰것부터 시작했으므로, Precision은 높고, Recall은 낮은 상태부터 시작한다. 주의할 점은 오른쪽 최대 Precision 값을 연결하고, mAP를 계산한다!
    drawing

  11. 지금까지가 AP를 구하는 방법이었다. 즉 AP는 한개의 Object에 대해서 값을 구하는 것이다. (참고 이전 Post) 그리고 모든 Object Class(새, 나비, 차, 사람 등등)에 대해서 AP를 구한 후 평균값을 사용하는 것이 바로 mAP이다.

  12. COCO Dataset에 대해서는 IOU Threshold를 다양하게(AP@[.50:.05:.95]) 주기 때문에 높은 IOU에 대해서 낮은 mAP가 나올 수 있음을 명심해야 한다.(높은 IOU Threshold라는 것은 FP와 TP 중 TP가 되기 힘듦을 의미한다.)
    그리고 COCO는 Object의 Scale 별로 대/중/소에 따른 mAP도 즉정한다.
    drawing

【VScode】 Prettier 문제 해결을 위한 고찰

Prettier 문제 해결을 위한 과정 기록

Prettier 문제 해결을 위한 과정 기록

문제점

  • junha1125.github.io 폴더의 파일은 Prettier이 동작하지 않는 문제

    image

구글링을 통한 해결 과정

  1. setting - format save on - 위의 사진과 같은 에러가 뜸.
  2. 하지만 windows VScode, windows 다른 폴더에서 작업을 하면 Prettier 정상작동 md, py 파일 모두 정상 작동
  3. 굳이 junha1125.github.io 이 폴더에서만 위와 같은 에러로 Formating 동작 안함
  4. setting - Prettier : Prettier path 를 npm -global~을 실행해서 나오는 결과로 적어 넣으라고 해서 그렇게 함. 위의 에러는 안 뜨지만 동작하지 않음 이 사이트의 조언
  5. junha1125.github.io 폴더를 완전히 전체 삭제한 후, C 드라이브 위치말고 ~/user/sb020 내부 onedrive위치에 옮겨놓음. 그래도 동작 안함
  6. 그러나 WSL에서는 모든 것이 잘 동작. 어느 폴더에서 어떤 파일형식으로 동작하든 잘 동작.

결론

  1. 어떤 폴더든 어떤 파일이든 Pretter는 window에서도 WSL에서도 잘 동작한다.
  2. 딱 하나! VScode - Open Folder - junha1125.github.io 로 열어서 작업하면 동작하지 않는다. (windows든 WSL이든)
  3. 따라서 md파일을 수정하면서 prettier효과를 보고 싶다면, md 파일 하나만 VScode로 열어서 작업하라.
  4. 또는 _post 폴더 위에서 작업해도 Prettier 효과를 잘 볼 수 있다.

해결

  • md파일을 수정하면서 prettier효과를 보고 싶다면, md 파일 하나만 VScode로 열어서 작업하라.
  • 근데 에러는 뜬다. (동작 잘하는데 왜 똑같은 에러가 뜨는거지??????)
  • 아하! 그렇다면 위의 링크 사이트대로 Prettier Path 수정하니까 에러도 안뜨고 동작도 잘 함(물론 Working Folder가 조금 꺼림직함…)

추가 조언

  • Powershell, WSL, git Bash를 VS vode에서 동작하게 하는 방법.
    1. Default Shell 클릭 -> 원하는 Shell 선택
    2. VScode - Terminal - New Terminal
    3. 내가 아까 원했던 Shell이 나오는 것을 확인할 수 있다.
  • 막상 Prettier이 있는 상태로 md파일을 수정하니 너무 불편하다. 그래서 Format Save 설정을 꺼버렸다.

문제 해결 완료.

【GPU_Server】 Google Cloud 플랫폼 - 적절한 conda 환경 Tensorflow, Keras 버전 맞추기

딥러닝을 위한 적절한 아나콘다 환경 셋팅하기

이전 게시물을 보고 오시는 것을 추천드립니다.

1. Tensorflow & Keras 버전 세팅 방법

  • 참고자료
    image
  • 추천하는 3가지 가상환경 :
    1. tf113 : Tensorflow 1.13, Keras 2.2
    2. tf115 : Tensorflow 1.15, Keras 2.3
    3. tf_obj : Tensorflow 1.15, Keras 2.3 -> Tensorflow object dection API 사용하기 위한 Env
  • 아래의 코드 참고할 것

      $ conda create -n tf113 python=3.6
      $ conda activate tf113
      $ cd envs/tf113/lib/python3.6   -> python3.6 설치
      $ cd ./site-packages  -> 기본 package들이 설치되어 있다. 
      $ cd ~/DLCV/data/util/
      $ chmod +x *.sh
      $ ./install_tf113.sh  (중간에 에러나오는거 무시 - 버전 맞춰주는 것)
    
      $ ps -ef | grep jupyter 
      - jupyter lab 말고 /계정ID/anaconda3 jupyter PID 
      $ kill -9 PID
      $ conda activate tf113
      $ cd ~/ && ./start_jn.sh         
      - jupyter의 목록에 conda 라는 목록이 추가된 것을 확인할 수 있다. 
    
  • 새로운 conda env를 사용해서 jupyter를 열고 싶으면 다음을 꼭 설치해야 한다.

      # DLCV/blob/master/data/util/install_tf113.sh 참조
      $ conda install -c conda-forge pycocotools -y
      $ conda install nb_conda -y
    
      # for  multi jupyter notebook kernal
      $ pip install ipykernel
      $ python -m ipykernel install --user --name <Conda Eev Name>
    
  • install_tf113.sh 내부에 있는 코드 중 $ conda install nb_conda -y 명령어를 통해서 콘다 환경들에게 별도로 jupyter를 따로 실행할 수 있게 해준다.
  • 여러개의 conda 가상환경에서 Jupyter를 열 때. kernel을 골라달라고 창이 뜰 수도 있다. 이때 tf113을 잘 골라주면 된다. 자주 나오니까 각 버전에 맞는 kernel 환경을 선택해 주면 된다. 선택할 kernel 이름이 있는 이유는 install.sh부분에 ‘$ python -m ipykernel install –user –name tf113’이 있기 때문에 이름이 있는거다. env여서 이름이 뜨는게 아니라 커널 설정을 해줬기 때문에 이름이 뜨는 거다. (Jypyter에서 Python [conda env:tf113] 와 같은 노투븍 커널 셋팅을 할 수 있도록!)

image

  • retinaNet에서 tf115를 사용하니까, 그때는 원래 띄어진 Jypyter를 죽이고 activate tf115 를 한 후 start_jn.sh를 실행한다.

2. 구글 클라우드 $300 무료 크레딧 효과적 사용법

  1. 결재 - 개요에 자주 들어가기
  2. 결제 - 예산 및 알림 - 알림 설정하기
  3. 결제 - 거래 - 자주 들어가서 확인하기
    • 300 GB storage PD capacity 한달에 14,000원 계속 나간다.
    • CPU core, Static ip(고정 ip) charging 등 돈이 추가적으로 많이 들어간다.
  4. GPU 서버를 항상 내리는 습관을 가지도록 하자. (VM instance 중지 및 정지)
  5. GPU 사용량, Setup 하는 자세를 배우는 것도 매우 필요하다.
  6. 구글 클라우드 서비스 모두 삭제하는 방법
    • instance 중지 - 삭제 - 서버 및 storage 비용은 안나간다
    • VPC network - 외부 IP 주소 - 고정 주소 해제 (이것도 매달 8천원 나간다.. )
    • Strage - 브라우저 - object storage 삭제
    • 프로젝트 설정 - 종료 (모든 결제 및 트래픽 전달 중지 된다) 7 결제 자주 확인하기
      image

3. Cloud 사용시 주의사항 및 Object Storage 설정

  1. 오류 해결 방법
    • GPU resources 부족 = 기다려라. 하루정도 기다리면 문제 해결 가능
    • 심각한 문제가 발생하면 VM instance 지우고 다시 설치 및 Setup하는 자세 및 습관을 들여라.
  2. Object Storage 설정하기
    • 작업을 편하기 하기 위해서 설정해두면 편리하다.
    • storage - 브라우저 - 버킷 생성 - 단일 region 및 설정 - default 설정 - 저장
    • 접근 인증을 받아야 한다. - server에서 object storage 에 붙기위해서 몇가지 설정이 필요.

        gsutil : google cloud와 연동되어 쉽게 이용할 수 있는 터미널 명령어
        $ gsutil ls gs://my_budcker_Name
        - 아직 권한이 없는 것을 확인할 수 있다. 
      
    • object storage 세부정보 - 권한 - 구성원추가 - 계정이메일 추가, 역할 Storage 저장소 관리자, 저장 - 이제 storage 에 등록을 했다. 하지만 server 인증을 받아야 한다.

        $ gcloud auth login
        - Yes
        - link copy
        - 웹 도메인에 paste - 로그인 및 코드 복사
        - SSH에서 Enter verification code
        $ gsutil ls gs://my_budcker_Name    -> 이제 여기 접근 가능
        $ qsutil cp <file Name> gs://my_budcker_Name    -> 이런식으로 bucket(object storage)에 접근 가능
      
    • winSCP를 사용해서 Putty와 연동 및 파일 업로드 가능
      • winSCP 다운로드 및 설치
      • 로그인 - 도구 - 가져오기 - Putty 원하는 환경 선택
      • 파일 업로드가 매우 쉽게 가능
      • image

4. Colab을 이용한 실습 환경 구축하기

  1. 런타임 유형 - GPU 설정 주의
  2. tensorflow 1.13에서 동작이 안되므로, tensorflow 1.15 설치하기.
  3. % cd, ! terminal command 와 같이 %와 !를 적절히 사용해라.
  4. google drive mount 해서 사용하기
    image

【GPU_Server】 Google Cloud 플랫폼 - VM instance Jupyter로 이용하기

무료로 150시간 정도 편리하게 GPU를 사용할 수 있는 Google Cloud 딥러닝 플렛폼 활용 방법

Google Cloud 딥러닝 플렛폼 이용하기

Google Cloud VS Colab

  • Colab을 사용해도 좋지만, Google Cloud를 사용하는 것이 빠르고 편리하므로 이것을 사용하는 방법에 대해서 공부할 계획이다.
  • 다양한 데이터를 사용해서, 다양한 모델을 사용해서 공부해볼 예정이다.

1. Google cloud platform 가입하고 활용하기

  • google cloud platform 사이트 바로가기
  • 콘솔 -> 서비스 약관 확인하기
  • 무료로 가입하기 -> 서비스 약관 확인하기
  • 무료계정이면 GPU를 사용할 수 없다. 자동 결제를 등록해서 유료계정으로 만들어야 GPU사용가능
  • Computer Engine -> VM 인스턴드 생성하기. 설정은 아래와 같이.
    image
  • 유료 계정으로 업데이트 -> GPU 할당 메일 보니게 -> GPU할당하기
  • 다시 VM 인스턴트 생성하기 - T4(추천), P100과 같은 GPU할당하는 인스턴트로 생성하기(운영체제 : 딥러닝 리눅스) -> 인스탄스 생성 안됨 -> 메일 보내야 함. -> IAM 및 관리자 - 할당량 - GPUs all region - 할당량 수정 - 메일 보내기 - 확인 답변 받고 인스턴트 재생성 (최근 메일에 대한 GPU 할당 거절이 많다. CPU서버를 48시간 이상 가동 후 요청을 다시 해보는 것을 추천한다.)
    image
  • 우선 Colab에서 작업하고 있자. Colab에서 나의 google drive와 마운트하고 그리고 작업을 수행하자. 코랩 오래 할당시 주의할 점 (런타임 연결 끊김 방지 정보)

2. Google cloud platform 이란. + Port Open하기.

  • 다음의 동영상(Youtube링크)을 보고 공부한 내용을 기록합니다,
    1. 구글 클라우드플랫폼 입문 활용
    • 아마존 AWS와 MS Azure 서비스와 비슷한 서비스이다. 하지만 경쟁사 서비스보다 늦게 시작했기 때문에 가성비가 좋다. 그리고 용어 하나하나가 AWS보다 이해가 쉽다는 장점이 있다.
    • 프로젝트 단위로 움직이다. 프로젝트당 Computers, VM 인스턴스들, Docker들을 묶음으로 사용할 수 있다. 프로젝트를 크게 한다고 하면 한달에 40만원이면 아주 편하게 사용할 수 있기 때문에 매우 유용하다.
    • 컴퓨팅 - 컴퓨터 엔진, 쿠버네틱스 엔진, 클라우드 Function, 클라우드 Run 등 가장 중요한 요소들이 존재한다.
    • 이 중 컴퓨터 엔진의 VM instance를 가장 많이 사용하게 되고 이 인스턴트 하나가 가상 컴퓨터 하나(하나의 기본적은 자원)라고 생각하면 편하다.
    • VM instance : Region(GPU, CPU 하드웨어가 있는 지역), 영역, 시리즈, 용도들을 선택하면서 가격이 변화하는 것을 확인할 수 있다. GPU를 사용하면 비용이 많이 든다. Colab에서는 무료로 GPU를 사용할 수 있기 때문에 Colab을 사용하는 것이 유용하다.
    • VM instance 설정 : 엑세스 범위를 설정해서 인스턴트 끼리의 연결, 공유를 가능하며 방화벽 설정은 무조건적으로 체크하는 것이 좋다. (나중에 바꿀 수 있다) 보안, 가용성 정책을 사용하면 가격이 저렴해지나 리소스가 전체적으로 부족해지면 리소스가 뺏길 수도 있다.
    • VM instance 생성 완료 : 외부 IP는 가변적이다. 알아두자. 내부 IP는 같은 Region의 인스턴트끼리 소통할 수 있는 IP이다.
  1. 인스턴트 SSH 접속과 도커 서비스, 방화벽 규칙
    • SSH에 접근하는 방법은 SSH를 클릭하거나, 다른 외부 SSH에서 접속하기, 웹으로 접속하기 3가지 방법이 있다. 아래의 방법을 통해서 웹으로 접속 설정을 해보자.
    • SSH 접속을 통해서 우분투와 접근할 수 있다. SSH-브라우저창 열기를 하면 Terminal을 쉽게 열 수 있다. apache2를 설치할 것(80/TCP로 웹서비스 사용 가능). git을 설치할 것.

    • $ sudo apt update
      $ sudo apt-get install apache2
      $ sudo service apache2 start
      $ sudo apt-get install git
      $ sudo netstat -na | grep 80
      
    • 외부 IP 클릭! -> 주소창 http 지우기 -> Apache2 Debian Default Page 확인 가능. Apache2를 그대로 사용하지 않고 Docker환경을 이용해서 어플리케이션 올릴 예정
    • Docker설치가 안되면 https://docs.docker.com/engine/install/debian/ 여기서! 우분투 아니라 데비안이다! 그리고 apt-get update에서 docker fetch 문제가 있어도 “ sudo apt-get install docker-ce docker-ce-cli containerd.io “ 걍 해도 잘 동작하는 것 확인 가능.

        $ sudo apt install docker.io
      
        $ sudo docker search bwapp
        $ sudo docker pull raesene/bwapp (또는 wordpress)
        $ sudo docker run -d --name webconnet -p 81:80 raesene/bwap
      
    • 이제 웹에서 외부 IP:81 로 들어가준다. 하지만 들어가지지 않은 것을 확인할 수 있다. 이것은 구글 클라우드에서 방화벽 처리를 해놓았기 때문이다.
    • Google Cloud Platform - VPC 네트워크 - 방화벽 - 방화벽 규칙 만들기 - 소스 IP 범위 : 0.0.0.0/0 tcp: 81 정의 - 그리고 다시 외부 IP:81로 접근하면 아래와 같은 화면 결과.
      image
    • 외부 IP:81/install.php 로 들어가면 bwapp(웹해킹)사이트로 들어갈 수 있다.

    • 나는 이 방법을 사용해서 8080 port의 방화벽을 허용해 놓고, ml-workspace Image를 가져와서 Container를 실행했다. 다음과 같은 명령어를 사용했다.

      $ sudo docker run -d \
      -p 8080:8080 \
      --name "ml-workspace" -v "${PWD}:/workspace" \
      --env AUTHENTICATE_VIA_JUPYTER="eoqkr" \
      --restart always \
      mltooling/ml-workspace:latest
      
    1. GCP의 MarektPlace 활용하기. 저장 디시크 활용

3. 딥러닝용 가상환경 구축하기

  • 1에서 GPU 할당을 받았다 그 후 작업하는 과정을 요약해 놓는다.
  • 아래의 과정은 SSH 크롬 브라우저를 사용해도 되지만, 고정 IP를 사용해서 Putty로 쉽게 윈도우에서 연결할 수 있도록 설정하는 방법을 적어 놓은 것이다. (Google cloud vm instance Putty connect 등으로 구글링하면 나올 내용들을 정리해 놓는다.)
    1. 4코어 15GB 메모리. GPU T4 1개. 부팅디스크 (Deep Learning on Linux) 디스크 300GB.
    2. Cloud 서버 활용하기 - IP설정(고정적으로 만들기) : VPC 네트워크 - 외부 IP주소 - 고정 주소 예약 (region-연결대상 만 맞춰주고 나머지는 Default로 저장)
    3. 방화벽 규칙 - 방화벽 규칙 만들기 - 8888 port 열기 - 네트워크의 모든 인스턴스 - tcp:8888 ->
    4. Putty donwnload - Putty gen (Private Key 만드는데 사용) 열기 - 인스턴스 세부정보 수정 - Key generate(Key comment : 구글 계정 아이디 넣기) - Key 복사해서 SSH 키 입력 - (Putty gen) Save private, public key - VM 인스턴스 세부정보 수정 저장.
    5. 외부 IP를 Putty에 넣어주고, SSH Auth Browsd - 위에 저장한 Private key 클릭 - Host Name을 sb020518@외부IP 로 저장하고 save_sessions - Open.
    6. Nvidia driver 설치 Yes. - Nvidia driver installed - nvidia-smi 체크해보기
    7. Nvidia driver가 잘 설치되지 않는다면 다음의 과정을 거친다.
      $ cd /opt/deeplearning
      $ sudo ./install-driver.sh
    

4. 주피터 노트북 Setup 하기

  • 실습을 위한 코드를 다운 받고, 아나콘다를 설치 후. Jupyter server를 설치한다.
  • 아래의 과정을 순서대로 수행하면 된다.

      $ git clone ~~culminkw/DLCV
      - anaconda download 하기.(wget 링크주소복사 및 붙여넣기)
      $ chmod 777 ./Anaconda3
      - 콘다 설치 완료
      $ cd ~/
      $ jupyter notebook --generate-config
      $ cd ~/.jupyter
      $ vi ~/.vimrc   ->   syntax off  -> :wq!  (편집창 색깔 이쁘게)
      $ vi ~/.jupyter/.jupyter*.py   ->   DLCV/data/util/jupyer_notebook_config.py 의 내용 복붙 해놓기 
      - (차이점을 비교해서 뭐가 다른지 공부하는 시간가지기 Ex.외부포트 공개, 비밀번호 없음 등... )
      $ cd && vi start_jn.sh    ->  nohup jupyter notebook &  (back End에서 실행)
      $ chmod +x start_jn.sh
      $ ./start_jn.sh
      $ tail -f nohup.out   (jupyter 실행라인이 보여야 함)
      - http:// VM instance 외부-IP:8888  (https 아님)
      - jupyter 실행되는 것을 볼 수 있다. 
    

    image

  • 이와 같이 우리의 SSH 환경이 jupyter에서 실행되는 것을 확인할 수 있다.

5. GCP tensorboard 열기

  • GCP의 SSH를 이용하는 경우
    1. SSH를 GCP를 통해서 열어서 $ tensorboard –logdir=runs 실행
    2. TensorBoard 2.2.1 at http://localhost:6006/ (Press CTRL+C to quit)
      라고 나오면 이떄 나오는 링크를 클릭해서 들어가야 tensorboard를 볼 수 있다.
    3. 참고했던 사이트 이 작업을 해서 되는건지 아닌지는 모르겠다. 이거 했을 때 에러가 많았는데…
    4. 인스턴스_외부_IP:6006/ 와 같은 링크로 크롬에 직접 쳐서는 들어갈 수 없다.
  • jupyter notebook의 terminal를 이용하는 경우
    1. 이상하게 jupyter notebook을 틀어서 위와 같은 작업을 똑같이 실행하면
      • localhost:6006/로 들어갈 수 없다
      • 실행하던 terminal이 멈처버린다. ctrl+c도 안 먹힌다.
      • terminal을 shortdown할 수도 없다.
    2. 내 생각인데, 인스턴스_외부_IP:8888에서 다시 6006을 열라고 하니까 안되는 것 같다.
      • 주인이 있는데, 고객이 고객을 상대하려고 하는 꼴인건가??
    3. 옛날에 은환이가 하던 jupyter 메뉴에서 tensorboard를 여는 방법은, 은환이 왈, ‘jupyter notebook에서 tensorboard와 연동이 안되어 있을 거다.’ 나중에 jupyter에서 tensorboard를 여는 방법은 연동을 해서 할 수 있도록 찾아보자. (ml_workspace 에서 할 수 있는 것처럼.)
    4. jupyter로 작업하는 동안, vscode와 GCP로 tensorboard를 열려고 하면 event파일을 다른 프로세서에서 잡고 있기 때문에 열 수 없다. 따라서, 주피터 cell에다가 ! tensorboard –logdir=runs 를 치고 localhost로 들어가면 된다. 신기하게 여기서 localhost도 내 노트북 IP를 사용한다.
    5. 근데 4번처럼 하면 다른 셀을 실행할 수가 없다. 개같다…
  • vscode를 이용하는 경우
    1. terminal에서 $ tensorboard –logdir=runs 실행하면, localhost:6006링크를 준다.
    2. 그리고 그 링크를 클릭하면, 나의 노트북 ip를 이용해서(신기방기) tensorboard를 열어준다!!
    3. 이게 GCP SSH 보다 훨씬 편할 듯 하다!
  • 최종방법!
    1. 다음 사이트를 참고 했다. jupyter에서 tensorboard 사용법
    2. ‘vision’ conda env에서 pip install jupyter-tensorboard 실행(conda install 없다.)
    3. 성공!
      image

6. GPU 할당 받은 instance 만들기

  1. GPU 할당은 받았다. 하지만 Credit을 사용하고 있어서 GPU instance 만들기 불가능
  2. $ gcloud computer 를 사용하는, google console 을 사용해보기로 했다.
  3. 다음과 같은 명령어를 사용했다. 걸리는 점은 image project와 family설정을 아무리 해줘도, cuda가 이미 잘 설치된 image는 설정이 불가능하더라. GCP image document
    gcloud compute instances create p100-1 \
    --machine-type e2-standard-2 --zone us-west1-b \
    --accelerator type=nvidia-tesla-p100,count=1 \
    --image-family debian-9  --image-project debian-cloud   \
     --restart-on-failure 
    # [--preemptible] 다른 사람이 사용하면 나의 GPU를 뺏기게 가능하게 설정 But 저렴한 가격으로 GPU 사용가능

    >> ERROR: (gcloud.compute.instances.create) Could not fetch resource:
    >> - Instances with guest accelerators do not support live migration.
  1. 결국 나는 guest 이므로 accelerators (GPU) 사용 불가능. 하…

7. snapshot 과 image를 이용해서 vm-instance 복사 및 저장하기

  1. snapshot 만들기
  2. Image 만들기
  3. 프로젝트 구성원 추가하기
  4. 다른 계정에서 인스턴스 만들기
  5. 이미지 선택 -> 맞춤 이미지 -> 프로젝트 선택 -> 아까 만든 이미지 선택
  6. 이미지 공유 성공!(공유는 불가능하고 migration은 가능하다)

【Ubuntu】 노마드 코더의 윈도우 10 개발환경 구축

참고 사이트 : 노마드 코더의 윈도우 10 개발환경 구축
이 과정을 메모리가 좀 더 높은 컴퓨터에 하고 싶은데… 지금 새로운 것을 사서 하기도 그렇고 일단 삼성 노트북 팬s에서 잘해보고 나중에 컴퓨터 새로 사면 또 다시 설치 잘 해보자^^

## [Final setting Image] img

1. Setup

  1. windows Update
    windows 10 - 2004 버전까지 업데이트가 되어있어야 WSL를 사용가능하다.
  2. VScode
    vscode를 설치하고 다양한 extension을 설치하면 좋다.
    예를 들어서 나는 material Theme, material theme icons, prettier등이 좋았다.
  3. Chocolatey
    우리가 우분투에서 프로그램을 설치하려면
    $ sudo apt-get install kolourpaint4
    를 하면 쉽게 설치할 수 있었다. 윈도우에서도 이렇게 할수 있게 해주는게 Chocolatey이다. 설치방법은 간단하고, 이제 windows powershell에서 Find packages에서 알려주는 명령어를 그냥 복사, 붙여넣기하면 프로그램 설치를 매우 쉽게 할 수 있다. 그럼에도 불구하고 이것보다 Linux환경을 사용하는 것을 더욱 추천한다.
  4. windows terminal
    MS store에서 다운받을 수 있는 터미널. 그리거 여기 WSL를 파워셀에 써넣어서 리눅스 계열 OS(Ubunutu) 설치할 수 있게 해준다. 그리고 MS store에 들어가서 Ubuntu를 설치해준다.(다시시작 반복 할 것)
    설치 후 바로 위의 사이트의 ‘~옵션 구성 요소 사용’, ‘~기본 버전 설정’, ‘~WSL 2로 설정’등을 그대로 수행한다.

2. Terminal Customization

  1. $ sudo apt install zsh
  2. 사이트의 bash install을 이용해 우분투에 설치. curl, wget 이용한 설치든 상관없음.
  3. Oh my zsh 설치완료.
  4. 터미널 테마 변경하기
    이 사이트를 이용해서 새로운 schems를 만들어주고 colorScheme을 변경해주면 좋다.
            
     // To view the default settings, hold "alt" while clicking on the "Settings" button.
     // For documentation on these settings, see: https://aka.ms/terminal-documentation
    
     {
         "$schema": "https://aka.ms/terminal-profiles-schema",
    
         "defaultProfile": "{c6eaf9f4-32a7-5fdc-b5cf-066e8a4b1e40}",
    
         "profiles":
         {
             "defaults":
             {
                     "fontFace" : "MesloLGS NF"
             },
             "list":
             [
                
                 {
                     // Make changes here to the powershell.exe profile
                     "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
                     "name": "Windows PowerShell",
                     "commandline": "powershell.exe",
                     "hidden": false,
                     "colorScheme" : "Monokai Night"
                 },
                 {
                     // Make changes here to the cmd.exe profile
                     "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
                     "name": "cmd",
                     "commandline": "cmd.exe",
                     "hidden": true
                 },
                 {
                     "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
                     "hidden": true,
                     "name": "Azure Cloud Shell",
                     "source": "Windows.Terminal.Azure"
                 },
                 {
                     "guid": "{c6eaf9f4-32a7-5fdc-b5cf-066e8a4b1e40}",
                     "hidden": false,
                     "name": "Ubuntu-18.04",
                     "source": "Windows.Terminal.Wsl",
                     "colorScheme" : "VSCode Theme for Windows Terminal"
                 }
    
            
            
             ]
         },
    
         // Add custom color schemes to this array
         "schemes": [
             {
                 "name" : "Monokai Night",
                 "background" : "#1f1f1f",
                 "foreground" : "#f8f8f8",
                 "black" : "#1f1f1f",
                 "blue" : "#6699df",
                 "cyan" : "#e69f66",
                 "green" : "#a6e22e",
                 "purple" : "#ae81ff",
                 "red" : "#f92672",
                 "white" : "#f8f8f2",
                 "yellow" : "#e6db74",
                 "brightBlack" : "#75715e",
                 "brightBlue" : "#66d9ef",
                 "brightCyan" : "#e69f66",
                 "brightGreen" : "#a6e22e",
                 "brightPurple" : "#ae81ff",
                 "brightRed" : "#f92672",
                 "brightWhite" : "#f8f8f2",
                 "brightYellow" : "#e6db74"
             },
             {
                 "name" : "VSCode Theme for Windows Terminal",
                 "background" : "#232323",
                 "black" : "#000000",
                 "blue" : "#579BD5",
                 "brightBlack" : "#797979",
                 "brightBlue" : "#9BDBFE",
                 "brightCyan" : "#2BC4E2",
                 "brightGreen" : "#1AD69C",
                 "brightPurple" : "#DF89DD",
                 "brightRed" : "#F6645D",
                 "brightWhite" : "#EAEAEA",
                 "brightYellow" : "#F6F353",
                 "cyan" : "#00B6D6",
                 "foreground" : "#D3D3D3",
                 "green" : "#3FC48A",
                 "purple" : "#CA5BC8",
                 "red" : "#D8473F",
                 "white" : "#EAEAEA",
                 "yellow" : "#D7BA7D"
             }
    
         ],
    
         // Add any keybinding overrides to this array.
         // To unbind a default keybinding, set the command to "unbound"
         "keybindings": []
     }
    
  5. 명령어 라인 테마 변경하기 - Powerlevel10k
    이 사이트로 좀 더 좋은 테마로 변경. 터미널을 다시 열면 많은 설정이 뜬다.
    잠시 발생하는 에러를 헤결하기 위해, 나는 추가로 위의 사이트 중간 부분에 존재하는 font ‘MesloLGS NG’를 다운받고 윈도위 글꼴 설정에 넣어주었다. 그랬더니 모든 설정을 순조롭게 할 수 있었다. 그리고 신기하게 언제부터인가 터미널에서 핀치줌을 할 수 있다.(개꿀^^) 뭘 설치해서 그런지는 모르겠다.
  6. vscode 터미널 모양 바꿔주기
    setting -> Terminal › Integrated › Shell: Windows -> edit json -> “terminal.integrated.shell.windows”: “c:\Windows\System32\wsl.exe”
    image
  7. ls color : code ~/.zshrc
  • 추가 메모
    • 뭔가 혼자 찾으면 오래 걸릴 것을 순식간에 해버려서… 감당이 안된다. 이 전반적인 원리를 알지 못해서 조금 아쉽지만, 내가 필요한 건 이 일렬의 과정의 원리를 아는 것이 아니라 그냥 사용할 수 있을 정도로만 이렇게 설정할 수 있기만 하면되니까, 걱정하지말고 그냥 잘 사용하자. 이제는 우분투와 윈도우가 어떻게 연결되어 있는지 알아볼 차례이다.
    • powerlevel10k 환경설정을 처음부터 다시 하고 싶다면, $ p10k configure 만 치면 된다.
    • 주의 할 점!! 우분투에 ~/.zshrc 파일을 몇번 수정해 왔다. oh my zsh를 설치할 때 부터.. 그래서 지금 설치한 우분투 18.04를 삭제하고 다 깔면 지금까지의 일렬의 과정을 다시 해야한다. ‘## Terminal customization’과정을 처음주터 다시 하면 된다.

3. Installing Everything

  1. 우분투와 윈도우와의 관계
    $ cd /mnt(mount)/c(c드라이브) -> 우분투와 윈도우를 연결해주는 부분
    $ ls /mnt/c/Users/sb020 -> 결국에 여기가 나의 Document들이 있는 부분
    • 여기서 내가 torch, vi 등으로 파일을 만들고 수정해도 가능하다. 즉 우분투 상에서 윈도우에 접근해서 뭐든 할 수 있는 것이다.
    • 대부분의 WSL사용자들은 우분투 공간에서 윈도우 파일을 만들고 수정하지 않는다. 일반적인 우분투 사용자처럼 /home/junha/~ 에 파일이나 프로젝트를 넣어두고 다룬다. 하지만!! 이러한 방법은 WSL에 문제가 생기거나 Ubuntu-18.04에 문제가 생겨서 지우게 된다면 발생하는 문제를 고스란히 감안해야한다. 따라서 노마드 쌤이 추천하길, 우분투 경로 말고 /mnt/c 위의 윈도우 경로에, 프로젝트 파일 등은 저장하고 다루는 것이 좋다.
    • 리눅스 콘솔에서 윈도우에 있는 파일을 건드릴 수 있다. 하지만 윈도우에서 리눅스 파일(/home/junha 맞나..? 잘 모르곘다. )을 건드린다면 그건 좋은 방법이 아니다. 문제가 발생할 수도 있다.
    • conda에 대한 나의 생각 : zsh의 상태를 보면 conda를 쳐도 읽지를 못한다. 이 말은 conda는 윈도우의 powerShell이나 cmd에서만 동장한다. 따라서 우분투에 들어가서 항상 내가 아나콘다부터 설치한 듯이, 아나콘다를 다시 설치해야한다.^^
  2. bashrc NO!. zshrc Yes!.
    • 강의에서 nodejs를 설치했다. 나는 그동안 anaconda를 설치했다. /home/junha/anaconda에 설치가 되었다. /mnt/c/Users/sb020/anaconda와는 완전히 다른 것이다. 즉 내가 설치한 Ubunutu 18.04에 ubuntu를 설치한 것이고, c드라이브와 영향은 없는 것으로 추측할 수 있다. /ageron/handson-ml/blob/master/requirements.txt) 딥러닝에 유용한 package requirements를 다운받을 수 있었다. (python == 3.6 version이어야 requiremtnet.txt가 잘 작동)
    • 이렇게 처음 설치하면 딥러닝 환경 설정으로 아주 편하다. conda를 사용해서 설정하는게 package 버전 관리에 매우 유용하다. pip을 사용해도 되지만 같이 쓰면 항상 문제가 발생하더라…
        $ conda install Numpy Scipy Scikit-learn Theano TensorFlow Keras PyTorch Pandas Matplotlib      
        $ conda install -c conda-forge opencv  
        $ conda install -c pytorch torchvision
      
    • 엄청난 것을 깨달았다. 왜 ~/.bashrc 에 conda에 관한 아무런 내용이 없지? 라고 생각했다. 왜냐하면 나는 지금 zsh shell을 사용하고 있기 때문이다. 따라서 ~/.zshrc 에 들어가면 conda에 대한 설정이 있었다.
    • vi를 사용해서 파일을 수정할 필요가 이제 없다. $ vi ~/.zshrc 하지말고 $ code ~/.zshrc를 하면 매우 쉽다. (vscode 자동실행) 여기에 들어가서 alias를 이용해서 단축어를 만들어놨다.
        alias python=python3.8  
        alias win="cd /mnt/c/Users/sb020"  
        alias acttor="conda activate torch"  
      
  3. WSL ubuntu VScode
    • image
    • 위의 사진에서 보이는 것처럼, 2가지의 운영체제에서 하나의 vscode를 사용하고 있다. 따라서 Extentions도 여러가지 다시 설치해줘야했다. 또한 VScode 맨아래 왼쪽에 WSL과 Local VScode로 이동할 수 있는 버튼이 있었다.
    • prettier를 사용하면 코드를 save하면 코드를 이쁘게 다 재배열해준다. vscode에 가장 필요한 extentions라고 하는데 진짜인 것 같다. WSL setting에 들어가서 ‘editer format on save’설정을 해줘야한다. 윈도우, 우분투 vscode Setting은 완전히 다르다. 따라서 윈도우도 같은 설정을 해줬다.
    • 하지만… 아래와 같이 이와 같은 오류가 떴다. “Failed to load module. If you have prettier or plugins referenced in package.json, ensure you have run npm install Attempted to load prettier from c:\projects\junha1125.github.io”
    • 그래서 npm 설치하기 위해서 인터넷에서 찾아보니 nodejs를 다운받으라고 해서 choco를 통해 빠르게 다운받았다. 그래도 안됐다.
    • 아래의 사진과 같이 setting도 2가지 환경에서 서로 다르게 셋팅할 수 있으니 주의할 것.
      image
    • 주의 더이상 vi쓰지마라. $ code <pathName or fileName or directoryName>
  4. VScode 사용 주의사항
    • interpretter 설정에 주의하기
      image

【Pytorch 실습】RNN, LSTM을 활용한 영화 평점 예측 모델.

아래의 코드는 Kaggle 및 Git의 공개된 코드를 적극 활용한, 과거의 공부한 내용을 정리한 내용입니다.

【Pytorch 실습】RNN, LSTM을 활용한 영화 리뷰 예측 모델.

  • torchvision이 아니라 torchtext에서 데이터를 가져오기 위해 torchtext import
  • 자연어 같은 경우 Text의 전처리가 가장 중요하다.
  • 자연어를 다뤄야할 일이 있다면 아래의 내용이나 torch document의 내용을 참고 공부하고 공부한다면 더 좋을 것 같다.
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchtext import data, datasets
BATCH_SIZE = 100
LR = 0.001
EPOCHS = 15
USE_CUDA = torch.cuda.is_available()

1. Data Load(Text이므로 어려울 수 있다.)

DEVICE = torch.device("cuda" if USE_CUDA else "cpu")
TEXT = data.Field(sequential = True, batch_first = True, lower = True) # lower : 전부 소문자로
LABEL = data.Field(sequential = False, batch_first = True) # 평점 : 긍정 vs 부정
  • datasets들 중에서 IMDB 데이터를 가져온다. 영화 리뷰 글(Text) + 긍정/부정(Lavel)가 있다.
    trainset, testset = datasets.IMDB.splits(TEXT, LABEL) 
    
  • 데이터가 문장이 되어 있으므로, 띄어쓰기 단위로 단어로 자른다. 그런 후 단어가 총 몇개가 있는지 확인한다. Ex i am a boy = 4 개
    TEXT.build_vocab(trainset, min_freq = 5) # 최고 5번 이상 나온 단어만 voca로 구분하겠다. 
    LABEL.build_vocab(trainset)
    
  • Train dataset과 valuation dataset으로 구분한다. split 함수를 사용하면 쉽다.
  • iter로 놓음으로써, 나중에 베치사이즈 기준으로 학습 시키기 쉽게 만든다.
    trainset, valset = trainset.split(split_ratio = 0.8)
    train_iter, val_iter, test_iter = data.BucketIterator.splits((trainset, valset, testset), batch_size = BATCH_SIZE, shuffle = True, repeat = False)
    
vocab_size = len(TEXT.vocab)
n_classes = 2  # 긍정 vs 부정
print("[TRAIN]: %d \t [VALID]: %d \t [TEST]: %d \t [VOCAB] %d \t [CLASSES] %d" % (len(trainset), len(valset), len(testset), vocab_size, n_classes))

[VOCAB] 46159(Train set안에 있는 voca만) [CLASSES] 2

2. RNN 모델 구현

class BasicRNN(nn.Module):
    def __init__(self, n_layers, hidden_dim, n_vocab, embed_dim, n_classes, dropout_p = 0.2):
        super(BasicRNN, self).__init__()
        print("Building RNN")
        self.n_layers = n_layers # layer 갯수 RNN을 몇번 돌건지
        self.embed = nn.Embedding(n_vocab, embed_dim) # 한 단어를 하나의 백터/값으로 임베팅 한다.
        self.hidden_dim = hidden_dim
        self.dropout = nn.Dropout(dropout_p)
        self.rnn = nn.RNN(embed_dim, self.hidden_dim, num_layers = self.n_layers, batch_first = True) # nn.RNN 을 이용하면 쉽게 RNN구현 가능!!
        self.out = nn.Linear(self.hidden_dim, n_classes) 

    def forward(self, x):
        x = self.embed(x) # 문자를 숫자/백터로 변환
        h_0 = self._init_state(batch_size = x.size(0)) # 가장 첫번째 h0는 아직 정의되지 않았으므로 다음과 같이 정의 해준다. 
        x, _ = self.rnn(x, h_0) # 이렇게 손쉽게 RNN을 구현할 수 있다. 
        h_t = x[:, -1, :] # 모든 문장을 거쳐서 나온 가장 마지막에 나온 단어(평점)의 값
        self.dropout(h_t)
        logit = torch.sigmoid(self.out(h_t))
        return logit

    def _init_state(self, batch_size = 1):
        weight = next(self.parameters()).data # hidden state에 대한 차원은 맞춰주면서 가중치 값은 아직은 0으로 만들어 준다. 
        return weight.new(self.n_layers, batch_size, self.hidden_dim).zero_()

3. 학습 및 추론

def train(model, optimizer, train_iter):
    model.train()
    for b, batch in enumerate(train_iter):
        x, y = batch.text.to(DEVICE), batch.label.to(DEVICE)
        y.data.sub_(1)
        optimizer.zero_grad()

        logit = model(x)
        loss = F.cross_entropy(logit, y)
        loss.backward()
        optimizer.step()

        if b % 50 == 0:
            print("Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}".format(e,
                                                                           b * len(x),
                                                                           len(train_iter.dataset),
                                                                           100. * b / len(train_iter),
                                                                           loss.item()))
def evaluate(model, val_iter):
    model.eval()
    corrects, total_loss = 0, 0

    for batch in val_iter:
        x, y = batch.text.to(DEVICE), batch.label.to(DEVICE)
        y.data.sub_(1) # 0아니면 1로 데이터 값 수정
        logit = model(x)
        loss = F.cross_entropy(logit, y, reduction = "sum")
        total_loss += loss.item()
        corrects += (logit.max(1)[1].view(y.size()).data == y.data).sum()

    size = len(val_iter.dataset)
    avg_loss = total_loss / size
    avg_accuracy = 100.0 * corrects / size
    return avg_loss, avg_accuracy
model = BasicRNN(n_layers = 1, hidden_dim = 256, n_vocab = vocab_size, embed_dim = 128, n_classes = n_classes, dropout_p = 0.5).to(DEVICE)
optimizer = torch.optim.Adam(model.parameters(), lr = LR)
for e in range(1, EPOCHS + 1):
    train(model, optimizer, train_iter)
    val_loss, val_accuracy = evaluate(model, val_iter)
    print("[EPOCH: %d], Validation Loss: %5.2f | Validation Accuracy: %5.2f" % (e, val_loss, val_accuracy))
Building RNN
Train Epoch: 1 [0/20000 (0%)]	Loss: 0.693486
Train Epoch: 1 [5000/20000 (25%)]	Loss: 0.693027
Train Epoch: 1 [10000/20000 (50%)]	Loss: 0.692615
Train Epoch: 1 [15000/20000 (75%)]	Loss: 0.693534
[EPOCH: 1], Validation Loss:  0.69 | Validation Accuracy: 49.00

Train Epoch: 15 [0/20000 (0%)]	Loss: 0.692949
Train Epoch: 15 [5000/20000 (25%)]	Loss: 0.695515
Train Epoch: 15 [10000/20000 (50%)]	Loss: 0.692522
Train Epoch: 15 [15000/20000 (75%)]	Loss: 0.693040
[EPOCH: 15], Validation Loss:  0.69 | Validation Accuracy: 50.00
test_loss, test_acc = evaluate(model,test_iter)
print("Test Loss: %5.2f | Test Accuracy: %5.2f" % (test_loss, test_acc))
Test Loss:  0.70 | Test Accuracy: 50.00

4. GRU 모델 구현 및 학습추론

  • RNN과 전체적인 구조가 같으나, Hidden state에서 사용되는 gate가 2개이다.
    class BasicGRU(nn.Module):
      def __init__(self, n_layers, hidden_dim, n_vocab, embed_dim, n_classes, dropout_p = 0.2):
          super(BasicGRU, self).__init__()
          print("Building GRU")
          self.n_layers = n_layers
          self.embed = nn.Embedding(n_vocab, embed_dim)
          self.hidden_dim = hidden_dim
          self.dropout = nn.Dropout(dropout_p)
          self.gru = nn.GRU(embed_dim, self.hidden_dim, num_layers = self.n_layers, batch_first = True)
          self.out = nn.Linear(self.hidden_dim, n_classes)
            
      def forward(self, x):
          x = self.embed(x)
          h_0 = self._init_state(batch_size = x.size(0))
          x, _ = self.gru(x, h_0)
          h_t = x[:, -1, :]
          self.dropout(h_t)
          logit = torch.sigmoid(self.out(h_t))
          return logit
        
      def _init_state(self, batch_size = 1):
          weight = next(self.parameters()).data
          return weight.new(self.n_layers, batch_size, self.hidden_dim).zero_()
    
model = BasicGRU(n_layers = 1, hidden_dim = 256, n_vocab = vocab_size, embed_dim = 128, n_classes = n_classes, dropout_p = 0.5).to(DEVICE)
optimizer = torch.optim.Adam(model.parameters(), lr = LR)
for e in range(1, EPOCHS + 1):
    train(model, optimizer, train_iter)
    val_loss, val_accuracy = evaluate(model, val_iter)
    print("[EPOCH: %d], Validation Loss: %5.2f | Validation Accuracy: %5.2f" % (e, val_loss, val_accuracy))
Building GRU
Train Epoch: 1 [0/20000 (0%)]	Loss: 0.691595
Train Epoch: 1 [5000/20000 (25%)]	Loss: 0.693059
Train Epoch: 1 [10000/20000 (50%)]	Loss: 0.693562
Train Epoch: 1 [15000/20000 (75%)]	Loss: 0.693485
[EPOCH: 1], Validation Loss:  0.69 | Validation Accuracy: 50.00
 
Train Epoch: 15 [0/20000 (0%)]	Loss: 0.363591
Train Epoch: 15 [5000/20000 (25%)]	Loss: 0.324579
Train Epoch: 15 [10000/20000 (50%)]	Loss: 0.335097
Train Epoch: 15 [15000/20000 (75%)]	Loss: 0.333244
[EPOCH: 15], Validation Loss:  0.45 | Validation Accuracy: 85.00
test_loss, test_acc = evaluate(model,test_iter)
print("Test Loss: %5.2f | Test Accuracy: %5.2f" % (test_loss, test_acc))
Test Loss:  0.46 | Test Accuracy: 84.00

5. GRU 모델 구현 및 학습추론

  • 알고 있듯이 LSTM의 Cell state의 gate는 forget,input,ouput이 존재한다.
  • 이렇게 nn모듈을 사용해서 LSTM을 쉽게 구현하고 사용할 수 있다.
class BasicLSTM(nn.Module):
    def __init__(self, n_layers, hidden_dim, n_vocab, embed_dim, n_classes, dropout_p = 0.2):
        super(BasicLSTM, self).__init__()
        print("Building LSTM")
        self.n_layers = n_layers
        self.embed = nn.Embedding(n_vocab, embed_dim)
        self.hidden_dim = hidden_dim
        self.dropout = nn.Dropout(dropout_p)
        self.lstm = nn.LSTM(embed_dim, self.hidden_dim, num_layers = self.n_layers, batch_first = True)
        self.out = nn.Linear(self.hidden_dim, n_classes)
        
    def forward(self, x):
        x = self.embed(x)
        h_0 = self._init_state(batch_size = x.size(0))
        c_0 = self._init_state(batch_size = x.size(0))
        
        x, _ = self.lstm(x, (h_0, c_0))
        h_t = x[:, -1, :]
        self.dropout(h_t)
        logit = torch.sigmoid(self.out(h_t))
        return logit
    
    def _init_state(self, batch_size = 1):
        weight = next(self.parameters()).data
        return weight.new(self.n_layers, batch_size, self.hidden_dim).zero_()
model = BasicLSTM(n_layers = 1, hidden_dim = 256, n_vocab = vocab_size, embed_dim = 128, n_classes = n_classes, dropout_p = 0.5).to(DEVICE)
optimizer = torch.optim.Adam(model.parameters(), lr = LR)
for e in range(1, EPOCHS + 1):
    train(model, optimizer, train_iter)
    val_loss, val_accuracy = evaluate(model, val_iter)
    print("[EPOCH: %d], Validation Loss: %5.2f | Validation Accuracy: %5.2f" % (e, val_loss, val_accuracy))
Building LSTM
Train Epoch: 1 [0/20000 (0%)]	Loss: 0.693381
Train Epoch: 1 [5000/20000 (25%)]	Loss: 0.693180
Train Epoch: 1 [10000/20000 (50%)]	Loss: 0.693065
Train Epoch: 1 [15000/20000 (75%)]	Loss: 0.695363
[EPOCH: 1], Validation Loss:  0.69 | Validation Accuracy: 49.00
   
Train Epoch: 15 [0/20000 (0%)]	Loss: 0.427247
Train Epoch: 15 [5000/20000 (25%)]	Loss: 0.454655
Train Epoch: 15 [10000/20000 (50%)]	Loss: 0.428639
Train Epoch: 15 [15000/20000 (75%)]	Loss: 0.428214
[EPOCH: 15], Validation Loss:  0.49 | Validation Accuracy: 82.00
test_loss, test_acc = evaluate(model,test_iter)
print("Test Loss: %5.2f | Test Accuracy: %5.2f" % (test_loss, test_acc))
Test Loss:  0.50 | Test Accuracy: 80.00

【Pytorch 실습】Pytorch 내장 Model 사용, 내장 weight 사용해서 Transfer Learning하기

아래의 코드는 Kaggle 및 Git의 공개된 코드를 적극 활용한, 과거의 공부한 내용을 정리한 내용입니다.

【Pytorch 실습】Pytorch 내장 Model 사용, 내장 weight 사용해서 Transfer Learning하기

1. 데이터 로드

  • 지금까지와는 약간 다르게 데이터 로드
  • hymenoptera_data를 사용할 예정이다. 다운로드 는 여기서 하면 되고, 데이터 구조는 다음과 같다. 꿀벌과 개미를 분류하기 위한 데이터 셋이다.
    image
  • 아래와 같은 방법 전처리 할 수 있다. 지금까지의 dataset, dataloader를 구성할 때와의 방법과는 조금 다르다.
  • 적은 데이터를 이용하기 위해, Data argumentation하는 방법이 아래와 같이 transforms.Compose를 이용하면 되는 것을 알아두자.
import torch 
USE_CUDA = torch.cuda.is_available()
DEVICE = torch.device("cuda" if USE_CUDA else "cpu")
from torchvision import datasets, transforms

data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.CenterCrop(224),
        transforms.Resize(256),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

image_datasets = {x: datasets.ImageFolder("../data/hymenoptera_data", data_transforms[x]) for x in ['train', 'val']}
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size = 8, num_workers = 0, shuffle = True) for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
class_names = image_datasets['train'].classes

2. 학습 및 추론 함수 정의

def train(model, train_loader, optimizer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(DEVICE), target.to(DEVICE)
        optimizer.zero_grad()
        output = model(data)
        loss = F.cross_entropy(output, target)
        loss.backward()
        optimizer.step()
        
        if batch_idx % 10 == 0:
            print("Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}".format(
                epoch, 
                batch_idx * len(data), 
                len(train_loader.dataset), 
                100. * batch_idx / len(train_loader), 
                loss.item()))


def evaluate(model, test_loader):
    model.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(DEVICE), target.to(DEVICE)
            output = model(data)
            test_loss += F.cross_entropy(output, target, reduction = "sum").item()
            prediction = output.max(1, keepdim = True)[1]
            correct += prediction.eq(target.view_as(prediction)).sum().item()
    
    test_loss /= len(test_loader.dataset)
    test_accuracy = 100. * correct / len(test_loader.dataset)
    return test_loss, test_accuracy

3. 내장 모델 사용하기(Transfer Learning 안함)

  • pretrained = True 를 사용하면 ImageNet에서 사용한 파라메터를 사용한다.
  • torch의 내장 모델을 그냥 사용할 때, input과 output사이즈(Groud True data size)는 현재 나의 data에 따라서 달라지기 떄문에 전혀 걱정하지 않아도 된다.
import torchvision.models as models
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

model = models.resnet18(pretrained = False).cuda()
optimizer = optim.Adam(model.parameters(), lr = 0.0001)
EPOCHS = 10
for epoch in range(1, EPOCHS + 1):
    train(model, dataloaders["train"], optimizer, epoch)
    test_loss, test_accuracy = evaluate(model, dataloaders["val"])
    print("[{}] Test Loss: {:.4f}, accuracy: {:.2f}%\n".format(epoch, test_loss, test_accuracy))
Train Epoch: 10 [0/397 (0%)]	Loss: 0.636741
Train Epoch: 10 [80/397 (20%)]	Loss: 0.449106
Train Epoch: 10 [160/397 (40%)]	Loss: 0.607533
Train Epoch: 10 [240/397 (60%)]	Loss: 0.713035
Train Epoch: 10 [320/397 (80%)]	Loss: 0.705570
[10] Test Loss: 0.6319, accuracy: 66.25%

4. 내장 모델 사용하기(Transfer Learning 사용)

  • pretrained된 weight를 사용하면, 마지막 Feature는 1*1000(ImageNet의 Class 갯수)이다.
  • 따라서 마지막에 출력되는 Feature의 갯수를 지금 나의 데이터의 Class의 갯수로 맞춰줘야 한다. 따라서 다음과 같은 작업을 수행한다.
model = models.resnet18(pretrained = True) 
num_ftrs = model.fc.in_features   # fully connected layer에 들어가기 직전의 feature의 갯수(numbers)를 알아온다. 
model.fc = nn.Linear(num_ftrs, 2) 
# model의 마지막 fully connected layer의 정의를 바꿔 버린다.  
model.fc = nn.Linear(num_ftrs, 2) 
# 원래는 num_ftrs -> 1000 이었다면, num_ftrs -> 2 으로 바꾼다. 


if USE_CUDA:
    model = model.cuda()

optimizer = optim.Adam(model.parameters(), lr = 0.0001)
EPOCHS = 10
for epoch in range(1, EPOCHS + 1):
    train(model, dataloaders["train"], optimizer, epoch)
    test_loss, test_accuracy = evaluate(model, dataloaders["val"])
    print("[{}] Test Loss: {:.4f}, accuracy: {:.2f}%\n".format(epoch, test_loss, test_accuracy))
Train Epoch: 10 [0/397 (0%)]	Loss: 0.821322
Train Epoch: 10 [80/397 (20%)]	Loss: 0.526726
Train Epoch: 10 [160/397 (40%)]	Loss: 0.820258
Train Epoch: 10 [240/397 (60%)]	Loss: 0.242522
Train Epoch: 10 [320/397 (80%)]	Loss: 0.604658
[10] Test Loss: 0.2158, accuracy: 93.70%
  • param.requires_grad = False : Backward에 의해서 gradient 계산이 안된다.
  • 아래와 같이 코딩을 하면 ‘nn.Linear(num_ftrs, 2)’로 정의한 마지막 Layer만 Backpropagation으로 weight가 update되지만, 나머지 pretrained weight 즉 가져온 weight는 변하지 않는다.
model = models.resnet18(pretrained=True)
for param in model.parameters():
    param.requires_grad = False 
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 2)

model = model.cuda()

optimizer = optim.Adam(model.parameters(), lr = 0.0001)

EPOCHS = 10
for epoch in range(1, EPOCHS + 1):
    train(model, dataloaders["train"], optimizer, epoch)
    test_loss, test_accuracy = evaluate(model, dataloaders["val"])
    print("[{}] Test Loss: {:.4f}, accuracy: {:.2f}%\n".format(epoch, test_loss, test_accuracy))
Train Epoch: 10 [0/397 (0%)]	Loss: 0.773592
Train Epoch: 10 [80/397 (20%)]	Loss: 0.575552
Train Epoch: 10 [160/397 (40%)]	Loss: 0.498209
Train Epoch: 10 [240/397 (60%)]	Loss: 0.761115
Train Epoch: 10 [320/397 (80%)]	Loss: 0.598199
[10] Test Loss: 0.6826, accuracy: 59.45%

Pagination


© All rights reserved By Junha Song.