ConvNet (CNN) 이해하기

지난 시리즈에서는 뉴럴넷 중 가장 단순한 형태인 MLP, dense (fully connected) layer만을 사용하는 뉴럴넷과 이를 학습시키는 방법에 대해서 살펴보았다. MLP를 사용하면 효과적으로 비선형 함수를 모사할 수 있었고 이 덕분에 기존의 선형함수 기반 모형에 비해 훌륭한 성능을 낼 수 있었다.

(1) 선형 분류기
(2) 퍼셉트론과 신경망
(3) 학습에는 왕도가 없다
(4) 디테일

그러나 실제 데이터를 올바르게 분류하거나 회귀할 때에는 이보다는 복잡한 구조가 필요한 경우가 있다. 다음의 몇 가지 상황을 생각해보자.

1) MLP에서는 별도의 feature engineering 없이 raw feature 곧바로 입력층에 넣었었다. 붓꽃 데이터, 또는 데이터의 차원이 크지 않은 경우에는 raw feature를 전부 사용해도 모형의 파라미터 수가 크지 않았기 때문에 학습 과정에서 문제가 생기지 않았고 성능도 좋았지만, 이미지와 같은 데이터에서는 문제가 달라진다.

이미지 데이터를 예시로 들어보자. 가로 48픽셀, 세로 48픽셀의 컬러(RGB) 이미지 데이터를 생각해보자. 이미지의 각각의 픽셀을 하나의 feature 사용해서 MLP 입력층에 넣을 있을 것이다. 이렇게 feature engineering 없이 픽셀의 raw value 전부 입력으로 넣는다면, 뉴럴넷이 감당해야 하는 feature 차원수는 48 \times 48 \times 3 = 6912 된다. 겨우 가로세로 48픽셀밖에 안되는 저화질 이미지였는데도 feature 차원이 7000 달한다. Feature 갯수가 이렇게 많아지게 되면 컴퓨팅 속도가 저하되고 오버피팅의 위험이 생길 있다.

2) MLP에서는 샘플이 등장한 맥락을 고려하지 않았다. , 샘플들이 정렬되어 있는 순서가 중요하지 않았다. 그러나 주식 일별 종가, 문장 속 단어와 같은 데이터에서는 각 샘플의 앞 뒤로 어떤 샘플들이 있었는지의 정보(‘문맥’)도 중요하다. 이 경우엔 MLP만으로는 충분히 좋은 성능을 발휘할 수 없다.

이번 시리즈에서는 전통적인 dense layer 외에 이미지 등의 데이터를 처리하기 위해 새로이 고안된 뉴럴넷의 레이어에 대해서 살펴보고자 한다. 시작은 convolutional neural network (CNN; ConvNet) 구성하는 레이어들이다.

 

  • 2-D CONV layer
    • Convolution 연산
    • 수학/신호처리학적 의미
  • RELU layer
  • POOL layer
  • 일반적인 ConvNet 구조
  • ConvNet 개선하기
    • 1×1 convolution (InceptionNet)
    • Dense CONV 표현하기
    • 변형된 convolution

 

Convolutional (CONV) layer

앞의 예시에서 이미지의 픽셀을 그대로 feature 사용하는 것은 좋지 않은 방법이라는 것을 언급했었다. 대신 이미지로부터 독특한 특성만을 뽑아내어 feature 사용한다면 좋은 성능을 있을 것이다. 과정을 feature extraction이라고 하고, 이미지에서 feature extractor 동작하는 레이어가 바로 convolutional layer이다.

Convolutional layer 가지 가정을 전제로 한다.

  1. Local connectivity: 이전 레이어의 모든 뉴런과 연결되는 MLP에서와는 달리 CONV layer는 이전 레이어의 뉴런 중 일부와만 연결된다. 즉 이미지의 모든 픽셀과 연결되는 대신 이미지 중 일부분의 픽셀과만 연결된다.
  2. Spatial invariance: 이미지의 한 부분의 데이터 분포는 다른 부분에서의 데이터 분포와 다르지 않다. , 이미지의 분포적인 특성은 어느 부위에서든 동일하다고 가정하는 것이다.

Dense layer에서 입력 샘플을 1차원의 벡터 데이터로 보았다면, Convolutional layer 입력 샘플을 3차원의 텐서(Tensor) 데이터로 인식한다. Convolutional layer 입력 3차원 데이터를 적절히 변형해서 또다른 3차원 데이터를 출력한다.

스케치

Convolutional layer 하는 일을 자세히 살펴보자.

  1. 먼저 이미지에서 특징적인 부분을 추출하는 데에 사용될 필터(또는 커널)가 정의되어야 한다. 필터 크기는 이미지 크기보다 작거나 같다. 필터는 인풋 이미지를 시작부터 끝까지 차례차례 훑으면서(마치 sliding window처럼) 이미지 픽셀 값에 필터 값을 곱해 더한 값을 출력한다.
  2. 필터가 이미지를 얼마나 자세히 훑으면서 지나갈지를 결정해야한다. 이것을 stride라고 한다. Stride 1로 정의된 경우, 필터는 이미지 위를 한 번에 한 픽셀씩 이동하면서 자세히 훑는다. Stride 10으로 정의된 경우, 필터는 이미지 위를 한 번에 10픽셀씩 이동하면서 대충 훑는다. (가로방향 stride와 세로방향 stride를 다르게 설정할 수도 있다)

