[딥러닝]신경망

c.haha.e·2025년 8월 25일

STUDY

목록 보기
24/27

sklearn으로 신경망 구현

tensorflow - keras 라이브러리와 fashion_mnist 데이터 불러오기

from tensorflow import keras
(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data()
# 애초에 4덩이로 구분되어있어서 train_input, train_target, test_input, test_target 변수로 받을 수 있음

train 데이터와 test 데이터 구조확인

print(train_input.shape, train_target.shape)
#(60000, 28, 28) (60000,)
print(test_input.shape, test_target.shape)
#(10000, 28, 28) (10000,)
각 변수에 들어있는 데이터 구조를 확인.
train_input 은 (60000, 28, 28)인데 이건 28*28 이미지 데이터가 60000개 있는것.
  (전체 이미지 개수(1차원), 이미지의 세로 픽셀 수(2차원), 이미지의 가로 픽셀 수(3차원))


train_target 은 (60000, )인데 타겟 데이터는 60000개의 라벨

fashion_mnist 데이터 시각화 확인하기

import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 10, figsize=(10,10))
for i in range(10):
  axs[i].imshow(train_input[i], cmap='gray_r')
  axs[i].axis('off')
plt.show()

fig, axs = plt.subplots(1, 10, figsize=(10,10))
1행 10열의 서브플롯을 생성


fig => 서브플롯(axes)을 포함하는 가장 바깥의 컨테이너. 캔버스(도화지)라고 보면 됨.
axes => 캔버스(도화지)안의 작은 네모칸 하나를 의미
axs => 서브플롯(axes)에 들어갈 데이터
subplot() => 도화지를 나누는 방식
  1행 10열의 서브플롯을 생성
fig = Figure(1000 * 1000)
figsize=(10, 10) -> 10인치, 10인치
  픽셀로 바꾸면 10인치 X 100dpi = 1000픽셀, 10인치 X 100dpi = 1000픽셀
import numpy as np
print(np.unique(train_target, return_counts=True))

#(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8), array([6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000]))
np.unique(train_target, return_counts=True)

return_counts = True 는
train_target의 unique한 값을 count해서 돌려줌.
-> 각 요소마다 몇 번 나오는지 알 수 있음

이 데이터에서는
10개의 카테고리가있고
각 카테고리별로 6000개씩 train데이터가 들어있음

train데이터 정규화

train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28*28)
픽셀은 0~255까지 있는데
SGDClassifier에서는 특성마다 범위가 많이 다르면 적용시키기 애매함.
0~1 사이로 정해주는것이 좋음
이런 이유로 0~1사이로 만들어주기위해 255로 나눠줌


또한
SGDClassifier는 2차원 배열은 다룰 수 없으므로
2차원 배열인 각 샘플(28, 28)을 1차원 배열로 맞춰줘야함
reshape()를 이용

reshape(-1, 28*28)
-1 : 알아서 맞춤
28*28 : 샘플데이터의 2,3차원을 1차원으로 합침
   -> 그러면 1차원의 샘플개수는 변화없이 60000개!!!

모델만들기

from sklearn.model_selection import cross_validate
from sklearn.linear_model import SGDClassifier
sc = SGDClassifier(loss = 'log_loss', max_iter = 5, random_state = 42)
scores = cross_validate(sc, train_scaled, train_target, n_jobs = -1)
print(np.mean(scores['test_score']))
#0.8194166666666666
확률적 경사 하강법(SGD)를 이용
  (loss = 'log_loss', max_iter = 5, random_state = 42)
    loss = 'log_loss' : 로지스틱 회귀를 의미
    max_iter = 5 : 한번 학습할때 최대5번만 데이터 반복


교차 검증(Cross Validation)
  -> 데이터를 여러 조각으로 나눠서 여러번 학습/검증하여 평균 성능을 계산

  작동흐름(기본 5-fold)
    데이터를 5등분
    4개는 훈련, 1개는 검증
    이걸 총 5번 바꿔가며 훈련/검증
    각각의 test_score 저장

      혹시 fold설정하고싶으면
        from sklearn.model_selection import KFold

        cv=KFold(n_splits=7, shuffle=True, random_state=42)  
          -> 7등분 + 섞기
        scores = cross_validate(model, X, y, cv=cv)  으로 사용 가능

  (sc, train_scaled, train_target, n_jobs = -1)
    sc : 사용할 모델
    train_scaled : 입력데이터 (X)
    train_target : 정답데이터 (y)
    n_jobs = -1 : CPU병렬처리(모든코어사용)

  scores = cross_validate(...)
    결과는 딕셔너리 형식으로 반환
    ex)
      scores.keys()
      # dict_keys(['fit_time', 'score_time', 'test_score'])

      scores['test_score']->5개의 검증 정확도 리스트가 들어있음

  print(np.mean(scores['test_score']))
    다섯 번 검증한 결과의 평균 정확도 출력


