티스토리 뷰

오랜만에 이 블로그를 업데이트한다.

 

예전에는 Colab(코랩)에서 실습할 때 데이터셋의 이미지를 resize할 때 메모리가 모자라서 중단된 적이 없었다. 그런데 이번에 수업 과제를 하는데 CIFAR-10 이미지를 resize 하는 단계에서 메모리가 부족해서 진행을 할 수가 없었다. 모두연에서 공부할 때 아마 I.D.G를 사용했을 텐데 이전에 실습한 노트북은 참고하지 않고 쌩으로 그냥 해 보고자 해서 삽질을 좀 했다. 당시 공부하면서 이론 부분에 부족함을 크게 느껴 그 부분을 보충하고자 하는 것도 대학원을 진학한 이유 중 하나이기 때문이다.

 

tf.image.resize()

아래가 내가 처음 시도한 코드. (tf.image.resize() 사용)

메모리 부족 에러가 뜨면서 런타임이 자동으로 중단되었다.

Training 단계에서 메모리 부족 문제는 mini-batch를 사용하여 해결한다지만, 이미지 resize 단계부터 메모리 문제가 발생하여 다른 방법을 찾아야 했다. (첫 번째 과제에 투자할 시간이 너무 없어서 model 구현, training, test의 원리 이해 정도로 과제를 수행하고자 코랩이 허용하는 Data 개수로 데이터를 Slicing해서 수행하였다.)

# Resize the images
resize_img = (227, 227)
x_train = tf.image.resize(x_train, resize_img)
x_test = tf.image.resize(x_test, resize_img)

 

그럼 어떻게 해야 이미지 사이즈를 모두 (227, 227)로 바꾸어줄 수 있을까?

ChatGPT는 keras의 ImageDataGenerator를 사용하라고 알려주었다. 그리고 검색을 통해 찾은 방법은 다음과 같이 3가지였다.

1. tf.keras.preprocessing.image.ImageDataGenerator

2. tf.keras.layers.Resizing

3. tf.data API

 

다행히도 교수님이 이후 과제들을 첫 번째 과제에서 변형을 하여 하드웨어적인 측면의 이해를 넓혀나가는 방식으로 내주었기 때문에, 시간을 투자할 수 있어졌을 때 더 탐구하여 문제를 해결할 수 있게 되었다.

 

Directory

일단 CIFAR10 데이터셋은 디렉토리 구조로 제공되지 않기 때문에 디렉토리 구조를 먼저 만들어 준다.

# Directory structure setting (CIFAT-10 데이터셋은 디렉토리 구조가 아니기에 뒤에서 img size를 227로 변경할 때 flow_from_directory()함수를 사용하고자 디렉토리 구조를 만들어 줌)
train_dir = 'cifar10/train'
test_dir = 'cifar10/test'
os.makedirs(train_dir, exist_ok=True)
os.makedirs(test_dir, exist_ok=True)

# Generated directory by classes
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
for class_name in class_names:
    os.makedirs(os.path.join(train_dir, class_name), exist_ok=True)
    os.makedirs(os.path.join(test_dir, class_name), exist_ok=True)

# Save img in diretory
for i in range(len(x_train)):
    img_path = os.path.join(train_dir, class_names[y_train[i, 0]], f'{i}.png')
    tf.keras.utils.save_img(img_path, x_train[i])

for i in range(len(x_test)):
    img_path = os.path.join(test_dir, class_names[y_test[i, 0]], f'{i}.png')
    tf.keras.utils.save_img(img_path, x_test[i])

base_dir/
    ├── train/
    │   ├── airplane/
    │   │   ├── airplane_image1.png
    │   │   ├── airplane_image2.png
    │   │   └── ...
    │   ├── automobile/
    │   │   ├── automobile_image1.png
    │   │   ├── automobile_image2.png
    │   │   └── ...
    │   ├── bird/
    │   │   ├── bird_image1.png
    │   │   ├── bird_image2.png
    │   │   └── ...
    │   ├── ...
    │   └── truck/
    │       ├── truck_image1.png
    │       ├── truck_image2.png
    │       └── ...
    └── test/
        ├── airplane/
        │   ├── airplane_image1.png
        │   ├── airplane_image2.png
        │   └── ...
        ├── automobile/
        │   ├── automobile_image1.png
        │   ├── automobile_image2.png
        │   └── ...
        ├── bird/
        │   ├── bird_image1.png
        │   ├── bird_image2.png
        │   └── ...
        ├── ...
        └── truck/
            ├── truck_image1.png
            ├── truck_image2.png
            └── ...

 

