딥러닝 - 인공신경망(ANN, Artificial Neural Nework)
- 딥러닝은 인공신경망을 기반으로 한 머신러닝 기술.
인공신경망은 인간의 뇌 신경망을 모방하여 만든 모델로, 복잡한 데이터 패턴을 학습하고 예측할 수 있다.
- 인공신경망(ANN) : 입력층(Input Layer), 은닉층(Hidden Layer), 출력층(Output layer)으로 구성된다.
각 층의 뉴런이 가중치와 활성화 함수를 이용해 연결됨. - 기본 구조 : [입력층] > [은닉층1] > [은닉층2] > ... > [출력층]
- 입력층 : 입력 데이터가 들어오는 층
- 은닉층 : 여러 개의 뉴런이 가중치를 통해 연결됨
- 출력층 : 최종 예측 결과가 출력되는 층
- 뉴런(Neuron) : 여러 개의 입력 값을 받아 가중치를 곱하고 이를 활성화 함수를 통해 비선형 변환해서 다음 층으로 전달.
# 텐서플로우, 케라스 설치
# 아나콘다 프롬프트(파워쉔 프롬프트)에서
# pip 업그레이드 : python -m pip install --upgrade pip
# conda 가상환경 만들기 : conda create -n tensorflow python=3.11
# conda 가상환경 활성화 : activate tensorflow
# tensorflow 설치 : pip install tensorflow
# 케라스 설치 : pip install keras
# 텐서플로우 버전 확인
import tensorflow as tf
print(tf.__version__)

샘플 데이터 로드
from tensorflow import keras
# 훈련 데이터, 테스트 데이터 로드
(train_input, train_target), (test_input, test_target) = \
keras.datasets.fashion_mnist.load_data()
print('훈련 이미지 크기 :', train_input.shape)
print('훈련 레이블 크기 :', train_target.shape)

# 테스트 데이터 크기 확인
print(test_input.shape, test_target.shape)

# 샘플 출력
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()



0 ~ 9 까지 각 레이블마다 6000개의 샘플이 있음
로지스틱 회귀로 패션 아이템 구분하기
# SGDClassifier : 확률적 경사하강법 사용
train_scaled = train_input / 255.0 # 값의 범위 표준화
train_scaled = train_scaled.reshape(-1, 28 * 28)
- train_scaled = train_input / 255.0 : 0-1로 표준화
- train_scaled = train_scaled.reshape(-1, 28 * 28) : 이미지를 1차원 벡터로 변

trian_input의 크기 (60000, 28, 28)에서 6000개의 28x28크기의 이미지 배열을
28 x 28 = 784 길이의 1차원 벡터로 변환
# SGDClassifier 클래스와 cross_validate 함수를 사용해서 교차검증으로 성능 확인
from sklearn.model_selection import cross_validate
from sklearn.linear_model import SGDClassifier
sgd = SGDClassifier(loss = 'log_loss', max_iter = 20, random_state = 42)
scores = cross_validate(sgd, train_scaled, train_target, n_jobs = -1)
print('교차 검증 점수 :', np.mean(scores['test_score']))

인공신경망 모델 만들기
# 훈련 데이터와 테스트 데이터로 나누기
from sklearn.model_selection import train_test_split
train_scaled, val_scaled, train_target, test_target = train_test_split(
train_scaled, train_target, test_size = 0.2, random_state = 42)
print('1차원 벡터로 변환된 훈련 이미지 데이터 :', train_scaled.shape)
print('훈련 이미지 레이블 :', train_target.shape)

