728x90
4. Initialization
앞으로 학습시킬 파라미터를 준비합니다. 이를 초기값을 설정한다 하여 initialize라고 합니다.
먼저, 필요한 파라미터 개수는 Fully-Connected layers의 개수 및 dimension에 따라 달라지므로 해당 정보를 argument로 받은 뒤 그에 맞게 weight와 bias를 initialize 합니다.
해당 세션에서는 총 4개의 layer로된 FC를 구성할 계획입니다. 그래서 model = [784, 128, 64, 10]와 같이 리스트 형태로 모델을 정의하도록 하겠습니다. 오직 MLP만 사용할 계획이므로 리스트로 표현하는 것만으로도 충분합니다.
class Initializers:
"""Initializers
Initializer list:
xavier_normal
he_normal
uniform
"""
def __init__(self, fn_name='xavier_normal'):
self.func = getattr(self, fn_name)
def __str__(self):
return f"Initialization Function: {self.func.__name__}"
def initialize(self, model, seed=None):
"""initialize weights & biases
"""
np.random.seed(seed)
parameters = dict()
layers = len(model)
for L in range(1, layers): # 1, 2, 3
weights, biases = self.func(model[L-1], model[L]) # weights & biases
parameters["W" + str(L)] = weights
parameters["b" + str(L)] = biases
return parameters
코드를 살펴보겠습니다.
- init 함수를 통해 어떤 initializer를 사용할지에 대한 정보를 인자값으로 받도록 합니다. (나중에 yaml 파일로 명세를 관리할 때 편할 것 같아서 위와 같이 했습니다.)
- getattr 함수는 입력받은 문자열과 동일한 이름을 가진 함수를 찾아서 불러주는 역할을 합니다.
- str 함수를 통해 인스턴스 생성 시 해당 인스턴스가 어떤 초기화 함수를 가지는 지 print문을 통해 확인할 수 있도록 하기 위해 간단히 작성해 보았습니다.
- initialize 함수에서는 model과 seed에 대한 정보를 받는데 여기서 model은 위에서 설명한 바와 같이 hidden layer의 개수(리스트의 length)와 각 레이어의 차원에 대한 정보(element)를 리스트 형태로 받습니다.
- 총 4개의 hidden layer를 구성했다면, 필요한 파라미터 층은 총 3개가 필요합니다. 각 hidden layer를 이어주는 역할을 할 것이기 때문입니다.
- for문을 통해 parameters 딕셔너리에 W1: 첫번째 weight 행렬, b1: 첫번째 bias 벡터와 같은 형태의 key, value값을 담은 후 리턴합니다. 이후 forward 연산에서 순서에 맞게 꺼내서 쓸 수 있도록 하기 위함입니다.
이제 초기화 함수 몇 가지를 살펴보겠습니다.
Xavier_normal
Xavier가 제시한 정규분포에서 파라미터값을 랜덤추출하는 방식입니다.
# randn은 기본적으로 N(0, 1)이지만 분포를 변경하고 싶다면 E + STD * randn을 하면 된다.
def xavier_normal(self, input_n_neurons, output_n_neurons):
"""Xavier_initializer
"""
weights = np.random.randn(input_n_neurons, output_n_neurons) * np.sqrt(1 / input_n_neurons)
biases = np.zeros(output_n_neurons)
return (weights, biases)
- randn 함수를 그냥 사용할 경우 $N(0, 1)$의 표준정규분포에서 랜덤 추출합니다. 하지만 Xavier가 제시한 정규분포는 기대값 0에 분산은 (1 / 인풋 뉴런의 개수)로 설정하도록 권장합니다. 그래서 분산에 루트를 씌운 표준편차값을 곱해줍니다. 저렇게 해주면 N(0, 1/neuron)의 정규분포에서 랜덤 추출하는 것과 동일해 집니다.
- 랜덤 추출의 결과를 (인풋 뉴런 수, 아웃풋 뉴런 수)로 된 2차원 행렬로 받습니다.
- bias의 경우 0으로 설정하는 경우와 0.01로 설정하는 경우가 있으나 여기서는 0으로 아웃풋 뉴런 개수만큼 추출합니다.
- 참고로 Xavier 초기화는 tanh와 sigmoid를 activation function으로 사용하는 모델에서 잘 작동하도록 설계되었다고 합니다. (https://cs230.stanford.edu/section/4/)
He_normal
He가 제시한 정규분포에서 파라미터값을 랜덤추출하는 방식입니다.
def he_normal(self, input_n_neurons, output_n_neurons):
"""HE initializer
"""
weights = np.random.randn(input_n_neurons, output_n_neurons) * np.sqrt(2/input_n_neurons)
biases = np.zeros(output_n_neurons)
return (weights, biases)
- Xavier 초기화에서 차이점은 정규분포의 분산을 (2 / 인풋 뉴런 수)로 설정했다는 점입니다. 그 외 작동방식은 Xavier와 동일합니다.
- He normal init에 대한 정보는 Kaiming He가 1저자로 등록된 “Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification” 논문에서 확인할 수 있으며 저자의 이름을 따서 He 또는 Kaiming initializer라고도 부릅니다.
Uniform Distribution
유니폼 분포에서 파라미터값을 랜덤추출하는 방식입니다.
def uniform(self, input_n_neurons, output_n_neurons):
"""Uniform initializer
"""
weights = np.random.uniform(-np.sqrt(6/input_n_neurons), np.sqrt(6/input_n_neurons), size=(input_n_neurons, output_n_neurons))
biases = np.zeros(output_n_neurons)
return (weights, biases)
- 사전에 설정해준 최소값과 최대값 사이의 값을 균등한 확률로 추출합니다. 최소, 최대 범위는 아래와 같습니다.
$$ -\frac{6}{input\_neurons} , \frac{6}{input\_neurons} $$
최종 코드
class Initializers:
"""Initializers
Initializer list:
xavier_normal
he_normal
uniform
"""
def __init__(self, fn_name='xavier_normal'):
self.func = getattr(self, fn_name)
def __str__(self):
return f"Initialization Function: {self.func.__name__}"
def initialize(self, model, seed=None):
"""initialize weights & biases
"""
np.random.seed(seed)
parameters = dict()
layers = len(model)
for L in range(1, layers): # 1, 2, 3
weights, biases = self.func(model[L-1], model[L]) # weights & biases
parameters["W" + str(L)] = weights
parameters["b" + str(L)] = biases
return parameters
# randn은 기본적으로 N(0, 1)이지만 분포를 변경하고 싶다면 E + STD * randn을 하면 된다.
def xavier_normal(self, input_n_neurons, output_n_neurons):
"""Xavier_initializer
"""
weights = np.random.randn(input_n_neurons, output_n_neurons) * np.sqrt(1/input_n_neurons)
biases = np.zeros(output_n_neurons)
return (weights, biases)
def he_normal(self, input_n_neurons, output_n_neurons):
"""HE initializer
"""
weights = np.random.randn(input_n_neurons, output_n_neurons) * np.sqrt(2/input_n_neurons)
biases = np.zeros(output_n_neurons)
return (weights, biases)
def uniform(self, input_n_neurons, output_n_neurons):
"""Uniform initializer
"""
weights = np.random.uniform(-np.sqrt(6/input_n_neurons), np.sqrt(6/input_n_neurons), size=(input_n_neurons, output_n_neurons))
biases = np.zeros(output_n_neurons)
return (weights, biases)
실행
model = [784, 128, 64, 10]
initializer = Initializers('xavier_normal')
parameters = initializer.initialize(model)
print(parameters)
>>
{'W1': array([[-0.05504582, 0.04282963, 0.02595826, ..., -0.00669037,
-0.04018348, -0.04663131],
[ 0.01021135, -0.00452216, 0.03960432, ..., -0.04031849,
-0.05577247, 0.03116825],
[-0.06263794, -0.02632167, -0.07130203, ..., 0.01598382,
0.01228563, 0.02785967],
...,
[ 0.02777647, 0.01758768, -0.02738023, ..., -0.01447581,
-0.01949043, 0.02401931],
[ 0.02945328, 0.01159059, -0.03148186, ..., -0.05432826,
0.06169061, -0.05389743],
[-0.03274268, -0.0338801 , -0.00144553, ..., -0.01839692,
-0.05859511, 0.03720035]]),
'b1': array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0.]),...
728x90
728x90
'데이터사이언스 이론 공부' 카테고리의 다른 글
하이퍼 파라미터 튜닝 구현하기 - Random Forest(랜덤포레스트) (0) | 2023.03.15 |
---|---|
ERC - CoMPM 모델 논문 구현 (0) | 2023.01.26 |
DNN(Deep Neural Network) 구현하기 with numpy(1) - Preprocess (0) | 2023.01.16 |
GPT3 모델의 대한 간략한 정리 (0) | 2023.01.09 |
BERT의 파생모델 [DistilBERT] (0) | 2022.12.30 |