스케치

f_{ij}는 필터의 ij열 값, x_{ij}는 인풋 이미지의 ij열 값이다.

convolutional layer는 필터를 일정 간격씩 이미지 위에서 이동시키면서 필터 값을 이미지 픽셀값에 곱하여 더한 값을 출력한다. 출력된 feature map의 픽셀 하나는 인풋 이미지 중 3×3만큼의 정보를 바탕으로 결정된 값이다. feature map receptive field 크기는 3×3이 된다는 뜻이다. 인풋 이미지 중 3×3만큼을보고‘ Feature map의 픽셀 하나의 값을 계산했다는 의미다.

애니메이션으로 살펴보면 이해가 쉽다. 파란색은 인풋 이미지, 초록색은 필터이다.

1*VVvdh-BUKFh2pwDD0kPeRA@2x

초록색 필터가 이미지를 칸씩(stride=1) 돌아다니면서 곱의 합을 출력하는 것을 있다. 이렇게 출력된 (convolved feature 또는 feature map; 붉은색) 추출된 이미지의 특징이라고 생각하여 feature 사용할 있다.

필터 하나 하나의 feature map 만들어지므로, 필터 n개를 사용하는 CONV layer 출력은 depth=n 갖는 텐서가 된다. 만약 32×32짜리 컬러(depth=3) 이미지 하나가 필터 10개를 사용하는 CONV layer 통과하면 출력 depth 10 된다.

1*BSLjlJf31gj98ABJMCt3-g@2x

수학/신호처리학에서의 cross-correlation

주의해야할 것은 수학에서 정의하는 convolution 연산과는 다른 연산이라는 것이다. 오히려 뉴럴넷에서의 convolution 연산은 수학/신호처리에서의 cross-correlation 같다.

신호처리에서 cross-correlation은 두 신호간의 유사성을 잴 때에 사용되는 연산이라고 한다. 때문에 뉴럴넷에서의 convolution convolution filter input image 사이의 유사성을 측정해서 출력하는 연산이라고 생각할 수 있다. 필터와 이미지의 패턴이 유사하다면 절대값이 큰 값을, 그렇지 않다면 작은 값을 반환하는 것이다.

예를 들어, 아래처럼 우상에서 좌하로 향하는 사선 모양의 convolution filter는 이미지 내에서 사선 모양이 있는 부분(주로 이미지의 윤곽선)을 보면 큰 값을 출력한다. 아래 돌고래 이미지에서 우상좌하 사선 모양의 윤곽선이 도드라지게 추출된 것을 확인할 수 있다.

실제 ConvNet에서는 필터를 우리가 직접 정해주지 않고 알고리즘이 데이터를 바탕으로 문제 해결에 적합한 형태가 되도록 학습해나간다.

Zero padding

이미지에 필터를 적용할 때, 아무리 촘촘히(stride=1) convolution을 해도 출력된 feature map의 가로세로 크기는 원본 이미지에 비해 반드시 작아질 수 밖에 없다. 원본 이미지와 가로세로 크기가 같은 feature map을 얻기 위해서는 필터를 적용하기 전에 입력 이미지에 처리를 해주어야 한다.

1*W2D564Gkad9lj3_6t9I2PA@2x

단순하고도 널리 사용되는 방법이 바로 zero padding, 즉 원본 이미지의 상하좌우를 0값으로 둘러싸는(padding) 방법이다. 아무 정보가 없는 0값으로 이미지를 패딩함으로써 feature map의 가로세로 크기를 인풋과 같게 유지하면서 convolution layer를 깊게 쌓을 수 있다.

 

ReLU layer

CONV layer 통해서 이미지로부터 추출한 feature map에서 양의 값만을 활성화시키는 레이어다. ReLU layer에서는 feature map에서 특히나 두드러지는 특징을 다시 추출한다.

사실 별도의 layer라고 칭하기는 뭣하고, CONV layer activation function으로 ReLU 사용한 것이라 이해하면 쉽다.

output_19_0

ReLU activation 적용 후 우상좌하 사선 모양의 윤곽선이 매우 잘 추출되었다.

 

POOL layer

수많은 이미지를 처리하는 과정에서 필연적으로 맞딱뜨릴 수 밖에 없는 것이 바로 메모리 문제다. 특히나 CONV layer는 원본 이미지의 가로세로 크기를 유지하면서 depth를 수백~수천 수준으로 키우기 때문에 메모리를 많이 먹는 레이어다. 이때문에 이미지와 feature map의 가로세로 크기를, 특징은 유지하되 적절한 수준으로 다운샘플링하여 메모리를 절약할 필요가 있다. 다운샘플링 방법 중 ConvNet에서는 pooling을 사용한다.

