Tensorflow : data 다루기 #1
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()