강명호 강사님
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_sample
과 t_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
)을 받아 시각화한다.cmap='grey'
로 설정해 회색조로 이미지를 표시하며 각 이미지의 제목에는 예측값과 실제값이 표시된다.# 예측값과 함께 이미지 출력
show_images_with_predictions(x_sample, t_sample, predicted_labels)
show_images_with_predictions
함수를 호출하여 모델의 예측 결과와 실제 레이블을 시각화한다.
최적화는 학습 중 손실 함수의 값을 최소화하는 매개변수들을 찾는 과정이다.
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]
에 학습률을 곱한 값을 빼서 매개변수를 손실을 줄이는 방향으로 업데이트한다.확률적 경사 하강법에 '관성' 개념을 추가해 경사하강의 방향성을 더욱 효율적으로 유지하고 빠르게 수렴하도록 돕는 방식이다. 이전 업데이트 방향을 일정 비율로 반영해 매개변수가 불필요하게 진동하는 것을 방지하면서 빠르게 최적화하는 역할을 한다.
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
를 반영해 업데이트한다.학습률을 자동으로 조정하는 방식으로 학습률이 큰 기울기는 줄이고 작은 기울기는 늘리면서 특히 희소(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으로 나누는 오류를 방지하기 위한 작은 값이다.일반 모멘텀에 '앞서 보기(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]
를 조합하여 더 넓은 시야로 기울기 정보를 반영한다.학습률을 자동으로 조정하는 기법으로, 기울기 제곱의 지수 이동 평균을 통해 학습이 안정적이고 빠르게 진행되도록 한다. 주로 학습률이 빠르게 감소하는 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은 안정성을 위한 작은 값이다.