【Paper】 Deep Learning for Generic Object Detection, A Survey - Summary

Deep Learning for Generic Object Detection, A Survey 논문 리뷰 및 정리

Deep Learning for Generic Object Detection: A Survey

My Conclusion after I read the paper.

0. Abstract

  1. a comprehensive survey of the recent achievements
  2. More than 300 research contributions
  3. frameworks/ representation/ proposal generation/ context modeling/ training strategies/ evaluation metrics
  4. promising directions for future research

1. introduction

  • Deep Convolutional Neural Network (DCNN) called AlexNet in 2012
  • Over the past 5 years, this article attempts to track in order to gain a clearer picture
  • popular datasets/ evaluation metrics/ context modeling/ detection proposal methods.

  • many object detection previous surveys (refer to reference this paper later)
    • pedestrian detection
    • face detection
    • vehicle detection
    • traffic sign detection
    • generic object detection
  • we have limited our focus to top journal and conference papers. and limited picture detection not Video.
  • follows
    1. 20-years are summarized
    2. A brief introduction to deep learning
    3. Popular datasets and evaluation criteria
    4. the milestone object detection frameworks
    5. state-of-the- art performance
    6. future research directions

2. Generic Object Detection

2.1 The Problem

  • future challenges will move to the pixel level object detection.

2.2 Challenges

  • Accuracy Related Challenges
    • intra-class variations : color, texture, material, shape, size, poses, clothes
    • Imaging condition variations : lighting, physical location, weather, backgrounds
    • 20, 200, 91 object classes / VOC, ILSVRC, COCO is much smaller than can be recognized by humans.
  • Efficiency and Scalability Related Challenges
    • mobile/wearable devices have limited computational capabilities and storage space
    • A further challenge is that of scalability : unseen objects, unknown situations, it may become impossible to annotate them manually, forcing a reliance on weakly supervised strategies.

2.3 Progress in the Past 2 Decades

  • image-20210114173125275
  • accurate annotations are labor intensive to obtain
  • Ability to detect many object categories matches that of humans(인간 같은) 3000~3000 categories is undoubtedly an unresolved problem so far.

3. A Brief Introduction to Deep Learning

  • pass

4.1 Dataset

  • PASCAL VOC
  • ImageNet
  • MS COCO
  • Places
  • Open Images

4.2 Evaluation Criteria

  • Frames Per Second (FPS)
  • precision, and recall.
  • Average Precision (AP) -> over all object categories, the mean AP (mAP)

5. Basic Frameworks

  • image-20210114192428720
  • image-20210114201752611

【Paper】 convolutional Block Attention Module - Paper Summary

CBAM : Convolutional Block Attention Module

0. Abstract

  1. our module sequentially infers attention maps along two separate dimensions
  2. the attention maps are multiplied to the input feature map for adaptive feature refinement (향상되어 정제된 feature)
  3. lightweight and general module, it can be integrated into any CNN architectures

