인공신경망(Artificial Neural Network, ANN)은 뇌의 뉴런을 본떠 만든 기계 학습 모델입니다. ANN은 여러 층(layer)으로 구성된 노드(node)를 통해 데이터의 패턴을 학습합니다. 여기서, 노드는 뇌의 뉴런과 비슷한 역할을 하고, 층은 데이터가 처리되는 단계라고 생각하면 됩니다. ANN은 이미지 인식, 음성 인식, 자연어 처리 등 다양한 분야에서 사용됩니다.
이번에는 TensorFlow를 이용해 ANN을 만들어보자. TensorFlow는 딥러닝을 쉽게 구현할 수 있게 도와주는 도구이다.
2.1 라이브러리 불러오기
import pandas as pd # 데이터 처리를 위한 라이브러리
import numpy as np # 수치 연산을 위한 라이브러리
import tensorflow as tf # 딥러닝을 위한 라이브러리
from sklearn.model_selection import train_test_split # 데이터셋을 나누기 위한 함수
from sklearn.preprocessing import MinMaxScaler # 데이터 스케일링을 위한 함수
from tensorflow.keras.utils import to_categorical # 원핫 인코딩을 위한 함수
tensorflow, pandas, numpy와 같은 라이브러리를 불러온다.
train_test_split은 데이터를 훈련용과 테스트용으로 나눌 때 사용한다.
MinMaxScaler는 데이터를 0과 1 사이의 값으로 변환해준다.
to_categorical은 종속 변수를 원-핫 인코딩해준다.
2.2 데이터 전처리
# 1) 데이터 읽기
df = pd.read_csv("creditset2.csv")
# 2) 변수 선택 (특징 X)
x = df[['income', 'age', 'loan']] # 'income', 'age', 'loan' 컬럼 선택
# 3) 타겟 변수 선택 (y) 및 원핫 인코딩
y = to_categorical(df[['default10yr']]) # 'default10yr' 컬럼을 원핫 인코딩
# 4) 데이터셋을 학습용(train)과 테스트용(test)으로 나누기 (8:2 비율)
train_x, test_x, train_y, test_y = train_test_split(x, y, test_size=0.2, random_state=42)
# 5) 학습용과 테스트용 데이터의 스케일링
scaler = MinMaxScaler() # MinMaxScaler 객체 생성
train_x = scaler.fit_transform(train_x) # 학습용 데이터를 스케일링
test_x = scaler.transform(test_x) # 테스트용 데이터를 스케일링
데이터를 불러와서 훈련용과 테스트용으로 나눈다.
income, age, loan 컬럼을 독립 변수로, default10yr 컬럼을 종속 변수로 사용한다.
데이터를 0과 1 사이의 값으로 변환한다.
2.3 모델링 및 학습
#DNN
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
#Hidden layer 구성하기
model = Sequential()
model.add(Dense(3, activation = 'relu', input_shape = (3, ))) #첫번째 은닉층, 3개입력->2개 은닉층 노드, Desnse: 일반적인 은닉층, Fully connected hidden layer
model.add(Dense(6, activation = 'relu')) #두번째 은닉층, 2개입력->6개 은닉층 노드, Desnse: 일반적인 은닉층, Fully connected hidden layer
model.add(Dense(2, activation = 'softmax')) #Desnse: 마지막 은닉층, Fully connected hidden layer, 분류의 경우 softmax
#모형 컴파일
model.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['acc']) #분류모형은 이대로 사용하기
model.summary()
#모형 학습 및 가중치 확인
model.fit(train_x,train_y,epochs = 20) #epoch수를 조정
Sequential 모델을 이용해 ANN을 만든다.
Dense 레이어를 이용해 은닉층과 출력층을 구성한다.
adam 옵티마이저와 categorical_crossentropy 손실 함수를 사용해 모델을 컴파일한다.
모델을 학습시킨다.
np.argmax 예제
np.argmax 함수는 배열에서 가장 큰 값의 인덱스를 반환합니다.
# np.argmax를 사용한 예제
print(np.argmax([1, 10, 100])) # 배열에서 가장 큰 값(100)의 인덱스(2)를 반환
# 2x3 행렬 생성 후 값 10 더하기
a = np.arange(6).reshape(2, 3) + 10
print(a)
# 출력:
# [[10 11 12]
# [13 14 15]]
# 각 열에서 가장 큰 값의 인덱스 반환
print(np.argmax(a, axis=0))
# 출력: [1 1 1] - 각 열에서 가장 큰 값이 있는 행의 인덱스
# 각 행에서 가장 큰 값의 인덱스 반환
print(np.argmax(a, axis=1))
# 출력: [2 2] - 각 행에서 가장 큰 값이 있는 열의 인덱스
np.argmax([1, 10, 100]): 주어진 배열에서 가장 큰 값(100)의 인덱스(2)를 반환합니다.
a = np.arange(6).reshape(2, 3) + 10: 2x3 행렬을 생성하고 각 값에 10을 더합니다.
np.argmax(a, axis=0): 각 열에서 가장 큰 값의 인덱스를 반환합니다.
np.argmax(a, axis=1): 각 행에서 가장 큰 값의 인덱스를 반환합니다.
2.4 결과 확인 및 평가
테스트 데이터를 이용해 모델의 예측값을 구한다.
예측값과 실제값을 비교해 정확도를 계산한다.
모델 예측 및 평가
이 부분은 학습된 모델을 사용해 테스트 데이터를 예측하고, 그 결과를 평가하는 과정입니다.
# 예측 수행
predicted = model.predict(test_x) # 테스트 데이터에 대한 예측 수행
predicted2 = np.argmax(predicted, axis=-1) # 예측 값 중 가장 큰 값을 갖는 인덱스 반환
actual = np.argmax(test_y, axis=-1) # 실제 값 중 가장 큰 값을 갖는 인덱스 반환
# 정확도 계산
print("Accuracy:", np.mean(predicted2 == actual))
# 예측 값(predicted2)과 실제 값(actual)이 일치하는 비율을 계산하여 정확도 출력
# 모델 요약 및 가중치 확인
model.summary() # 모델의 구조를 요약해서 보여줌
print(model.get_weights()) # 모델의 가중치(학습된 값) 출력
model.predict(test_x): 테스트 데이터를 사용하여 모델이 예측한 결과를 반환합니다.
np.argmax(predicted, axis=-1): 예측 결과에서 가장 큰 값의 인덱스를 반환하여 예측된 클래스(label)를 얻습니다.
np.argmax(test_y, axis=-1): 실제 결과에서 가장 큰 값의 인덱스를 반환하여 실제 클래스(label)를 얻습니다.
np.mean(predicted2 == actual): 예측된 클래스와 실제 클래스가 일치하는 비율을 계산하여 정확도를 출력합니다.
model.summary(): 모델의 구조(레이어 구성, 파라미터 수 등)를 요약하여 출력합니다.
model.get_weights(): 학습된 가중치 값을 출력합니다.
분류 보고서 출력
모델의 예측 성능을 자세히 평가하기 위해 분류 보고서를 생성합니다.
from sklearn.metrics import classification_report, confusion_matrix
# 분류 보고서 출력
print('\n', classification_report(actual, predicted2))
# classification_report 함수는 precision, recall, f1-score, support를 포함한 자세한 성능 지표를 출력
classification_report(actual, predicted2): 실제 값과 예측 값을 비교하여 precision, recall, f1-score, support 등을 포함한 성능 지표를 출력합니다.
precision: 모델이 True라고 예측한 것 중 실제로 True인 비율.
recall: 실제 True인 것 중 모델이 True라고 예측한 비율.
f1-score: precision과 recall의 조화 평균.
support: 각 클래스의 실제 샘플 수.
3. MNIST 데이터셋에 대한 DNN
이번에는 MNIST 데이터셋을 이용해 딥러닝 모델을 만들어보자. MNIST 데이터셋은 손글씨 숫자 이미지 데이터이다.
손글씨 숫자 데이터셋을 불러옵니다. x_train과 y_train은 훈련 데이터와 레이블, x_test와 y_test는 테스트 데이터와 레이블입니다.
데이터 시각화
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (5, 5)
plt.imshow(x_train[0])
plt.show()
첫 번째 훈련 이미지를 화면에 표시합니다.
손글씨 숫자 이미지가 어떻게 생겼는지 볼 수 있습니다.
데이터 전처리
# 데이터 형태 변환 및 정규화
x_train = x_train.reshape((60000, 28 * 28)) / 255.0
x_test = x_test.reshape((10000, 28 * 28)) / 255.0
y_train = tf.keras.utils.to_categorical(y_train, 10)
y_test = tf.keras.utils.to_categorical(y_test, 10)
데이터를 2차원 배열로 변환하고, 0과 1 사이의 값으로 스케일링한다.( 이미지를 2차원 배열에서 1차원 배열로 바꾸고, 픽셀 값을 0에서 1 사이로 정규화합니다.)
종속 변수를 원-핫 인코딩한다. 예를 들어, 숫자 3은 [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]로 변환됩니다.
3.3 모델링 및 학습
신경망 모델 구성
# Sequential 모델 생성
model = tf.keras.models.Sequential()
# 은닉층 추가
model.add(tf.keras.layers.Dense(units=128, activation='relu', input_shape=(28*28,)))
model.add(tf.keras.layers.Dense(units=64, activation='relu'))
model.add(tf.keras.layers.Dense(units=32, activation='relu'))
model.add(tf.keras.layers.Dense(units=16, activation='relu'))
model.add(tf.keras.layers.Dense(units=10, activation='softmax'))
Sequential 모델을 이용해 DNN을 만든다.
여러 개의 Dense 레이어를 추가해 은닉층을 구성한다.
신경망 모델을 구성합니다. Dense 레이어는 완전히 연결된 레이어를 의미하며, activation='relu'는 활성화 함수로 렐루 함수를 사용합니다. 마지막 레이어는 클래스 확률을 나타내기 위해 softmax를 사용합니다.
모델 요약, 컴파일, 학습, 저장
# 모델 요약
model.summary()
# 모델 컴파일
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.01), loss=keras.losses.categorical_crossentropy)
# 모델 학습
model.fit(x_train, y_train, epochs=5, verbose=1, validation_split=0.2)
# 모델 평가
model.evaluate(x_test, y_test)
# 모델 저장 및 불러오기
model.save('mnist_dnn_model.h5')
new_model = tf.keras.models.load_model('mnist_dnn_model.h5')
new_model.summary()
모델을 컴파일합니다. 옵티마이저는 adam을 사용하고, 손실 함수는 categorical_crossentropy, 평가 지표는 accuracy를 사용합니다.
모델을 훈련 데이터로 학습시킵니다. epochs=5는 데이터를 5번 반복해서 학습한다는 의미이고, validation_split=0.2는 훈련 데이터의 20%를 검증 데이터로 사용합니다.
타겟 변수인 Pass.Fail을 원-핫 인코딩합니다. 원-핫 인코딩은 타겟 값을 0과 1로 변환하는 것을 의미합니다.
3. 모델 정의하기
from keras.models import Sequential
from keras.layers import Dense, Dropout
model = Sequential()
model.add(Dense(32, activation='relu', input_shape=(48,)))
model.add(Dense(16, activation='relu'))
model.add(Dense(8, activation='relu'))
model.add(Dense(2, activation='softmax'))
딥러닝 모델을 정의합니다. 여기서는 4개의 Dense(밀집) 레이어를 사용했습니다. 첫 번째 레이어는 입력 데이터가 48개의 피처를 가지고, 32개의 노드로 구성되어 있습니다. 각 레이어는 ReLU 활성화 함수를 사용합니다. 마지막 레이어는 분류 문제를 해결하기 위해 Softmax 활성화 함수를 사용합니다.
학습 과정에서의 정확도와 손실 값을 시각화합니다. 이를 통해 학습 과정에서 모델의 성능이 어떻게 변했는지 확인할 수 있습니다.
이와 같이, 데이터 전처리부터 딥러닝 모델 학습, 평가, 시각화까지의 전체 과정을 초등학생도 이해할 수 있도록 설명했습니다. 각 단계의 코드를 실행하면서 모델의 성능을 확인하고, 시각화를 통해 결과를 쉽게 이해할 수 있습니다.
정확도(Accuracy) 그래프
이 그래프는 학습 과정에서의 정확도(Accuracy)의 변화를 보여줍니다.
파란색 선은 훈련 데이터(train)의 정확도를, 주황색 선은 검증 데이터(val)의 정확도를 나타냅니다.
그래프를 통해 훈련이 진행됨에 따라 모델의 정확도가 어떻게 변하는지를 알 수 있습니다.
정확도가 증가한다면 모델이 점점 더 잘 예측하고 있다는 것을 의미합니다.
손실 함수 그래프
이 그래프는 학습 과정에서의 손실(Loss) 값의 변화를 보여줍니다.
파란색 선은 훈련 데이터(train)의 손실 값을, 주황색 선은 검증 데이터(val)의 손실 값을 나타냅니다.
그래프를 통해 훈련이 진행됨에 따라 손실 값이 어떻게 변하는지를 알 수 있습니다.
손실 값이 감소한다면 모델이 점점 더 잘 학습하고 있다는 것을 의미합니다.
데이터의 불균형 해결하기: 오버샘플링과 다운샘플링
데이터가 불균형할 때, 즉 어떤 클래스가 다른 클래스보다 훨씬 더 많은 경우 모델 학습에 문제가 발생할 수 있습니다. 이를 해결하기 위해 오버샘플링과 다운샘플링을 사용합니다.
다운샘플링: 데이터 수가 많은 클래스를 줄이는 것
오버샘플링: 데이터 수가 적은 클래스를 늘리는 것
여기서는 오버샘플링을 통해 적은 클래스의 데이터를 늘리는 방법을 설명합니다.
1. 필요한 라이브러리 불러오기
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn import metrics
from sklearn.metrics import recall_score
from imblearn.over_sampling import SMOTE
필요한 라이브러리를 불러옵니다. numpy와 pandas는 데이터 처리, matplotlib와 seaborn은 시각화, scikit-learn은 머신러닝 모델링, imblearn은 오버샘플링에 사용됩니다.
2. 데이터 불러오기 및 확인하기
data = pd.read_csv("data.csv")
data.info()
data['Pass.Fail'].value_counts()
데이터를 읽어와서 정보와 각 클래스의 개수를 확인합니다.
여기서 0 클래스가 1 클래스보다 훨씬 많음을 알 수 있습니다.
3. 데이터 전처리와 업샘플링 (Data Preprocessing and Upsampling)
data[~data.applymap(np.isreal).all(1)]ㅌ
데이터 확인하고 결측값 채우기
목적: 숫자가 아닌 값이 있는 행을 찾기.
방법: 모든 값을 확인해서 숫자가 아닌 값이 있는 행을 보여줌.
applymap(np.isreal): 데이터의 모든 값을 숫자인지 확인.
~: 부정 연산자로, 숫자가 아닌 값을 찾음.
data = data.fillna(data.median())
목적: 비어 있는 값을 채우기.
방법: 각 열의 중앙값으로 비어 있는 값을 채움.
fillna: 비어 있는 값을 채움.
data.median(): 각 열의 중앙값을 계산.
data.describe().transpose()
목적: 데이터의 기본 통계를 확인.
방법: 데이터의 평균, 표준편차, 최소값, 최대값 등을 계산하고 보여줌.
describe(): 데이터의 요약 통계를 계산.
transpose(): 행과 열을 바꿔서 통계를 더 쉽게 보기 좋게 만듦.
data.groupby(["Pass.Fail"]).count()
목적: 각 그룹의 데이터 개수를 세기.
방법: Pass.Fail 값에 따라 데이터를 그룹화하고 각 그룹의 개수를 셈.
groupby(["Pass.Fail"]): Pass.Fail 값에 따라 데이터를 그룹화.
count(): 각 그룹의 데이터 개수를 셈.
오버샘플링은 주로 데이터 불균형 문제를 해결하기 위해 소수 클래스 데이터를 늘리는 데 사용되며, 새로운 합성 데이터를 생성하는 방법이 포함됩니다.
업샘플링은 주로 시간 시계열 데이터의 해상도를 높이기 위해 기존 데이터 포인트 사이에 새로운 데이터를 추가하는 방법입니다.
2. 업샘플링 (Up sampling)
목적: 데이터가 적은 그룹(소수 클래스)을 늘려서 데이터를 더 균형 있게 만듦.
방법: 주로 데이터 불균형 문제를 해결하기 위해 사용하며, 새로운 합성 데이터를 생성하는 방법이 포함됩니다.
array = data.values
X = array[:,0:48] # 입력 데이터 (특징들)
Y = array[:,48] # 목표 데이터 (결과 값)
오버샘플링 (Oversampling)
목적: 주로 데이터 불균형 문제를 해결하기 위해 소수 클래스 데이터를 늘리는 데 사용됩니다.
방법: 소수 클래스 데이터를 복제하거나 새로운 합성 데이터를 생성하여 늘립니다. 대표적인 방법으로 SMOTE가 있습니다.
비교:
업샘플링은 보통 시간 시계열 데이터에서 해상도를 높이는 방법을 의미하지만, 여기서는 오버샘플링의 의미로 사용되었습니다.
오버샘플링은 주로 데이터 불균형 문제를 해결하기 위해 사용됩니다.
4. 데이터 나누기 및 SMOTE를 이용한 오버샘플링
데이터 나누기:
array = data.values
X = array[:, 0:48]
Y = array[:, 48]
방법: 입력 데이터와 목표 데이터를 나눔.
data.values: 데이터프레임을 배열로 변환.
X: 첫 48개의 열을 선택 (특징들).
Y: 49번째 열을 선택 (결과 값).
test_size = 0.30 # 70:30 비율로 학습과 테스트 데이터 나눔
seed = 7 # 랜덤 시드 값
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=test_size, random_state=seed)
목적: 데이터를 학습용과 테스트용으로 나누기.
방법: 70%는 학습용, 30%는 테스트용으로 나눔.
train_test_split: 데이터를 학습용과 테스트용으로 나눔.
test_size=0.30: 데이터의 30%는 테스트용으로 사용.
random_state=seed: 재현 가능성을 위해 랜덤 시드를 설정.
SMOTE를 사용한 업샘플링
SMOTE (Synthetic Minority Over-sampling Technique) 기법을 사용해서 적은 데이터를 늘림.
sm = SMOTE(sampling_strategy=0.5, k_neighbors=3, random_state=1)
X_train_res, y_train_res = sm.fit_resample(X_train, y_train)
목적: 적은 데이터를 늘리기.
방법:
SMOTE: 소수 클래스의 데이터를 합성하여 데이터를 늘림.
fit_resample: 데이터를 오버샘플링하여 학습용 데이터를 증가시킴.
print("Before UpSampling, counts of label '1': {}".format(sum(y_train==1)))
print("Before UpSampling, counts of label '0': {} \n".format(sum(y_train==0)))
목적: 업샘플링 전 데이터 개수 확인.
방법: Pass.Fail 값이 1인 데이터와 0인 데이터의 개수를 셈.
print("After UpSampling, counts of label '1': {}".format(sum(y_train_res==1)))
print("After UpSampling, counts of label '0': {} \n".format(sum(y_train_res==0)))
print('After UpSampling, the shape of train_X: {}'.format(X_train_res.shape))
print('After UpSampling, the shape of train_y: {} \n'.format(y_train_res.shape))
SMOTE를 사용하여 오버샘플링을 수행합니다.
오버샘플링 후 클래스의 개수와 데이터 모양을 출력합니다.
종합 설명
업샘플링과 오버샘플링: 업샘플링은 데이터 포인트의 수를 늘려서 해상도를 높이는 반면, 오버샘플링은 소수 클래스의 데이터를 늘려 데이터 불균형 문제를 해결합니다. 여기서 설명된 업샘플링은 실제로는 오버샘플링의 방법 중 하나로, SMOTE 기법을 사용하여 소수 클래스를 늘렸습니다.