0418 binary classification

wldnjswldnjs·2022년 5월 16일
0

딥러닝

목록 보기
6/10
post-custom-banner

1. 이미지 파일 -> csv 파일로 변환

conda install tqdm
conda install -c conda-forge ipywidgets
pip install opencv_python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import cv2 as cv   # OpenCV
from sklearn import utils
from tqdm.notebook import tqdm   # progressbar 처리
import os    # file의 경로를 설정하기 위해 필요!
# 폴더 경로 설정
train_dir = 'C:/jupyter_home/data/cat_dog/train'

# label(target)을 알아내기 위한 함수
# cat => 0, dog => 1
# img는 파일이름(cat.0.jpg)
def labeling(img):
    class_name = img.split('.')[0] # cat, 0, jpg로 나누어짐
    if class_name == 'cat':
        return 0 
    if class_name == 'dog':
        return 1
    
# pixel data(x_data)와 label data(t_data)를 저장할 변수 생성
x_data = []
t_data = []
# 파일을 하나씩 반복하면서 처리
# 특정 폴더에 있는 모든 파일명을 알아야 함 => os.listdir()

for img in tqdm(os.listdir(train_dir),
                total=len(os.listdir(train_dir)), # 몇 번 반복할 것인지
                position=0,                       # progressbar의 시작 위치
                leave=True):                     # 실행될수록 bar 색칠

    label_data = labeling(img)  # 0 or 1
    
    img_path = os.path.join(train_dir,img)       # 경로명, 파일명 join
    
    # img_path(이미지 full path)를 이용 => opencv를 통해 픽셀데이터를 추출
    # size가 너무 크면 그만큼의 많은 데이터양이 필요하고
    # size가 너무 작으면 데이터가 깨져서 특징을 추출하기가 힘들다.
    # 동일 크기로 resize 해야 함 => (80, 80)으로 size 변경
    img_data = cv.resize(cv.imread(img_path, cv.IMREAD_GRAYSCALE), (80,80))
    
    print(img_data.shape) # (80, 80)
    
    t_data.append(label_data)          # [0, 1, 1, 0, 0, ...]
    x_data.append(img_data.ravel())    # 2차원 => 1차원 변경

t_data안에 label 정보

x_data안에 픽셀 정보가 들어가 있을 것이다.

 t_df = pd.DataFrame({'label' : t_data}) # dictionary이므로 'label'
display(t_df.head())

x_df = pd.DataFrame(x_data)
display(x_df.head())

# x_data와 t_data 결합
df = pd.merge(t_df, x_df, left_index=True, right_index=True)
display(df.head())

# shuffle을 이용해서 편향된 dataframe의 row를 섞는다.
shuffle_df = utils.shuffle(df)
display(shuffle_df.head())

# 최종적으로 만들어진 DataFrame을 파일로 저장!
shuffle_df.to_csv('C:/jupyter_home/data/cat_dog/train.csv', index=False)

2. CNN 구현 (colab)

현재 사용하는 데이터의 크기가 약 500M정도이기 때문에

google drive에서 colab으로 파일을 불러올 수 있다.

파일이 더 커지면 못 불러온다.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.layers import Flatten, Dense, Dropout
from tensorflow.keras.optimizers import Adam
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

Raw Data Loading

df = pd.read_csv('/content/drive/MyDrive/colab/cat_dog/train.csv')
display(df.head())
print(df.shape)   # (25000, 6401)

x_data, t_data 분리

x_data = df.drop('label', axis=1, inplace=False).values
t_data = df['label'].values

size 조절

plt.imshow(x_data[152:153].reshape(80,80), cmap='gray')
# 하나의 행 slicing (1차원)
# reshape해서 2차원으로 변경

plt.show()

data split

train_x_data, test_x_data, train_t_data, test_t_data = \
train_test_split(x_data,
                 t_data,
                 test_size=0.3,
                 stratify=t_data)

Normalization(정규화)

scaler = MinMaxScaler()
scaler.fit(train_x_data)

norm_train_x_data = scaler.transform(train_x_data)
norm_test_x_data = scaler.transform(test_x_data)

model 생성

model = Sequential()

# CNN - Feature Extraction

model.add(Conv2D(filters=64,
                 kernel_size=(3,3),
                 activation='relu',
                 padding='SAME',
                 input_shape=(80,80,1))) # 세로, 가로, channel 수

model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(filters=128,
                 kernel_size=(3,3),
                 activation='relu',
                 padding='SAME'))

model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(filters=64,
                 kernel_size=(3,3),
                 activation='relu',
                 padding='SAME'))

model.add(MaxPooling2D(pool_size=(2,2)))

# FC Layer
model.add(Flatten())
model.add(Dropout(rate=0.5))

# Hidden layer
model.add(Dense(units=256, 
                activation='relu'))

# output layer
model.add(Dense(units=1,
                activation='sigmoid'))

print(model.summary())

model 실행 옵션

model.compile(optimizer=Adam(learning_rate=1e-4),
              loss='binary_crossentropy',
              metrics=['accuracy'])

model 학습

history = model.fit(norm_train_x_data.reshape(-1,80,80,1),
                    train_t_data.reshape(-1,1),
                    epochs=200,
                    batch_size=100,
                    verbose=1,
                    validation_split=0.3)  

result = model.evaluate(norm_test_x_data.reshape(-1,80,80,1),
                        test_t_data.reshape(-1,1))
print(result)
#        loss                accuracy
# [0.8235462307929993, 0.7775999903678894]

model 저장