1. introduction

  1. Recent Detectors
    1. recent researches have mainly investigated depth, width(#channel), and cardinality(같은 형태의 빌딩 블록의 갯수).
    2. VGGNet, ResNet, GoogLeNet has become deeper for rich representation(중요한 특징 표현력).
    3. GoogLeNet and Wide ResNet(2016), width must be another important factor.
    4. Xception and ResNeXt, increase the cardinality of a network . the cardinality saves the total number of parameters and make results powerful than depth and width.
    5. significant visual attention papers
      • [16] A recurrent neural network for image generation
      • [17] Spatial transformer networks
  2. Emphasize meaningful features / along those two principal dimensions / channel(depth) and spatial axes(x,y). -> channel and spatial attention modules -> learning which information to emphasize or suppress.
    • image-20210114212858200
  3. Contribution
    1. Can be widely applied to boost representation power of CNNs
    2. Extensive ablation studies
    3. Performance of various networks is greatly improved

2. Related Work

  1. Network engineering

    1. ResNet / ResNeXt / Inception-ResNet
    2. WideResNet : a larger number of convolutional filters and reduced depth
      • image-20210114214240109
    3. PyramidNet : a strict generalization of WideResNet and the width increases.
      • image-20210114214431894
    4. ResNeXt : use grouped convolutions and vertify cardinality effect
      • image-20210114214135397
    5. DenseNet : Concatenates the input features with the output features
      • image-20210114214036592
  2. Attention

    • (2017) Residual attention network for image classification
      • image-20210114215737540
      • encoderdecoder style attention module
      • By refining the feature maps, performance good, robust to noisy inputs
      • more computational and parameter
    • (2017) Squeeze-and-excitation networks
      • image-20210114220217634
      • Exploit the inter-channel relationship
      • global average-pooled features to compute channel-wise attention. (‘what’ to focus) -> we suggest to use max-pooled features.
      • miss the spatial attention deciding ‘where’ to focus.
    • (2019) Spatial and channel-wise attention in convolutional networks for image captioning

3. Convolutional Block Attention Module

image-20210114223009703

  • ⊗ : element-wise multiplication
  • channel attention values are broadcasted along the spatial dimension

  • Channel attention module

    • In the past, make model learn the extent of the target object or compute spatial statistics.[33] [28]
    • exploiting the inter-channel relationship of features.
    • each channel is considered as a a feature detector.
    • ‘what’ is meaningful
    • average pooling and max-pooling -> two different spatial context (F^c_avg and F^c_max)
    • image-20210114224244736
    • W1, W0 are shared for both inputs and the ReLU activation function is followed by W0. r = reduction ratio.
  • Spatial attention module

    • The design philosophy is symmetric with the channel attention branch.
    • [34] Paying more attention to attention, pooling along channel axis can be effective in highlighting informative regions.
    • concatenated feature (both descriptor)
    • image-20210114225054378 : encodes where to emphasize or suppress.
    • image-20210114225827305
    • σ : the sigmoid function, the filter size of 7 × 7
  • Arrangement of attention modules

    • the sequential arrangement gives a better result than a parallel arrangement. (첫번째 그림처럼. 직렬로. width하게 병렬로 NO)
    • our experimental result.

4. Experiments

  • We apply CBAM on the convolution outputs in each block
  • image-20210114230937883
  • top-5 error, top-1 error : 감소해야 좋음
  • FLOPS = FLoating point Operations Per Second
    GFLOPS = GPU FLoating point Operations Per Second
    (그래픽카드의 소요 정도)
  • we empirically show the effectiveness of our design choice.
    • FLOPS = FLoating point Operations Per Second
      GFLOPS = GPU FLoating point Operations Per Second
      (그래픽카드의 소요 정도)
    • Channel attention
      • a shared MLP
      • using both poolings
      • r = the reduction ratio to 16.
    • Spatial attention
      • channelpooling
      • convolution layer with a large kernel size
    • Arrangement

4.2 Image Classification on ImageNet-1K

4.3 Network Visualization with Grad-CAM

  • Grad-CAM is a recently proposed visualization method.
  • Grad-CAM uses gradients in order to calculate the importance of the spatial locations.
  • image-20210114233249882

5. conclusion

  • we observed that our module induces the network to focus on target object properly.
  • We hope CBAM become an important component of various network architectures.

모르는 내용

【CV】Computer Vision at FastCampus1, chap1~6

FastCampus 사이트의 Computer vision 강의 내용 정리

  1. FastCampus 사이트의 Computer vision 강의 내용을 정리해 두었다.
  2. 수학적이고, 심도적인 내용은 윤성민교수님의 컴퓨터 비전 수업을 통해 배울 수 있었다. 강의 필기 자료는 다음에 업로드할 예정.
  3. 심도적인 증명보다는, OpenCV를 사용해서 실습에 바로 적용할 수 있도록 하는데 중점을 주는 좋은 강의 였다.
  4. 몇가지 중요한 부분만 정리해 놓는다. 만약 다음에 공부할 필요가 느껴지면 그때 다시 사이트에 들어가서 공부하면 된다.
  5. FastCampus - Computer vision Lecture

목차

  • 아래의 목차에서 정말 듣고 싶은 것만 듣자.
  • 어차피 학교 수업에서도 배울 내용이고, 너무 오래전 기술이라 몰라도 되는 것도 많다.
  • 따라서 목차를 보고 ‘이런 내용이 있구나’하고 나중에 필요하면, 와서 듣자. 지금은 진짜 궁금한것만 듣자.
  •   OpenCV-Python 시작하기
      Ch 01. OpenCV-Python 시작하기 - 01. 전체 코스와 컴퓨터 비전 소개
      Ch 01. OpenCV-Python 시작하기 - 02. 영상의 구조와 표현
      Ch 01. OpenCV-Python 시작하기 - 03. OpenCV 소개와 설치
      Ch 01. OpenCV-Python 시작하기 - 04. VS Code 설치와 개발 환경 설정
      Ch 01. OpenCV-Python 시작하기 - 05. 영상 파일 불러와서 출력하기
      Ch 01. OpenCV-Python 시작하기 - 06. OpenCV 주요 함수 설명
      Ch 01. OpenCV-Python 시작하기 - 07. Matplotlib 사용하여 영상 출력하기
      Ch 01. OpenCV-Python 시작하기 - 08. 실전 코딩 - 이미지 슬라이드쇼
      OpenCV-Python 기초 사용법
      Ch 02. OpenCV-Python 기초 사용법 - 01. 영상의 속성과 픽셀 값 처리
      Ch 02. OpenCV-Python 기초 사용법 - 02. 영상의 생성, 복사, 부분 영상 추출
      Ch 02. OpenCV-Python 기초 사용법 - 03. 마스크 연산과 ROI
      Ch 02. OpenCV-Python 기초 사용법 - 04. OpenCV 그리기 함수
      Ch 02. OpenCV-Python 기초 사용법 - 05. 카메라와 동영상 처리하기 1
      Ch 02. OpenCV-Python 기초 사용법 - 06. 카메라와 동영상 처리하기 2
      Ch 02. OpenCV-Python 기초 사용법 - 07. 키보드 이벤트 처리하기
      Ch 02. OpenCV-Python 기초 사용법 - 08. 마우스 이벤트 처리하기
      Ch 02. OpenCV-Python 기초 사용법 - 09. 트랙바 사용하기
      Ch 02. OpenCV-Python 기초 사용법 - 10. 연산 시간 측정 방법
      Ch 02. OpenCV-Python 기초 사용법 - 11. 실전 코딩 - 동영상 전환 이펙트
      기본적인 영상 처리 기법
      Ch 03. 기본적인 영상 처리 기법 - 01. 영상의 밝기 조절
      Ch 03. 기본적인 영상 처리 기법 - 02. 영상의 산술 및 논리 연산
      Ch 03. 기본적인 영상 처리 기법 - 03. 컬러 영상 처리와 색 공간
      Ch 03. 기본적인 영상 처리 기법 - 04. 히스토그램 분석
      Ch 03. 기본적인 영상 처리 기법 - 05. 영상의 명암비 조절
      Ch 03. 기본적인 영상 처리 기법 - 06. 히스토그램 평활화
      Ch 03. 기본적인 영상 처리 기법 - 07. 특정 색상 영역 추출하기
      Ch 03. 기본적인 영상 처리 기법 - 08. 히스토그램 역투영
      Ch 03. 기본적인 영상 처리 기법 - 09. 실전 코딩 - 크로마키 합성
      필터링
      Ch 04. 필터링 - 01. 필터링 이해하기
      Ch 04. 필터링 - 02. 블러링 (1) - 평균값 필터
      Ch 04. 필터링 - 03. 블러링 (2) - 가우시안 필터
      Ch 04. 필터링 - 04. 샤프닝 - 언샤프 마스크 필터
      Ch 04. 필터링 - 05. 잡음 제거 (1) - 미디언 필터
      Ch 04. 필터링 - 06. 잡음 제거 (2) - 양방향 필터
      Ch 04. 필터링 - 07. 실전 코딩 - 카툰 필터 카메라
      기하학적 변환
      Ch 05. 기하학적 변환 - 01. 영상의 이동 변환과 전단 변환
      Ch 05. 기하학적 변환 - 02. 영상의 확대와 축소
      Ch 05. 기하학적 변환 - 03. 이미지 피라미드
      Ch 05. 기하학적 변환 - 04. 영상의 회전
      Ch 05. 기하학적 변환 - 05. 어파인 변환과 투시 변환
      Ch 05. 기하학적 변환 - 06. 리매핑
      Ch 05. 기하학적 변환 - 07. 실전 코딩 - 문서 스캐너
      영상의 특징 추출
      CH 06. 영상의 특징 추출 - 01. 영상의 미분과 소베 필터
      CH 06. 영상의 특징 추출 - 02. 그래디언트와 에지 검출
      CH 06. 영상의 특징 추출 - 03. 캐니 에지 검출
      CH 06. 영상의 특징 추출 - 04. 허프 변환 직선 검출
      CH 06. 영상의 특징 추출 - 05. 허프 원 변환 원 검출
      CH 06. 영상의 특징 추출 - 06. 실전 코딩 동전 카운터
      이진 영상 처리
      CH 07. 이진 영상 처리 - 01. 영상의 이진화
      CH 07. 이진 영상 처리 - 02. 자동 이진화 Otsu 방법
      CH 07. 이진 영상 처리 - 03. 지역 이진화
      CH 07. 이진 영상 처리 - 04. 모폴로지 (1) 침식과 팽창
      CH 07. 이진 영상 처리 - 05. 모폴로지 (2) 열기와 닫기
      CH 07. 이진 영상 처리 - 06. 레이블링
      CH 07. 이진 영상 처리 - 07. 외곽선 검출
      CH 07. 이진 영상 처리 - 08. 다양한 외곽선 함수
      CH 07. 이진 영상 처리 - 09. 실전 코딩 명함 인식 프로그램
      영상 분할과 객체 검출
      CH 08. 영상 분할과 객체 검출 - 01. 그랩컷
      CH 08. 영상 분할과 객체 검출 - 02. 모멘트 기반 객체 검출
      CH 08. 영상 분할과 객체 검출 - 03. 템플릿 매칭 (1) 이해하기
      CH 08. 영상 분할과 객체 검출 - 04. 템플릿 매칭 (2) 인쇄체 숫자 인식
      CH 08. 영상 분할과 객체 검출 - 05. 캐스케이드 분류기 - 얼굴 검출
      CH 08. 영상 분할과 객체 검출 - 06. HOG 보행자 검출
      CH 08. 영상 분할과 객체 검출 - 07. 실전 코딩 간단 스노우 앱
      특징점 검출과 매칭
      CH 09. 특징점 검출과 매칭 - 01. 코너 검출
      CH 09. 특징점 검출과 매칭 - 02. 특징점 검출
      CH 09. 특징점 검출과 매칭 - 03. 특징점 기술
      CH 09. 특징점 검출과 매칭 - 04. 특징점 매칭
      CH 09. 특징점 검출과 매칭 - 05. 좋은 매칭 선별
      CH 09. 특징점 검출과 매칭 - 06. 호모그래피와 영상 매칭
      CH 09. 특징점 검출과 매칭 - 07. 이미지 스티칭
      CH 09. 특징점 검출과 매칭 - 08. 실전 코딩 - AR 비디오 플레이어
      객체 추적과 모션 벡터
      CH 10. 객체 추적과 모션 벡터 - 01. 배경 차분 정적 배경 차분
      CH 10. 객체 추적과 모션 벡터 - 02. 배경 차분 이동 평균 배경
      CH 10. 객체 추적과 모션 벡터 - 03. 배경 차분 MOG 배경 모델
      CH 10. 객체 추적과 모션 벡터 - 04. 평균 이동 알고리즘
      CH 10. 객체 추적과 모션 벡터 - 05. 캠시프트 알고리즘
      CH 10. 객체 추적과 모션 벡터 - 06. 루카스 - 카나데 옵티컬플로우
      CH 10. 객체 추적과 모션 벡터 - 07. 밀집 옵티컬플로우
      CH 10. 객체 추적과 모션 벡터 - 08. OpenCV 트래커
      CH 10. 객체 추적과 모션 벡터 - 09. 실전 코딩 - 핸드 모션 리모컨
      머신러닝
      CH 11. 머신 러닝 - 01. 머신 러닝 이해하기
      CH 11. 머신 러닝 - 02. OpenCV 머신 러닝 클래스
      CH 11. 머신 러닝 - 03. k최근접 이웃 알고리즘
      CH 11. 머신 러닝 - 04. KNN 필기체 숫자 인식
      CH 11. 머신러닝 - 05. SVM 알고리즘
      CH 11. 머신러닝 - 06. OpenCV SVM 사용하기
      CH 11. 머신러닝 - 07. HOG SVM 필기체 숫자 인식
      CH 11. 머신러닝 - 08. 숫자 영상 정규화
      CH 11. 머신러닝 - 09. k-평균 알고리즘
      CH 11. 머신러닝 - 10. 실전 코딩 문서 필기체 숫자 인식
      딥러닝 이해와 영상 인식
      CH 12. 딥러닝 이해와 영상 인식 - 01. 딥러닝 이해하기
      CH 12. 딥러닝 이해와 영상 인식 - 02. CNN 이해하기
      CH 12. 딥러닝 이해와 영상 인식 - 03. 딥러닝 학습과 모델 파일 저장
      CH 12. 딥러닝 이해와 영상 인식 - 04. OpenCV DNN 모듈
      CH 12. 딥러닝 이해와 영상 인식 - 05. MNIST 학습 모델 사용하기
      CH 12. 딥러닝 이해와 영상 인식 - 06. GoogLeNet 영상 인식
      CH 12. 딥러닝 이해와 영상 인식 - 07. 실전 코딩 한글 손글씨 인식
      딥러닝 활용 : 객체 검출, 포즈 인식
      CH 13. 딥러닝 활용 객체 검출 - 01. OpenCV DNN 얼굴 검출
      CH 13. 딥러닝 활용 객체 검출 - 02. YOLOv3 객체 검출
      CH 13. 딥러닝 활용 객체 검출 - 03. Mask-RCNN 영역 분할
      CH 13. 딥러닝 활용 객체 검출 - 04. OpenPose 포즈 인식
      CH 13. 딥러닝 활용 객체 검출 - 05. EAST 문자 영역 검출
      CH 13. 딥러닝 활용 객체 검출 - 06. 실전 코딩 얼굴 인식
    

Chap 1 - OpenCV basics

1강

2강

  • Gray (Black) 0~255 (White)
  • 프로그래밍 언어의 1Byte
    • unsigned char
    • numpy.uint8
  • 색의 성분 (의 삼원색)
    • 0 : 색의 성분이 전혀 없는 상태 = 검정
    • 255 : 색의 성분이 가득 있는 상태 = 흰색
  • 영상의 좌표계
    • 행렬을 읽듯이 읽어야 한다.
    • 우리가 아는 2차원 좌표계를 사용해서 읽지 말고. 따라서 y축은 아래를 향한다.
  • 영상의 파일 형식의 특징
    • JPG는 원본 이미지 데이터가 약간 손실됨. 인간은 못 느끼는 정도
    • GIF는 움짤용. 영상 처리에서 사용 안함
    • PNG 영상처리에서 가장 많이 사용
    • image-20210111224950317

3강

  • BSD license : Free for academic & commercial use
  • OpenCV 구성

4강 기본 코드

import sys
import cv2
print(cv2.__version__)

img = cv2.imread('cat.bmp')

if img is None:
    print('Image load failed!')
    sys.exit()

cv2.namedWindow('image')
cv2.imshow('image', img)
cv2.waitKey() # 아무키나 누르면 window 종료
cv2.destroyAllWindows()

5강 OpenCV 기본 명령어

  • OpenCV 도움말: http://docs.opencv.org/ -> 버전 선택
  • cv2.imread(filename, flags = ‘cv2.IMREAD_COLOR ‘) -> BGR 순서
  • 이미지 저장 : cv2.imwrite(filename, img : numpy.ndarray, params=None)
  • 새 창 띄우기(imshow위해 꼭 안해도 됨) : cv2.namedWindow(winname : str, flags=None) -> None
  • 새 창 모두 닫기 : cv2.destroyWindow(winname : str)
  • cv2.moveWindow(winname, x, y) , cv2.resizeWindow(winname, width, height)
  • cv2.imshow(winname, mat : ndarray_dtype_8uint)
  • cv2.waitKey(delay=’0’)
    • dalay = ms 단위의 대기 시간. If delay = 0, 무한히 기다림
    • return 값은 눌린 키 값.
    • 사용법
      while True:
      	if cv2.waitKey() == ord('q'):
      		break
      # 27(ESC), 13(ENTER), 9(TAB)
      

6강 Matplotlib 기본 명령어

  • BGR 순서 -> cv2.cvtColor() , GRAY -> cmap=’gray’

    import matplotlib.pyplot as plt
    import cv2
      
    # 컬러 영상 출력
    imgBGR = cv2.imread('cat.bmp')
    imgRGB = cv2.cvtColor(imgBGR, cv2.COLOR_BGR2RGB) # cv2.IMREAD_GRAYSCALE
      
    plt.axis('off')
    plt.imshow(imgRGB) #  cmap='gray'
    plt.show()
      
    # subplot
    plt.subplot(121), plt.axis('off'), plt.imshow(imgRGB)
    plt.subplot(122), plt.axis('off'), plt.imshow(imgGray, cmap='gray')
    plt.show()
    

8강 - 이미지 슬라이드쇼 프로그램

  • 폴더에서 파일 list 가져오기
    import os
    file_list = os.listdir('.\\images')
    img_files = [file for file in file_list if file.endswith('.jpg')]
    # 혹은
    import glob
    img_files = glob.glob('.\\images\\*.jpg') 
    
  • 전체 화면 영상 출력

    cv2.namedWindow('image', cv2.WINDOW_NORMAL) # normal 이여야 window 창 변경 가능.
    cv2.setWindowProperty('image', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
    
  • 반복적으로, 이미지 출력
    cnt = len(img_files)
    idx = 0
    while True:
        img = cv2.imread(img_files[idx])
        if img is None:
            print('Image load failed!')
            break
        cv2.imshow('image', img)
        if cv2.waitKey(1000) >= 27: # 1초 지나면 False, ESC누루면 True
            break # while 종료
        # cv2.waitKey(1000) -> 1
        # cv2.waitKey(1000) >= 0: 아무키나 누르면 0 초과의 수 return
        idx += 1
        if idx >= cnt:
        	idx = 0
    

chap2 - Basic image processing technique

1장

  • cv2.imread(‘cat.bmp’, cv2.IMREAD_COLOR) -> numpy.ndarray [행, 열, depth, 몇장]
  • for y in range(h):
        for x in range(w):
            img1[y, x] = 255
            img2[y, x] = [0, 0, 255]
    
  • 이런 식으로 이미지, 픽셀값을 For로 바꾸면 엄청느리다.
  • 함수를 찾아 보거나, img[:,:,:] = [0,255,255] 이런식으로 사용해야 한다.

2장

  • 이미지(=영상) 새로 생성하기

    • numpy.empty / numpy.zeros / numpy.ones / numpy.full
  • 이미지 복사

    •   img1 = cv2.imread('HappyFish.jpg')
        img2 = img1 -> 같은 메모리 공유
        img3 = img1.copy() 
      
    • img3 = img1.copy() -> 새로운 메모리에 이미지 정보 다시 할당 array안의 array도 다시 할당한다. 여기서는 deepcopy랑 같다. ](https://junha1125.github.io/docker-git-pytorch/2021-01-07-torch_module_research/#21-copydeepcopy)
    • numpy에서는 deepcopy랑 copy가 같다. 라고 외우자

2-3강 - 마스크 연산과 ROI

  • 마스크 영상으로는 0 또는 255로 구성된 이진 영상(binary image), Gray Scale
  • cv2.copyTo(src, mask, dst=None) -> dst
    •   src = cv2.imread('airplane.bmp', cv2.IMREAD_COLOR)
        mask = cv2.imread('mask_plane.bmp', cv2.IMREAD_GRAYSCALE)
        dst = cv2.imread('field.bmp', cv2.IMREAD_COLOR)
        cv2.copyTo(src, mask, dst1)
        dst2 = cv2.copyTo(src, mask)
              
        # 하지만 아래와 같은 슬라이딩 연산도 가능!!
        dst[mask > 0] = src[mask > 0] # -> dist = dst1
      
    • src, mask, dst는 w,h 모두 크기가 같아야 함. src와 dst는 같은 타입. mask는 그레이스케일 타입의 이진 영상.
    • image-20210113090901294
    • dst2 : image-20210113090939395
    • dst과 dst2는 완전히 다른 이미지로 생성되니 주의해서 사용할 것.
  • 투명한 배경이 있는 png 파일 (4channel)
    • src = cv2.imread('airplane.bmp', cv2.IMREAD_UNCHANGED) ## 투명배경 있는 것은 IMREAD_UNCHANGED!!! 
      mask = src[:,:,-1]
      src = src[;,:,0:3]
      h,w = src.shape[:2]
      crop = dst[x:x+h,y:w+2]  # src, mask, dst는 w,h 모두 크기가 같아야 함
      cv2.copyTo(src, mask, crop)
      

2-4강 - OpenCV그리기 함수

  • 주의할 점 : in-place 알고리즘 -> 원본 데이터 회손
  • 자세한 내용은 인강 참조, 혹은 OpenCV 공식 문서 참조 할 것.
  • 직선 그리기 : cv2.line
  • 사각형 그리기 : cv2.rectangle
  • 원 그리기 : cv2.circle
  • 다각형 그리기 : cv2.polylines
  • 문자열 출력 : cv2.putText

5강 - 카메라와 동영상 처리하기 1

  • OpenCV에서는 카메라와 동영상으로부터 프레임(frame)을 받아오는 작업을 cv2.VideoCapture 클래스 하나로 처리함
    image-20210113093215343
  • 카메라 열기
    • index : 2대가 있으면 테스트 해봐서 0,1번 중 하나 이다. domain_offset_id는 무시하기(카메라를 Open하는 방법을 운영체제가 적절한 방법을 사용한다.)
    • 아래 코드 꼭 읽어 보기: image-20210113093306495
    • 추가 함수
      • 준비 완료? : cv2.VideoCapture.isOpened() -> retval
      • 프래임 받아오기 : cv2.VideoCapture.read(image=None) -> retval, image
    •   import sys
        import cv
        cap = cv2.VideoCapture()
        cap.open(0)
        # 혹은 위의 2줄 한줄로 cap = cv2.VideoCapture(0)
            
        if not cap.isOpend()
          print('camera open failed!')
            sys.exit()
        while Ture :
            ret, frame = cap.read()
            if not ret : # frame을 잘 받아 왔는가? # 가장 마지막 프레임에서 멈춘다
                break
            edge = cv2.Canny(frame,50,150)
            cv2.imshow('edge', edge) # 2개의 창이 뜬다!! figure 설정할 필요 없음
            cv2.imshow('frame', frame)
            cv2.waitKey(20) == 27: # ESC눌렀을떄
                break
            
        cap.release() # cap 객체 delete
        cv2.destroyAllWindows()
      
  • 동영상 열기

    • 위의 코드에서 cap = cv2.VideoCapture(‘Video File Path’) 를 넣어주고 나머지는 위에랑 똑같이 사용하면 된다.
  • 카메라 속성 열고 바꾸기
    • cv2.VideoCapture.get(propId) -> cap.get(‘propId’)
    • cv2.VideoCapture.set(propId, value) -> cap.set(‘propId’, value)

2-6장 - 카메라와 동영상 처리하기 2

  • 동영상 저장 : cv2.VideoWriter 클래스
    • 소리는 저장이 안된다!!
    • cv2.VideoWriter / cv2.VideoWriter.open
    • cv2.VideoWriter.isOpened() / cv2.VideoWriter.write(image)
    • image-20210113094959326
  • 코덱 종류와 다운로드 링크

    • image-20210113094922834
  • 예시 코드
    • 이미지 반전 : inversed = ~frame. RGB 중 Grean = 0, RB는 255에 가까워짐
    • # 나의 카메로 open
      cap = cv2.VideoCapture(0)
      w = round(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
      h = round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
          
      # 동영상 준비 중
      fourcc = cv2.VideoWriter_fourcc(*'DIVX') # *'DIVX' == 'D','I','V','X'
      fps = 30
      delay = round(1000/fps) # 프레임과 프레임 사이의 시간간격 (1000ms/30fps)
      out = cv2.VideoWriter('output.avi', fourcc, 30, (w, h))
          
      if not out.isOpened():
          print('File open failed!')
          cap.release()
          sys.exit()
          
      while True:
          ret, frame = cap.read()
          if not ret:
              break
          inversed = ~frame 
          # 반전하는 코드. RGB 중 Grean = 0, RB는 255에 가까워짐
          # 신기하니, 아래의  cv2.imshow('inversed', inversed) 결과 확인해보기.
              
          """
          edge = cv2.Canny(frame,50,150)
          edge_color = cv2.cvtColor(edge,cv2.COLOR_GRAY2BGR)
          out.write(edge_color)
          """
              
          out.write(frame)
          cv2.imshow('frame', frame) 
          cv2.imshow('inversed', inversed)
          if cv2.waitKey(delay) == 27: # delay는 이와 같이 사용해도 좋다. 없어도 됨.
          	break	
          
      

2-7장 - 키보드 이벤트 처리하기

  • cv2.waitKey(delay=None) -> retval
  • while True: 문을 계속 돌면서, 매 시간 마다 키보드 input이 없으면 필요없는 값을 return하고 while문에는 영향을 끼치지 않는다.
  • # 키보드에서 'i' 또는 'I' 키를 누르면 영상을 반전
    import cv2
    img = cv2.imread('cat.bmp', cv2.IMREAD_GRAYSCALE)
    cv2.imshow('image', img)
    while True:
        keycode = cv2.waitKey()
        if keycode == ord('i') or keycode == ord('I'):
            img = ~img
            cv2.imshow('image', img)
        elif keycode == 27:
            break
    cv2.destroyAllWindows()
    

2-8장 - 마우스 이벤트 처리하기

  • 마우스 이벤트 콜백함수 등록 함수 : cv2.setMouseCallback(windowName, onMouse, param=None) -> None
  • 마우스 이벤트 처리 함수(콜백 함수) 형식 : onMouse(event, x, y, flags, param) -> None
  • 이벤트에 대한 event 목록들은 강의 자료 참조.
  • oldx = oldy = -1
    def on_mouse(event, x, y, flags, param):
        global oldx, oldy
        if event == cv2.EVENT_LBUTTONDOWN:
        	oldx, oldy = x, y
        elif event == cv2.EVENT_MOUSEMOVE:
        	if flags & cv2.EVENT_FLAG_LBUTTON:
                cv2.line(img, (oldx, oldy), (x, y), (0, 0, 255), 4, cv2.LINE_AA)
                cv2.imshow('image', img)
                oldx, oldy = x, y
    img = np.ones((480, 640, 3), dtype=np.uint8) * 255
    cv2.imshow('image', img)
    cv2.setMouseCallback('image', on_mouse)
    cv2.waitKey()
    

2-9강 - 트랙바 사용하기

  • cv2.createTrackbar(trackbarName, windowName, value, count, onChange) -> None
  • def on_level_change(pos):
        value = pos * 16
        if value >= 255:
        	value = 255
        img[:] = value
        cv2.imshow('image', img)
    img = np.zeros((480, 640), np.uint8)
    cv2.namedWindow('image')
    cv2.createTrackbar('level', 'image', 0, 16, on_level_change)
    cv2.imshow('image', img)
    cv2.waitKey()
    cv2.destroyAllWindows()
      
    

10장 - 연산시간 측정

  • python time.time() 사용하자.
  • cv2의 시간측정함수를 소개한다.

2-11장 - 동영상 전환 이펙트 코드 만들기

  • image-20210114084035017
  •     import sys
        import numpy as np
        import cv2
    
    # 두 개의 동영상을 열어서 cap1, cap2로 지정
    cap1 = cv2.VideoCapture('video1.mp4')
    cap2 = cv2.VideoCapture('video2.mp4')

    if not cap1.isOpened() or not cap2.isOpened():
        print('video open failed!')
        sys.exit()

    # 두 동영상의 크기, FPS는 같다고 가정함
    frame_cnt1 = round(cap1.get(cv2.CAP_PROP_FRAME_COUNT))  # 15초 * 24 = Total 360 frame
    frame_cnt2 = round(cap2.get(cv2.CAP_PROP_FRAME_COUNT))
    fps = cap1.get(cv2.CAP_PROP_FPS) # 24
    effect_frames = int(fps * 2)  # 48 -> 1번 동영상의 맨 뒤 48프레임과, 2번 동영상의 맨 앞 48프레임이 겹친다

    print('frame_cnt1:', frame_cnt1)
    print('frame_cnt2:', frame_cnt2)
    print('FPS:', fps)

    delay = int(1000 / fps)

    w = round(cap1.get(cv2.CAP_PROP_FRAME_WIDTH))
    h = round(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fourcc = cv2.VideoWriter_fourcc(*'DIVX')

    # 출력 동영상 객체 생성
    out = cv2.VideoWriter('output.avi', fourcc, fps, (w, h))

    # 1번 동영상 복사
    for i in range(frame_cnt1 - effect_frames):
        ret1, frame1 = cap1.read()

        if not ret1:
            print('frame read error!')
            sys.exit()

        out.write(frame1)
        print('.', end='')

        cv2.imshow('output', frame1)
        cv2.waitKey(delay)

    # 1번 동영상 뒷부분과 2번 동영상 앞부분을 합성
    for i in range(effect_frames):
        ret1, frame1 = cap1.read()
        ret2, frame2 = cap2.read()

        if not ret1 or not ret2:
            print('frame read error!')
            sys.exit()

        dx = int(w / effect_frames) * i

        frame = np.zeros((h, w, 3), dtype=np.uint8)
        frame[:, 0:dx, :] = frame2[:, 0:dx, :]
        frame[:, dx:w, :] = frame1[:, dx:w, :]

        #alpha = i / effect_frames
        #frame = cv2.addWeighted(frame1, 1 - alpha, frame2, alpha, 0)

        out.write(frame)
        print('.', end='')

        cv2.imshow('output', frame)
        cv2.waitKey(delay)

    # 2번 동영상을 복사
    for i in range(effect_frames, frame_cnt2):
        ret2, frame2 = cap2.read()

        if not ret2:
            print('frame read error!')
            sys.exit()

        out.write(frame2)
        print('.', end='')

        cv2.imshow('output', frame2)
        cv2.waitKey(delay)

    print('\noutput.avi file is successfully generated!')

    cap1.release()
    cap2.release()
    out.release()
    cv2.destroyAllWindows()

```

chap3 - 기본 영상 처리 기법

Ch 03. 기본적인 영상 처리 기법 - 01. 영상의 밝기 조절

  • 밝기 조절을 위한 함수 : cv2.add(src1, src2, dst=None, mask=None, dtype=None) -> dst

Ch 03. 기본적인 영상 처리 기법 - 02. 영상의 산술 및 논리 연산

  • 두 이미지 덧셉, 가중치 합
  • cv2.add(src1, src2, dst=None, mask=None, dtype=None) -> dst
  • cv2.addWeighted(src1, alpha, src2, beta, gamma, dst=None, dtype=None) -> dst
  • 두 이미지 뺄셈
  • cv2.subtract(src1, src2, dst=None, mask=None, dtype=None) -> dst
  • 두 이미지 차이 계산 dst( , ) = |src1( , ) - src2( , ) |
  • cv2.absdiff(src1, src2, dst=None) -> dst

Ch 03. 기본적인 영상 처리 기법 - 03. 컬러 영상 처리와 색 공간

  • b_plane, g_plane, r_plane = cv2.split(src)
  • b_plane = src[:, :, 0] g_plane = src[:, :, 1] r_plane = src[:, :, 2]
  • cv2.cvtColor(src, code, dst=None, dstCn=None) -> dst

Ch 03. 기본적인 영상 처리 기법 - 04. 히스토그램 분석

  • cv2.calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None) -> hist

  • src = cv2.imread('lenna.bmp')
    colors = ['b', 'g', 'r']
    bgr_planes = cv2.split(src)
    for (p, c) in zip(bgr_planes, colors):
        hist = cv2.calcHist([p], [0], None, [256], [0, 256])
        plt.plot(hist, color=c)
    plt.show()
    

Ch 03. 기본적인 영상 처리 기법 - 05. 영상의 명암비 조절

  • dst( , ) = saturate(src( , ) + (src( , ) - 128) ) + a
  • image-20210114085414553
  •   src = cv2.imread('lenna.bmp', cv2.IMREAD_GRAYSCALE)
      alpha = 1.0
      dst = np.clip((1+alpha)*src - 128*alpha, 0, 255).astype(np.uint8)
    
  • 명암비 자동 조절

    • dst = cv2.normalize(src, None, 0, 255, cv2.NORM_MINMAX)

Ch 03. 기본적인 영상 처리 기법 - 06. 히스토그램 평활화

  • 히스토그램이 그레이스케일 전체 구간에서 균일한 분포로 나타나도록 변경하는 명암비 향상 기법
  • 히스토그램 균등화, 균일화, 평탄화
  • cv2.equalizeHist(src, dst=None) -> dst

Ch 03. 기본적인 영상 처리 기법 - 07. 특정 색상 영역 추출하기

  • 특정 범위 안에 있는 행렬 원소 검출 : cv2.inRange(src, lowerb, upperb, dst=None) -> dst

Ch 03. 기본적인 영상 처리 기법 - 08. 히스토그램 역투영

  • cv2.calcBackProject(images, channels, hist, ranges, scale, dst=None) -> dst
  • image-20210114090121180

Ch 03. 기본적인 영상 처리 기법 - 09. 실전 코딩 - 크로마키 합성

  • cv2.inRange() 함수를 사용하여 50 ≤ 𝐻 ≤ 80, 150 ≤ 𝑆 ≤ 255, 0 ≤ 𝑉 ≤ 255 범위의 영역을 검출
  • 마스크 연산을 지원하는 cv2.copyTo() 함수 사용
  • image-20210114090209199
  • 강의자료 FastCampus_CV\opencv_python_ch01_ch05\ch03\chroma_key.py 참조

chap4 - 필터링

  • cv2.filter2D

  • cv2.GaussianBlur

  • cv2.medianBlur(src, ksize, dst=None) -> dst

    • 주변 픽셀들의 값들을 정렬하여 그 중앙값(median)으로 픽셀 값을 대체
    • 소금-후추 잡음 제거에 효과적
  • cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None) -> dst

    • edge-preserving noise removal filter / Bilateral filter
    • 평균 값 필터 또는 가우시안 필터는 에지 부근에서도 픽셀 값을 평탄하게 만드는 단점
    • 에지가 아닌 부분에서만 blurring(잡음제거)
  • 카툰 필터 만들기

    • 아래의 방법은 사람들이 찾아낸 방법 중 하나. 다양한 방법이 있다.

    • image-20210114090945601

    • image-20210114091006607

    • # 카툰 필터 카메라
          
      import sys
      import numpy as np
      import cv2
          
      def cartoon_filter(img):
          h, w = img.shape[:2]
          img2 = cv2.resize(img, (w//2, h//2))
          blr = cv2.bilateralFilter(img2, -1, 20, 7)
          edge = 255 - cv2.Canny(img2, 80, 120)
          edge = cv2.cvtColor(edge, cv2.COLOR_GRAY2BGR)
          dst = cv2.bitwise_and(blr, edge)  # 논리 연산자
          dst = cv2.resize(dst, (w, h), interpolation=cv2.INTER_NEAREST)
          return dst
          
      def pencil_sketch(img):
          gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
          blr = cv2.GaussianBlur(gray, (0, 0), 3)
          dst = cv2.divide(gray, blr, scale=255)
          return dst
          
      cap = cv2.VideoCapture(0)
      if not cap.isOpened():
          print('video open failed!')
          sys.exit()
      cam_mode = 0
          
      while True:
          ret, frame = cap.read()
          if not ret:
              break
          if cam_mode == 1:
              frame = cartoon_filter(frame)
          elif cam_mode == 2:
              frame = pencil_sketch(frame)
              frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
          cv2.imshow('frame', frame)
          key = cv2.waitKey(1)
          if key == 27:
              break
          elif key == ord(' '):
              cam_mode += 1
              if cam_mode == 3:
                  cam_mode = 0
          
      cap.release()
      cv2.destroyAllWindows()
          
      

chap5 - 기하학적 변환

  • 수학적 공식은 ‘20년2학기/윤성민 교수님 컴퓨터 비전 수업 자료 참조’

  • cv2.warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None) -> dst

  • cv2.resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None) -> dst

  • cv2.flip(src, flipCode, dst=None) -> dst

  • cv2.pyrDown(src, dst=None, dstsize=None, borderType=None) -> dst : 다중 피라미드 이미지 자동 return

  • cv2.pyrUp(src, dst=None, dstsize=None, borderType=None) -> dst

  • rot = cv2.getRotationMatrix2D(cp, 20, 1)

    • dst = cv2.warpAffine(src, rot, (0, 0))
  • 어파인 변환과 투시 변환

    • image-20210114091721057

    • cv2.getAffineTransform(src, dst) -> retval

    • cv2.getPerspectiveTransform(src, dst, solveMethod=None) -> retval

    • cv2.warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None) -> dst

    • cv2.warpPerspective(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None) -> dst

    • src = cv2.imread('namecard.jpg')
      w, h = 720, 400
      srcQuad = np.array([[325, 307], [760, 369], [718, 611], [231, 515]],
      np.float32)
      dstQuad = np.array([[0, 0], [w-1, 0], [w-1, h-1], [0, h-1]], np.float32)
      pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
      dst = cv2.warpPerspective(src, pers, (w, h))
      
    • image-20210114091945757
  • 리매핑 : 영상의 특정 위치 픽셀을 다른 위치에 재배치하는 일반적인 프로세스

    • cv2.remap(src, Pixel좌표1, Pixel좌표2, interpolation, dst=None, borderMode=None, borderValue=None) -> dst
  • [실전 코딩] 문서 스캐너

    • 위의 방법 적절히 사용
    • 코드는 FastCampus_CV\opencv_python_ch01_ch05\ch03\docuscan.py 참조

chap6 - 영상의 특징 추출

  • 아래의 함수를 사용하고 싶다면, 어줍잖은 블로급 보지 말고 동영상 찾아보자.
  • cv2.Sobel(src, ddepth, dx, dy, dst=None, ksize=None, scale=None, delta=None, borderType=None) -> dst
  • cv2.Scharr(src, ddepth, dx, dy, dst=None, scale=None, delta=None, borderType=None) -> dst
  • 2D 벡터의 크기 계산 함수 : cv2.magnitude(x, y, magnitude=None) -> magnitude
  • 2D 벡터의 방향 계산 함수 : cv2.phase(x, y, angle=None, angleInDegrees=None) -> angle
  • cv2.Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient=None) -> edges
  • cv2.HoughLines(image, rho, theta, threshold, lines=None, srn=None, stn=None, min_theta=None, max_theta=None) -> lines
  • cv2.HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None) -> lines
  • cv2.HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None) -> circles

【LinearAlgebra】선형대수 정리 3 (한글강의)

쑤튜브 선형대수 강의내용 정리 45~86강. - 57강 행공간의 보존 ~ 74강까지 패스. 너무 수학적임 나한테 아직 필요 없음

  • 나중에 꼭 들어야 하는 강의 -71강 : k < n, k개의 정규기저백터에서, n-k개의 추가 정규기저백터 찾기
    -72강 : 블록행렬. 내가 만든 열=다열, 행=행다 개념을 블록으로 설명하는 강의.

youtube 강의 링크 : 쓔튜브 선형대수 강의 링크

Matric 내적 정리 요약

  • 블록행렬 강의를 한번 보면 좋을 듯. 하지만 우선 아래는 내가 만든 공식
  • image-20210108203403357

Basis & Dimension

  • 45강, 46강 기저와 차원
  • 기저 백터의 조건
    • 선형적으로 독립
    • n차원이면 n개의 백터 이상.
  • 47강 기저 변환
    • E = {e1,e2,e3 … en} -> V = {v1,v2,v3 … vn} | e1과 v1은 백터 | v끼리는 서로 정규일 필요는 없다.
      • 아래에서 x(kn) 은 V의 원소들의 선형결합 계수 이다.
      • xk1v1 * xk2v2 * xk3v3 * … xknvn = ek | k = 1~n까지 n차 연립방정식
      • 위의 n개의 연립방정식으로 행렬로 표현하면 아래와 같다.
      • image-20210108203403357
      • 정리 :
        • image-20210108203850458
        • 일반화 (48강에서 증명)
          • (x1,x2 … xn)B = B의 기저백터들에 x1,x2,x3..xn의 계수로의 선형결합
          • image-20210108210028031
          • 예시
            image-20210108210028031
          • 해석 : B를 기저로 하는 좌표값이 x1~xn 이라면, 그 좌표를 B’을 기저로하는 좌표값으로 바꾸면 어떤 좌표 y1~yn이 되는가? 에 대한 공식이다.
      • 예제 :
        • (2,1)E는 E의 백터들에 2와 1의 계수로 선형결합 해준 백터 = v1 을 의미함.
        • image-20210108204107154
  • 48강 기저변환과 대각화(= EVD(Eigen Value Decomposition) 기초)
    • 대각화 : P * A * inverse(P) = D’(대각행렬) -> A =inverse(P) * D’(대각행렬) * P
    • 위의 일반화 공식과 고유백터&고유값을 이용해 대각화 공식을 찾아보자.
    • 대각변환 : 축을 기준으로 상수배(확대/축소)하는 변환
    • image-20210108213604777에 대해서 자세히 알아보자. 동영상에서는 위의 기저변환 일반화 공식을 이용해서 아래의 대각화 공식을 정의하고 있다.
      • [v1 v2] A’ [v1 v2]-1 = A’ 을 A의 고유백터 좌표를 기준으로 기저변환한 ‘결과’
      • [v1 v2] A’ [v1 v2]-1 = 위 ‘결과’를 다시 E를 기준으로 기저변환한 결과 = A !!
      • A와 A’은 위의 x1~xn, y1~yn과 같은 역할이다.
        • A’ 은 A의 고유값들로 만든 대각행렬, [v1 v2]는 A의 고유백터를 열백터로 가지는 행렬
        • A 는 [E(기본 좌표계)]를 기준좌표계(기저)로 생각하는 선형변환이다.
    • 고민을 많이 해야하므로 위의 내용을 이해하고 싶으면 강의를 다시 보자.
    • 이 대각화 공식을 다음과 같이 증명하면 쉽게 이해 가능하다.
      • image-20210108214614430
  • 49강 대각화가능행렬과 그 성질들
    • image-20210108214915839
    • 대각화 가능한 행렬 A는 n개의 선형독립인 고유백터를 가진다.
    • n개의 선형독립인 고유백터를 가지는 A는 대각화가 가능하다.
    • 대각화 왜해??
      • 대각행렬(D)은 n승을 하면, 대각원소의 n승인 행렬이다.
      • A^n = P * D^n * inverse(P)
      • A^n을 대각화로 엄청 쉽게 구할 수 있다!!
  • 50강 - 증명 : n차원에서 ‘n개의 원소를 가지는 백터 v’들의 선형독립 백터(v1 v2 … vn)의 최대갯수는 n개이다.
  • 51강 - 증명 : (1) A의 span(열백터들 or 행백터들) = n이면, A는 가역행렬이다. (2) 가역행렬(n차 정사각행렬)의 행백터, 열백터는 n dimention의 기저백터(독립!, 정규일 필요 X)이다.

Matrix similarity, Fuctnion, Space(닮음과 함수, 공간)

  • 52강 Matrix similarity(행렬의 닮음)
    • 두 행렬이 서로 닮음이면, 아래와 같은 많은 성질을 가진다.
    • image-20210109143042489
  • 53강 kernal and range(핵과 치역)
    • kernal : (m x n 행렬 (n차원 백터 -> m차원 백터 로 변환하는 행렬)) 선형사상 F행렬 (=선형함수,=선형변환)에 대해, F * x = {0백터}. 즉 F에 의해서 0백터가 돼버리는 백터(n차원 공간의 좌표)들. 이 백터들을 kernal, null space(영공간) 이라고 한다.
    • 선형사상 F에 의해서 n차원의 부분공간(원소들을 스칼라배, 덧셈을 하면 ‘집합 내의 원소’가 나오는 공간)이 m차원의 부분공간으로 변환됨
    • 선형변환 행렬 A에 대해, range(A) (Ax의 공간. x는 백터) = col(A) (A의 colum space 차원)이다.
    • 더 이해하고 싶으면, 53강 보충강의 보기
  • 54강 일대일 합수
    • 집합의 갯수를 새보자. A = {1,3,4} 3개이다. 새로은 집합 B의 갯수는 몇게 일까?
      • 집합 A와 B의 원소의 갯수가 같으려면, A와 B사이의 일대일 대응 함수가 존재함을 증명하면 된다.
      • 따라서 자연수집합과 정수 집합은 원소의 갯수가 같다. (일대일대응함수는 동영상 참조)
    • Thm : T ( R^n -> R^m ) 이라는 선형사상 T에 대해서, ‘T가 일대응 함수이다.’와 ‘kernal(T) = {0}이다.’ 는 동치이다.
      • 증명은 동영상 참조
  • 55강 전사 함수
    • 단사 : 일대일 대응이고 치역에 남은 원소가 있어도 됨.
    • 전사 : 일대잉 대응이고 치역에 남은 원소가 없다. 모든 정의역에 치역에 대응 됨.
    • 추가 증명 및 내용은 동영상 참조
  • 56강 직교여공간
    • 영공간(null space)
    • 행공간 = 영공간
      • rank (행백터 중 기저가 될 수 있는 백터의 최대 갯수)
    • 직교여공간(orthogonal complement)
      • 추후에 배울 최소제곱법에서 필요한 내용이다.
      • image-20210109163632668
      • non empty set : 영공간이 아닌 백터 집합
      • V = (1,1,1)의 직교여공간은 (1,1,1)를 법선백터로 가지는 평면이다.
      • 직교여공간에 0백터는 무조건 들어가 있다. 어떤 백터든 0백터를 곱하면 0백터가 되므로.
  • 57강 행공간의 보존
  • 74강까지 패스. 너무 수학적임 나한테 아직 필요 없음.

Orthogonal Diagnalizing & Eigen Value Decomposition & SVD

  • 75강 대각화가능 행렬(EVD, 교유값 분해)
    • 대각화 가능한 행렬은 n개의 선형독립인(정규일 필요 X) 고유백터를 가진다. = 모든 열백터가 독립이다. = 가역행렬이다.
  • 77강 직교행렬
    • A 직교행렬 : A의 모든 열백터(and 행백터)는 서로 orthonormal(정규) 하다.
    • 직교 변환 : 두 백터 v1,v2에 대해서 선형변환을 해도 두 백터의 길이(norm)이 유지되고, 두 백터와의 각도도 변하지 않는 변환을 말한다.
  • 78강 직교행렬의 조건
    1. (참조 transpose(T), trace(대각합) 서로 헷갈리지 말자.)
    2. inverse(A) = transpose(A)이면 A는 직교행렬이다.
      • image-20210109165441523
    3. A가 직교행렬이면 A의 행백터는 모두 orthonormal 하다.
    4. A가 직교행렬이면 transpose(A)도 직교행렬이다.
      • 이 모든것의 증명은 동영상 참조. 하지만 직교변환의 개념을 사용하므로 쉽지 않다. 일단 다 외어.
  • 79강 켤레 전치와 대칭 함수
    • 켤레 전치(confugate transpose) : A가 복소행렬(원소가 복소수)일 때, A의 결레전치행렬은
      • image-20210109165441523
      • 을 말한다. bar(A) : 모든 원소에 켤레복소수화. (1+i -> 1-i)
      • 컬레 전치의 기본 성질
          1. (A*)* = A
          2. (AB)* = (B*A*)*
    • 원소가 모두 실수로 이뤄진 ‘대칭행렬’의 고유값은 항상 실수 이다.
      • 증명은 동영상 참조.
  • 80강 직교대각화 가능(Orthogonal Diagonalizability)
    • 직교 닮음 이란?
      • C = inverse(P) * A * P (이때 P는 직교 행렬 : inverse(P) = transpose(P))
      • C는 A와 닮음이고, A는 C와 닮음이다.
      • 아래는 C가 D (대각행렬)
    • 직교 대각화(orthogonal diagonalizability)
      • image-20210109195906359
  • 81강 orthogonal diagonalizing (직교 대각화 하기)=Eigen Value Decomposition 시작
    • 대칭행렬이면 직교대각화가능 행렬이다.
    • 대칭행렬을 직교대각화 하는 방법.
      1. A가 대칭행렬이면, A의 고유백터들은 서로 ‘독립’일 뿐만 아니라 ‘직교’한다. = (‘서로 다른 고유공간’에 속한 고유백터는 서로 직교한다.)
        • ‘서로 다른 고유공간’ 이란?
          • 하나의 고유값에 대해서, 여러개의 고유백터들(1) 존재 가능(ex. 상수배 등)
          • 다른 고유값에 대한, 고유백터들(2)이 존재 할 때.
          • 고유백터들(1)과 고유백터(2)는 서로 직교한다. (당연한 얘기지만 일단 참고)
          • (아래) 선형변환 A를 내적 안에다 넣을 때는 inverse(A)가 들어간다. 증명은 17강 or 75강 참조.
        • image-20210109202311070
      2. 직교대각화하는방법
        1. A는 대칭행렬이다.
        2. A의 n개의 고유값을 구한다.(실수 고유값이 나온다.)
        3. 고유값에 맞는 orthonormal basis(단위 고유 직교 백터) n개 백터들을 구한다.
        4. 위의 n개의 백터를, 열백터로 가는 행렬 P를 만든다.
        5. inverse(P) A P = D(고유값으로 만든 대각행렬)
        6. 즉 A가 P에 의해서 대각행렬이 되었다.
      3. 직교대각화 예제
        1. image-20210110140953404
        2. 그람슈미트 변환을 알면, 고유값의 중근이 존재할 때, 중근인 고유값에 대한 2개의 기저백터를 뽑아내는 방법을 알 수 있다.
  • 82강 고유값 분해를 이용한 이미지 손실 압축(Eigen Value Decomposition)
    • image-20210110141923780
    • image-20210110150938824
  • 83강 SVD(Singular Value Decompostion)
    • 바로 위의 Eigen Value Decompostion의 시작은 대칭행렬이다! 대칭행렬만, 직교 대각화가 가능하므로.
    • A가 대칭행렬이 아니고, 정사각행렬이라면?? ㅠㅠ 직교대각화 (P * D * transpose(P)) 불가능!
    • A = U * Σ * transpose(V) 로 분해해보자.
    • A * transpose(A)는 대칭행렬이기 때문에, 교유백터들은 모두 독립일 뿐만 아니라 직교하다. 이 고유백터들을 각각 정규화(norm = 1)로 만들어 준 행렬이 아래의 V이다.
    • image-20215555
  • 84강 SVD 예제
    • image-20210110162049418
  • 85강 특이값 분해 일반화 (정사각행렬이 아닌 A)
    • image-20210110164410923
  • 86강 축소된 특이값 분해
    • image-20210110165648929

【Pytorch Package】 SSD Pytorch 'Module' Research

SSD package를 공부하면서 새로 익힌 내용들을 정리한다.

  • 아직 python에 대해서도 많은 부분을 모른다.
  • 모르는게 있으면, 끝까지 탐구하는 자세는 좋다. 하지만 너무 오랜 시간은 좋지 않다. 버릴건 버리고 나중에 필요하면 그때 다시 공부하면 이해가 될 수 있다.

1. py파일에서 부모 directory의 py파일에 접근

  • reference
    1. https://myjorney.tistory.com/52
    2. https://devlog.jwgo.kr/2019/09/17/how-to-test-package-created-by-myself/
  • 문제점 : 다음과 같은 파일 구조에서
      aa
          - a.py
          - bb
              - b.py
    

    b.py에서 from .. import a, from … import a 이 잘 동작하지 않는다.

  • 해결책 (위의 레퍼런스 요약)
    1. (1번째 refer) terminal에서 path를 b가 아닌 a에 두고, “$ python -m b/b.py”를 실행한다.
      • “-m” 옵션을 사용함으로써 모듈의 위치에 집중하라고 알려준다,
      • python을 실행할 때, 터미널의 pwd가 굉장히 중요하다,
    2. (추천-2번째 refer) setup.py를 이용한다.
      • sys.path.append 과거 블로그 설명과 사용법, sys.path.insert와 같은 방법. 혹은 컴퓨터의 환경변수를 넣어주는 방법 등이 있지만 모두 비추이다.
      • 나만의 패키지를 만들 때, 가장 맨위 디렉토리에 setup.py를 만들어 준다. 양식은 python공식문서를 참고하면 된다. 그리고 “$python setup.py install /or/ $ pip install .”을 해준다!!
    3. 나중에 setup.py 에 대해서 공부해보자. Google : how work setup.py

2. __init__.py 파일의 힘 (init.py)

  • 문제점
    • “아니 이게 왜 호출이 되지??? import한 적이 없는데???” 라는 생각을 자주해서 해당경로에 __init__.py에 들어가보면 import를 대신 해준것을 확인할 수 있었다.
    • 그렇다면 이게 어떻게 동작하는 걸까?
  • 결론 ⭐
    • 내가 만약 import package.dir1.dir2 를 파일 맨 위에 한다면, dir2에 있는 __init__.py 이 자동으로 호출되며 안의 내용을 모두 읽고 실행한다.
    • 만약 dir2의 __init__.py에 from .dir3.dir4 import fun4 가 있다면?
    • a.py에서 아래의 2가지 방법을 사용하면 된다.
      • from package.dir1 import dir2를 한다면, a.py에서 dir2.fun4로 써놓음으로써 fun4를 사용할 수 있다!!
      • from dir2 import fun4라고 한다면, a.py에서 fun4를 그대로 사용할 수 있다.
    • 원래는 a.py에서 fun4로만 생각해서, 직접 패키지를 만들고 실험을 해봤더니, 에러가 났다.
    • debugging을 해보니까, 다음과 같은 실행이 이뤄짐을 알 수 있었다.
      image
  • 궁금증2

    •   from mmdet.apis import inference_detector, init_detector, show_result_pyplot
      
    • 이러고 inference_detector, init_detector 함수를 그냥 사용할 수 있다. /mmdet/apis.py 파일이 있고, 저 파일안에 저 함수들이 정의되어 있다면 내가 궁금해하지도 않는다. 아래와 같은 구조를 하고 있기 때문이다.

    • image-20210128205145476

    • 물론 위의 문제점1에서 깨달았던 방법을 사용하면 아래와 같은 모듈사용이 가능했다.

        from mmdet import apis
              
        config = 'configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco.py'
        checkpoint = 'checkpoints/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco_bbox_mAP-0.408__segm_mAP-0.37_20200504_163245-42aa3d00.pth'
              
        model = apis.init_detector(config, checkpoint, device='cuda:0')
      
    • 어떻게 위의 form과 import의 실행이 가능했던 것일까??
  • 결론

    • from이 가르키는 마지막 directory의 __init__.py 또한 일단 다 읽는다! 그리고 import다음으로 넘어간다.
    • 우리가 아는 아주 당연한 방법으로, import 다음 내용으로 from A.B.C import py_file_name/function_defined 과 같이 import를 수행해도 된다.
    • 하지만 from 가장 마지막 directory의 (위의 예시에서 C)의 __init__.py 안에서 한번 import된 함수를 import해서 가져와도 된다.
    • 이를 이용해서, 궁금증2의 첫 실행문을 다시 설명하자면, from mmdet.apis 을 통해서 apis의 __init__.py를 모두 읽는다. 여기서 from .inference import (async_inference_detector, inference_detector,init_detector, show_result_pyplot) 이 수행되므로, import에서 import inference_detector, init_detector, show_result_pyplot를 하는 것에 전혀 무리가 없는 것이다.

3. os.path 모듈

  • reference : https://devanix.tistory.com/298
  • os.path.abspath(path)
  • os.path.basename(path)
  • os.path.commonprefix(path_list)
  • os.path.dirname(path) : 굳이 내가 \로 직접 자를 필요가 없었다.
  • os.path.exists(path)
  • os.path.getsize(path)
  • os.path.isfile(path)
  • os.path.isdir(path)
  • os.path.join(path1[,path2[,…]]) : 나의 os 확인하니, 일반 string class의 + 연산자보다 이게 낫겠다.
  • os.path.normpath(path) : 현재 디렉터리(“.”)나 상위 디렉터리(“..”)와 같은 구분자를 최대한 삭제

4. ModuleList

  •   class VGG(nn.Module):
          def __init__(self, cfg):
              super().__init__()
              size = cfg.INPUT.IMAGE_SIZE
              vgg_config = vgg_base[str(size)]
              extras_config = extras_base[str(size)]
        
              self.vgg = nn.ModuleList(add_vgg(vgg_config : [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'C', 512, 512, 512, 'M', 512, 512, 512]))
        
      def add_vgg(cfg, batch_norm=False):
          layers = []
          in_channels = 3
          for v in cfg:
              if v == 'M':
                  layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
              elif v == 'C':
                  layers += [nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)]
              else:
                  conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1) 
                  if batch_norm:
                      layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]
                  else:
                      layers += [conv2d, nn.ReLU(inplace=True)]
                  in_channels = v
          pool5 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
          conv6 = nn.Conv2d(512, 1024, kernel_size=3, padding=6, dilation=6)
          conv7 = nn.Conv2d(1024, 1024, kernel_size=1)
          layers += [pool5, conv6,
                  nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True)]
          return layers
    
  • 코드 설명
    • ModuleList()에는 input으로 python-list가 들어가고 list-component는 nn.layer 이다.
    • conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1) 이 문장.
      • conv2d은 계속 새로운 nn.Conv2d 객체로 바끤다.
      • 아래의 코드를 참고해보자.
      •   >>> a = (1,2)
          >>> id(a)
          2289005091144
          >>> id((1,2))
          2289005102280
          >>> a = (1,2)
          >>> id(a)
          2289005092296
        
      • 이처럼 같은 클래스 tuple이지만, 객체 (1,2)는 다시 만들어지고 그것을 a가 가리킨다.

5. __init__() defined in Class

  • Class의 __init__함수는 객체 선언시 처음부터 끝까지 읽혀진다.
  • 아래의 코드에서도 self.set_c()까지 처리되는 것을 확인할 수 있다.
  •   class a():
      def __init__(self, a,b):
          self.a = a
          self.b = b
          self.c = 1
          self.set_c()
        
      def set_c(self):
          self.c = self.a + self.b
        
      obj = a(4,3)
      print(obj.c) 
      >> 7
    
  •   class VGG(nn.Module):
      def __init__(self, cfg):
          super().__init__()
          size = cfg.INPUT.IMAGE_SIZE
          vgg_config = vgg_base[str(size)]
          extras_config = extras_base[str(size)]
        
          self.vgg = nn.ModuleList(add_vgg(vgg_config))
          self.extras = nn.ModuleList(add_extras(extras_config, i=1024, size=size))
          self.l2_norm = L2Norm(512, scale=20)
          self.reset_parameters()
    
  • 따라서 위 코드의 reset_parameters도 반드시 실행된다.

6. torch.tensor.function (permute, contiguous)

  •   cls_logits = []
      bbox_pred = []
      for feature, cls_header, reg_header in zip(features, self.cls_headers, self.reg_headers):
          cls_logits.append(cls_header(feature).permute(0, 2, 3, 1).contiguous())
          bbox_pred.append(reg_header(feature).permute(0, 2, 3, 1).contiguous())
    
  • 위의 cls_header, reg_header 는 nn.Conv2d 이다.
  • torch document에 적혀 있는 view는 tensor의 shape, size를 의미한다. view라는 단어를 더 자주쓰지 하나의 명사로 알아두기

7. os.environ([“variable”])

  • 터미널 내부 환경 변수를 읽어오는 모듈이다.
  • $ export COCO_ROOT=”/path/to/coco_root” 와 같이 환경변수를 설정해 두면, python내부 os.environ 함수가 이 환경변수를 읽오와 변수에 저장해둔다.
  • drawing

8. package 다운 후 코드 수정하기

  • 궁금증 :
    • $python setup.py install / $ pip install .
    • 이 명령어를 이용해서, package의 setup을 마친 상태라고 치자.
    • setup을 하고 난 후, package의 코드를 바꾸면 다시 setup을 실행해줘야 하는가?
    • 아니면 setup은 처음에만 하고, 코드 수정 후 그냥 사용하기만 하며 되는가?
  • 해답 :
    • 정답은 ‘처음에만 setup 해주면 된다.’ 이다
    • 아래와 같은 세팅의 실험에서, 내가 추가해준 코드가 아주 잘 실행되는 것을 확인할 수 있었다.
    • image

【Pytorch Package】 SSD Pytorch Research / Detectron2 & mmdetection short research

Pytorch tuto를 모두 공부하고, 더 깊은 공부를 위해 SSD package를 공부한다.

  • SSD package를 가장 먼저 공부하는 이유는, SSD가 신경망 패키지 공부에 가장 쉽겠다고 생각했기 때문이다.
  • 무엇으로 공부하지..? 라고 고민을 먼저 했다. 가장 유명한 detection 패키지인 Detectron2, mmdetection으로 공부해볼까 했지만, 그것보다 좀 더 쉬운 하나 detection 패키지만을 먼저 공부해보는게 좋겠다고 생각했다

0. Find Reference Github Code

  1. amdegroot/ssd.pytorch
    • star : 4.1k, Contributors : 9, pytorch version : 1.0.0
    • last commit : 19.5 lnitial commit : 17.4
  2. sgrvinod/a-PyTorch-Tutorial-to-Object-Detection
    • star : 1.8k, Contributors : 2, pytorch version : 0.4
    • last commit : 20.8 lnitial commit : 18.8
    • Great Explanation about basics to SSD details
  3. lufficc/SSD
    • star : 1k, Contributors : 8, pytorch version : 1.4
    • last commit : 20.11 lnitial commit : 19.12
    • influenced by ssd.pytorch, aim to be the code base (very modular)

I will use lufficc/SSC repo. I think that this is up-to-date repository and developers emphasize this repo is high quality, fast and modular.

  • installation
      $ cd SSD
      $ pip install -r requirements.txt
      $ python setup.py install  # or $ pip install .
    
  • Colab installation
      !git clone https://github.com/lufficc/SSD.git
      %cd SSD
      !pip install -r requirements.txt
      !python setup.py install
        
      import ssd.config
      print(ssd.config.cfg)
    

Detectron2 & mmdetection short research

  1. Detectrion2 에서는 SSD, Yolo 와 같은 detector들은 제공하지 않는다.
  2. it is important to try building a model at least once from scratch to understand the math behind it.
  3. detectron2/MODEL_ZOO.md에 보면 제공되는 모델과 그 성능을 확인할 수 있다.
  4. 이것을 이용해서 pretrain할 때, cs231n-Transfer Learning을 참고하면 좋겠다. 나의 데이터량과 모델의 구조에 따라서 내가 어떤식으로 Transfer Learning을 진행해야하는지 나와있다.
  5. 아래에 공부하는 lufficc/SSD 또한 detectron2와 거의 유사한 구조를 가지고 있다. 따라서 lufficc/SSD를 적극적으로 공부해도 되겠다 (어차피 detectron2에서 SSD를 제공하지 않으므로)
  6. 하지만! mmdetection에서 SSD를 제공한다. 따라서 lufficc/SSD는 최대한 빠르게 넘어가고, mmdetection으로 넘어가는게 좋을 듯하다. mmdetection에서는 detection2보다 상대적으로 아주 많은 모델을 제공한다. 모델 비교는 아래의 링크에서 확인 가능 하다.
  7. detectron2와 mmdetection을 공부하기 전 논문을 읽어도 좋을 것 같다. 한글 블로그 정리 글도 많으니 참고하면 좋을 듯.
  8. 따라서 앞으로 공부순서는 아래와 같다.
    1. lufficc/SSD
    2. mmdetection의 SSD
    3. detectrion의 fasterRCNN
  9. detectron2/projects를 보면 [DeepLab, DensePose, Panoptic-DeepLab, PointRend, TensorMask, TridentNet] 와 같은 읽기만 해도 멋진 Detector or Segmentation 모델, 논문이 있으니 이것들을 공부해도 좋을 듯 하다.
  10. 특히 mmdetection에 대해서는 나중에 추가적으로 더 공부.

1. Analysis of lufficc/SSD

  1. 독자적으로 사용하는 pypi 패키지가 2개 있다.
    • yacs : config파일을 다루기 쉽게, CN()이라는 자체적은 클래스를 제작해놓음. 아래와 깉이 디렉토리 구조로 내용을 담고 있다.
        DATASETS:
            TEST: ()
            TRAIN: ()
        DATA_LOADER:
            NUM_WORKERS: 8
            PIN_MEMORY: True
        INPUT:
            IMAGE_SIZE: 300
            PIXEL_MEAN: [123, 117, 104]
      
    • vizer : 이미지에 vizualization을 해주는 툴을 직접 개발해 놓음. 이미지와 box좌표, 이미지와 mask좌표가 있다면 그걸로 이미지에 그림을 그려 시각화를 해줌.
  2. VOC와 COCO data를 직접 다운
    • 과거에 정리해둔 Datasets 정리 포스트를 보고 파일 다운로드
    • 그리고 export 설정으로 우분투 터미널에게 path를 알려줘야 한다.
    • 경로 설정 까지 완료 (코랩 ssd_package_setup.ipynb 파일 참조)
  3. 그 후, 코드 공부 순서는 다음과 같다
    • Demo
      • $ python demo.py –config-file configs/vgg_ssd300_voc0712.yaml –images_dir demo –ckpt https://github.com/lufficc/SSD/releases/download/1.2/vgg_ssd300_voc0712.pth
    • Single GPU training
      • $ python train.py –config-file configs/vgg_ssd300_voc0712.yaml
    • Single GPU evaluating
      • $ python test.py –config-file configs/vgg_ssd300_voc0712.yaml

2. Package Github Exploration

  • file Tree
      📦SSD
      ┣ 📂configs
      ┃ ┣ 📜efficient_net_b3_ssd300_voc0712.yaml
      ┃ ┣ 📜mobilenet_v2_ssd320_voc0712.yaml
      ┃ ┣ 📜mobilenet_v3_ssd320_voc0712.yaml
      ┃ ┣ 📜vgg_ssd300_coco_trainval35k.yaml
      ┃ ┣ 📜vgg_ssd300_voc0712.yaml
      ┃ ┣ 📜vgg_ssd512_coco_trainval35k.yaml
      ┃ ┗ 📜vgg_ssd512_voc0712.yaml
      ┣ 📂demo
      ┃ ┣ 📜000342.jpg
      ┃ ┣ 📜000542.jpg
      ┃ ┣ 📜003123.jpg
      ┃ ┣ 📜004101.jpg
      ┃ ┗ 📜008591.jpg
      ┣ 📂figures
      ┃ ┣ 📜004545.jpg
      ┃ ┣ 📜losses.png
      ┃ ┣ 📜lr.png
      ┃ ┗ 📜metrics.png
      ┣ 📂outputs
      ┃ ┗ 📜.gitignore
      ┣ 📂ssd
      ┃ ┣ 📂config
      ┃ ┃ ┣ 📜defaults.py
      ┃ ┃ ┣ 📜path_catlog.py
      ┃ ┃ ┗ 📜__init__.py
      ┃ ┣ 📂data
      ┃ ┃ ┣ 📂datasets
      ┃ ┃ ┃ ┣ 📂evaluation
      ┃ ┃ ┃ ┃ ┣ 📂coco
      ┃ ┃ ┃ ┃ ┃ ┗ 📜__init__.py
      ┃ ┃ ┃ ┃ ┣ 📂voc
      ┃ ┃ ┃ ┃ ┃ ┣ 📜eval_detection_voc.py
      ┃ ┃ ┃ ┃ ┃ ┗ 📜__init__.py
      ┃ ┃ ┃ ┃ ┗ 📜__init__.py
      ┃ ┃ ┃ ┣ 📜coco.py
      ┃ ┃ ┃ ┣ 📜voc.py
      ┃ ┃ ┃ ┗ 📜__init__.py
      ┃ ┃ ┣ 📂transforms
      ┃ ┃ ┃ ┣ 📜target_transform.py
      ┃ ┃ ┃ ┣ 📜transforms.py
      ┃ ┃ ┃ ┗ 📜__init__.py
      ┃ ┃ ┣ 📜build.py
      ┃ ┃ ┗ 📜__init__.py
      ┃ ┣ 📂engine
      ┃ ┃ ┣ 📜inference.py
      ┃ ┃ ┣ 📜trainer.py
      ┃ ┃ ┗ 📜__init__.py
      ┃ ┣ 📂layers
      ┃ ┃ ┣ 📜separable_conv.py
      ┃ ┃ ┗ 📜__init__.py
      ┃ ┣ 📂modeling
      ┃ ┃ ┣ 📂anchors
      ┃ ┃ ┃ ┣ 📜prior_box.py
      ┃ ┃ ┃ ┗ 📜__init__.py
      ┃ ┃ ┣ 📂backbone
      ┃ ┃ ┃ ┣ 📂efficient_net
      ┃ ┃ ┃ ┃ ┣ 📜efficient_net.py
      ┃ ┃ ┃ ┃ ┣ 📜utils.py
      ┃ ┃ ┃ ┃ ┗ 📜__init__.py
      ┃ ┃ ┃ ┣ 📜mobilenet.py
      ┃ ┃ ┃ ┣ 📜mobilenetv3.py
      ┃ ┃ ┃ ┣ 📜vgg.py
      ┃ ┃ ┃ ┗ 📜__init__.py
      ┃ ┃ ┣ 📂box_head
      ┃ ┃ ┃ ┣ 📜box_head.py
      ┃ ┃ ┃ ┣ 📜box_predictor.py
      ┃ ┃ ┃ ┣ 📜inference.py
      ┃ ┃ ┃ ┣ 📜loss.py
      ┃ ┃ ┃ ┗ 📜__init__.py
      ┃ ┃ ┣ 📂detector
      ┃ ┃ ┃ ┣ 📜ssd_detector.py
      ┃ ┃ ┃ ┗ 📜__init__.py
      ┃ ┃ ┣ 📜registry.py
      ┃ ┃ ┗ 📜__init__.py
      ┃ ┣ 📂solver
      ┃ ┃ ┣ 📜build.py
      ┃ ┃ ┣ 📜lr_scheduler.py
      ┃ ┃ ┗ 📜__init__.py
      ┃ ┣ 📂structures
      ┃ ┃ ┣ 📜container.py
      ┃ ┃ ┗ 📜__init__.py
      ┃ ┣ 📂utils
      ┃ ┃ ┣ 📜box_utils.py
      ┃ ┃ ┣ 📜checkpoint.py
      ┃ ┃ ┣ 📜dist_util.py
      ┃ ┃ ┣ 📜logger.py
      ┃ ┃ ┣ 📜metric_logger.py
      ┃ ┃ ┣ 📜misc.py
      ┃ ┃ ┣ 📜model_zoo.py
      ┃ ┃ ┣ 📜nms.py
      ┃ ┃ ┣ 📜registry.py
      ┃ ┃ ┗ 📜__init__.py
      ┃ ┗ 📜__init__.py
      ┣ 📜demo.py
      ┣ 📜DEVELOP_GUIDE.md
      ┣ 📜requirements.txt
      ┣ 📜setup.py
      ┣ 📜test.py
      ┣ 📜train.py
    
  1. ssd/modeling/detector
    • ssd/modeling에는 아래와 같은 신경망 구성 요소를 nn.module로 구현해놓은 파일이 있다.
      1. anchors
      2. backbone
      3. box_head
    • ssd_detector.py 에서 nn모듈”SSDDetector”을 return 해줌.
      • SSDDetector는 아주 짧은 nn모듈이며, 아래의 2 모듈을 사용
        • from ssd.modeling.backbone import build_backbone
        • from ssd.modeling.box_head import build_box_head
    • 따라서 신경망 구현에 대한 정확한 코드를 보고 싶다면, 위의 3개의 폴더 내부의 파일들을 봐야한다.
    • 이 폴더 내부 파일에 대해서는 아래의 큰 chapter로 다시 다룰 예정
  2. ssd/utils
    • checkpoint.py import CheckPointer : ckpt의 링크에서 모델 paramerter를 다운받고, 나의 신경망에 넣는 함수
      • model_zoo 파일로 가서, pth파일을 download하고 받은 cached_file을 return받는다.
      • torch.load 함수를 사용한다.
    • model_zoo.py
      • torch.hub 모듈을 사용한다.
      • 이 모듈에는 download_url_to_file/ urlparse/ HASH_REGEX 와 같은 함수가 있다.
      • 나의 신경망 파라미터를 pht파일로 저장하고, 그것을 github에 올려놓고 누군가가 나의 신경망 파라미터를 사용할 수 있게 하려면, 이 torch.hub모듈을 사용해야겠다.
    • registry.py
      • registry - 모듈을 config의 dictionary구조처럼 저장해 놓고, 쉽게 불러와 사용할 수 있게 해놓은 툴.
      • 이와 같이 사용함
              # ssd/modeling/backbone/vvg.py
              @registry.BACKBONES.register('vgg')
              def vgg(cfg, pretrained=True):
                  model = VGG(cfg)  # 같은 파일에서 정의한 클래스
                  if pretrained:
                      model.init_from_pretrain(load_state_dict_from_url(model_urls['vgg']))
                  return model
                    
              # ssd/modeling/backbone/__init__.py
              def build_backbone(cfg):
                  return registry.BACKBONES[cfg.MODEL.BACKBONE.NAME](cfg, cfg.MODEL.BACKBONE.PRETRAINED)
        
      • 또는 이와 같이 사용됨.
              # ssd/modeling/box_head/vvg.py
              @registry.BOX_HEADS.register('SSDBoxHead')
              class SSDBoxHead(nn.Module):
                  def __init__(self, cfg):
                      super().__init__()
                      self.cfg = cfg
                      self.predictor = make_box_predictor(cfg)
                      self.loss_evaluator = MultiBoxLoss(neg_pos_ratio=cfg.MODEL.NEG_POS_RATIO)
                      self.post_processor = PostProcessor(cfg)
                      self.priors = None
              # ssd/modeling/box_head/__init__.py
              def build_box_head(cfg):
                  return registry.BOX_HEADS[cfg.MODEL.BOX_HEAD.NAME](cfg)
        
      • registry에 모듈을 저장해두고, config에 적혀있는데로, 각각의 상황마다 각각의 모듈을 호출하기 쉽게 만들어 놓음. switch문이나 if문을 여러개써서 어떤 boakbone을 string으로 입력했는지 확인하는 작업이 필요없다.
      • 어려울 것 없고, 이 registry도 하나의 dictionary이다. 전체 코드에서는 dict{dict, dict, dict, dict …} 와 같은 구조로 사용 중.
  3. ssd/data/transforms
    • transforms.py -torchvision.transfoms 에 있을 법한 함수들이 직접 만들어져 있다.
      • Ex) resize, ToTensor, RandomFlip.. 과 같은 클래스들이 직접 구현되어 있다.
      • 특히 compose 또한 직접 구현해놓았다.
      • 위의 클래스들은 모두 __call__(parameters) 들이 구현되어 있다. def과 다르게 class로 만들어 놓은 클래스는 call을 정의해야만, 함수 포인터로써 클래스를 사용할 수 있다. 예를 들어 아래와 같이 사용이 가능하다.
          class ToTensor(object):
              def __call__(self, cvimage, boxes=None, labels=None):
                  return torch.from_numpy(cvimage.astype(np.float32)).permute(2, 0, 1), boxes, labels
                    
          transform = [RandomSampleCrop(),
                          RandomMirror(),
                          ToTensor()]
                    
          transform = Compose(transform)
          return transform
        
    • __init__.py :

      • build_transforms, build_target_transform 와 같은 함수들이 정의되어 있고, 다른 파일에서 이 함수만 사용함으로써 쉽게 transform을 수행할 수 있다.
  4. SSD/ssd/data
    • ssd/data/datasets/coco.py & SSD/dataset/voc.py 각 데이터 셋을 사용하기 위한 함수들이 잘 정의되어 있다.
      • Readme.md에 있는 data directory 구조를 똑같이 사용한다면, 나중에도 사용 가능!
      • terminal 필수
          $ VOC_ROOT="/path/to/voc_root"
          $ export COCO_ROOT="/path/to/coco_root"
        
      • export한 정보는 아래와 같이, os.environ 함수를 사용해 호출 될 수 있다.
          # SSD/train.py
          num_gpus = int(os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1
          voc_root = os.environ['VOC_ROOT']
          coco_root = os.environ['COCO_ROOT']
        
    • ssd/data/datasets/build.py & SSD/dataset/__init__.py

      • build.py : make_data_loader라는 함수가 정의되어 있고, from torch.utils.data.dataloader import default_collate 를 사용해서, 거의 직접 dataloader를 구현해 놓았다.

3. Analysis of lufficc/SSD/demo.py

  •   $ python demo.py \
          --config-file configs/vgg_ssd300_voc0712.yaml \
          --images_dir demo \
          --ckpt https://github.com/lufficc/SSD/releases/download/1.2/vgg_ssd300_voc0712.pth
      $ python demo.py \
          --config-file configs/vgg_ssd512_voc0712.yaml \
          --images_dir demo \
          --ckpt https://github.com/lufficc/SSD/releases/download/1.2/vgg_ssd512_voc0712.pth
    
  • def main()
    1. argparse 나의 포스트
    2. load config file that include info like num_classes, Dataset…
    3. print
       Loaded configuration file configs/vgg_ssd300_voc0712.yaml
              
       MODEL:
       NUM_CLASSES: 21
       INPUT:
       IMAGE_SIZE: 300
       ...
      
  • def run_demo(cfg, ckpt, score_threshold, images_dir, output_dir, dataset_type)
    1. @torch.no_grad() : decorator, Because it define __enter__, __exit__ on code here.
    2. model = build_detection_model(cfg)
      • modeling/detector/__inti__.py에서 modeling/deector/ssd_detector.py의 nn모듈”SSDDetector”을 return 해줌
      • 이 모듈의 전체 신경망 코드는 나중에 공부.
    3. ssd.utils.checkpoint import CheckPointer 로 신경망 파라메터 load.
    4. transforms = build_transforms(-> compose([transforms]))
    5. glob.glob(directory_path) == os.listdir(directory path)
    6. for i, image_path in enumerate(image_paths : list of images_path):
      • os.path.basename : 마지막 파일명만 return (‘Module’ Research 참고)
      • result = model(images.to(device))[0]
      • boxes, labels, scores = result[‘boxes’], result[‘labels’], result[‘scores’]
      • drawn_image = draw_boxes(image, boxes, …)
      • Image.fromarray(drawn_image).save(path)

4. Analysis of lufficc/SSD/ssd/modeling

  • SSD/ssd/modeling/backbone/vvg.py
    • class vvg16(nn.module)
      • input(300x300,500x500) 따라서 많은 convd2d, relu, Maxpooling 등을 처리해나간다.
      • 3개의 feature이 returm되며, features = [(1024,w,h),(512,w/2,h/2),(256,w/4,h/4)] 이다. (정확하지 않다.)
  • SSD/ssd/modeling/box_head/box_head.py
    • class SSDBoxHead(nn.Module)
    • 여기에서 많은 모듈을 사용한다
            from ssd.modeling.anchors.prior_box import PriorBox
        (1) from ssd.modeling.box_head.box_predictor import make_box_predictor
            from ssd.utils import box_utils
            from .inference import PostProcessor
        (2) from .loss import MultiBoxLoss
      
    • 하나하나 간략이 알아가보자.
      1. self.predictor = make_box_predictor(cfg)
        • cls_logits, bbox_pred = self.predictor(features)
        • cls_logits, bbox_pred : 모든 class에 대한 점수값, 이미지에서 bbox의 의미를 return한다.
        • conv2d만을 사용해서 최종결과를 반환한다. 생각보다 softmax 이런거 안하고 생각보다 단순하게 conv2d를 반복해서 적용하여, 마지막에 가져야할 tensor size에 맞춘다.
        • 그렇게 적당한 크기에 맞춰진 cls_logits, bbox_pred가 return 되는 것이다
      2. self.loss_evaluator = MultiBoxLoss(neg_pos_ratio=cfg.MODEL.NEG_POS_RATIO)
        •   gt_boxes, gt_labels = targets['boxes'], targets['labels']
            reg_loss, cls_loss = self.loss_evaluator(cls_logits, bbox_pred, gt_labels, gt_boxes)
          
        • 코드에서 위와 같이 사용된다. 즉 ground true와 비교해서 regressing_loss와 class_loss를 계산하게 된다.
        • class MultiBoxLoss(nn.Module)의 forward에서 loss함수를 정의했다.
          •   classification_loss = F.cross_entropy(confidence.view(-1, num_classes), labels[mask], reduction='sum')
              smooth_l1_loss = F.smooth_l1_loss(predicted_locations, gt_locations, reduction='sum')
              return smooth_l1_loss / num_pos, classification_loss / num_pos
            
          • 이와 같이 우리가 흔히 아는, torch.nn.functional.Fcross_entropy, torch.nn.functional.smooth_l1_loss 함수를 사용한 것을 볼 수 있다.
        • 앞으로 코드는 이 loss를 줄이기 위해 노력할 것이다. 그렇다면 cls_logits, bbox_pred가 self.predictor(features)에 의해서 더욱 정확하게 나오기 위해 노력할 것이다.
        • 코드 전체에서 forward만 잘 구현해 놓음으로써 이렇게 자동으로 backpropagation이 이뤄지고, 신경망 내부의 모든 weight, bias가 갱신되게 만들어 놓았다. 막상 backward까지 직접 구현하는 코드는 많이 없는듯 하다.
      3. self.post_processor = PostProcessor(cfg)
      4. self.priors = None
        • 위의 3,4는 inference를 위한 코드이다. 나중에 필요하면 보자.
        • 지금은 빨리 mmdetection구조를 알아가고 싶다.
        • 코드 구조와 모듈들 알아가는게 너무 재미있다.
        • 이제 torch layer가 구현되는 코드는 완전히 이해가 가능하다. 모르는 것도 없고, 모르면 금방 찾을 수 있겠다.
    • 그래서 결국에는 아래와 같은 값을 return 한다.
      • train 과정에서는 tuple(detections, loss_dict)
      • test 과정에서는 tuple(detections, {})
      • 이때, detections = (cls_logits, bbox_pred)
      • 그리고, loss_dict = 위의 regressing_loss와 class_loss가 dictionary 형태로 return 된다.
  • SSD/ssd/modeling/detector/ssd_detector.py
    • 위의 2개의 큰 모듈을 modeling/backbone, modeling/boxhead를 사용하는 간단한 코드
    •   class SSDDetector(nn.Module):
            def __init__(self, cfg):
                super().__init__()
                self.cfg = cfg
                self.backbone = build_backbone(cfg)
                self.box_head = build_box_head(cfg)
              
            def forward(self, images, targets=None):
                features = self.backbone(images)
                detections, detector_losses = self.box_head(features, targets)
                if self.training:
                    return detector_losses
                return detections
              
      
    • 여기서 신기한건, train하는 과정에서 detection결과(cls_logits, bbox_pred)는 아에 버려진다. 왜냐면 이미, loss 계산을 마쳤으니까!!

5. Analysis of lufficc/SSD/train.py

  • 시작 하기 전에
    • 처음 보는 pypi 모듈이라고 하더라도, 쫄지말고 공부하자.
    • 앞으로 mmdetection, detectron2에서 더 모르는 모듈이 많이 나올텐데, 이 정도로 쫄면 안된다.
    • SSD package 부시기로 했는데, 내가 부셔지면 안되지!! 화이팅!
  • main()
    1. import torch.distributed
      • GPU가 2개 이상일 때 사용하는 코드이다. 데이터 병렬처리 작업을 하고 싶으면 공부해서 사용하면 된다.
      • Official document
      • Data Parallel Tutorial : 나의 상황(single-device training, single-machine multi-GPU)에 따라서 torch에서 추천해주는 모듈을 사용하면 된다.
    2. 코드 제작자는 print를 절대 사용하지 않는다. logger를 사용해서 terminal에 출력!
    3. model = train(cfg, args)
  • train(cfg, args):
    1. optimizer, scheduler 정의
      • from ssd.solver.build import make_optimizer, make_lr_scheduler
      • from ssd.solver.build 에는 optimizer, lr_scheduler 가 정의되어 있다. (별거 없음)
      • optimizer = torch.optim.SGD(model.parameters(), lr=lr, … )
      • LRscheduler = torch.optim.lr_scheduler(optimizer, last_epoch)
    2. checkpointer = CheckPointer(model, optimizer, scheduler, cfg.OUTPUT_DIR, save_to_disk, logger)
      • ssd/utils/checkpoint.py : 모델을 학습시키는 중간중간, model, optimizer, scheduler를 save, load하는 함수가 def 되어 있다.
      • data = {‘model’: ~ ,’optimizer’: ~ ,’scheduler’: ~ } 이와 같이 dict으로 저장한다음, torch.save(data, “{}.pth 형식의 paht”)로 저장하면 된다.
    3. model = do_train(cfg, model, train_loader, optimizer, scheduler, checkpointer, device, arguments, args)
  • do_train (ssd/engine/trainer.py)
    • torchvision을 만들기
    • dataloder에서 data 가져오기
    • 파라메터 갱신하기
    •   summary_writer = SummaryWriter(log_dir=os.path.join(cfg.OUTPUT_DIR, 'tf_logs'))
        for iteration, (images, targets, _) in enumerate(data_loader, start_iter):
            loss_dict = model(images, targets=targets)
            loss = sum(loss for loss in loss_dict.values())    
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            scheduler.step()
              
            if iteration % args.log_step == 0:
                logger.info( # 현재 학습 상태 출력
                summary_writer.add_scalar
      
    • MAX_ITER = ephch: 160000 정도로 설정되었지만, 그래도 아마 scheduler에 의해서 조기 학습 종료도 가능할 듯 싶다.

6. Analysis of lufficc/SSD/inferene.py

  • pass

7. summary

  • 지금까지의 과정을 통해서 lufficc/SSD을 이용해서 아래와 같은 것을 알아보았다.
    1. 어떻게 구성되어 있는지
    2. 각각의 파일들은 대충 어떤 역할을 하는지
    3. 파일들이 서로 어떻게 호출되고, 어떻게 사용되는지
    4. 다음에 이런 방식으로 모듈화 되어 있는 패키지를 어떻게 사용해야 할지
  • 분명 지금은 코드를 한줄한줄 정확히 알고, 코드 한줄을 지나면 데이터들의 형태나 타입이 어떻게 되는지 확인해보지는 않았다.
  • 지금은 당장 사용할 것도 아닌데 그렇게 까지 코드를 공부할 필요는 없다고 생각했다. 차라리 detectron2 혹은 mmdetection의 내부 코드들을 하나하나 씹어 먹는게 낫지 굳이 이거는 그냥 꿀덕꿀덕 삼키는 식으로 공부했다.
  • 이 과정을 통해서, 패키지를 보고 탐구하는 것에 대한 두려움이 사라졌다.
  • 패키지 내부의 코드를 부셔버려야지, 내가 맨붕와서 부셔지면 안된다. 라는 것을 깨달았다.
  • 이와 같은 방식으로 탐구해 나간다면, 어떤 패키지와 코드를 만나든, 잘 분석할 수 있겠다.
  • 추가로!! 다음에 정말 정확히 분석해야할 패키지가 생긴다면, 아래와 같은 작업을 꼭 하자.
    • 원하는 모듈만 import해서, 직접 함수나 클래스를 사용해보거나
    • 디버깅을 해서, 데이터 흐름이 어떻게 되는지 정확하게 뜯어보거나
    • 직접 코드 전체를 가지고 학습이나, inference를 해보거나
    • 즉. 눈으로만 코드 보지말고, 직접 코드를 실행해보고 확인해보자!!

【Python-Module】 Module, Function research of Pytorch tuto

Pytorch tutorial을 공부하면서, 새로운 함수나 모듈이 나왔을 때 고찰해보고 공부해본 내용을 담아 놓았다.

  • 너무 깊이 들어가지 말자. 1단계만 타고 들어가자.
  • 2단계 초과로 타고 들어가지 말자!!! 나는 너무 끝도 없이 타고 들어간다.

1. torch.max()

!ls -al
total 16
drwxr-xr-x 1 root root 4096 Dec 21 17:29 .
drwxr-xr-x 1 root root 4096 Jan  5 07:34 ..
drwxr-xr-x 1 root root 4096 Dec 21 17:29 .config
drwxr-xr-x 1 root root 4096 Dec 21 17:29 sample_data
  • 꼭 먼저 아래의 사진 부터 보기

  • n차원 행렬 array에 대해서 array[1,2,:,1] , array[:,2,3,1] , array[1,2,:,1,5] 를 출력해보면 1차원 백터이다!

  • 이 1차원 백터에 대해서 가장 큰 값 (max)를 찾는다

import torch
arr = torch.randint(1,100,(3,6,9))
max_value0, index0 = torch.max(arr,0)
max_value1, index1 = torch.max(arr,1)
max_value2, index2 = torch.max(arr,2)

print(max_value0.shape) # 3빠지고 -> index는 0~2 중 하나겠군
print(max_value1.shape) # 6빠지고 -> index는 0~5 중 하나겠군
print(max_value2.shape) # 9빠지고 -> index는 0~8 중 하나겠군

# 아래처럼 x,y의 위치가 그대로 대응된다.
arr[0,:,0], torch.max(arr[0,:,0]), max_value1[0,0]
arr[1,:,2], torch.max(arr[1,:,2]), max_value1[1,2]
torch.Size([6, 9])
torch.Size([3, 9])
torch.Size([3, 6])





(tensor([53, 34, 59, 48, 90, 34]), tensor(90), tensor(90))

2. np.shape, torch.shape

  • if 2차원이라고 감지되고 있다면, (1,4)와 (4,1)은 완전히 다른거다.
  • 2차원이라고 감지되는 상태와, 1차원이라고 감지되는 상태는 완전 다르다.
output = torch.randint(1,100,(4,10))
preds = torch.randint(1,10,(4,1)) # 1,4 를 하면 아래의 zip이 잘 동작 안한다.

# i.shape = 1
# ei.shape = 1,10

for i, el in zip(preds, output):
    print(el, el.shape, i)
tensor([26, 78,  9,  1, 81, 82, 82, 51, 28, 41]) torch.Size([10]) tensor([3])
tensor([36, 80, 87, 30, 26,  8,  3, 89, 96, 83]) torch.Size([10]) tensor([3])
tensor([62, 35, 60, 90, 20, 84, 32, 72, 64, 83]) torch.Size([10]) tensor([7])
tensor([81, 23, 72, 88, 43, 79, 59,  2, 12, 40]) torch.Size([10]) tensor([4])
import numpy as np
a = np.random.randn(1,4)
b = np.random.randn(4,1)
print(a.shape, b.shape)

c = torch.randn(1,3)
d = torch.randn(3,1)
print(c.shape, d.shape)
(1, 4) (4, 1)
torch.Size([1, 3]) torch.Size([3, 1])
  • np.sqeeze는 2차원으로 감지되는 행렬을, 1차원으로 바꿔주는 역할도 한다.
# https://note.nkmk.me/en/python-numpy-ndarray-ndim-shape-size/
a = np.squeeze(a)  # (4,)는 원소 4개의 tuple을 의미한다. 즉 2차원 행렬이 아니라고 감지하고 있는 상태. 즉 백터.
b = np.squeeze(b)
print(a.shape, b.shape)

c = torch.squeeze(c)  # (4,)는 원소 4개의 tuple을 의미한다. 즉 2차원 행렬이 아니라고 감지하고 있는 상태. 즉 백터.
d = torch.squeeze(d)
print(a.shape, b.shape)
(4,) (4,)
(4,) (4,)

3. torch.nn.functional

  • nn.module이란 무엇일까?
    • nn document에 Containers에 Module, Sequential, ModuleList 등이 있다. 이것은 “Layer를 담는 그릇” 이다. 즉 “신경망 전체 그릇”이라고 표현하면 좋다.
    • 그리고 nn document 여기에, 이 그릇에 들어갈 층(Layer)들이 들어가 있다. 또한 Loss Function도 들어가 있다.
  • 위의 nn document 와는 다르게, Layer 하나하나를 독단적으로 사용할 수 있게 하는 것이, torch.nn.functional as F 이다.
    • torch.nn.functional 의 return은 해당 layer를 통과하고 나온 tensor가 나온다. (def -> Tensor)
    • F.relu() 이와 같이 GIt에 저장되어 있다.
  • F.softmax
    • return : -> Tensor
    • input의 shape가 어떤 것이라 할지라도, 하나의 dim만 바라보면 1차원 백터가 된다.
    • Ex) dim=1 일 때 arr[1,:,2], arr[5,:,2,1] = 1차원! 백터 ()
    • 그 1차원 백터에 대해서 모든 index값의 softmax값을 구한다.
filters = torch.randn(8,4,3,3) # 몇장 depth 행 열

inputs = torch.randn(1,4,5,5) # 몇장 depth 행 열

out_tensor = F.conv2d(inputs, filters, padding=1)

out_tensor.shape
torch.Size([1, 8, 5, 5])
# `junha <https://devguide.python.org/documenting/>`_



# A Foolish Consistency is the Hobgoblin of Little Minds [1]

# [1]: http://www.python.org/dev/peps/pep-0008/#a-foolish-consistency-is-the-hobgoblin-of-little-minds
import torch
import torch.nn.functional as F
output = torch.randn((4,10))
preds = torch.randint(0,9,(4,))

# 2차원이라고 인지한 상태
temp1 = torch.randint(1,100,(1,10))
print(temp1.shape)
temp2 = torch.randint(1,100,(10,1))
print(temp2.shape)

# 여기서 el은 2차원이 아니라, 1차원으로 인지되어 나온다.
for i, el in zip(preds, output):
    print(type(i), type(i.item()))
    print(el, el.shape)
    break

for i in zip(preds, output):
    print(type(i), len(i), "elements : ",i[0].item(), i[1].tolist())
    break
torch.Size([1, 10])
torch.Size([10, 1])
<class 'torch.Tensor'> <class 'int'>
tensor([-0.1235,  1.0481, -0.3385, -0.6615,  1.2481, -1.0524, -0.3961,  0.7990,
         1.6359, -0.3628]) torch.Size([10])
<class 'tuple'> 2 elements :  3 [-0.12354857474565506, 1.0481327772140503, -0.3384615480899811, -0.6614770889282227, 1.248133897781372, -1.0524193048477173, -0.3961334228515625, 0.7990166544914246, 1.635870337486267, -0.36283737421035767]
# [F.softmax(el, dim=0)[i].item() for i, el in zip(preds, output)]
# [F.softmax(torch.squeeze(el), dim=0)[i.item()].item() for i, el in zip(preds, output)]
[F.softmax(el, dim=0)[i].item() for i, el in zip(preds, output)]

# pred_index : 4장의 사진 각각의 해당하는 index
# softmax_result : 1장의 사진에 대한 labels 10개의 softmax결과 값 중. 그 index가 가지는 softmax값

4. torch.cat

  • Concatenates (tensors (sequence of Tensors), Dimension)
  • document
  • Concatenates 되기 위해, 들어가는 tensor들의 dimention이 적절해야한다.
x = torch.randn(2, 3)
print('x :',x)
cat_dim0 = torch.cat((x, x, x), 0) # (**2**, 3) * 3개 = (**6**, 3)
print('cat_dim0 :\n',cat_dim0)
cat_dim1 = torch.cat((x, x, x), 1) # (2, **3**) * 3개 = (2, **9**)
print('cat_dim1 :\n',cat_dim1)

5. torch.stack

  • list나 tuple을 이용해서, sequence of Tensors로 표현되어 있는 것을 tensor로 묶어 준다.
  • 아래와 같은 경우. len of list(3) + tensor_x(2,3) -> tensor(3,2,3)
x = torch.randn(2, 3)
print('x :',x)
stack_dim0 = torch.stack([x, x, x], 0) 
print('stack_dim0 :\n',stack_dim0, stack_dim0.shape)
stack_dim1 = torch.stack((x, x, x), 1) 
print('stack_dim0 :\n',stack_dim1, stack_dim1.shape)
x : tensor([[-0.6724,  0.4038,  1.3529],
        [ 0.1946,  1.9841, -0.4614]])
stack_dim0 :
 tensor([[[-0.6724,  0.4038,  1.3529],
         [ 0.1946,  1.9841, -0.4614]],

        [[-0.6724,  0.4038,  1.3529],
         [ 0.1946,  1.9841, -0.4614]],

        [[-0.6724,  0.4038,  1.3529],
         [ 0.1946,  1.9841, -0.4614]]]) torch.Size([3, 2, 3])
stack_dim0 :
 tensor([[[-0.6724,  0.4038,  1.3529],
         [-0.6724,  0.4038,  1.3529],
         [-0.6724,  0.4038,  1.3529]],

        [[ 0.1946,  1.9841, -0.4614],
         [ 0.1946,  1.9841, -0.4614],
         [ 0.1946,  1.9841, -0.4614]]]) torch.Size([2, 3, 3])

6. PIL.Image

  • depth checking
  • PIL 기초
    • R_image = PIL.Image.open(‘path’)
    • R_image.size = 행렬
    • R_image.mode = depth
try :
    from PIL import Image
    import os
    # PIL 간단하게 사용해보기. 
    root = "/home/sb020518/tutoPytorch/data_for_5/PennFudanPed"
    mask_path = os.path.join(root, "PedMasks", "FudanPed00001_mask.png")
    mask1 = Image.open(mask_path)
    print(type(mask1),mask1.size, mask1.mode) # L은 gray scale image = 8 bit 이미지

    root = "/home/sb020518/tutoPytorch/data_for_5/PennFudanPed"
    mask_path = os.path.join(root, "PNGImages", "FudanPed00001.png")
    img1 = Image.open(mask_path)
    print(img1.size, img1.mode)
except :
    pass

7. np.unique + objs - broadcast + np.where

- np.unique

  • 중복되는 원소들을 제거해준다.
  • np.unique document
  • [1 2 1 1 2 2 3] -> [1,2,3]

    - torch에서 broadcast를 이용한 COC O형식의 Mask 결과 추출하기

(5.torchvision_finetuning_instance_segmentation의 내용중 일부)
obj_ids = [1 2] => shape : (2,)
objs_ids[:] => array([1, 2], dtype=uint8)
obj_ids[:, None, None] = not defiend 이라고 하지만, –broadcast—> (2, width, hight) 가 되겠다.
masks = [1,width, hight] ———————————— –broadcast—> (2, width, hight)
masks = ( mask == objs_ids[:, None, None]) ————shape is———> (2, 536, 559)

masks[0,:,:] ==> 원래 1이 있던 자리만 True되어 있음
masks[1,:,:] ==> 원래 2가 있던 자리만 True되어 있음

img

- np.where

  • 원하는 숫자가 어느 위치에 있는지를 찾아 return해주는 모듈 (Find index of a value in a Numpy array (both 1D & 2D))
  • where document : https://thispointer.com/find-the-index-of-a-value-in-numpy-array/
  • 숫자를 찾고 싶으면 np.where(arr=hope_to_find_num)
  • output = 원한 위치의 all indices
  • bool에서 ture를 찾고 싶으면 np.where(arr), 단 arr의 data type = bool
import numpy as np
root = "/home/sb020518/tutoPytorch/data_for_5/PennFudanPed"
mask_path = os.path.join(root, "PedMasks", "FudanPed00001_mask.png")
mask1 = Image.open(mask_path)
mask = np.array(mask1) 
print('mask\'s shaep : ' , mask.shape)

objs_ids = np.unique(mask)
objs_ids = objs_ids[1:]
print("A number of objects :",objs_ids)
masks = ( mask == objs_ids[:, None, None])
print("masks.shape : ",masks.shape)
print("1번째 객체가 위치하는 곳 :", np.where(masks[0,...]==True))
print("2번째 객체가 위치하는 곳 :", np.where(masks[1,:,:]==True))
import torch
boxes = []
for i in range(objs_ids[-1]):
    pos = np.where(masks[i]) # masks[i] == masks[i,...] == masks[i,:,:] = 2차원 백터 = 여기서 True만 반환
    xmin = np.min(pos[1])
    xmax = np.max(pos[1])
    ymin = np.min(pos[0])
    ymax = np.max(pos[0])
    boxes.append([xmin, ymin, xmax, ymax])
torch.tensor(boxes,dtype=torch.float32)


8. torch.tensor VS torch.as_tensor VS torch.from_numpy()

각각의 document를 읽고 핵심만 정리한다. 참고 stackoverfloar PyTorch memory model: “torch.from_numpy()” vs “torch.Tensor()”

  • torch.tensor : list나 numpy를 받아들임 , copy a data = memory overhead = out-place 알고리즘
  • tensor_object.new_tensor : 보통 tensor를 받아들임, create a tensor with similar type but different size as another tensor.
  • torch.as_tensor: in place 알고리즘, numpy랑 메모리를 공유해서, numpy를 바꾸면 tensor도 바뀜, numpy의 dtype무시 torch.FloatTensor!
  • torch.from_numpy() : in place 알고리즘, numpy랑 메모리를 공유해서, numpy를 바꾸면 tensor도 바뀜, numpy의 dtype를 존중

Network에서 사용할 tensor함수

  • torch.Tensor.requires_grad_() - inplace 알고리즘
  • torch.Tensor.detach() - inplace 알고리즘

쨋든 pytorch에서 말하길 The recommended way to build tensors in Pytorch is to use the following two factory functions: {torch.tensor} and {torch.as_tensor}


9. TORCHVISION.TRANSFORMS

  • documentary site 내용 정리 하기.
    • img input은 PIL, Tensor image, Tensor images.
    • WARNING : batch에서 randoom seed를 그냥 이용하면 backpropa와 잘 양립 되지 않을 수 있으므로, torch.manual_seed(17) 를 이용해 seed 값 맞춰 줘라.
    • (torchvision.transroms.)Grayscale, Colorjitter, CenterCrop,Pad 등등.. 또한 하나의 nn모듈이다. 그래서 다 forward가 있고, 그것을 사용하는 것이다.
    • compose([list of Transforms]) 내부에는 위와 같은 nn모듈 클래스가 들어가고, 자동으로, forward에 들어가는 input은 img input이 된다. 여기에 들어가야할 자료형은 위에 정리 완료
    • scripted_transforms = torch.jit.script(transforms); # 이렇게 script를 사용하기 위해서는 compose말고 nn.Sequential로 묶으라는데 아직 뭔지 모르겠음.

10. Imform Return type or Variable type

def funtion(parameters) -> return_type : 
variable : type = value
def add(a,b) -> int:
    return a+b
a : int = 3
b : float = 4
type(b), add(a,b)

11. Object에 새로운 맴버변수 삽입이 가능하다,

  • backbone.out_channels??
  • ~(nn.Module 로써 정의된 class의 객체는 아니다) nn.sequential로 정의된 (class의) 객체든 뭐든 out_channels라는 맴버변수를 사용하면, 가장 마지막 layer의 out_channels 맴버변수가 자동으로 호출된다.~ -> 개소리 였다. 이거 아니다.
  • 결론 : Python 클래스로 정의된 객체에 새로운 맴버변수를 추가하는 것이 가능하다. 맴버함수도 가능하지만 self.Mamber_valuabe이 들어가선 안된다.
# 1. 여기서 1280은 어디서 나온 것 일까??
import torchvision
backbone = torchvision.models.mobilenet_v2(pretrained=True).features
backbone.out_channels = 1280

# 2. 기본 Faster RCNN에서 사용하는 backbone의 out_channels을 확인해보자,
#     하지만 잘 살펴보니, class FasterRCNN(GeneralizedRCNN):; out_channels = backbone.out_channels; 를 해줘서 알아서 out_channels에 맞춰주는 것 같은데...
from torchvision.models.detection.backbone_utils import resnet_fpn_backbone
backbone_2 = resnet_fpn_backbone('resnet50', pretrained=False)
out_channels = backbone_2.out_channels # resnet_fpn_backbone는 nn.Module로 정의된 class지만 out_channels라는 맴버변수 있다. 
print(type(backbone), out_channels)
# 3. test
backbone = torchvision.models.mobilenet_v2(pretrained=True).features
print(type(backbone)) # <class 'torch.nn.modules.container.Sequential'>
# backbone.out_channels  # 에러발생!!
backbone.junhaJJang  = 1111 # 이렇게 정의를 해주면?
backbone.junhaJJang # 이거는 사용가능하다. 
class junha:
    def __init__(self,a,b):
        self.a=a
        self.b=b
    def add(self,c,d):
        return self.a + self.b + c + d

object = junha(1,2)
dir(object)   # 'a', 'add', 'b'
object.e = 10
dir(object)   # 'a', 'add', 'b', 'e'
pass
object.f = 11

object.junhafuntion = lambda x,y:  x * y
print( object.junhafuntion(2,3) )
object.junhafuntion = lambda x,y: self.a * x * y
# print( object.junhafuntion(2,3) ) -> 에러발생!!
object.junhafuntion = lambda x,y, object_: x * y * object_.a
object.junhafuntion(1,2,object)

11.2 self로 정의한 변수만이 클래스의 attribute (맴버변수)로 인식한다

class junha():
    def __init__(self,a,b):
        self.a = a
        self.b = b
        hihi = 111 # 이건 단지 함수내 변수 일 뿐이다.
        self.hiii = 111
    def add():
        return self.a + self.b
    
ob = junha(1,2)

>>> ob.hihi 
    >>> # 에러발생!!  no attribute 'hihi'!!
>>> ob.hiii 
    >>> # 111로 정확하게 인식!

12. 상속과 __init__, super

  • maskrcnn.py 여기서 공부하면 좋을 코드를 가져왔다.
  • https://junha1125.github.io/docker-git-pytorch/2020-09-04-BalloonMask/ 여기를 보면 super에 대한 작은 정리가 되어 있다.
  • 좀더 자세한 설명은 여기를 참고 한다. https://leemoney93.tistory.com/37
try:
    class MaskRCNNPredictor(nn.Sequential):
        def __init__(self, in_channels, dim_reduced, num_classes):
            super(MaskRCNNPredictor, self).__init__(OrderedDict([
                ("conv5_mask", misc_nn_ops.ConvTranspose2d(in_channels, dim_reduced, 2, 2, 0)),
                ("relu", nn.ReLU(inplace=True)),
                ("mask_fcn_logits", misc_nn_ops.Conv2d(dim_reduced, num_classes, 1, 1, 0)),
            ]))

            for name, param in self.named_parameters():
                if "weight" in name:
                    nn.init.kaiming_normal_(param, mode="fan_out", nonlinearity="relu")
                # elif "bias" in name:
                #     nn.init.constant_(param, 0)
except:
    pass

이 코드를 유심히 유심히 보자. 여기서 공부해아할 것은 2개이다.

  1. nn.Sequential 를 상속한다.
  2. super().__init__(*parameters)
  3. OrderedDict 라는 함수를 사용한다.
  4. super(MaskRCNNPredictor, self) == super() ??

하나하나 알아보자.

  1. nn.Sequential는 Layer를 담는 Containers역할을 하는 하나의 Class이다. __init__ 말고도 다른 매소드 함수가 구현되어 있다. 그 메소드 함수들은 __init__에서 정의한 맴버변수를 사용할 것이다. nn.Sequential 클래스로 만든 객체 자체에 맴버변수가 정의 되어 있어야 한다.
    • nn.Sequential documentary 에서 볼 수 있는 것 처럼, segquential에는 ordered dict도 input 매개변수로 들어갈 수 있다.
  2. super().__init__(*parameters) 이것이 바로 위의 1번이 잘 동작되도록 만드는 코드이다. nn.Sequential내부의 다른 맴버함수들을 (클래스의 맴버변수가 잘 정의 된 상태에서) 문제 없이 잘 사용하기 위해서 해주는 작업니다.
  3. 아래의 코드 처럼
    • d = dir(); 라고 사용하면 d라는 dictionary 변수가 하나 정의 되는 것이다.
    • dir_valable = OrderedDict()를 하면 OrderedDict 변수가 하나 정의 되는 것이다.
    • dir과 OrderedDict는 거의 똑같은 동작을 하는 클래스이지만, OrderedDict는 값이 들어온 순서를 더 정확하게 기억해 놓는다.
    • 그리고 OrderedDict()내부에 [*(keyname, value)]를 적어 놓는 생성자를 아래에 사용한 것이다. OrderedDict Initialization, constructor에 대한 문서
  4. super자리에 코드들이 쫘르르륵 들어간다고 생각하라.(마치 해더파일에 있는 함수의 내용이 링크에 의해서 쫘르르 코드가 옮겨 들어가듯)
from collections import OrderedDict

dir_valable = OrderedDict([
                ("conv5_mask", 1),
                ("relu",2),
                ("mask_fcn_logits", 3),
            ])
dir_valable, list(dir_valable.keys()), (dir_valable.values())
(OrderedDict([('conv5_mask', 1), ('relu', 2), ('mask_fcn_logits', 3)]),
 ['conv5_mask', 'relu', 'mask_fcn_logits'],
 odict_values([1, 2, 3]))

13. import와 package

  • 공부하던 자료 : /tutoPytorch/5.torchvision_finetuning_instance_segmentation.ipynb
  • 이 파일을 공부하면서 생긴 궁금증을 아래와 같이 나열해 해결해나간다.
  • Torch Git 내부의 document1 : mask_rcnn.py, document2 : fast_rcnn.py 가능하면 꼭 열어볼 것을 추천
  1. model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True)로 정의한 model에서, type(model.box_predictor)를 하면 왜 없는 모듈이라고 뜰까??
    • 111. mask_rcnn에 init가 정의되므로, 자식함수의 함수 오버라이딩이 발생한다. 222. 따라서 fast_cnn의 init의 내용은 전부 무시된다. 333. fast_cnn에서는 box_predictor가 fast_crnn_box_predictor로 정의가 되지만, mask_rcnn에서는 이 내용이 적혀 있지 않으므로, box_predictor로 정의된 맴버변수는 없다.
    • 위와 같은 개소리가 아니라… no attribute라고 뜨는 이유는… self.box_predictor 라고 정의된게 아니라서!!! 으그…. 유일한 맴버변수는 roi_heads 뿐이었다ㅠㅠ 다른것은 그냥 좆밥들…. (큰 목차 11-2 내용 참조)
    • super 덕분에, fast_rcnn의 init 내용이 mask_rcnn의 init에 전부 그대로 들어간다!!! super자리에 코드들이 쫘르르륵 들어간다고 생각하라.(마치 해더파일에 있는 함수의 내용이 링크에 의해서 쫘르르 코드가 옮겨 들어가듯)
    • 따라서 이와 같이 접근해야 한다.
       >>> type(model.roi_heads.box_predictor)
       torchvision.models.detection.faster_rcnn.FastRCNNPredictor
       >>> type(model.roi_heads.box_predictor.bbox_pred )
       torch.nn.modules.linear.Linear
      
  2. 내가 여기서 신기하다고 생각하는 것은 이거다 : mask_rcnn.py 파일에는 FastRCNNPredictor를 import내용이 전혀없다. 그럼에도 불구하고… from .faster_rcnn import FasterRCNN 를 호출했다는 이유만으로 FastRCNNPredictor가 Mask_crnn의 init의 super에 의해서 호출된다. 이게 가능한 이유가 뭘까??
    • 이 코드가 문제 없이 구동 되는 이유가 뭘까?
        import torchvision
        model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True) # 이거를 그대로 부르면 num_classes = 91 이다. 
        type(model.roi_heads.box_predictor)
              
        >>> torchvision.models.detection.faster_rcnn.FastRCNNPredictor # (에러 안남)
      
    • 이것에 대해서는 다음과 같은 구조로 실험을 해보면 쉽게 이해할 수 있다. ```python
      • init.py
      • classes1.py
        • class junha1 여기서 junha2에 의해 정의된 객체를 맴버변수로 가지고 있기.
        • class junha2
      • classes2.py from .classes1 import junha1 junha1을 사용한 객체 생성 이 객체(junha1)의 junha2에 의해 정의된 맴버변수를 호출하면 어찌 될까?

      나의 상식과 다르게, 에러가 나지 않는다!!! ```

    • 결론 :
      • classes2.py에서 from .classes1 import junha2를 해주지 않아도 된다.
      • 다른 파일의 class, fun이든 import를 하면, 그 class 내부에 맴버변수나 맴버함수에서 사용되는, (다른 파일의) 다른 class의 객체는 무리 없이 사용가능하다.
      • 따라서 User는 내가 원하는 클래스, 함수만 import하면 그 내부에 속한 외부 클래스, fun에 대한 import는 신경쓰지 않아도 된다.
  3. A파일에서 from B파일 import B함수, Bclass 를 해놓았다면, C파일에서 form A파일 import B함수, Bclass 가능!
    • 참고 git line
    • 5.torchvision_finetuning_instance_segmentation.ipynb 코드 내부
        from torchvision.models.detection.rpn import AnchorGenerator 
        from torchvision.models.detection.anchor_utils import AnchorGenerator 
        # torchvision 0.5.0에서는 rpn.py에 import AnchorGenerator 정의
        # torchvision 0.1.5에서는 anchor_utils.py에 import AnchorGenerator 정의
      
    • 하지만 torchvision 0.1.5에서도 from torchvision.models.detection.rpn import AnchorGenerator를 해도 아주 잘 된다.
    • 왜냐하면, rpn.py에서 아래와 같이 정의 되어 있기 때문이다.
        # Import AnchorGenerator to keep compatibility.
        from .anchor_utils import AnchorGenerator
      

14. asset, unittest, logging, debudding

1. assert

  1. 파이썬은 동적 특성으로 인해 애플리케이션 대부분에 있어 디버깅보다 테스팅이 매우 중요하다.
  2. assert <표현식> [, '진단 메시지']
  3. 여러개의 assert를 확인하기 위해서 import unittest 를 한 test파일을 만드는 방법도 있다.
    1. test_filename.py를 만든다
    2. 그 파일 내부에 import unittest 하다.
    3. unittest.TestCase룰 상속하는 class를 만든다.
    4. unittest 클래스의 맴버함수로써 self.assetEqual()를 사용해 내가 만든 class를 test해볼 수 있다.
  4. 위와 같이 복잡하게 self.assetEqual()같은 맴버함수를 사용하지 않고, 직관적으로 asset만으로 test할 수 있는 pytest와 같으 모듈도 존재한다.
  5. 나중에 pytest를 구글링해서 찾아서 공부해보자.
a = 4
assert a == 4
# assert a != 4 , 'a shoud be 4'

2. logging

  • 과거 내가 만든 내용을 참고해서 다시 공부해보자.Blog logging Link : 다시 보니까.. 너무 대충 만듬 감이 있다. 그래서 아주 기초만 다시 공부해보자. 아래 문서도 그리 많은 내용을 담고 있진 않다.
  • logging 기초 문서
    1. 아래와 같은 log객체의 함수를 하용해서 메세지를 발행한다.
       # 코드 중간에 이런거 넣으면 된다
       logger.debug("debug 하고 싶은 내용 %s", str)
       logger.info("info하고 싶은 내용")
       logger.warning("warning해주고 싶은 내용")
       logger.error("error 내용")
       logger.critical("critical출력 하고 싶은 내용")
       log.critical(message [, args])
      
    2. 이는 메세지의 심각도 수준이 각기 다르기 때문이다. debug가 가장 낮은 심각도 critical이 가장 심각한 심각도를 의미한다.
    3. try, except문이 있다면, except문 내부에 위와 같은 log메세지 발행을 위한 코드를 넣어주면 된다.

3. debugging


15. python decorator 기본만 알기

  • decorator 란? 함수 앞뒤에 들어가야할 내용을 자동으로 넣어주는 매크로
  • 참조 reference
  • Python 으로 작성된 Opensource 의 코드들을 보다 보면, 아래와 같이 @ 로 시작하는 구문 들을 볼 수 있다.
  • 대상 함수를 wrapping 하고, 이 wrapping 된 함수의 앞뒤에 추가적으로 꾸며질 구문들을 decorator로 정의한다. 정의한 내용을 바꾸면 손쉽게 재사용이 가능하다.


  • decorator 정의 하는 방법 1 : def 사용
    1. 함수의 구조는 다음과 같다.
           def dec_functionName(func):
               def decorated():
                   ~~ 함수 이전에 실행되야하는 구문
                   ~~
                   func()  # 위에 매개변수로 들어간다.
                   ~~ 함수 이후에 실행되야하는 구문
                   ~~
                   return decorated
      
    2. 그리고 원하는 함수(위의 func의 인자로 들어감) 위에 @dec_functionName 를 적어주면 된다.
    3. 즉! decorator는 원래 작업의 앞 뒤에 추가적인 작업을 손쉽게 사용 가능하도록 도와주는 역할을 한다.
  • decorator 정의 하는 방법 2 : class 사용
    1. class의 call 맴버함수를 다음과 같이 정의한다.
      class class_for_decorator:
          def __init__(self, func):
                  self.func = func
          def __call__(self, *args, **kwargs):
                  ~~ 함수 이전에 실행되야하는 구문
                  ~~
                  self.func(*args, **kwargs)
                  ~~ 함수 이후에 실행되야하는 구문
                  ~~
      
    2. 그리고 원하는 함수(위의 func의 인자로 들어감) 위에 @class_for_decorator 를 적어주면 된다.

16. python 주의 할점

  1. self.variable, variable 분별하기
    • 아래의 코드를 살펴보자.
        class PennFudanDataset(Dataset):
            def __init__(self, root, transforms):
                self.root = os.path.join(root,"data_for_5","PennFudanPed")
                self.transforms = transforms
                # root = /home/sb020518/tutoPytorch
                self.imgs = list(sorted(os.listdir(os.path.join(self.root,"PNGImages"))))
      
    • self.root와 root는 완전히 다른 객체이다. 따라서 분리해서 생각해야한다.
    • 여기서 코딩 에러가 많이 나오니 주의하자.

17. __call__? + T.Compose(transforms) VS transforms.Compose?

  • 참고 링크
  • 5.torchvision_finetuning_instance_segmentation.ipynb 에서
    1. T.Compose(transforms) 를 적용한 transform
    2. transforms.Compose 를 적용한 traansforms_C 을 (내가 직접) 만들었다.
  • 그것을 이용해서 각각 dataset, dataset2를 만들었다.
  • 그리고 dataloader에 dataset, dataset2를 넣고, next(iter())를 적용해본 결과
    1. dataset 으로는 잘 동작하는데,
    2. dataset2 으로는 잘 동작하지 않는다.
  • 맨 처음 T.Compose(transforms) 그리고 transforms.Compose 이 코드상의 차이가 무엇인지 살펴보자.
    1. T.Compose(transforms) :
    2. transforms.Compose :
  • 이건 나중에 필요할 때 공부하자…

18. torch와 numpy의 이미지 차원 차이

  • 4Classifier.ipynb 에 이런 코드가 있다.
      # torchvision.datasets.CIFAR10.__getitem__(index=4) 라고 사용하면 안되지. 객체 만들고 그 객체로 Attribute 함수 사용해라.
      image, target =trainset.__getitem__(index=144)
      # type(image), target, image.size()
      plt.imshow(np.transpose(image.numpy(),(1,2,0))) # 4Classifier.ipynb에 설명 있으니 참조
      plt.title(classes[target])
      plt.show()
    
  • image.numpy() 필수로 해줘야 한다.
  • np.transpose(image.numpy(),(1,2,0)) 를 왜 하는 걸까?
    • 중요! 만약 이미지를 어디선가 load해서 가져왔을때.
    • tensor에서는 (몇장 ,depth ,행, 열)
    • numpy에서는 (행, 열, depth, 몇장)
    • tensor에서는 (depth ,행, 열)
    • numpy에서는 (행, 열, depth)
    • 따라서 바꿔줘야 한다.
from google.colab import files
uploaded = files.upload()

Upload widget is only available when the cell has been executed in the current browser session. Please rerun this cell to enable.

Saving testimage.png to testimage.png
from matplotlib import pyplot as plt
from matplotlib.image import imread
import numpy as np
import os
img = plt.imread('./testimage.png')
tensor = torch.tensor(img)
type(img), img.shape, type(tensor), tensor.shape
(numpy.ndarray, (300, 300, 4), torch.Tensor, torch.Size([300, 300, 4]))

하지만 data를 행렬로 그대로 가져온다면 torch와 tensor의 shape는 동일하게 생각해도 좋다

a = [[[[1,2],

     [4,5],

     [7,8]],

     [[10,11],

     [13,14],

     [16,17]]], ##

     [[[1,2],

     [4,5],

     [7,8]],

     [[10,11],

     [13,14],

     [16,17]]], ##

     [[[1,2],

     [4,5],

     [7,8]],

     [[10,11],

     [13,14],

     [16,17]]], ##

     [[[1,2],

     [4,5],

     [7,8]],

     [[10,11],

     [13,14],

     [16,17]]], ##

     [[[1,2],

     [4,5],

     [7,8]],

     [[10,11],

     [13,14],

     [16,17]]]] ##

     

import torch

temp1 = torch.randint(1,100,(2,3,4))

t3 = torch.tensor(a)

temp1.shape

temp1



import numpy as np

temp2 = np.random.randint(1,100,(2,3,4))

t4 = np.array(a)


temp1.shape, temp2.shape, t3.shape, t4.shape
(torch.Size([2, 3, 4]), (2, 3, 4), torch.Size([5, 2, 3, 2]), (5, 2, 3, 2))

  • 여기서 부터는 6.Transfer Learning for Computer Vision Tuto 참조

19. torchvision.datasets.ImageFolder

  1. 5.torchvision_finetuning_instance_segmentation.ipynb를 참고하면, 내가 새로운 dataset을 위한 class를 어떻게 정의하고, __getitem__ 과 같은 함수를 어떻게 정의해야하는지 알 수 있다.

  2. ImageFolder 공식 문서 참고하면 좋다.

  3. 만약 나의 데이터가 다음과 같은 구조로 정리 되어 있다면, 이 모듈을 사용하면 된다.

        
     root/dog/xxx.png
        
     root/dog/xxy.png
        
     root/dog/xxz.png
    
    
    
     root/cat/123.png
        
     root/cat/nsdf3.png
        
     root/cat/asd932_.png
        
    
  4. torchvision.datasets.ImageFolder(root : str, transform : Optional[Callable] = None)

data_dir = 'data/hymenoptera_data'

image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),

                                          data_transforms[x])

                  for x in ['train', 'val']}

dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,

                                             shuffle=True, num_workers=4)

              for x in ['train', 'val']}

dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}

class_names = image_datasets['train'].classes



device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

20. torchvision.utils.make_grid

  • 참고 문서 : torchvision.utils.make_grid

  • 참고 파일 2개

    1. 4.tensorbord.ipynb

    2. 6.Transfer Learning for Computer Vision Tuto.ipynb

  • 예제 코드 1

  • 예제 코드 2 : 그냥 이거 항상 이용하기

        
          def imshow(inp, title=None):
        
              """Imshow for Tensor."""
        
              inp = inp.numpy().transpose((1, 2, 0))
        
              mean = np.array([0.485, 0.456, 0.406])
        
              std = np.array([0.229, 0.224, 0.225])
        
              inp = std * inp + mean
        
              inp = np.clip(inp, 0, 1)
        
              plt.imshow(inp)
        
              if title is not None:
        
                  plt.title(title)
        
              plt.pause(0.001)  # pause a bit so that plots are updated
        
          # Get a batch of training data
        
          inputs, classes = next(iter(dataloaders['train']))
    
    
    
          # Make a grid from batch
        
          out = torchvision.utils.make_grid(inputs)
    
    
    
          imshow(out, title=[class_names[x] for x in classes])
        
    

