본문 바로가기
CS/MachineLearning

기초부터 탄탄히 - 만들면서 배우는 생성AI

by Diligejy 2023. 10. 18.

 

만들면서 배우는 생성AI라고 하면 뭔가 생성모델 쪽 라이브러리를 가지고 실습만 하는 책으로 생각할 수 있겠지만 그렇지 않다. 이 책은 매우 기초적인 내용부터 하나하나 다루고 실무적인 팁까지 다루는 책이다. 

 

패딩이 무엇인지, 임베딩이란 무엇인지 기초개념까지 저자가 그리고 역자가 하나하나 가르쳐주면서 이끌어가는 책이다. 

 

사실 처음 AI를 접했을 때 임베딩이라는 단어를 많이 접했고 대충 느낌적인 느낌(?!)으로 임베딩이 뭐겠다 라고 알고는 있었지만, 임베딩이 무엇인지와 같이 기초를 잡고 가지 않아서 나중에 헷갈릴 때가 많았다. 그러니 아무리 활용 위주로 AI를 사용한다고 하더라도 기초적인 용어나 개념같은 건 이런 책을 통해 배우고 가면 좋을 거라고 생각한다.

 

책이 기초부터 다루고 있긴 하지만 쉬운 책은 아니다. AI가 쉬운 분야가 아니기 때문이다. 하나하나 가르쳐준다고 해도 원래 AI 자체가 어려운 것인데 어느 정도 고생은 해야한다.

 

그렇게 고생하고 이 책을 본다고 해서 바로 전문 엔지니어급이 될 수 있는 것도 아니고, 미래를 예측할 수 있는 것도 아니다. 다만, 조금 더 그럴 확률이 높아질 수 있을거라고 생각한다. 이 책의 초반부에서 생성모델은 결정론적 모델이 아닌 확률적 모델이라고 강조하듯, 확률적인 사고를 해본다면 이 책을 통해 얻을 수 있는 기대가치는 꽤나 크다고 할 수 있다.

 

 

밑줄긋기

p.34~35

생성 모델은 또한 결정적(deterministic)이 아니고 확률적(probabilistic)이어야 합니다. 매번 동일한 값을 출력하는 것이 아니라 다양한 출력 결과를 샘플링할 수 있어야 하기 때문입니다. 모델이 데이터셋에 있는 모든 픽셀의 평균값을 구하는 일처럼 고정된 계산만 수행한다면 생성 모델이 아닙니다. 생성 모델은 생성되는 개별 샘플에 영향을 미칠 수 있는 랜덤한 요소를 포함해야 합니다.

 

다른 말로 하면 어떤 이미지는 훈련 데이터셋에 있을 것 같고, 다른 이미지는 그렇지 않은 이유를 설명하는 알려지지 않은 확률분포가 있다고 가정합니다. 해야 할 일은 최대한 이 분포에 가깝게 흉내 내는 모델을 만드는 것입니다. 그다음 이 분포에서 샘플링하여 원본 훈련 세트(training set)에 있을 것 같은 새롭고 완전히 다른 샘플을 생성합니다. 

 

p.36

수학적으로 생성 모델링과 판별 모델링을 정의해보죠.

 

판별 모델링은 p(y | x)를 추정(estimation)합니다.

즉, 판별 모델링은 샘플 x가 주어졌을 때 레이블 y의 확률을 모델링하는 것이 목표입니다.

 

생성 모델링은 p(x)를 추정합니다.

즉, 생성 모델링은 샘플 x를 관측할 확률을 모델링하는 것이 목표입니다.

 

p.37

최근까지 판별 모델링은 머신러닝 분야에서 대부분의 발전을 이끈 원동력이었습니다. 그 이유는 판별 문제에 상응하는 생성 모델링 문제가 일반적으로 훨씬 해결하기 어렵기 때문입니다. 예를 들어 반 고흐 스타일의 그림을 생성하는 모델을 훈련하는 것보다 반 고흐의 그림인지를 예측하는 모델을 훈련하기가 훨씬 쉽습니다. 마찬가지로 찰스 디킨스 스타일의 문장을 생성하는 모델을 만드는 것보다 찰스 디킨스의 글인지 예측하는 모델을 훈련하기가 훨씬 쉽습니다. 최근까지만 해도 대부분의 생성 문제는 근접할 수 없는 영역이었으며 이를 해결할 수 있을지에 대한 의구심이 많았습니다. 창의성을 AI가 따라올 수 없는 순수한 인간의 능력으로 여겼기 때문입니다.

 

