출처: https://brunch.co.kr/@jennyjang93/30


0. 회귀 분석(Regression)이란?


회귀 분석은 머신러닝에서 연속적인 값을 예측하는 데 활용되는 기법으로, 입력 변수와 출력 변수 간의 관계를 학습합니다. 주로 가격 예측, 수요 예측, 트렌드 분석 등에 효과적이며, 데이터의 패턴을 파악해 미래 값을 예측하는 데 강점을 가집니다. 특히, 과적합 방지를 위한 정규화 기법(L1, L2)과 배치 정규화 등을 적용하면 더욱 일반화된 모델을 만들 수 있습니다.


1. 회귀 분석(Regression) 개요

회귀 분석은 입력 변수 \( X \)와 출력 변수 \( Y \) 간의 관계를 모델링하는 과정입니다. 일반적으로 다음과 같이 표현됩니다:

$$
Y = f(X) + \epsilon
$$

여기서:

  • \( Y \) : 출력 변수(종속 변수)
  • \( X \) : 입력 변수(독립 변수)
  • \( f(X) \) : 입력 변수 \( X \)에 대한 함수
  • \( \epsilon \) : 모델이 설명하지 못하는 오차 항

 

2. 선형 회귀(Linear Regression)

선형 회귀는 입력 변수와 출력 변수 간의 선형 관계를 가정하는 기법입니다.

단순 선형 회귀의 경우:

$$
Y = \beta_0 + \beta_1 X + \epsilon
$$

다중 선형 회귀의 경우:

$$
Y = \beta_0 + \beta_1 X_1 + \beta_2 X_2 + \dots + \beta_n X_n + \epsilon
$$

 

3. 배치 정규화 (Batch Normalization, BN)

배치 정규화는 각 층의 입력을 정규화하여 학습을 빠르고 안정적으로 만드는 기법입니다.

미니배치의 평균과 분산은 다음과 같이 계산됩니다:

$$
\mu_B = \frac{1}{m} \sum_{i=1}^{m} x_i
$$

$$
\sigma_B^2 = \frac{1}{m} \sum_{i=1}^{m} (x_i - \mu_B)^2
$$

정규화 (Normalization)를 수행하면:

$$
\hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}
$$

이후, 스케일링(Scale) 및 이동(Shift)을 적용하여 최종 변환을 수행합니다:

$$
y_i = \gamma \hat{x}_i + \beta
$$

 

4. 정규화 기법 (L1, L2 Regularization)

과적합을 방지하기 위해 사용되는 정규화(Regularization) 기법입니다.

 

🔹 L1 정규화 (Lasso Regression)

$$
\text{Loss} = \text{MSE} + \lambda \sum_{j=1}^{n} |\beta_j|
$$

🔹 L2 정규화 (Ridge Regression)

$$
\text{Loss} = \text{MSE} + \lambda \sum_{j=1}^{n} \beta_j^2
$$


4.5 BatchNormalization VS L1, L2 (Lasso, Ridge)

1. 목적의 차이:

  • Batch Normalization: 주로 신경망에서 사용되며, 각 층의 입력을 정규화하여 학습 속도를 높이고, 내부 공변량 변화(Internal Covariate Shift)를 줄이는 데 도움을 줍니다. 이는 모델의 안정성을 높이고, 더 깊은 네트워크를 효과적으로 학습할 수 있게 합니다.
  • Lasso 및 Ridge: 주로 회귀 분석에서 사용되며, 모델의 복잡성을 줄이고 과적합을 방지하기 위해 계수에 대한 규제를 적용합니다. Lasso는 L1 규제를 통해 일부 계수를 0으로 만들고, Ridge는 L2 규제를 통해 계수를 축소합니다.

2. 상호작용:

  • Batch Normalization은 각 층의 출력을 정규화하여 학습을 안정화하지만, 이 과정에서 Lasso나 Ridge와 같은 규제 기법이 적용되는 방식에 영향을 줄 수 있습니다. 예를 들어, Batch Normalization이 계수를 정규화하는 방식과 Lasso 또는 Ridge가 계수에 규제를 적용하는 방식이 서로 충돌할 수 있습니다.

3. 적용 시기:

  • 일반적으로 Batch Normalization은 활성화 함수 이전에 적용되며, Lasso와 Ridge는 손실 함수에 포함되어 계수에 대한 규제를 적용합니다. 이로 인해 두 기법을 함께 사용할 때는 적절한 순서와 방법을 고려해야 합니다.

