스물아홉번째 수업 | 조퇴 | 오차역전파법 | 학습 관련 기술들

Faithful Dev·2024년 10월 28일
0

강명호 강사님

오차역전파법

이미지 예측 실험

import matplotlib.pyplot as plt

# 임의의 5개 이미지 선택
sample_indices = np.random.choice(x_test.shape[0], 5)
x_sample = x_test[sample_indices]
t_sample = t_test[sample_indices]
  • np.random.choice를 사용해 테스트 데이터셋에서 임의로 5개의 이미지를 선택한다.
  • 선택된 인덱스를 x_samplet_sample에 저장하여 각각 이미지 데이터와 실제 모델 레이블로 사용한다.
# 예측
y_sample = network.predict(x_sample)
predicted_labels = np.argmax(y_sample, axis=1)
  • TwoLayerNet 클래스의 predict() 메서드를 사용해 x_sample에 대한 예측을 수행한다.
  • 소프트맥스 출력 중 가장 높은 값을 가진 인덱스가 모델의 예측 레이블이므로 np.argmax를 사용해 각 샘플에 대한 예측 레이블을 predicted_labels에 저장한다.
# 이미지와 예측 결과 출력
def show_images_with_predictions(images, true_labels, predicted_labels):
    plt.figure(figsize=(10, 4))
    for i in range(len(images)):
        # 이미지 시각화 (28x28 이미지를 원래 크기로 복원)
        img = images[i].reshape(28, 28)
        true_label = true_labels[i]
        predicted_label = predicted_labels[i]

        # 서브플롯에 이미지 그리기
        plt.subplot(1, 5, i+1)
        plt.imshow(img, cmap='gray')
        plt.title(f"Pred: {predicted_label}\nTrue: {true_label}", fontsize=7)
        plt.axis('off')

    plt.tight_layout()
    plt.show()
  • show_images_with_predictions: 이미지와 예측 결과를 표시.
    - plt.subplot(1, 5, i+1): 1행 5열의 레이아웃에서 현재 이미지 위치를 지정한다.
    • plt.imshow(img, cmap='grey'): 이미지를 회색조로 표시.
    • plt.title(): 각 이미지의 제목을 예측 레이블과 실제 레이블로 표시.
  • plt.tight_layout(): 서브플롯 간 간격을 자동으로 조절해 그래프가 겹치지 않도록 한다.
# 예측값과 함께 이미지 출력
show_images_with_predictions(x_sample, t_sample, predicted_labels)
  • 임의로 선택된 이미지와 예측된 레이블 및 실제 레이블을 시각화한다.
import pickle
# 가중치 저장 함수
def save_params(network, file_name='params.pkl'):
    with open(file_name, 'wb') as f:
        pickle.dump(network.params, f)
  • 신경망 객체 network의 파라미터를 파일로 저장
  • pickle.dump()를 사용해 network.params를 파일로 저장하는데 params에는 신경망의 가중치와 편향이 포함되어 있다.
    파일이 wb 모드로 열려있으므로 바이너리 쓰기 모드로 저장된다.
  • 기본 파일 이름은 params.pkl이며 필요한 경우 다른 이름으로 지정할 수 있다.
# 가중치 로드 함수
def load_params(network, file_name='params.pkl'):
    with open(file_name, 'rb') as f:
        network.params = pickle.load(f)
  • 지정한 파일(file_name)에서 파라미터를 로드하여 신경망에 적용한다.
  • pickle.load()를 사용해 params.pkl 파이렝서 파라미터를 읽어 network.params에 저장한다.
  • 신경망은 이 파라미터를 통해 가중치와 편향 값을 설정하게 되므로 로드 후에는 학습된 모델을 바로 사용할 수 있다.
  • 기본 파일 이름은 params.pkl이지만 저장할 때와 마찬가지로 파일명을 변경할 수 있다.
load_params(network) # 저장된 가중치를 로드
  • load_params(network)를 사용하여 학습된 가중치와 편향을 params.pkl 파일에서 로드한다. 이를 통해 network 객체가 학습된 모델의 상태로 설정된다.
# 임의의 5개 이미지 선택
sample_indices = np.random.choice(x_test.shape[0], 5)
x_sample = x_test[sample_indices]
t_sample = t_test[sample_indices]
  • 테스트 데이터셋 x_test에서 무작위로 5개의 이미지를 선택하여 예측에 사용할 샘플을 만든다.
# 예측
y_sample = network.predict(x_sample)
predicted_labels = np.argmax(y_sample, axis=1)
  • network.predict(x_sample)를 통해 샘플 이미지에 대한 예측을 수행한다.
  • np.argmax(y_sample, axis=1)을 사용하여 각 샘플에 대해 가장 높은 확률 값을 가진 클래스 인덱스를 predicted_labels에 저장한다.
