[Tensorflow] CNN_개 고양이 구분 AI 만들기

Sireal·2021년 10월 4일
4

AI

목록 보기
5/12
post-thumbnail
post-custom-banner
  • 완전 쌩 이미지를 이용하여 CNN 모델을 만들어보자
  • 현재 노트북 환경(NoneGPU)이기 때문에 Colab을 사용할 것임

이미지 준비

  • kaggle에서 이미지를 가져온다.
  • kaggle 을 사용하려면 토큰이 필요함
    • Account>API에서 CreateNewToken으로 .json 다운
    • colab에 업로드
# 케글 데이터 다운받기
import os
os.environ['KAGGLE_CONFIG_DIR'] = '/content/'

!kaggle competitions download -c dogs-vs-cats-redux-kernels-edition

압축해제

  • 예시
# train.zip 압축해제
!unzip -q train.zip -d .

데이터셋 만들기

  • 데이터셋 폴더 만들기
import os
import tensorflow as tf
import shutil
# 파일 갯수 새보기
print(len(os.listdir('/content/train/')))

# 이미지를 숫자로 바꿔주기 (openCV 해도되고, keras 써도되고)
## cat, dog 폴더 만들고 데이터 옮겨담기
for i in os.listdir('/content/train'):
  if 'cat' in i:
    shutil.copyfile('/content/train/'+i, '/content/dataset/cat/'+i)
  if 'dog' in i:
    shutil.copyfile('/content/train/'+i, '/content/dataset/dog/'+i)

## 케라스로 이미지를 데이터셋(숫자)로 바꾸기
#tf.keras.preprocessing.image_dataset_from_directory()
## 케라스로 이미지를 데이터셋(숫자)로 바꾸기
### validation_split -> 데이터 갯수 쪼개기
### seed -> 랜덤으로 뽑을 때 필요한 그런 값
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    '/content/dataset',
    image_size=(64,64),
    batch_size=64,
    subset='training',
    validation_split=0.2,
    seed=1234
)
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    '/content/dataset',
    image_size=(64,64),
    batch_size=64,
    subset='validation',
    validation_split=0.2,
    seed=1234
)
###  train_ds 는 이렇게 된다. ((xxxxxx..), (yyyyyy...))

print(train_ds)
  • 클래스가 2개가 아닌 3개가 나온다.
  • 전처리로 처리해보자

전처리 및 모델만들기

  • 폴더 일단 비우기
  • 리눅스 명령어로 다시 만들기
os.mkdir('/content/dataset')
os.mkdir('/content/dataset/cat')
os.mkdir('/content/dataset/dog')
  • 다시 처리하고 결과
    • 2개 클래스 나온것을 확인
  • Dropout(0.n) : 오버피팅방지를 위해 레이어 하나 추가해봄.
    • 노드를 일부 삭제해줌
# 모델 만들기
model = tf.keras.Sequential([
    ## 컬러사진이기때문에 마지막 차원수 3.
    tf.keras.layers.Conv2D(32, (3,3), padding="same",activation='relu', input_shape=(64,64,3)),
    tf.keras.layers.MaxPooling2D( (2,2) ),
    ## 학습효과를 더좋게하기위해 중간분석 더 많이 해보자
    tf.keras.layers.Conv2D(64, (3,3), padding="same",activation='relu'),
    tf.keras.layers.MaxPooling2D( (2,2) ),
    ## 더더더 ~
    ### 오버피팅 완화를 위해 Dropout 으로 (아래는 20% 삭제) 노드 일부 제거
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Conv2D(128, (3,3), padding="same",activation='relu'),
    tf.keras.layers.MaxPooling2D( (2,2) ),
    tf.keras.layers.Dense(128, activation="relu"),
    tf.keras.layers.Flatten(),
    ## 개인지 고양이인지 확인하는것이기때문에 답은 1개(0~1)
    tf.keras.layers.Dense(1, activation="softmax") # sofmax :0~1 로 압축시켜줌_카테고리예측용_총합1 // sigmoid 는 정답,오답 두개분류일때 사용)
])

# 모델 아웃라인 출력하기
model.summary()