가장 빈번히 사용되는 풀링은 max pooling이다. Max pooling pool region 내에서 가장 수치가 위치의 값만을 가져온다.

1*GksqN5XY8HPpIddm5wzm7A

2×2 pool size, stride 2 max pooling 적용한 모습이다. 2×2 pool region 내에서 가장 수치가 값만을 샘플링한 것을 있다.

Weakly-supervised localization 등의 문제를 해결할 때에는 average pooling 사용하기도 한다. Average pooling 해당 pool region 내의 모든 값을 평균내어 가져온다.

돌고래 이미지의 예시에 2×2 max pooling (stride 2) 적용한 결과, 아래와 같이 feature map 특징은 유지하면서 이미지 크기를 1/4 축소할 있었다.

output_20_0

 

ConvNet 일반적인 구조

일반적으로 ConvNet의 구조는 다음과 같이 표현할 수 있다.

\{(CONV + RELU) \times n + POOL \} \times m + (Dense \times k)

여기서 CONV + RELU + POOL feature extractor 역할을 하고 Dense layer classifier 또는 regressor 역할을 한다. 이미지 분류 문제를 예시로 들자면, CONV + RELU + POOL 인풋 이미지로부터 분류에 사용할만한 특징적인 feature 추출하고 Dense layer 추출된 feature 입력받아 이미지를 적당한 카테고리로 분류한다.

이 때 얕은(입력층에 가까운) CONV layer일수록 단순한 특성윤곽선, 음영 등을 추출하고 깊은(출력층에 가까운) CONV layer일수록 복잡한 특성동물 모양, 특정 색상 조합 등을 추출한다.

2012 ILSVRC에서 우승한 AlexNet이 유행시킨 구조라 할 수 있겠다. 딥러닝을 사용해서 효과적으로 이미지를 분석할 수 있다는 것을 보여준 첫 사례다.

1*qyc21qM0oxWEuRaj-XJKcw

그림에서 있듯, 5개의 CONV layer 3개의 dense layer 사용하여 최종적으로 1000 카테고리에 대한 softmax 값을 출력한다. AlexNet 대해서는 이후 기회가 자세히 다루도록 한다.

 

ConvNet 개선하기

1×1 convolution

어느 모형에서나 파라미터 수가 지나치게 많아지는 것은 overfitting 컴퓨팅 속도 저하를 의미하기에 좋지 않다. convolution 연산에 사용되는 파라미터 (필터값 ) 줄이기 위해서 1×1, 1xn 또는 nx1 convolution 사용할 있다.

n \times n \times 3 형태의 인풋 이미지에 receptive field 3×3 되도록, 128개의 필터를 사용해서 convolution 한다고 가정해보자. 단순히 3×3 filter 사용할 수도 있다. 경우 필요한 파라미터 수는 3 \times 3 \times 3 \times 128 = 3456개이다.

반면 1×1 > 1×3 > 3×1 순서로 convolution 한다면? 필요한 파라미터 수는 (3 \times 1 \times 1 \times 128) + (1 \times 1 \times 3 \times 128) + (1 \times 3 \times 1 \times 128) = 384 + 384 + 384 = 1152 뿐이다. 같은 크기의 receptive field 유지하면서 파라미터 수를 거의 1/3 수준으로 줄였다!

inception-v4-fig-5

구글에서 개발한 GoogLeNet에서 바로 이 방법을 활용한 Inception 구조를 사용한다.

Dense layer CONV layer 표현하기

Dense layer CONV layer 차이점은 local connection 뿐이다. Dense layer에서는 이전 레이어의 모든 뉴런이 다음 레이어의 모든 뉴런과 연결되어 있는 반면(그래서 fully connected layer라고도 불린다), CONV layer에서는 이전 레이어의 일부분만이 다음 레이어의 뉴런과 연결되어 있다.

그럼 CONV layer에서 이전 레이어의 모든 뉴런을 다음 레이어와 연결시킨다면? 즉 인풋 이미지의 일부분에만 필터를 적용시키지 않고 이미지 전체에 이미지와 동일한 크기의 필터를 적용시킨다면? Dense layer와 동일한 연산을 하는 CONV layer를 만들 수 있다. 계산해보면 파라미터 수도 일치한다.

스케치

Dense layer CONV layer로 대체함으로써 인풋 이미지 크기를 고정하지 않아도 된다는 이익을 얻을 수 있다. 사전에 정의된 크기의 이미지를 인풋하지 않으면 오류를 뿜는 Dense layer와는 달리, CONV layer는 사전 정의된 것보다 큰 이미지를 인풋해도 오류 없이 연산을 해낸다. (다만 3차원 텐서 형태로 출력하기는 한다)

1*wRkj6lsQ5ckExB5BoYkrZg