ImageDataGenerator()

ImageDataGenerator를 사용하여 Normalization 및 Argumentation 조건을 만들어준다.

# ImageDataGenerator for data argumentation
train_datagen = ImageDataGenerator(
        rescale=1./255,
        horizontal_flip=True)
test_datagen = ImageDataGenerator(rescale=1./255)

 

flow_from_directory()

flow_from_directory()를 사용하여 Train data를 batch size만큼 나누어 입력할 수 있도록 설정한다. (데이터셋의 디렉토리를 설정한 것은 이 단계에서 디렉토리 경로가 필요하기 때문이다.)

# Load train dataset (이미지 사이즈 227로 조정하는 단계에 mini-batch 적용하게 만듬)
train_generator = train_datagen.flow_from_directory(
    train_dir,
    target_size=(227, 227),
    batch_size=128,
    class_mode='categorical'
)

# Load test dataset
test_generator = test_datagen.flow_from_directory(
    test_dir,
    target_size=(227, 227),
    batch_size=128,
    class_mode='categorical',
    shuffle=False
)

 

결론적으로, GPU로 50epochs를 돌리는데 2시간이 걸렸다. 이전에는 CPU와 GPU의 차이를 체감할 계기가 없었는데 이론과 함께 코드를 이해하면서 사용하게 되니 더욱 효율적인 엔지니어링을 할 수 있게 되어간다. (이전에 대강 공부한 것을 하나씩 자세히 들여다보게 되니 더 명확해지는 것 같기도 하다.)

# Train the model
history = model.fit(train_generator, batch_size=128, epochs=50)
 
Epoch 50/50 391/391 [==============================] - 115s 293ms/step - loss: 0.0961 - accuracy: 0.9730

 

# Evaluate the model
test_loss, test_acc = model.evaluate(test_generator)
print(f"Test loss: {test_loss}, Test accuracy: {test_acc}")
 
79/79 [==============================] - 20s 248ms/step - loss: 0.6300 - accuracy: 0.8570 Test loss: 0.6300482153892517, Test accuracy: 0.8569999933242798

이제 부족했던 이론적인 측면을 하나씩 알아가고 있으니 석사를 졸업할 때쯤이면 이론에 빠삭해질 것을 기대하며, 이번 글을 마친다.

 

 

뜻밖의 GPU vs CPU 실험.

GPU 설정으로 20epochs를 돌렸을 쯤 코랩 사용량 초과로 중단되어 다른 계정으로 GPU 50epochs를 돌리고, 사용량 초과로 중단된 계정으로 CPU 설정으로 동시에 Training을 실행시켜 두었다. GPU로 50epochs가 완료될 때까지 CPU는 1epoch도 완료되지 않았다.

 

 

 

ChatGPT와의 대화

 

Q. Alexnet에서 dataset image를 255로 divide하는 이유는 뭐야?

A. AlexNet에서 dataset 이미지를 255로 나누는 이유는 이미지의 픽셀 값을 [0, 1] 범위로 정규화(normalization)하기 위함입니다. 정규화는 데이터를 일정한 범위로 조정하여 모델의 학습을 도와주는 일반적인 전처리 기법입니다.

AlexNet은 입력 이미지의 픽셀 값들을 신경망에 주입하기 전에 이러한 정규화를 수행합니다. 일반적으로 컬러 이미지의 각 픽셀 값은 0부터 255까지의 범위를 가집니다. 이를 0에서 1 사이의 값으로 정규화하면 학습 알고리즘이 더 잘 동작하게 됩니다. 이는 일부 최적화 알고리즘이 작은 입력 값을 선호하거나, 가중치 갱신에 영향을 주는 기울기를 제어하는 데 도움이 되기 때문입니다.

따라서 AlexNet은 각 픽셀 값에 255로 나누어서 [0, 1] 범위로 정규화합니다. 이를 통해 모델이 입력 데이터를 더 효과적으로 처리하고 학습할 수 있도록 도와줍니다.

 

Q. AlexNet에서 이미지 크기를 227*227로 조정하는 이유는 뭐야?