21. copy.deepcopy

  • reference : https://wikidocs.net/16038
  • python은 변수값이 메모리에 먼저 적히고, 객체가 그 메모리 위치를 기억하는 형태의 동적 언어인 것을 잊지 말자.
  • copy의 종류는 3가지가 있다고 생각하자. (1) shallow copy, (2) deep copy 가 아니라, (1) just shallow copy, (2) slicing shallow copy, (3)deep copy.
  • 내용 정리
    1. mutable
    2. 중요 파이썬 기본 함수
      • id(object) : 메모리 공간 번호
      • == : 서로 내용이 같은 값을 가지는 가?
      • is : 객체가 서로 같은 메모리 공간 번호를 가지나?
    3. shallow copy (just copy)
      • a = b
      • a is b » Ture
      • a == b » True
      • a[0] = ‘hi’ » b[0] = ‘hi’
    4. shallow copy (using slicing or copy.copy)
      • 사용법 : a = b[:] or a=copy.copy(b)
        • a is b » False (즉 b에 새로운 id 부여됨)
        • a == b » True
        • a[0] = ‘hi’ » b[0] != ‘hi’
        • 이처럼, a의 ‘원소’가 immutable이면 deepcopy라고 해도 무방하다. 즉 서로 영향없이 안전하다.
            import copy
            a = [1,2,3]
            b = copy.copy(a)
            print(a == b, a is b) >> True, False
            a[0] = 4
            print(b[0]) >> 1
          
      • 하지만!! a의 ‘원소’가 mutable이면 문제가 발생한다. ex) a = [[1,2],[3,4]]
        • a = b[:]
          • a is b » False, BUT!!!
          • a[0] is b[0] » True
        • a[0] 그 자체를 바꾸면 b[0]도 같이 바뀐다. ex)a[0].append(num), a[0].remove/pop(index), del a[0][2]
        • 하지만, a[0] = [1,5] 와 같이 재할당 하면, b[0]은 안바뀐다.
    5. deep copy
      • 그냥 모~~든게 새로 만들어 진다. mutale객체의 ‘원소’들 까지도.
      • b = copy.deepcopy(a)
      • a is b » False
      • a[0] is b[0] » False
      • a == b » True (초기에 서로 내용은 같을 수 있다.)