Fully Convolutional Network (FCN)이 바로 이 구조를 처음 제안한 모형이다.

특수한 Convolution

외에도 위에서 정의한 것과는 다른, 서로다른 문제에 특화된 특수한 convolution 사용할 수도 있다. 예를 들어 atrous convolution 구멍이 숭숭 뚫린 듯한 모양의 필터를 사용해서 receptive field 더욱 향상시킨다. Deconvolution Convolution 연산을 역으로 수행해 추출된 feature map 원본 이미지에 가까운 형태로 되돌린다.

특수한 convolution 연산들에 대해서는  페이지를 참고하면 좋다.

 

참고

Google Duplex: 인공지능-인간간 대화를 꿈꾸다

3일쯤 전에 있었던 구글 IO 2018 키노트에서는 구글 포토의 신기능, 어시스턴트의 새로운 목소리, 새로 디자인된 TPU 3.0 등등 많은 업데이트가 있었다.

아니나 다를까 AI와 딥러닝은 이 모든 업데이트들을 관통하는 핵심 제재였다. 안드로이드 신기능 중 상당수는 어시스턴트, 렌즈와 같이 AI에 뿌리를 두는 기술들이었고 새로 발표한 TPU 역시 딥러닝에 특화된 하드웨어라는 점에서 그러했다.

이처럼 AI 관련 업데이트가 많을거라 예상은 했지만, 개 중에서 특히나 눈을 휘둥그레지게 한 기능이 있어 간단히 다뤄보고자 한다. 바로 Google Duplex라 명명된 기능인데, 상용화된다면/혹은 상용화되기 전부터 상당히 큰 파장을 일으킬 것으로 생각된다.

 

Google Duplex?

OpenTable 등 온라인 예약 서비스 시장이 꽤나 활발한 북미 시장에서도 소규모 영업장과 같이 온라인 예약을 지원하지 않는 경우에는 사람이 직접 전화를 걸어서 예약을 해야했다. 그런데 Google Duplex는 사람에게 명령을 받은 구글 어시스턴트가 직접 영업장에 전화를 걸어서 예약을 한다.

백문이 불여일견이다.

 

영상에서 소개된 실제 Duplex-사람간 통화에서 주목할만한 점은

  1. 액센트, 인토네이션이 완벽에 가깝다. 타사의 음성 기반 어시스턴트를 사용할 때 느껴지는 약간의 어색함이 없다.
  2. hmm, um.. uh, 같은, 사람이 생각할 때에 사용할만한, 의미 전달과는 관계가 없는 표현을 사용할 수 있다. (자연어처리, 음성생성 분야에서는 이런 단어들을 speech disfluency라 한다)
  3. 상대의 발화에 따라 대답까지의 딜레이 시간을 조절한다. “여보세요?”같은 짧은 발화에는 빠르게 대답하는 한편, “정오에는 예약이 불가능해요”같은 긴 발화에 대해서는 대답하기까지의 딜레이가 조금 더 길다.
  4. 뜻 밖의 시나리오에도 대응할 수 있다. “5명 이상인 경우에만 예약이 가능해요. 그냥 매장에 오세요”라는 말에 “그냥 가면 오래 기다리나요?”라고 물어볼 수 있다.

사실 대화 내용 전체가 주목할 만 하다. 그저 놀랍다.

 

Duplex의 아키텍처

개인적으로는 알파고 이상의 충격을 받았던 터라 그 아키텍처가 심히 궁금해서 찾아보았는데, 아직까지 공식적으로 공개된 디테일은 거의 없었다.

구글 공식 AI 블로그에 공개된 매우 단순화된 아키텍처는 다음과 같다.

뉴럴넷에 인풋으로 들어가는 Feature는 세 가지 정도로 분류할 수 있다. (1) 대화 상대방의 음성 신호. (2) 1의 음성 신호로부터 추출한 발화 텍스트. 텍스트 추출에는 구글이 직접 개발한 ASR(automatic speech recognition)이 사용된다. (3) 발화가 이루어진 환경, 문맥과 관련된 정보들. 이전까지 나눈 대화라던가, 어시스턴트가 사람에게 하달받은 명령, 대화 중인 영업장의 업종, 대화 중인 시간 등의 정보가 사용되는 듯하다.

이 Feature들로 RNN(recurrent neural network)을 돌린다고 한다. (아직 개발 중이니 당연하겠지만 디테일이라곤 찾아볼 수 없는 설명이다. 나중에라도 세부 내용을 좀 더 알려줬으면 좋겠다) RNN은 인풋으로 들어온 상대방의 발화에 대해 어시스턴트가 대답할 내용을 텍스트 형태로 출력한다.

RNN에서 출력된 텍스트를 구글의 TTS(text-to-speech) 시스템이 음성 신호로 변환한다, 즉 “읽는다”. 사람만큼이나 자연스럽게 말하게 하기 위해 딥마인드의 WaveNet과 구글브레인의 Tacotron을 사용하는 음성합성 엔진을 사용한다고 한다.

