부스트 캠프 ai tech 2주 4일차 Pytorch (8)


Pytorch Troubleshooting

  • OOM : Out Of Memory
    • GPU의 메모리가 터질때 발생하는 현상…
    • 왜 발생했는지 알기힘듬
    • 메모리의 이전상황의 파악이 어려움
  • OOM의 해결방법
    • 보통 이 아래방법으로 대부분 해결된다
    • Batchsize를 줄여서 메모리 부하를 줄인다
    • torch.cuda.empty_cache()를 이용하여 GPU의 메모리를 clear 한 뒤에 학습시킨다
  • 그 외에 신경쓰면 좋을점
    • GPUtil Module 사용하기
    • tensor.no_grad() 사용하기
    • 적절하게 del 명령어 사용하기
    • 다양한 batchsize로 돌려서 가능한 batchsize 알아보기
    • tensor의 float 32를 float 16으로 줄여보기

reference

부스트 캠프 ai tech 2주 4일차 Pytorch (7)


8. Hyperparameter Tuning

  • Hyperparameter 란?
    • Learning Rate, Model의 inputsize, optimizer, loss function, batchsize 등의 모델이 스스로 학습하지 않는 값을 말한다
    • 이 Hyperparameter를 조절하여 성능을 올리는 방법을 Hyperparameter Tuning이라고 부른다
    • 생각보다 스펙타클하게 성능이 좋아지지는 않는다
  • parameter에 따른 기울기값을 계산한뒤 큰값을 내는(빠르게 학습이 가능한) parameter를 찾는 기법
  • 보통 Learning rate를 찾는데 사용하는 기법이다
  • 특정 간격마다의 값으로 검색하는 Grid Layout과 랜덤한 값으로 검색하는 Random Layout 등 여러가지 방법이 존재한다
  • 최근에는 베이지안 기반의 기법들이 주도하고 있다
    • BOHB(Baysian Optimizer Hyperband)

8.2 Ray 라이브러리

  • ML과 DL의 병렬 처리를 위해 개발된 모듈이다
  • Hyperparameter Search를 위한 다양한 모듈을 제공한다
  • ML과 DL을 위해 개발되긴 했는데 분산처리(Multiprocessing)코드를 단순하고, 범용적으로 작성할 수 있게 도와준다
  • 병렬처리 양식으로 학습을 시행해서 성능이 좋지않은 process들을 제외해 가면서 최적의 hyperparameter를 찾는다
  • 아래쪽의 참고 문서를 보는것을 추천한다

reference

부스트 캠프 ai tech 2주 4일차 Pytorch (6)


7. Multi GPU 학습

  • 데이터의 양이 방대해짐에 따라서 모든 데이터들을 전부 메모리에 올리는것이 물리적으로 힘들고, 시간적으로도 소요가 많이 되어서 이를 해결하기 위해 여러대의 GPU를 병렬적으로 사용하는 방법이다
  • 크게 2가지의 방법으로 나뉜다
    • Model 병렬화 : 모델을 나눠서 학습한다
    • Data 병렬화 : 데이터를 나눠서 학습한다

7.1 Model 병렬화

  • 모델을 나눠서 여러대의 GPU에 올려서 연산하는 방법

  • 모델의 크기가 너무 커서 GPU에 올라가지 않는 상황에서 사용한다

  • 모델의 병목화, 파이프라인 구축 등의 문제로 인해 구현 난이도가 높다

    • pipeline을 제대로 구축하지 않으면 한 GPU가 연산하는동안 다른 GPU가 놀고있는 상황이 발생해 오히려 Single GPU보다 못한 상황이 발생 할 수 있다
  • Model Pipeline Paralle 예시 - Pytorch 공식 모델 병렬화 Tutorial

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class PipelineParallelResNet50(ModelParallelResNet50):
    def __init__(self, split_size=20, *args, **kwargs):
    super(PipelineParallelResNet50, self).__init__(*args, **kwargs)
    self.split_size = split_size

    def forward(self, x):
    splits = iter(x.split(self.split_size, dim=0))
    s_next = next(splits)
    s_prev = self.seq1(s_next).to('cuda:1')
    ret = []

    for s_next in splits:
    # A. s_prev는 두 번째 GPU에서 실행됩니다.
    s_prev = self.seq2(s_prev)
    ret.append(self.fc(s_prev.view(s_prev.size(0), -1)))

    # B. s_next는 A.와 동시에 진행되면서 첫 번째 GPU에서 실행됩니다.
    s_prev = self.seq1(s_next).to('cuda:1')

    s_prev = self.seq2(s_prev)
    ret.append(self.fc(s_prev.view(s_prev.size(0), -1)))

    return torch.cat(ret)
  • 아래의 그림에서 2장의 레이어 사이에 교차하는 부분이 병렬 GPU간의 교차 통신이다

    • Model 병렬화는 꽤 예전 논문인 AlexNet에서도 사용되고 있었다

