[개발일지 2022.4.18] Microsoft Azure(1)

1.학습한 내용

1)이미지 분석 샘플

개와 고양이를 구분을 실습하게된다.

kaggle.com 에서 개와 고양이의 이미지 데이터를 받아온다.

csv파일과 test 파일, 그리고 train 파일을 받아온다.

이때, 오늘의 작업은 GPU를 사용해야하기때문에, 구글드라이브의 colab을 사용한다.

import keras
keras.__version__

케라스 라이브러리를 불러오고,
구글드라이브에 파일을 업로드 한것을 불러오기 위해서 구글 드라이브와 연결을 한다.

from google.colab import drive
drive.mount('/content/dirve')

드라이브의 연결이 끝났으니 필요한 라이브러리를 불러온다.

import os, shutil

이때
shutil는 Shell Script Utility , 리눅스 같은 명령어를 쓸수있게 해주는 유틸리티이다.

이제 이미지 데이터를 분류하기 위해서
폴더들을 확인하는 코드들을 사용한다.

original_dataset_dir = './drive/MyDrive/datasets/cats_and_dogs/train'

base_dir ='./drive/MyDrive/datasets/cats_and_dogs_small'

기본이 되는 데이터셋의 디렉터리를 설정한다.

if os.path.exists(base_dir): 
  shutil.rmtree(base_dir) 
os.mkdir(base_dir)

이때. base_dir 가 이미 존재한다면 삭제를 하고, 없다면 mkdir 을 통해서 base_dir 을 생성한다.

이후 이 base_dir 의 하위폴더를 만드는데

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

이를 통해서 base_dir 의 바로 아래에 train폴더, validation폴더, test 폴더를 만든다.

train_cats_dir = os.path.join(train_dir,'cats')
os.mkdir(train_cats_dir)

train_dogs_dir = os.path.join(train_dir,'dogs')
os.mkdir(train_dogs_dir)



validation_cats_dir = os.path.join(validation_dir,'cats')
os.mkdir(validation_cats_dir)

validation_dogs_dir = os.path.join(validation_dir,'dogs')
os.mkdir(validation_dogs_dir)



test_cats_dir = os.path.join(test_dir,'cats')
os.mkdir(test_cats_dir)

test_dogs_dir = os.path.join(test_dir,'dogs')
os.mkdir(test_dogs_dir)

이후 train, validation, test 폴더에 각각 dogs 와 cats 디렉터리를 만든다.

이를 통해서

하위 폴더들이 만들어 진다는것을 확인할수있다.

이제 이 하위폴더에 이미지들을 복사해서 넣게된다.

print('Copy files....')
print('---Training file(s) (cat)....')
fnames = ['cat.{}.jpg'.format(i) for i in range(1000)] 
for fname in fnames:
  src = os.path.join(original_dataset_dir, fname)
  dst = os.path.join(train_cats_dir, fname)
  shutil.copy(src,dst)

이를 통해서 고양이 이미지를 0부터 999까지 1천개를 복사하게 된다.
이제 이 코드를 복사하게 되면