【Pytorch】Pytorch Tutorial 내용 핵심 정리

  • Pytorch Tutorial 내용을 핵심만 요약 정리 하였습니다.
  • 저 코드와, 한줄한줄 공부한 내용은 /sb_kookmin_googledrive/GCPcode/pytorch 에 있습니다.

1. pytorch document 순서 정리

  1. torch - create, indexing, Math Operation
  2. torch.Tensor - details on the above
  3. torch.autograd - backword, grad
  4. torch.nn - layer, loss
  5. torchvision - dataset
  6. torch.utils.data - Dataloader
  7. torch.optim
  8. torch.utils.tensorboard
  9. torchvision.transforms - data augm
  10. torchvision.models

3NeuralNetworks in 60min learn

  1. Numpy를 이용한 가중치 갱신해보기
    • Numpy 함수들을 이용해서 2층 affine Layer 구성하기
  2. torch.tensor를 사용해서 2층 layer 구성하기
    • Numpy와 거의 동일하지만 매소드 함수 이름이 가끔 다름
  3. Autograd
  4. 새로운 Layer, Function 정의하기
    • torch.clamp라는 함수를 사용하면, relu 처럼 동작 가능 + loss.backward할 때 backward알아서 처리 됨.
    • 하지만 직접 relu를 정의하면?? backward가 안된다.
    • torch.autograd.Function 상속하는 class를 만들어야 한다. (torch.autograd.Function)
  5. nn 모듈 - Sequential과 Module과 같은 container 존재
    • 정의 방법과 사용방법이 다르다.
    • 하지만 zero_grad(). backward(), parameters(), step() 사용법은 모두 같다.
    • 갱신은 param -= learning_rate * param.grd (간단한 고찰 있음)
  6. Optimiaer
    • 갱신은 Optimizer.step()!
  7. 같은 원리로, resnet을 만드는 건 쉽다.
    • model.foward 만 잘 손보면 된다.