Alexnet

7.2 Data 병렬화

  • 데이터를 나눠서 GPU에 할당한 후 결과의 평균을 취하는 방법
  • 각 데이터에 대한 연산을 여러 GPU에서 동시에 수행해서 학습의 효율을 높인다
    • 합칠때
  • pytorch에서는 두 가지 방식을 제공한다
    • DataParallel : 단순하게 데이터를 분배한 뒤 평균을 취하는 방식
    • Distributed DataParallel : GPU에서 모든 연산이 끝난뒤에 결과만을 공유하는 방식
  1. DataParallel:
    • 단순하게 GPU에 데이터를 분배한 뒤 평균을 취하는 방식
    • 연산이 끝난뒤에 하나의 GPU에 loss값을 모아서 gradient를 만들고 이것들 다시 다른 GPU에 전달을 해준다
    • 하나의 GPU가 특별하게 자원을 많이 사용하는 문제가 발생할 수 있다
      • 합쳐진 loss연산을 GPU는 더 많은 메모리를 사용하기 때문에 Batch사이즈의 감소등의 방법으로 메모리 부하를 줄여야 할 수도 있다
    • 매우 간단하게 pytorch에서 구현 할 수 있다
      1
      parallel_model = torch.nn.DataParallel(model) # 나머지는 일반 모델과 동일
  2. Distributed DataParallel:
    • GPU에서 모든 연산이 끝난뒤에 결과만을 공유하는 방식
    • Loss, Backward 계산 모두 각각의 GPU에서 이루어지며 연산이 완전히 끝나고 평균값이 결과로 출력된다
    • 개별 GPU마다 CPU에서 프로세스를 생성해서 할당한다 (Multiprocessing)
    • DataParallel과는 다르게 DataLoader에서 Shuffle 대신에 DistributeSampler를 사용하고, pin_memory를 활성화 시킨다

reference

부스트 캠프 ai tech 2주 3일차 Pytorch (5)


  • 학습시킨 모델을 다른사람들에게 공유하거나, 보관하기 위에서는 메모리에 있는 Model들을 따로 파일로 만들어서 저장할 필요가 있는데 본 글에서는 저장을 어떻게 해야하는지, 그리고 이를 이용한 Tranfer Learning 에 대해서 다룰 예정이다

5. Pytorch Model Save & Load

  • torch.save()
    • 학습의 결과를 저장하기 위한 함수이다
    • 모델의 Layer들과 Parameter, Buffer를 저장한다
    • 학습 중간중간 Model을 저장해서 최선의 성능을 가지는 결과모델을 선택하는 방식으로 사용 할 수 있다 (Checkpoint)
      • model : 학습한 모델
      • PATH : 모델을 저장할 directory
      1
      2
      3
      4
      # 모델의 weight 만 저장하는 방법
      torch.save(model.state_dict(), PATH)
      # 모델의 weight와 내부모듈 구조, Buffer까지 저장하는 방법
      torch.save(model, PATH)
  • checkpoints
    • 학습의 중간 결과를 저장해서 최선의 성능을 가지는 결과모델을 선택하는 방법
    • 보통 early stopping 기법과 함께 사용한다
      • early stopping : Loss와 Metric값을 지속적으로 확인 하면서 일정 기간이상 줄지 않으면 학습을 멈추는 방법
    • 일반적으로 epoch, loss, mertic을 함께 저장하여 확인한다
1
2
3
4
5
6
7
8
9
10
11
12
torch.save({
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'loss': epoch_loss,
}, f"saved/checkpoint_model_{epoch}_{epoch_loss/len(dataloader)}_{epoch_acc/len(dataloader)}.pt")

