Bootcamp_zerobase/Tensorflow

Tensorflow : data 다루기 #1

Loft_mind 2025. 4. 19. 17:01

2025.04.19

 

Part.11 텐서플로

Chapter 07. Data 다루기

  • 01_tf.data(1)
  • 02_tf.data(2)

 

데이터 다루기 (1)

 

로컬에 저장된 파일 읽기

 

일단, 관련된 라이브러리, 클래스를 IMPORT 한다.

import os
from glob import glob   # 파일조회

import tensorflow as tf
import numpy as np
from PIL import Image

import matplotlib.pyplot as plt
  • import os : 운영체제(OS) 관련 기능 제공.
    예를 들면 폴더 만들기, 파일 경로 다루기, 디렉터리 탐색하기 같은 걸 할 때 사용.
    대표적 : os.listdir(), os.path.join(), os.makedirs() 
  • from glob import glob : 파일 경로를 패턴 매칭해서 찾는 기능을 제공. (예를 들어 특정 폴더 안에 .jpg 파일만 찾기 등)
    glob('폴더경로/*.jpg') 이렇게 쓰면 그 폴더 안에 .jpg로 끝나는 모든 파일 경로를 리스트로 돌려줌.
  • from PIL import Image : 이미지 파일을 열거나, 수정하거나, 저장하는 기능을 제공해.
    Image.open('이미지파일경로') 이렇게 하면 이미지를 읽어올 수 있어.
    리사이징, 자르기, 포맷 변환 등 이미지 작업할 때 자주 씀.

 

os.listdir('./')    # 현재 디렉토리의 파일목록 조회

---------------------------------------------------------------------------------------
['001_TensorFlow_Class_Chapter00~01_20241222.ipynb',
 '002_TensorFlow_Class_Chapter02_20241223.ipynb',
 '003_TensorFlow_Class_Chapter02_linearRegression_20241225.ipynb',
 '004_TenserFlow_Class_chapter02_perceptron_20241226.ipynb',
 '005_TensorFlow_Class_Chapter03_DeeplearningFlow_20241229.ipynb',
 '006_tf_class_Modeling_250331.ipynb',
 '007_tf_class_VGGNet_250331.ipynb',
 '008_tf_class_functional_modeling_250401.ipynb',
 '009_tf_class_SubClass_250403.ipynb',
 '010_tf_class_SubClass2_250407.ipynb',
 '011_tf_class_Model_Training_250407.ipynb',
 '012_tf_class_Model_Training_250413.ipynb',
 '013_tf_class_Evaluation_tensorboard_250413.ipynb',
 '014_tf_class_Data_250419.ipynb',
 'logs']
## local에 CIfar10 데이터 
os.listdir("G:\\Zerobase_data_1(24)\class\zerobase_datasciences_school__class__part__11__15__230120\Part11__tensorflow_and_Part12__pytorch\deeplearning_frameworks_zerobaseDSS\datasets\cifar")

---------
['labels.txt', 'test', 'test_dataset.csv', 'train', 'train_dataset.csv']

 

 

 

 

 

glob 함수 : 특정 파일만 찾아서 리스트로 반환

## 폴더 내 png파일만 찾아서 리스트로 반환

# train datasets 폴더 path
train_ciar10_datapath = ciar10_datapath + '/train/'

train_img = glob(train_ciar10_datapath + '/*.png')
len(train_img)

=============================================================
>> 50000

 

.jpg, .png 등 특정 확장자의 파일의 이름만 모아서 리스트형태로 저장할 수 있다. 확장자만 가능한 건 아니고 특정 패턴이 있는 파일들을 선별해서 해당 파일의 이름을 리스트형태로 반환할 수 있는 기능이다.

 

 

tf로 Image 읽기

 

tf.io.read_file( ) 함수를 통해 파일을 읽어올 수 있다. 이미지 파일에 대한 디코딩을 해야한다. read_file(  ) 함수는 단순히 파일을 통으로 읽어오기만 한다.

# tf.io.read_file 함수 : 파일을 통째로 읽어옴 (바이너리 형태, )
# tf.image.decode_jpeg() : 이미지 파일이라면 적용되는 디코딩 형태. ~_png() 또는 ~_image() 형태도 있다.
# ~_image() 는 파일 형태와 상관없이 다 적용된다 (알아서 적용)

tf.io.read_file(train_img[0])