## loss 함수는 binary_crossentropy
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=['accuracy'])
## train과 정답이 train_ds에 다있어서, trainX,trainY 를 대체 
## val_ds 또한 그럼
model.fit(train_ds, validation_data=val_ds, epochs=5)
  • 너무 느리다..
  • 데이터 전처리를 안해서 느린것임

전처리

  • 0~255를 0~1로 압축
## 케라스로 이미지를 데이터셋(숫자)로 바꾸기
### validation_split -> 데이터 갯수 쪼개기
### seed -> 랜덤으로 뽑을 때 필요한 그런 값
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    '/content/dataset',
    image_size=(64,64),
    batch_size=64,
    subset='training',
    validation_split=0.2,
    seed=1234
)
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    '/content/dataset',
    image_size=(64,64),
    batch_size=64,
    subset='validation',
    validation_split=0.2,
    seed=1234
)
###  train_ds 는 이렇게 된다. ((xxxxxx..), (yyyyyy...))

print(train_ds)

#### *** 데이터 전처리 ****
##### 인풋데이터 0~1사이로 압축하기
def 전처리함수(i, 정답):
  #i = i/255.0
  i = tf.cast(i/255.0, tf.float32)
  return i, 정답

#### 0~255의 값을 0~1 값으로 변경.(이유 불문, 효과 그냥 좋다. 꼬우면 논문ㄱㄱ)
##### .map(함수) : 이 함수를 똑같이 전부 적용시켜주세요.
train_ds = train_ds.map(전처리함수)
val_ds = val_ds.map(전처리함수)

# import matplotlib.pyplot as plt

# # 반복문으로 데이터셋 확인
# ## .take(1) 1개 가져올게용
for i, 정답 in train_ds.take(1):
  print(i)
  print(정답)
  # 텐서를 보여줄려면 꼭 numpy 붙여줘야 함.
  plt.imshow(i[0].numpy().astype('uint8'))
  plt.show()
  • 학습코드(같음)
# 모델 만들기
model = tf.keras.Sequential([
    ## 컬러사진이기때문에 마지막 차원수 3.
    tf.keras.layers.Conv2D(32, (3,3), padding="same",activation='relu', input_shape=(64,64,3)),
    tf.keras.layers.MaxPooling2D( (2,2) ),
    ## 학습효과를 더좋게하기위해 중간분석 더 많이 해보자
    tf.keras.layers.Conv2D(64, (3,3), padding="same",activation='relu'),
    tf.keras.layers.MaxPooling2D( (2,2) ),
    ## 더더더 ~
    ### 오버피팅 완화를 위해 Dropout 으로 (아래는 20% 삭제) 노드 일부 제거
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Conv2D(128, (3,3), padding="same",activation='relu'),
    tf.keras.layers.MaxPooling2D( (2,2) ),
    tf.keras.layers.Dense(128, activation="relu"),
    tf.keras.layers.Flatten(),
    ## 개인지 고양이인지 확인하는것이기때문에 답은 1개(0~1)
    tf.keras.layers.Dense(1, activation="softmax") # sofmax :0~1 로 압축시켜줌_카테고리예측용_총합1 // sigmoid 는 정답,오답 두개분류일때 사용)
])

# 모델 아웃라인 출력하기
model.summary()

## loss 함수는 binary_crossentropy
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=['accuracy'])
## train과 정답이 train_ds에 다있어서, trainX,trainY 를 대체 
## val_ds 또한 그럼
model.fit(train_ds, validation_data=val_ds, epochs=1)

결과

  • 정확도가 낮네용..
  • 문제 : 데이터의 퀄리티
      1. 데이터 양 늘리기
      1. 데이터 질 늘리기

pb, ckpt 저장하기

  • 체크포인트로 저장하기
  • 교육을 이어하 할 수 있게 해줌

방법

    1. 전체 모델 저장
# ckpt 만들기
# pb로 전체 저장(model1 저장)
model.save('./model1')
  • pb 파일로 모델 전체가 폴더내에 저장된다.
  • 모델 불러오기
# 저장된 model 불러오기
불러온모델 = tf.keras.models.load_model('./model1')
불러온모델.summary()
# 테스트
불러온모델.evaluate(testX,testY)

    1. ckpt :w값만 저장
    • ckpt는 epoch 완료시 (중간중간에) 저장 가능.
# ckpt 저장 예제
import tensorflow as tf 
import numpy as np