전체 흐름 정리
  - train_scaled, train_target으로
  - SGDClassifier 모델을 5번 훈련 + 검증하면서
  - test_score에 성능 저장
  - 평균 정확도를 print로 출력

덴서플로의 케라스 사용하며 인공신경망 모델 만들기

모델 구조정의

# (케라스의 Dense클래스를 사용해 밀집층만들기)
from tensorflow import keras
dense = keras.layers.Dense(10, activation = 'softmax', input_shape = (784,))
# (케라스의 Dense클래스를 사용해 밀집층만들기)

Dense(10, activation = 'softmax', input_shape = (784,))
  (출력층의 개수, 출력에 적용할 함수, 입력의 크기)
  -> 입력의 크기는 784, 출력에 적용할 함수는 softmax, 출력층의 갯수는 10개


********Dense는 무조건 2차원으로 입력을 받아야함. 고로 3차원인 데이터는 평탄화 필요
# 신경망 모델을 Sequential클래스로 만들기
# Sequential 클래스는 밀집층인 danse를 받음.

model = keras.Sequential([dense])
# 신경망 모델을 Sequential클래스로 만들기
# Sequential 클래스는 밀집층인 danse를 받음.




Sequential 모델은 언제 사용???
  입력 → 은닉층 → 출력층
  레이어가 순서대로만 흘러가는 구조일 때
  복잡한 연결(분기, 병합 등)이 없을 때 적합



model = keras.Sequential(dense)  # 에러 발생 / 책이 잘못나옴

* 이유
여기서 dense는 레이어 하나인데,
Sequential()은 내부적으로 레이어들을 반복(iterate) 해서 쌓기 때문에,
리스트 형태로 넣어줘야 함.

최신 권장 방식

from tensorflow import keras
inputs = keras.Input(shape=(784,))  # 입력 정의 (명시적인 Input)
outputs = keras.layers.Dense(10, activation='softmax')(inputs)  # Dense는 입력을 받아서 연결
model = keras.Model(inputs=inputs, outputs=outputs)

또는,

model = keras.Sequential([
    keras.Input(shape=(784,)),                      # 명시적 입력
    keras.layers.Dense(10, activation='softmax')    # Dense는 입력만 받음
])

모델 학습설정

model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
keras에서 모델 학습설정은
model.compile() 사용


model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
  loss = 손실함수
    손실함수
      이진 분류 -> binary_crossentropy
      다중 분류 ->
        원핫인코딩 후 사용
          categorical_crossentropy
        원핫인코딩 안된 데이터에 사용
          sparse_categorical_crossentropy

  metrics = ['accuracy']
    Keras는 metrics에 여러 개의 평가 지표를 넣을 수 있게 설계!!
    ********항상 리스트 형태로 받음



나와있지않지만 강사님이 많이 쓰신 파라(07-2에서 나옴)
optimizer = 'adam'
  optimizer :
    - 모델이 오답을 줄이기 위해 가중치를 조금씩 조정하는 방법
    - 딥러닝 모델이 **손실(loss)**을 줄이기 위해 가중치를 어떻게 바꿀지 결정하는 알고리즘,
    즉 **최적화 함수(Optimizer)**

  adam :
    - Adaptive Moment Estimation의 줄임말
    - 많이 쓰이는 최적화 알고리즘 중 하나
    - 학습 속도도 빠르고 성능도 좋아서 대부분의 모델에서 기본값처럼 자주 사용
  • Adam 특징
특징설명
학습률 자동 조절학습률을 각 가중치마다 자동으로 조정
빠르고 안정적초반에 빠르게 수렴하면서 진동도 적음
모멘텀 + RMSProp 결합과거 기울기 방향 + 변화량까지 고려

실제 모델 학습

model.fit(train_scaled, train_target, epochs = 5)

