데이터 전처리/증강
torchvision의 transforms를 사용
이미지 데이터 전처리
데이터 다양성을 높이기 위해 증강
필요 라이브러리 임포트
import torch
from torchvision import transforms
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
먼저 원본 이미지(뉴진스 민지)를 PIL의 Image.open으로 확인해보겠습니다.
img = Image.open('./minji.png')
img
type 변경
PIL인 상태에서 numpy 형태로 바꿔주겠습니다.
원본 이미지의 넘파이는 numpy_img라는 변수로 받아놓겠습니다.
# PIL -> numpy
numpy_img = np.array(img)
numpy_img.shape # h, w, channel
이미지 출력 함수
이제 numpy/tensor 상태의 배열을 이미지로 출력하는 함수를 만들겠습니다.
def imgshow(array, tensor=True): # 배열과 tensor인지 여부를 받는다
if tensor: # tensor 배열이면
numpy_array = array.numpy() # 넘파이로 바꾼다
img = numpy_array.transpose(1,2,0) # tensor 형태(channel,h,w) -> numpy 형태(h,w,channel)
else: # numpy 배열이면
img = array # 그대로
plt.axis('off') # 눈금 제거
plt.imshow(img) # 이미지 시각화
자주 쓰이는 속성
기본 변환
- ToTensor()
- Normalize(mean, std)
크기 변환
- Resize((h,w))
- CenterCrop(size)
- RandomCrop(size)
데이터 증강
- RandomHorizontalFlip(p), RandomVerticalFlip(p)
- RandomRotation(degrees)
- ColorJitter(brightness, contrast, saturation, hue)
- RandomResizedCrop(size, scale, ratio)
transforms.Compose([변환할 전처리 리스트])로 묶어줍니다.
<기본 변환>
1. ToTensor()
이미지(PIL 이미지/Numpy 배열)를 텐서 형태로 변환
0~255 사이의 픽셀 값을 0~1 사이로 정규화(픽셀값 정규화)
tensor_transform = transforms.Compose([
transforms.ToTensor()
])
원본 이미지 넘파이와 ToTensor()를 적용한 텐서와의 차이를 보겠습니다.
shape 확인
원본 | ToTensor() | |
type | numpy | tensor |
shape | (h,w,channel) | (channel,h,w) |
픽셀 값 | 0~255 | 0~1 |
2. Normalize(mean, std)
각 채널(RGB / 흑백)의 값들을 정규화
각 채널의 값이 평균 0, 표준편차 1을 가지도록 하여 학습을 더 안정적이고 빠르게 만들어준다.
각 채널에서 mean을 빼고 std로 나눈다
- 빨간색(R)은 평균이 0.485, 표준편차가 0.229
- 초록색(G)은 평균이 0.456, 표준편차가 0.224
- 파란색(B)은 평균이 0.406, 표준편차가 0.225
- 흑백은 평균이 0, 표준편차가 1
민지 이미지는 컬러이기 때문에, RGB 값에 맞춰서 정규화해주겠습니다.
normalize_transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
ToTensor()만 한 것과 Normalize()를 한 것을 비교해보겠습니다.
확실히 보기 위해 이미지로 출력해보겠습니다
원본과 Normalize()의 차이를 살펴보겠습니다.
<크기 변환>
1. Resize((h,w))
h,w 크기로 변경
Resize(size)처럼 하나만 쓰면 h, w 중 짧은 길이에 size를 맞춘다.
resize_transform = transforms.Compose([
transforms.ToTensor(),
transforms.Resize((224,224))
])
ToTensor()만 했을 때와 Resize()를 적용했을 때의 shape을 보니 크기가 변환되었습니다.
이미지로 출력해보겠습니다.
이번에는 h,w 다 입력하지 않고 하나만 넣어보겠습니다.
resize_transform1 = transforms.Compose([
transforms.ToTensor(),
transforms.Resize(224)
])
h와 w 중 길이가 더 짧은 것에 224를 맞춥니다.
2. CenterCrop(size)
이미지 중앙 부분을 size x size 로 자른다.
CenterCrop((h,w))로도 적용 가능
centercrop_transform = transforms.Compose([
transforms.ToTensor(),
transforms.CenterCrop(224)
])
Resize((224,224))와 shape은 똑같은데요. 이미지를 출력해보겠습니다.
3. RandomCrop(size)
랜덤 위치에서 size x size 로 자른다
RandomCrop((h,w))로도 적용 가능
randomcrop_transform = transforms.Compose([
transforms.ToTensor(),
transforms.RandomCrop(224)
])
랜덤으로 바뀝니다
<데이터 증강>
모델이 더 다양한 형태의 데이터를 학습할 수 있도록 원본 데이터를 변형하여 다양한 버전을 만들어 주는 과정
1. RandomHorizontalFlip(p) / RandomVerticalFlip(p)
랜덤으로 이미지를 뒤집는다
p는 뒤집힐 확률(p = 0.5가 기본)
RandomHorizontalFlip(p)
랜덤으로 이미지를 좌우로 뒤집는다
randomhorizontalflip_transform = transforms.Compose([
transforms.ToTensor(),
transforms.RandomHorizontalFlip()
])
뒤집힐 확률이 0.5로 반반이라 한 번은 뒤집히고, 한 번은 안 뒤집혔습니다.
RandomVerticalFlip(p)
랜덤으로 이미지를 위아래로 뒤집는다
randomverticalflip_transform = transforms.Compose([
transforms.ToTensor(),
transforms.RandomVerticalFlip()
])
2. RandomRotation(degrees)
-degrees ~ +degrees 범위 내에서 랜덤하게 이미지 회전
randomrotation_transform = transforms.Compose([
transforms.ToTensor(),
transforms.RandomRotation(30) # -30~30
])
-30~30도 사이 랜덤 값으로 각도가 회전됩니다
조금씩 각도가 다르게 회전됐습니다.
3. ColorJitter(brightness, contrast, saturation, hue)
이미지의 밝기, 대비, 채도, 색조를 랜덤하게 변경
- brightness: 밝기를 변경. brightness=0.5는 밝기를 ±50% 범위 내에서 랜덤하게 변경
- contrast: 대비를 변경. contrast=0.5는 대비를 ±50% 범위 내에서 랜덤하게 변경
- saturation: 채도를 변경. saturation=0.5는 채도를 ±50% 범위 내에서 랜덤하게 변경
- hue: 색조를 변경. hue=0.5는 색조를 ±50% 범위 내에서 랜덤하게 변경
변경 범위는 0이 기본
# 모두 변경
colorjitter_transform = transforms.Compose([
transforms.ToTensor(),
transforms.ColorJitter(brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5)
])
# 밝기만
bright_transform = transforms.Compose([
transforms.ToTensor(),
transforms.ColorJitter(brightness=0.5)
])
# 대비만
contrast_transform = transforms.Compose([
transforms.ToTensor(),
transforms.ColorJitter(contrast=0.5)
])
# 채도만
saturation_transform = transforms.Compose([
transforms.ToTensor(),
transforms.ColorJitter(saturation=0.5)
])
# 색조만
hue_transform = transforms.Compose([
transforms.ToTensor(),
transforms.ColorJitter(hue=0.5)
])
brightness
-50~50 범위 내에서 밝기 변경
contrast
-50~50 범위 내에서 대비 변경
saturation
-50~50 범위 내에서 채도 변경
hue
-50~50 범위 내에서 색조 변경
brightness, contrast, saturation, hue
모두 변경
4. RandomResizedCrop(size, scale, ratio)
이미지를 임의로 자르고, 지정된 크기로 리사이즈
scale과 ratio로 자를 영역의 크기와 비율을 조절 -> 자른 후에는 지정된 size로 리사이즈
scale=(0.3, 0.8)은 전체 이미지에서 30%에서 80% 사이에서 자르고,
ratio=(3/4, 4/3)은 자를 영역의 가로 세로 비율이 3:4에서 4:3 사이로 랜덤하게 선택
Resize와의 차이
Resize: 자르기 X
RandomResizedCrop: 자르기 있음
randomresizedcrop_transform = transforms.Compose([
transforms.ToTensor(),
transforms.RandomResizedCrop(224, scale=(0.3,0.8), ratio=(3/4,4/3))
])
shape은 Resize((224, 224))와 동일하니 이미지를 출력해보겠습니다.
먼저 crop하고 resize를 하기 때문에 어떻게 crop하냐에 따라 결과가 달라집니다.
+ train과 test에 적용될 transform은 다를 수 있다.
train에서는 다양한 데이터를 위해 데이터 증강을 적용하지만,
test에서는 추론을 하기 때문에 증강하지 않기 때문(단순한 크기 변환같은 기본적인 전처리만 적용)
'Pytorch' 카테고리의 다른 글
[파이토치] CNN Lenet5 구현 (1) | 2025.01.04 |
---|---|
[파이토치] MNIST로 이미지 데이터 처리 (1) | 2024.12.31 |
[파이토치] CNN (0) | 2024.12.26 |
[파이토치] iris 데이터를 위한 신경망 만들어보기 (0) | 2024.12.24 |
[파이토치] 모델 학습하기 (0) | 2024.12.23 |