Klasyczne modele ze scikit-learn miały granicę. Gdy dane są ogromne i skomplikowane - miliony zdjęć zwierząt - potrzebujesz sieci neuronowych, a do nich narzędzia cięższego kalibru: PyTorch. Zanim zaczniesz, poznaj dwa filary, na których stoi cała biblioteka - tensor i autograd. Reszta to szczegóły.
1pip install torch torchvisionTensor to podstawowe pudełko na dane w PyTorch - jak tablica NumPy, ale z dwiema supermocami, które poznasz za chwilę: umie liczyć na karcie graficznej i umie zapamiętać, jak powstał. Na razie potraktuj go jak znajomą tablicę liczb.
1import torch
2
3tensor = torch.tensor([1, 2, 3, 4, 5])
4matrix = torch.tensor([[1, 2], [3, 4], [5, 6]])
5
6zeros = torch.zeros(3, 4) # macierz 3x4 zer
7random = torch.rand(3, 3) # losowe wartości 0-1
8
9print(tensor.shape) # rozmiar
10print(tensor.device) # cpu czy cuda (GPU)Tworzysz tensory prawie tak jak w NumPy, ale zwróć uwagę na ostatni atrybut -
device. To on zdradza pierwszą supermoc: tensor wie, czy leży w pamięci procesora (cpu), czy karty graficznej (cuda). Do tego zaraz wrócimy.Operacje na tensorach też przypominają NumPy - dodajesz, mnożysz, liczysz statystyki:
1a = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
2b = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32)
3
4c = a + b # dodawanie element po elemencie
5c = a @ b # mnożenie macierzowe (operator @)
6
7print(a.mean()) # średnia
8print(a.argmax()) # indeks największej wartości
9
10reshaped = torch.arange(12).reshape(3, 4) # zmiana kształtuWażne rozróżnienie:
+ i * działają element po elemencie, a @ to prawdziwe mnożenie macierzy - w sieciach neuronowych używasz głównie tego drugiego. reshape zmienia kształt bez ruszania danych, co przyda się przy przepychaniu obrazów przez sieć.Oto dlaczego deep learning w ogóle jest możliwy w rozsądnym czasie. Sieci wykonują miliardy mnożeń macierzy, a karta graficzna (GPU) robi je setki razy szybciej niż procesor. Tensor przenosisz na GPU jedną metodą.
1device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
2
3tensor = torch.tensor([1, 2, 3]).to(device) # przenieś na GPU (jeśli jest)
4tensor_gpu = torch.rand(3, 3, device='cuda') # albo od razu tam stwórzWzorzec
device = 'cuda' if ... else 'cpu' to standard: kod działa na GPU, gdy jest dostępne, a na zwykłym procesorze, gdy go nie ma - bez przepisywania. Zapamiętaj jedną zasadę: żeby tensory mogły się dodać czy pomnożyć, muszą leżeć na tym samym urządzeniu. Mieszanie CPU i GPU to najczęstszy błąd początkującego.Teraz druga supermoc - ta, dzięki której model w ogóle potrafi się uczyć. Uczenie to poprawianie parametrów w stronę mniejszego błędu, a do tego trzeba pochodnych (gradientów). Autograd liczy je za Ciebie: gdy oznaczysz tensor
requires_grad=True, PyTorch zapamiętuje każdą operację i potrafi cofnąć rachunek.1x = torch.tensor([2.0], requires_grad=True)
2y = x ** 2 + 3 * x + 1
3
4y.backward() # policz pochodną wstecz
5print(x.grad) # dy/dx = 2x + 3 = 7To jest sedno PyTorcha. Ty zapisałeś tylko wzór "w przód" (
y = x**2 + 3x + 1), a backward() sam wyliczył pochodną - 7, dokładnie jak z kartki. Nigdzie nie różniczkowałeś ręcznie. W prawdziwym modelu ten sam mechanizm liczy, jak zmienić każdą wagę, by błąd zmalał:1w = torch.tensor([1.0], requires_grad=True)
2b = torch.tensor([0.0], requires_grad=True)
3
4y_pred = w * torch.tensor([2.0]) + b # przewidywanie modelu
5loss = (y_pred - torch.tensor([5.0])) ** 2 # jak bardzo się mylimy
6
7loss.backward()
8print(w.grad, b.grad) # w którą stronę poprawić w i bPrześledź logikę: liczysz przewidywanie, liczysz błąd (
loss), wołasz backward() - a w.grad i b.grad mówią, w którą stronę pchnąć każdy parametr, żeby błąd zmalał. Cała nauka sieci to powtarzanie tego kroku tysiące razy. To dlatego autograd jest filarem, nie ciekawostką.Zostało praktyczne pytanie: jak karmić model danymi? Sieci uczą się na małych porcjach (batystach), więc PyTorch daje dwa klocki -
Dataset opakowuje Twoje dane, a DataLoader porcjuje je i miesza.1from torch.utils.data import Dataset, DataLoader
2
3class SafariDataset(Dataset):
4 def __init__(self, X, y):
5 self.X = torch.tensor(X, dtype=torch.float32)
6 self.y = torch.tensor(y, dtype=torch.long)
7
8 def __len__(self):
9 return len(self.X)
10
11 def __getitem__(self, idx):
12 return self.X[idx], self.y[idx]
13
14dataset = SafariDataset(X_train, y_train)
15dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
16
17for batch_X, batch_y in dataloader:
18 print(batch_X.shape, batch_y.shape)
19 breakTwój
Dataset musi umieć dwie rzeczy: powiedzieć, ile ma przykładów (__len__) i zwrócić jeden po numerze (__getitem__). DataLoader bierze to i podaje w paczkach po 32 (batch_size), za każdą epoką tasując kolejność (shuffle=True) - dzięki czemu model nie uczy się przypadkowej kolejności danych.Pamiętaj z tej lekcji dwa filary: tensor to dane, które liczą na GPU, a autograd sam wylicza pochodne, dzięki którym model się uczy. Gdy to rozumiesz, budowa samej sieci jest już tylko układaniem warstw.