# 이미지와 예측 결과 출력
def show_images_with_predictions(images, true_labels, predicted_labels):
    plt.figure(figsize=(10, 4))
    for i in range(len(images)):
        # 이미지 시각화 (28*28 이미지를 원래 크기로 복원)
        img = images[i].reshape(28, 28)
        true_label = true_labels[i]
        predicted_label = predicted_labels[i]

        # 서브플롯에 이미지 그리기
        plt.subplot(1, 5, i+1)
        plt.imshow(img, cmap='grey')
        plt.title(f'Pred: {predicted_label}\nTrue: {true_label}', fontsize=7)
        plt.axis('off')

    plt.tight_layout()
    plt.show()
  • show_images_with_prediction: 입력 이미지(images), 실제 레이블(true_labels), 예측 레이블(predicted_labels)을 받아 시각화한다.
  • 각 이미지를 28*28 크기로 복원하고 서브 플롯에 배치해 5개의 이미지를 한 번에 보여준다.
  • cmap='grey'로 설정해 회색조로 이미지를 표시하며 각 이미지의 제목에는 예측값과 실제값이 표시된다.
# 예측값과 함께 이미지 출력
show_images_with_predictions(x_sample, t_sample, predicted_labels)

show_images_with_predictions 함수를 호출하여 모델의 예측 결과와 실제 레이블을 시각화한다.

학습 관련 기술들

매개변수 갱신

최적화는 학습 중 손실 함수의 값을 최소화하는 매개변수들을 찾는 과정이다.

확률적 경사하강법 (Stochastic Gradient Descent, SGD)

SGD는 한 번에 전체 데이터를 사용하지 않고 일부 샘플을 사용해 손실의 기울기를 계산하고, 그 방향으로 이동해 최적의 매개변수를 찾아간다. 기울기가 급격하게 변하면 효율이 떨어질 수 있다.

class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr

    def update(self, params, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key]
  • __init__ 메서드
    - 학습률(lr)을 설정. lr 값은 학습의 속도를 결정하는 요소이다.
    • lr의 기본값은 0.01로 설정되어 있으며 초기화 시 다른 값으로 변경할 수 있다.
  • update 메서드
    - params: 모델의 매개변수를 담고 있는 딕셔너리. 각 매개변수의 이름을 키로 사용하고 해당 매개변수의 값을 저장한다.
    • grads: 매개변수들에 대한 기울기(gradient) 값들을 담고 있는 딕셔너리이다. params와 동일한 키를 가지고 있어 각 매개변수에 대한 기울기를 저장한다.
    • params[key] -= self.lr * grads[key]: 각 매개변수 params[key]에서 기울기 grads[key]에 학습률을 곱한 값을 빼서 매개변수를 손실을 줄이는 방향으로 업데이트한다.

모멘텀 (Momentum)

확률적 경사 하강법에 '관성' 개념을 추가해 경사하강의 방향성을 더욱 효율적으로 유지하고 빠르게 수렴하도록 돕는 방식이다. 이전 업데이트 방향을 일정 비율로 반영해 매개변수가 불필요하게 진동하는 것을 방지하면서 빠르게 최적화하는 역할을 한다.

class Momentum :
    def __init__(self, lr=0.01, momentum=0.9) :
            self.lr = lr
            self.momentum = momentum
            self.v = None
        
    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for key, val in params.items():
                self.v[key] = np.zeros_like(val)

            for key in params.keys():
                self.v[key] = self.momentum*self.v[key] - self.lr*grads[key]
                params[key] += self.v[key]
  • __init__ 메서드
    - lr: 학습률. 매개변수의 변화량을 조정한다.
    • momentum: 모멘텀 계수로 보통 0.9로 설정된다. 이 계수가 클수록 이전 업데이트 방향을 더 많이 반영하게 된다.
    • v: 각 매개변수별로 저장되는 속도(velocity) 벡터를 저장하기 위한 변수. 첫번째 업데이트 시에 초기화된다.
  • update 메서드
    - 속도 초기화: v가 None일 경우 params의 모든 키에 대해 v[key]를 0으로 초기화한다.
    • self.v[key] = self.momentum * self.v[key] - self.lr * grads[key]: 속도 업데이트. 현재 기울기 방향과 모멘텀 계수를 이용해 매개변수의 속도를 업데이트한다.
    • params[key] += self.v[key]: 매개변수 업데이트. 각 매개변수를 속도 v를 반영해 업데이트한다.

AdaGrad

학습률을 자동으로 조정하는 방식으로 학습률이 큰 기울기는 줄이고 작은 기울기는 늘리면서 특히 희소(sparse)한 특성에서 효과적인 학습을 가능하게 한다.