checkpoint = torch.load(PATH)
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']
loss = checkpoint['loss']

6. Transfer Learning

  • 다른 데이터셋으로 만든 모델을 현재 데이터셋에 맞춰서 다시 학습시키는 방법
    • 일반적으로 큰 데이터셋으로 학습시킨 모델(ex Imagenet 10K로 학습시킨 resnet50 등등)의 성능이 다른 데이터셋에 적용시키는것이 처음부터 학습하는 모델보다 학습이 빠르고, 학습이 잘된다
  • 현재 DeepLearning에서 가장 일반적인 학습 방법이다
  • 기존의 pretrained 된 모델을 backbone 모델이라고 하며 여기서 일부 Layer만 변경시켜서 학습을 수행한다
  • CV : Pytorch 공식 비전 라이브러리 TorchVision 이나 torch image model(timm)을 많이 이용한다
  • NLP : transformer 전문 라이브러리인 HuggingFace를 많이 사용한다

6.1 Freezing

  • pretrained model을 활용할때 모델의 일부분을 freeze 시켜 파라미터의 업데이트가 일어나는것을 막는 방법
  • DeepLearning의 특성상 학습이 계속 진행되면서 파라미터가 바뀌면 과거에 학습했던 정보가 희석되는 현상이 일어나는데 특히 pretrained 모델에게 안좋은 영향을 준다
  • pytorch의 requires_grad를 비활성화 시키거나 hook를 이용해서 backward의 input_grad를 0으로 고정시켜버리는 것으로도 가능하다

reference

부스트 캠프 ai tech 2주 3일차 Pytorch (4)


4. Dataset & DataLoader

  • pytorch에서 생성한 모델을 학습시키기 위해 데이터를 공급해주는 유틸리티

4.1 Dataset

  • Data를 담고 있는 Class
  • pytorch Dataset은 아래와 같이 3가지의 기본 Method로 구성되어있다
  • __init__: 초기화 함수. 필요한 변수들을 선언하고, data를 load하는 부분이다
  • __len__: 데이터의 개수를 반환하는 함수. Dataloader에서 길이등을 반환하는데 쓰인다
  • __get_item__(index): index번째의 data를 반환하는 함수. tensor로 return 해준다.
  • 데이터에 따라 Map style과 iterable style로 나뉜다
    • Map style : 일반적인 data 구조
    • iterable style : random으로 읽기 어렵거나 data에 따라 batchsize가 달라지는 data. 시계열 데이터 등에 적합하다
  • Map style 코드는 아래와 같다
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class BasicDataset(Dataset):
    def __init__(self, path):
    self.data = pd.read_csv(path)
    self.X = self.data.drop(['label'])
    self.y = self.data['label']

    def __get_item__(self, idx):
    return self.X.iloc[idx], self.y[idx]

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

4.2 DataLoader

  • Dataset을 iterable 하게 사용할 수 있도록 도와주는 Utility
  • data loading 순서 커스터마이징, 자동 batch 설정, Single-Multi process data loading등 여러가지 기능을 지원한다
1
2
3
4
5
DataLoader(dataset, batch_size=1, shuffle=False, sampler=None,
batch_sampler=None, num_workers=0, collate_fn=None,
pin_memory=False, drop_last=False, timeout=0,
worker_init_fn=None, *, prefetch_factor=2,
persistent_workers=False)
  1. dataset
    • torch.utils.data.Dataset parameter
  2. batch_size
    • Data를 불러올 때 배치사이즈를 설정하는 항목
  3. shuffle
    • Data load 순서를 항상 랜덤하게 뽑을지를 결정하는 항목
    • torch.manual_seed 를 통해 랜덤값을 고정할 수도 있다
  4. sampler
    • Data의 index를 컨트롤 하는 방법
    • torch.utils.data.Sampler 객체를 사용한다
    • SequentialSampler : 항상 같은 순서로 elements들을 sampling한다
    • RandomSampler : 랜덤하게 sampling 한다. replacement 가능, random의 범위를 지정 가능하다 (default=len(dataset))
    • SubsetRandomSampler : 랜덤하게 sampling 한다 위의 두 기능은 없다
    • WeigthRandomSampler : 가중치에 따라 뽑히는 확률이 달라진다
    • BatchSampler : Batch단위로 sampling을 해준다
    • DistributedSampler : Multi GPU에서 분산처리를 할때 사용한다
  5. batch_sampler
    • sampler와 같지만 기본적으로 BatchSampler가 적용된 상태이다
  6. num_workers
    • GPU에 Data를 load 할때 사용할 process의 수를 결정한다
  7. collate_fn
    • sample list를 합쳐서 tensor의 minibatch로 바꿔주는 기능. map style의 dataset에서 사용한다
    • 데이터마다의 길이가 다른 NLP에서 많이 사용한다
  8. pin_memory
    • pin memory를 사용하여 GPU에 더 빠르게 data를 load하는 방법.
    • 추가적인 메모리 자원이 필요하다. 보통 parallel 모델에서 많이 사용한다
  9. drop_last
    • Data의 전체 개수가 batchsize로 나누어 떨어지지 않을때 마지막 batch를 drop를 결정하는 parameter

