Fourier Transform(푸리에 변환)의 이해와 활용

영상처리 2017.09.27 12:39

푸리에 변환(Fourier transform)에 대해서는 예전부터 한번 정리를 해야겠다고 생각만 했었는데 이번에 기회가 되어 글을 올립니다.


푸리에 변환(Fourier transform)은 신호처리, 음성, 통신 분야에서 뿐만 아니라 영상처리에서도 매우 중요한 개념으로 다양한 응용을 가지고 있습니다. 영상을 주파수 성분으로 변환하여 다양한 분석 및 처리를 할 수 있고 임의의 필터링 연산을 fft(fast Fourier transform)를 이용하여 고속으로 구현할 수도 있습니다. 그리고 푸리에 변환과 같은 근원적인 이론들은 특정 응용에 국한되지 않기 때문에 한번 알아두면 분야를 떠나서 두고두고 도움이 됩니다.


이 글에서는 푸리에 변환(Fourier transform)이 무엇이고 어디에 쓸 수 있는지, 그리고 어떻게 쓸 수 있는지 직관적 이해와 유용한 성질들, 영상처리 응용, 그리고 푸리에 변환(Fourier transform)을 실제 활용하는데 있어서 필요한 사항들을 최대한 직관적으로 정리하고자 합니다.


그동안 푸리에 변환(Fourier transform)에 대해 개인적으로 가지고 있었던 의문은 푸리에 변환을 통해 얻어지는 스펙트럼과 페이즈(phase) 중 페이즈(phase)가 무엇인가? 그리고 푸리에 주파수 공간의 좌표값을 어떻게 해석할까입니다. 아마도 비슷한 의문을 가진 분들도 꽤 있을 것으로 생각됩니다. 이 글을 통해서 그러한 의문에 대한 답도 같이 다루게 됩니다.



1. 푸리에 변환(Fourier transform) - 직관적 이해


모든 공부의 시작은 핵심 개념을 정확히 이해하는데 있다. 그리고 그 이해는 가급적 직관적일수록 좋다.


푸리에 변환(Fourier transform)을 직관적으로 설명하면 푸리에 변환은 임의의 입력 신호를 다양한 주파수를 갖는 주기함수들의 합으로 분해하여 표현하는 것이다.


좀더 들어가면, 푸리에 변환에서 사용하는 주기함수는 sin, cos 삼각함수이며 푸리에 변환은 고주파부터 저주파까지 다양한 주파수 대역의 sin, cos 함수들로 원본 신호를 분해하는 것이다.


아래 그림(그림 1)의 예를 보자. 맨 앞의 붉은 색 신호는 입력 신호이고 뒤의 파란색 신호들은 푸리에 변환(Fourier transform)을 통해 얻어진 (원본 신호를 구성하는) 주기함수 성분들이다. 각각의 주기함수 성분들은 고유의 주파수(frequency)와 강도(amplitude)를 가지고 있으며 이들을 모두 합치면 원본 붉은색 신호가 된다.


그림 1. 푸리에 변환 (그림출처: 위키피디아)


여기서 입력 신호는 전파, 음성 신호 등과 같이 시간축(time)에 대해 정의된 신호일 수도 있고 이미지(image) 등과 같이 공간축에 대해 정의된 신호일 수도 있다. 통신 분야에서는 푸리에 변환(Fourier transform)을 time domain에서 frequency domain으로의 변환이라고 하고, 컴퓨터 비전(computer vision), 영상처리 쪽에서는 spatial domain에서 frequency domain으로의 변환이라고 부른다. 명칭이야 어쨌든 그 핵심은 입력 신호를 sin, cos의 주기성분으로 분해하는 것이다.


푸리에 변환(Fourier transform)의 대단한 점은 입력 신호가 어떤 신호이든지 관계없이 임의의 입력 신호를 sin, cos 주기함수들의 합으로 항상 분해할 수 있다는 것이다. 그리고 그 과정을 수식으로 표현한 것이 푸리에 변환식이다.



2. 푸리에 변환(Fourier transform) - 수식적 이해


어떤 개념을 직관적으로 이해했다면 그 개념에 대한 수식적 이해는 그 개념을 한층 풍성하고 깊이있게 이해하게 해 준다.


푸리에 변환(Fourier transform)은 프랑스의 수학자 Joseph Fourier (1768 ~ 1830)가 제안한 방법으로서 수학사(해석학)의 역사가 새로 씌여질 정도로 대단한 발견이었다고 한다. 그 유명한 푸리에 변환의 수식은 다음과 같다.


, --- (1)


. --- (2)


여기서 j는 허수단위 , f(x)는 원본 입력 신호, ej2πux는 주파수 u인 주기함수 성분, F(u)는 해당 주기함수 성분의 계수(coefficient)를 나타낸다.


일단 식을 있는 그대로 해석하면 식 (1)은 입력신호 f(x)가 ej2πux들의 합으로 표현(분해)된다는 의미이다 (적분은 합한다는 의미를 갖는다). 그리고 식 (2)는 f(x)를 주기함수 성분으로 분해했을 때의 계수(coefficient) F(u)가 식 (2)로 주어진다는 의미이다. 앞서 그림 1과 연관해 보면 ej2πux는 f(x)를 구성하는 (파란색의 주파수 u인) 주기함수 성분들이고 F(u)는 해당 주기함수 성분의 강도(amplitude)를 나타낸다.


☞ 푸리에 변환에 대한 일반적인 설명 방식은 두번째 식 (2)를 푸리에 변환이라고 정의하고 첫번째 식 (1)을 푸리에 역변환(inverse Fourier transform)이라고 정의하는 것이다. 그리고 푸리에 역변환을 하면 다시 원래의 함수로 돌아온다고 한다. 하지만 이러한 기계적인 이해(푸리에 변환을 어디 하늘에서 뚝 떨어진 정의로만 받아들이는 것)는 푸리에 변환의 본질을 이해하는데 별 도움이 되지 않는다.


