일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- SQL
- Flex Box 기본
- java spring
- 자바스프링
- 오산대맛집
- Eclipse
- Flexbox Froggy
- HTML5
- numpy
- node.js
- 스프링
- spring
- 자바 스프링
- Hooks
- 이클립스
- 타입
- 환경설정
- SQL 명령어
- REACT
- ubuntu
- 관계형데이터베이스
- 리액트
- 플랙스박스기본
- java설치
- SQL 연산자
- spring 환경설정
- 객체지향프로그래밍
- 노마드코더
- 람다식
- SQL 문제
- Today
- Total
이것저것
딥러닝 - 이미지 데이터 전처리 및 학습(2) 본문
[기초기초기초!!/Python] - 딥러닝 - 이미지 데이터 전처리 및 학습(1)
위의 글에 이어서 작성하겠다
쓰고있는 노트북의 GPU가 낮아 colab의 Tesla T4를 사용해서 작업하도록하겠다.
google drive에서 colab을 실행
colab 사용법은 여기서 확인하면된다
우선 런타임 유형을 T4 GPU로 변경해주자 안그러면 하루종일 걸린다...
드라이브도 마운트 한뒤 위에서 생성한 train.csv 파일을 구글 드라이브에 넣어주자 (이것도 상당히 오래걸린다..)
위처럼 개와 고양이에 train.csv 파일을 넣어줬다.
필요한 모듈들을 import해준다.
# CSV파일을 이용한 Kaggle의 Cat & Dog 전체 이미지 학습과 평가
# CNN으로 구현할것이다.
# 필요한 module import
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dropout # 필수로 필요한 것들
from tensorflow.keras.layers import Flatten, Dense, BatchNormalization # 있으면 좋은 것들 써주는게 좋다
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
학습 진행
# Raw Data Loading
df = pd.read_csv('/content/drive/MyDrive/빅데이터 과정/data/개와고양이/train.csv')
display(df.head(), df.shape) # (25000, 6401)
# CSV 파일 불러오기
pd.read_csv()는 pandas 라이브러리에서 제공하는 함수로 CSV 파일의 내용을 Pandas의 DataFrame형태로 읽어오는데 사용한다. 자주 사용하니 외워두도록한다.
제대로 불러와지는지 df.head를 이용해서 알아보았다.
# label(target) data와 pixel data를 분리해보자
# 데이터 확인하기 위해서
label_data = df['label'].values # 1차원 ndarray
pixel_data = df.drop('label', axis=1, inplace=False).values # 2차원 ndarray
# label(target) data와 pixel data 분리하기
# label_data
df['label']은 DataFrame에서 label이라는 이름의 열을 선택한다. 이 label 열은 이미지 데이터의 레이블(고양이 or 개)를 나타낸다.
.value는 해당 열의 데이터를 numpy의 ndarray 형식으로 반환한다. 여기서 1차원 배열로 반환된다.
# pixel_data
df.drop은 DataFrame에서 label열을 삭제한 새로운 DataFrame을 반환한다.
axis = 1은 열(column)을 기준으로 동작한다는 것을 나타내고, inplace=Flase는 원래의 DataFrame(df)는 변경하지 않고 새로운 DataFrame을 반환한다는 것을 의미한다.
.values는 해당 위와같이 DataFrame의 데이터를 numpy의 ndarray 형식으로 반환하지만 여기서는 2차원 배열로 반환한다.
# 샘플 이미지 확인
# print(pixel_data[150])
plt.imshow(pixel_data[150].reshape(80, 80), cmap='gray')
print(label_data[151]) # =>1 또는 0으로 강아지인지 고양이인지 확인
plt.show()
# 샘플 이미지 확인
주석처리된 print는 6400이 나온다. (80,80)의 크기이므로 6400이 나온다.
# plt.imshow
pixel_data[150]은 pixel_data(ndarray)에서 150번재 샘플(이미지)의 픽셀 데이터를 선택한다는 뜻이다.
print했을때 6400으로 나오는 1차원 배열을 reshape(80, 80)을 통해 2차원 배열로 변형한다.
plt.imshow는 주어진 2차원 배열 데이터를 그레이스케일 이미지로 시각화한다.
# print 부분
label_data[151]은 151번째 샘플의 레이블 값을 선택하여 출력한다는 뜻이다. 즉 0(고양이)인지 1(강아지)인지 확인하려고 작성한 코드이다.
# plt.show()
이미지를 화면에 표시하는 함수이다.
# 데이터 전처리
# 1. 결측치 - 없다
# 2. 이상치 - 없다
# 이미지로부터 직접 프로그램 짜서 가져온것이기 때문에 없다.(코드를 잘못 짜지 않은 이상)
scaler = MinMaxScaler()
scaler.fit(pixel_data)
x_data_norm = scaler.transform(pixel_data)
# 4. train, test 분리
x_data_train_norm, x_data_test_norm, t_data_train, t_data_test = \
train_test_split(x_data_norm,
label_data.reshape(-1, 1),
test_size=0.3)
# 데이터 전처리
데이터의 결측치나 이상치가 없어야지 데이터에 이상이 없으므로 항상 확인해야한다.
이미지로 부터 직접 데이터를 추출했기때문에 이상치와 결측치가 없다고 작성한것이다.
# 정규화
scale = MinMaxScaler()의 MinMaxScaler는 데이터의 범위를 [0,1] 사이로 조정한다. 보통 신경망쪽이나 다른 머신 러닝 알고리즘에서 일반적으로 좋은 성능을 내기 위해 사용한다.
scaler.fit(pixel_data) 데이터의 최대 및 최소 값에 맞게 스케일러를 조정(학습)한다.
x_dat_norm = ~~ 앞서 학습된 스케일러를 사용해서 데이터를 [0,1] 범위로 변환한다.
# 학습 데이터와 테스트 데이터 분리
x_data_train_norm, x_data_test_norm은 정규화된 학습 이미지 데이터와 테스트 이미지 데이터이다.
t_data_train, t_data_test는 학습용 레이블 데이터와 테스트용 레이블 데이터이다.
train_test_split은 함수를 사용하여 전체 데이터를 학습 데이터와 테스트 데이터로 분리한다.
test_size에 0.3을 입력했으니 70%는 학습용으로 30%는 테스트용으로 쓴다는 뜻이다.
이러한 전처리를 통해 데이터는 학습과 테스트를 위해 준비된 상태가 된다.
# Model 구현
model = Sequential()
model.add(Conv2D(filters=32,
kernel_size=(3,3), # 일반적으로 3,3을 많이쓴다
strides=(1,1),
activation='relu',
input_shape=(80,80,1)))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=64,
kernel_size=(3,3),
strides=(1,1),
padding='same',
activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=128,
kernel_size=(3,3),
strides=(1,1),
padding='same',
activation='relu'))
model.add(Conv2D(filters=256,
kernel_size=(3,3),
strides=(1,1),
padding='same',
activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=256,
kernel_size=(3,3),
strides=(1,1),
padding='same',
activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
# FC Layer(Classifier - 분류기)
model.add(Flatten())
model.add(Dense(units=256,
activation='relu'))
model.add(Dropout(rate=0.4))
model.add(Dense(units=1,
activation='sigmoid'))
model.summary()
# CNN 모델 구축
# 모델 초기화
model = Sequential() - Sequential API를 사용해서 모델을 초기화한다.
Sequential API는 레이어를 순차적으로 쌓아가는 방식으로 모델을 만든다.
# 합성곱 레이어 (Convolutional Layers)
Conv2D - 2D 합성곱 레이어이다. 이미지 데이터를 처리하는데 주로 사용한다.
filters - 필터(커널)의 수 이다. 이 필터들이 이미지에서 패턴을 학습한다.
kernel_size - 필터의 크기. (3,3)은 3X3 크기의 필터를 의미한다.
strides - 필터가 이미지 위를 이동하는 스텝의 크기. (1,1)은 한칸씩 이동한다는 뜻이다.
padding - same은 패딩을 추가하여 출력 이미지 사이즈가 입력 이미지 사이즈와 동일하게 유지되도록 한다. 지정하지 않으면 값은 없다.(defalut 값이 없음)
activation - 활성화 함수이다. relu은 자주 사용되는 활성화 함수중 하나이다.
relu가 뭔가 발음도 렐루?? 이상해서 한번 찾아봤는데 음... 어렵다..
Rectified Linear Unit 의 약자이고 비선형 함수로 딥러닝 모델에서 복잡한 패턴과 관계를 학습할 수 있게 해준다.
그리고 매우 간단한 연산으로 구성되어있어 계산이 빠르고 효율적이다.
또 몇가지 더 있지만 이러한 장점들로 대부분 activation = 'relu'.를 사용한다고한다...
# 풀링 레이어 (Pooling Layers)
MaxPooling2D - 이미지의 크기를 줄이는 동시에 중요한 특징을 유지하기위해 사용한다.
pool_size - 풀링 영역의 크기. (2,2)는 2X2 크기의 영역에서 최대값을 선택한다는 뜻이다.
# 완전 연결 레이어 (Fully Connection Layers)
Flatten() - 2D 데이터를 1D 데이터로 평탄화한다. 평탄화 하는 이유는 이렇게 해야지 완전 연결 레이어(Dense)에 데이터를 전달 할 수 있다고한다.
합성곱 레이어와 풀링 레이어를 거친 후의 다차원 특성 맵을 완전 연결 레이어에 입력하기 위해 1차원 형태로 변환하는 것이다.
Dense - 완전 연결 레이어
units - 뉴런(노드)의 수
activation - 여기서는 relu와 sigmoid가 사용되었는데 sigmoid는 이진 분류 문제에서 결과를 0과 1사이의 값을 출력하기위해 사용된다.
# 드롭아웃(Dropout)
Dropout - 과적합을 방지하기 위해 일부 뉴런을 무작위로 비활성화하는 기술.
rate - 비활성화 뉴런의 비율. 0.4로 작성했으므로 40%가 무작위로 비활성화 시킨다는 뜻이다.
# 모델 출력
model.summary() - 모델의 구조를 출력해준다.
# 순서 해석
1. 모델을 초기화 한다.
2. 첫번째 합성곱 레이어로 32개의 필터를 사용한다. 필터의 크기는 3X3이고 입력 이미지의 형태는 80X80 픽셀이며 흑백이므로 1이다.
3. 첫번째 풀링 레이어로 최대 풀링레이어를 추가한다. 크기는 2X2로 특성맵의 크기를 절반으로 줄인다.
4. 두번째 합석곱은 64개의 필터를 사용하고 입력 데이터의 경계를 유지하기 위해 padding을 same으로 설정한다.
5. 두번째 풀링레이어를 추가
6. 세번째, 네번째 합성곱 레이어를 추가한다.
7. 세번째 풀링레이어를 추가한다.
8. 다서번째 합성곱 레이어와 네번째(마지막) 풀링레이어를 추가한다.
9. 합성곱 레이어와 풀링 레이어에서 생성된 특성 맵은 다차원이므로, 이것을 완전 연결층에 연결하기전에 1차원으로 평탄화를 해야한다. 그래서 Flatten을 사용해 평탄화 작업을 한다.
10. Dense를 사용해서 평탄화된 데이터에서 패턴을 학습한다.
11. Dropout이 중간에 위치한것은 과적합을 방지하기 위해 일반적으로 큰 Dense 다음에 위치한다.
12. 마지막 Dense는 최종 분류 결정을 생성하기 위해서 사용된다.
13. summary로 모델의 구조와 레이어의 출력 형태, 파라미터 수를 출력한다.
**합성곱 레이어와 풀링레이어를 반복하는 이유는 특징 추출, 차원 축소, 문맥 인식의 이유가 있다.
여러개의 합성곱 레이어와 풀링 레어어를 통해 점점 더 복잡한 특징을 추출할 수 있다. 첫번째 합성곱으로 일반적으로 간단한 모양과 가장자리 같은 기본적인 특징을 검출하고, 깊은 레이어로 들어갈 수 록 복잡한 패턴과 개체의 부분을 학습할 수 있다. (특징 추출)
풀링 레이어는 특성 맵의 차원을 축소하여 계산 효율성을 높이고 과적합의 위험을 줄여준다. (차원 축소)
깊은 네트워크 구조를 통해, 이미지의 넓은 범위의 문맥을 포착할 수 있다. (문맥 인식)
** 아래쪽에 합성곱을 256개의 필터를 2번이나 쓰는 이유는 동일한 크기의 필터를 여러번 연속으로 사용하면 해당 레이어의 표현 능력이 더 높아진다.(표현 능력 증가) 또한 복잡한 패턴을 학습하는데 도움이 된다.(비선형성 증가)
작은 필터를 사용하는 연속적인 합성곱 레이어는 큰 필터를 사용하는 단일 합성곱 레이어보다 계산적으로 효율적이다. (계산 효율성)
# 학습 설정하고 학습 진행!
model.compile(optimizer=Adam(learning_rate=1e-4),
loss='binary_crossentropy',
metrics=['accuracy'])
# 일반적으로 callback을 설정한다.
# 우리는 callback을 설정하지 않고 학습을 진행
history = model.fit(x_data_train_norm.reshape(-1,80,80,1),
t_data_train,
epochs=100,
verbose=1,
batch_size=100,
validation_split=0.3)
# 모델 학습 시키기
# model.compile() 부분
모델을 학습하기 전에 학습에 필요한 설정들을 지정하는 단계이다.
optimizer=Adam(learing_rate=1e-4) - 최적화 알고리즘으로 Adam을 사용, Adam은 모멘텀과 RMSProp의 개념을 결합한 알고리즘이다. 신경망 학습에서 널리 사용된다.
learning_rate=1e-4 - 학습률을 0.0001로 설정한다는 뜻이다. 학습률은 각 반복에서 모델의 가중치를 얼마나 업데이트할지 결정하는 파라미터이다.
loss='binary_crossentropy' - 이진 분류 문제에서 사용하는 손실 함수이다. 이 손실 함수는 모델의 예측과 실제 레이블 간의 차이를 측정한다.
metrics=['accuracy'] - 학습 중에 모델의 성능을 평가하기 위한 지표로 정확도(accuracy)를 사용한다.
# history 부분
model.fit() - 모델을 학습시키는 함수이다. 입력 데이터와 레이블을 기반으로 학습을 진행한다.
x_dat_train_nor.reshape(-1,80,80,1) - 학습 데이터를 모델의 입력 형태에 맞게 변형한다. 이밎 데이터는 (이미지수, 높이, 너비, 채널 수)의 형태를 가져야한다.(여기서는 흑백이미지이기 때문에 채널수는 1을 쓴다.)
t_data_train - 학습 데이터의 레이블이다.
epochs=100 - 전체 학습 데이터를 100번 반복하여 학습시킨다.
verbose=1 - 학습 과정을 화면에 출력한다. 1은 매 에폭마다의 진행 상황을 표시하고, 0은 아무것도 출력하지 않는다.
batch_size=100 - 한 번의 배치마다 100개의 데이터를 사용하여 모델을 업데이트한다. 이는 학습의 속도와 안정성을 조절하는데 도움이된다.
validation_split=0.3 - 전체 학습 데이터 중 30%를 검증 데이터로 사용한다는 뜻이다. 이는 학습 중에 모델의 성능을 평가하는데 사용되며, 과적합을 감지하는데 도움된다.
# 학습이 잘 됬으면 이제 모델 평가를 진행해야 해요!
print(model.evaluate(x_data_test_norm.reshape(-1,80,80,1,),
t_data_test))
# [0.8023147583007812, 0.8352000117301941]
# 학습된 모델의 성능을 평가하기
model.evaluate() - 주어진 테스트 데이터를 사용하여 학습된 모델의 성능을 평가한다.
x_data_test_norm_reshape(-1,80,80,1) - 테스트 데이터셋을 모델이 요구하는 입력 형태로 변형한다.
t_data_test - 테스트 데이터셋의 실제 레이블이다.
결과 출력값 해설
앞부분 - 테스트 데이터에 대한 손실값. 모델의 예측이 얼마나 실제 레이블과 일치하는지 나타내는 지표이다. 이 값이 작을 수록 모델의 성능이 좋다고 판단할 수 있다.
뒷부분 - 테스트 데이터에 대한 정확도이다. 모델이 올바르게 예측한 데이터의 비율을 나타낸다. 약 83.52%의 테스트 이미지를 올바르게 분류했음을 의미한다.
# 마지막으로 그래프 그려보아요!
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)
ax1.plot(history.history['loss'], color='r')
ax1.plot(history.history['val_loss'], color='b')
ax2.plot(history.history['accuracy'], color='r')
ax2.plot(history.history['val_accuracy'], color='b')
plt.tight_layout()
plt.show()
# 그래프 출력해보기
fig = plt.figure() - 새로운 그림(figure) 객체를 생성한다. 도화지를 준비
ax1 = fig.add_subplot(1,2,1), ax2 = fig.add_subplot(1,2,2) - 두개의 서브 플롯 생성 1,2,1은 1X2의 첫번째 위치 1,2,2는 1X2의 두번째 위치이다. (가로로 나란히 배치)
ax1.plot(history.history['loss'], color='r') - ax1 서브플롯에 훈련 손실값을 빨간색으로 그린다.
ax1.plot(history.history['val_loss'], color='b') - ax1 서브플롯에 검증 손실값을 파란색으로 그린다.
ax2.plot(history.history['accuracy'], color='r') - ax2 서브플롯에 훈련 정확도를 빨간색으로 그린다.
ax2.plot(history.history['val_accuracy'], color='b') - ax2 서브플롯에 검증 정확도를 파란색으로 그린다.
plt.tight_layout() - 그래프들이 서로 겹치지않게 자동으로 간격을 조정한다.
plt.show() - 준비된 그림을 화면에 출력.
왼쪽 서브플롯 - 에폭(epoch)별 훈련 손실과 검증 손실의 변화를 보여준다. 이 그래프를 통해 모델의 오버피팅, 언더피팅 여부 등을 확인 할 수 있다.
오른쪽 서브플롯 - 에폭별 훈련 정확도와 검증정확도의 변화를 보여준다. 그래프를 통해 모델의 성능을 직관적으로 확인 할 수 있다.
3차원 데이터를 CSV로 만들어서 학습하는 것과 gray 처리를 해서 작업한것 모두 학습에 부적합하다.
그래서 CSV 파일을 만드는것이 아니라 ImageDataGenerateor를 이용(keras가 제공(utility)) 하려고한다.
가진 image가 적을때는 어떻게 해야하나??
-> 결과가 좋지는 않을 것이다.
ImageDataGenerator를 사용하려면 적절한 Data구조(폴더 구조)가 필요하다
다음 글에는 ImageDataGenerator를 사용해보도록 하자.
'Python' 카테고리의 다른 글
(2) pycharm에 mysql 불러오기 (2) | 2023.11.22 |
---|---|
(1) Pycharm에서 Flask 사용하기 (2) | 2023.11.22 |
딥러닝 - 이미지 데이터 전처리 및 학습(1) (0) | 2023.11.02 |
Anaconda 사용해서 python 사용하기 (2) | 2023.11.01 |
Numpy 기본 설명 2(복습용으로 적는 설명) (2) | 2023.10.31 |