==========================================================================
<tf.Tensor: shape=(), dtype=string, 
numpy=b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x...e5\x9e\xe3\xffx\xcd\x00\x00\x00\x00IEND\xaeB`\x82'>

 

디코딩 진행 ( tf.io.decode_image( ) )

img = tf.io.decode_image(raw)
img.shape, img.dtype

========================================
>> (TensorShape([32, 32, 3]), tf.uint8)

 

 

그래서 이제 제대로 읽어서 디코딩이 되었는지 한번 확인해 보면??

plt.imshow(img)
plt.axis('off')
plt.tight_layout()
plt.show()

 

 

 

 

PIL 로 읽기

 

근데 아까 제일 위에서 from PIL import Image 으로 관련 라이브러리를 불러왔기 때문에 plt 말고 아래의 방법으로도 이미지를 읽을 수 있다.

Image.open(train_img[0])

 

일단 Cifar10 이미지 자체가 매우 작은 (32X32) 사이즈기 때문에 Image로 Open했을때 실제 사이즈로 Open된다. PIL 라이브러리에서 Image 클래스의 open 메서드 파일은 읽은 이후 편집이 가능하다.

 

 

※ 파일 (이미지) 조작관련 메서드

  • 이미지 크기확인 = img.size
  • 크기 조정 (resize) = img.resize((width, height))
  • 축소 (thumbnail) = img.thumbnail((max_width, max_height))
  • 회전 (rotate) = img.rotate(90)
  • 자르기 (crop) = img.crop((left, upper, right, lower))
  • 색변경 (convert) = img.convert('L') → 흑백 변환

 

그래서 이미지를 OPEN하고 사이즈를 확대하려면...

# 이미지 읽기
pil_img = Image.open(train_img[0])

# 이미지 사이즈 확인
pil_img.size
>> (32, 32)

# 리사이징 및 출력
b = pil_img.resize((32 * 10, 32 * 10), Image.LANCZOS)
b

# 또는 새창으로 이미지 띄우기기
pil_img.show()

# 변경된 사이즈 확인
b.size
>> (320, 320)

 

 

 

 

단순 이미지 확대 시, 픽셀이 깨지는 현상이 발생하기에, 아래와 같은 보간( interpolation) 방법을 같이 적용해야 함. 단 tensorflow 데이터로 활용 시에는 아닌 것 같음..

  • Image.NEAREST : 가장 단순. 픽셀 복사. (조금 깨짐)
  • Image.BILINEAR : 부드럽게 확대
  • Image.BICUBIC : 더 고급 부드러운 확대
  • Image.LANCZOS : 고퀄리티 확대 (느리지만 제일 부드러움)

 

데이터 다루기(2)

 

tf.data API

미리 이미지 데이터를 모두 읽어오는 게(read) 아니라, 그때그때 처리하는 것. 메모리 용량을 효율적으로 사용할 수 있다.

그래서 50000개의 이미지 데이터에 대해서, 20개의 이미지 데이터를 메모리에 불러오고, 학습을 한 후 메모리에서 제거하고, 다시 또 다른 20개의 이미지 데이터를 메모리에 불러오고, 학습, 제거반복하며 학습진행하는 방식이다.

 

 

# train datasets 폴더 path
train_ciar10_datapath = ciar10_datapath + '/train/'
train_img = glob(train_ciar10_datapath + '/*.png')

# 배열,리스트 등을 받아서 하나씩 Dataset 객체로 변환해준다.
dataset = tf.data.Dataset.from_tensor_slices(train_img)

# 반복가능한 객체를 이터레이터로 변환
iter(dataset)
>> <tensorflow.python.data.ops.iterator_ops.OwnedIterator at 0x2246bca4ee0>

# 이터레이터로 변환된 객체에서 next() 함수를 이용해서 하나씩 꺼내 확인
next(iter(dataset))
>> <tf.Tensor: shape=(), dtype=string, 
    numpy=b'G:\\Zerobase_data_1(24)\\class\\zerobase_datasciences_school__class__part__11__15__230120\\Part11__tensorflow_and_Part12__pytorch\\deeplearning_frameworks_zerobaseDSS\\datasets\\cifar/train\\0_frog.png'>

 

 

그래서 아래처럼 실행하게 되면, 이게 각각의 사진에 대한 path가 아닌 tensor가 불러지는 것을 확인할 수 있음.

## 함수를 이용해서 아래처럼 작업 가능

def read_image_tf(path):
    img = tf.io.read_file(path)
    img = tf.io.decode_image(img)
    return img

# tf.data API 로딩속도 최적화 자동튜닝 옵션 
# tf가 컴퓨터 자원을 보고 알아서 GPU,CPU 사용
AUTOTNE = tf.data.experimental.AUTOTUNE

# map() 함수 : tf.data.Dataset 객체에 있는 각 항목에 대해 주어진 함수를 적용
dataset = dataset.map(read_image_tf, num_parallel_calls=AUTOTNE)

next(iter(dataset))

 

 

 

 

dataset.batch(  )

그러면 일단 하나씩 읽어오는건 next(iter(datasets)) 으로 가능하단 사실을 확인하였다. 하지만, 통상 모델학습 시 하나씩 꺼내서 학습하는건 아니고, 배치사이즈를 설정해서 배치크기만큼 학습이 진행되게 된다. 이제 그럼 배치사이즈를 어떻게 설정하는지 보겠다.

dataset = dataset.batch(32)

next(iter(dataset))

 

처음 했던 것과 다르게 이제 32개가 한 번에 읽어와 진 것을 알 수 있다 (32, 32, 3) → (32, 32, 32, 3)

통상 배치학습 시, 데이터의 기본 순서대로 진행하지 않고, 데이터를 랜덤 하게 뽑아서 진행하기 때문에 shuffle() 함수 적용

# shuffle, buffer_size는 얼만큼 데이터를 섞을 것인가?..
dataset = dataset.shuffle(buffer_size=1000)

 

 

 

 

dataset.prefech(  )

추가적으로, prefetch( ) 함수가 있다.

이는 병렬 동작에 대한 것이고, 배치학습에 의해서 처음 32개의 데이터가 읽어오고, 학습하는 동안 다음 배치의 32개의 데이터를 준비하는 것이다. (병렬). 이는 속도가 개선되는 효과가 있다. → 데이터셋을 만들 때.

# prefetch 설정
dataset = dataset.prefetch(AUTOTNE)

 

 

 

dataset.repeat(  )

지금까지 만든 데이터셋은 1번 돌면, 즉 50000개의 데이터를 다 쓰면 끝난다. 그렇기에 epoch 학습을 하기 위해선, repeat( ) 함수를 적용시켜야 한다.

dataset = dataset.repeat()

 

 

 

정리

AUTOTNE = tf.data.experimental.AUTOTUNE

dataset = tf.data.Dataset.from_tensor_slices(train_img)
dataset = dataset.map(read_image_tf, num_parallel_calls=AUTOTNE)
dataset = dataset.batch(32)
dataset = dataset.prefetch(AUTOTNE)
dataset = dataset.shuffle(buffer_size=1000)
dataset = dataset.repeat()