요약하자면 그냥 [음성신호와 발화내용과 문맥 -> RNN -> 대답할 텍스트 -> TTS -> 대답 음성]이 전부다. Duplex의 실제 통화 음성을 들었을 때의 충격에 비하면, 현재까지 발표된 내용에서는 기술적으로 대단한 부분은 딱히 없다. 이후의 발표가 더욱 기대되는 이유다.

추가적으로 실제 통화가 이루어지는 중에 사람이 개입해서 올바른 대화를 지시할 수 있도록 real-time supervised learning을 사용했다고 한다.

 

한계

Duplex도 한계는 명확하다. Duplex가 이렇게 자연스러운 대화를 할 수 있는 도메인은 오직 “특정 영업장에 서비스를 예약하고자 할 때”, “영업시간 등의 영업장 정보를 묻고자 할 때 뿐이다. 상기된 것과 다른 목적의 대화 또는 목적이 없이 시작되는 일상 대화(small talk)는 할 수 없다.

사실 이건 Duplex의 문제라기보다는 현 시대 인공지능의 한계, 또는 자연어처리 문제의 내재적인 복잡성이라고 생각할 수 있다. 작년 11월에 아마존이 주최한 Alexa Prize 2017에서는 음성 어시스턴트 알렉사가 가장 오랫동안 일상적인 대화를 이어나가게 하는 팀에 총 백만달러의 상금을 걸기도 했었다 (1등 팀이 10분 22초라는 성적을 냈다). 50만 달러를 가져갈 수 있었던 이유가 고작 10분간의 대화라니, 이 문제가 얼마나 어려운 문제인지 알려주는 예시라 할 수 있겠다. 누군가는 사람과 20분 자유대화를 할 수 있는 프로그램을 개발하는 것은 “달 착륙 수준이 아니라, 화성 여행을 하는 것이나 마찬가지”라고 평가했었다.

 

의의와 영향

Duplex가 발표됨에 따라 기술과 규제의 측면과 사회윤리적 측면에서 다양한 논의를 해볼 수 있는 주제가 던져졌다고 본다. 여기서는 짧은 시간동안 생각해본 몇 가지만 다뤄보았다.

첫 번째는 인공지능이 할 수 있는 것의 영역에 대한 이야기다.

인공지능과 딥러닝이 일궈온 놀라운 성과가 있었음에도, 지금까지 혁신적인 성과가 있었던 것은 주로 이미지/영상 인식 및 생성 분야였다 (CNN, DCGAN). 물론 문맥이 있는 데이터, 특히 자연어 처리에서도 이에 버금가는 성과가 있었다고 알고는 있었지만, 사람이 대화 상대가 기계일지도 모른다는 생각조차 하지 못할 정도로 발전했는지는 미처 알지 못했다.

인공지능이 뭔가를 할 때마다 나오는 말 같아서 식상하지만, Duplex는 이런 점에서 다시 한 번 ‘인공지능이 할 수 있는 것’의 영역을 크게 넓혔다고 생각된다. 어쩌면 이번에 넓힌 영역의 크기는 알파고가 했던 것 그 이상일지도 모른다.

두 번째는 사회적, 윤리적 영향에 대한 이야기다.

1)

Duplex가 발표되고 나서, 트위터를 비롯한 몇몇 포럼에서는 많은 의견이 오갔다. 기술 발전에 놀라워 하는 의견이 대부분이었지만 몇몇은 끔찍한 아이디어라고 평가하기도 했다. Duplex를 끔찍해하는 사람들의 의견에는 인간 특유의 것이라 믿었던, 즉 인간성에 대한 배신감이 서려있다. 더 이상 실시간 대화는 (특정 분야의 대화에 한해서는) 사람만의 것이 아니다.

바둑에서도 한 차례 이런 일이 있었지만 그 때는 이처럼 거부감이 크지는 않았다. Google Duplex에 대한 거부감이 큰 것은 Duplex가 정복한(것으로 보이는) 분야가 하필 대화이기 때문일 것이다.

인간의 언어를 사용한 대화는 실로 인간만 하는 행위이(었)다. 지능이 높은 동물들도 대화를 한다고는 알려져 있지만, 우리의 언어를 사용하지는 않았다. 사람의 말로 자연스럽게 대화할 수 있는 능력은 곧 인간성을 구성하는 핵심 중 하나였다. 곧, 대화에 자연스럽게 참여하는 모든 대상은 사람으로 간주할 수 있다는 뜻이었다.

물론 Google Duplex 이전의 어시스턴트도 자연스러운 대화가 가능했다. 하지만 이때는 목적을 가지고 대화를 시작하는 주체가 항상 사람이었다. 어시스턴트는 인간의 명령을 대기하고 있을 뿐이었다. 초기발화주체가 항상 사람이라는 일방성이 존재했기 때문에 우리는 발화 상대가 인간이 아님을 알 수 있었고, 따라서 거부감이 느껴지지 않았다.