하지만 머신러닝 기술이 발전함에 따라 이러한 가정은 점차 약해지고 있습니다. 지난 10년 동안 이 분야에서 가장 흥미로운 발전은 생성 모델링 작업에 머신러닝을 새롭게 적용하면서 일어났습니다. 예를 들어 아래 그림은 2014년 이후 얼굴 이미지 생성 분야에서 일어난 놀라운 발전 과정을 보여줍니다.

 

 

p.41

생성 모델링 프레임워크

 

- 샘플 데이터셋 X를 가지고 있습니다.

- 샘플이 알려지지 않은 어떤 P_data 분포로 생성되었다고 가정합니다.

- P_data를 흉내내는 생성 모델 P_model을 만들려고 합니다. 이 목표를 달성하려면 P_model에서 샘플링하여  P_data에서 뽑은 것 같은 샘플을 생성할 수 있습니다.

- 따라서 P_model의 바람직한 속성은 다음과 같습니다.

 

     - 정확도

       생성된 샘플의 P_model이 높으면 P_data에서 뽑은 것처럼 보여야 합니다. 생성된 샘플의 P_model이 낮으면 P_data에서 뽑은 것처럼 보여서는 안 됩니다.

    - 생성

      P_model에서 새로운 샘플을 쉽게 샘플링할 수 있어야 합니다.

    - 표현

     데이터의 다양한 고수준 특성이 P_model로 어떻게 표현되는지 이해할 수 있어야 합니다.

 

p.43~45

당신의 외모를 모르면서 군중 속에서 당신을 찾고 있는 사람이 있습니다. 이 사람에게 당신 외모를 설명한다고 가정해봅시다. 당신 사진에 있는 픽셀 1의 색상부터 픽셀 2, 픽셀 3 등의 색상을 말하는 식으로 설명하지 않을 것입니다. 대신 상대방이 평균적인 사람의 외모를 안다는 합리적인 가정을 합니다. 그 다음 '나는 금발이다' 또는 '안경을 쓰고 있다'와 같이 픽셀의 그룹에 해당하는 특성으로 이 가정을 개선해갑니다. 이런 설명이 10개 정도만 있으면 상대방은 이를 다시 픽셀로 매핑하여 머릿속에 당신의 이미지를 생성할 수 있습니다. 이 이미지가 완벽하지는 않겠지만 당신을 본 적이 없는 사람도 수백 명의 사람 중에서 당신을 찾을 수 있을 정도로 실제 모습과 비슷할 것입니다.

 

이것이 표현 학습(representation learning) 이면의 핵심 아이디어입니다. 고차원 표본 공간을 직접 모델링 하는 방식이 아니라 대신 저차원의 잠재 공간(latent space)을 사용해 훈련 세트의 각 샘플을 표현하고 이를 원본 공간의 포인트에 매핑합니다. 다른 말로 하면, 잠재 공간의 각 포인트는 어떤 고차원 이미지에 대한 표현입니다.

 

실제로 이것은 무엇을 의미할까요? 회색 비스킷 깡통 이미지로 이루어진 훈련 세트가 있다고 가정해보죠.

깡통의 높이와 너비라는 두 가지 특성으로 각 깡통을 고유하게 표현할 수 있습니다. 즉, 훈련 세트의 이미지가 고차원 픽셀 공간으로 주어지더라도 각 깡통의 이미지를 2차원 잠재 공간의 한 포인트로 변환할 수 있습니다. 특히 아래 그림에서처럼 적절한 매핑함수 f를 잠재 공간의 새로운 포인트에 적용하여 훈련 세트에 없는 깡통 이미지를 생성할 수도 있다는 의미입니다.

 