A. AlexNet에서 이미지 크기를 227x227로 조정하는 이유는 해당 아키텍처가 설계될 당시의 목적과 제약 사항 때문입니다.
AlexNet은 2012년 ImageNet Large Scale Visual Recognition Challenge (ILSVRC) 대회에서 우승한 모델로, 대규모 이미지 분류 문제에 효과적인 딥러닝 모델을 개발하기 위해 제안되었습니다.
(1) 컴퓨팅 리소스: AlexNet은 초기 딥러닝 모델로서, 2012년 당시에는 컴퓨팅 리소스에 제한이 있었습니다. 227x227 크기의 이미지는 상대적으로 더 작은 크기의 입력이며, 이는 모델의 학습과 추론에 필요한 계산 리소스를 줄일 수 있습니다.
(2) 컨볼루션 레이어 설계: AlexNet은 여러 개의 컨볼루션 레이어와 풀링 레이어로 구성되어 있습니다. 이러한 레이어 구조는 공간적인 계층 구조를 학습하고 이미지의 다양한 특징을 추출할 수 있도록 도와줍니다. 227x227 크기의 이미지를 사용하면 이러한 계층 구조가 적절하게 설계될 수 있습니다.
(3) 전이 학습의 가능성: AlexNet은 ImageNet 데이터셋으로 사전 훈련된 모델로서, 이미지 분류 태스크에서 강력한 성능을 보입니다. 227x227 크기의 이미지를 사용한 사전 훈련은 이 모델을 다른 작업에 적용할 때 전이 학습의 잠재력을 향상시킵니다. 예를 들어, AlexNet을 다른 이미지 분류 문제에 적용하거나 객체 감지나 세분화와 같은 다른 컴퓨터 비전 작업에 이 모델을 사용할 수 있습니다.
따라서 AlexNet은 초기 딥러닝 모델의 한 예로서, 해당 모델이 설계되었을 당시의 제약 사항과 목적에 따라 이미지 크기를 227x227로 조정했습니다. 이 크기는 모델의 효율성과 학습 성능을 균형있게 유지하는 역할을 합니다.

 

Q. validation data와 test data의 차이점

A. Validation 데이터와 Test 데이터는 모델의 성능을 평가하는 데 사용되는 데이터 세트입니다. 그러나 두 데이터 세트는 목적과 사용 방법에서 약간의 차이가 있습니다.

1. Validation 데이터:
훈련 과정에서 모델의 성능을 평가하고 조정하는 데 사용됩니다.
훈련 데이터의 일부를 따로 떼어서 만들어지며, 일반적으로 훈련 데이터의 10-20% 정도를 할당합니다.
모델의 매개변수 조정이나 하이퍼파라미터 튜닝 등의 결정을 내리기 위해 사용됩니다.
Validation 데이터를 사용하여 모델의 성능을 측정하고, 이를 바탕으로 모델을 개선하기 위해 학습 과정을 조정합니다.

2. Test 데이터:
- 모델의 최종 성능을 평가하는 데 사용됩니다.
- 모델의 개발 및 조정 단계가 모두 완료된 후, 최종 모델을 평가하는 데에 사용됩니다.
- 이 데이터는 모델이 이전에 본 적이 없는 완전히 새로운 데이터로 구성되어야 합니다.
- 테스트 데이터는 모델의 일반화(generalization) 성능을 평가하는 데 사용되며, 모델이 실제 배포되었을 때 예상되는 성능을 추정하는 데 도움을 줍니다.
- 테스트 데이터는 모델 성능을 정확하게 평가하기 위해 모델의 최종 평가에만 사용되어야 하며, 모델 개발이나 하이퍼파라미터 튜닝에는 사용해서는 안 됩니다.

 

요약하면, Validation 데이터는 모델 개발 단계에서 사용되어 모델을 튜닝하고 최적화하는 데 도움을 주는 반면, Test 데이터는 모델의 최종 성능을 평가하는 데 사용되어 모델의 일반화 성능을 측정합니다. Test 데이터는 모델을 배포하기 전에 사용되어야 하며, 모델의 실제 성능을 예측하는 데 중요한 역할을 합니다.

 

Q. tf.data API를 사용하는 이유는 무엇인가요?