(trainX, trainY), (testX, testY) = tf.keras.datasets.fashion_mnist.load_data()

trainX = trainX / 255.0
testX = testX / 255.0

trainX = trainX.reshape( (trainX.shape[0], 28,28,1) )
testX = testX.reshape( (testX.shape[0], 28,28,1) )

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax'),
])

# 체크포인트 콜백함수
## mnist폴더에 저장하겠음. {epoch}변수를 넣으면 덮어쓰기 안함. 에포크 수를 확인 가능
## monitor와 mode를 통해 val값이 높은것만 저장할 수 있도록 할 수 있다.
콜백함수 = tf.keras.callbacks.ModelCheckpoint(
    # filepath='ckpt/mnnist{epoch}',
    filepath='ckpt/mnnist',
    monitor='val_acc',
    mode='max',
    save_weights_only=True,
    save_freq='epoch'
)

model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['acc'])
# model fit 뒤에 콜백함수 넣기
model.fit(trainX, trainY, validation_data=(testX, testY), epochs=3, callbacks=[콜백함수])

model.evaluate(testX,testY)

# ckpt 로드해보기

# 초기값은 shape 지정해야함.
model2 = tf.keras.Sequential([
    tf.keras.layers.Flatten( input_shape=(28,28,1) ),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax'),
])

model2.summary()
model2.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

## 로드 W !
model2.load_weights('ckpt/mnnist')

model2.evaluate(testX,testY)

  • 짱짱 멋있는 ckpt를 만들었다!!

이미지 증강

  • 이미지 비틀기, 이미지 수 뻥튀기
  • 효과 : 오버피팅 방지효과, 정확도 상승
  • 방법
      1. 증강데이터 사본 생성
      • 초기데이터 적으면 효과 X
      • 초기데이터 너무 많으면 X
      1. 모델에 넣기 전에 이미지 증강

모델에 넣기 전에 이미지 증강

