PyTorch 뒤에 있는 Python 마법.

PyTorch는 최근 몇 년 동안 깊이 있는 학습 틀 중의 하나가 되었다.이런 유행은 사용하기 쉬운 API와 더 "pythonic"덕분일 수 있다.

Pytork는 Python의 많은 기본 기능을 이용하여 우리에게 일치하고 깨끗한 API를 제공하였다.본문에서 나는 이러한 원생 특성을 상세하게 설명할 것이다.이런 것들을 배우면 왜 PyTorch에서 어떤 방식으로 일을 하는지 이해하고 제공하는 것을 더욱 잘 활용할 수 있습니다.

분층 마술법


레이어

 are some of the basic constructs in PyTorch that we use to build our models. You import the layer and apply them to tensors.



```python
import torch
import torch.nn as nn

x = torch.rand(1, 784)
layer = nn.Linear(784, 10)
output = layer(x)
여기에서 우리는 장량x의 층을 호출할 수 있기 때문에 그것은 틀림없이 함수일 것이다. 그렇지?nn.Linear() 함수를 반환하시겠습니까?검사 유형을 통해 그것을 검증합시다.
>>> type(layer)
<class 'torch.nn.modules.linear.Linear'>
서프라이즈nn.Linear는 사실상 하나의 클래스이고 층은 이 클래스의 대상이다.

"What! How could we call it then? Aren't only functions supposed to be callable?"


아니오, 호출 가능한 대상을 만들 수도 있습니다.Python은 클래스에서 만든 대상을 호출할 수 있도록 마술 함수를 사용하는 기본 방법을 제공합니다.
하나의 종류가 하나의 숫자를 배로 늘리는 간단한 예를 봅시다.
class Double(object):
    def __call__(self, x):
        return 2*x
여기서 우리는 클래스에 마술 방법__call__을 추가하여 그 어떤 숫자도 배로 전달한다.이 클래스에서 대상을 만들고 호출할 수 있습니다.
>>> d = Double()
>>> d(2)
4
또는 상술한 코드는 단행에 조합할 수 있다.
>>> Double()(2)
4
파이썬의 모든 내용이 대상이기 때문이다.다음 숫자를 배로 늘리는 함수 예시를 참고하십시오.
def double(x):
    return 2*x

>>> double(2)
4
심지어 함수도 백그라운드에서 __call__ 방법을 호출한다.
>>> double.__call__(2)
4

앞으로 패스하는 마술 방법


모델 예제를 살펴보겠습니다. 이 모델은 10개의 출력을 얻기 위해 하나의 완전히 연결된 레이어를 MNIST 이미지에 적용합니다.
import torch.nn as nn

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(784, 10)        

    def forward(self, x):
        return self.fc1(x)
다음 코드를 숙지해야 합니다.우리는 이 모델이 일부 장량 x에서의 출력을 계산하고 있다.
x = torch.rand(10, 784)
model = Model()
output = model(x)
우리는 어떤 장량에서 모델을 직접 호출하면 그 위에서 .forward() 함수를 실행할 수 있다는 것을 안다.이게 어떻게 된 일입니까?
이것은 이전 예시의 원인과 같다.우리는 이 종류nn.Module를 계승했다.내부적으로는 nn.Module 마술 방법이 있는데 이 방법은 __call__() 호출된다.그래서 우리가 잠시 후에 .forward() 방법을 다시 쓸 때, 그것은 실행된다.
# nn.Module
class Module(object):
    def __call__(self, x):
        # Simplified
        # Actual implementation has validation and gradient tracking.
        return self.forward(x)
따라서 우리는 직접 장량에서 이 모델을 호출할 수 있다.
output = model(x)
# model.__call__(x) 
#   -> model.forward(x)

데이터 집중의 마술 방법


PyTorch에서는 일반적으로 .forward() 클래스로부터 계승된 사용자 정의 클래스를 만들어서 우리의 훈련과 테스트 데이터 집합을 준비합니다.왜 우리가 방법을 정의할 때 모호한 이름을 사용했는지 생각해 본 적이 있습니까? 예를 들어 Dataset__len__?
from torch.utils.data import Dataset

class Numbers(Dataset):
    def __init__(self, x, y):
        self.data = x
        self.labels = y

    def __len__(self):
        return len(self.data)

    def __getitem__(self, i):
        return (self.data[i], self.labels[i])

>>> dataset = Numbers([1, 2, 3], [0, 1, 0])
>>> print(len(dataset))
3
>>> print(dataset[0])
(1, 0)
이 방법들은 파이썬의 내장 마술 방법이다.너는 우리가 __getitem__ 함수를 어떻게 사용하여 목록과 원조 등 비교할 수 있는 데이터의 길이를 얻는지 안다.
>>> x = [10, 20, 30]
>>> len(x)
3
Python은 사용자 정의 클래스len를 정의하여 __len__ 에서 작업할 수 있도록 합니다.예:
class Data(object):
    def __len__(self):
        return 10

>>> d = Data()
>>> len(d)
10
이와 유사하게, 색인 표현을 사용하여 목록과 메타그룹 요소에 접근하는 방법을 알고 있습니다.
>>> x = [10, 20, 30]
>>> x[0]
10
파이썬은 마술 방법으로 사용자 정의 클래스에 이런 기능을 제공할 수 있습니다.예:
class Data(object):
    def __init__(self):
        self.x = [10, 20, 30]

    def __getitem__(self, i):
        return x[i]

>>> d = Data()
>>> d[0]
10
이러한 개념을 통해 이제 내장 데이터 세트(예: MNIST)를 쉽게 이해하고 사용할 수 있습니다.
from torchvision.datasets import MNIST

>>> trainset = MNIST(root='mnist', download=True, train=True)
>>> print(len(trainset))
60000
>>> print(trainset[0])
(<PIL.Image.Image image mode=L size=28x28 at 0x7F06DC654128>, 0)

DataLoader의 마술 방법


NIST 디지털 트레이닝 데이터 세트를 위한 데이터 로더를 만듭니다.
from torchvision.datasets import MNIST
from torch.utils.data import DataLoader
import torchvision.transforms as transforms

trainset = MNIST(root='mnist', 
                 download=True, 
                 train=True, 
                 transform=transforms.ToTensor())
trainloader = DataLoader(trainset, batch_size=32, shuffle=True)
이제 순환하지 않고 데이터 캐리어에서 첫 번째 데이터에 직접 접근해 보겠습니다.만약 우리가 색인을 통해 그것을 방문하려고 시도한다면, 이상이 발생할 것이다.
>>> trainloader[0]
TypeError: 'DataLoader' object does not support indexing
너는 아마 이미 이렇게 하는 것에 익숙해졌을 것이다.
images, labels =  next(iter(trainloader))
너는 우리가 왜 기차 적재기를 len() 옆에 싸서 전화하는지 생각해 본 적이 있니?우리 이 수수께끼를 풀자.
3개의 요소를 포함하는 목록을 고려합니다__getitem__.Python에서는 iter() 함수를 사용하여 next() 에서 교체기를 생성할 수 있습니다.
x = [1, 2, 3]
y = iter(x)
교체기를 사용하는 이유는 교체기가 로드 지연을 허용하기 때문에 한 번에 메모리에 하나의 요소만 불러올 수 있기 때문이다.
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> next(x)
StopIteration:
우리는 모든 원소를 얻었다. 우리가 목록의 끝에 도착했을 때, 우리는 x 이상을 얻었다.
이런 모델은 우리의 일반적인 기계 학습 작업 절차와 일치한다. 이런 작업 절차에서 우리는 한 번에 메모리에서 소량의 데이터를 얻고 앞뒤로 전달한다.그래서 x PyTorch에도 이 모델이 포함되어 있다.
Python의 클래스로 교체기를 만들기 위해서는 마술 방법iterStopIteration을 정의해야 합니다
class ExampleLoader(object):
    def __init__(self, data):
        self.data = iter(data)

    def __iter__(self):
        return self

    def __next__(self):
        return next(self.data)        

>>> l = ExampleLoader([1, 2, 3])
>>> next(iter(l))
1
여기에서 DataLoader 함수는 같은 대상의 클래스로 되돌아오는 __iter__ 마술 방법을 호출합니다.그리고 __next__ 함수 호출 클래스의 iter() 마술 방법으로 데이터의 다음 요소를 되돌려줍니다.
PyTorch에서 DataLoader의 구현은 다음과 같습니다.
class DataLoader(object):
    def __iter__(self):
        if self.num_workers == 0:
            return _SingleProcessDataLoaderIter(self)
        else:
            return _MultiProcessingDataLoaderIter(self)

class _SingleProcessDataLoaderIter(_BaseDataLoaderIter):
    def __next__(self):
        # logic to return batch from whole data
        ...
따라서 그들은 교체기 생성 부분과 실제 데이터 불러오는 부분을 결합시킨다.
  • 데이터 캐리어에서 호출 __iter__ 할 때, 우리가 사용하는 것이 단일한지 여러 개의 워커인지 검사합니다
  • 이를 바탕으로 한 개 이상의worker를 다른 교체기 클래스로 되돌려줍니다
  • >>> type(iter(trainloader))
    torch.utils.data.dataloader._SingleProcessDataLoaderIter
    
  • 이 교체기류는 next() 방법을 정의했다. 우리가 __next__ 를 호출할 때, 이 방법은 집합iter()의 실제 데이터를 되돌려준다
  • images, labels =  next(iter(trainloader))
    
    # equivalent to:
    images, labels = trainloader.__iter__().__next__()
    
    따라서 우리는 한 차례의 이미지와 라벨을 얻을 수 있다.

    결론


    따라서 우리는 PyTorch가 어떻게 그 API 디자인에서 로컬 Python 자체의 고급 개념을 참고하는지 보았다.나는 이 문장이 이러한 개념의 배후에 있는 신비한 베일을 벗기고 당신이 더 좋은PyTorch 사용자가 되는 데 도움이 되기를 바랍니다.

    연결


    만약 당신이 이 박문을 좋아한다면, 언제든지 저에게 연락 주십시오. 저는 매주 그곳에서 새로운 박문을 공유할 것입니다.

    좋은 웹페이지 즐겨찾기