A. Bing ai: tf.data API는 TensorFlow에서 데이터를 로드하고 전처리하는 데 사용되는 강력한 API입니다. 이 API를 사용하면 데이터 파이프라인을 빌드하고 데이터를 효율적으로 로드하고 전처리할 수 있습니다. tf.data API는 다양한 데이터 소스에서 데이터를 읽을 수 있으며, 데이터 전처리 및 증강을 위한 다양한 변환을 제공합니다. 이 API는 또한 데이터를 배치로 분할하고 셔플링하는 기능도 제공합니다. 이러한 기능들은 모델 학습을 더욱 효율적으로 만들어줍니다.

 

A. ChatGPT: tf.data API는 TensorFlow에서 데이터셋을 효율적으로 처리하기 위해 제공되는 고수준 API입니다. 다음은 tf.data API를 사용하는 이유입니다:

1. 메모리 효율성: 대용량 데이터셋을 메모리에 한 번에 로드하는 것은 비효율적일 수 있습니다. tf.data API는 데이터를 조각 내어 효율적으로 메모리에 로드하고 처리할 수 있습니다. 이를 통해 시스템 메모리를 효율적으로 활용하고, 대용량 데이터셋도 처리할 수 있습니다.

2. 병렬 처리: tf.data API는 데이터를 병렬로 읽고 전처리할 수 있습니다. 데이터를 여러 스레드에서 동시에 처리하여 GPU 또는 TPU의 연산 처리량을 효과적으로 활용할 수 있습니다. 이는 데이터 입력 파이프라인의 병목 현상을 줄이고 학습 또는 추론 속도를 향상시킵니다.

3. 유연한 전처리: tf.data API는 데이터셋을 생성, 변환 및 조작하는 다양한 전처리 기능을 제공합니다. 데이터 증강, 이미지 크기 조정, 정규화, 셔플링, 배치 처리 등과 같은 일반적인 전처리 작업을 쉽게 구현할 수 있습니다. 이를 통해 데이터 전처리 과정을 간단하게 유지하면서도 복잡한 전처리 기능을 쉽게 추가할 수 있습니다.

4. 확장성: tf.data API는 다양한 데이터소스와 통합할 수 있는 인터페이스를 제공합니다. 파일 시스템, CSV 파일, TFRecord 파일, 데이터베이스 등 다양한 데이터 소스에서 데이터셋을 생성하고 처리할 수 있습니다. 또한 사용자 정의 데이터소스를 만들어 특수한 데이터 처리 요구사항을 충족시킬 수도 있습니다.

5. 간편한 사용성: tf.data API는 TensorFlow의 다른 구성 요소와 통합되어 사용하기 쉽습니다. tf.data.Dataset 객체를 생성하고 모델 훈련 또는 추론에 직접 사용할 수 있으며, TensorFlow의 기능과 메서드와 함께 자연스럽게 통합됩니다.

tf.data API를 사용하면 데이터 입력 파이프라인을 구축하고 데이터셋을 효율적으로 처리할 수 있으며, 모델의 학습 및 추론 성능을 향상시킬 수 있습니다.

 

Q. cifar10 데이터셋을 tf.keras.utils.image_dataset_from_directory로 로드하는 코드를 알려줘

A. tf.keras.utils.image_dataset_from_directory 함수는 디렉토리에서 이미지 데이터셋을 로드하는 데 사용되는 유틸리티 함수입니다. 하지만 cifar10 데이터셋은 이미 파일 시스템의 디렉토리 구조로 구성되어 있지 않기 때문에 이 함수를 직접 사용하여 로드할 수는 없습니다. 대신 tf.data.Dataset.from_tensor_slices를 사용하여 CIFAR-10 데이터셋을 로드하고 전처리하는 방법을 앞서 제시한 바 있습니다.

 

 

 

참고

[1] tf.keras.preprocessing.image.ImageDataGenerator

https://keras.io/ko/preprocessing/image/

https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/ImageDataGenerator

 

[2] tf.keras.layers.Resizing

https://www.tensorflow.org/api_docs/python/tf/keras/layers/Resizing

https://www.tensorflow.org/tutorials/images/data_augmentation?hl=ko 

https://machinelearningmastery.com/image-augmentation-with-keras-preprocessing-layers-and-tf-image/

 

[3] tf.data API

https://lynnshin.tistory.com/26

 

 

댓글
최근에 올라온 글
페이지 이동 안내

보던 글 목록 : 브라우저 뒤로 가기 메인 화면 : 좌측 상단 아이콘
🍍 The GOAL: AI expert에 가까워지는 중

🍍 I am becoming AI expert who can develop cool things by coding.