print('---Validation file(s) (cat)....')
fnames = ['cat.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
  src = os.path.join(original_dataset_dir, fname)
  dst = os.path.join(validation_cats_dir, fname)
  shutil.copy(src,dst)

print('---Test file(s) (cat)....')
fnames = ['cat.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
  src = os.path.join(original_dataset_dir, fname)
  dst = os.path.join(test_cats_dir, fname)
  shutil.copy(src,dst)

1000번째부터 1500번째까지 이미지를 validation cats 로, 1500번째부터 2000번째까지의 이미지를 test cats 로 복사를 해서 넣는다는것을 알수있다.

이를 cat부분을 dog 으로 바꾸게 되면

print('---Training file(s) (dog)....')
fnames = ['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
  src = os.path.join(original_dataset_dir, fname)
  dst = os.path.join(train_dogs_dir, fname)
  shutil.copy(src,dst)

print('---Validation file(s) (dog)....')
fnames = ['dog.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
  src = os.path.join(original_dataset_dir, fname)
  dst = os.path.join(validation_dogs_dir, fname)
  shutil.copy(src,dst)

print('---Test file(s) (dog)....')
fnames = ['dog.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
  src = os.path.join(original_dataset_dir, fname)
  dst = os.path.join(test_dogs_dir, fname)
  shutil.copy(src,dst) 

를 입력하는것으로 강아지의 이미지 데이터 또한 복사가 가능하다.

이때
src는 복사하는 파일을 가져올 폴더.
dst은 복사하는 파일을 넣을 폴더이다.


이렇게 중간에 print 문을 넣는것으로 진행도에 따른 위치가 표시가 된다.

이제 이렇게 복사된 파일들을 확인하기 위해서 코드를 만든다.

print('훈련용 고양이 이미지:', len(os.listdir(train_cats_dir)))
print('검증용 고양이 이미지:', len(os.listdir(validation_cats_dir)))
print('테스트용 고양이 이미지:', len(os.listdir(test_cats_dir)))

print('훈련용 강아지 이미지:', len(os.listdir(train_dogs_dir)))
print('검증용 강아지 이미지:', len(os.listdir(validation_dogs_dir)))
print('테스트용 강아지 이미지:', len(os.listdir(test_dogs_dir)))

이제 이를 적용시킬 신경망을 만든다.

from keras import layers
from keras import models

model = models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Flatten())
model.add(layers.Dense(512,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))

신경망의 구조를 정했으면 신경망을 compile한다.

from tensorflow.keras import optimizers

model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['acc'])

이제 이 신경망에 이미지파일을 적용하기 위해서는 이미지 스케일이 필요하여, 그를 위한 라이브러리를 불러온다.

from keras.preprocessing.image import ImageDataGenerator
# 이미지 스케일을 위한 도구

train_datagen = ImageDataGenerator(rescale=1./255)
validation_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
    train_dir,
    target_size=(150,150),
    batch_size=20,
    class_mode='binary'
)

validation_generator = validation_datagen.flow_from_directory(
    validation_dir,
    target_size=(150,150),
    batch_size=20,
    class_mode='binary'
)

이제 이렇게 만들어진 데이터들을 신경망에 적용을 시킨다.

model.fit_generator(
    train_generator,
    epochs=30,
    steps_per_epoch=100,
    validation_data = validation_generator,
    validation_steps = 50
)

이때, 데이터가 큰 이미지파일을 가지고 진행하는것이어서 오래걸린다. GPU를 사용한다.


이제 이렇게 학습한 데이터를 파일로 저장을 한다.

model.save('cats_and_dogs_small_1.h5')

이때, 저장을 하지 않으면 model을 새로 만들때마다 오래걸리는 작업을 다시 실행해야한다.

이렇게 나온 데이터들을 시각적으로 확인하기 위해서 그래프를 그린다.

history = model.history

import matplotlib.pyplot as plt

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()


이를 통해서 가장 적절한 시행횟수를 확인할수있다.

이제 훈련용 이미지 데이터들을 증식을 시킨다.

datagen = ImageDataGenerator(
      rotation_range=40,#각도를 40도를 돌린다
      width_shift_range=0.2,
      height_shift_range=0.2,
      shear_range=0.2,
      zoom_range=0.2,
      horizontal_flip=True,#수평으로 좌우를 바꿔서 증식한다
      fill_mode='nearest')#이동했을때 빈공간을 뭘로 채울것인가. nearest: 근처의색으로 채워준다.

# 이미지 전처리 유틸리티 모듈
from keras.preprocessing import image

fnames = sorted([os.path.join(train_cats_dir, fname) for fname in os.listdir(train_cats_dir)])

# 증식할 이미지 선택합니다
img_path = fnames[3]

# 이미지를 읽고 크기를 변경합니다
img = image.load_img(img_path, target_size=(150, 150))

# (150, 150, 3) 크기의 넘파이 배열로 변환합니다
x = image.img_to_array(img)

# (1, 150, 150, 3) 크기로 변환합니다
x = x.reshape((1,) + x.shape)

# flow() 메서드는 랜덤하게 변환된 이미지의 배치를 생성합니다.
# 무한 반복되기 때문에 어느 지점에서 중지해야 합니다!
i = 0
for batch in datagen.flow(x, batch_size=1):
    plt.figure(i)
    imgplot = plt.imshow(image.array_to_img(batch[0]))
    i += 1
    if i % 4 == 0:
        break

이렇게 하면 3번(4번째)의 이미지를 조금씩 이동한 이미지로 증식을 시킨다.

이때 주의할점은, 학습용 데이터는 증식을 시켜도 되지만, 검증용, 테스트용 데이터는 증식시키면 안된다.

새로운 신경망을 만든다.

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu',
input_shape=(150, 150, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))



model.compile(loss='binary_crossentropy',
optimizer=optimizers.RMSprop(lr=1e-4),
metrics=['acc'])

이렇게 신경망을 하나 새로 만든다.

그 후 그를 바탕으로 이미지를 적용한다.

train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,)



# 검증 데이터는 증식되어서는 안 됩니다!
test_datagen = ImageDataGenerator(rescale=1./255)



train_generator = train_datagen.flow_from_directory(
# 타깃 디렉터리
train_dir,
# 모든 이미지를 150 × 150 크기로 바꿉니다
target_size=(150, 150),
batch_size=20,
# binary_crossentropy 손실을 사용하기 때문에 이진 레이블을 만들어야 합니다
class_mode='binary')



validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=20,
class_mode='binary')



history = model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=100,
validation_data=validation_generator,
validation_steps=50)


이렇게 100회가 끝나면 저장을 한다.

model.save('cats_and_dogs_small_2.h5')

이 또한 그래프를 통해서 시각화를 하여서 확인을 한다.

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']



epochs = range(len(acc))



plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()



plt.figure()



plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()


이전의 그래프보다 횟수가 많아져서 더 촘촘해진것을 확인할수있다.

2.학습내용 중 어려웠던 점

웹에서 커다란 데이터를 사용하는 것이기 때문에, 업로드가 느려진다거나, 코드는 올바른데 실행이 되지않는등의 오류들이 있었다.

3.해결방법

이러한 오류들은 이미 겪은 사람들이 있어서, 인터넷의 검색을 통하여서, 업로드는 구글드라이브 앱을 사용하는식으로 더 빠르게 올리는 방법을 찾아낼수있었고,
실행이 되지않는 오류의 경우에는 예전과 다르게 colab 에서 제공하는 리소스가 줄어들어서 batch_size 를 줄이는 것으로 해결이 되었다.

4.학습소감

지금까지는 개인 컴퓨터를 사용하는것으로 코드를 진행하는데에 어려움을 크게 느끼지 못하였지만, 대량의 데이터를 가지고 작동하는 코드의 경우에는, 수업하는 학우분들과 강사님들을 포함해서 컴퓨터의 성능에 따라서 속도가 다른것을 보고, 장비의 중요성 또한 깨달았다.
이와 관련해서 클라우드서비스를 사용하기 위해서 Azure 에 대하여 맛보기만 듣게 되었는데, 이러한 서비스를 활용하는 것으로 컴퓨터의 성능부족을 많이 완화시킬수있을것으로 기대되어서, 다음 수업을 듣는것을 기대하고있다.

좋은 웹페이지 즐겨찾기