reference

부스트 캠프 ai tech 2주 2일차 Pytorch (3)


3. torch.nn

  • Pytorch의 Nerual Network와 관련된 기능들이 있는 모듈이다
  • Neural Network와 관련된 Layer, Function들이 속해있다
    • Layer : 1층의 인공신경망을 이야기한다. input으로 들어온 값을 선형연산이나, 비선형연산을 통해 output을 return해 주는 class이다
    • Function : 활성화함수 등의 Neural Network의 연산을 하기위해 필요한 함수을 이야기한다

3.1 nn.Module

  • Custom Network(모델)를 만들기 위해서 지원하는 module이다
  • nn.Module은 내부에 Module을 포함할 수 있다
    • 여러층으로 쌓이는 모양으로 인해 Layer라고도 부른다
    • Layer가 모여서 Model을 이룬다
  • 기본적으로 아래와 같은코드를 베이스로 만들 수 있다
    • super : nn.Module에서 Attribute를 상속받기위한 선언. 이것이 없으면 빈 깡통 클래스이다
    • forward : 순전파를 구현하는 함수
      1
      2
      3
      4
      5
      6
      class TestNet(nn.Module):
      def __init__(self):
      super(TestNet, self).__init__()

      def forward(self, x):
      return x_out

3.2 Container

  1. nn.Sequential()
    • 여러 모듈을 하나로 묶어서 하나의 모듈처럼 사용할 수 있는 Container
    • 순차적인 Layer들을 하나로 묶어서 깔끔하게 관리 할 수 있다
  2. nn.ModuleList()
    • 여러 모듈을 list처럼 한군데 모아두는 Container
    • indexing을 통해 필요한 모듈을 꺼내 쓸 수 있다
    • 일반적인 List와 다르게 Attribute여도 Class를 print할 때 외부에 출력된다
  3. nn.ModuleDict()
    • 여러 모듈을 dict처럼 한군데 모아두는 Container
    • Key값을 통해 필요한 모듈을 불러올 수 있다
    • ModuleList()와 같이 Class를 print할 때 외부에 출력된다

3.3 Parameter & Buffer

  • Parameter
    • 모듈안에 임시로 저장되는 특별한 Tensor
    • 일반적인 Tensor attribute와는 다르게 기울기 계산이 가능하고, 모델저장시에 같이 저장된다
    • RNN 같이 parameter가 반복되고, 갱신이 필요한 경우 사용된다
    • 또한 모듈속의 내부모듈들의 tensor는 전부 parameter로 지정된다
    • Parameter()로 선언 할 수 있다
  • Buffer
    • 모듈안에 임시로 저장되는 Tensor
    • 모델저장시에 같이 저장된다
    • config용의 정보등을 저장할 때 사용한다
    • nn.Module의 register_buffer로 등록할 수 있다

3.4 Module 내부 살펴보기

  • nn.module에는 내부의 여러 attribute를 볼 수 있는 기능이 존재한다
  • 내부의 모듈, Parameter, buffer 등 여러 attribute가 ObjectDict형태로 저장되어 불러올 수 있다
  1. submodule
    • 모듈속 모듈인 submodule은 아래의 함수들로 살펴 볼 수 있다
    • named_children
      • module에 바로 아래단계에 속한 submodule만 보여준다
    • named_modules
      • submodule 뿐만아니라 module에 속해있는 모든 module을 보여준다
  2. parameter
    • named_parameters를 통해 parameter를 호출이 가능하다
  3. buffer
    • named_buffers를 통해 buffer 호출이 가능하다