원본 데이터셋을 간단한 잠재 공간으로 설명할 수 있음을 기계가 깨닫기는 쉽지 않습니다. 먼저 높이와 너비가 이 데이터셋을 가장 잘 설명하는 두 개의 잠재 공간 차원임을 알아야 합니다. 그 다음 이 공간의 한 포인트를 회색 비스킷 깡통 이미지에 매핑하는 매핑 함수 f를 학습해야 합니다. 머신러닝(특히 딥러닝)을 사용하면 사람의 개입 없이 이런 복잡한 관계를 찾도록 기계를 훈련시킬 수 있습니다.

잠재 공간을 활용하는 모델을 훈련하는 장점 중 하나는 의미 있는 잠재 공간에서 표현 벡터를 조작하여 이미지의 고수준 속성에 영향을 미치는 연산을 수행할 수 있다는 것입니다. 비스킷 깡통 이미지가 주어졌을 때 높이를 크게 하려면 개별 픽셀을 어떻게 조정해야 할지 알지 못합니다. 하지만 잠재 공간에서는 간단히 잠재 공간의 높이 차원에 1을 더하고 매핑 함수를 적용해 이미지를 얻을 수 있습니다. 이어지는 장에서는 비스킷 깡통 대신 얼굴 이미지에 적용한 구체적인 예제를 보겠습니다. 

 

이 책의 뒷부분에서 살펴보겠지만 훈련 데이터셋을 잠재 공간으로 인코딩하고 이 공간에서 샘플링한 다음 디코딩하여 원래 도메인으로 되돌아가는 개념은 많은 생성 모델링 기법에서 널리 사용합니다. 수학적으로 인코더-디코더 기법은 (예를 들면 픽셀 공간에) 데이터가 놓여 있는 고차원 비선현 매니폴드를 샘플링 가능한 단순한 잠재 공간으로 변환합니다. 아래 그림과 같이 이 잠재 공간의 모든 포인트가 잘 구성된 이미지의 표현이 됩니다.

 

p.48

가능도는 데이터가 아니라 파라미터의 함수입니다. 이를 주어진 파라미터 집합이 올바른지에 대한 확률로 해석해서는 안 됩니다. 다른 말로 하면 파라미터 공간의 확률분포가 아닙니다 (즉, 파라미터에 대해 적분(합)하면 1이 되지 않습니다)

 

p.49

모든 생성 모델은 궁극적으로 동일한 작업을 해결하는 것이 목표이지만 밀도 함수 p_theta(x)를 모델링하는 방식이 조금씩 다릅니다. 크게 세 가지 방식이 있습니다.

 

1. 명시적으로 밀도 함수를 모델링하지만 밀도 함수를 다루기 쉽도록 (즉, 계산할 수 있도록) 어떤 식으로 모델을 제약합니다.

2. 다루기 쉬운 밀도 함수의 근사치를 명시적으로 모델링합니다.

3. 데이터를 직접 생성하는 확률적 과정을 통해 밀도 함수를 암묵적으로 모델링합니다.

 

p.64

이 책의 많은 모델에서는 한 층의 출력이 여러 개의 후속 층으로 전달됩니다. 또는 그 반대로 한 층이 여러 개의 이전 층으로부터 입력받습니다. 이런 모델에는 Sequential클래스가 적합하지 않으며, 훨씬 더 유연한 함수형 API를 사용해야 합니다.

 

TIP_ 케라스로 처음 선형 모델을 만들 때도 Sequential 모델보다는 함수형 API를 사용하는 것이 좋습니다. 신경망의 구조가 점점 복잡해짐에 따라 장기적으로 더 나은 선택이 됩니다. 함수형 API를 사용하면 심층 신경망의 설계를 완전히 자유롭게 할 수 있습니다.

 

p.65

Flatten 클래스의 객체를 만든 다음 이 객체를 매개변수 input_layer로 호출했습니다. 파이썬의 객체는 함수처럼 호출할 수 있습니다. 이때 이 객체에 정의된 __call__() 메서드가 호출됩니다. 케라스에서는 이런 식의 객체 호출을 즐겨 사용합니다. 

 

p.65~66