4Classiffier.ipynb in 60min learn

  1. Data Load 하기
    • torchvision.transform
    • trainset = torchvision.datasets
    • torch.utils.data.DataLoader
  2. 신경망 정의하기
    • class (torch.nn.module)
    • __init__, forward
  3. Loss, Optimizer 정의
    • criterion/loss = torch.nn.LOSS_FUNC
    • optimizer = torch.optim.OPTIM_FUNC
  4. 신경망 학습 시키기
    • for epoch
      • for i, data in enumerate(trainloader) # data = [label, img]
        • optimizer.zero_grad()
        • outputs = net(inputs)
        • loss = criterion(outputs, labels)
        • loss.backward()
        • optimizer.step()
  5. Test하기
    • outputs = net(images)
    • with torch.no_grad():
      • for data in testloader:
        • outputs = net(images)
        • _, predicted = torch.max(outputs.data, 1)
        • correct += (predicted == labels).sum().item()
    • class별 accuracy 분석은 코드 참조
  6. 신경망 저장, load하기
    • torch.save # 신경망 저장, 변수 저장 모두 가능, .pt 파일
    • nn.module.state_dirt()
  7. GPU 사용하기
    • net.to(device)
    • data[0].to(device), data[1].to(device) # label, data

3.WhatIsTorch.nnReally.ipynb