# 패션 아이템 10개를 분류하기 위한 10개의 뉴런
# 10 - 뉴련 갯수, activation - 뉴런의 출력층에 적용할 함수, input_shape - 입력 크기
dense = keras.layers.Dense(10, activation = 'softmax', input_shape = (784,))
# Sequential - 케라스에서 신경망 모델을 생성하는 클래스
model = keras.Sequential([dense])
model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
# 케라스 모델 훈련 전 설정 단계 : compile() 메서드
# 이진분류 : loss = 'binary_crossentropy'
# 다중분류 : loss = 'categorial_crossentropy'
- keras.layers.Dense : 출력층 정의
- 10 : 출력층의 뉴런 수
- activation = 'sorftmas : sorftmax 활성화 함수(다중 클래스 분류에서 사용)
각 클래스에 대한 확률을 출력 - input_shpae(784,) : 입력 데이터 크기
- model = keras.Sequential([dense])
- keras.Sequential : 순차 모델 정의
- [dense] : 출력층만 있는 모델
- model.compile(loss='sparse_categorical_crossentropy', metrics=['accuracy'])
- loss='sparse_categorical_crossentropy' : 손실 함수를 설정
- metrics=['accuracy']: 모델의 성능을 평가할 지표로 정확도(accuracy)를 설정

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

5번의 에포크(epoch) 동안 학습 : accuracy(정확도) - loss(손실)
>> 정확도 85%
검증 세트에서 모델 성능 확인하기
val_loss, val_acc = model.evaluate(val_scaled, test_target)
print(f"검증 데이터 손실 : {val_loss}, 검증 데이터 정확도 : {val_acc}")

검증 세트 점수는 훈련 세트 보다 조금 낮은 수
딥러닝 - 심층 신경망(DNN, Deep Neural Networks)
- 여러개의 은닉층을 가진 신경망 모델
- 특징
- 다양한 층 : 은닉층이 여러 개인 신경망, 모델이 더 복잡한 패턴을 학습할 수 있다.
- 활성화 함수 : 단순한 선형 모델이 아니라 복잡한 패턴을 학습할 수 있다.
- 역전파 : 신경망의 가중치 학습을 위한 알고리즘, 예측 결과와 실제 값의 차이를 계산하고 오차를 기반으로 가중치를 조정.
- 장점
- 특징 학습을 통해 데이터를 직접적으로 특성으로 변환해 자동으로 중요한 정보를 추출
- 단순한 선형 관계를 넘어 복잡한 비선형 관계를 모델링할 수 있음
- 데이터가 많을수록 성능이 향상됨
- 단점
- 모델이 매우 복잡하기 때문에 훈련 데이터에 과적합
- 훈련에 많은 계산 자원(CPU/GPU)과 시간이 필요
- 하이퍼파라미터 조정이 중요
# 2개의 층 생성
# 데이터셋 준비
from tensorflow import keras
# 훈련 데이터와 데스트 데이터 로드
(train_input, train_target), (test_input, test_target) = \
keras.datasets.fashion_mnist.load_data()
print('훈련 이미지 크기 :', train_input.shape)
print('훈련 레이블 크기 :', train_target.shape)

from sklearn.model_selection import train_test_split
train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28 * 28)
train_scaled, val_scaled, train_target, val_target = train_test_split(
train_scaled, train_target, test_size = 0.2, random_state = 42)
시그모이드 활성화 함수를 사용한 은닉층과 소프트맥스 함수를 사용한 출력층을 케라스의 Dense 클래스에 등록
dense1 = keras.layers.Dense(100, activation = 'sigmoid', input_shape = (784,))
dense2 = keras.layers.Dense(10, activation = 'softmax')
- dense1
- 100개의 뉴런을 가진 은닉층
- 입력 크기 : (784,) = 28 x 28 이미지를 1차원 벡터로 변환
- 활성화 함수 : 시그모이드(sigmoid)는 출력값을 0과 1사이로 제한해서 각 뉴런의 출력을 표현
- dense2
- 10개의 뉴런을 가진 출력층
- 활성화 함수 : 소프트맥스(softmax)로 각 뉴런의 출력값을 클래스 확률로 변환해서 각 클래스의 확률을 출
심층 신경망 만들기
model = keras.Sequential([dense1, dense2])
model.summary()

층을 추가하는 다른 방법
1. Sequential 클래스 안에 바로 작성해서 추가하기
# dense1과 dense2 객체를 따로 사용할 일이 없으므로 Sequential클래스 안에 바로 작성
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()