.fit() : 케라스에서 모델의 학습을 하는 메서드
sklearn과 비슷하나 epochs가 차이남.
  model.fit(입력데이터, 정답데이터, epochs = 반복할 횟수)

모델 검증

model.evaluate(val_scaled, val_target)

evaluate() : 케라스에서 모델의 성능을 평가하는 메서드
  model.evaluate(입력데이터, 정답데이터)

정리

사이킷런 모델

모델 -> sc = SGDClassifier(loss='log_loss(손실함수)', max_iter = 5(반복횟수))
훈련 -> sc.fit(train_scaled, train_target)
평가 -> sc.score(val_scaled, val_target)

케라스 모델

층생성 -> dense = keras.layers.Dense(10(출력층 개수), activation='softmax'(함수설정), input_shape=(784,)(입력 개수))
모델 -> model = keras.Sequential(dense)
        model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
훈련 -> model.fit(train_scaled, train_target, epochs = 5(반복횟수))
평가 -> model.evaludte(val_sacled, val_target)

활성화 함수

소프트맥스 함수

  • 여러 클래스 중 하나를 선택할 수 있도록 출력을 확률처럼 정규화
  • 출력값들이 모두 0~1 사이이며, 총합이 1이 되는 확률 벡터
    (softmax([2.0, 1.0, 0.1]) -> [0.659, 0.242, 0.099] -> 전체 합이 1 )
  • 각 클래스에 대해 예측된 확률을 명확히 해석 가능
  • 다중 분류 문제의 출력층
  • 예측 결과를 확률로 해석할 수 있어 직관적이고 분석이 쉬움

시그모이드 함수

  • 초창기 인공신경망에 많이 사용된 활성화 함수
  • 입력 값을 0~1 사이의 확률처럼 변환
  • 출력이 항상 부드럽고 연속적
  • 입력이 매우 크거나 작으면 기울기 소실(Vanishing Gradient) 발생
    올바른 출력을 만드는데 신속한 대응이 안됨.
  • 층이 많을수록 그래디언트가 누적되며 학습이 잘 안 됨
  • 은닉층 또는 이진분류의 출력층에 사용
    (과거에는 은닉층에서 사용, 현재는 이진 분류의 출력층에서만 주로 사용)

렐루함수

  • 입력이 양수일 경우 마치 활성화함수가 없는 것처럼 입력을 통과시키고,
    입력이 음수일 경우 0으로 만듦
  • 계산 빠름, 기울기 소실이 없음 (그래디언트 유지됨)
  • 심층 신경망에서 빠른 학습, 효과적인 수렴
  • 이미지 처리, CNN, DNN에 기본 활성화 함수처럼 사용됨
  • 은닉층에서 매우 널리 사용

심층신경망(DNN)

심층 신경망(DNN)

  입력층(Input layer)과 출력층(Output layer) 사이에
  은닉층(Hidden layers)이 2개 이상 존재하는 인공 신경망



[예시 구조]

[입력층]
   ↓
[은닉층1]  ← Dense
   ↓
[은닉층2]  ← Dense
   ↓
[출력층]   ← Softmax
  • 얕은 신경망 vs 심층 신경망 비교표
항목얕은 신경망 (Shallow NN)심층 신경망 (Deep NN)
정의은닉층이 1개 이하은닉층이 2개 이상
구조 예시입력 → 은닉 1개 → 출력입력 → 은닉 1 → 은닉 2 → ... → 출력
복잡도구조가 단순구조가 복잡
표현력제한적복잡한 패턴 표현 가능
학습 난이도쉽고 빠름느리고 튜닝 필요
적합 문제간단한 문제복잡한 문제 (이미지, 자연어 등)
예시퍼셉트론, 간단한 MLPCNN, RNN, Transformer 등

신경망(분류)

  • 출력층의 활성화 함수
  - 이진분류 : 시그모이드 함수
  - 다중분류 : 소프트맥스 함수
  • 은닉층의 활성화 함수
  - 시그모이드 함수
  - 렐루 함수

신경망(회귀)

  • 활성화 함수가 필요없음
  -> 회귀는 Dense층의 activation 매개변수에 아무런 값을 지정하지 않음.

모델에 층 추가하는 방법

방법 1

dense1 = keras.layers.Dense(100, activation = 'sigmoid', input_shape = (784, ))
dense2 = keras.layers.Dense(10, activation = 'sigmoid')
두 번째 층부터는 Keras가 자동으로 입력 shape를 추론
즉, dense1의 출력이 dense2의 입력이 되기 때문에 input_shape가 필요 없음.
model = keras.Sequential([dense1, dense2])
model.summary()

  • model.summary()