Google Duplex를 탑재한 어시스턴트는 “인간성”을 획득함과 동시에, 기존 어시스턴트에 존재했던 발화의 일방성을 깨버렸기 때문에 문제가 된다. 이제는 인공지능이 먼저 목적을 가지고 발화를 시작한다. 경우에 따라서는 사람을 수동적인 존재로 만드는 듯한 느낌까지 준다. 사람(영업장의 직원)이 인공지능(구글 어시스턴트)의 발화를 기다리는 것 같은 상황이 연출된다.

2)

요즘들어 젊은 세대의 통화공포증에 대해 연구가 진행 중이라고 한다. ‘공포증’이라 이름붙일만한 수준은 아니지만 본인도 통화를 꺼리고 메신저를 선호하는데, 비슷한 생각을 하는 이들의 의견을 종합해보면 그 이유는 이렇다.

  • 발화는 수정이 불가능하다.
  • 물음과 답변 사이의 긴 딜레이가 용납되지 않는다. 준비할 수 없는 느낌이다.
  • 주로 메신저를 사용하는 등, 안하다보니 통화가 필요한 상황에서도 하기가 겁난다.

Duplex는 마치 이 문제를 해결하기 위해서 개발된 듯하다. 대부분의 “통화가 필요한 상황”은 예약이나 영업시간 질문 등을 위한 것이니, 어시스턴트가 전화를 대신 해주면 전부 해결된다. 유일한 문제는 이게 근본적인 해결책이 아니라는 데에 있다.

 

혼란 속에서 커뮤니티엔 이런 토의주제가 등장했었다:
“당신이 대화하는 대상이 사람이 아니라는 것을 의무적으로 밝히도록 해야 하는가?”

 

맺으며

구글에 의하면 Duplex 기능은 지난 몇 년간 개발되어 왔고, 앞으로도 상용화까지는 상당한 시간이 더 필요할 것이라고 한다.

당장의 문제는 아니지만 자율주행차 논의와 함께 대화봇 논의도 지금보다 활발히 진행될 필요가 있다고 본다. 충분히 대비해서 해로울 것은 없다.

Duplex가 끼칠 영향이 마음 한 켠에선 걱정되는 한편, 실은 이 기술이 가져다줄 미래가 기대되는 마음이 훨씬 더 크다. 당장 오늘 해야하는 전화도 Google Duplex가 있었다면 (그리고 한국어를 지원한다면) 난 주저않고 어시스턴트에게 부탁했을 것이다.

아키텍쳐가 더 자세하게 공개가 된다면 이 내용도 기회가 될 때 다루고싶다.

 

Logistic, cross-entropy loss의 확률론적 의미

머신러닝을 공부하다보면 logistic을 참 많이 접하게 된다. 당장 로지스틱 회귀만 해도 그렇고, 딥러닝에서 자주 사용하는 saturating non-linearity 중 하나인 softmax function도 logistic function의 multi-class 버전이니 말이다.

Logistic(또는 softmax) function은 어떤 값들을 (0, 1) 사이의 값으로 squash하면서, 동시에 값들의 총 합이 1이 되도록 하는 성질이 있는데, 이 결과 logistic function의 함수값이 Kolmogorov의 확률의 정의에 부합하기 때문에 주로 값들을 확률화하는 함수로 쓰인다. 딥러닝에서 분류문제를 풀때 output layer의 activation function으로 자주 쓰이곤 하는 이유도 여기에 있다 (각 클래스의 ‘확률’ 값을 계산하기 위해).

그런데 하고많은, (0, 1)에 bounded되어있고 합이 1이 되는 함수들 중에서 굳이 logistic function을 사용하는 이유는 뭘까? 그건 바로 logistic function이 확률값에서부터 자연스럽게 유도되는, 내재적으로 확률의 성질을 가지는 함수이기 때문이다. 이 글은 logistic이 그냥 이유없이 확률처럼 생겨서 만들어지고 사용되는 함수가 아니라는 것을 증명해보는 지루한 글이다. Logistic function은 내재적으로 cross-entropy loss와 깊은 연관이 있는데, 이 로스를 줄이는 것이 왜 classification을 해결하는 과정이 되는지 역시 같은 맥락에서 함께 살펴볼 것이다.

 

Odds, Log odds, Logit, 그리고 Logistic

어떤 사건이 일어날 확률은 P(x) 외에도 다양한 방법으로 표현될 수 있다. Odds가 그 종류 중 하나다. 주로 질병통계학이나 도박과 같이 카테고리가 두 개(성공과 실패/발병과 비발병)인 분야에서 자주 사용하는 표현인데, 로지스틱 함수의 확률론적 의미는 바로 여기에서부터 시작한다.

발생 확률(또는 성공 확률)이 p인 어떤 사건 A의 Odds는 다음과 같이 나타낼 수 있다.

Odds(A) = \frac{p}{1-p}