3.5 hook

  • package화 된 코드에서 custom 코드를 중간에 실행시킬 수 있도록 만들어 놓은 인터페이스
  • pytorch에는 등록하는 대상에 따른 2가지 종류의 hook
    • Tensor에 등록하는 Tensor hook
    • Module에 등록하는 Module hook
  • 실행 시점에 따른 5가지 종류의 hook이 존재한다
    • forward pre hooks : forward 연산 전에 실행되는 hook
    • forward hooks : forward 연산 후에 실행되는 hook
    • backward_hooks : backward 연산이 수행될때 마다 실행되는 hook. 현재는 사용하는걸 권장하지 않는다
    • full backward hooks : backward 연산이 수행될때 마다 실행되는 hook
    • state dict hooks : load_state_dict 함수가 모듈 내부에서 실행하는 hook, 직접적으로 user가 잘 사용하지는 않는다
  1. Tensor hook
    • Tensor에 대한 Backward Propagation 후에 작동하는 hook
    • torch.Tensor.register_hook 을 통하여 hook을 등록 할 수 있다
    • torch.Tensor._backward_hooks 을 통하여 등록한 hook을 확인 할 수 있다
      1
      2
      3
      4
      def hook(grad):
      pass
      tensor.register_hook(hook)
      tensor_backward_hooks() # OrderedDict([(0, <function __main__.hook(grad)>)])
  2. Module hook
    • Module hook은 3개의 종류의 hook으로 사용된다
    • forward pre hooks
    • forward hooks
    • backward_hooks
    • full backward hooks
  • forward pre hooks
    • forward 연산이 일어나기 전 시점에서 실행되는 hook
    • parameter로 module과 input으로 받고 input을 수정해서 return 할 수 있다
    • Module.register_forward_pre_hook(hook)으로 등록이 가능하다
      1
      forward_pre_hook(module, input) -> None or modified input
  • forward hooks
    • forward 연산이 일어난 뒤 시점에서 실행되는 hook
    • parameter로 module, input, output으로 받고, output을 수정해서 return 할 수 있다
    • input값또한 수정이 가능하지만 forward 연산에 변화는 없다
    • Module.register_forward_hook(hook)으로 등록이 가능하다
      1
      forward_hook(module, input, output) -> None or modified output
  • full backward hooks
    • backward 연산이 수행될때 마다 실행되는 hook
    • parameter로 module, grad_input, grad_output으로 받고, 새로운 grad_input return 할 수 있다
    • parameter인 grad_input 자체를 수정하면 Error가 발생할 수 있다
    • Module.register_full_backward_hook(hook)으로 등록이 가능하다
      1
      full_backward_hooks(module, grad_input, grad_output) -> None or modified grad_input

3.6 apply

  • 특정 함수를 Module과 Module에 속한 submodule에 적용하는 함수
  • weight 초기화나, 내부 모듈에 특정한 method를 추가할 때 사용할 수 있다
  • weight_initialization
    1
    2
    3
    4
    def weight_initialization(module):
    module_name = module.__class__.__name__
    if 'Function' in module_name:
    module.W.data.fill_(1)
  • make_method
    1
    2
    3
    4
    5
    6
    7
    def function_repr(self):
    return f'name={self.name}'

    def add_repr(module):
    module_name = module.__class__.__name__
    if 'Function' in module_name:
    module.extra_repr = partial(function_repr, module)

부스트 캠프 ai tech 2주 1일차 Pytorch (2)


2. 유용한 torch 함수들

  1. Tensors
  2. Creation Ops
  3. indexing, Slicing, Joining, Mutating

2.1 Tensors

  1. is_*
    • 데이터 형태가 tensor인지 판단, tensor의 내부 데이터 등의 여러가지 판단을 하는 함수
      1
      2
      3
      x = torch.tensor([0])
      is_tensor(x) # True
      is_nonzero(x) # False, input : single element tensor
  2. torch.numel(x)
    • 전체 element가 몇개인지 출력하는 함수
      1
      2
      a = torch.randn(1, 2, 3, 4, 5)
      torch.numel(a) # 120