케라스는 모델의 summary() 메서드를 호출하면 층에 대한 정보를 얻을 수 있음
  • Dense 층의 파라미터 수 공식
파라미터 수 = (입력 노드 수 × 출력 노드 수) + 출력 노드 수
  • name을 매개변수로 지정할 수 있음
from tensorflow import keras
dense1 = keras.layers.Dense(100, activation='relu', input_shape=(784,), name='hidden_layer_1')
dense2 = keras.layers.Dense(10, activation='softmax', name='output_layer')
model = keras.Sequential([dense1, dense2])
  • 출력 크기가 None인 이유
  - (None, 100) = (배치 크기, 뉴런 수)
  None → 입력 데이터가 한 번에 몇 개 들어올지는 아직 모른다
     (fit() 할 때 batch_size = .. 로 설정 가능)
  - 100 → 이 레이어에서 나가는 출력 뉴런 수
  • batch_size
케라스에서 기본 미니 batch_size = 32
모델이 다양한 크기의 입력을 받을 수 있도록(유연하게 사용하기 위해) None으로 남겨 둠.
fit()할때 사용
1개만 넣어도 되고 (배치=1), 64개 넣어도 되고 (배치=64), 전부 넣어도 됨

방법 2

model = keras.Sequential([
    keras.layers.Dense(100, activation='sigmoid', input_shape=(784, ), name = 'hidden'),
    keras.layers.Dense(10, activation='softmax', name = 'output')
], name = '패션 MNIST 모델')
model.summary()

방법 3

model = keras.Sequential()
model.add(keras.layers.Dense(100, activation='sigmoid', input_shape=(784,), name = 'hidden'))
model.add(keras.layers.Dense(10, activation='softmax', name = 'output'))
model.summary()

방법 3은
- Dense 클래스의 객체를 따로 변수에 담지않고 바로 add()메서드로 전달할 수 있음.
- 추가되는 층을 한눈에 볼 수 있음
- 실행시 동적으로 층을 선택하여 추가할 수 있음.

Flatten 층

  • Flatten 클래스는 배치차원을 제외하고 나머지 입력 차원을 모두 일렬로 펼치는 역할
  • Flatten클래스를 층처럼 입력층과 은닉층 사이에 추가하기 때문에 층이라고 부름.
  • 위 코드처럼 입력층 바로 뒤에 추가
  • Flatten을 사용하면 입력값의 차원을 짐작하기 쉬움.
model = keras.Sequential([
    keras.Input(shape=(28, 28)),               # ← 입력층 명시
    keras.layers.Flatten(),                    # ← Flatten은 평탄화만 함
                                               # 앞에서 데이터 전처리시 reshape() 필요없음
    keras.layers.Dense(100, activation='relu'),
    keras.layers.Dense(10, activation='softmax')
])
model.summary()

모델 설정 & 훈련 & 검증

from tensorflow import keras
(train_input, train_target), (test_input, test_tergat) = keras.datasets.fashion_mnist.load_data()
train_scaled = train_input / 255.0
train_scaled, val_scaled, train_target, val_target = train_test_split(
    train_scaled, train_target, test_size = 0.2, random_state = 42
)

model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
model.fit(train_scaled, train_target, epochs = 5)

model.evaluate(val_scaled, val_target)

하이퍼파라미터

  • 모델이 학습하지않아 사람이 직접 지정해줘야하는 파라미터
    (은닉층의 수, 은닉층의 뉴런의 수, 활성화함수, 층의 종류, 배치 사이즈의 크기, 에포크의 수, 옵티마이저 등..)

옵티마이저 ( Adam 중요 )

  • 손실 함수의 값을 최소화(minimize)하기 위해 가중치를 어떻게 업데이트할지 결정하는 알고리즘
  • 대표 옵티마이저