즉, Odds는 성공 확률이 실패 확률에 비해 얼마나(몇 배나) 더 큰가?를 나타내는 척도라고 해석할 수 있다. Odds가 클수록 성공확률이 큰 것이다. Odds는 평범한(?) 확률값 p에 비해 성공확률값의 변화에 민감하다는 특징이 있다. 또한 질병통계학에서는 relative risk 등의 다른 표현에 비해 robust하기에 자주 사용한다.

Odds에 (자연)로그를 취한 것을 Log odds라고 한다.

\log{Odds(A)} = \log{\frac{p}{1-p}} = \log{p} - \log{(1-p)}

로그변환은 통계학에서 자주 사용하는 변환으로,

  • 함수의 증감 형태, convex/concave 형태를 유지시키고
  • 극점의 위치를 유지시키며
  • 곱(또는 나눗셈)으로 표현된 식을 선형조합의 꼴로 풀어쓸 수 있도록 해준다

는 장점이 있다. 즉, 계산은 용이하게 해주는데 함수의 특성은 그대로 유지하는 변환이라 할 수 있겠다. 로그변환의 이러한 성질에 의해 Log odds는 여전히 값이 클수록 성공확률이 큰 것을 의미하는 함수이다.

한 편, Logit function은 다음과 같은 꼴의 함수를 말한다. Logit function은 (0, 1)을 support로 가지며 (- \infty, + \infty) 값을 domain으로 가진다.

logit(x) = \log{\frac{x}{1-x}}

어디서 많이 본 꼴이다. 그렇다. Log odds는 성공확률 p에 대한 Logit function 함수값과 일치한다 (\log{Odds(A)} = logit(p)). 다시말해 Logit 함수는 log Odds의 성질을 가지는 함수이다.

Logistic function은 바로 이 Logit function의 역함수이다.

 

logistic(x) = \frac{1}{1+e^{-x}}

성공확률 p를 갖는 사건 A를 바탕으로 해석해보면 Logistic function은 성공확률 p 그 자체이다.

\frac{p}{1-p} = e^{\log{Odds(A)}},

p = e^{\log{Odds(A)}} -e^{\log{Odds(A)}}p,

(1+e^{\log{Odds(A)}})p = e^{\log{Odds(A)}},

\begin{array}{lcl}\therefore p &=& \frac{e^{\log{Odds(A)}}}{1+e^{\log{Odds(A)}}} \\ &=& \frac{1}{1+e^{-\log{Odds(A)}}} \end{array}

 

Binary classification과 Logistic function

두 개의 클래스(클래스 1, 2)를 분류하는 문제를 생각해보자. 우리가 분류에 사용할 데이터를 X,특정 샘플이 클래스 1, 2에 속한다고 판단하는 사건을 각각 Y_1, Y_2라고 하자.

Binary classification 문제는 데이터 X가 주어졌을 때 둘 중 어느 클래스에 속할지 그 확률 P(Y_i|X) (posterior probability)를 구하는 문제라고 할 수 있다. P(Y_1|X) >P(Y_2|X)일 때 우리는 Y_1이 옳은 클래스일 것이라고 예측을 하게 되고, P(Y_1|X) < P(Y_2|X)일 때 Y_2가 옳은 클래스일 것이라고 예측하게 된다.

Bayes’ rule에 의해서 posterior probability P(Y_i|X)는 likelihood P(X|Y_i)와 prior probability P(Y_i)의 곱에 비례한다. (분모인 prior predictive probability P(X)는 클래스에 관계 없이 X의 marginal probablity로 항상 같으므로 덜 중요하다)

P(Y_i|X) = \begin{cases}P(Y_1|X)=\frac{P(X|Y_1)P(Y_1)}{P(X)} =\frac{P(X|Y_1)P(Y_1)}{P(X|Y_1)P(Y_1) +P(X|Y_2)P(Y_2)}  \\ P(Y_2|X)=\frac{P(X|Y_2)P(Y_2)}{P(X)} =\frac{P(X|Y_2)P(Y_2)}{P(X|Y_1)P(Y_1) +P(X|Y_2)P(Y_2)} \end{cases}

따라서

P(Y_i|X) = \begin{cases}P(Y_1|X) \propto P(X|Y_1)P(Y_1)  \\ P(Y_2|X) \propto P(X|Y_2)P(Y_2) \end{cases}

여기서 a_i = \log{P(X|Y_i)P(Y_i)}를 정의하면 다음과 같이 각 클래스의 posterior probability를 표현할 수 있게 된다.

\begin{array}{lcl} P(Y_1|X) &=& \frac{e^{a_1}}{e^{a_1} + e^{a_2}} \\ &=& \frac{1}{1+e^{-(a_1-a_2)}} \end{array}

a = a_1 - a_2 = \log{ \frac{P(X|Y_1)P(Y_1)}{P(X|Y_2)P(Y_2)} }라고 하면 P(Y_1|X)a에 대한 로지스틱 함수값이 된다.