2.2 Creation Ops

  1. torch.from_numpy
    • ndarray를 torch.Tensor로 바꾸는 함수
  2. torch.zeros(size), empty(size), ones(size)
    • 0, 빈, 1로 이루어진 tensor를 size 형태로 생성하는 함수
    • numpy와 같은 기능을 한다
  3. torch.zeros_like(tensor), empty_like(tensor), ones_like(tensor)
    • tensor의 size를 가진 0, 빈, 1로 이루어진 tensor를 생성하는 함수
    • numpy와 같은 기능을 한다
  4. torch.arrange(start, end, step)
    • numpy의 arrange와 같은 기능을 하는 함수
    • start 부터 end 까지 step마다의 수를 가진 1D-tensor를 생성한다
  5. torch.linspace(start, end, steps)
    • start에서 end의 구간의 길이를 steps개로 균등하게 나누는 1D-tensor를 생성한다
  6. torch.full(size, fill_value), torch.full_like(tensor, fill_value)
    • fill_value로 채워진 tensor를 생성한다

2.3 indexing, Slicing, Joining, Mutating 함수

  1. torch.index_select(input, dim, index)
    • 특정한 index에 위치한 데이터를 모아서 return 해주는 함수
      1
      2
      3
      4
      5
      6
      A = torch.Tensor([[1, 2], [3, 4]])
      torch.index_select(A, 1, torch.tensor([0]))
      ===========================================
      output:
      tensor([[1.],
      [3.]])
  2. torch.gather(input, dim, index)
    • 특정한 index들에 위치한 데이터를 모아서 return 해주는 함수
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      t = torch.tensor([[1, 2], [3, 4]])
      torch.gather(t, 1, torch.tensor([[0, 0], [1, 0]]))
      ==================================================
      output:
      tensor([[ 1, 1],
      [ 4, 3]])
      ==================================================
      index calculate:
      out[i][j][k] = input[index[i][j][k]][j][k] # if dim == 0
      out[i][j][k] = input[i][index[i][j][k]][k] # if dim == 1
      out[i][j][k] = input[i][j][index[i][j][k]] # if dim == 2
  3. torch.cat(tensors, dim) == torch.concat
    • tensors들을 합치는 함수
    • 기준이 되는 dim을 제외하고 같은 shape를 가지고 있어야한다
      1
      2
      3
      x = torch.rand(1, 3)
      y = torch.rand(2, 3)
      torch.cat((x,y), 0).size() # torch.Size([3, 3])
  4. torch.chunk(input, chunks, dim)
    • tensor를 chunk의 갯수만큼으로 분리해주는 함수
    • chunks의 갯수가 넘어가지 않는 선에서 같은 size의 tensor로 분리해준다
    • 나누어 떨어지지 않는경우 마지막 tensor의 사이즈의 크기가 다를 수도 있다
      1
      2
      3
      4
      5
      6
      7
      8
      torch.arange(13).chunk(6)
      =========================
      output:
      (tensor([0, 1, 2]),
      tensor([3, 4, 5]),
      tensor([6, 7, 8]),
      tensor([ 9, 10, 11]),
      tensor([12]))
      1
      2
      3
      4
      5
      6
      7
      8
      t = torch.tensor([[1, 2, 3],
      [4, 5, 6]])
      print(torch.chunk(t, 2, 1))
      ===========================
      output:
      (tensor([[1, 2],
      [4, 5]]), tensor([[3],
      [6]]))
  5. torch.Tensor.scatter_(dim, index, src, reduce=None)
    • Tensor에 index에 맞춰서 src를 삽입하는 함수이다
    • reduce에 add, multiple을 넣어서 더하거나 곱하기도로 바꿀 수 있다
    • torch.gather와 반대로 작동한다
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      src = torch.arange(1, 11).reshape((2, 5)) 
      # tensor([[ 1, 2, 3, 4, 5], [ 6, 7, 8, 9, 10]])
      index = torch.tensor([[0, 1, 2, 0]])
      torch.zeros(3, 5, dtype=src.dtype).scatter_(0, index, src)
      ==========================================================
      output:
      tensor([[1, 0, 0, 4, 0],
      [0, 2, 0, 0, 0],
      [0, 0, 3, 0, 0]])
      ==========================================================
      index calculate:
      self[index[i][j][k]][j][k] = src[i][j][k] # if dim == 0
      self[i][index[i][j][k]][k] = src[i][j][k] # if dim == 1
      self[i][j][index[i][j][k]] = src[i][j][k] # if dim == 2
  6. torch.stack(tensors, dim)
    • 지정하는 차원으로 확장해서 tensor를 쌓아주는 함수이다
    • 두 차원이 정확하게 일치해야 쌓기가 가능하다
      1
      2
      3
      x = torch.rand(3, 1, 3) # 3, 1, 3
      y = torch.rand(3, 1, 3) # 3, 1, 3
      torch.stack((x,y), dim=2).size() #torch.Size([3, 1, 2, 3])

      2.4 random Sampling

  • 자주 쓰이지만 numpy와 비슷해서 문서를 참고하는편이 좋을듯 하다
  • Random sampling - PyTorch 공식 문서
  • torch.seed(), torch.manual_seed(int)
    • Seed값을 고정해서 랜덤한 변수를 고정시킬 수 있다
    • manual_seed는 직접 시드값을 입력할 수 있다