class Adagrad :
    def __init__(self, lr=0.01) :
        self.lr = lr
        self.h = None

    def update(self, params, grads):
        if self.h is None:
            self.h = {}
            for key, val in params.items():
                self.h[key] = np.zeros_like(val)

            for key in params.keys():
                self.h[key] += grads[key] * grads[key]
                params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
  • __init__ 메서드
    - lr: 학습률. 학습률은 Adagrad에서 자동으로 조정되지만 초기 학습률을 설정할 수 있다.
    • h: 각 매개변수의 기울기 제곱합을 저장하는 변수.
  • update 메서드
    - 기울기 제곱합 초기화: self.h가 None이면 params의 모든 키에 대해 h를 0으로 초기화한다.
    • self.h[key] += grads[key] * grads[key]: 기울기 제곱 합산: 각 매개변수에 대한 기울기의 제곱을 누적하여 합산.
    • params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7): 매개변수 업데이트. 누적된 기울기의 제곱합을 제곱근으로 감쇠시키면서 매개변수를 업데이트한다. 1e-7은 0으로 나누는 오류를 방지하기 위한 작은 값이다.

NAG (Nesterov Accelerated Gradient)

일반 모멘텀에 '앞서 보기(lookahead)' 기능을 추가하여 현재 지점이 아닌 예상 위치에서 기울기를 계산한다. 이렇게 하면 경사면의 더 나은 정보를 활용해 매개변수 업데이트의 방향을 정할 수 있다.

class Nesterov :
    def __init__(self, lr=0.01, momentum=0.9) :
        self.lr = lr
        self.momentum = momentum
        self.v = None
        
    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for key, val in params.items():
                self.v[key] = np.zeros_like(val)

            for key in params.keys():
                self.v[key] *= self.momentum
                self.v[key] -= self.lr * grads[key]
                params[key] += self.momentum * self.momentum * self.v[key]
                params[key] -= (1 + self.momentum) * self.lr * grads[key]
  • __init__
    - lr: 학습률. 기울기를 적용하는 크기를 조정한다.
    • momentum: 모멘텀 계수. 이전 속도를 얼마나 반영할지 결정한다.
    • v: 매개변수와 같은 구조를 가진 속도 벡터. 각 매개변수에 대한 속도를 저장한다.
  • update
    - 속도 초기화: self.v가 None일 경우 params의 키를 이용해 속도 벡터를 0으로 초기화.
    • self.v[key] *= self.momentum: 속도 갱신. 현재 속도에 모멘텀 계수를 곱해 갱신한다. 이후 self.v[key] -= self.lr * grads[key]에서 기울기 정보를 사용해 조정한다.
    • 매개변수 업데이트: 네스테로프 방식에 따라 params[key]를 업데이트한다. 모멘텀 값을 두 번 곱한 항목(self.momentum * self.momentum * self.v[key])과 (1 + self.momentum) * self.lr * grads[key]를 조합하여 더 넓은 시야로 기울기 정보를 반영한다.

RMSProp

학습률을 자동으로 조정하는 기법으로, 기울기 제곱의 지수 이동 평균을 통해 학습이 안정적이고 빠르게 진행되도록 한다. 주로 학습률이 빠르게 감소하는 Adagrad의 문제를 보완하는 방법이다.

class RMSProp:
    def __init__(self, lr=0.01, decay_rate = 0.99):
        self.lr = lr
        self.decay_rate = decay_rate
        self.h = None
    
    def update(self, params, grads):
        if self.h is None:
            self.h = {}
            for key, val in params.items():
                self.h[key] = np.zeros_like(val)
            
        for key in params.keys():
            self.h[key] *= self.decay_rate
            self.h[key] += (1 - self.decay_rate) * grads[key] * grads[key]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
  • __init__
    - lr: 학습률. 업데이트에 적용하는 기울기의 크기를 조절한다.
    • decay_rate: 감쇠 계수. 보통 0.99로 설정되며 기울기의 지수 이동 평균을 계산할 때 사용한다. 값이 클수록 과거 기울기의 영향을 더 크게 반영하게 된다.
    • h: 기울기 제곱 합을 저장하는 변수. 각 매개변수에 대한 기울기 정보를 누적하는 데 사용한다.
  • update
    - h 초기화: self.h가 None일 경우 params의 키를 사용해 각 매개변수와 동일한 구조로 h를 0으로 초기화한다.
    • 기울기 제곱 합 갱신: self.h[key] *= self.decay_rate로 이전 기울기 제곱합에 감쇠 계수를 곱해 누적을 줄이고, self.h[key] += (1 - self.decay_rate) * grads[key] * grads[key]를 통해 현재 기울기 제곱의 비율을 추가한다.
    • 매개변수 업데이트: params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)에서 기울기 제곱합의 제곱근을 사용해 학습률을 조정한다. 1e-7은 안정성을 위한 작은 값이다.
profile
Turning Vision into Reality.

0개의 댓글