model.save('/content/drive/MyDrive/colab/cat_dog/full_data_model/full_data_model.h5')

history 속성 보기

# history 객체를 이용해서 간단하게 학습과정에 대한 그래프

# history 객체 안에 history라는 속성
train_acc = history.history['accuracy']
train_loss = history.history['loss']

valid_acc = history.history['val_accuracy']
valid_loss = history.history['val_loss']

figure = plt.figure()
ax1 = figure.add_subplot(1,2,1)
ax2 = figure.add_subplot(1,2,2)

ax1.plot(train_acc, color='b', label='training accuracy')
ax1.plot(valid_acc, color='r', label='valid accuracy')
ax1.legend()

ax2.plot(train_loss, color='b', label='training loss')
ax2.plot(valid_loss, color='r', label='valid loss')
ax2.legend()

plt.tight_layout()
plt.show()

3. Keras가 제공하는 ImageDataGenerator 사용

1. cat_dog_full_folder 생성 (windows10)

import os, shutil

original_dataset_dir = '../data/cat_dog/train'

base_dir = '../data/cat_dog_full'
os.mkdir(base_dir)

train_dir = os.path.join(base_dir,'train').replace('\\','/')
os.mkdir(train_dir)
validation_dir = os.path.join(base_dir,'validation').replace('\\','/')
os.mkdir(validation_dir)
test_dir = os.path.join(base_dir,'test').replace('\\','/')
os.mkdir(test_dir)


train_cats_dir = os.path.join(train_dir,'cats').replace('\\','/')
os.mkdir(train_cats_dir)
train_dogs_dir = os.path.join(train_dir,'dogs').replace('\\','/')
os.mkdir(train_dogs_dir)

validation_cats_dir = os.path.join(validation_dir,'cats').replace('\\','/')
os.mkdir(validation_cats_dir)
validation_dogs_dir = os.path.join(validation_dir,'dogs').replace('\\','/')
os.mkdir(validation_dogs_dir)

test_cats_dir = os.path.join(test_dir,'cats').replace('\\','/')
os.mkdir(test_cats_dir)
test_dogs_dir = os.path.join(test_dir,'dogs').replace('\\','/')
os.mkdir(test_dogs_dir)

## file 복사 ##
## 고양이와 멍멍이가 각각 12,500개
## train : 7,000 
## validation : 3,000
## test : 2,500 

fnames = ['cat.{}.jpg'.format(i) for i in range(7000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname).replace('\\','/')
    dst = os.path.join(train_cats_dir, fname).replace('\\','/')
    shutil.copyfile(src,dst)

fnames = ['cat.{}.jpg'.format(i) for i in range(7000,10000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname).replace('\\','/')
    dst = os.path.join(validation_cats_dir, fname).replace('\\','/')
    shutil.copyfile(src,dst)

fnames = ['cat.{}.jpg'.format(i) for i in range(10000,12500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname).replace('\\','/')
    dst = os.path.join(test_cats_dir, fname).replace('\\','/')
    shutil.copyfile(src,dst)
    
fnames = ['dog.{}.jpg'.format(i) for i in range(7000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname).replace('\\','/')
    dst = os.path.join(train_dogs_dir, fname).replace('\\','/')
    shutil.copyfile(src,dst)

fnames = ['dog.{}.jpg'.format(i) for i in range(7000,10000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname).replace('\\','/')
    dst = os.path.join(validation_dogs_dir, fname).replace('\\','/')
    shutil.copyfile(src,dst)

fnames = ['dog.{}.jpg'.format(i) for i in range(10000,12500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname).replace('\\','/')
    dst = os.path.join(test_dogs_dir, fname).replace('\\','/')
    shutil.copyfile(src,dst)

2. ImageDataGenerator 사용

import os
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt

train_dir = '../data/cat_dog_full/train'    # cats folder, dogs folder
valid_dir = '../data/cat_dog_full/validation'
 
# ImageDataGenerator를 생성해요!
# RGB값이 0~255로 구성되어 있으므로
# 각 픽셀의 값을 255로 나눠서 정규화 (MinMaxScaling)
train_datagen = ImageDataGenerator(rescale=1/255)
validation_datagen = ImageDataGenerator(rescale=1/255)

train_generator = train_datagen.flow_from_directory(
    train_dir,    # target directory
    classes=['cats', 'dogs'], # 폴더명을 class로 잡는다. cats : 0, dogs : 1
                              # 따로 명시하지 않으면 오름차순으로 명시  
    target_size=(150,150),    # CNN에는 동일 크기로 들어가야 한다.
    batch_size=20,            # 한번에 20개 가져온다. 많아서 한번에 못들고 옴
    class_mode='binary'
)

validation_generator = validation_datagen.flow_from_directory(
    valid_dir,                 # target directory
    classes=['cats', 'dogs'],
    target_size=(150,150),
    batch_size=20,
    class_mode='binary'
)

for x_data, t_data in train_generator:
    print(x_data.shape)
    print(t_data.shape)
    break
    
figure = plt.figure()
ax = []

for i in range(20):
    ax.append(figure.add_subplot(4,5,i+1))

for x_data, t_data in train_generator:
    print(x_data.shape)   # (20, 150, 150, 3)
    print(t_data.shape)
    
    # enumerate() : 앞에꺼 index, 뒤에꺼 data
    for idx, img_data in enumerate(x_data): # idx : 20, img_data (150, 150, 3)
        ax[idx].imshow(img_data)
        
    break
    
plt.tight_layout()
plt.show()

post-custom-banner

0개의 댓글