Input 층은 네트워크의 시작점입니다. 네트워크가 기대하는 입력 데이터 크기를 튜플로 알려주어야 합니다. 배치 크기는 지정하지 않습니다. Input 층에 임의의 이미지 개수를 전달할 수 있기 때문에 배치 크기는 필요하지 않습니다. 따라서 Input 층을 정의할 때 배치 크기를 입력하지 않습니다.

 

그 다음 Flatten 층은 입력을 하나의 벡터로 펼칩니다. 결과 벡터의 길이는 3,072 (32 * 32 * 3) 입니다. 이렇게 하는 이유는 뒤따르는 Dense 층이 다차원 배열이 아니라 평평한 입력을 기대하기 때문입니다. 나중에 보겠지만 다른 종류의 층은 입력으로 다차원 배열을 사용해야 합니다. 언제 Flatten 층을 사용하는지 이해하려면 층마다 필요한 입력과 출력의 크기를 알아야 합니다.

 

Dense 층은 기본적인 신경망 구성 요소입니다. 이 층에는 이전 층과 완전하게 연결(fully connected)되는 유닛이 있습니다. 즉, 이 층의 각 유닛은 이전 층의 모든 유닛과 연결됩니다. 연결마다 하나의 (양수 또는 음수인) 가중치가 동반됩니다. 유닛의 출력은 이전 층에서 받은 입력과 가중치를 곱하여 더한 것입니다. 그 다음 비선형 활성화 함수 (nonlinear activation function)를 통과하여 다음 층으로 전달됩니다. 활성화 함수는 신경망이 복잡한 함수를 학습하는 데 아주 중요한 역할을 합니다. 그렇지 않으면 입력을 선형적으로 조합한 값만 출력할 것입니다. 

 

p.72

전체 데이터셋을 사용해 훈련 스텝마다 그레이디언트를 계산하는 작업은 너무 시간이 오래 걸리고 계산 비용이 많이 듭니다. 일반적으로 32에서 256 사이의 배치 크기를 사용합니다. 요즘엔 훈련이 진행됨에 따라 배치 크기를 증가시키는 방식을 권장합니다.

 

Samuel L. Smith et al., "Don't Decay the Learning Rate, Increase the Batch Size.", November 1, 2017. https://arxiv.org/abs/1711.00489. 옮긴이주 -> Adam, RMSProp과 같은 옵티마이저는 훈련이 진행됨에 따라 최솟값을 찾기 쉽도록 학습률을 줄여갑니다. 이 논문은 학습률을 줄이는 대신 배치 크기를 늘리는 방식으로 훈련 반복 횟수를 줄이면서 동일한 정확도를 얻을 수 있다고 소개합니다. 케라스 훈련 과정에서 배치 크기를 조정하려면 fit 메서드 대신 train_on_batch 메서드를 사용하세요. 

 

p.76

합성곱은 원래 계산하기 전에 필터를 뒤집습니다. 필터를 뒤집지 않고 계산하는 것은 교차 상관(cross correlation)입니다. 합성곱 층은 처음에 필터를 랜덤하게 초기화하기 때문에 뒤집는 것이 의미가 없습니다. 실제로 합성곱 층은 교차 상관을 수행하지만 관례적으로 합성곱이라 부릅니다. 

 

p.79

padding = "same"으로 지정하면 여러 개의 합성곱 층을 통과할 때 텐서의 크기를 쉽게 파악할 수 있기 때문에 유용합니다. padding = "same"인 합성곱 층의 출력 크기는 다음과 같습니다.

 

(입력 높이 / 스트라이드, 입력 너비 / 스트라이드, 필터 개수)

 

p.81

입력의 크기는 (None, 32, 32, 3)입니다. 케라스는 None을 사용해 한꺼번에 임의 개수의 이미지를 네트워크로 통과시킬 수 있음을 표현합니다. 네트워크는 텐서에 대해 대수학 계산을 수행하므로 이미지를 하나씩 전달할 필요가 없습니다. 대신 여러 개를 묶어 배치로 전달합니다.

 

p.82

손실 함수가 NaN을 반환하기 시작하면 가중치가 오버플로(overflow) 오류를 발생시킬 만큼 커졌다는 신호입니다.

 

p.82~83