P(Y_1|X) =\frac{1}{1+e^{-a}} = logistic(a)

그런데 a는 위의 정의에 따라

\begin{array}{lcl} a &=& \log{ \frac{P(X|Y_1)P(Y_1)}{P(X|Y_2)P(Y_2)} } \\ &=& \log{ \frac{P(Y_1|X)}{P(Y_2|X)} } \\ &=& \log{ \frac{P(Y_1|X)}{1-P(Y_1|X)} } \\ &=& \log{Odds(Y_1|X)} \end{array}

즉, 데이터 X를 바탕으로 Y_1이 옳은 클래스라고 판단할 log odds이다.

위에서 사건 A의 logistic은 사건의 성공확률 p 그 자체라는 것을 보였으므로, 결론적으로 logistic(Y_1|X)는 사건 Y_1|X의 확률, 즉 내재적으로 P(Y_1|X) 그 자체이다 (바로 위의 증명과 완전히 일맥상통한다).

이때문에 우리는 확률분포에 대한 가정 없이도 (deterministic하게) logistic function을 각 클래스로 판단할 ‘확률값’으로 곧바로 사용할 수 있는 것이다.

Multi-class classification과 Softmax function

n 개의 클래스(클래스 1, 2, … n)를 분류하는 문제를 생각해보자. 우리가 분류에 사용할 데이터를 X,특정 샘플이 클래스 1, 2, … n에 속한다고 판단하는 사건을 각각 Y_1, Y_2, ..., Y_n라고 하자. Logistic function을 유도했을 때와 마찬가지로,

P(Y_i|X) = \begin{cases}P(Y_1|X)=\frac{P(X|Y_1)P(Y_1)}{P(X)} =\frac{P(X|Y_1)P(Y_1)}{\sum_{i=1}^{n} P(X|Y_i)P(Y_i)}  \\ P(Y_2|X)=\frac{P(X|Y_2)P(Y_2)}{P(X)} =\frac{P(X|Y_2)P(Y_2)}{\sum_{i=1}^{n} P(X|Y_i)P(Y_i)} \\ ... \\ P(Y_n|X)=\frac{P(X|Y_n)P(Y_n)}{P(X)} =\frac{P(X|Y_n)P(Y_n)}{\sum_{i=1}^{n} P(X|Y_i)P(Y_i)} \end{cases}

이고, a_i = \log{P(X|Y_i)P(Y_i)}를 정의하면 posterior probability는 다음과 같이 Softmax function의 꼴로 표현된다.

\begin{array}{lcl} P(Y_1|X) &=& \frac{e^{a_1}}{e^{a_1} + e^{a_2} + ... +e^{a_n}} \\ &=&\frac{e^{a_1}}{\sum_{i=1}^{n} e^{a_i}} \end{array}

이처럼 Logistic function을 multi-class 문제로 일반화시키면 Softmax function을 얻을 수 있다. 이때문에 Softmax function을 multi-class logistic function이라고 하기도 한다.

 

Cross-entropy loss와 MLE

i번째 관측치 벡터 (x_i)의 ground truth 클래스를 t_i, 분류기를 통해 판단한 클래스를 y_i라고 하면,

t_i|x_i, a {\sim}^{iid} Bernoulli(p_i),  where p_i = P(t_i=1|x_i) = P(Y_1|X) = y_i

라고 가정할 수 있다. 이 때 likelihood는 다음과 같이 적을 수 있다.

\begin{array}{lcl} L = \prod_{i=1}^{n} P(t_i|x_i, a) &=& \prod_{i=1}^{n} p_{i}^{t_i} (1-p_i)^{1-t_i} \\ &=& \prod_{i=1}^{n} y_{i}^{t_i} (1-y_i)^{1-t_i}  \end{array}

Maximum likelihood estimation(MLE)을 위해서 log likelihood \log{L}을 구하면

\log{L} = \sum_{i=1}^{n} \log{\{y_{i}^{t_i} (1-y_i)^{1-t_i}\}} = \sum_{i=1}^{n} \{ t_i \log{y_i} + (1-t_i) \log{(1-y_i)} \}

인데, 이 식에 negative(-)를 취하면 cross-entropy loss(CE)의 정의와 일치한다. 따라서

\hat{\theta}^{MLE} = argmax_{\theta}(\log{L}) = argmin_{\theta}(-\log{L}) =argmin_{\theta}(CE)

이므로, 위의 Bernoulli 분포 가정 하에서 cross-entropy loss를 minimize하는 것은 MLE와 동일한 과정이 된다. 이때문에 cross-entropy loss를 최소화하는 과정을 통해 올바른 클래스 t_i에 가까운 예측 확률값 y_i를 얻을 수 있게 된다.

 

참고

  • 이 글을 많이 참고했다. 이 글을 바탕으로 노테이션을 정리하고 수식 유도를 풀어 쓴 정도다.
  • Odds에 대해서는 이 글을 참고했다.
  • 이 글에서 영감(?)을 얻었다.