오늘 다룬 내용은 상당히 광범위했다. 그래서 양 자체는 많은데, 다행히 어려운 부분은 적었기 때문에 오늘도 기억할 부분 위주로 정리하려고 한다.
오늘 배운 내용은 아래와 같다.
베이즈 통계학에서는 사전 확률에 대하여 새로 발생한 사건을 근거로 사후 확률을 갱신한다.
최근 많은 머신러닝이 베이즈 통계학을 기반으로 돌아간다. 이전에 계산된 사후 확률이 이후의 사전 확률으로 쓰일 수 있기 때문이다.
따라서 잘 이해하고 넘어가도록 하자.
베이즈 통계학에서 사후확률과 사전확률 사이의 관계식은 아래와 같다.
여기서 좌변은 사후확률(Posterior), 우측의 $P(\theta)$는 사전확률(Prior)을 의미한다. 또한 $P(\mathcal{D})$는 새로 관측된 증거(Evidence)(=정보)이다. $P(\mathcal{D} \vert \theta)$는 이전에 배웠던 가능도로, 현재 주어진 모수(가정)에서 이 데이터가 관찰될 확률을 의미한다. 알고있는 내용이니 자세한 설명은 생략한다.
아래 문제를 보면 이 식이 어떤 프로세스로 동작하는지 파악할 수 있다.
어떤 병의 발병률이 10%로 알려져있다. 이 병에 실제로 걸렸을 때 걸렸다고 검진될 확률은 99%이고, 실제로 걸리지 않았을 때 오검진될 확률이 1%라고 할 때, 어떤 사람이 이 병에 걸렸다고 검진결과가 나왔을 때 정말로 병에 걸렸을 확률은?
중요한 것은 아래 관계를 파악해서 이용하는 것이고, 다른 내용은 알기 쉬우니 생략한다.
계산해보면 약 0.916의 확률이 나온다. 여기까지는 그냥 하면 되고 이제 문제를 좀 변형해서 값이 얼마나 바뀌는지 파악해보자.
만약 이 병에 걸리지 않았는데 오검진될 확률이 1%가 아닌 10%라고 해보자. 이렇게 하면 확률이 0.524로 급격하게 떨어진다.
이와 같이 오탐율(False alarm)이 올라가면 테스트의 정밀도가 급격하게 떨어진다는 점을 기억하자.
위 그림은 오탐율 1%일 때의 조건부확률들을 시각화 한것으로, True Positive는 병이 있고 양성일 확률, True Negative는 병이 없고 음성일 확률이다.
False Negative는 병이 있고 음성일 확률, False Positive는 병이 없고 양성일 확률이다. 그림에서 각각이 2종 오류, 1종 오류라고 써져있는데 이들 용어를 잘 정리해두자.
머신러닝에서 베이즈 정리가 많이 쓰이는 이유는 이전에 구한 사후 확률을 다음의 사전 확률로 사용할 수 있기 때문이다.
만약 오탐율을 10%라고 하고 딸림문제를 아래와 같이 설정하면,
앞서 양성 판정을 받은 사람이 두 번째 검진을 받았을 때도 양성 판정을 받았을 때 이 사람이 진짜 이 병에 걸렸을 확률은?
0.524였던 확률이 약 0.917으로 다시 급격히 올라가게 되는 것을 확인할 수 있다. (자세한 계산은 생략)
조건부 확률은 유용한 통계적 해석을 제공하지만 인과관계(causality)를 추론할 때 이를 함부로 사용해서는 안된다.
인과관계는 데이터 분포의 변화에 강건한(즉, 시나리오에 따른 확률 변화가 적은) 예측모형을 만들 때 필요하다.
조건부 확률 기반 예측 모형은 아래와 같이 시나리오에 따라 확률변화가 매우 크지만 인과 관계 기반 예측 모형은 여러 시나리오에 대해 예측 정확도가 안정적이다.
다만 보다시피 인과 관계만으로는 높은 정확도가 보장되지 않는다.
또한 인과관계를 알아내기 위해서는 중첩요인(confounding factor)의 효과를 제거하고 원인에 해당하는 변수만의 인과관계를 계산해야 한다.
예를 들어, ‘키가 크다’->’지능이 높다’는 별 관계가 없어보이지만 실제로 분석을 해보면 데이터상으로 이 관계는 성립한다.
하지만 우리는 이 둘의 인과관계를 파악할 때 중첩요인인 ‘나이’를 제거하지 않았다. 이렇게 중첩요인을 제거하지않으면 가짜 연관성(spurious correlation)이 나오게 된다.
참고로, 여기서 키와 지능은 상관관계가 있으나, 인과관계는 없는 것이다. 둘의 차이점을 명확히 이해하고 넘어가자.
아래는 비슷한 일례로 심슨의 역설을 보여주는 문제이다.
분명 Z=0, Z=1 모두에서 치료법 a가 더 높은 치료율을 보여주지만 합산치로 보면 b가 더 높은 치료율을 보인다.
이러한 문제는 $\text{do}(T=a)$라는 조정(intervention) 효과를 통해 혼재변수 $Z$의 개입을 제거함으로써 해결할 수 있다. 실제로 개입을 제거하고 계산한 결과는 a가 약 0.8325, b가 약 0.7789의 치료율로 a의 치료율이 더 높은 것으로 판단할 수 있다.
현재를 기준으로 가장 많이 쓰이는 딥러닝 프레임워크는 Tensorflow와 PyTorch이다.
둘 모두 장단점이 있다고 하는데, 강의해주시는 교수님께서는 논문 쓸 때는 PyTorch, 서비스 런칭시에는 Tensorflow를 많이 사용하신다고 한다.
아직 제대로 배우지는 않아서 정확한 장단점이나 위와 같이 프레임워크를 복합적으로 사용하시는 이유는 잘 모르겠다.
아무튼 우리가 앞으로 배울 것은 PyTorch이다.
PyTorch는 크게보면 Numpy + AutoGrad(자동 미분) + Function으로 이루어진다.
PyTorch 역시 Numpy 구조를 가지는 Tensor 객체로 array를 표현한다. 다만 완전히 ndarray 구조는 아니기 때문에 실사용시 상호변환이 필요하기는 하다.
무료로 제공되는 전자책으로 이 좋은 듯하니 시간 날 때마다 읽어봐야겠다.
PyTorch에서의 문법을 아~주 간단하게 보면 numpy와 대부분이 비슷한데, 일단은 아래 3가지만 숙지하고 가자.
dot()
이 PyTorch에서는 matmul()
이다. 표현이 더 직관적인 것 같다.reshape()
이 PyTorch에서는 view()
이다. 이건 오히려 직관성면에서는 퇴보했다. squeeze()
로 랭크 축소, unsqueeze()
로 랭크 확장을 할 수 있다.가장 중요한 것은 처음보는 클래스/함수들은 직접 깃허브에서 코드를 따고 들어가 살펴보는 것이다.
오늘 실습할 때도 실제로 그렇게 몇 번 해봤는데 정말 도움되고 이해도 더 잘되는 것 같다.
시간이 없다면 적어도 각 class의 attribute가 무엇을 의미하는지, 각 메소드의 parameter로 들어가는게 무엇을 의미하는지정도는 분명히 확인해볼 가치가 있다.
솔직히 이 부분은 들어도 아직 모르는게 당연하긴한데, 적어도 역사적 흐름 정도와 나중에 읽어볼 논문들을 살펴보는 정도에 의의를 두고 넘어가려고 한다.
머신러닝 역사가 제대로 시작된지는 얼마 안되었기 때문에 역사가 짧다는 것이 장점 이라면 장점이다.
딥러닝이 출범한지 얼마 되지 않아 2021년에는 또 어떤 패러다임이 제시될지 모두의 기대가 클 것이라 생각한다.
보면 알겠지만 거의 1년 간격으로 새로운 성과들이 속속들이 발표되는데, 그만큼 이 분야에 종사하려면 계속해서 공부하는 것이 더욱 중요한 것 같다.
뉴럴 네트워크(Neural Network)는 인간의 신경망 구조를 표방해서 말한 것이라고 하지만, 사실 더 정확히 말하면 이건 현실 세계와 근사하도록 만든 일종의 함수이기도 하다.
Neural networks are function approximations that stack affine transformations followed by nonlinear transformations.
여기서 말하는 affine transformation은 차원 변환을 말하는데, 한 마디로 비선형변환이 있는 다층의 차원변환 함수가 바로 NN이라는 것이다.
뉴럴 네트워크에서는 가중치 행렬을 곱해주고 비선형 변환(activation function) 후 다시 다음 층을 통과한다. 이 일련의 과정이 위 한 문장에 축약되어 담겨있다. 같은 맥락에서, 뉴럴 네트워크에서의 행렬은 서로 다른 두 벡터 공간 사이의 매핑이라고 간주할 수 있다.
참고로,
다만 이는 어디까지나 존재성이 밝혀진 것이지, 어떻게 찾는지도 중요한 요소이기 때문에 실제로는 싱글 레이어만으로 뉴럴 네트워크를 구성하지는 않는다.
MLP에 대한 실습도 MNIST 데이터로 간단하게 진행해보았다.
여기에 코드를 담지는 않지만 간단한 프로세스정도만 남겨두려고 한다.
torch.nn.Linear
객체를 원하는 층 개수만큼 레이어 역할로 넣어주는데 이 때 파라미터로 위에서 말한 행/열 개수를 설정한다. 가중치는 nn.Module(이걸 MLP 클래스가 상속받았다)에서 미리 구현된 init_param()
으로 초기화해준다.init_param()
) 학습을 돌리면 된다.
전체 코드도 길이는 긴데 간단한 편이라 이해가 다 돼서 따로 적진 않으려고 한다.
하지만 이해만 될 뿐이지 이 프로세스에 익숙해지는 데에는 오래 걸릴 듯하니 기억할 것은 잘 기억해두자.
학습을 하기 위해서는 데이터 셋을 세팅하는 것이 가장 중요하며, 이를 위한 클래스가 PyTorch에서도 정의되어있다. (torch.utils.data.Dataset
)
이 데이터셋을 이용하여 데이터를 벡터화해서 불러오고, 데이터 이터레이터를 반환받을 수 있다.
그리고 이러한 클래스를 상속받아서 커스텀 데이터셋을 만들 줄 알아야한다.
일단 이를 위해 Dataset 클래스의 구조를 파악해야하는데, 요약하면 프로세스는 다음과 같다.
__init__
, 전처리를 해주는(이미지를 벡터화 등 => PIL
lib 이용) __getitem__
메소드를 구성한다.사실 그냥 보면 굉장히 간단할 것 같은데, Dataset 클래스의 구조를 잘 파악하고 있어야만 커스텀 데이터셋도 만들 수 있다.
그리고 그 Dataset 클래스 구조가 좀 복잡한 편이다 (…)
일단 내용은 이게 다이다. 이 부분은 추후 연습을 하면서 메꿔나가야 할 것 같다.
오늘은 시간이 부족하여 당장 연습은 어렵고, 주말즈음에 커스텀 Dataset을 구성하는 연습을 해보아야겠다.
(예정)
고전 통계학과 베이지안 통계학
심슨의 역설
Generative Adversarial Network(GAN)
Epoch, Batch size, iteraion