subscriptable타입: indexing을 이용해 원소 조회가 가능한 타입)
torch.utils.data.Dataset
의 하위클래스로 구현되있다.torchvision 모듈을 통해 다양한 오픈소스 이미지 데이터셋을 loading할 수 있는 Dataset 클래스를 제공한다.
import torch
import torch.nn as nn
from torchvision import datasets #torchvision(파이토치 영상처리 모율).datasets(이미지 데이터셋 제공 class
import numpy as np
# 데이터들을 저장할 메모리
DATASET_ROOT_PATH = "datasets" # 상대 경로, 절대경로 상관 없ㅇㅁ
# MNIST Dataset 생성
## Train dataset
mnist_trainset = datasets.MNIST(root = DATASET_ROOT_PATH, # 원본 데이터 파일을 저장 위치
train =False, #)True: Train set, False:Test set
download = True, # True : 원본파일이 없으면 다운로드,, False: 다운받지 않는다
# Transform = 이미지변환처리함수 # 이미지를 제공하기 전체 전처리 필요
)
# Test dataset -> train = Flase
mnist_testset = datasets.MNIST(root=DATASET_ROOT_PATH, train=False, download = True)
### 타입 확인
print(type(mnist_trainset), type(mnist_testset))
print(isinstance(mnist_trainset, torch.utils.data.Dataset)) # Dataset의 하위 객체인지
# isinstance(객체, 클래스) -> 객체가 클래스 타입의 객체인지 확인, 보통 상속관계 확인 많이 씀
print(mnist_testset)
## 총 데이터의 개수만 확인
print(len(mnist_trainset), len(mnist_testset))
##6만과 만이라는 int값이 필요한 경우 사용
## Dataste은 subscriptable 타입(indexing이 기능)이다.
### => indexing으로 개별 데이터 조회가 가능 (Dataset은 slicing/facy indexing 은 안됨 = 한개씬만 조회 가능ㅇ)
data1 = mnist_trainset[0]
print(type(data1)) # tuple: (input, output)
print(type(data1[0]), type(data1[1]))
print(data1[1])
data1[0]
# data1의 image를 ndarray 변환
img1 = np.array(data1[0])
print(img1.shape, img1.min(), img1.max())
import matplotlib.pyplot as plt
plt.imshow(img1, cmap='gray')
plt.show()
# 이미지 여러개 확인 - 반복문 사용
for i in range(15):
plt.subplot(3, 5, i + 1)
img, label = mnist_trainset[i] #튜플 대입
img = np.array(img) #PLT.Image-> ndarray
plt.imshow(img, cmap = "gray")
plt.title(str(label)) # Label: int -> 문자열로 변환
plt.tight_layout()
plt.show()
mnist_trainset.class_to_idx
# 정답의 의미 -> class : 딕셔너리
pred_label = 3 # 모델이 추정한 값으로 가정
mnist_trainset.classes[pred_label]
# 위에서 읽은 mnist 이미지 정보
data = mnist_trainset[0][0] # 이미지만 가져온 것
img = np.array(data)
print("data의 type:", type(data))
print(img.shape)
print("pixcel 최소, 최대값 - ", img.min(), img.max())
print("dtype:", img.dtype)
from torchvision import transforms
# 영상데이처(이미지)를 전처리 하기 위한 transforms(변환합수)들을 제공하는 모듈
mnist_trainset2 = datasets.MNIST(root=DATASET_ROOT_PATH, train=True, download=True,
transform = transforms.ToTensor() # ToTensor 클래스 객체 -객체를 함수처럼 사용 가능
)
# transform 이 설정 안된 경우: 원본이미지 파일 -읽어서-> Dataset -반환 ->
# transform 이 설정된 경우: 원본이미지 파일 - 읽어서 -> Dataset - transform함수(이미지) - 반환->
data2, label = mnist_trainset2[0]
print(label)
print("data2의 타입: ", type(data2)) # PLI.Image -> Tensor # 데이터 타입이 tensor type으로 바뀜
print(data2.shape) # [channel, height, width]
print("pixcel의 최소, 최대:", data2.min(), data2.max()) # 0~1 사이로 정규화(normalize) ==> scaling
print("pixcel의 타입:",data2.dtype) # unit8 -> float32
###### ToTensor가 하는 일
torchvision.transforms.Compose
클래스를 이용한다.Compose를 이용해서 변환기를 묶어준다.
-> compose도 하나의 함수
torch.utils.data.Dataset
클래스를 상속한 클래스를 정의한다.__init__(self, ...)
__len__(self)
__getitem__(self, index)
# subscriptable 타입 클래스 구현 -> indexing 가능 객체
class MySub:
def __init__(self):
# 제공하 값들을 초기화
self.one = "사자"
self.two = "호랑이"
self.three = "하마"
def __len__(self):
# 제공할 데이터의 개수를 반환
return 3
def __getitem__(self, idx):
# idx의 값을 반환
if idx == 0:
return self.one
elif idx == 1:
return self.two
elif idx == 2:
return self.three
else:
raise IndexError(f"{idx}번째 값이 없습니댜")
m=MySub()
len(m) # m.__len__()
개,고양이 37가지 품종
품종별로 200장 정도씩 구성됨. (품종별로 이미지 개수는 다르다)
목표
import os
import re
from glob import glob
import tarfile
from PIL import Image
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
#압축 풀기 전 압축됬던 데이터가 압축해제 후 저장될 디렉토리 생성
DATA_ROOT_PATH = "datasets"
tarfile_path = os.path.join(DATA_ROOT_PATH, 'images.tar.gz')
PET_DATA_PATH = os.path.join(DATA_ROOT_PATH, 'oxfordpet') # 압축풀 디렉토리 경로
PET_IMAGE_PATH = os.path.join(PET_DATA_PATH, "imafes") # 압축 푼 이미지들 디렉토리 경로
os.makedirs(PET_DATA_PATH, exist_ok=True)
압축 해제
# 압축 풀기: zip: z|ipfile 모듈, tar: tarfile 모듈
with tarfile.open(tarfile_path, "r:gz") as tar: # 압축파일과 연결
tar.extractall(PET_DATA_PATH) # 압축풀 디렉토리 경로를 지정해서 압축푼다
각 파일의 경로 조회
# 모든 이미지 파일의 경로를 조회 => glob
file_list = glob(r"datasets/oxfordpet/**/*.jpg") #**는 해당 하는 항목 아래의 모든 파일이 해당
print(len(file_list))
file_list
파일 경로를 분리 (사용할 범위에 따라서)
## 참조 코드
f = file_list[0]
print(f)
print("파일결로에서 파일명과 확장자를 분리: ", os.path.splitext(f)) # 확장자와 나머지 경로를 분리
print("파일경로에서 파일명(확장자포함)을 분리: ", os.path.basename(f))
print("파일경로에서 디렉토리만 분리: ", os.path.dirname(f))
이미지들 중 RGB 모드의 이미지만 남기고 삭제한다
(이때는 open cv 보다 확장자가 더 편하다)
# 이미지들 중 RGB 모드의 이미지만 남기고 삭제 - 이때는 open cv 보다 확장자가 더 편하다
remove_cnt = 0 # 몇장 삭제했는지 저장
for idx, image_path in enumerate(file_list):
# print(idx, image_path)
# 이미지 읽기 -> PIL.Image,open()
with Image.open(image_path) as img:
image_mode = img.mode # str: 'L' - grayscale, 'RGB': rgb
# RGB가 아니면 삭제
if image_mode != "RGB":
os.remove(image_path)
remove_cnt += 1
print(f"{idx+1} 번째 파일 삭제. 파일 명: {os.path.basename(image_path)}, mode: {image_mode}")
총 몇개의 파일이 삭제되었는지 확인
remove_cnt
삭제결과를 적용해서 file_list르 새로 생성
file_list = glob(r"datasets/ozfordpet/**/*.jpg")
len(file_list)
위에서 만든 file_list
를 사용
file_list[0]
# 0-> american bulldog: index_to _class
# american bulldog -> 0: class_to_index
class_name_set = set() # 중복된것은 하나만 저장하기 위해 set을 생성 <- vkdlfaud: 품종_번호.jpg 품종만 set에 추가
for file in file_list:
## file_list에서 파일명 안의 품종을 추출한 뒤 class_name_set에 추가
filename = os.path.basename(file)
filename = os.path.splitext(filename)[0]
class_name = re.sub(r" _\d+", "", filename)
#print(filename, classname)
class_name_set.add(class_name)
#break
제대로된 결과 도출
index_to_class = list(class_name_set)
# index -> 클래스 이름
index_to_class.sort()
print(len(index_to_class))
index_to_class
## 클래스 이름 -> index : dic
class_to_index = {name: idx for idx, name in enumerate(index_to_class)}
class_to_index
(이 부분에서 코드 점검 필요)
import
import pandas as pd
import numpy as np
import torch
from torch.utils.data import Dataset,DataLoader,TensorDataset
헤더 없음
수정 필요 - 고치자
iris = pd.read_csv('data/iris.data', header=None,
names=["꽃받침길이", "꽃맏침너비", "꽃잎길이", "꽃잎너비", "정답"]) # 정답- 품종
iris.shape
iris['정답'].unique()
index_to_class = list(iris['정답'].unique())
# index_to_class
class_to_index = {class_name: idx for idx, classs_name in enumerate(index_to_class)}
class_to_index
torch에서는 제공 안하는 샐ㅗㅜ 맛집을 ㅁ크
!pip install scikit-learn
gdown library 새로 설치 - google drive의 공유파일 다운 가능하게 하는 library
(공유 파일의 ID 만 알고 있다면 다운로드 가능)
그러나 한번씩 upgrade를 해주어야 한다
!pip install gdown --upgrade
import os
from zipfile import ZipFile
import gdown
def down_extract():
os.makedirs('data', exist_ok=True)
url = 'https://drive.google.com/uc?id=1YIxDL0XJhhAMdScdRUfDgccAqyCw5-ZV' # 파일 링크 중간에 보면 id가 있다
fname = 'data/cats_and_dogs_small.zip' #파일을 어디에 넣을지 지정
gdown.download(url, fname, quiet=False) #quiet를 true 로 하면 다운로드 되는것이 안보인다
#zipfile모듈: Zip 압축파일을 다루는 모듈(압축하기, 풀기)
from zipfile import ZipFile #zip 파일 안에 zip파일 존재
# 압축풀기: ZipFile(압축파일경로).extractall(풀경로) # 디렉토리 없으면 생성해 준다.
with ZipFile(fname) as zipFile:
zipFile.extractall(os.path.join('datasets','cats_and_dogs_small'))
down_extract()
- (Parameter)머신러닝 모델 파라미터
- 성능에 영향을 주는 값으로 최적의야 하는 대상내는 값을 찾아야 한다.
- 하이퍼파라미터(Hyper Parameter)
- 사람이 직접 설정해야하는 파라미터 값
- 파라미터(Parameter)
- 데이터 학습을 통해 찾는 파라미터 값