Dataset은 데이터셋을 관리하고 DataLoader는 Model에 데이터를 제공하는 것을 관리한다.subscriptable타입: indexing을 이용해 원소 조회가 가능한 타입
Dataset은 slicing과 fancy indexing은 지원하지 않는다. 즉 한번에 여러개 데이터조회를 지원하지 않는다.
torch.utils.data.Dataset의 하위클래스로 구현되있다.torchvision 모듈을 통해 다양한 오픈소스 이미지 데이터셋을 loading할 수 있는 Dataset 클래스를 제공한다.
############# # MNIST Dataset loading ############ data_dir_path = r"/Users/sechankim/Library/CloudStorage/OneDrive-개인/classes/playdata/DA-35/08_deeplearning_pytorch/deeplearning/datasets" mnist_trainset = datasets.MNIST( root=data_dir_path, train=True, download=True, ) mnist_testset = datasets.MNIST( root=data_dir_path, train=False, # test set download=True ) print(type(mnist_trainset)) print(isinstance(mnist_trainset, Dataset))<class 'torchvision.datasets.mnist.MNIST'>
Truemnist_trainsetDataset MNIST
Number of datapoints: 60000
Root location: /Users/sechankim/Library/CloudStorage/OneDrive-개인/classes/playdata/DA-35/08_deeplearning_pytorch/deeplearning/datasets
Split: Trainmnist_testsetDataset MNIST
Number of datapoints: 10000
Root location: /Users/sechankim/Library/CloudStorage/OneDrive-개인/classes/playdata/DA-35/08_deeplearning_pytorch/deeplearning/datasets
Split: Test# Dataset의 데이터개수 확인 print("trainset 데이터수:", len(mnist_trainset)) # Data indexing zero_idx = mnist_trainset[0] # (X, y) print(type(zero_idx)) print(type(zero_idx[0])) # input: X print(type(zero_idx[1])) # output: ytrainset 데이터수: 60000
<class 'tuple'>
<class 'PIL.Image.Image'>
<class 'int'>zero_idx[0]
zero_idx[1]5
print(mnist_trainset[1][1]) mnist_trainset[1][0]0
mnist_trainset2 = datasets.MNIST( root=data_dir_path, train=True, download=True, transform=transforms.ToTensor(), ### 읽은 data를 어떻게 변환할 지 정의한 함수/객체 ) # ToTensor() -> ndarray, PIL.Image를 torch.Tensor 로 변환. # shape을 변환 (channel, height, width) # pixcel값을 0 ~ 1 변환.(scaling)type(mnist_trainset2[0])tuple
x, y = mnist_trainset2[0] y5
type(x)torch.Tensor
x.shapetorch.Size([1, 28, 28])
```python ###### y의 class 확인 mnist_trainset.class_to_idx # dict: key-class name, value - class (index){'0 - zero': 0,
'1 - one': 1,
'2 - two': 2,
'3 - three': 3,
'4 - four': 4,
'5 - five': 5,
'6 - six': 6,
'7 - seven': 7,
'8 - eight': 8,
'9 - nine': 9}mnist_trainset.classes # list: index-class, value-class name['0 - zero',
'1 - one',
'2 - two',
'3 - three',
'4 - four',
'5 - five',
'6 - six',
'7 - seven',
'8 - eight',
'9 - nine']
from torchvision import datasets cifa10_trainset = datasets.CIFAR10( root=r"/Users/sechankim/Library/CloudStorage/OneDrive-개인/classes/playdata/DA-35/08_deeplearning_pytorch/deeplearning/datasets", # Dataset이 있는 경로. train=True, # Trainset: True, Testset: False download=True, # root에 data가 없으면 다운로드 받을지 여부. ) cifa10_testset = datasets.CIFAR10( root=r"/Users/sechankim/Library/CloudStorage/OneDrive-개인/classes/playdata/DA-35/08_deeplearning_pytorch/deeplearning/datasets", # Dataset이 있는 경로. train=False, # Trainset: True, Testset: False download=True, # root에 data가 없으면 다운로드 받을지 여부. ) ##### STL10 dataset root_path = r"/Users/sechankim/Library/CloudStorage/OneDrive-개인/classes/playdata/DA-35/08_deeplearning_pytorch/deeplearning/datasets" stl_trainset = datasets.STL10( root=root_path, # Dataset 저장 경로 split="train", download=True ) stl_testset = datasets.STL10( root=root_path, split="test", download=True )print(stl_trainset) print(stl_testset)Dataset STL10
Number of datapoints: 5000
Root location: /Users/sechankim/Library/CloudStorage/OneDrive-개인/classes/playdata/DA-35/08_deeplearning_pytorch/deeplearning/datasets
Split: train
Dataset STL10
Number of datapoints: 8000
Root location: /Users/sechankim/Library/CloudStorage/OneDrive-개인/classes/playdata/DA-35/08_deeplearning_pytorch/deeplearning/datasets
Split: test# data 개수를 int 조회 print(len(stl_trainset)) print(len(stl_testset))5000
8000# Data1개 조회 stl_trainset[0] # tuple(이미지, label) : 분류 - 사진-주제(대상)(<PIL.Image.Image image mode=RGB size=96x96>, 1)
# class - classname 조회 stl_trainset.classes # list - index: class index, value: class name['airplane',
'bird',
'car',
'cat',
'deer',
'dog',
'horse',
'monkey',
'ship',
'truck']idx = 100 class_name = stl_trainset.classes result = stl_trainset[idx] # tuple(0: X, 1: y) print(result[1], class_name[result[1]]) result[0]2 car
# matplotlib 으로 출력 import matplotlib.pyplot as plt import numpy as np plt.figure(figsize=(20, 5)) for idx in range(10): plt.subplot(2, 5, idx+1) img, label = stl_trainset[idx] #PIL.Image -> ndarray 변환. np.array(Image), ndarray->Image: Image.fromarray(ndarray) img_array = np.array(img) plt.imshow(img_array) plt.title(f"{label} - {class_name[label]}") plt.tight_layout() plt.show()
stl_trainset[0](<PIL.Image.Image image mode=RGB size=96x96>, 1)
from torchvision import transforms, datasets # transforms: 영상데이터(이미지)를 변환 처리하는 (전처리) # 다양한 함수들,호출가능한 객체들을 제공하는 모듈 # Dataset에 설정 -> 원본이미지를 전처리한 결과를 반환 하도록 정의가능. stl_trainset2 = datasets.STL10(root=root_path, split="train", download=True, transform=transforms.ToTensor() # ToTensor: 호출가능한 클래스 )x_0, _ = stl_trainset[0] print(type(x_0)) arr = np.array(x_0) print(arr.shape, arr.dtype, arr.min(), arr.max())<class 'PIL.Image.Image'>
(96, 96, 3) uint8 0 255x, y = stl_trainset2[0] # tuple(input, output) print(type(x), x.dtype, x.min(), x.max()) print(x.shape)<class 'torch.Tensor'> torch.float32 tensor(0.) tensor(1.)
torch.Size([3, 96, 96])
torchvision.transforms.Compose 클래스를 이용해서 묶어준다.transforms.Normalize(mean=0.5, std=0.5):
import torch x, _ = stl_trainset2[0] x2 = transforms.Normalize(mean=100, std=20)(x) print(x2.min(), x2.max())tensor(-5.) tensor(-4.9500)
(0-100)/20, (1 - 100)/20(-5.0, -4.95)
# 0 ~ 1(ToTensor) -> 평균: 0.5, 표준편차: 0.5 (Normalize) (0-0.5/0.5), (1-0.5)/0.5(-1.0, 1.0)
transform = transforms.Compose([ transforms.ToTensor(), # 이미지를 텐서로 변환하고, 각 픽셀 값을 [0, 1] 범위로 정규화 transforms.Normalize(mean=0.5, std=0.5) # 모든 채널에 동일한 값을 적용: 상수., 채널별로 다른 값 적용: 리스트. # 픽셀 값을 정규화하여 [0, 1] 범위에서 [-1, 1] 범위로 변환 ]) # Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) stl_trainset3 = datasets.STL10(root_path, split="train", download=True, transform=transform # ToTensor -> Normalize : 순서대로 묶어서 전달.=> Compose() ) stl_testset3 = datasets.STL10(root_path, split="test", download=True, transform=transform # ToTensor -> Normalize : 순서대로 묶어서 전달.=> Compose() )len(stl_trainset3), len(stl_testset3)(5000, 8000)
x2, _ = stl_trainset3[5] # 0 ->index -> 몇번째 data인지의 index print(_) print(type(x2), x2.dtype, x2.type()) print(x2.shape, x2.min(), x2.max())9
<class 'torch.Tensor'> torch.float32 torch.FloatTensor
torch.Size([3, 96, 96]) tensor(-1.) tensor(1.)
import torch from torch.utils.data import DataLoader device = "cuda" if torch.cuda.is_available() else "cpu" # Train set을 모델에 제공하기 위한 DataLoader stl_trainloader = DataLoader( dataset=stl_trainset3, # Dataset 지정. batch_size=32, # Batch size: 한번에 모델에 제공할 데이터 개수. shuffle=True, # 한 epoch 끝나고 데이터셋을 한번 썩을지 여부.(default: False) drop_last=True, # 마지막 batch 크기가 batch_size보다 적으면 모델에 제공할지 여부(default:False) # generator=torch.Generator(device="mps") # mac )# Test set을 모델에 제공하기 위한 DataLoader ### validation, test data loader: shuffle, drop_last는 설정하지 않는다. (False) stl_testloader = DataLoader( dataset=stl_testset3, batch_size=32 )# DataLoader: iterable 타입 -> for in 문에서 반복 조회가 가능. # -> 한번 반복시 batch_size 개수만큼 데이터를 제공. print("step 수 확인") # 몇번만에 데이터를 다 제공하는지. (epoch당 step 수) # 전체 데이터개수 // batch_size #(drop_last=True) # ceil(전체 데이터개수 / batch_size) #(drop_last=False) print(len(stl_trainloader), len(stl_testloader))step 수 확인
156 250##### 1 step용 batch 데이터들 조회 ## iterable을 타입은 iterator를 먼저 조회. iterator = iter(iterable) ## iterator를 이용해서 값을 조회 value = next(iterator) ##### iterable: 제공할 데이터들을 가지고 있는 객체 ##### iterator: iterable의 값을 제공해주는 객체. # DataLoader -> Iterable type. Subscriptable type은 아니다. (indexing 못한다.) # stl_trainloader[0] iterator = iter(stl_trainloader) # print(type(iterator)) v = next(iterator) # 값을 하나씩 하나씩 제공.print(type(v), len(v)) # [X batch들, y batch들]<class 'list'> 2
v[0].shape # [32: batchsize, 3:channel, 96:height, 96:width]torch.Size([32, 3, 96, 96])
for idx, (X_train, y_train) in enumerate(stl_trainloader, start=1): print(f"{idx}. {X_train.shape} - {y_train.shape}")
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
...- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
- torch.Size([32, 3, 96, 96]) - torch.Size([32])
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
torch.utils.data.Dataset 클래스를 상속한 클래스를 정의한다.__init__(self, ...) __len__(self)__getitem__(self, index)# subscriptable type 클래스 구현. -> indexing 가능한 클래스. ### __getitem__(self, index) 특수메소드를 추가. ==== indexing 연산자와 연결. ### __len__(self) 특수메소드 ====== len() 함수와 연결. class MySub: def __init__(self): # 제공할 데이터들을 초기화. self.one = "호랑이" self.two = "사자" self.three = "기린" def __getitem__(self, index): ## index(key)를 받아서 그 index(key)의 값을 반환. # print("0000000000000") if index == 0: return self.one elif index == 1: return self.two elif index == 2: return self.three else: raise IndexError(f"{index} 번째 value가 없습니다.") def __len__(self): # len(객체) 시 호출되는 메소드. -> 제공할 데이터의 개수를 반환. return 3ms = MySub() # ms.__getitem__(2) ms[2]'기린'
len(ms)3
from torch.utils.data import Dataset isinstance(stl_testset, Dataset)True
import os import re from glob import glob import tarfile from PIL import Image import torch from torch.utils.data import Dataset, DataLoader from torchvision import transforms img_tarfile_path = r"c:\Classes\images.tar.gz" pet_data_path = r"c:\Classes\deeplearning\datasets" # 압축 풀 경로 pet_image_path = os.path.join(pet_data_path, "images") # 압축 풀린 이미지가 있는 경로# 2. 압축 풀기 with tarfile.open(img_tarfile_path) as tar: # 압축풀 파일과 연결. tar.extractall(pet_data_path) # 압축풀 경로를 넣어서 풀기. (경로지정안하면 현재경로에 품.)# 3. 이미지 파일 경로 목록 file_list = glob(pet_image_path+"\\*.jpg") file_list[:5]['c:\Classes\deeplearning\datasets\images\Abyssinian_1.jpg',
'c:\Classes\deeplearning\datasets\images\Abyssinian_10.jpg',
'c:\Classes\deeplearning\datasets\images\Abyssinian_100.jpg',
'c:\Classes\deeplearning\datasets\images\Abyssinian_101.jpg',
'c:\Classes\deeplearning\datasets\images\Abyssinian_102.jpg']f = file_list[0] # 한 파일의 경로: 디렉토리경로 + 파일명. # os.path 모듈 -> 파일/디렉토리 경로를 다루는 함수들을 제공. print("파일경로에서 디렉토리경로만 조회:", os.path.dirname(f)) print("파일경로에서 파일명만 조회:", os.path.basename(f)) print("파일경로에서 확장자를 분리:", os.path.splitext(f)) # (확장자뺀경로, 확장자)파일경로에서 디렉토리경로만 조회: c:\Classes\deeplearning\datasets\images
파일경로에서 파일명만 조회: Abyssinian_1.jpg
파일경로에서 확장자를 분리: ('c:\Classes\deeplearning\datasets\images\Abyssinian_1', '.jpg')os.path.splitext("my_file.txt")('my_file', '.txt')
len(file_list)7390
# 4. JPG Color 가 아닌 이미지파일을 삭제. ## 파일삭제: os.remove(삭제할파일경로) ## 이미지 모드 -> PIL.Image.mode -> 어떤 종류의 이미지인지의 속성값.: str: L-grayscale, 'RGB': RGB 컬러 #### PIL.Image로 개별 이미지를 연결후 RGB가 아닌 이미지는 제거. remove_cnt = 0 # 파일 몇개 삭제했는지 저장. for file in file_list: # 이미지파일과 연결 with Image.open(file) as img: image_mode = img.mode # "RGB", "L": grayscale, if image_mode != "RGB": # RGB 가 아닌 파일은 제거 os.remove(file) remove_cnt += 1 print(f"삭제파일명: {os.path.basename(file)}, mode: {image_mode}")삭제파일명: Abyssinian_34.jpg, mode: P
삭제파일명: Abyssinian_5.jpg, mode: RGBA
삭제파일명: Egyptian_Mau_129.jpg, mode: L
삭제파일명: Egyptian_Mau_139.jpg, mode: P
삭제파일명: Egyptian_Mau_14.jpg, mode: RGBA
삭제파일명: Egyptian_Mau_145.jpg, mode: P
삭제파일명: Egyptian_Mau_167.jpg, mode: P
삭제파일명: Egyptian_Mau_177.jpg, mode: P
삭제파일명: Egyptian_Mau_186.jpg, mode: RGBA
삭제파일명: Egyptian_Mau_191.jpg, mode: P
삭제파일명: staffordshire_bull_terrier_2.jpg, mode: L
삭제파일명: staffordshire_bull_terrier_22.jpg, mode: Lremove_cnt12
### 이미지 파일목록을 갱신 file_list = glob(pet_image_path+"\\*.jpg") print(len(file_list))7378
# 아래작업을 모든 파일에 적용. fname = os.path.basename(file_list[0]) fname = os.path.splitext(fname)[0] label = fname.split("_")[0] label2 = "고양이" if label[0].isupper() else "개" # label2 print(label, label2)Abyssinian 고양이
import re class_name_set = set() # 빈 set. 여기에 파일명들을 저장. -> 중복 제거를 위해서 set사용. for file in file_list: file_name = os.path.basename(file) file_name = os.path.splitext(file_name)[0] label = re.sub('_\d+', "", file_name) #_, \d (정수1개), +(1개이상) class_name_set.add(label)len(class_name_set)37
index_to_class = list(class_name_set) index_to_class.sort() class_to_index = {value:index for index, value in enumerate(index_to_class)} class_to_index{'Abyssinian': 0,
'Bengal': 1,
'Birman': 2,
'Bombay': 3,
'British_Shorthair': 4,
'Egyptian_Mau': 5,
'Maine_Coon': 6,
'Persian': 7,
'Ragdoll': 8,
'Russian_Blue': 9,
'Siamese': 10,
'Sphynx': 11,
'american_bulldog': 12,
'american_pit_bull_terrier': 13,
'basset_hound': 14,
'beagle': 15,
'boxer': 16,
'chihuahua': 17,
'english_cocker_spaniel': 18,
'english_setter': 19,
'german_shorthaired': 20,
'great_pyrenees': 21,
'havanese': 22,
'japanese_chin': 23,
'keeshond': 24,
...
'scottish_terrier': 32,
'shiba_inu': 33,
'staffordshire_bull_terrier': 34,
'wheaten_terrier': 35,
'yorkshire_terrier': 36}
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...# 모델 추정한 값 pred = 5 pred_label = index_to_class[pred] pred_label'Egyptian_Mau'
######### 6. train/valid/test set 분리 - file 목록 index로 분리. # train: 70%, valid: 20%, test: 10% ==> class 별로 처리. # 200장 기준 70%: 140장-train, 40장-validation, 나머지-test train_idx = int(200 * 0.7) # trainset 기준 index val_idx = train_idx + int(200*0.2) print(f"Train set: file_list[: {train_idx}]") print(f"Valid set: file_list[{train_idx}:{val_idx}]") print(f"Test set: file_list[{val_idx}:]")Train set: file_list[: 140]
Valid set: file_list[140:180]
Test set: file_list[180:]#### train/validation/test set 에 넣을 파일경로 나누기. train_file_list = [] valid_file_list = [] test_file_list = [] cnt = 0 # class 별 파일 index previous_class = None # 이전 처리했던 파일이 어느 class(품종)인지 저장할 변수 file_list.sort() # file_list 정렬 - 같은 품종의 파일끼리 뭉쳐 있도록 정렬. for path in file_list: #Abyssinian_83, beagle_90 file_name = os.path.splitext(os.path.basename(path))[0] # 디렉토리 빼고 확장자 빼고 파일명만 추출 class_name = re.sub(r"_\d+", "", file_name) # 품종만 추출, Abyssinian, beagle if previous_class == class_name: # 이전 처리 class와 현재 처리 클래스가 같은 거야? cnt += 1 # 동일한 클래스 처리: cnt 를 1 증가. else: cnt = 1 # 새로운 클래스에 대한 처리. cnt = 1 (첫번째 파일.) if cnt <= train_idx: # 0 ~ 140-1 train_file_list.append(path) elif cnt > train_idx and cnt <=val_idx: # 140 ~ 180 valid_file_list.append(path) else: # 180 ~ 200 test_file_list.append(path) previous_class = class_name # 현재 처리한 class이름을 previous_class 이름으로 설정.len(train_file_list), len(valid_file_list), len(test_file_list)(5180, 1480, 718)
test_file_list[:50] test_file_list[-50:]['c:\Classes\deeplearning\datasets\images\shiba_inu_99.jpg',
'c:\Classes\deeplearning\datasets\images\staffordshire_bull_terrier_91.jpg',
'c:\Classes\deeplearning\datasets\images\staffordshire_bull_terrier_92.jpg',
'c:\Classes\deeplearning\datasets\images\staffordshire_bull_terrier_93.jpg',
'c:\Classes\deeplearning\datasets\images\staffordshire_bull_terrier_94.jpg',
'c:\Classes\deeplearning\datasets\images\staffordshire_bull_terrier_95.jpg',
'c:\Classes\deeplearning\datasets\images\staffordshire_bull_terrier_96.jpg',
'c:\Classes\deeplearning\datasets\images\staffordshire_bull_terrier_97.jpg',
'c:\Classes\deeplearning\datasets\images\staffordshire_bull_terrier_98.jpg',
'c:\Classes\deeplearning\datasets\images\staffordshire_bull_terrier_99.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_81.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_82.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_83.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_84.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_85.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_86.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_87.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_88.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_89.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_9.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_90.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_91.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_92.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_93.jpg',
'c:\Classes\deeplearning\datasets\images\wheaten_terrier_94.jpg',
...
'c:\Classes\deeplearning\datasets\images\yorkshire_terrier_95.jpg',
'c:\Classes\deeplearning\datasets\images\yorkshire_terrier_96.jpg',
'c:\Classes\deeplearning\datasets\images\yorkshire_terrier_97.jpg',
'c:\Classes\deeplearning\datasets\images\yorkshire_terrier_98.jpg',
'c:\Classes\deeplearning\datasets\images\yorkshire_terrier_99.jpg']
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...# 7. Dataset 구현 import cv2 class OxfordPetDataset(Dataset): def __init__(self, path_list, class_to_index, index_to_class, transform=None): # 제공할 데이터셋 관련 정보들을 초기화. # path_list: 제공할 파일들의 경로 목록 # transform: 제공 전 처리 작업을 할 함수/호출가능 객체 self.path_list = path_list self.transform = transform self.class_to_index = class_to_index self.index_to_class = index_to_class def __len__(self): ## 제공할 총 데이터 개수 반환 return len(self.path_list) def __getitem__(self, index): ## index 데이터의 x(input), y(output) 를 반환 ### x(input): 이미지(PIL.Image, ndarray, torch.Tensor), y(output): class index path = self.path_list[index] # x - input img = cv2.cvtColor(cv2.imread(path), cv2.COLOR_BGR2RGB) # resize : 이미지 size를 통일. (DataLoader 에 주입되는 개별 데이터는 shape이 같아야함.) img = cv2.resize(img, (224, 224)) if self.transform is not None: img = self.transform(img) # y - output class_name = re.sub(r"_\d+\.jpg", "", os.path.basename(path)) class_index = self.class_to_index[class_name] return img, class_indextrainset = OxfordPetDataset( train_file_list, # trainset 에 사용할 이미지파일경로 목록 class_to_index, # classname을 index로 변환 index_to_class, # index를 class name으로 변환 ) validset = OxfordPetDataset(valid_file_list, class_to_index, index_to_class) testset = OxfordPetDataset(test_file_list, class_to_index, index_to_class)train_loader = DataLoader(trainset, batch_size=32, shuffle=True) val_loader = DataLoader(validset, batch_size=32) test_loder = DataLoader(testset, batch_size=32)for X, y in train_loader: print(X.shape, y.shape) breaktorch.Size([32, 224, 224, 3]) torch.Size([32])
plt.imshow(X[0]) print(y[0], trainset.index_to_class[y[0].item()])tensor(26) miniature_pinscher
import os import re from glob import glob import tarfile from PIL import Image import cv2 from torch.utils.data import Datasetclass OxfordPetDataset2(Dataset):def __init__(self, root, split, transform=None): self.root = root # 파일들이 저장된 root 디렉토리. self.split = split # train / valid / test self.transform = transform # trainset, validation set 구분 기준 index self.train_idx = int(200 * 0.7) # trainset 기준 index self.val_idx = self.train_idx + int(200*0.2) # RGB 이미지 빼고 제거 + file_list 생성 self.file_list = self._remove_not_rgb() self.file_list.sort() ####################### sort 필수(linux, mac은 정렬이 안되있다.) # index_to_class, class_to_index 생성 self.index_to_class, self.class_to_index = self._create_class_index() # 파일 경로 목록 생성 self.split_file_list = self._create_split_file_list(split)def _create_split_file_list(self, split): """ split(train/valid/test) 별 파일 경로 list 반환 Parameter split:str train/valid/test return list: 파일 경로 List """ split_file_list = [] cnt = 0 previous_class = None for path in self.file_list: file_name = os.path.splitext(os.path.basename(path))[0] # 디렉토리 빼고 확장자 빼고 파일명만 추출 class_name = re.sub(r"_\d+", "", file_name) if previous_class == class_name: cnt += 1 else: cnt = 1 if split=="train": if cnt <= self.train_idx: split_file_list.append(path) elif split=="valid": if cnt > self.train_idx and cnt <= self.val_idx: split_file_list.append(path) elif split=="test": if cnt > self.val_idx: split_file_list.append(path) else: raise Exception(f"split은 train/valid/test 중 하나를 입력하세요.") previous_class = class_name return split_file_listdef _create_class_index(self): """ index: class index, class: class_name 파일명 label을 이용해 index_to_class 리스트, class_to_index dictionary 생성 return tuple: index_to_class, class_to_index """ class_name_set = set() # 빈 set. 여기에 파일명들을 저장. -> 중복 제거를 위해서 set사용. for file in self.file_list: file_name = os.path.basename(file) # Beagle_32.jpg label = re.sub('_\d+.jpg', "", file_name) # Beagle class_name_set.add(label) index_to_class = list(class_name_set) index_to_class.sort() # [A, B, C, ..] # 리스트 index: class index, value: class Name class_to_index = {value:index for index, value in enumerate(index_to_class)} return index_to_class, class_to_indexdef _remove_not_rgb(self): """ 데이터파일에서 RGB 를 제외한 이미지 제거 """ file_list = glob(os.path.join(self.root, "*.jpg")) for file in file_list: # 이미지파일과 연결 with Image.open(file) as img: image_mode = img.mode # "RGB", "L": grayscale, if image_mode != "RGB": # RGB 가 아닌 파일은 제거 os.remove(file) return glob(os.path.join(self.root, "*.jpg")) # 파일목록 리턴def __len__(self): return len(self.split_file_list)def __getitem__(self, index): path = self.split_file_list[index] # x - input img = cv2.cvtColor(cv2.imread(path), cv2.COLOR_BGR2RGB) img = cv2.resize(img, (224, 224)) # Transform에서 처리. if self.transform is not None: img = self.transform(img) # y - output class_name = re.sub(r"_\d+\.jpg", "", os.path.basename(path)) class_index = self.class_to_index[class_name] return img, class_indexdef __str__(self): return f"OxfordPet Dataset\nSplit: {self.split}\n총데이터수: {self.__len__()}"root_path = r"C:\Classes\deeplearning\datasets\images" train_set = OxfordPetDataset2(root_path, "train") valid_set = OxfordPetDataset2(root_path, "valid") test_set = OxfordPetDataset2(root_path, "test")print(len(train_set), len(valid_set), len(test_set))5180 1480 718
print(train_set)OxfordPet Dataset
Split: train
총데이터수: 5180x, y = train_set[0] print(y) train_set.index_to_class[y]0
'Abyssinian'import matplotlib.pyplot as plt plt.imshow(x);
# DataLoader from torch.utils.data import DataLoader train_loader = DataLoader(train_set, batch_size=64, shuffle=True)X, Y = next(iter(train_loader)) X.shape, Y.shape(torch.Size([64, 224, 224, 3]), torch.Size([64]))
import numpy as np import pandas as pd import torch from torch.utils.data import Dataset, DataLoaderdf = pd.read_csv( 'data/iris.data', header=None, names=["petal_length", "petal_width", "sepal_length", "sepal_width", "label"]) df.shape(150, 5)
index_to_class = list(df['label'].unique()) class_to_index = {name:idx for idx, name in enumerate(index_to_class)} print(index_to_class) print(class_to_index)['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
{'Iris-setosa': 0, 'Iris-versicolor': 1, 'Iris-virginica': 2}# X, y 를 분리 X = df.drop(columns="label").values y_tmp = df['label'] y = y_tmp.apply(lambda x: class_to_index[x]).values # 각 라벨을 인덱스로 변환하여 NumPy 배열로 y에 저장class IrisDataset(Dataset): def __init__(self, X, y): self.X = torch.Tensor(X) self.y = torch.Tensor(y) def __len__(self): return len(self.y) def __getitem__(self, index): ## getitem -> index의 x 와 y를 반환. return self.X[index], self.y[index]# Train/Test set 분리 from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)train_set = IrisDataset(X_train,y_train) test_set = IrisDataset(X_test, y_test) len(train_set), len(test_set)(120, 30)
x, y = train_set[0] x.shape, y.shape print(x, y)tensor([6.4000, 3.1000, 5.5000, 1.8000]) tensor(2.)
## TensorDataset ### 원본 Data set이 메모리에 torch.Tensor객체나 ndarray 객체로 있는 경우 사용. ### dataset = TensorDataset(X, y) # X, y: torch.Tensor from torch.utils.data import TensorDataset trainset = TensorDataset( torch.Tensor(X_train), # X/input torch.Tensor(y_train) # y/output ) testset = TensorDataset( torch.Tensor(X_test), torch.Tensor(y_test) )from torch.utils.data import TensorDataset trainset = TensorDataset( torch.Tensor(X_train), # X/input torch.Tensor(y_train) # y/output ) testset = TensorDataset( torch.Tensor(X_test), torch.Tensor(y_test) )trainset[0](tensor([6.4000, 3.1000, 5.5000, 1.8000]), tensor(2.))

import os from zipfile import ZipFilef import gdown def down_extract(): os.makedirs(r'C:\Classes\deeplearning\datasets', exist_ok=True) url = 'https://drive.google.com/uc?id=1YIxDL0XJhhAMdScdRUfDgccAqyCw5-ZV' fname = r'C:\Classes\deeplearning\datasets\cats_and_dogs_small.zip' gdown.download(url, fname, quiet=False) #zipfile모듈: Zip 압축파일을 다루는 모듈(압축하기, 풀기) from zipfile import ZipFile # 압축풀기: ZipFile(압축파일경로).extractall(풀경로) # 디렉토리 없으면 생성해 준다. with ZipFile(fname) as zipFile: zipFile.extractall(os.path.join(r'C:\Classes\deeplearning\datasets','cats_and_dogs_small')) down_extract()import os from torchvision.datasets import ImageFolder from torchvision import transforms # ImageFolder(이미지들 root path 를 지정.) root_path = r'C:\Classes\deeplearning\datasets\cats_and_dogs_small' train_set = ImageFolder(root=os.path.join(root_path, "train")) test_set = ImageFolder(root=os.path.join(root_path, "test")) valid_set = ImageFolder(root=os.path.join(root_path, "validation"), transform=transforms.ToTensor())type(train_set), isinstance(train_set, Dataset)(torchvision.datasets.folder.ImageFolder, True)
```python print(len(train_set), len(valid_set), len(test_set))2000 1000 1000
## class 이름, class index 조회 train_set.classes['cats', 'dogs']
train_set.class_to_idx{'cats': 0, 'dogs': 1}
x, y = train_set[0] type(x), type(y)(PIL.Image.Image, int)
print(y, train_set.classes[y]) x0 cats
x, y = valid_set[0] type(x), x.min(), x.max(), x.shape(torch.Tensor, tensor(0.), tensor(1.), torch.Size([3, 149, 150]))
- (Parameter)머신러닝 모델 파라미터
- 성능에 영향을 주는 값으로 최적화의야 하는 대상내는 값을 찾아야 한다.
- 하이퍼파라미터(Hyper Parameter)
- 사람이 직접 설정해야하는 파라미터 값으로 주로 어떻게 모델을 학습시킬지에 대한 모델설정 값이다.
- 딥러닝에서는 학습률, Epoch수, batch size, optimizer, loss 함수 등 다양한 하이퍼파라미터가 있다.
- 파라미터(Parameter)
- 모델의 함수를 데이터에 맞추기 위한 값으로 학습을 통해 찾는 변수.
- 딥러닝 모델에서는 weight와 bias 가 파라미터다.
import torch from torch.utils.data import Subset, TensorDataset #, Dataset, DataLoader data = torch.tensor([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]) y = torch.tensor([[1], [2], [3], [4], [5]]) print(data.shape, y.shape)torch.Size([5, 2]) torch.Size([5, 1])
dataset = TensorDataset(data, y) print(len(dataset))5
# Dataset 5 -> 3개 를 가지고 Subset을 생성. ### Subset(대상 dataset, [subset에 넣을 값들의 index]) subset1 = Subset(dataset, [0, 2, 3]) # dataset의 0, 2, 3 index의 값들로 subset을 생성 subset2 = Subset(dataset, [1, 4]) print(len(subset1), len(subset2))3 2
for x, y in subset1: print(x, y)tensor([1, 2]) tensor([1])
tensor([5, 6]) tensor([3])
tensor([7, 8]) tensor([4])for x, y in subset2: print(x, y)isinstance(subset1, Dataset)True
##### Subset(Tensor, [index들]) # Tensor의 index로 지정한 일부 값들을 이용해 Subset생성 # # Tensor의 원소: 2개의 값으로 구성되야함. 첫번째 값: X, 두번째 값: y print(data.shape) subset3 = Subset(data, [0, 1, 2]) for x, y in subset3: print(x, y, sep=", ")torch.Size([5, 2])
tensor(1), tensor(2)
tensor(3), tensor(4)
tensor(5), tensor(6)datatensor([[ 1, 2],
[ 3, 4],
[ 5, 6],
[ 7, 8],
[ 9, 10]])# shuffle -> data를 섞지 않고 index를 섞어서 조회. idx = torch.randperm(100) # 0 ~ 99 값들을 섞은뒤 반환. idx[:10], idx[10:](tensor([60, 37, 71, 95, 51, 63, 52, 34, 69, 46]),
tensor([ 5, 81, 0, 49, 36, 21, 23, 19, 44, 14, 87, 7, 54, 76, 38, 17, 45, 66,
77, 82, 96, 12, 88, 53, 93, 56, 50, 78, 74, 41, 6, 68, 13, 30, 8, 48,
98, 55, 73, 22, 94, 40, 42, 72, 4, 16, 35, 59, 83, 1, 2, 67, 79, 91,
33, 39, 90, 27, 9, 47, 32, 75, 26, 15, 84, 29, 61, 18, 10, 92, 25, 31,
62, 11, 89, 64, 97, 28, 58, 86, 3, 70, 20, 99, 80, 24, 43, 65, 57, 85]))from torchvision.datasets import MNIST mnist_set = MNIST(r"C:\Classes\deeplearning\datasets", train=True) len(mnist_set)60000
indexes = torch.randperm(60000) # train_indexes = list(range(50000)) train_indexes = indexes[:50000] # valid_indexes = list(range(50000, 60000)) valid_indexes = indexes[50000:] trainset = Subset(mnist_set, train_indexes) validset = Subset(mnist_set, valid_indexes)len(trainset), len(validset)(50000, 10000)
data = torch.tensor([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]) y = torch.tensor([[1], [2], [3], [4], [5]]) dataset = TensorDataset(data, y)from torch.utils.data import random_split # 5 -> 3, 2 sub1, sub2 = random_split( dataset, # 나눌 대상 Dataset [3, 2] # 몇개씩으로 나눌지 subset의 크기. ) len(sub1), len(sub2), type(sub1)(3, 2, torch.utils.data.dataset.Subset)
for x,y in sub1: print(x, y)tensor([1, 2]) tensor([1])
tensor([ 9, 10]) tensor([5])
tensor([7, 8]) tensor([4])sub10, sub11, sub12 = random_split(dataset, [2, 2, 1]) # 몇개의 subset이든 만들 수있다. len(sub10), len(sub11), len(sub12)(2, 2, 1)
# mnist_set: 60000 => 40000, 20000 mnist_sub1, mnist_sub2 = random_split(mnist_set, [40000, 20000]) len(mnist_sub1), len(mnist_sub2)(40000, 20000)
train_loader = DataLoader(mnist_sub1, 256, shuffle=True, drop_last=True) valid_loader = DataLoader(mnist_sub2, 256) len(train_loader), len(valid_loader)(156, 79)