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
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)
our module sequentially infers attention maps along two separate dimensions
the attention maps are multiplied to the input feature map for adaptive feature refinement (향상되어 정제된 feature)
lightweight and general module, it can be integrated into any CNN architectures
1. introduction
Recent Detectors
recent researches have mainly investigated depth, width(#channel), and cardinality(같은 형태의 빌딩 블록의 갯수).
VGGNet, ResNet, GoogLeNet has become deeper for rich representation(중요한 특징 표현력).
GoogLeNet and Wide ResNet(2016), width must be another important factor.
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.
significant visual attention papers
[16] A recurrent neural network for image generation
[17] Spatial transformer networks
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.
Contribution
Can be widely applied to boost representation power of CNNs
따라서 목차를 보고 ‘이런 내용이 있구나’하고 나중에 필요하면, 와서 듣자. 지금은 진짜 궁금한것만 듣자.
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. 실전 코딩 얼굴 인식
importsysimportcv2print(cv2.__version__)img=cv2.imread('cat.bmp')ifimgisNone:print('Image load failed!')sys.exit()cv2.namedWindow('image')cv2.imshow('image',img)cv2.waitKey()# 아무키나 누르면 window 종료
cv2.destroyAllWindows()
importmatplotlib.pyplotaspltimportcv2# 컬러 영상 출력
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 가져오기
importosfile_list=os.listdir('.\\images')img_files=[fileforfileinfile_listiffile.endswith('.jpg')]# 혹은
importglobimg_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=0whileTrue:img=cv2.imread(img_files[idx])ifimgisNone:print('Image load failed!')breakcv2.imshow('image',img)ifcv2.waitKey(1000)>=27:# 1초 지나면 False, ESC누루면 True
break# while 종료
# cv2.waitKey(1000) -> 1
# cv2.waitKey(1000) >= 0: 아무키나 누르면 0 초과의 수 return
idx+=1ifidx>=cnt:idx=0
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는 그레이스케일 타입의 이진 영상.
dst2 :
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 클래스 하나로 처리함
카메라 열기
index : 2대가 있으면 테스트 해봐서 0,1번 중 하나 이다. domain_offset_id는 무시하기(카메라를 Open하는 방법을 운영체제가 적절한 방법을 사용한다.)
importsysimportcvcap=cv2.VideoCapture()cap.open(0)# 혹은 위의 2줄 한줄로 cap = cv2.VideoCapture(0)
ifnotcap.isOpend()print('camera open failed!')sys.exit()whileTure:ret,frame=cap.read()ifnotret:# frame을 잘 받아 왔는가? # 가장 마지막 프레임에서 멈춘다
breakedge=cv2.Canny(frame,50,150)cv2.imshow('edge',edge)# 2개의 창이 뜬다!! figure 설정할 필요 없음
cv2.imshow('frame',frame)cv2.waitKey(20)==27:# ESC눌렀을떄
breakcap.release()# cap 객체 delete
cv2.destroyAllWindows()
동영상 열기
위의 코드에서 cap = cv2.VideoCapture(‘Video File Path’) 를 넣어주고 나머지는 위에랑 똑같이 사용하면 된다.
이미지 반전 : 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=30delay=round(1000/fps)# 프레임과 프레임 사이의 시간간격 (1000ms/30fps)
out=cv2.VideoWriter('output.avi',fourcc,30,(w,h))ifnotout.isOpened():print('File open failed!')cap.release()sys.exit()whileTrue:ret,frame=cap.read()ifnotret:breakinversed=~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)ifcv2.waitKey(delay)==27:# delay는 이와 같이 사용해도 좋다. 없어도 됨.
break
2-7장 - 키보드 이벤트 처리하기
cv2.waitKey(delay=None) -> retval
while True: 문을 계속 돌면서, 매 시간 마다 키보드 input이 없으면 필요없는 값을 return하고 while문에는 영향을 끼치지 않는다.
# 키보드에서 'i' 또는 'I' 키를 누르면 영상을 반전
importcv2img=cv2.imread('cat.bmp',cv2.IMREAD_GRAYSCALE)cv2.imshow('image',img)whileTrue:keycode=cv2.waitKey()ifkeycode==ord('i')orkeycode==ord('I'):img=~imgcv2.imshow('image',img)elifkeycode==27:breakcv2.destroyAllWindows()
2-8장 - 마우스 이벤트 처리하기
마우스 이벤트 콜백함수 등록 함수 : cv2.setMouseCallback(windowName, onMouse, param=None) -> None
마우스 이벤트 처리 함수(콜백 함수) 형식 : onMouse(event, x, y, flags, param) -> None
# 두 개의 동영상을 열어서 cap1, cap2로 지정
cap1=cv2.VideoCapture('video1.mp4')cap2=cv2.VideoCapture('video2.mp4')ifnotcap1.isOpened()ornotcap2.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번 동영상 복사
foriinrange(frame_cnt1-effect_frames):ret1,frame1=cap1.read()ifnotret1:print('frame read error!')sys.exit()out.write(frame1)print('.',end='')cv2.imshow('output',frame1)cv2.waitKey(delay)# 1번 동영상 뒷부분과 2번 동영상 앞부분을 합성
foriinrange(effect_frames):ret1,frame1=cap1.read()ret2,frame2=cap2.read()ifnotret1ornotret2:print('frame read error!')sys.exit()dx=int(w/effect_frames)*iframe=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번 동영상을 복사
foriinrange(effect_frames,frame_cnt2):ret2,frame2=cap2.read()ifnotret2: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
# 카툰 필터 카메라
importsysimportnumpyasnpimportcv2defcartoon_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)returndstdefpencil_sketch(img):gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)blr=cv2.GaussianBlur(gray,(0,0),3)dst=cv2.divide(gray,blr,scale=255)returndstcap=cv2.VideoCapture(0)ifnotcap.isOpened():print('video open failed!')sys.exit()cam_mode=0whileTrue:ret,frame=cap.read()ifnotret:breakifcam_mode==1:frame=cartoon_filter(frame)elifcam_mode==2:frame=pencil_sketch(frame)frame=cv2.cvtColor(frame,cv2.COLOR_GRAY2BGR)cv2.imshow('frame',frame)key=cv2.waitKey(1)ifkey==27:breakelifkey==ord(' '):cam_mode+=1ifcam_mode==3:cam_mode=0cap.release()cv2.destroyAllWindows()
chap5 - 기하학적 변환
수학적 공식은 ‘20년2학기/윤성민 교수님 컴퓨터 비전 수업 자료 참조’
cv2.warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None) -> dst
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개의 연립방정식으로 행렬로 표현하면 아래와 같다.
정리 :
일반화 (48강에서 증명)
(x1,x2 … xn)B = B의 기저백터들에 x1,x2,x3..xn의 계수로의 선형결합
예시
해석 : B를 기저로 하는 좌표값이 x1~xn 이라면, 그 좌표를 B’을 기저로하는 좌표값으로 바꾸면 어떤 좌표 y1~yn이 되는가? 에 대한 공식이다.
예제 :
(2,1)E는 E의 백터들에 2와 1의 계수로 선형결합 해준 백터 = v1 을 의미함.
48강 기저변환과 대각화(= EVD(Eigen Value Decomposition) 기초)
대각화 : P * A * inverse(P) = D’(대각행렬) -> A =inverse(P) * D’(대각행렬) * P
위의 일반화 공식과 고유백터&고유값을 이용해 대각화 공식을 찾아보자.
대각변환 : 축을 기준으로 상수배(확대/축소)하는 변환
에 대해서 자세히 알아보자. 동영상에서는 위의 기저변환 일반화 공식을 이용해서 아래의 대각화 공식을 정의하고 있다.
[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(기본 좌표계)]를 기준좌표계(기저)로 생각하는 선형변환이다.
고민을 많이 해야하므로 위의 내용을 이해하고 싶으면 강의를 다시 보자.
이 대각화 공식을 다음과 같이 증명하면 쉽게 이해 가능하다.
49강 대각화가능행렬과 그 성질들
대각화 가능한 행렬 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(행렬의 닮음)
두 행렬이 서로 닮음이면, 아래와 같은 많은 성질을 가진다.
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 차원)이다.
⭐ 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를 하는 것에 전혀 무리가 없는 것이다.
이것을 이용해서 pretrain할 때, cs231n-Transfer Learning을 참고하면 좋겠다. 나의 데이터량과 모델의 구조에 따라서 내가 어떤식으로 Transfer Learning을 진행해야하는지 나와있다.
아래에 공부하는 lufficc/SSD 또한 detectron2와 거의 유사한 구조를 가지고 있다. 따라서 lufficc/SSD를 적극적으로 공부해도 되겠다 (어차피 detectron2에서 SSD를 제공하지 않으므로)
하지만! mmdetection에서 SSD를 제공한다. 따라서 lufficc/SSD는 최대한 빠르게 넘어가고, mmdetection으로 넘어가는게 좋을 듯하다. mmdetection에서는 detection2보다 상대적으로 아주 많은 모델을 제공한다. 모델 비교는 아래의 링크에서 확인 가능 하다.
detectron2/projects를 보면 [DeepLab, DensePose, Panoptic-DeepLab, PointRend, TensorMask, TridentNet] 와 같은 읽기만 해도 멋진 Detector or Segmentation 모델, 논문이 있으니 이것들을 공부해도 좋을 듯 하다.
특히 mmdetection에 대해서는 나중에 추가적으로 더 공부.
1. Analysis of lufficc/SSD
독자적으로 사용하는 pypi 패키지가 2개 있다.
yacs : config파일을 다루기 쉽게, CN()이라는 자체적은 클래스를 제작해놓음. 아래와 깉이 디렉토리 구조로 내용을 담고 있다.
ssd/modeling에는 아래와 같은 신경망 구성 요소를 nn.module로 구현해놓은 파일이 있다.
anchors
backbone
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로 다시 다룰 예정
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')defvgg(cfg,pretrained=True):model=VGG(cfg)# 같은 파일에서 정의한 클래스
ifpretrained:model.init_from_pretrain(load_state_dict_from_url(model_urls['vgg']))returnmodel# ssd/modeling/backbone/__init__.py
defbuild_backbone(cfg):returnregistry.BACKBONES[cfg.MODEL.BACKBONE.NAME](cfg,cfg.MODEL.BACKBONE.PRETRAINED)
summary_writer=SummaryWriter(log_dir=os.path.join(cfg.OUTPUT_DIR,'tf_logs'))foriteration,(images,targets,_)inenumerate(data_loader,start_iter):loss_dict=model(images,targets=targets)loss=sum(lossforlossinloss_dict.values())optimizer.zero_grad()loss.backward()optimizer.step()scheduler.step()ifiteration%args.log_step==0:logger.info(# 현재 학습 상태 출력
summary_writer.add_scalar
MAX_ITER = ephch: 160000 정도로 설정되었지만, 그래도 아마 scheduler에 의해서 조기 학습 종료도 가능할 듯 싶다.
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)
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)
# 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)
# `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
# [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)
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 # 이거는 사용가능하다.
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 (맴버변수)로 인식한다
classjunha():def__init__(self,a,b):self.a=aself.b=bhihi=111# 이건 단지 함수내 변수 일 뿐이다.
self.hiii=111defadd():returnself.a+self.bob=junha(1,2)>>>ob.hihi>>># 에러발생!! no attribute 'hihi'!!
>>>ob.hiii>>># 111로 정확하게 인식!
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개이다.
nn.Sequential 를 상속한다.
super().__init__(*parameters)
OrderedDict 라는 함수를 사용한다.
super(MaskRCNNPredictor, self) == super() ??
하나하나 알아보자.
nn.Sequential는 Layer를 담는 Containers역할을 하는 하나의 Class이다. __init__ 말고도 다른 매소드 함수가 구현되어 있다. 그 메소드 함수들은 __init__에서 정의한 맴버변수를 사용할 것이다. nn.Sequential 클래스로 만든 객체 자체에 맴버변수가 정의 되어 있어야 한다.
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자리에 코드들이 쫘르르륵 들어간다고 생각하라.(마치 해더파일에 있는 함수의 내용이 링크에 의해서 쫘르르 코드가 옮겨 들어가듯)
내가 여기서 신기하다고 생각하는 것은 이거다 : mask_rcnn.py 파일에는 FastRCNNPredictor를 import내용이 전혀없다. 그럼에도 불구하고… from .faster_rcnn import FasterRCNN 를 호출했다는 이유만으로 FastRCNNPredictor가 Mask_crnn의 init의 super에 의해서 호출된다. 이게 가능한 이유가 뭘까??
이 코드가 문제 없이 구동 되는 이유가 뭘까?
importtorchvisionmodel=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는 신경쓰지 않아도 된다.
A파일에서 from B파일 import B함수, Bclass 를 해놓았다면, C파일에서 form A파일 import B함수, Bclass 가능!
# 코드 중간에 이런거 넣으면 된다
logger.debug("debug 하고 싶은 내용 %s",str)logger.info("info하고 싶은 내용")logger.warning("warning해주고 싶은 내용")logger.error("error 내용")logger.critical("critical출력 하고 싶은 내용")log.critical(message[,args])
이는 메세지의 심각도 수준이 각기 다르기 때문이다. debug가 가장 낮은 심각도 critical이 가장 심각한 심각도를 의미한다.
try, except문이 있다면, except문 내부에 위와 같은 log메세지 발행을 위한 코드를 넣어주면 된다.
3. debugging
-i 옵션 사용하기
python3 -i blah.py 와 같이 -i옵션을 사용해 실행한다.
터미널에 인터프리터(»>) 가 나타나면서, 충돌이후 여기저기 찔러보며 변숫값과 기타 상태를 확인할 수 있다.
5.torchvision_finetuning_instance_segmentation.ipynb 에서
T.Compose(transforms) 를 적용한 transform
transforms.Compose 를 적용한 traansforms_C 을 (내가 직접) 만들었다.
그것을 이용해서 각각 dataset, dataset2를 만들었다.
그리고 dataloader에 dataset, dataset2를 넣고, next(iter())를 적용해본 결과
dataset 으로는 잘 동작하는데,
dataset2 으로는 잘 동작하지 않는다.
맨 처음 T.Compose(transforms) 그리고 transforms.Compose 이 코드상의 차이가 무엇인지 살펴보자.
T.Compose(transforms) :
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()
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
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")
defimshow(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+meaninp=np.clip(inp,0,1)plt.imshow(inp)iftitleisnotNone: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]forxinclasses])
그냥 단순 무식하게 함수 찾아서 공부하지 말자. 예제 코드를 보면서 그 코드에서 어떻게 사용되고 있는지를 보고, 공부하자. 예를 들어서, 지금 TensorDataset이 뭔지 모른다. 하지만 지금 알 필요는 없다. 나중에 Detection, Segmentation 코드 공부할 때, 나오면 깨달으면 된다.
MNIST Data download
새로운 모듈
from pathlib import Path = os.path
import requests = wegt역할
import pickle = File loading
import gzip = 압축 안 풀고 읽기
map(torch.tensor, *datas)
tensor만 사용해서 신경망 구현
loss = -input[range(target.shape[0]), target].mean() # 배월 원소 특정 부분
preds = torch.argmax(preds_before, dim=1)
Using torch.nn.functional
loss_func = F.cross_entropy
Refactor using nn.Module
class Mnist_Logistic(nn.Module)
self.weights = nn.Parameter(torch.randn(784, 10)
for p in model.parameters():
Refactor using nn.Linear
Refactor using optim
Refactor using Dataset
torch.utils.data.TensorDataset
Refactor using DataLoader
train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs)
for (xb, y) in train_dl:
Add validation
model.eval()
with torch.no_grad(): valid_loss 출력해보기
지금까지 했던 것을 함수로 만들기!
for epoch in range(10):
model.train()
for xb, yb in train_dl:
model.eval()
with torch.no_grad():
nn.linear말고, CNN 사용하기
def forward(self, xb):
xb = xb.view(-1, 1, 28, 28)
return xb.view(-1, xb.size(1))
nn.Sequential
nn.Sequential에는 nn.Module을 상속하는 layer들이 들어가야 함. (Ex. nn.Conv2d, nn.ReLU() 등 init에서 사용하는 함수들)
데카르트 좌표계(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)
선형 독립의 정의
영백터는 모든 백터들과 독립이 아니다. (위의 정의에 그대로 대입해서 생각해보기)
선형독립의 집합은 공집합을 제외한 모든 부분집합은 선형독립 집합이다.
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) 이다.
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)
30강, 31강 LU분해의 이론적인 근거와 계산법
가우스 소거법(forward)을 시행할 때 사용되는 모든 기본행렬은 항상 Lower triangular matrix(하삼각행렬)이다. (행교환 제외. 행교환 기본행렬은 하삼각행렬이 아니다.)
하삼각행렬꼴의 기본행렬의 역행렬은 하삼각행렬이다.
하삼각행렬 x 하삼각행렬 = 하삼각행렬 이다.
위의 3가지 이론을 근거로 아래와 같이 표현할 수 있다 . 여기서 A에 대한 가오스 소거법(forward)과정은 Ek… E2 E1 (기본행렬 곱)이라고 표현할 수 있다.
따라서 LU를 구하는 방법은 아래와 같다.
A에 대한 [가오스 소거법을 모아놓은 기본행렬들(행교환 제외)]을 찾는다.
(그 기본행렬들의 곱) x A = U이다. U를 구했다.
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강 참조)
fromPILimportImageimporttkinterastkfromtkinterimportfiledialogfromtkinterimportmessageboxfromosimportlistdirfromos.pathimportisfile,joinimages_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)defgetFile():globalimages_openedimages_opened=[]import_file_path=filedialog.askopenfilename()slice_index=[posforpos,charinenumerate(import_file_path)ifchar=='/']dir_path=import_file_path[:slice_index[-1]]imgs=[fforfinlistdir(dir_path)iff.endswith('.png')]defgetOrder(img):order=img[-6:-4]ifimg[-6:-4].isdigit()elseimg[-5]returnint(order)imgs_tuple=[(img,getOrder(img))forimginimgs]imgs_tuple_SR=sorted(imgs_tuple,key=lambdat:t[1])imgs_path=[join(dir_path,file)forfile,iinimgs_tuple_SR]foriinimgs_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)defconvertToPdf():globalimages_openedexport_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)defexitApplication():MsgBox=tk.messagebox.askquestion('Exit Application','Are you sure you want to exit the application',icon='warning')ifMsgBox=='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()