깨달은점들

  • Torch basic operation 정리 해놓은 사이트
  • 그냥 단순 무식하게 함수 찾아서 공부하지 말자. 예제 코드를 보면서 그 코드에서 어떻게 사용되고 있는지를 보고, 공부하자. 예를 들어서, 지금 TensorDataset이 뭔지 모른다. 하지만 지금 알 필요는 없다. 나중에 Detection, Segmentation 코드 공부할 때, 나오면 깨달으면 된다.
  1. MNIST Data download
    • 새로운 모듈
      • from pathlib import Path = os.path
      • import requests = wegt역할
      • import pickle = File loading
      • import gzip = 압축 안 풀고 읽기
    • map(torch.tensor, *datas)
  2. tensor만 사용해서 신경망 구현
    • loss = -input[range(target.shape[0]), target].mean() # 배월 원소 특정 부분
    • preds = torch.argmax(preds_before, dim=1)
  3. Using torch.nn.functional
    • loss_func = F.cross_entropy
  4. Refactor using nn.Module
    • class Mnist_Logistic(nn.Module)
    • self.weights = nn.Parameter(torch.randn(784, 10)
    • for p in model.parameters():
  5. Refactor using nn.Linear
  6. Refactor using optim
  7. Refactor using Dataset
    • torch.utils.data.TensorDataset
  8. Refactor using DataLoader
    • train_ds = TensorDataset(x_train, y_train)
    • train_dl = DataLoader(train_ds, batch_size=bs)
    • for (xb, y) in train_dl:
  9. Add validation
    • model.eval()
    • with torch.no_grad(): valid_loss 출력해보기
  10. 지금까지 했던 것을 함수로 만들기!
    • for epoch in range(10):
      • model.train()
      • for xb, yb in train_dl:
      • model.eval()
      • with torch.no_grad():
  11. nn.linear말고, CNN 사용하기
    • def forward(self, xb):
      • xb = xb.view(-1, 1, 28, 28)
      • return xb.view(-1, xb.size(1))
  12. nn.Sequential
    • nn.Sequential에는 nn.Module을 상속하는 layer들이 들어가야 함. (Ex. nn.Conv2d, nn.ReLU() 등 init에서 사용하는 함수들)
  13. Wrapping DataLoader
    • 모델에서 데이터 전처리 하지 말고. 전처리한 데이터를 모델에 넣기 위해.
    • train_dl = WrappedDataLoader(train_dl, preprocess)
    • class WrappedDataLoader 구현
    • def __iter__(self): batches = iter(self.dl); for b in batches: yield (self.func(*b))
  14. Using GPU
    • model.to(dev)
    • Input data.to(dev)
    • 항상 이 2개!

4.tensorbord.ipynb ⭐

  1. DataLoader, Net, Loss, Optim - Define
  2. writer = torch.utils.tensorboard.SummaryWriter()
  3. DataLoader
    • DataLoader는 __iter__가 잘 정의된 하나의 단순 class일 뿐이다. -“3.what torch.nn”에서 WrappedDataLoader 도 참조
    • DataLoader사용 방법은 3가지 이다.
      1. for x,y in DataLoader:
      2. x, y = iter(DataLoader).next()
      3. x, y = next(iter(DataLoader))
      4. PS: return되는 type은 list[ x_torch.tensor_batch, y_torch.tensor_batch ] 이다.
  4. torch.utils.tensorboard.SummaryWriter()의 대표 매소드 함수
    • writer.add_image(“title=tag”,img_grid) : input img_grid 보기
      • img_grid = torchvision.utils.make_grid( torch.tensor( 몇장, depth, w, h) ) : ‘몇장’ 에 대해서 grid_image를 만들어 tensor로 뱉어줌.(torch_module_research.ipynb 꼭 참조)
    • writer.add_graph(model,input_data) : model Architecture 보기
    • writer.add_embedding() : 고차원 Data 3차원으로 Visualization 하기
  5. Train
    • torch.max(arr, dim= 제거할 차원)
    • np.squeeze(np.arry) : shape에서 1은 다 없애 버린다. 2차원으로 감지되는 행렬을, 1차원으로 바꿔주는 역할도 한다.
    • torch.shape, np.shape : if 2차원이라고 감지되고 있다면, (1,4)와 (4,1)은 완전히 다른거다.
    • torch.nn.functional.softmax(input, dim=None) : Ex) dim=1 일 때 arr[1,:,2] = 1차원! 이 1차원 백터에 대한 모든 원소 softmax
    • 학습 도중 writer.add_scalar, writer.add_figure
        for epoch in range(2):  
            for i, data in enumerate(trainloader, 0):
                if i % 1000 == 0:
                    writer.add_scalar("title=tag", scalar_value, global_step) - Loss plot
                    writer.add_figure
      
  6. Test
    • torch.cat : concatenation
    • torch.stack : list to tensor
    • 각 class에 대한 precision-recall curve 그리기
      • writer.add_pr_curve(class이름, TrueOrFalse, PositiveOrNagative)