2. add() 메서드 사용해서 추가하기
model = keras.Sequential()
model.add(keras.layers.Dense(100, activation='sigmoid', input_shape=(784,)))
model.add(keras.layers.Dense(10, activation='softmax'))
model.summary()

모델 훈련
model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
model.fit(train_scaled, train_target, epochs = 5)
- sparse_categorical_crossentropy는 다중 클래스 분류 문제에서 사용되는 손실 함수(레이블이 정수형일 때 사용)
- metrics = ['accuracy'] : 훈련 중 모델 성능을 평가할 지표로 정확도를 사용

훈련 세트에 대한 성능을 보면 층이 추가되서 성능이 향상됨
Relu 함수
- 딥러닝에서 가장 많이 사용되는 활성화 함수 중 하나
>> 계산이 간단하고, 기울시 소실 문제를 해결하는데 효과적
비선형 함수로 출력값이 0보다 크면 그대로 출력하고, 0이하일 때는 0으로 출력
# 함수의 오른쪽 끝과 왼쪽 끝으로 갈수로 그래프가 누워있음(값의 변화가 거의 없다)
# == 시그모이드 함수의 단점 >>> 옳바른 출력을 만드는데 신속하게 대응하지 못함
# Relu함수로 개선 >> 0보다 크면 그대로 사용 0보다 작으면 0으로 만듬
model = keras.Sequential()
# Flatten() : 입력데이터를 받아 1차원 배열로 변환
model.add(keras.layers.Flatten(input_shape = (28, 28)))
model.add(keras.layers.Dense(100, activation = 'relu'))
model.add(keras.layers.Dense(10, activation = 'softmax'))
model.summary()

(train_iniput, train_target), (test_input, test_target) = \
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)

시그모이드 함수를 사용했을때 보다 조금 향상됨

옵티마이저
- 신경망 모델 훈련 시 손실 함수를 최소화하는 방법을 결정하는 알고리즘
모델의 가중치를 업데이트해서 예측 오류를 줄여가는 역할
- 가중치 업데이트 : 모델이 훈련 중 학습하는 가중치와 편향 조정
- 학습률 조정 : 각 파라미터의 업데이트 크기를 결정하는 학습률을 조절
- 최소화할 손실 함수 선택 : 옵티마이저는 손실 함수의 값을 최소화하는 방향으로 학습
# 케라스에서 기본적으로 미니 배치 경사하강법을 사용.(미니배치 개수 32)
# 케라스에서 다양한 종류의 경사하강법 알고리즘을 제공 >> 옵티마이저
# optimizer : compile() 함수의 속성
# 옵티마이저로 경사하강법 알고리즘을 사용하기 위해 sgd값으로 설정
model.compile(optimizer = 'sgd', loss = 'sparse_categorical_crossentropy',
metrics = ['accuracy'])
# 위의 코드와 동일한 코드
# SGD 옵티마이저 설정
sgd = tf.keras.optimizers.SGD()
# 모델 컴파일
model.compile(optimizer=sgd, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# SGD 클래스의 학습률의 기본값 = 0.01 >> learning_rate 속성과 지정 가능
sgd = keras.optimizers.SGD(learning_rate = 0.1)
- 기타 경사하강법 옵티마이저
# momentum은 0.9 이상 지정.
sgd = keras.optimizers.SGD(momentum=0.9, nesterov=True)
- 적응적 학습률 : Adagrad()
adagrad = keras.optimizers.Adagrad()
model.compile(optimizer=adagrad, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# Optimizer의 속성 : adam
# >> 모멘텀 최적화, 적응률 학습
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(train_scaled, train_target, epochs=5)

적응적 학습률을 적용해서 모델 학습
model = keras.Sequential()
model.add(keras.layers.Flatten(input_shape = (28, 28)))
model.add(keras.layers.Dense(100, activation = 'relu'))
model.add(keras.layers.Dense(10, activation = 'softmax'))
model.compile(optimizer = 'adam', loss = 'sparse_categorical_crossentropy',
metrics = ['accuracy'])
model.fit(train_scaled, train_target, epochs = 5)