신경망에 주입되는 입력 데이터를 스케일 조정하는 이유 중 하나는 처음 몇 번의 반복 훈련을 안정적으로 시작하기 위해서입니다. 네트워크의 가중치가 랜덤하게 초기화되었기 때문에 스케일이 조정되지 않은 입력은 큰 활성화 출력을 만들어 그레이디언트 폭주로 바로 이어질 가능성이 있습니다. 그래서 입력층으로 0~255 사이의 픽셀 값을 전달하는 대신 -1에서 1 사이의 값으로 스케일을 바꿉니다.

 

입력 스케일을 조정했기 때문에 모든 층의 활성화 출력도 비교적 스케일이 안정되리라 기대할 수 있습니다. 초기에는 맞는 말입니다. 하지만 네트워크가 훈련됨에 따라 가중칫값이 랜덤한 초깃값과 멀어지기 때문에 이런 가정이 무너지기 시작합니다. 이런 현상을 공변량 변화(covariate shift)라고 부릅니다.

 

배치 정규화(batch normalization)는 이 문제를 극적으로 줄이는 해결책입니다. 방법은 놀랍게도 간단합니다. 훈련하는 동안 배치 정규화 층은 배치에 대해 각 입력 채널별로 평균과 표준 편차를 계산한 다음 평균을 빼고 표준 편차로 나누어 정규화합니다. 채널로 학습되는 두 개의 파라미터가 있습니다. 스케일 파라미터(gamma)와 이동 파라미터(beta)입니다. 정규화한 입력을 gamma로 스케일 조정하고 beta로 이동시켜 출력합니다.

 

p.84~85

예측할 때는 이 층이 어떻게 동작하는지 궁금할 것입니다. 예측을 수행할 때는 하나의 샘플에 대해 예측을 만들기 때문에 평균과 표준 편차를 계산할 배치가 없습니다. 이 문제를 처리하기 위해 훈련 과정에서 배치 정규화 층이 채널별로 평균과 표준 편차의 이동 평균(moving average)을 계산하여 저장합니다. 테스트할 때 이 값을 사용하여 입력을 정규화합니다.

 

배치 정규화 층에는 몇 개의 파라미터가 필요할까요? 이전 층의 채널마다 스케일(gamma)과 이동(beta)을 위한 2개의 가중치가 학습되어야 합니다. 이 둘은 학습되는 파라미터입니다. 평균과 표준편차의 이동 평균은 채널마다 계산되지만, 역전파를 통해 훈련되는 것이 아니라 층을 통과하는 데이터에서 계산됩니다. 이 둘은 훈련되는 파라미터가 아닙니다. 종합해보면 채널마다 4개의 파라미터가 있고 2개는 훈련되고 2개는 훈련되지 않습니다.

 

p.86

p의 확률로 유닛을 드롭아웃하여 모델을 훈련하면 테스트할 때는 모든 유닛을 사용하기 때문에 1/(1-p)배 만큼 더 큰 출력이 만들어집니다. 이를 보완하려고 테스트할 때 출력에 (1-p)를 곱하여 감소시킵니다. 케라스와 같은 구현에서는 테스트할 때 출력을 보정하지 않고 훈련할 때 드롭아웃 층의 출력을 (1-p)로 나누어 증폭시킵니다. 두 방식이 완전히 같지는 않지만 잘 작동합니다.

 

p.97

인코더는 디코더가 정확하게 재구성할 수 있도록 가능한 한 많은 정보를 내포시키려 하므로 이 벡터를 임베딩(embedding)이라고도 합니다.

 

오토인코더(autoencoder)는 단순히 어떤 항목의 인코딩과 디코딩 작업을 수행하도록 훈련된 신경망입니다. 이 과정을 통해 출력이 가능한 한 원본 아이템에 가까워지도록 합니다.

 

p.99

오토인코더는 두 부분으로 구성된 신경망입니다.

 

- 인코더: 네트워크는 이미지 같은 고차원 입력 데이터를 저차원 임베딩 벡터로 압축합니다.

- 디코더: 네트워크는 임베딩 벡터를 원본 도메인으로 압축 해제합니다 (예를 들어 이미지로 되돌립니다).

 

 

댓글