๋ฐ์ํ
โ ๏ธ ๋ณธ ๋ด์ฉ์ PyTorch Korea์ ๊ณต์ ๋ฌธ์์ ๊ธฐ๋ฐํ์ฌ ๊ณต๋ถํ ๋ด์ฉ์ ์ ์๊ฒ์ด๋ ์ํด๋ฐ๋๋๋ค!
Dataset & DataLoader
PyTorch์ Dataset๊ณผ DataLoader๋ ๋ฐ์ดํฐ์ ์ ํจ์จ์ ์ผ๋ก ๋ก๋ํ๊ณ ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋๋ค.
๋๊ท๋ชจ ๋ฐ์ดํฐ์ ์ ๋ฐฐ์น ๋จ์๋ก ๋๋์ด ๋ชจ๋ธ์ ๊ณต๊ธํ ์ ์๋๋ก ๋์์ค๋๋ค.
- ๋ฐ์ดํฐ ์ํ์ ์ฒ๋ฆฌํ๋ ์ฝ๋๋ ์ง์ ๋ถ(messy)ํ๊ณ ์ ์ง๋ณด์๊ฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค.
- ๋ ๋์ ๊ฐ๋ ์ฑ(readability)๊ณผ ๋ชจ๋์ฑ(modularity)์ ์ํด ๋ฐ์ดํฐ์ ์ฝ๋๋ฅผ ๋ชจ๋ธ ํ์ต ์ฝ๋๋ก๋ถํฐ ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์ด์์ ์ ๋๋ค.
- PyTorch๋ torch.utils.data.DataLoader ์ torch.utils.data.Dataset ์ ๋ ๊ฐ์ง ๋ฐ์ดํฐ ๊ธฐ๋ณธ ์์๋ฅผ ์ ๊ณตํ์ฌ ๋ฏธ๋ฆฌ ์ค๋นํด๋(pre-loaded) ๋ฐ์ดํฐ์ ๋ฟ๋ง ์๋๋ผ ๊ฐ์ง๊ณ ์๋ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ํฉ๋๋ค.
- Dataset์ ์ํ๊ณผ ์ ๋ต(label)์ ์ ์ฅํ๊ณ , DataLoader ๋ Dataset ์ ์ํ์ ์ฝ๊ฒ ์ ๊ทผํ ์ ์๋๋ก ์ํ ๊ฐ๋ฅํ ๊ฐ์ฒด(iterable)๋ก ๊ฐ์๋๋ค.
- PyTorch์ ๋๋ฉ์ธ ํนํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ (FashionMNIST์ ๊ฐ์) ๋ฏธ๋ฆฌ ์ค๋นํด๋(pre-loaded) ๋ค์ํ ๋ฐ์ดํฐ์ ์ ์ ๊ณตํฉ๋๋ค.
- ๋ฐ์ดํฐ์ ์ torch.utils.data.Dataset ์ ํ์ ํด๋์ค๋ก ๊ฐ๋ณ ๋ฐ์ดํฐ๋ฅผ ํน์ ํ๋ ํจ์๊ฐ ๊ตฌํ๋์ด ์์ต๋๋ค.
- ์ด๋ฌํ ๋ฐ์ดํฐ์ ์ ๋ชจ๋ธ์ ๋ง๋ค์ด๋ณด๊ณ (prototype) ์ฑ๋ฅ์ ์ธก์ (benchmark)ํ๋๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์๋๋ ์ฌ๋ฌ ๋ฐ์ดํฐ์ ์์์ ๋๋ค. ๋งํฌ๋ฅผ ๋ฌ์๋์์ผ๋ ํ์ธํด๋ณด์ธ์!
Image Dataset
Text Dataset
Audio Dataset
Dataset ๋ถ๋ฌ์ค๊ธฐ
TorchVision์์ CIFAR-10 ๋ฐ์ดํฐ์ ์ ๋ถ๋ฌ์ค๋ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๊ณต์๋ฌธ์์๋ MNIST๋ก ๋์ด ์์ง๋ง, ๋ฐ๋ผํ๋๊ฑฐ ๊ฐ์์ ํ๋ฒ ๋ค๋ฅธ ๋ฐ์ดํฐ์ ์ผ๋ก ์ ์๋ํด ๋ณด๊ฒ ์ต๋๋ค!
- CIFAR-10 ๋ฐ์ดํฐ์ ์ 60,000๊ฐ์ 32x32 ์ปฌ๋ฌ ์ด๋ฏธ์ง๋ก ๊ตฌ์ฑ๋์ด ์์ผ๋ฉฐ, ๊ฐ ์ด๋ฏธ์ง๋ 10๊ฐ์ ํด๋์ค ์ค ํ๋์ ์ํฉ๋๋ค.
- 50,000๊ฐ์ ํ์ต ์ด๋ฏธ์ง์ 10,000๊ฐ์ ํ ์คํธ ์ด๋ฏธ์ง๋ก ๋๋์ด์ ธ ์์ต๋๋ค.
CIFAR-10 Dataset Parameter (๋งค๊ฐ๋ณ์)
- root ๋ ํ์ต/ํ ์คํธ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋๋ ๊ฒฝ๋ก์ ๋๋ค.
- train ์ ํ์ต์ฉ ๋๋ ํ ์คํธ์ฉ ๋ฐ์ดํฐ์ ์ฌ๋ถ๋ฅผ ์ง์ ํฉ๋๋ค.
- download=True ๋ root ์ ๋ฐ์ดํฐ๊ฐ ์๋ ๊ฒฝ์ฐ ์ธํฐ๋ท์์ ๋ค์ด๋ก๋ํฉ๋๋ค.
- transform ๊ณผ target_transform ์ ํน์ง(feature)๊ณผ ์ ๋ต(label) ๋ณํ(transform)์ ์ง์ ํฉ๋๋ค.
import torch
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
# ๋ฐ์ดํฐ ๋ณํ ์ ์ (์ ๊ทํ ํฌํจ)
transform = transforms.Compose([
transforms.ToTensor(), # ์ด๋ฏธ์ง๋ฅผ ํ
์๋ก ๋ณํ
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) # ์ด๋ฏธ์ง ์ ๊ทํ
])
# CIFAR-10 ํ์ต ๋ฐ์ดํฐ์
๋ถ๋ฌ์ค๊ธฐ
training_data = datasets.CIFAR10(
root="data",
train=True,
download=True,
transform=transform
)
# CIFAR-10 ํ
์คํธ ๋ฐ์ดํฐ์
๋ถ๋ฌ์ค๊ธฐ
test_data = datasets.CIFAR10(
root="data",
train=False,
download=True,
transform=transform
)
Dataset์ ์ํํ๊ณ ์๊ฐํ ํ๊ธฐ
Dataset์ ๋ฆฌ์คํธ(list)์ฒ๋ผ ์ง์ ์ ๊ทผ(index)ํ ์ ์์ต๋๋ค.
training_data[index]. matplotlib ์ ์ฌ์ฉํ์ฌ ํ์ต ๋ฐ์ดํฐ์ ์ผ๋ถ๋ฅผ ์๊ฐํํด๋ณด๊ฒ ์ต๋๋ค.
# CIFAR-10 ํด๋์ค ๋ ์ด๋ธ ๋งต
labels_map = {
0: "Airplane",
1: "Automobile",
2: "Bird",
3: "Cat",
4: "Deer",
5: "Dog",
6: "Frog",
7: "Horse",
8: "Ship",
9: "Truck"
}
# ์๊ฐํ
figure = plt.figure(figsize=(8, 8))
cols, rows = 3, 3
for i in range(1, cols * rows + 1):
sample_idx = torch.randint(len(training_data), size=(1,)).item()
img, label = training_data[sample_idx]
figure.add_subplot(rows, cols, i)
plt.title(labels_map[label])
plt.axis("off")
img = img / 2 + 0.5 # ์ ๊ทํ ํด์
plt.imshow(img.permute(1, 2, 0)) # (C, H, W) -> (H, W, C)๋ก ๋ณ๊ฒฝ
plt.show()
ํ์ผ์์ ์ฌ์ฉ์ ์ ์ ๋ฐ์ดํฐ์ ๋ง๋ค๊ธฐ
- ์ฌ์ฉ์ ์ ์ Dataset ํด๋์ค๋ ๋ฐ๋์ 3๊ฐ ํจ์๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค.
- __init__, __len__, and __getitem__. ์๋ ๊ตฌํ์ ์ดํด๋ณด๋ฉด CIFAR-10 ์ด๋ฏธ์ง๋ค์ img_dir ๋๋ ํ ๋ฆฌ์ ์ ์ฅ๋๊ณ , ์ ๋ต์ annotations_file csv ํ์ผ์ ๋ณ๋๋ก ์ ์ฅ๋ฉ๋๋ค.
- ํ๋ฒ ๊ฐ ํจ์๋ค์์ ์ผ์ด๋๋ ์ผ๋ค์ ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
import os
import pandas as pd
from torchvision.io import read_image
from torch.utils.data import Dataset
class CustomImageDataset(Dataset):
def __init__(self, annotations_file, img_dir, transform=None, target_transform=None):
self.img_labels = pd.read_csv(annotations_file)
self.img_dir = img_dir
self.transform = transform
self.target_transform = target_transform
def __len__(self):
return len(self.img_labels)
def __getitem__(self, idx):
img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
image = read_image(img_path)
label = self.img_labels.iloc[idx, 1]
if self.transform:
image = self.transform(image)
if self.target_transform:
label = self.target_transform(label)
sample = {"image": image, "label": label}
return sample
__init__
- __init__ ํจ์๋ Dataset ๊ฐ์ฒด๊ฐ ์์ฑ(instantiate)๋ ๋ ํ ๋ฒ๋ง ์คํ๋ฉ๋๋ค.
- ์ฌ๊ธฐ์๋ ์ด๋ฏธ์ง์ ์ฃผ์ ํ์ผ(annotation_file)์ด ํฌํจ๋ ๋๋ ํ ๋ฆฌ์ (๋ค์ ์ฅ์์ ์์ธํ ์ดํด๋ณผ) ๋๊ฐ์ง ๋ณํ(transform)์ ์ด๊ธฐํํฉ๋๋ค. labels.csv ํ์ผ์ ์์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
tshirt1.jpg, 0
tshirt2.jpg, 0
......
ankleboot999.jpg, 9
def __init__(self, annotations_file, img_dir, transform=None, target_transform=None):
self.img_labels = pd.read_csv(annotations_file)
self.img_dir = img_dir
self.transform = transform
self.target_transform = target_transform
Parameter
- annotations_file: ์ด๋ฏธ์ง ํ์ผ ์ด๋ฆ๊ณผ ๋ ์ด๋ธ์ด ํฌํจ๋ CSV ํ์ผ์ ๊ฒฝ๋ก.
- img_dir: ์ด๋ฏธ์ง ํ์ผ์ด ์ ์ฅ๋ ๋๋ ํ ๋ฆฌ ๊ฒฝ๋ก.
- transform: ์ด๋ฏธ์ง์ ์ ์ฉํ ๋ณํ(์ ์ฒ๋ฆฌ).
- target_transform: ๋ ์ด๋ธ์ ์ ์ฉํ ๋ณํ(์ ์ฒ๋ฆฌ).
- self.img_labels: CSV ํ์ผ์ ์ฝ์ด์ ๋ฐ์ดํฐํ๋ ์์ผ๋ก ์ ์ฅ.
- self.img_dir: ์ด๋ฏธ์ง ๋๋ ํ ๋ฆฌ ๊ฒฝ๋ก ์ ์ฅ.
- self.transform: ์ด๋ฏธ์ง ๋ณํ ์ ์ฅ.
- self.target_transform: ๋ ์ด๋ธ ๋ณํ ์ ์ฅ.
__len__
- __len__ ํจ์๋ ๋ฐ์ดํฐ์ ์ ์ํ ๊ฐ์๋ฅผ ๋ฐํํฉ๋๋ค.
def __len__(self):
return len(self.img_labels)
- len(self.img_labels): CSV ํ์ผ์ ์ ์ฅ๋ ๋ ์ด๋ธ์ ๊ฐ์๋ฅผ ๋ฐํํฉ๋๋ค.
__getitem__
- __getitem__ ํจ์๋ ์ฃผ์ด์ง ์ธ๋ฑ์ค idx ์ ํด๋นํ๋ ์ํ์ ๋ฐ์ดํฐ์ ์์ ๋ถ๋ฌ์ค๊ณ ๋ฐํํฉ๋๋ค.
- ์ธ๋ฑ์ค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก, ๋์คํฌ์์ ์ด๋ฏธ์ง์ ์์น๋ฅผ ์๋ณํ๊ณ , read_image ๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง๋ฅผ ํ ์๋ก ๋ณํํ๊ณ ,self.img_labels ์ csv ๋ฐ์ดํฐ๋ก๋ถํฐ ํด๋นํ๋ ์ ๋ต(label)์ ๊ฐ์ ธ์ค๊ณ , (ํด๋นํ๋ ๊ฒฝ์ฐ) ๋ณํ(transform) ํจ์๋ค์ ํธ์ถํ ๋ค, ํ ์ ์ด๋ฏธ์ง์ ๋ผ๋ฒจ์ Python ์ฌ์ (dict)ํ์ผ๋ก ๋ฐํํฉ๋๋ค.
def __getitem__(self, idx):
# ์ด๋ฏธ์ง ํ์ผ์ ๊ฒฝ๋ก๋ฅผ ์์ฑํฉ๋๋ค. self.img_labels์ ์ฒซ ๋ฒ์งธ ์ด์๋ ํ์ผ ์ด๋ฆ์ด ์์ต๋๋ค.
img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
# ์ด๋ฏธ์ง๋ฅผ ์ฝ์ด์ ํ
์๋ก ๋ณํํฉ๋๋ค.
image = read_image(img_path)
# ๋ ์ด๋ธ์ ๊ฐ์ ธ์ต๋๋ค. self.img_labels์ ๋ ๋ฒ์งธ ์ด์๋ ๋ ์ด๋ธ์ด ์์ต๋๋ค.
label = self.img_labels.iloc[idx, 1]
# transform์ด ์ ์๋์ด ์๋ค๋ฉด, ์ด๋ฏธ์ง๋ฅผ ๋ณํํฉ๋๋ค.
if self.transform:
image = self.transform(image)
# target_transform์ด ์ ์๋์ด ์๋ค๋ฉด, ๋ ์ด๋ธ์ ๋ณํํฉ๋๋ค.
if self.target_transform:
label = self.target_transform(label)
# ์ด๋ฏธ์ง์ ๋ ์ด๋ธ์ ํฌํจํ๋ ์ํ์ ์ฌ์ (dict) ํ์์ผ๋ก ๋ฐํํฉ๋๋ค.
sample = {"image": image, "label": label}
return sample
Parameter
- img_path: ์ฃผ์ด์ง ์ธ๋ฑ์ค์ ํด๋นํ๋ ์ด๋ฏธ์ง ํ์ผ์ ๊ฒฝ๋ก๋ฅผ ์์ฑํฉ๋๋ค.
- read_image(img_path): ์ด๋ฏธ์ง ํ์ผ์ ์ฝ์ด์ ํ ์๋ก ๋ณํํฉ๋๋ค.
- label: ์ฃผ์ด์ง ์ธ๋ฑ์ค์ ํด๋นํ๋ ๋ ์ด๋ธ์ ๊ฐ์ ธ์ต๋๋ค.
- if self.transform: ์ด๋ฏธ์ง ๋ณํ์ด ์ง์ ๋ ๊ฒฝ์ฐ, ๋ณํ์ ์ ์ฉํฉ๋๋ค.
- if self.target_transform: ๋ ์ด๋ธ ๋ณํ์ด ์ง์ ๋ ๊ฒฝ์ฐ, ๋ณํ์ ์ ์ฉํฉ๋๋ค.
- sample = {"image": image, "label": label}: ์ด๋ฏธ์ง์ ๋ ์ด๋ธ์ ํฌํจํ๋ ์ํ์ ์ฌ์ (dict) ํ์์ผ๋ก ๋ฐํํฉ๋๋ค.
DataLoader๋ก ํ์ต์ฉ ๋ฐ์ดํฐ ์ค๋นํ๊ธฐ
- Dataset ํด๋์ค๋ ๋ฐ์ดํฐ์ ์ ํน์ง(feature)์ ๊ฐ์ ธ์ค๊ณ , ๊ฐ ์ํ์ ์ ๋ต(label)์ ์ง์ ํ๋ ์ผ์ ํฉ๋๋ค.
- ๋ชจ๋ธ์ ํ์ตํ ๋๋ ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋๋ฐฐ์น(minibatch)๋ก ์ ๋ฌํ๊ณ , ๋งค ์ํญ(epoch)๋ง๋ค ๋ฐ์ดํฐ๋ฅผ ๋ค์ ์์ด์ ๊ณผ์ ํฉ(overfit)์ ๋ฐฉ์งํ๋ฉฐ, ๋ฉํฐํ๋ก์ธ์ฑ์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ๊ฒ์ ์๋๋ฅผ ๋์ด๋ ค ํฉ๋๋ค.
- DataLoader๋ ์ด๋ฌํ ๋ณต์กํ ๊ณผ์ ๋ค์ ์ถ์ํํ ๊ฐ๋จํ API๋ฅผ ์ ๊ณตํ์ฌ, ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ๋ถ๋ฌ์ฌ ์ ์๋ ์ํ ๊ฐ๋ฅํ ๊ฐ์ฒด(iterable)๋ฅผ ๋ง๋ญ๋๋ค.
DataLoader ์์ฑ
๋จผ์ torch.utils.data ๋ชจ๋์์ DataLoader ํด๋์ค๋ฅผ ๊ฐ์ ธ์ ํ์ต์ฉ ๋ฐ์ดํฐ์ ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ์ํ DataLoader๋ฅผ ์์ฑํฉ๋๋ค.
from torch.utils.data import DataLoader
# ํ์ต ๋ฐ์ดํฐ์ฉ DataLoader
train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)
# ํ
์คํธ ๋ฐ์ดํฐ์ฉ DataLoader
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)
Parameter
- batch_size=64: ํ ๋ฒ์ 64๊ฐ์ ์ํ์ ๊ฐ์ ธ์ต๋๋ค.
- shuffle=True: ์ํญ๋ง๋ค ๋ฐ์ดํฐ๋ฅผ ์์ด์ค๋๋ค.
DataLoader๋ฅผ ํตํด ๋ฐ์ดํฐ ์ํํ๊ธฐ
- DataLoader ์ ๋ฐ์ดํฐ์ ์ ๋ถ๋ฌ์จ ๋ค์๋ ํ์์ ๋ฐ๋ผ ๋ฐ์ดํฐ์ ์ ์ํ(iterate)ํ ์ ์์ต๋๋ค.
- ์๋์ ๊ฐ ์ํ(iteration)๋ (๊ฐ๊ฐ batch_size=64 ์ ํน์ง(feature)๊ณผ ์ ๋ต(label)์ ํฌํจํ๋train_features ์ train_labels ์ ๋ฌถ์(batch)์ ๋ฐํํฉ๋๋ค.
- ๋ํ shuffle=True ๋ก ์ง์ ํ์ผ๋ฏ๋ก, ๋ชจ๋ ๋ฐฐ์น๋ฅผ ์ํํ ๋ค ๋ฐ์ดํฐ๊ฐ ์์ ๋๋ค.
# DataLoader์์ ์ฒซ ๋ฒ์งธ ๋ฐฐ์น ๊ฐ์ ธ์ค๊ธฐ
train_features, train_labels = next(iter(train_dataloader))
# ๋ฐฐ์น์ ํฌ๊ธฐ ์ถ๋ ฅ
print(f"Feature batch shape: {train_features.size()}")
print(f"Labels batch shape: {train_labels.size()}")
# ์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง์ ๋ผ๋ฒจ์ ๊ฐ์ ธ์์ ์๊ฐํ
img = train_features[0].permute(1, 2, 0) / 2 + 0.5 # ์ ๊ทํ ํด์ ๋ฐ (C, H, W) -> (H, W, C) ๋ณ๊ฒฝ
label = train_labels[0]
plt.imshow(img.numpy())
plt.title(f"Label: {label}")
plt.axis("off")
plt.show()
print(f"Label: {label}")
Feature batch shape: torch.Size([64, 3, 32, 32])
Labels batch shape: torch.Size([64])
Parameter
- next(iter(train_dataloader)): DataLoader์์ ์ฒซ ๋ฒ์งธ ๋ฐฐ์น๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
- train_features.size(): ํน์ง(feature) ๋ฐฐ์น์ ํฌ๊ธฐ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
- train_labels.size(): ์ ๋ต(label) ๋ฐฐ์น์ ํฌ๊ธฐ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
- train_features[0]: ์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
- permute(1, 2, 0): ์ด๋ฏธ์ง์ ์ฐจ์์ (H, W, C) ํ์์ผ๋ก ๋ณ๊ฒฝํ์ฌ ์๊ฐํํฉ๋๋ค.
- img.numpy(): ์ด๋ฏธ์ง๋ฅผ NumPy ๋ฐฐ์ด๋ก ๋ณํํ์ฌ plt.imshow๋ก ์๊ฐํํฉ๋๋ค.
- plt.title(f"Label: {label}"): ์ด๋ฏธ์ง์ ๋ผ๋ฒจ์ ์ ๋ชฉ์ผ๋ก ํ์ํฉ๋๋ค.
- plt.axis("off"): ์ถ์ ๋๋๋ค.
๋ ์์ธํ ๋ด์ฉ์ ๋ณด๊ณ ์ถ์ผ์๋ฉด ์๋ ๋งํฌ์ ๋ค์ด๊ฐ์ ๊ณต์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์ธ์!
- torch.utils.data ๊ด๋ จ PyTorch ๊ณต์ ๋ฌธ์
๋ฐ์ํ
'๐ฅ PyTorch' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[PyTorch] ๋ชจ๋ธ ๋งค๊ฐ๋ณ์ ์ต์ ํ(Optimization) ํ๊ธฐ (0) | 2024.07.30 |
---|---|
[PyTorch] Torch.Autograd๋ฅผ ์ด์ฉํ ์๋ ๋ฏธ๋ถ (0) | 2024.07.30 |
[PyTorch] Neural Network Model (์ ๊ฒฝ๋ง ๋ชจ๋ธ) ๊ตฌ์ฑํ๊ธฐ (0) | 2024.07.26 |
[PyTorch] Transform (๋ณํ) (0) | 2024.07.26 |
[PyTorch] PyTorch Intro & Tensor (ํ ์) (0) | 2024.07.26 |