4. 차이점

  • 그러나 전통적인 회귀 모델(예: 선형 회귀, 다항 회귀 등)에서는 Batch Normalization을 사용할 필요가 없습니다. 이러한 모델은 일반적으로 입력 데이터의 스케일링이나 정규화가 필요할 수 있지만, Batch Normalization의 개념은 신경망의 층에서의 정규화에 초점을 맞추고 있습니다.

 

5. 회귀 모델의 성능 평가

✅ 평균 제곱 오차 (Mean Squared Error, MSE)

$$
\text{MSE} = \frac{1}{N} \sum_{i=1}^{N} (Y_i - \hat{Y}_i)^2
$$

✅ 결정 계수 (R-squared)

$$ R^{2} = 1 - \frac{\sum_{i=1}^{N} (Y_i - \hat{Y}_i)^2}{\sum_{i=1}^{N} (Y_i - \bar{Y})^2} $$

 

여기서 \( \bar{Y} \)는 실제 값의 평균입니다.



6. 구현 코드

import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, regularizers
import matplotlib.pyplot as plt

# 1. 랜덤 데이터 생성 (회귀 문제)
np.random.seed(42)
X = np.linspace(-3, 3, 300)
y = 2 * X + np.random.normal(0, 1, 300)  # 노이즈 추가

# 훈련 및 검증 데이터 나누기
X_train, X_test = X[:250], X[250:]
y_train, y_test = y[:250], y[250:]

# 데이터를 (N, 1) 형태로 변환
X_train = X_train.reshape(-1, 1)
X_test = X_test.reshape(-1, 1)

# 2. 모델 생성 함수
def build_model(use_bn=False, use_l1=False, use_l2=False):
    model = keras.Sequential()
    
    # 첫 번째 Dense 레이어 (입력층)
    if use_bn:
        model.add(layers.Dense(64, input_shape=(1,), activation=None, kernel_initializer='he_normal'))
        model.add(layers.BatchNormalization())  # 배치 정규화 적용
        model.add(layers.Activation('relu'))  # 배치 정규화 후 활성화 함수 적용
    else:
        reg = None
        if use_l1:
            reg = regularizers.l1(0.01)  # L1 정규화 적용
        elif use_l2:
            reg = regularizers.l2(0.01)  # L2 정규화 적용
            
        model.add(layers.Dense(64, input_shape=(1,), activation='relu', kernel_regularizer=reg))
    
    # 두 번째 Dense 레이어
    model.add(layers.Dense(32, activation='relu'))
    
    # 출력층
    model.add(layers.Dense(1))  # 선형 회귀이므로 activation 없음
    
    # 모델 컴파일
    model.compile(optimizer='adam', loss='mse', metrics=['mae'])
    return model

# 3. 각각의 모델 생성
model_bn = build_model(use_bn=True)   # 배치 정규화 적용
model_l1 = build_model(use_l1=True)   # L1 정규화 적용
model_l2 = build_model(use_l2=True)   # L2 정규화 적용
model_base = build_model()            # 기본 모델 (정규화 없음)

# 4. 모델 학습
history_bn = model_bn.fit(X_train, y_train, epochs=100, verbose=0, validation_data=(X_test, y_test))
history_l1 = model_l1.fit(X_train, y_train, epochs=100, verbose=0, validation_data=(X_test, y_test))
history_l2 = model_l2.fit(X_train, y_train, epochs=100, verbose=0, validation_data=(X_test, y_test))
history_base = model_base.fit(X_train, y_train, epochs=100, verbose=0, validation_data=(X_test, y_test))

# 5. 학습 결과 비교
plt.figure(figsize=(12, 6))

plt.plot(history_base.history['val_loss'], label='No Regularization', linestyle='dashed')
plt.plot(history_bn.history['val_loss'], label='Batch Norm', linestyle='dotted')
plt.plot(history_l1.history['val_loss'], label='L1 Regularization')
plt.plot(history_l2.history['val_loss'], label='L2 Regularization')

plt.xlabel('Epochs')
plt.ylabel('Validation Loss')
plt.title('Effect of Batch Normalization & Regularization on Regression')
plt.legend()
plt.show()

+ Recent posts