2.5 Pointwise Ops

  • 수학 연산과 관련된 기능을 포함하는 함수군
    • numpy와 비슷하다
  1. torch.sqrt(tensor)
    • 각 tensor의 element에 대한 제곱근을 구해주는 함수
  2. torch.exp(tensor)
    • 각 tensor의 element에 대한 $e^x$
  3. torch.pow(tensor)
    • 각 tensor의 element에 대한 $x^2$

2.6 Reduction Ops

2.7 Comparison Ops

  1. torch.argsort(tensor)

    • tensor를 sort하는 index를 return 해준다
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      a = torch.randint(1, 10, (3, 3))
      a
      torch.argsort(a)
      ================
      output:
      tensor([[9, 5, 3],
      [6, 4, 2],
      [5, 8, 6]])
      tensor([[2, 1, 0],
      [2, 1, 0],
      [0, 2, 1]])
  2. torch.eq, torch.gt, torch.ge

    • tensor의 값들이 같은지, 더 큰지, 이상인지를 판단하는 함수들이다
  3. torch.allclose(input, other, trol, atol)

    • input tensor와 other의 원소들의 차가 특정 범위인지를 판단하는 함수
      $$
      |\operatorname{input} - \operatorname{other}| \leq atol + rtol \times|other|
      $$
1
2
torch.allclose(torch.tensor([10.1, 1e-9]), torch.tensor([10.0, 1e-08]))
# False

2.8 Other Operations

  1. torch.einsum
    • Einstein Notation에 따라 연산을 진행하는 함수
    • Einstein Notation은 특정 index의 집합에 대한 합연산을 간결하게 표시하는 방법이다
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      x = torch.randn(5)
      y = torch.randn(4)
      torch.einsum('i,j->ij', x, y)
      ============================
      output:
      tensor([[ 0.1156, -0.2897, -0.3918, 0.4963],
      [-0.3744, 0.9381, 1.2685, -1.6070],
      [ 0.7208, -1.8058, -2.4419, 3.0936],
      [ 0.1713, -0.4291, -0.5802, 0.7350],
      [ 0.5704, -1.4290, -1.9323, 2.4480]])
      ==============================================
      As = torch.randn(3,2,5)
      Bs = torch.randn(3,5,4)
      torch.einsum('bij,bjk->bik', As, Bs)
      ====================================
      output:
      tensor([[[-1.0564, -1.5904, 3.2023, 3.1271],
      [-1.6706, -0.8097, -0.8025, -2.1183]],

      [[ 4.2239, 0.3107, -0.5756, -0.2354],
      [-1.4558, -0.3460, 1.5087, -0.8530]],

      [[ 2.8153, 1.8787, -4.3839, -1.2112],
      [ 0.3728, -2.1131, 0.0921, 0.8305]]])

2.9 BLAS & LAPACK Ops

부스트 캠프 ai tech 2주 1일차 Pytorch (1)