...
# 모델 만들기
model = tf.keras.Sequential([   
    # **이미지 증강**           
    ## RandomFlip() : 사진뒤집기    
    tf.keras.layers.experimental.preprocessing.RandomFlip('horizontal', input_shape=(64,64,3)),
    ## RandomRotation() : 회전
    tf.keras.layers.experimental.preprocessing.RandomRotation(0.1),
    ## RandomZoom() : 확대
    tf.keras.layers.experimental.preprocessing.RandomZoom(0.1),
    # ** **

    ## 컬러사진이기때문에 마지막 차원수 3.
    tf.keras.layers.Conv2D(32, (3,3), padding="same",activation='relu'),
    tf.keras.layers.MaxPooling2D( (2,2) ),
...

imageDataGenerator : tensorflow 정통방식 이미지 증강

  • 코드
  • 이미지를 생성할때부터 꼬아서 만든다.
  • class_mode : 두개면 binary, 몇개더면 categorical
  • train은 만드는데, val은 안 뒤틀어도 됨.

테스트 자동화

TensorBoard 확인

  • 텐서보드를 이용하여 log 파일 받아오기(시간도 적었음)
...
model = tf.keras.Sequential([
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax'),
])

model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['acc'])

# 텐서보드 시각화
from tensorflow.keras.callbacks import TensorBoard
import time

tensorboard = TensorBoard( log_dir= 'logs/{}'.format('첫모델'+str(int(time.time()))))

model.fit(trainX, trainY, validation_data=(testX, testY), epochs=3, callbacks=[tensorboard])
...

log 열어보기

# Colab에서 텐서보드 log 확인
%load_ext tensorboard

%tensorboard --logdir logs

모델 함수화 하기

# 모델 만들기
## 모델 만들기 함수
def 모델만들기(덴스값):
    model = tf.keras.Sequential([   
        # **이미지 증강**           
        ## RandomFlip() : 사진뒤집기    
        tf.keras.layers.experimental.preprocessing.RandomFlip('horizontal', input_shape=(64,64,3)),
        ## RandomRotation() : 회전
        tf.keras.layers.experimental.preprocessing.RandomRotation(0.1),
        ## RandomZoom() : 확대
        tf.keras.layers.experimental.preprocessing.RandomZoom(0.1),
        # ** **

        ## 컬러사진이기때문에 마지막 차원수 3.
        tf.keras.layers.Conv2D(32, (3,3), padding="same",activation='relu'),
        tf.keras.layers.MaxPooling2D( (2,2) ),
        ## 학습효과를 더좋게하기위해 중간분석 더 많이 해보자
        tf.keras.layers.Conv2D(64, (3,3), padding="same",activation='relu'),
        tf.keras.layers.MaxPooling2D( (2,2) ),
        ## 더더더 ~
        ### 오버피팅 완화를 위해 Dropout 으로 (아래는 20% 삭제) 노드 일부 제거
        tf.keras.layers.Dropout(0.2),
        tf.keras.layers.Conv2D(128, (3,3), padding="same",activation='relu'),
        tf.keras.layers.MaxPooling2D( (2,2) ),
        tf.keras.layers.Dense(덴스값, activation="relu"),
        tf.keras.layers.Flatten(),
        ## 개인지 고양이인지 확인하는것이기때문에 답은 1개(0~1)
        tf.keras.layers.Dense(1, activation="softmax") # sofmax :0~1 로 압축시켜줌_카테고리예측용_총합1 // sigmoid 는 정답,오답 두개분류일때 사용)
    ])
    return model

NEW_model = 모델만들기(128)
  • 요런식

EarlyStopping

  • 더 이상 진전이 없을 경우 epoch 알아서 스탑
tensorboard = TensorBoard( log_dir= 'logs/{}'.format('첫모델'+str(int(time.time()))))


# EarlyStopping
from tensorflow.keras.callbacks import EarlyStopping
## monitor : 지금은 '...' 를 모니터 하겠다. ( val_loss, val_accuracy )
## patience : 몇번 이상 진전이 없으면 멈춘다.
# es = EarlyStopping(monitor='val_loss', patience=5, mode='min')
es = EarlyStopping(monitor='val_accuracy', patience=5, mode='max')

model.fit(trainX, trainY, validation_data=(testX, testY), epochs=3, callbacks=[tensorboard, es])

Sequential 말고 FunctionalAPI

  • 레이어를 유연하게 연결가능
  • 일단 모델 미리 보기 함수_plot_model

레이어 함수화

# 함수로 레이어 만들기
## 레이어 맘대로 연결도 가능 --> 소괄호 하나더 넣고, 레이어 하나 더 넣기
input1 = tf.keras.layers.Input(shape=[28,28])
flatten1 = tf.keras.layers.Flatten()(input1)
dense1 = tf.keras.layers.Dense(28*28, activation='relu')(flatten1)
## dense1 -(연결)-> 차원수 조정(현재 2차원)
### (28,28) 모양으로 만들려면 이전 레이어의 크기가 28*28이여야함
reshape1= tf.keras.layers.Reshape((28,28))(dense1)

# 레이어 합치기
concat1 = tf.keras.layers.Concatenate()([input1,reshape1])
# concat- -> 2차원 레이어 다시 1차원으로 연결
flatten2 = tf.keras.layers.Flatten()(concat1)
# fatten2 - -> output Layer 
output = tf.keras.layers.Dense(10,activation='softmax')(flatten2)

# 마무리작업( 시작, 끝 명시 )
model = tf.keras.Model(input1, output)

model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['acc'])

# 모델 미리보기 함수
from tensorflow.keras.utils import plot_model
plot_model(model, to_file='model.png', show_shapes=True,show_layer_names=True)

  • 결과를 이렇게 볼 수 있다.
  • 함수화 하면 이렇게 유연하게 레이어를 붙였다 땠다 할수 있다.
  • 데이터 쉐잎이 잘 꼬이니까 잘 만져주기

전이학습

  • 모델을 배껴서 사용하자~
  • 구글모델은 심지어 오픈소스!!
  • 실무자들도 다 사용한다.
  • 모델사용 방법
      1. 전부쓰기(GoogleNet을 쓰면 1천개 사진 분류가능)
      1. 일부레이어만 씀 (구글이 학습했던 Conv 레이어만 사용)
  • 결과 : 너무 사기적이다.. 교육 몇시간 돌린거보다 훨씬좋은 데이터가 나와버렸다. (에포크1회가 무슨 ac:0.97가 나오냐

전체코드

profile
🚄계속 앞으로🚄
post-custom-banner

0개의 댓글