이제 식으로 좀더 들어가 보자. 일단, 식 자체는 푸리에 변환의 대단함에 비추어 매우 단순하다 (Simple is the best!!). 다만 한 가지 ej2πux의 의미만 이해하면 된다. 그리고 이를 위해서는 오일러 공식(Euler's formula)이 필요하다.


오일러 공식(Euler's formula)은 복소지수함수를 삼각함수로 변환할 수 있도록 하는 유명한 식이다.


 --- (3)


식 (3)은 증명 가능한 식이며 그 증명은 인터넷에서 어렵지 않게 찾을 수 있다. 어쨌든 오일러 공식을 이용하면 식 (1)의 ej2πux는 실수부가 cos(2πux), 허수부가 sin(2πux)인 주기함수임을 알 수 있다.


 --- (4)


여기서 cos(2πux), sin(2πux) 모두 주기(period)가 1/u, 주파수(frequency) u인 주기함수이므로 결국 ej2πux는 주파수 u인 정현파(sinusoidal wave)의 복소지수함수 표현임을 알 수 있다.

    • 주기: 파동이 한번 진동하는데 걸리는 시간, 또는 그 길이. sin(wx)의 주기는 2π/w 임.
    • 주파수: 1초 동안의 진동 횟수. 주파수와 주기는 서로 역수 관계 (주파수 = 1/주기)


☞ 정현파(sinusoidal wave)는 파형이 sin 또는 cos 함수인 파동(wave)을 말한다. 그런데, 여기서 왜 갑자기 복소수가 나오고 또 주기함수를 저렇게 표현하느냐고 따질 수 있다. 하지만 여기서는 그냥 복수지수함수는 정현파(sinusoidal wave)를 표현하는 방법 중 하나라는 정도로만 알아두자. 정현파 및 복수지수함수 표현에 대한 보다 자세한 내용은 AngeloYeo님의 페이저(phasor)에 대한 설명글을 참고하기 바란다.


이제 다시 원래의 식 (1), (2)로 돌아가 보자. 식 (1)은 함수 f(x)를 모든 가능한 주파수(u)의 주기함수들(ej2πux)의 일차결합으로 표현한 것이다. 그리고 그 일차결합 계수 F(u)는 식 (2)로 항상 주어질 수 있다는 것이 요지이다. 이와 같이 푸리에 변환식을 볼 수 있다면 푸리에 변환의 핵심을 이해한 것이다.


☞ 식 (1), (2)의 푸리에 변환(Fourier transform)식은 언뜻 보면 정의(definition)로 보이지만 사실은 증명해야 할 정리(theorem)이다. 즉, 식 (2)의 F(u)를 식 (1)에 대입하면 항상 f(x)가 나옴을 증명해야 한다. 이것이 증명되면 모든 임의의 신호함수는 항상 주기함수들의 일차결합으로 분해될 수 있음이 증명되는 것이다 (증명은 이곳 참조).


마지막으로, (증명은 아니지만) 왜 일차결합의 계수 F(u)가 식 (2)로 주어지는지를 선형대수학과 연관지어 직관적으로 이해해 보자. 식 (1)에서 ej2πux, u = 0, ±1, ±2, ...은 모든 신호를 생성할 수 있는 직교(orthogonal) 기저(basis) 함수들로 볼 수 있다 (편의상 u를 정수 범위로 표기했으나 u는 실수 전체 범위임). 그러면 입력 신호 f(x)를 이들 기저함수들로 분해했을 때의 계수 F(u)는 f(x)와 기저함수의 내적(dot product)으로 계산될 수 있다 (아래의 ☞선형대수학 관련 설명 참조). 식 (2)는 f(x)와 ej2πux의 함수 내적이기 때문에 그 결과는 f(x)를 ej2πux들로 분해했을 때의 계수가 된다. 따라서, F(u)가 식 (2)로 주어지는 이유가 설명이 되었다. 참고로, 식 (2)에서 j 앞에 -가 붙은 이유는 복소수에서의 내적은 어느 한쪽에 켤레(conjugate) 복소수를 취한 후 계산되기 때문이다.


☞ 선형대수학(linear algebra)에서는 어떤 벡터 공간을 생성할 수 있는 일차독립인 벡터들의 집합을 기저(basis)라고 한다. 만일 기저(basis) 벡터들이 v1, v2, ..., vn라 하면 이 벡터공간에 속하는 임의의 벡터 v는 v = a1v1 + a2v2 + ... + anvn (ai는 상수)와 같이 기저 벡터들의 일차결합으로 표현될 수 있다 (왜냐하면 vi들이 이 벡터공간의 모든 벡터들을 생성할 수 있으니까). 그런데 만일 기저벡터들이 서로 수직(vi·vj = 0)인 단위벡터라면 일차결합 계수 ai는 내적을 이용하여 ai = v·vi로 손쉽게 계산할 수 있다 (∵ v·vi = (a1v1 + ... + anvn)·vi = ai*(vi·vi) = ai). 어떤 벡터와 기저(basis) 벡터를 내적하면 이 벡터에 포함된 기저 성분의 계수가 얻어진다는 것은 선형대수학에서 매우 유용한 성질이다.


☞ F(u)가 식 (2)로 주어지는 이유에 대한 선형대수학적 설명은 개인적 이해 방식이라서 증명이 있거나 근거 문헌이 있는 내용은 아닙니다. 그냥 그런 식으로 이해할 수도 있구나 하고 참고만 하기 바랍니다. 정말 그런지 수학적으로 증명해 봐라 하면 골치아픕니다..



3. 이미지(영상신호)에서의 푸리에 변환(Fourier transform)


푸리에 변환(Fourier transform)을 영상처리에 적용하기 위해서는 이미지(영상신호)가 가지고 있는 몇 가지 차이점을 인지해야 한다. 먼저, 이미지는 2차원의(x축 방향의 변화와 y축 방향의 변화가 동시에 포함된) 신호이기 때문에 2차원에서 정의되는 푸리에 변환이 필요하다. 2차원 신호에 대한 푸리에 변환(Fourier transform)은 다음과 같이 정의된다.


, --- (5)


. --- (6)


단, 여기서 F(u, v)는 x축 방향으로 주파수(frequency) u, y축 방향으로 v인 주기함수 성분의 계수이다. 그리고 그 값은 식 (6)에 의해 계산된다.


그런데 이미지는 연속(continuous)이 아닌 이산(discrete) 신호이다. 그리고 한정된 유한(finite) 구간에서 정의되는 신호이다. 따라서, 이산 데이터에서 정의되는 푸리에 변환이 필요하다. W x H 크기의 이미지 f(x, y)에 대한 이산 푸리에 변환(discrete Fourier transform)은 다음과 같이 정의된다.


, ---(7)


. ---(8)


단, x = 0, 1, ..., W-1, y = 0, 1, ..., H-1이고 u = 0, 1, ..., W-1, v = 0, 1, ..., H-1.


식 (7)에서 ej2π(ux/W+vy/H)x축 방향으로 주파수가 u/W, y축 방향으로 주파수가 v/H인 sinusoidal 주기함수이다 (by 오일러 공식). 일반적인 푸리에 변환식과는 달리 W와 H로의 나누기가 들어있음에 유의해야 하며 이는 데이터가 정의된 구간을 하나의 단위 주기(unit period)로 만드는 효과가 있다. 일종의 정규화 팩터(normalization factor)라고 생각하면 된다.


여기서 2D 이미지를 어떻게 신호로 해석할 수 있는지, 그리고 2D 정현파(sinusoidal wave) ej2π(ux/W+vy/H)가 도대체 어떤 모습일지 아마도 의아해할 수 있다. 첫째, 이미지를 신호로 해석하는 문제는 x 또는 y축을 시간축으로 놓고 좌표의 변화에 따라 변하는 이미지 픽셀의 밝기 변화를 신호로 생각하면 쉽게 이해할 수 있다. 다음으로, 2D에서 정의되는 정현파(sinusoidal wave)의 모습은 아래 그림과 같이 모든 방향으로의 단면이 sinusoidal이 되는 물결 형태의 파동을 생각하면 된다.

그림 2. 2D에서의 sinusoidal wave


앞서 그림 1의 1D 푸리에 변환의 경우와 유사하게 생각해 보면, 이미지에 대한 푸리에 변환(Fourier transform)은 그림 2와 같은 형태의 다양한 2D 정현파들의 합으로 이미지를 분해하여 표현하는 것으로 이해할 수 있다.


이미지에 대한 푸리에 변환(Fourier transform)에서 한 가지 주의해야 할 것은 푸리에 변환의 계수 F(u, v)가 ej2π(ux+vy)의 계수가 아니라 ej2π(ux/W+vy/H)의 계수라는 점이다. 즉, 이산 푸리에 변환에서 F(u, v)는 주파수 u, v 성분이 아니라 주파수 u/W, v/H 성분에 대한 계수를 나타낸다.


W × H 이미지에 대한 이산 푸리에 변환에서 F(u, v)는

- x축 주파수 u/W, y축 주파수 v/H인 주기함수 성분에 대응

- 주기로는 x축 방향 W/u 픽셀, y축 방향 H/v 픽셀인 주기성분을 나타냄 (주기 = 1/주파수)


☞ 바로 이 부분이 개인적으로 푸리에 변환에 대해서 혼동스러웠던 부분 중 하나이다. W x H 이미지의 푸리에 변환에서 F(u, v)는 주파수 u, v의 성분이 아니라 주파수 u/W, v/H 성분이다. 따라서, 주파수 공간에서 특정 F(u, v) 값이 높게 나타났다면 원래의 이미지 공간에서는 x축 방향으로 주기가 W/u 픽셀, y축 방향 주기가 H/v 픽셀인 주기성 성분이 존재한다는 의미가 된다.


참고로, 1차원에서의 함수 f(x), x = 0, 1, 2, ..., W-1에 대한 이산 푸리에 변환(discrete Fourier transform)은 다음과 같이 정의된다.


 --- (9)


 --- (10)


☞ 1차원 이산 푸리에 변환(discrete Fourier transform)식은 실제 푸리에 변환을 컴퓨터로 구현하는데 있어서 가장 기본이 되는 식이다. 왜냐하면 파동과 같은 연속 신호라 할지라도 실제 분석에 있어서는 샘플링된 이산 데이터를 이용해야 하고 2차원 푸리에 변환에 대한 구현도 내부적으로는 1차원 푸리에 변환을 이용하여 구현되기 때문이다.



4. 푸리에 스펙트럼(spectrum)과 페이즈(phase)


이제 실제로 푸리에 변환(Fourier transform)을 통해 얻어지는 F(u, v) 값들이 어떤 의미를 가지며 어떤 형태(visualization)를 갖는지 살펴보자.


푸리에 변환을 통해 얻어지는 F(u, v)는 복소수(complex number)이며 실수부(Real)와 허수부(Imaginary)로 구성된다 (1차원 푸리에 변환의 경우도 마찬가지이다).


 --- (11)


이 때, 복소수 F(u, v)의 크기 |F(u, v)|를 푸리에 변환의 spectrum(스펙트럼) 또는 magnitude라고 부르고, F(u, v)의 각도 Φ를 phase(페이즈) angle 또는 phase spectrum이라고 부른다.


 --- (12)


 --- (13)


A. 푸리에 스펙트럼(Fourier spectrum)


먼저, 푸리에 스펙트럼(Fourier spectrum)에 대해 살펴보자. 푸리에 스펙트럼은 해당 주파수 성분이 원 신호(이미지)에 얼마나 강하게 포함되어 있는지를 나타낸다. W x H 이미지를 푸리에 변환(Fourier transform)하면 식 (7), (8)에 의해 W x H의 F(u, v), u = 0, ..., W-1, v = 0, ..., H-1 가 얻어진다. 따라서, |F(u, v)|를 픽셀값으로 잡으면 아래 예와 같이 푸리에 스펙트럼을 원본 이미지와 동일한 크기의 이미지로 시각화할 수 있다.


그림 3. 푸리에 스펙트럼(spectrum)과 좌표계

(a) 입력 이미지, (b) 푸리에 스펙트럼, (c) shifted 스펙트럼


푸리에 스펙트럼(Fourier spectrum)을 이미지로 시각화하는 데에는 2가지 문제점이 있다. 먼저, 푸리에 스펙트럼은 저주파 영역은 매우 큰 값을 갖는 반면에 대부분의 다른 영역은 0에 가까운 값을 갖는다. 따라서 푸리에 스펙트럼을 그대로 이미지로 시각화하면 검은 바탕 위에 흰점 하나만 존재하는 형태가 된다. 이러한 문제를 해결하기 위해서 스펙트럼을 이미지로 표현할 때에는 그림 3(b)처럼 스펙트럼에 log를 취하는 것이 일반적이다. 다음으로, 원래의 스펙트럼 이미지는 그림 3(b)처럼 모서리로 갈수록 값이 높아지기 때문에 스펙트럼의 형태를 파악하기 힘들다. 따라서 이러한 문제를 해결하기 위해 그림 3(c)처럼 원점이 중심(center)에 오도록 스펙트럼의 위치를 이동시킨(shift) 형태의 이미지를 사용하는 것이 일반적이다 (아래 ☞설명 참조). 앞으로 푸리에 스펙트럼 이미지라 하면 그림 3(c)와 같은 shifted 스펙트럼 이미지를 생각하면 된다.


☞ 그림 3(c)와 같은 shift가 가능한 이유는 푸리에 스펙트럼이 원점대칭인 주기함수이기 때문이다. 사실 식 (9), (10)로 주어지는 이산 푸리에 변환(discrete Fourier transform)식은 f(x)가 주기함수일 때에만 성립하는 식이다. 원래의 입력신호 f(x)는 x = 0, 1, ..., W-1의 유한 구간에서 정의된 함수이다. 우리가 관심있는 부분은 0 ~ W-1 구간에서의 특성이므로 그 외의 구간에 대해서는 함수를 어떻게 정의해도 무방하다. 따라서, 푸리에 변환 적용을 위해 이 함수를 확장하여 f(x + W) = f(x)인 주기함수(0 ~ W-1에서의 함수값이 다른 구간에서도 계속 반복)로 가정하고 식을 세운 것이 식 (9), (10)이다. 이 때, F(u) 또한 f(x)와 동일한 주기(W)의 주기함수가 된다. 즉. F(u) = F(u + W). 또한 식 (10)에서 |F(u)| = |F(-u)|임도 쉽게 알 수 있다. 즉, 이산 푸리에 스펙트럼은 원점대칭이면서 W를 주기로 하는 주기함수 형태임을 알 수 있다. 2차원의 경우도 마찬가지이며 F(u, v) = F(u + W, v) = F(u, v+ H) = F(u + W, v + h), |F(u, v)| = |F(-u, -v)|인 주기함수가 된다. 그리고 이러한 원점 대칭성과 주기성으로 인해 스펙트럼 이미지를 그림 3(c)와 같이 shift하여 표현하는 것이 가능해진다.


shifted 스펙트럼을 이해하기 위해 한 예로 아래 그림 4의 왼쪽과 같은 형태의 스펙트럼 신호를 생각해 보자. 그런데 만일 스펙트럼이 원점대칭이고 W를 주기로 반복된다면 푸리에 스펙트럼은 오른쪽과 같은 형태가 될 수밖에 없음을 알 수 있다. 원래의 푸리에 스펙트럼의 형태는 구간 0 ~ W의 형태(그림 3b)이지만 (어차피 정보가 반복되기 때문에) 이를 구간 -W/2 ~ W/2 형태(그림 3c)로 shift하여 표현한 것이 shifted 스펙트럼이다.



그림 4. 푸리에 스펙트럼의 주기 특징


B. 푸리에 스펙트럼의 해석


앞서 푸리에 스펙트럼(Fourier spectrum)은 해당되는 주파수 성분의 강도를 나타난다고 했는데, 정말 그런지 그리고 이 값이 이미지 도메인에서 어떻게 해석될 수 있는지 실제 예를 통해서 살펴보자.


아래 예는 이미지에 인위적으로 주기성분을 추가하였을 때 주파수 공간에서의 푸리에 스펙트럼이 어떻게 변하는지를 보여준다. 원본 이미지의 해상도는 205 × 205 픽셀이며(W = 205, H = 205) 따라서 스펙트럼 이미지도 205 x 205 해상도를 갖는다.


그림 5. 주기성분 추가에 따른 푸리에 스펙트럼의 변화


먼저, 그림 5(a)는 원본 이미지 및 대응되는 푸리에 스펙트럼 이미지를 보여준다. 그림의 예와 같이 일반적인 푸리에 스펙트럼 이미지는 원점 F(0, 0) 주변의 저주파 영역에서 강한 피크(peak)가 나타나고 원점에서 멀어질수록 즉, 고주파 영역으로 갈수록 값이 급격히 작아지는 형태를 갖는다.


그림 5(b)는 (a)의 이미지에 5 픽셀(pixel) 간격의 수평선을 인위적으로 추가한 경우이다. 그러면 주파수 공간에서는 그림과 같이 F(0, 41), F(0,82)에 강한 피크(peak)가 나타난다. 앞서 이산 푸리에 변환에서 F(u, v)는 x축 주기 W/u 픽셀, y축 주기 H/v 픽셀인 주기성분의 계수라 했다. 그러면, F(0, 41)은 주기가 x축 방향 205/0 = ∞, y축 방향 205/41 = 5 픽셀인 주기성분에 대응된다. 그리고 이것은 그림 5(b)를 만들 때 사용한 수평선의 주기(세로방향 5픽셀)와 정확히 일치한다.


☞ F(0, 82)에도 피크(peak)가 나타나는 것은 y축 방향으로 205/82 = 2.5 픽셀 간격의 주기 성분이 입력 이미지에 있다는 의미이다. 이는 이미지에 추가한 수평선이 정현파(sinusoidal wave)가 아니라 계단 형태이기 때문에 5 픽셀 주기의 정현파와 2.5 픽셀 주기의 정현파를 합쳐서 그러한 계단 형태를 근사했기 때문이다.


다음으로, 이번에는 그림 5(c)와 같이 대각선 방향의 정현파를 (a)의 이미지에 추가해 보자. 추가한 정현파는 x축 방향 주기 20 pixel, y축 방향 주기 10 픽셀인 2D sin 함수를 이용했다. 이 때, 푸리에 스펙트럼에는 F(10, 20.5)에 강한 피크(peak)가 생성됨을 확인할 수 있다. 즉, x축 방향으로는 W/u = 205/10 = 20.5 픽셀, y축 방향으로는 H/v = 205/20.5 = 10 픽셀의 주기 성분이 입력 이미지에 있음을 의미한다. 그리고 이는 실제 입력 이미지에 추가된 주기 성분과 정확히 일치한다 (소수점 오차는 u, v좌표를 정수로 표현함에 의한 것이다).


이상으로 주파수 공간에서의 F(u, v)가 입력 이미지 공간에서 어떻게 연관되어 해석될 수 있는지를 실제 예를 통해서 살펴보았다. 마지막으로 앞서 그림 5(b), (c)에서 스펙트럼의 피크(peak) 영역을 지운 후 푸리에 역변환(inverse Fourier transform)하면 아래와 같은 재미있는 결과를 얻을 수 있다 (지운다는 의미는 해당되는 F(u, v) 값들을 0으로 만든다는 의미이다).


그림 6. 푸리에 변환을 이용한 주기 성분 제거


[개발한 것들] - FFT와 모아레 제거 프로그램을 이용하면 이미지의 푸리에 변환, 특정 스펙트럼 삭제 및 역변환을 직접 테스트해 볼 수 있다.


C. 푸리에 변환의 페이즈(phase)


푸리에 변환(Fourier transform)에서 스펙트럼(spectrum)은 잘 알려진 반면 페이즈(phase)는 상대적으로 잘 알려져 있지 않다. 하지만 페이즈(phase)에도 스펙트럼(spectrum) 못지 않은 중요한 정보가 담겨 있다고 한다.


페이즈(phase)를 우리말로 번역하면 '단계'가 되고 전문용어로는 '위상'이 된다. 위키피디아에는페이즈(phase, 위상)를 '반복되는 파형의 한 주기에서 첫 시작점의 각도 혹은 어느 한 순간의 위치'라고 정의한다. 즉, 파형(wave)의 시점이 어디인지가 페이즈(phase)이다. 예를 들어, sin 파와 cos 파는 90도의 페이즈(phase, 위상) 차이가 존재하는 동일한 파형으로 볼 수 있다.


푸리에 변환의 관점에서 보면 페이즈(phase)는 원본 신호를 주기 신호로 분해했을 때 각 주기성분의 시점이 어딘인지(즉, 각 주기성분들이 어떻게 줄을 맞춰서 원본 신호를 생성했는지)를 나타내는 요소가 된다.


아래 그림은 페이즈(phase)의 영향을 보여주는 예로서 파란색 주기성분 신호들을 합쳐서 빨간색 신호가 생성되는 예를 보여준다. 왼쪽, 오른쪽 경우 모두 동일한 주파수의 주기성분들을 합쳤지만 각 성분의 페이즈(phase) 차이로 인하여 전혀 다른 신호가 생성됨을 확인할 수 있다.

그림 7. 페이즈(phase) 차이에 따른 신호 생성의 차이


다음으로 푸리에 변환의 페이즈(phase)가 어떻게 수식으로 표현되는지 살펴보자. (1차원) 푸리에 변환의 계수 F(u)는 식 (12), (13) 및 오일러 공식에 의해 다음과 같이 극좌표(polar coordinate) 형태로 표현될 수 있다 (설명의 편의상 1차원의 경우를 예로 든다).


 --- (14)


☞ 실수축이 x축, 허수축이 y축인 복소평면에서 F(u)는 x축과 이루는 각이 Φ인 막대기의 끝점 (R, I)에 대응된다. 이 때, R = |F|cosΦ, I = |F|sinΦ이므로 F = |F|cosΦ + j|F|sinΦ = |F|e.


이제 식 (14)를 식 (1)에 대입하면,


. --- (15)


와 같이 페이즈(phase) 텀이 주기함수 성분의 시점을 조절하는 텀이 된다.


즉, 푸리에 계수 F(u)에는 대응되는 주기함수 성분의 강도(amplitude)를 나타내는 스펙트럼 정보 |F(u)|와 시점을 조절하는 페이즈(phase) 정보 Φ(u)가 함께 포함되어 있음을 알 수 있다.


참고로, 푸리에 스펙트럼(spectrum)과 페이즈(phase)에 관한 재미있는 비교 결과를 하나 소개한다. 아래 그림 8에서 (a)는 원본 이미지, (b)는 푸리에 스펙트럼을 보존하고 페이즈(phase)를 랜덤(random)하게 했을 때의 역변환 결과, (c)는 페이즈(phase)를 보존하고 스펙트럼을 랜덤하게 했을 때의 역변환 결과이다. 결과를 보면 이미지의 푸리에 변환에서 스펙트럼(spectrum)보다 페이즈(phase)에 보다 더 중요한 정보가 포함되어 있음을 확인할 수 있다.


그림 8. 푸리에 스펙트럼과 페이즈의 중요도 비교



5. 푸리에 변환의 유용한 성질들


마지막으로 푸리에 변환(Fourier transform)에 대한 몇 가지 유용한 성질들을 정리하면 다음과 같다.


- 주파수 공간의 원점 F(0, 0)의 값은 이미지의 평균값과 일치



- Impulse 함수(Dirac delta 함수)에 대한 푸리에 변환/역변환은 유니폼(uniform) 함수 (아래 식에서 푸리에 변환/역변환 관계를 ⇔ 로 표기).



- 가우시언(Gaussian) 함수의 푸리에 변환/역변환은 가우시언 함수가 됨




6. 맺음말


이상으로 푸리에 변환(Fourier transform)에 대한 정리를 마칩니다. 원래는 이렇게까지 길게 쓸 생각은 아니없는데 쓰다 보니 글이 길어졌네요.. ^^



참고자료 및 유용한 관련 글 링크


푸리에 변환 by jipark

푸리에 급수의 시작 by 전파거북이

푸리에 변환 by 전파거북이

페이저(phasor) by AngeloYeo

허수의 존재 의미에 대하여 by AngeloYeo

Magnitude and Phase by Deepa Kundur (토론토 대학)

What information is contained in the phase spectrum of a signal?


by 다크 프로그래머

  • 이전 댓글 더보기
  • BlogIcon 너부리이놈 2018.02.27 10:30 신고 ADDR 수정/삭제 답글

    안녕하세요
    예전에 마커인식 AR을 구현하면서 많은 도움을 받았습니다.
    감사합니다.
    도넛모양의 이미지를 긴 직사각형 띠로 펼쳐야 하는데 어떻게 하는게 좋은지
    시작할만한 단초라도 알려주실수 있을까요?
    동심원은 아닙니다.

    • BlogIcon 다크pgmr 2018.02.27 17:16 신고 수정/삭제

      극좌표(polar coordinate)를 일반 유클리디언 좌표(Euclidean coordinate)로 변환하는 방식으로 해결하면 가능하지 않을까 싶습니다. 즉, 도넛 이미지의 각 픽셀에 대한 극좌표 (radius, theta)를 구한 후에, radius를 x축, theta를 y축으로 매핑하면 직사각형 이미지가 얻어질 것으로 생각됩니다.

  • korjw 2018.02.28 15:51 신고 ADDR 수정/삭제 답글

    페이즈를 이용해본적이 없어서 무지하였는데.. 비교 결과가 신기하네요.. 페이즈가 랜덤하게 변하면 아예 다른 신호로 나오는군요. 페이즈를 이용할만한 곳이 있는지 궁금합니다~

    • BlogIcon 다크pgmr 2018.02.28 18:11 신고 수정/삭제

      통신쪽에서 많이 쓸 것 같긴 한데, 잘은 모르겠습니다.

  • 루루 2018.03.13 20:46 신고 ADDR 수정/삭제 답글

    설명도 잘 하시는데 글도 잘 쓰시네요. 부러워요. 푸리에급수에서 어려움 겪고 있었는데 수학 잘 못하는 사람도이해할수 있는 친절한 글을 만나서 눈물나게 반갑습니다. 좋은 글 감사합니다.

  • 하얀천벌 2018.03.20 17:51 신고 ADDR 수정/삭제 답글

    코세라 컴퓨터 비전 강의를 보다가 푸리에 변환 부분이 어려워서 찾게되었는데 이 글이 이해하는데 많은 도움이 되었습니다. 감사합니다.

    • BlogIcon 다크pgmr 2018.03.20 18:26 신고 수정/삭제

      네, 감사합니다. 코세라 강의는 저도 시간이 되는데로 들어봐야겠습니다 ^^

  • 천비 2018.03.20 20:54 신고 ADDR 수정/삭제 답글

    좋은 설명 감사합니다. 저는 이번에 막 석사 입학한 학생입니다. 타전공에서 넘어온지라 쉽지 않네요.
    질문좀 드리겠습니다.
    우선 영상처리에서 푸리에 변환 같은 주파수로 이용해서 다시 역변환으로 원본영상을 얻으면 많은 이점이 있는 경우들이 얼마나 있는걸까요? 제가 알기론 컨볼루션시에 속도가 빠르다, 필터 통과시에 다양한 영상처리를 할 수 있다(사실 이부분도 마스킹처리로 기존 영상에서 가능한 부분이 아닐까 싶고..) 정도인데 다른 쓰임새가 있을까요?

    두번째로 마지막부분에 스펙트럼을 랜덤하게 하고 페이즈만 보존했더니 형태는 그대로 나타났는데, 사실 이정도면 에지검출이나 세그멘테이션 같은 곳에 충분히 활용할만큼 좋은 결과로 이용될 수 있지 않을까요? 단지 저 영상에서만 저런결과를 보이는 것인지, 다른 모든 영상에서도 저렇게 윤곽이 뚜렷하게 보이는 것인지 알고싶네요.

    • BlogIcon 다크pgmr 2018.03.21 08:16 신고 수정/삭제

      영상처리에서 fft의 응용은 저도 그 정도로 알고 있습니다. 두번째, 페이즈 보존 영상을 이용한 에지검출은 흥미로운데요, matlab 등을 이용해서 직접 결과를 확인해 보셔도 좋을 것 같습니다. 일반적으로 신호의 스펙트럼을 구하면 저주파 성분은 값이 크고 고주파 성분들은 아주 작은 값을 가집니다 (그래서 가시화를 위해서는 log scale을 사용합니다). 그런데, 페이즈 보존 영상은 그러한 값의 차이를 없애고 동일한(유사한) 스펙트럼 값을 부여했기 때문에 결과적으로 고주파 성분(에지 성분)이 역변환 영상에서 강조되게 됩니다. 따라서, 에지가 강조되는 현상은 모든 영상에서 유사하게 나타나리라 생각됩니다. 하지만, 이러한 결과가 에지 검출기로서 유용한지는 확인이 필요해 보입니다 (고주파 성분만 역변환해도 에지 이미지는 얻어지기 때문에...).
      에지검출기로서의 유용성을 떠나서 페이즈 보존 영상을 하나의 새로운 변환으로 본 관점은 개인적으로 신선합니다 (저는 그렇게는 생각 못했거든요..). 페이즈 보존 영상만이 갖고 있는 고유의 특성이 있을 것이고 그 특성과 부합하는 응용을 찾을 수 있다면 의미있는 결과가 될 것으로 생각됩니다.

  • 훈장님 2018.04.17 11:21 신고 ADDR 수정/삭제 답글

    레포트 작성하는 데 참고용으로 좀 쓰겠습니다. 출처는 남기겠습니다. 감사합니다 고맙습니다

  • MENBUNG 2018.04.17 16:32 신고 ADDR 수정/삭제 답글

    FFT, DFT.. 자주 나오는데 제대로 의미를 알지 못한다고 생각되어서 찾아보고 있던 중 좋은 글을 찾았네요.
    대학교에서 직관적인 의미를 깨닫지 못해서 시간 ↔ 주파수 개념으로만 알고 있었는데, 이 글을 통해서 직관적인 이해를 할 수 있었습니다.
    스크롤이 길다고 생각됐었는데 몰입해서 읽으니 어느새 끝까지 다 읽었네요. 감사합니다.

    • BlogIcon 다크pgmr 2018.04.17 21:43 신고 수정/삭제

      네, 제가 봐도 너무 글이 깁니다 ^^. 다 써놓고 보니 글이 너무 길어서 쓸데없이 길게 썼구나 싶었지만 이왕 쓴거 어떻게 하기도 그렇고 그렇습니다. 그래도 긴 글을 끝까지 다 읽으셨다니 감사합니다.

  • 고고피자 2018.04.30 17:18 신고 ADDR 수정/삭제 답글

    좋은 글 써주셔서 감사합니다. 약간 헷갈리는 개념이 많았는데, 이글을 통해서 좀 더 이해하기가 수월해졌네요. 그런데 푸리에 변환을 할 때, 음수값을 같는 주파수에 대한 의미는 어떻게 생각하면 될지 궁금합니다.

    • BlogIcon 다크pgmr 2018.04.30 17:56 신고 수정/삭제

      음수값을 갖는 경우는 실제의 의미는 없다고 생각합니다. 단지 주기함수로 만들어주기 위한 수식상의 장치라 생각합니다.

    • 안녕하세요 2018.05.06 02:49 신고 수정/삭제

      안녕하세요. 지나가던 길인데... 제가 주제 넘게 답변드리자면, 음의 주파수는 반대방향 회전을 의미합니다. 양의 주파수를 갖는 신호와 음의 주파수를 갖는 신호를 함께 이용해줌으로써 하나의 실수 신호를 표현할 수 있게 됩니다.

      자세한 것은 이 영상 참고해주세요. https://youtu.be/K8DuEYyYWNQ

    • BlogIcon 다크pgmr 2018.05.07 08:37 신고 수정/삭제

      @안녕하세요. 감사합니다. 아직 모르는게 많습니다.

  • 로봇박사 2018.06.15 20:53 신고 ADDR 수정/삭제 답글

    고2인데 수학 창의탐구 시간에 멋모르고 푸리에변환을 주제로 정했다가
    며칠 전만해도 멘탈이 나갔었는데
    이글 보니까 이해가 꽤 되는 것 같네요
    정말 감사합니다!

  • signal 2018.06.22 23:25 신고 ADDR 수정/삭제 답글

    안녕하세요. 공부하다가 궁금한게 있어서 질문드리려고 합니다.
    식 (1)에서 ej2πux, u = 0, ±1, ±2, ...은 모든 신호를 생성할 수 있는 직교(orthogonal) 기저(basis) 함수들로 볼 수 있다. 라고 되어있는데, 여기에서 u는 주파수로 알고있습니다. 그런데 이것이 왜 정수여야만 하는지 자세히 알려주실 수 있는지요..? 부탁드립니다..

    • BlogIcon 다크pgmr 2018.06.25 00:36 신고 수정/삭제

      안녕하세요. 정수로 표기한 것은 제 실수입니다. 영상처리 쪽에 있다보니 저도 모르게 이산적으로만 생각해서 정수로 가정한 것 같습니다. 본문 글을 수정했습니다. 감사합니다.

  • 냐냐 2018.06.28 22:52 신고 ADDR 수정/삭제 답글

    정말 감사해요 너무 도움이 되었습니다. 어떤 글보다 명쾌하고 쉽게 이해할 수 있는 글이었어요.
    그런데 혹시 푸리에 역변환 식을 푸리에 변환식에 대입하였을 때 항상 원본입력신호가 나온다는 증명 링크를 얻을 수 있을까요?

  • signal 2018.07.09 13:16 신고 ADDR 수정/삭제 답글

    한가지 질문 드릴 것이 있습니다.
    cos함수를 푸리에 변환하여 phase를 구하게 되면, 0도와 180도가 나오는 것이 정상인 것으로 알고 있습니다. 이는 실수부분과 허수 부분으로 나누어지는 것으로 표현해보면, 허수는 sine 함수로 표현되고, 이는 직교하기 때문에, 0이 되는 것이라고 생각했습니다.
    그런데, 실제로 그래프를 그려보니, 허수가 cos함수의 주파수 f0에 값을 가지고 있었습니다.
    매트랩으로 계산을 하였는데, 이는 컴퓨터 상의 오류인가요? 아니면, 허수 부분을 가지는 것이 정상인가요?
    답변해주시면 감사하겠습니다.

  • BlogIcon 너부리이놈 2018.08.16 10:24 신고 ADDR 수정/삭제 답글

    도넛 이미지 직사각형으로 펼치기
    다크pgmr 2018.02.27 17:16 신고 수정/삭제
    극좌표(polar coordinate)를 일반 유클리디언 좌표(Euclidean coordinate)로 변환하는 방식으로 해결하면 가능하지 않을까 싶습니다. 즉, 도넛 이미지의 각 픽셀에 대한 극좌표 (radius, theta)를 구한 후에, radius를 x축, theta를 y축으로 매핑하면 직사각형 이미지가 얻어질 것으로 생각됩니다.
    ---------------------
    안녕하세요.2월말에 질문 드린걸 이제서야 하고 있네요ㅎㅎ
    radius를 x축, theta를 y축 매핑 하면 직사각형이 되는건 알겠는데
    매핑 시키려면 정수값이 나와야할것 같은데 지름과 각도가 정수값이 안나오는데 어떻게 해결해야 하나요?
    답변미리 갑사드립니다.

    • BlogIcon 다크pgmr 2018.08.16 13:04 신고 수정/삭제

      정수로 근사시키면 되지 않을까요? 3.1→3, 3.7→4

  • coherence 2018.08.20 09:04 신고 ADDR 수정/삭제 답글

    덕분에 푸리에변환에 대해 쉽게 이해할 수 있었습니다.
    저도 질문이 하나 있는데요. 파장에 따른 intensitry 데이터를 FFT를 하면 주파수 축으로 변환이 되는데 matlab에서는 DC포함 총 3 Peak가 뜨잖아요? 그럼 한 peak만 필터링을 하고 ifft를 하면 축이 파장 축으로 다시 넘어오나요?

    • BlogIcon 다크pgmr 2018.08.20 22:49 신고 수정/삭제

      답변을 드리고 싶어도 질문이 난해하네요. 일단 DC가 무엇인지 모르겠고.. 축이 파장축으로 넘어온다는 말도 무슨 의미인지 파악이 어렵습니다.

  • 전자공학도 2018.08.28 01:19 신고 ADDR 수정/삭제 답글

    정말 감사합니다 ㅠㅠ
    무지한 학생에게 정말 하나하나 꼼꼼히, 그리고 이해하기 쉽게 풀어주셔서
    어떤 자료보다 더 많은 도움을 받았습니다.
    꼭 감사의 말씀을 전해드리고 싶었습니다. 지식을 공유해주셔서 감사합니다.

  • iam공돌 2018.09.22 20:47 신고 ADDR 수정/삭제 답글

    이런 글 써주셔서 진짜 감사합니다 ㅎㅎㅎㅎㅎ

  • ㅇㅇ 2018.10.12 02:37 신고 ADDR 수정/삭제 답글

    좋은글 감사합니다. 그런데 shift할때의 내용이 정확히 이해가 가지않습니다.. 질문하나만 드리겠습니다 ㅠㅠ

    x,y를 u,v로 대응시키고 범위는 0~W-1인데 왜 shift가 가능한지 설명하는 예제에선 스펙트럼이 0~W/2까지만 있고 그뒤론 값을 가지지 않는건가요?

    • BlogIcon 다크pgmr 2018.10.12 10:52 신고 수정/삭제

      그 뒤로도 값이 있습니다. 그림 4(좌)는 설명을 위한 그림입니다.. 실제 스펙트럼은 그림 4(우)와 같은 형태가 될 것입니다.

  • 123 2018.11.03 13:43 신고 ADDR 수정/삭제 답글

    푸리에 변환을 설명하면 푸리에 변환은 임의의 입력 신호를 다양한 주파수를 갖는 주기함수들의 합으로 분해하여 표현하는 것인데 수식에서는 왜 입력신호를 분해하는거를 역변환이라고 하는거에요??

    • BlogIcon 다크pgmr 2018.11.05 19:14 신고 수정/삭제

      어떤 식이 푸리에 변환식이냐 역변환 식이냐 구분하는 것은 그렇게 중요한 것 같지는 않은데요. 보기 나름이라서.. 식이야 어쨌든, 입력 신호로부터 주파수 계수를 구하는 것은 푸리에 변환, 주파수 계수로부터 원본 신호를 얻는 것은 푸리에 역변환입니다.

  • 고딩 2018.11.10 18:23 신고 ADDR 수정/삭제 답글

    안녕하세요. 수학 주제탐구로 이와 관련된 내용을 탐구하고 있는 고등학생입니다. [그림 3]에서 원점대칭과 주기성으로 인해 shift가 가능하다고 하셨는데, 이 부분이 잘 이해되지 않아 이렇게 질문 드립니다. 원점대칭이면 스펙트럼 상에서 어떻게 좌표 이동이 가능한가요?

    • BlogIcon 다크pgmr 2018.11.10 23:28 신고 수정/삭제

      그림 4와 손가락 표시(☞) 부분이 그 이유를 설명한 내용입니다.

  • 안녕하세여 글을보고 질문하나 남기려고 합니다
    현재 컴퓨터 비전 안면인식 쪽을 개발중인데 기존 카메라로만 하게된다면 해당 사람과 같은 사진으로도 오픈이 되는경우가 있는데 적외선 카메라를 통해 주파수를 통해 사람과 사진을 구별할 수 있을까요??
    제가 아무래도 전문 수학지식이 없다보니 이렇게 두서없이 질문드리게 되었습니다 .

    • BlogIcon 다크pgmr 2018.11.15 18:21 신고 수정/삭제

      안녕하세요. 적외선 영상에서 주파수를 이용하는 방법은 저도 잘 모르겠습니다. 적외선 영상의 온도 분포를 확인하면 사진과는 구분이 될것 같습니다만.. 그리고 영상에서의 미세한 변화를 감지해서 사람의 맥박수를 셀수 있는 기술이 있다고 들었습니다. 그런 종류의 기술을 적용하면 효과적으로 tampering을 감지할수 있을 것 같습니다.

YOLO 윈도우즈(windows) 버전

기계학습 2017.09.01 10:15

얼마 전 YOLO를 다운받아서 돌려보았다. 그동안 말로만 들어왔던 딥러닝 기술을 실제로 돌려본 건 처음이다.


YOLO를 돌려본 느낌은 멋지다이다. 그리고 yolo와 darknet을 만든 Joseph Redmon이란 사람도 멋있다는 생각이 든다. 사실 이 분야에 있다보니 그동안 딥러닝에 대한 것은 많이 보고 들어 왔다. 하지만, 그것을 자신이 직접 돌려 본 느낌은 또 다른 것 같다.


이 분야에 있는 사람들은 YOLO가 무엇인지는 대부분 다 알 것이다. 이 글에서는 YOLO와 딥러닝에 대한 이런 저런 생각, 그리고 YOLO를 윈도우(window)에서 빌드하고 실행시키는 방법을 소개한다.


1. YOLO (you only look once)

2. YOLO 윈도우즈(windows) 빌드

3. YOLO의 실행

4. 딥러닝에 대한 잡담



1. YOLO (you only look once)


YOLO의 원래 의미는 you only live once이다. 한번뿐인 인생 마음 가는데로 살자는 말이다. 하지만 여기서 말하는 YOLO(욜로)는 you only look once이다. 한 번만 본다... YOLO가 무엇인지 그리고 무슨 의미인지는 YOLO의 개발자 Joseph Redmon이 최근(2017년 4월) TED에서 발표한 내용에 잘 나타나 있다.



YOLO는 무공으로 치면 사파에 해당된다. 즉, 남들이 일반적으로 따르는 정통 주류의 방법론을 따르지 않고 자신의 독자적인 무공 체계를 세워 왔다. 그리고 최근 주류의 정점에 있는 CVPR 2017에서 Best Paper Honorable Mention 상을 수상하였다.


YOLO를 실행시키기 위해서는 Darknet이 필요하다. Darknet은 Joseph Redmon이 독자적으로 개발한 신경망 프레임워크(neural network framework)로서 dnn(deep neural network)들을 학습시키고 실행시킬 수 있는 틀(framework)이다. 그리고 yolo는 학습된 신경망(결과물) 중 하나이다. Darknet을 이용하면 yolo 뿐만 아니라 AlexNet, VGG-16, Resnet, Densenet 등 기존의 정통 주류의 dnn(deep neural network)들도 돌려 볼 수 있다.


일단, 나는 '다크넷'이란 용어가 맘에 든다. 내 블로그 필명과도 유사하고 정파가 아닌 사파라는 점도 마음에 든다. Darknet은 부정적인 의미(법망에서 벗어난 어둠의 인터넷 환경)도 있지만 구속되지 않음으로 인해 자유로움이 가능한 공간으로 해석될 수도 있다. 일반적으로 보기 힘든 Joseph Redmon의 독특한 이력서(resume)도 매우 인상적이다 (관심있는 분은 이력서 링크를 한번 클릭해 보시길.. ^^).


Darknet과 yolo는 그 코드가 모두 공개되어 있으며 누구라도 사용할 수 있다.



2. YOLO 윈도우즈(windows) 빌드


나는 리눅스(Linux) 환경과는 별로 친하지 않다. 그래서 번거롭지만 윈도우즈(windows)에서 돌릴 수 있는 버전을 찾아서 작업을 하였다.


YOLO 윈도우즈 버전은 구글에서 검색해 보면 어렵지 않게 찾을 수 있다.

첫 번째 사이트(AlexeyAB)에 가면 YOLO 윈도우 버전을 다운받을 수 있다. 또한 설치, 컴파일, 실행 방법까지 상세하게 설명되어 있다. 따라서 설명만 따르면 어렵지 않게 빌드 및 테스트가 가능하다.


사이트에 잘 설명되어 있긴 하지만 그래도 간단히 그 과정을 적어보면 다음과 같다.

  1. 사이트에서 소스코드를 다운받는다 (git clone 또는 zip 다운로드)
  2. NVIDIA 계열의 그래픽카드(GPU)가 컴퓨터에 있어야 한다 (그래픽 메모리 4GB 이상 권장). NVIDIA 그래픽카드가 없어도 CPU 버전으로 빌드 및 실행은 가능하다. 하지만 매우 매우 느리다.
  3. CUDA 8.0 설치: https://developer.nvidia.com/cuda-downloads (그래픽카드가 없는 경우에는 설치할 필요가 없다)
  4. 다운받은 소스에서 visual studio 프로젝트 파일(*.sIn)을 찾아서 실행시킨다. 끝.


다운받은 소스에 보면 여러 가지 설정의 Visual Studio (VS) 프로젝트 파일들이 제공된다. 나는 이 중에서 yolo_cpp_dll 버전으로 빌드 및 테스트를 했다. yolo를 dll 라이브러리로 만들어 놓으면 다른 윈도우즈 프로그램에서도 자유롭게 사용할 수 있기 때문이다.


다만, 한 가지 문제는 사이트에서 제공하는 프로젝트 파일은 Visual Studio 2015 용이기 때문에 그 이전버전의 Visual Studio(VS 2013 등)에서는 사용이 안된다는 점이다.


한 가지 해결법은 다음과 같다. (1) 먼저, *.sIn 파일을 삭제한다. (2) 이후 *.vcxproj 파일을 메모장으로 열어서 프로젝트의 버전을 자신의 VS에 맞게 수정해 준다. (3) 이후 수정된 *.vcxproj를 클릭하여 프로젝트를 연다 (프로젝트를 저장하면 *.sIn 파일이 자신의 버전에 맞게 자동 생성된다).


예를 들어, 자신이 사용하는 버전이 Visual Studio 2013라면 14.0은 12.0으로 v140은 v120으로 변경해 주면 된다.


- ToolsVersion="14.0" 을 찾아서 14.0을 자신의 Visual Studio 버전으로 변경

- v140을 찾아서 (총 4곳) 자신의 Visual Studio 버전으로 변경



3. YOLO의 실행


yolo를 실행시키기 위해서는 darknet에서 yolo의 cfg 파일과 weights 파일을 불러와야 한다. cfg 파일은 신경망의 구조(layer 개수, 입력 데이터의 차원 등)를 명시한 파일이고 weights 파일은 실제로 학습된 신경망의 weight 값들을 저장한 것이다.


yolo 사이트에서는 아래와 같이 다양한 버전의 미리 학습된 yolo 신경망(cfg & weights 파일)들을 제공한다. 이들 중 원하는 버전을 다운받은 후 darknet에 넣고 실행하면 된다. 자세한 실행법은 yolo 사이트의 설명문서 참조.



참고로, VOC 2007+2012 데이터에 대해 학습시킨 yolo는 20개의 물체 클래스에 대해 학습시킨 버전이고 COCO 데이터로 학습한 것은 80개의 물체 클래스에 대해 학습한 것이다. 따라서, 일반적인 목적으로는 위 그림에서 표기한 YOLOv2 608x608 버전을 다운받는 것이 무난하다. Tiny 버전은 용량도 작고 속도도 빠르지만 성능은 그다지 좋지 않다. 또한 최근에 공개된 yolo9000 모델(http://pjreddie.com/media/files/yolo9000.weights)도 한번 테스트해 봄직하다 (9000개의 물체 클래스에 대해 학습된 버전이며 cfg 파일은 git에서 다운받을 수 있다: https://github.com/pjreddie/darknet/blob/master/cfg/yolo9000.cfg).


YOLOv2 608x608의 실행 속도는 데스크탑에서 직접 돌려보니 GPU(GTX 1080)를 사용했을 때에는 35 fps, GPU 없이 CPU(i7-6700k)만으로 돌렸을 때에는 0.3 fps가 나왔다. 새삼 GPU의 위력을 실감할 수 있다..



4. 딥러닝에 대한 잡담


요즘 어딜 가나 딥러닝이다. 딥러닝이 나온 게 불과 몇년 전인데, 그동안 딥러닝으로 인한 변화는 엄청나다. 우리는 그 변화의 한가운데에 서 있으며 그 변화의 끝이 어디일지 두렵기까지 하다.


나는 사실 딥러닝에 대해서는 잘 모른다. 옛날 학생 때 인공신경망(artificial neural network)을 몇 번 학습시켜 본 것이 다이다. 그래도 몇 년 동안 이래 저래 줏어듣다 보니 몇 가지 기본적인 개념 정도는 이해하고 있는 수준이다.


요즘 사람들을 보면 모든 관심이 딥러닝에 모여지는 것 같다. 지식의 블랙홀 같기도 하고.. 그러한 변화를 따라가고 있는 사람들을 보면 대단하다는 생각도 들고 또 한편으로 우려도 된다.


딥러닝은 학생들이나 입문자들에게는 좋은 기회이다. 딥러닝의 뛰어난 성능은 수십년 동안 쌓아온 전통적인 지식 체계를 무색하게 하고 그들과 동일 선상에 설 수 있는 기회를 준다. 딥러닝은 그 사용법만 잘 알아도 창의성과 아이디어만 있다면 좋은 결과를 낼 수 있는 것으로 보인다. 그러다 보니 수십년 동안 전통적인 지식 체계를 쌓아 온 사람과 입문자가 같은 선 상에 설 수 있는 기회를 준다.


하지만 딥러닝은 지식의 추구 관점에서는 걸림돌이 될 수도 있다. 기본을 몰라도 결과를 낼 수 있으니 굳이 힘들게 체계적인 공부를 할 필요가 없기 때문이다. 딥러닝의 사용자 입장으로만 남을 것이면 사실 큰 문제가 없다. 하지만 소위 말하는 black-box implementer로만 남지 않으려면 그 시스템 안으로 조금은 들어가 볼 필요가 있다. 그리고 시스템에 들어가기 위해서, 나아가 시스템을 바꾸기 위해서는 항상 기본이 필요하다.


나는 그동안 딥러닝에 있어서는 아웃사이더(outsider)로만 있어 왔다. 인공신경망(artificial neural network) 자체도 별로 좋아하지 않고 (입력주고 원하는 출력을 주면 지가 알아서 뭔가를 만들어 내는데, 내가 할 수 있는 일이라곤 별로 없다. 열심히 학습 버튼 눌러주고.. 컴퓨터 좀 바꿔주고.. 나의 직관력이나 이해가 끼어들 여지가 별로 없다) 또 뭔가 새로운 것을 배워야 한다는 것도 귀찮기 때문이다.


하지만 어.. 하는 사이에 세상은 너무 빠르게 변해가고 이젠 어쩔 수 없이 딥러닝을 배워야 하는 것 같다. 개인적으로는 그것들을 잘 사용해서 데이터를 모으고 실제 문제를 푸는 것이 목적은 아니다. 그냥 그 안으로 들어가서 그 원리를 조금씩 보고자 한다.


by 다크 프로그래머

  • 아에이오우 2017.09.05 15:13 신고 ADDR 수정/삭제 답글

    약 2년 동안 열심히 만들고 보완한 보행자 검출 알고리즘 성능이,
    하루 노력해서 돌려본 YOLO에 비해 형편없다는 사실이
    참으로 슬프네요. 하지만 2년 동안 노력해서 얻은 컴퓨터비전 지식들은
    소중한 자산이 된다고 믿고 있습니다.
    항상 좋은 글 잘 보고 있습니다^^

    • BlogIcon 다크pgmr 2017.09.05 18:38 신고 수정/삭제

      네 공감합니다. 그러한 자산이 좀더 멀리 나아갈 수 있는 소중한 자산이 되리라 생각합니다. 감사합니다.

  • 다크님ㅠㅠ 2017.09.06 09:54 신고 ADDR 수정/삭제 답글

    너무 늦게 오셨습니다. ㅠㅠ 블로그 항상 잘 참고했었는데요.
    얼른 따라잡으셔서 좋은글 부탁 드립니다.

  • ctw 2017.09.06 12:54 신고 ADDR 수정/삭제 답글

    어서 오십시요.
    많은 분들이 딥러닝을 직관적으로 풀어주실 다크님 글들을 기다리고 있습니다. ^^

    Open CV 3.3(2018.08.03) 버전부터는 컴퓨터 비전이 딥러닝을 품고 있습니다. 다크님께서도 품어 주실것이라 믿습니다.
    http://opencv.org/opencv-3-3.html

    • BlogIcon 다크pgmr 2017.09.06 14:08 신고 수정/삭제

      ㅎㅎ 제가 점쟁이라도 된 것 같은데요, 그럴리는 없구요.. 조금씩 배워가는 입장에서 정리할 게 생기면 가끔 글도 올리고 하겠습니다.

  • 김공자 2017.09.15 21:02 신고 ADDR 수정/삭제 답글

    다크....에 저런 좋은 뜻이 있었군요?ㅎㅎㅎ
    딥러닝이 빛본지가 얼마 안되서 그렇지 이론같은건 꽤 오래되지 않았나요?ㅎㅎ
    글 잘읽었습니다. ^^

    • BlogIcon 다크pgmr 2017.09.18 12:03 신고 수정/삭제

      네 소수 연구자에 의해 오래전부터 연구되어 오다가 최근에(2012년 경) 몇가지 벽이 뚫리면서 빛을 본 것으로 알고 있습니다.

  • CV 2017.09.28 19:26 신고 ADDR 수정/삭제 답글

    딥러닝에 대해 이제 막 공부해보려합니다.
    YOLO에 대해 한가지 여쭤보고 싶은게 있는데요,
    혹시 yolo를 사용하여 object detection을 수행하되, detected 된 object를 rectangular box로 나타내기에 앞서 binary image형태로 object있는 부분만 표현할 수 있을까요?

    • BlogIcon 다크pgmr 2017.09.28 23:36 신고 수정/삭제

      YOLO에 대해 잘 알진 못하지만 아마도 안되는 것으로 알고 있습니다. 물체의 경계를 따는 것이 목적이라면 최근에 나온 MASK R-CNN을 찾아보시면 좋을 듯 싶습니다.

    • CV 2017.09.29 04:16 신고 수정/삭제

      감사합니다.!! 더 공부해보도록 하겠습니다.

  • 태크닉 2017.09.29 15:25 신고 ADDR 수정/삭제 답글

    안녕하세요 다크프로그래머님 리눅스 환경 뿐만 아니라 윈도우환경에서 YOLO v2를 사용해 보고있습니다. 이미지, 동영상은 정상적으로 잘 불러와서 실행되는데 노트북 내장 웹캠을 불러오려 하니 stream 에러를 뱉어내네요, 혹시 이와같은 경험이 있으셨나요?

    • BlogIcon 다크pgmr 2017.09.29 15:42 신고 수정/삭제

      전 dll로 만들어 써서 그러한 문제는 발생하지 않습니다 (입력 소스에 대한 dependency가 없기 때문). 다른 opencv 프로그램으로도(간단하게 하나 구현) 동일한 현상이 나타나는지 한번 확인해 보시면 좋을 것 같습니다.

  • ydgoo 2017.10.18 08:20 신고 ADDR 수정/삭제 답글

    글에보면 GPU 를 사용하면 35fps. 사용하지 않으면 0.3fps 로 되어 있습니다. 약 10배의 차이가 난다는것인데요 gpu 를 사용하지 않는 경우 성능을 올릴수 있는 방법들이 있는지 궁금합니다.

    • BlogIcon 다크pgmr 2017.10.18 11:30 신고 수정/삭제

      3가지 정도 방법이 있습니다. 1. tiny 버전의 yolo를 사용한다. 검출 성능은 크게 저하되지만 속도는 상승합니다. 2. 고가의 고성능 cpu를 사용한다. 3. cpu에서도 병렬처리가 되도록 yolo 코드를 수정한다 (실제 yolo 코드에 cpu 병렬처리가 들어있는지는 모릅니다. 만일 들어있지 않다면 병렬처리를 하면 속도가 향상될 것입니다).

  • ydgoo 2017.10.19 22:47 신고 ADDR 수정/삭제 답글

    실제로 저희도 tiny YOLO 는 사용을 해보았습니다만 원하는 성능이 나오지는 않더라구요. 가성비가 좋아보이는건 cpu 병렬처리일것 같아 보입니다. 혹시 yolo 말고 다른 좋은 솔루션이 있는지도 궁금하네요. 친절한 답변 감사드립니다.

    • BlogIcon 다크pgmr 2017.10.20 01:23 신고 수정/삭제

      저도 따로 아는 건 없습니다. 글에서 적었듯이 저도 deep learning 쪽은 거의 문외한이라.. 혹시 사람만 찾는 것이 목적이라면 tiny yolo를 사람에 대해서 fine tuning을 해서 성능을 높이는 방법도 있을 것 같습니다. 물론 방법은 직접 공부를 하셔야...

    • 대전학생 2017.10.30 13:04 신고 수정/삭제

      NNPACK를 검색해보시는건 어떠신지요?

      CPU나 임베디드 기기에서 뉴럴넷 가속을 위해서 나온 패키지로 알고 있습니다.

    • BlogIcon 다크pgmr 2017.11.01 13:50 신고 수정/삭제

      @대전학생 좋은 정보 감사합니다. 누군가는 이렇게 유용한 것들을 만들고 또 공유하니 참 좋은 것 같습니다.

  • ydgoo 2017.10.20 13:36 신고 ADDR 수정/삭제 답글

    네 답변 너무 감사드립니다. 저도 좀 더 찾아보도록 하겠습니다.

  • jackalee 2017.10.26 16:52 신고 ADDR 수정/삭제 답글

    안녕하세요. YOLO win7에 설치해서 해보려 하는데..
    완전 초보라. 빌드하는것도 잘 못하는데..ㅡㅡ;
    실례지만 질문 좀 드려도 될까요?? ^^;
    Github에 나온데로 따라 하는데요.
    sln파일 오픈하고 set x64하고 Release하면 된다고 적혀있던데...
    MSVS에서 어떻게 해야하나요?

    • BlogIcon 다크pgmr 2017.10.27 00:02 신고 수정/삭제

      빌드설정을 그렇게 하고 빌드를 하라는 의미인데요, vs 사용법은 설명이 힘들고 책등을 통해서 공부해야 할 것 같습니다.

  • 드디어!! 2017.11.08 20:45 신고 ADDR 수정/삭제 답글

    드디어 다크 선생님도 오시는군요!! 많은 좋은 글 기대할께요 ~ ㅋㅋ

  • 호롤롤루 2017.11.09 15:10 신고 ADDR 수정/삭제 답글

    안녕하세요 최근 우분투환경에서 yolo를 통해 object detection을 실습해보는 와중에 질문을좀 드려도 될까요ㅠㅠㅠ
    tiny yolo로 진행하고 있는데 물제 detection에 있어 조명에 영향에 성능이 떨어지는것 같습니다. 만일 opencv함수를 사용하여 영상전처리를 진행시키면서 gray scale에서 yolo를 사용할 수 있을지 의문이듭니다.
    그리고 예를들어 사람의 얼굴 하나만 detect하려고 하는데 사람의 얼굴에 대해 4~5개의 rect가 grid 되는데 1개로 구현이 가능한지 궁금합니다..ㅠㅠ

    • BlogIcon 다크pgmr 2017.11.09 16:12 신고 수정/삭제

      제가 코드를 짜거나 한 것이 아니라서 딱히 뭐라고 말씀드리기가 그렇네요.. 직접 테스트해보시면 될 것 같습니다만 제 생각에는 모두 가능할 것 같습니다.

    • 베가 2018.04.20 17:58 신고 수정/삭제

      인접한 그리드셀에서 3-4개의 박스가 쳐진다고 하셨는데, iou가 50% 이상 인 것들 NMS(non max. suppression) 처리하지 못해서 발생하는 것 같아 보입니다.

  • yolo 2017.12.05 19:20 신고 ADDR 수정/삭제 답글

    안녕하세요 우분투 환경에서 윈도우 환경으로 넘어오면서 dll 파일로 실행하는 법을 알고 싶어서 질문 드립니다.
    본문에 dll을 만들어 쓰셨다고 하셨는데 제가 dll에 지식이 부족하여 제공되는 dll 파일 생성 후 제가 사용하고 싶은 프로그램에 코드구성을 어떻게 해야하는지 구글을 찾아봤지만 잘 이해가 안되서 도움을 구하고자 합니다...
    구현하신 응용프로그램파일 공유는 불가능 할 까요? ㅠㅠ 아니면 방법을 간단히라도 설명가능하신지 궁금합니다...

    • BlogIcon 다크pgmr 2017.12.05 22:07 신고 수정/삭제

      dll이라고 해서 특별히 다른 것은 없습니다. 리눅스 환경에서 라이브러리(lib) 사용하듯이 헤더화일을 include한 후에 헤더화일에서 제공되는 함수나 클래스를 동일하게 사용하면 됩니다. 윈도우즈에서 dll은 xxx.h, xxx.lib, xxx.dll 이렇게 3개의 파일로 구성됩니다. 헤더파일(xxx.h)은 include하고 lib파일(xxx.lib)은 link 시키고, dll파일은 생성되는 .exe 파일과 같은 폴더에 놓고 실행하면 됩니다.

    • yolo 2017.12.05 23:04 신고 수정/삭제

      답변 너무 감사드립니다.
      그렇다면 DARKNET에서 쓰이는 헤더와
      함수들을 모아 dll을 따로 만드셨다는 말씀이신지 궁금합니다.
      https://github.com/AlexeyAB/darknet/tree/master/build/darknet
      사이트에서 기본적으로 제공하는 yolo_cpp_dll.sln을 컴파일 하면 dll파일만이 생성되는데 lib파일과 .h파일은 따로 어떻게 생성해야할지 명시된게 없어서 고민하고 있었는데 선생님께서는 직접 dll 파일을 만드신건가요??
      제가 뭔가 잘못이해하고 있는거 같기도하고...

    • BlogIcon 다크pgmr 2017.12.06 01:19 신고 수정/삭제

      lib 파일은 dll 만들면 같이 자동으로 만들어지니 dll 파일이 생성된 곳을 다시 한번 찾아보시기 바랍니다. 그리고 .h 파일은 이것도 따로 만드는 것이 아니라 dll 만들 때 사용한 헤더파일과 같은 것입니다 (darknet-master\\src\\yolo_v2_class.hpp)

    • yolo 2017.12.06 20:37 신고 수정/삭제

      감사합니다 제가 이해가 부족했었습니다 !!
      덕분에 이해하는데 도움이 많이 되었습니다.

  • Beginner 2017.12.11 06:57 신고 ADDR 수정/삭제 답글

    다크님이 한대로 따라해봤는데, 아직 제가 부족하긴하네요, "yolo_cpp_dll_no_gpu.sln" debug 모드에서 컴파일을 하면, dll, pdb만생성되고, release 모드에서는 lib, exp, dll, pdb가 생성되는데 무슨 차이인지를 모르겠습니다. #define문도 꼼꼼히 봤는데 무슨 차이일지를 모르겠네요, 혹시 조언 가능하실까요?

    - 글 작성하고 일단은 해결했습니다. 정확한 이유는 모르고, Property 속성을 지우고, 다시 설정하니. 생성되네요. ㅠㅠ 간혹 이럴때 당황스럽긴합니다.

    • BlogIcon 다크pgmr 2017.12.11 08:24 신고 수정/삭제

      저는 release로 빌드한 거라서.. 그럼 문제와 해결법이 있는 줄은 몰랐습니다. 유용한 정보 감사합니다.

  • 아에이오우 2017.12.11 13:58 신고 ADDR 수정/삭제 답글

    다크님, 문득 궁금증이 생겨 급한데로 이 포스팅에 질문을 남겨봅니다.
    실무에서는 OpenCV를 전혀 사용하지 않나요?
    즉, 상용화 되는 어떤 소프트웨어에서 OpenCV 사용 여부 또는 빈도(?)가 궁금합니다.

    • BlogIcon 다크pgmr 2017.12.11 14:19 신고 수정/삭제

      실제 얼마나 사용되는지는 저도 아는 바가 없습니다. 하지만 굳이 사용되지 않을 이유는 없을 같습니다.

  • Beginner 2017.12.12 17:03 신고 ADDR 수정/삭제 답글

    혹시... 다크님은 OpenCV에서 프로그램 종료시 메모리 누수는 어떻게 해결하시나요? 저만 그런지는 모르겠지만, 웹에 나오는 방법으로는 다 해결되지 않더라고요, VS2015에서 사용중이고, dll 해제 문제라고 얘기하지만, 혹시, 제가 모르는 방법이 있나해서요?

    • BlogIcon 다크pgmr 2017.12.14 00:16 신고 수정/삭제

      딱히 신경쓰지 않고 있습니다. 제가 상용 프로그램을 만드는 것은 아니라서..

  • Say 2017.12.27 13:36 신고 ADDR 수정/삭제 답글

    안녕하세요 다크님. 최근 SSD, YOLO를 보다가 다크님도 YOLO를 했다는 걸 이제서야 봤네요..
    한가지 질문 드릴게 있습니다.

    지금 YOLO를 빌드해보려고 하고 있습니다. 일단 Github에 써져있는 순서대로 해보고 있구요.
    근데 빌드를 하면(경로 설정 다하고...등 일단 기본 세팅은 다했다고 생각) 계속 GPU쪽 함수들이 문제가 나더라구요..(예를들면 copy_ongpu 함수 등..)

    그래서 일단 blah나 cuda 코드를 보고 있는데
    분명 CPU관련 함수들은 다 정의가 되어있는데 GPU관련 함수들은 선언만 되어있고 정의가 되어 있지 않습니다.
    혹시 다크님은 이런 현상 없으셨나요?
    Github Issue나 이런데 찾아봐도 저랑 관련된 현상은 없었고...Cuda 8.0의 코드에서도 일단 저는 못찾았습니다..(계속 찾고는 있습니다.)

    아, 참고로 설정은( VS2015, Opencv 3.0, Cuda 8.0이구요, Cudnn은 있긴 있는데 아예 전처리에서 빼서 안쓰고 있습니다.)

    • BlogIcon 다크pgmr 2017.12.27 14:11 신고 수정/삭제

      글쎄요. 저는 특별한 문제없이 빌드가 잘 되어서.. 혹시 64비트(x64)로 빌드해야 하는데, 32비트(win32)로 빌드한 것은 아닌지 확인해 보시면 좋을 것 같습니다.

    • Say 2017.12.27 14:14 신고 수정/삭제

      아뇨...X64에 분명 설정은 다 맞췄습니다.

      "외부 기호를 확인할 수 없습니다"
      이거 문제는 링크 에러라고 생각되는데, 혹시 추가적으로 링크를 거신게 있으신가요? 추가적인 lib등....
      친절한 답변 감사드립니다.

    • BlogIcon 다크pgmr 2017.12.27 14:31 신고 수정/삭제

      이미 다운받은 프로젝트 설정에 필요한 라이브러리 파일들이 링크되어 있기 때문에 따로 추가할 사항은 없습니다. 말씀하신 내용으로 봐서 CUDA 라이브러리 링크에 문제가 있는 것 같습니다. 프로젝트 설정에 설정되어 있는 라이브러리 링크 경로가 실제 Say 님 PC의 CUDA 설치 경로와 일치하는지 확인해 주시고, link된 library 파일들도 해당 폴더 위치에 잘 있는지 확인해 보시면 좋을 것 같습니다. 만약 다른 부분이 있다면 프로젝트 설정을 Say 님 PC 경로에 맞게 수정해 주시면 되리라 생각합니다.

    • Say 2017.12.27 15:12 신고 수정/삭제

      일단 해결했습니다..
      링크가 제대로 연결은 되있었습니다. 문제는 props파일이었네요.
      개발하다보니 Cuda를 버전별로 여러개 깔았었는데 props 파일은 최신버전으로만 만들어져서 들어가네요...
      그래서 8.0 props가 없어서...여태까지 못읽고 있었습니다..

      신기한건 8.0이 아니라 Cuda 9.1로 해도 빌드가 잘 되네요. 아직 테스트는 못해봤지만..

      친절한 답변 감사합니다.

    • BlogIcon 다크pgmr 2017.12.28 09:55 신고 수정/삭제

      해결이 되셨다니 다행입니다. 그리고 참고가 되도록 문제 원인도 남겨주셔서 감사합니다.

  • 댑초보 2018.03.09 16:12 신고 ADDR 수정/삭제 답글

    질문하나 올립니다ㅠㅠ
    일단 전 win10 i7 nvidia gpu1050ti 이구요. vs2013이랑 cuda 8.0인데요.
    전 다크님이랑 조금다르게 전 darknet 솔루션을 실행해서 빌드를 시도했어요. 위에 말씀하셨던,그 솔루션파일제거하고 darknet.vcxproj 요거 편집해서 시도했는데,
    오류가 뜨더라구요.
    cuda관련 오류도아니고 뭔가 좀,,, 제가잘몰라서ㅠㅠ

    오류 1870 error C2440: '=' : 'image'에서 'int'(으)로 변환할 수 없습니다.
    오류 2162 error C2275: 'list' : 이 형식을 식으로 잘못 사용했습니다.
    오류 2269 error C2065: 'd' : 선언되지 않은 식별자입니다.
    이런 기본적인 오류가뜨니깐 당황스럽네요..
    이런게 403개가 떴는데.. 코드 안에 내용을 건든게 아닌데 왜이러는지... 혹시 아시는분들 댓글 달아주시면 감사하겠습니다 ㅠㅠㅠ

    • marshall 2018.03.23 17:27 신고 수정/삭제

      저도 같은 환경에서 에러가 뜨네요...
      cuda 8.0
      센텐스 컴파일 에러같은데..
      이게 왜뜨는건지;;;;
      ㅡ,.ㅡ

  • kkid2 2018.03.20 14:28 신고 ADDR 수정/삭제 답글

    포스팅 잘 봤습니다.
    질문이 하나 있습니다.
    혹시 yolo 학습할때 멀티 GPU로 할려면 SLI 브릿지가 필요한가요?

  • 딥러닝학생 2018.07.22 10:34 신고 ADDR 수정/삭제 답글

    혹시 yolo9000도 돌려보셨나요?? 같은 cfg파일이랑 같은 weight파일을 데모로 돌려본정도만 해봤는데, 9000의 trree나 label등은 이해가 안가네요..
    제가 가진 데이터베이스로 새롭게 학습하고 tree구조도 변경해보고싶은데,,, 이런 내용에 대한 글이없어서 답답해서, 글 남겨봅니다.~

역수와 역행렬

수학 이야기 2017.08.12 15:48

3의 역수는? 1/3


그럼 '역수'란? ...


역수를 구하는 방법은 알아도 역수가 무엇인지는 모르는 경우가 많다.


마찬가지로 역행렬이 무엇인지 물어보면,


학생 1) 1/(ad-bc) * [d -b; -c a]


학생 2) 곱해서 항등행렬(I)이 나오는 행렬


물론 두번째 대답이 정확한 대답이다. 만일, 이와 같이 바로 답할 수 있다면 이 학생의 수학실력이나 앞으로의 공부에 대해서는 걱정할 필요가 없을 듯 하다.


그런데, 학생 2와 같이 대답한 경우에도 사실은 한번 더 확인할 필요가 있다. 그걸 그냥 지식처럼 알고 있는 것인지, 아니면 정말 이해한 것인지


만일 대학생에게 두 행렬의 곱 AB의 역행렬이 무엇이냐고 물어보면 아마도 대부분 B-1A-1라고 자신있게 대답할 것이다 (물론, A-1B-1인가? 하는 학생도 분명 있다). 하지만, B-1A-1가 역행렬인 이유를 증명해봐라 하면 대부분 당황해 한다.


'증명'이라는 말만 들어도 사고기능이 정지하는 경우도 있고 역행렬의 의미를 제대로 이해하고 못한 경우도 있을 것이다. 하지만 그 증명은 정말 간단하다.


증명: AB에 B-1A-1를 곱하면 AB * B-1A-1 = I이다. 따라서, AB의 역행렬은 B-1A-1이다. 끝.


역행렬의 정의를 정확히 이해하고 있다면 당연히 풀수 있는 문제이다. 또한 역행렬의 정의를 안다면 AB의 역행렬이 A-1B-1인지 B-1A-1인지 혼동할 이유도 암기할 이유도 없다. 그리고, 정의로부터 kA의 역행렬은 1/kA-1, ABC의 역행렬은 C-1B-1A-1, PAP-1의 역행렬은 PA-1P-1, 대각행렬 diag{c1, c2, ..., cn}의 역행렬은 diag{1/c1, ..., 1/cn}임도 손쉽게 알 수 있다.


☞ 어떤 수의 역수는 자신과 곱해서 (곱셈에 대한 항등원인) 1이 나오는 수입니다.


☞ 2018.8.14일자 댓글을 참고로 적습니다: 두 행렬의 곱 P = AB가 full-rank square matrix 일 때 inv(P)가 존재하고, 또한 A와 B 각각은 full-rank square matrix가 아닐수도 있으므로 inv(A)나 inv(B)는 존재하지 않을 수도 있습니다. 따라서 만약 AB의 역행렬이 존재한다면 그것의 정확한 표기는 inv(B)*inv(A)가 아니라 inv(AB) 라고 해야합니다.


by 다크 프로그래머


'수학 이야기' 카테고리의 다른 글

아이와 수학 공부하기  (3) 2017.11.15
역수와 역행렬  (6) 2017.08.12
Gram–Schmidt(그람-슈미트) 직교화  (6) 2017.05.17
곱셈과 덧셈  (2) 2017.04.26
  • 질문 2017.08.15 09:35 신고 ADDR 수정/삭제 답글

    안녕하세요. 오랜만에 수학 보면서 블로그 방문 자주 하고 있습니다. 먼저 감사드립니다.
    mahalanobis distance를 보다 역행렬 올려주셔서 두개 묶어서 질문 드리려고 합니다.
    1차원의 MD는 이해가 되었는데, 2차원의 MD에서의 식이 잘 이해가 되지 않아 혹시 아실까 해서 여쭤봅니다. transpose와 공분산의 역행렬은 왜 들어가는지..모르겠습니다..ㅠㅠ

    • BlogIcon 다크pgmr 2017.08.15 21:26 신고 수정/삭제

      안녕하세요. 질문하신 내용에 대한 정확한 설명은 다소 긴 수학적 설명과 배경설명을 필요로 합니다. 간단히 댓글로 설명하기에는 어려움이 있습니다. 일단 직관적으로만 설명해보면 열벡터 x가 있을 때 x^T*x는 x의 길이(norm)의 제곱이 됩니다. 따라서, 평균이 벡터 m이라고 하면 (x-m)^T*(x-m)은 데이터 x와 평균까지의 거리^2(Euclidean distance)입니다. 그런데, MD는 데이터와 평균까지의 거리를 그 방향으로의 표준편차로 나눈 값입니다. 공분산행렬의 역행렬을 곱하는 것은 나누기의 의미를 갖습니다. 즉, 공분산 행렬 Σ에 대해, (x-m)^T * Σ^-1 * (x-m)은 x와 평균관의 거리의 제곱을 분산으로 나누는 의미가 됩니다. 따라서 여기에 sqrt(제곱근)를 씌우면 MD가 됩니다.

  • 질문2 2017.08.15 15:47 신고 ADDR 수정/삭제 답글

    안녕하세요, 저도 요즘 아주 블로그 잘 보고 있습니다. 데이터 분석을 하던중 MLE(최대가능도)에 대한 이론이 많이 나오더라구요..... MLE,,,이해할 듯 말듯 합니다... 이론적으로 이해를 하려니 와닿지가 않고,, 예를 들어 어떻게 이해해야할까요?

    • BlogIcon 다크pgmr 2017.08.15 21:27 신고 수정/삭제

      MLE에 대해서는 http://darkpgmr.tistory.com/119 글을 보시면 좋을 것 같습니다.

  • 진지충 2018.08.14 13:04 신고 ADDR 수정/삭제 답글

    두 행렬의 곱 P = AB가 full-rank square matrix 일 때 inv(P)가 존재하고, 또한 A와 B 각각은 full-rank square matrix가 아닐수도 있으므로 inv(A)나 inv(B)는 존재하지 않을 수도 있습니다. 따라서 만약 AB의 역행렬이 존재한다면 그것의 정확한 표기는 inv(B)*inv(A)가 아니라 inv(AB) 라고 해야합니다.

    • BlogIcon 다크pgmr 2018.08.14 13:38 신고 수정/삭제

      네 맞습니다. 좋은 의견 감사합니다. 다른 분들도 참고할 수 있도록 본문 말미에 말씀하신 내용을 추가하였습니다.