0. pytorch란?

  • Meta(구 Facebook) 에서 개발한 딥러닝 프레임워크
  • numpy + AutoGradient
  • 동적 그래프 기반

1. pytorch 기본

  • pytorch 에서는 Tensor class를 사용한다
  • Tensor
    • numpy의 ndarray와 사실상 동일하다
      • 내장 함수도 대부분 비슷한 기능이 존재한다
    • tensor가 가질수 있는 type은 ndarray와 동일하나 GPU 사용이 가능한 차이가 존재한다

1.1 기본 Tensor 함수

  • list > tensor
    1
    2
    3
    4
    5
    6
    7
    import torch
    data = [[3, 5],[10, 5]]
    x_data = torch.tensor(data)
    ##########################
    output:
    tensor([[ 3, 5],
    [10, 5]])
  • ndArray > tensor
    1
    2
    3
    4
    5
    6
    nd_array_ex = np.array(data)
    tensor_array = torch.from_numpy(nd_array_ex)
    ############################################
    output:
    tensor([[ 3, 5],
    [10, 5]])
  • tensor > ndarray
    1
    2
    3
    4
    5
    tensor_array.numpy()
    ####################
    output:
    array([[ 3, 5],
    [10, 5]])
  • flatten
    1
    2
    3
    4
    5
    6
    data = [[3, 5, 20],[10, 5, 50], [1, 5, 10]]
    x_data = torch.tensor(data)
    x_data.flatten()
    ################
    output:
    tensor([ 3, 5, 20, 10, 5, 50, 1, 5, 10])
  • one_like
    1
    2
    3
    4
    5
    6
    torch.ones_like(x_data)
    #######################
    output:
    tensor([[1, 1, 1],
    [1, 1, 1],
    [1, 1, 1]])
  • shape, dtype
    1
    2
    x_data.shape # torch.Size([3, 3])
    x_data.dtype # torch.int64
  • GPU load
    1
    2
    3
    device = torch.device('cpu')
    if torch.cuda.is_available():
    device = torch.device('cuda')

1.2 Tensor handling

  • view & reshape
    • tensor의 shape를 변경하는 함수
    • view는 input tensor와 return tensor가 데이터를 공유하여 항상 같은 주소값들을 가진다
    • reshape은 tensor의 복사본 혹은 view를 반환한다
      • 원본과 동일한 tensor값이 필요할 경우에는 view를 사용하거나 clone()을 이용해야한다
  • squeeze & unsqueeze
    • 차원의 개수가 1인 차원을 축소, 확장하는 함수
    • unsqueeze(index) : index에 1인 차원을 삽입해서 차원을 확장한다
      1
      2
      3
      4
      5
      6
      7
      8
      tensor_ex = torch.rand(size=(2, 1, 2))
      tensor_ex.squeeze().shape # torch.Size([2, 2])
      tensor_ex = torch.rand(size=(2, 2))
      tensor_ex.unsqueeze(0).shape # torch.Size([1, 2, 2])
      tensor_ex = torch.rand(size=(2, 2))
      tensor_ex.unsqueeze(1).shape # torch.Size([2, 1, 2])
      tensor_ex = torch.rand(size=(2, 2))
      tensor_ex.unsqueeze(2).shape # torch.Size([2, 2, 1])

1.3 Tensor operation

  • numpy와 동일하게 operation에 대해서 broadcasting을 지원한다
  • 행렬곱셈 연산은 mm 및 matmul을 사용한다
    • dot은 1차원 벡터와 스칼라 연산에서만 사용가능
    • mm과 matmul은 2차원이상의 행렬연산에서만 사용가능
    • mm은 broadcasting을 지원하지 않지만 matmul은 지원한다

1.4 Tensor operation for ML/DL formula

  • nn.functional을 이용한 다양한 연산가능
  • softmax, argmax, one_hot 등등

1.5 AutoGrad

  • 자동 미분
  • tensor에 requires_grad=True로 설정해서 자동으로 gradient 추적이 가능하다
    • 기본적으로 nn모듈의 선형연산들은 default로 True로 설정되어있어 잘 쓰지 않는다
      1
      tensor(data, requires_grad=True)
  • backward() 함수를 통하여 Backpropagation 수행