Optimizer핵심 아이디어수식 요약대표 특징
SGD순수 경사하강법θ=θηL\theta = \theta - \eta \cdot \nabla L단순하지만 진동 심하고 느림
Momentum이전 속도(모멘텀)를 이용한 가속vt=γvt1+ηLv_t = \gamma v_{t-1} + \eta \nabla L진동 줄이고 빠른 수렴 가능
Nesterov모멘텀 + 미리 한 발 앞으로 가서 기울기 확인vt=γvt1+ηL(θγvt1)v_t = \gamma v_{t-1} + \eta \nabla L(\theta - \gamma v_{t-1})더 정교한 방향 제어
Adagrad각 가중치별로 학습률 자동 조절θ=θηG+ϵL\theta = \theta - \frac{\eta}{\sqrt{G + \epsilon}} \nabla L희소 데이터에 유리 (텍스트 등)
RMSpropAdagrad의 단점 보완 (최근 기울기에 가중치)Gt=ρGt1+(1ρ)g2G_t = \rho G_{t-1} + (1-\rho)g^2RNN 계열에 잘 작동
AdamMomentum + RMSprop 조합mt,vtm_t, v_t로 평균과 제곱평균 반영대부분의 문제에 기본값처럼 사용됨
NadamAdam + Nesterov복잡한 결합식Adam보다 빠른 수렴 가능

SGD (Stochastic Gradient Descent)

  • 가장 기본적인 옵티마이저, 간단하고 직관적
  • 단순하지만,기울기 방향만 보고 이동하기 때문에
    손실이 들쭉날쭉하게 줄어들고 진동이 심할 수 있음
  • 매 반복마다 일부 데이터(batch)로 손실을 계산해 가중치 갱신
optimizer = keras.optimizers.SGD(learning_rate=0.1)
model.compile(optimizer = optimizer, loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])

Momentum

  • 관성 개념을 사용해 이전 방향으로 더 강하게 이동
  • 진동 감소 + 수렴 속도 증가
optimizer = keras.optimizers.SGD(momentum=0.9, nesterov = True)
model.compile(optimizer = optimizer, loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])

Nesterov (Nesterov Accelerated Gradient, NAG)

  • 모멘텀을 적용하기 전에 미리 한 걸음 앞서서 기울기를 계산하는 방식
  • 더 정확한 방향 제어
  • 수렴이 더 안정적이고 빠를 수 있음
optimizer = keras.optimizers.SGD(learning_rate=0.01, momentum=0.9, nesterov=True)

RMSprop

  • Adagrad의 단점(학습률 소멸)을 해결
  • 최근 기울기에 지수적으로 가중치를 줘서 더 안정적 (지수평균)
  • RNN, LSTM에 매우 적합
  • 빠른 수렴
optimizer = keras.optimizers.RMSprop(learning_rate=0.001)
model.compile(optimizer = optimizer, loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])

Adagrad

  • 각 파라미터마다 학습률을 자동 조절
  • 자주 바뀌는 가중치는 더 천천히 학습
    → 희소 데이터에 효과적(ex. 텍스트)
  • 단점: 학습률이 너무 작아져서 금방 멈춰버릴 수 있음
optimizer = keras.optimizers.Adagrad(learning_rate=0.01)
model.compile(optimizer = optimizer, loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])

Nadam (Nesterov + Adam)

  • Adam에 Nesterov 모멘텀을 추가한 방식
  • 최신 최적화 기법 중 하나
  • 이론적으로 Adam보다 빠르게 수렴할 수도 있음 (실험적으로 사용됨)
optimizer = keras.optimizers.Nadam(learning_rate=0.001)
model.compile(optimizer = optimizer, loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])

Adam (Adaptive Moment Estimation) 중요

  • Momentum + RMSprop 결합
  • Momentum (기울기의 평균)
  • RMSprop (기울기의 제곱 평균)
  • 가장 널리 쓰임, 대부분의 문제에서 잘 동작
optimizer = keras.optimizers.Adam(learning_rate=0.001)
model.compile(optimizer = optimizer, loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])

정리

옵티마이저계산 방식장점대표 용도
SGD순수 경사 하강단순, 느림실험, 비교용
Momentum+ 속도빠른 수렴CNN 등
Nesterov+ 더 앞서 보기정교한 이동고급 CNN
Adagrad개별 학습률희소 데이터에 강함텍스트
RMSprop최근 기울기 반영빠름, RNN에 좋음시계열
AdamMomentum + RMSprop👍가장 널리 쓰임거의 모든 문제
NadamAdam + Nesterov더 빠를 수 있음실험적 최적화
model.fit(train_scaled, train_target, epochs = 5)

model.evaluate(val_scaled, val_target)00

profile
기록용 블로그

0개의 댓글