5.torchvision_finetuning_instance_segmentation.ipynb

  • 6.transfer_learning_tutorial.ipynb를 먼저 공부하고, 여기 보는게 낫다.
  1. 새로운 Dataset 정의하는 방법
    • torch.utils.data.Dataset을 상속하는 클래스.
    • __len__ and __getitem__ 정의하기
    • __getitem__ (self, idx) 은 [image, target]을 return해야한다.
    • 자세한 내용은 파일 참조
  2. Dataset을 새로 정의하는 Class 만들기
    • os.path.join, os.listdir
    • target[“masks”]를 정의하기 위한 변수 만들기
      • broadcastion 적용 : masks = (mask == obj_ids[:, None, None])
  3. torchvision.models를 사용한 model 정의하기
    • 아래의 내용은 필요할 때! Tuto 코드 & Torch Git 코드 꼭 봐야 함.
      1. torch Git, torchvision Git의 함수나 클래스 호출하는 방법 (헷갈리면 읽어보기!)
      2. model의 마지막 단에 나오는 class 갯수만 바꾸고 싶을 때.
      3. model의 class갯수와 backbone network를 모두 바꾸고 싶을 때
      4. 2번 방법으로 get_model_instance_segmentation함수 정의하기.
  4. train과 evaluation 하기
    1. dataset = PennFudanDataset(위에서 내가 만든 클래스)

    2. 하나의 데이터를, train set, validation set으로 나누는 방법
       indices = torch.randperm(len(dataset)).tolist()
       dataset = torch.utils.data.Subset(dataset, indices[:-50])
       dataset_test = torch.utils.data.Subset(dataset_test, indices[-50:])
      
    3. data_loader = torch.utils.data.DataLoader(dataset, batch_size=2 … )

    4. model.to(device)

    5. optimizer정의 후 lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer …)

      • optimizer.step,() 후 lr_scheduler.step() 또한 해줘야 함.
    6. epoch 돌면서 Git의 vision.reference.detection.engine의 train_one_epoch, evalate 사용해서 log 출력

6.transfer_learning_tutorial.ipynb ⭐

  1. Import Modules, Dataloader Define
    • datasets.ImageFolder(root, transforms)
    • dictionary구조를 이용한, datasets, dataloaders 정의 -Ex) dataloaders[‘train’], dataloaders[‘test’]
  2. dataloader가 잘 정의 되었나 확인

    • torchvision.utils.make_grid 를 완벽하게 사용하는 방법 - imshow 함수 정의(np.transpose, 정규화, np.clip, show)
  3. Train과 Validation 전체를 하는 함수 정의

    • def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
      • return model.load_state_dict(best_model_wts)
    • best_model_wts = copy.deepcopy(model.state_dict())
    • time_elapsed = time.time() - since
    • 전체 순서 정리(원본은 ipynb 파일 참조)
      image
  4. Define Function (visualizing the model predictions)
    • def visualize_model(model, num_images=6):
      • ax = plt.subplot(num_images//2 , 2, images_so_far )
  5. model 정의하고, Train 및 validation 해보기
    1. Finetuning the conv_Net
      • 직접 torch git 에서 전체 코드를 꼭 봐야 함.
      • 요약
          model_ft = models.resnet18(pretrained=True)
          model_ft.fc = nn.Linear(num_in_features, 2)  
          model_ft = train_model(model_ft, criterion, optimizer_ft, ...)
          visualize_model(model_ft)
        
    2. Conv_Net as fixed feature extractor
      • 요약
          model_conv = torchvision.models.resnet18(pretrained=True)
          for param in model_conv.parameters():
              param.requires_grad = False
          num_ftrs = model_conv.fc.in_features
          model_conv.fc = nn.Linear(num_ftrs, 2)
          model_conv = train_model(model_conv, criterion, optimizer_ft, ...)
          visualize_model(model_conv)
        

【LinearAlgebra】선형대수 정리 2 (한글강의)

쑤튜브 선형대수 강의내용 정리 24강~44강

youtube 강의 링크 : 쓔튜브 선형대수 강의 링크

선형 결합과 선형독립

  • 24강 선형결합(Linear combination)과 생성(Span)
    • 데카르트 좌표계(2차원 직교 좌표계) : 하지만, 좌표계는 꼭 직교(직각)이어야만 하는 것은 아니다. 평행이 아닌 두 직선으로 좌표계를 표현할 수도 있다.
    • 3차원 이상의 좌표계를 표한하려고 할때, 주어진 백터 n개가 n차원 좌표계의 좌표축이 될 수 있는지 없는지를 판단하는 것이, 선형독립 판단이다.
    • Linear combination (선형 결합) : v1,v2,v3의 각각의 스칼라곱의 합에 의해서 v를 표현할 수 있다면, v를 v1,v2,v3의 선형결합이다. 라고 한다. Ex) v = a*v1+ b*v2 + c*v3
    • Span(v1, v2, v3, v4, v5 … )이란 v1, v2, v3, v4, v5 …이 만들 수 n차원 공간을 말한다. 백터들이 서로 독립이면 n공간 그대로 가진다. 하지만 종속이면 n미만의 공간이다.
  • 25강 선형독립(linearly independent)
    • 선형 독립의 정의
    • image-20201120172426393
    • 영백터는 모든 백터들과 독립이 아니다. (위의 정의에 그대로 대입해서 생각해보기)
    • 선형독립의 집합은 공집합을 제외한 모든 부분집합은 선형독립 집합이다.
    • 3차원 열백터 4개에 대해서, 3x4행렬의 확장행렬을 만들고, 왼쪽 3x3 블락에 대해서 기약행사다리꼴 모양으로 만들어준다.(기양행사다리꼴로 구하는 해는 c1, c2, c3이다.) 이때 왼쪽 3x1의 값이 0이 아니라면 선형종속이다. (consisitent) 반대로 왼쪽 3x1의 값이 0이라면 선형독립이다.
    • n차원 열백터 n개를 묶은 n x n 행렬의 역행렬이 존재한다 = 그 행렬의 기약행사다리꼴 단위행렬 이다. = n차원 열백터 n개는 서로 독립니다.
    • 선형 독립 판별법 : 동차 연립 선형 방정식(이전 강의 참조)이 자명해만을 가지면, 독립이다. 즉! 열백터로 만든 행렬이 가역행렬이면, 그 열 백터들은 독립이다.
    • 그 열백터 n개로 n차원 좌표계를 표현할 수 있다. Span(v1, v2, v3, v4, …vn ) = R^(n) 이다.
    • image-20201120173335391
  • 26강, 27강 해집합의 성질
    • column space, row space : 행렬을 열 백터, 행 백터의 관점으로 봤을 때, 만들수 이는 span(A) 차원의 공간
    • A의 열백터가 선형독립이면 A는 가역행렬이다. 그렇다면, transe(A)의 행백터가 선형독립이다. A가 가역행렬이면 transe(A)도 가역행렬이다. 따라서 B의 행백터가 선형독립이면, B는 가역행렬이다.
    • 행렬 A의 열백터가 선형독립이면, 열백터의 일차 계수 선형결합으로 span(A)차원 백터 V가 있을 때, 그 일차 계수들(x1,x2,x3,x4…) 는 유일하다. AX = V -> X = inverse(A) x V 는 유일하므로.
    • AX = 0가 자명해 만을 가지면 A의 열백터는 선형독립니다. = transe(A)도 가역이다. A의 행백터도 선형독립이다.

LU decomposition

  • 29강 LU decomposition
    • AX = b에서 X를 구하는 방법은, 확장행렬 변환후 기약형사다리꼴로 바꾸는 방법이 있다. 하지만 다른 좋은 방법은 없을까?
    • 대각 행렬 : 대각선의 성분을 제외한 모든 부분이 0인 행렬. 대각행렬은 가역행렬이다. 대각행렬의 역행렬은 대각 성분을 모두 역수 취해준 행렬이다. 하지만 대각 성분 중 하나라도 0이 존재한다면 역수를 취하는 게 불가능하다. 따라서 대각행렬의 대각 성분 중 하나라도 0이 존재하면 비가역행렬이다.
    • 삼각행렬 : 대각성분을 기준으로 위(Lower) or 아래(Upper)가 모두 0인 행렬이다. 대각 행렬은 삼각행렬의 한 원소이다. 이 삼각행렬의 대각성분 중 0이 존재하지 않는다면, 가오스조던 소거법에 의해서 (forward, backward 둘 중 하나만 해서) 기약형사다리꼴로 바꿀 수 있다. 즉 가역행렬이다.
    • A = LxU (Lower triangular matrix) x (Upper triangular matrix)
    • image-20210106160928953
  • 30강, 31강 LU분해의 이론적인 근거와 계산법
    • 가우스 소거법(forward)을 시행할 때 사용되는 모든 기본행렬은 항상 Lower triangular matrix(하삼각행렬)이다. (행교환 제외. 행교환 기본행렬은 하삼각행렬이 아니다.)
    • 하삼각행렬꼴의 기본행렬의 역행렬은 하삼각행렬이다.
      • image-20210106161532372
    • 하삼각행렬 x 하삼각행렬 = 하삼각행렬 이다.
    • 위의 3가지 이론을 근거로 아래와 같이 표현할 수 있다 . 여기서 A에 대한 가오스 소거법(forward)과정은 Ek… E2 E1 (기본행렬 곱)이라고 표현할 수 있다.
      • image-20210106162215984
    • 따라서 LU를 구하는 방법은 아래와 같다.
      1. A에 대한 [가오스 소거법을 모아놓은 기본행렬들(행교환 제외)]을 찾는다.
      2. (그 기본행렬들의 곱) x A = U이다. U를 구했다.
      3. inverse(그 기본행렬들의 곱) = L이다. L을 구했다.
    • 하지만! LU분해를 해서 나오는 L,U는 유일하지 않다. 여러개가 나올 수 있다.
  • 32강 PLU분해
    • A에 대한 [가오스 소거법을 모아놓은 기본행렬들]을 찾을 때 행교환이 꼭 필요하다면 어떡하지??
    • 그렇다면! A에서 필요한 [행교환 기본행렬들(!= 하삼각행렬)]을 모두 찾아놓고, 그것들의 곱을 P라고 하면 된다.

Determinant (33강~39강)

  • 33강 행렬식,판별식
    • 2차 행렬의 판별식 공식을 구하는 방법
    • 3차 행렬의 판별식 공식을 구하는 방법(크래머의 공식) -> 동영상 참조
    • 4차 행렬의 판별식 공식을 구하는 방법
  • 특수한 경우의 determinant
    • 대각행렬, 삼각행렬의 determinant = 대각원소의 곱이다.
    • 영행, 영열을 포함하는 행렬의 determinant는 0이다.
  • 나머지 강의는 나중에 필요하면 보자.

Eigen value & Eigen vector

  • 40강 고유값과 고유벡터
    • 관점(좌표축)을 달리해서 보이지 않던 것을 찾아보자.
    • Ax = λx 이때, λ = Eigen value, x = Eigen vector A = invertible
    • n개의 고유백터는 서로 독립이다. 그리고! n개의 고유백터는 서로 orthogonal (백터의 내적은 0)하다.
  • 41강, 42강 특성방정식 (Characteristic Equation)
    • Ax = λx -> (A-λI)x = 0, 이때 det(λI-A) = |(λI-A)|를 특성 방정식이라고 한다.
    • 그리고 이 특성방정식의 해(λ)들이 고유값들(λ)이다.
    • (A가 n차 정사각행렬일때) 특성방정식의 해가 n개 이면, 선형독립인 고유백터 n개를 찾아낼 수 있다. (증명은 동영상 참조 굳이 알 필요 없음)
  • 43강, 44강 특수한 행렬들의 고유값
    • 대각행렬 : 대각원소가 결국 고유값이다.
    • 삼각행렬 : 대각원소가 결국 고유값이다.
    • nxn 행렬 A의 고유값을 λ1, λ2, λ3 — λn 이라 하면, 아래와 같이 정의할 수 있다. (증명은 43강44강 참조)
      • det(A) = λ1 x λ2 x λ3 x — x λn
      • trace(A) 대각합 = λ1 + λ2 + λ3 + — + λn

【Python】Convert Images(PNGs,JPGs) to PDF using Python

In this short guide, you’ll see how to convert images to PDF using Python

In this short guide, you’ll see how to convert images to PDF using Python

reference : https://datatofish.com/images-to-pdf-python/

PNG,JPG-To-PDF-Python

PNG,JPG-To-PDF Python Code

Precaution

  1. The number of images must be 100 less.
  2. The index must be written at the end of the file name.
    • Ex) firstimage1.png, firstimage2.png, firstimage3.png …. firstimage99.png
    • Ex) img1.jpg, img2.jpg, img3.jpg …. img80.jpg

How to use

  1. Run python code “png2pdf.py” with VScode
  2. Click “Select First File”
  3. Check print output
  4. Click “Convert to PDF”
  5. Input PDF file name
  6. Check print ouput

img

Python Code

from PIL import Image
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
from os import listdir
from os.path import isfile, join
images_opened = []
root= tk.Tk()

canvas1 = tk.Canvas(root, width = 300, height = 300, bg = 'white', relief = 'raised')
canvas1.pack()

label1 = tk.Label(root, text='PNGs to PDF', bg = 'white')
label1.config(font=('helvetica', 20))
canvas1.create_window(150, 60, window=label1)

def getFile ():
    global images_opened
    images_opened = []
    import_file_path = filedialog.askopenfilename()
    slice_index = [pos for pos, char in enumerate(import_file_path) if char == '/']
    dir_path = import_file_path[:slice_index[-1]]
    imgs = [f for f in listdir(dir_path) if f.endswith('.png')]
    def getOrder(img):
        order = img[-6:-4] if img[-6:-4].isdigit() else img[-5]
        return int(order)
    imgs_tuple = [ (img,getOrder(img)) for img in imgs]
    imgs_tuple_SR = sorted(imgs_tuple, key=lambda t: t[1])
    imgs_path = [join(dir_path,file) for file, i in imgs_tuple_SR]
    
    for i in imgs_path:
        im_t = Image.open(i)
        images_opened.append(im_t.convert('RGB'))

    print(str(len(images_opened)) + " images were saved \nClick Convert to PDF button")
        
    
browseButton = tk.Button(text="Select First File", command=getFile, bg='green', fg='white', font=('helvetica', 12, 'bold'))
canvas1.create_window(150, 130, window=browseButton)

def convertToPdf ():
    global images_opened
    export_file_path = filedialog.asksaveasfilename(defaultextension='.pdf')
    images_opened[0].save(export_file_path,save_all=True, append_images=images_opened[1:])
    print("Saved pdf file completely ")

saveAsButton = tk.Button(text='Convert to PDF', command=convertToPdf, bg='green', fg='white', font=('helvetica', 12, 'bold'))
canvas1.create_window(150, 180, window=saveAsButton)

def exitApplication():
    MsgBox = tk.messagebox.askquestion ('Exit Application','Are you sure you want to exit the application',icon = 'warning')
    if MsgBox == 'yes':
       root.destroy()
     
exitButton = tk.Button (root, text='Exit Application',command=exitApplication, bg='brown', fg='white', font=('helvetica', 12, 'bold'))
canvas1.create_window(150, 230, window=exitButton)

root.mainloop()

Pagination


© All rights reserved By Junha Song.