반응형

 

Pytorch

  • 페이스북이 초기 루아(Lua) 언어로 개발된 토치(Torch)를 파이썬 버전으로 개발하여 2017년도에 공개

  • 초기에 토치(Torch)는 넘파이(NumPy) 라이브러리처럼 과학 연산을 위한 라이브러리로 공개

  • 이후 GPU를 이용한 텐서 조작 및 동적 신경망 구축이 가능하도록 딥러닝 프레임워크로 발전시킴

  • 파이썬답게 만들어졌고, 유연하면서도 가속화된 계산 속도를 제공

 

Pytorch 모듈 구조

 

파이토치의 구성요소

  • torch: 메인 네임스페이스, 텐서 등의 다양한 수학 함수가 포함
  • torch.autograd: 자동 미분 기능을 제공하는 라이브러리
  • torch.nn: 신경망 구축을 위한 데이터 구조나 레이어 등의 라이브러리
  • torch.multiprocessing: 병럴처리 기능을 제공하는 라이브러리
  • torch.optim: SGD(Stochastic Gradient Descent)를 중심으로 한 파라미터 최적화 알고리즘 제공
  • torch.utils: 데이터 조작 등 유틸리티 기능 제공
  • torch.onnx: ONNX(Open Neural Network Exchange), 서로 다른 프레임워크 간의 모델을 공유할 때 사용

 

텐서(Tensors)

  • 데이터 표현을 위한 기본 구조로 텐서(tensor)를 사용
  • 텐서는 데이터를 담기위한 컨테이너(container)로서 일반적으로 수치형 데이터를 저장
  • 넘파이(NumPy)의 ndarray와 유사
  • GPU를 사용한 연산 가속 가능

import torch

# 버전확인
torch.__version__
>>1.12.1+cu113

 

텐서 초기화와 데이터 타입

  • 초기화 되지 않은 텐서
x = torch.empty(4,2)
print(x) # 초기화 X
>>  tensor([[6.6778e+01, 0.0000e+00],
            [1.3024e+00, 1.1959e+00],
            [       nan, 2.2405e+17],
            [1.6457e+19, 1.7743e+28]])
  • 무작위로 초기화된 텐서
x = torch.rand(4, 2)
print(x) # random 기준 초기화
>>  tensor([[0.6760, 0.4138],
            [0.2524, 0.4750],
            [0.2445, 0.6606],
            [0.9425, 0.7982]])
  • 데이터 타입(dtype)이 long이고, 0으로 채워진 텐서
x = torch.zeros(4, 2, dtype=torch.long)
print(x) # long 정수형
>>  tensor([[0, 0],
            [0, 0],
            [0, 0],
            [0, 0]])
  • 사용자가 입력한 값으로 텐서 초기화
x = torch.tensor([3, 2.3])
print(x)
>> tensor([3.0000, 2.3000])
  • 2 x 4 크기, double 타입, 1로 채워진 텐서
x = x.new_ones(2, 4, dtype=torch.double)
print(x)
>> tensor([[1., 1., 1., 1.],
           [1., 1., 1., 1.]], dtype=torch.float64)
  • x와 같은 크기, float 타입, 무작위로 채워진 텐서
x = torch.randn_like(x, dtype=torch.float) # 기존의 x와 같은 크기 만들어 주는것
print(x)
>>  tensor([[-0.0198, -0.6520,  0.7265,  0.1030],
            [-1.1093, -0.4835,  0.1521,  0.4217]])
  • 텐서의 크기 계산
print(x.size())
>> torch.Size([2, 4])

 

데이터 타입(Data Type)

ft = torch.FloatTensor([1,2,3])
print(ft)
print(ft.dtype)
>>  tensor([1., 2., 3.])
    torch.float32


# type cast
print(ft.short())
print(ft.int())
print(ft.long())
>>  tensor([1, 2, 3], dtype=torch.int16)
    tensor([1, 2, 3], dtype=torch.int32)
    tensor([1, 2, 3])

it = torch.IntTensor([1,2,3])
print(it)
print(it.dtype)
>>  tensor([1, 2, 3], dtype=torch.int32)
    torch.int32

print(ft.float())
print(ft.double())
print(ft.half())
>>  tensor([1., 2., 3.])
    tensor([1., 2., 3.], dtype=torch.float64)
    tensor([1., 2., 3.], dtype=torch.float16)

 

CUDA Tensors

  • .to 메소드를 사용하여 텐서를 어떠한 장치(cpu, gpu)로도 옮길 수 있음
x = torch.randn(1)
print(x)
print(x.item()) #  실제값
print(x.dtype)

>>  tensor([0.3407])
    0.34074530005455017
    torch.float32


device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # gpu check
print(device)
y = torch.ones_like(x, device= device)
print(y)
x = x.to(device)
print(x)
z = x + y
print(z) 
print(z.to('cpu', torch.double))

>>  cuda
    tensor([1.], device='cuda:0')
    tensor([0.3407], device='cuda:0')
    tensor([1.3407], device='cuda:0')
    tensor([1.3407], dtype=torch.float64)

 

다차원 텐서 표현

  • 0D Tensor(Scalar)
    • 하나의 숫자를 담고 있는 텐서(tensor)
    • 축과 형상이 없음
t0 = torch.tensor(0)
print(t0.ndim)
print(t0.shape)
print(t0)

>>  0
    torch.Size([])
    tensor(0)
  • 1D Tensor(Vector)
    • 값들을 저장한 리스트와 유사한 텐서
    • 하나의 축이 존재
t1 = torch.tensor([1,2,3])
print(t1.ndim)
print(t1.shape)
print(t1)

>>  1
    torch.Size([3])
    tensor([1, 2, 3])
  • 2D Tensor(Matrix)
    • 행렬과 같은 모양으로 두개의 축이 존재
    • 일반적인 수치, 통계 데이터셋이 해당
    • 주로 샘플(samples)과 특성(features)을 가진 구조로 사용

t2 = torch.tensor([[1,2,3], [4,5,6], [7,8,9]])
print(t2.ndim)
print(t2.shape)
print(t2)

>>  2
    torch.Size([3, 3])
    tensor([[1, 2, 3],
            [4, 5, 6],
            [7, 8, 9]])
  • 3D Tensor
    • 큐브(cube)와 같은 모양으로 세개의 축이 존재
    • 데이터가 연속된 시퀀스 데이터나 시간 축이 포함된 시계열 데이터에 해당
    • 주식 가격 데이터셋, 시간에 따른 질병 발병 데이터 등이 존재
    • 주로 샘플(samples), 타임스텝(timesteps), 특성(features)을 가진 구조로 사용

t3 = torch.tensor([[[1,2,3], 
                   [4,5,6], 
                   [7,8,9]],
                  [[1,2,3], 
                   [4,5,6], 
                   [7,8,9]],
                  [[1,2,3], 
                   [4,5,6], 
                   [7,8,9]]])
print(t3.ndim)
print(t3.shape)
print(t3)

>>  3
    torch.Size([3, 3, 3])
    tensor([[[1, 2, 3],
             [4, 5, 6],
             [7, 8, 9]],

            [[1, 2, 3],
             [4, 5, 6],
             [7, 8, 9]],

            [[1, 2, 3],
             [4, 5, 6],
             [7, 8, 9]]])    
  • 4D Tensor
    • 4개의 축
    • 컬러 이미지 데이터가 대표적인 사례 (흑백 이미지 데이터는 3D Tensor로 가능)
    • 주로 샘플(samples), 높이(height), 너비(width), 컬러 채널(channel)을 가진 구조로 사용

  • 5D Tensor
    • 5개의 축
    • 비디오 데이터가 대표적인 사례
    • 주로 샘플(samples), 프레임(frames), 높이(height), 너비(width), 컬러 채널(channel)을 가진 구조로 사용

 

텐서의 연산(Operations)

  • 텐서에 대한 수학 연산, 삼각함수, 비트 연산, 비교 연산, 집계 등 제공
import math

a = torch.rand(1, 2) * 2 -1
print(a)
print(torch.abs(a))
print(torch.ceil(a)) # 올림
print(torch.floor(a)) # 내림
print(torch.clamp(a, -0.5, 0.5)) # 최소값 -0.5 , 최대값 0.5로 값 범위를 조정

>>  tensor([[-0.6188,  0.1688]])
    tensor([[0.6188, 0.1688]])
    tensor([[-0., 1.]])
    tensor([[-1.,  0.]])
    tensor([[-0.5000,  0.1688]])

print(a)
print(torch.min(a))
print(torch.max(a))
print(torch.mean(a))
print(torch.std(a))
print(torch.prod(a)) # 곱셈
print(torch.unique(torch.tensor([1, 2, 3, 1, 2, 2])))

>>  tensor([[-0.6188,  0.1688]])
    tensor(-0.6188)
    tensor(0.1688)
    tensor(-0.2250)
    tensor(0.5569)
    tensor(-0.1044)
    tensor([1, 2, 3])
  • max와 min은 dim 인자를 줄 경우 argmax와 argmin도 함께 리턴
    • argmax : 최대값을 가진 인덱스
    • argmin : 최소값을 가진 인덱스
x = torch.rand(2, 2)
print(x)
print(x.max(dim=0))
print(x.max(dim=1))

>>  tensor([[0.4750, 0.1135],
        [0.5480, 0.9679]])
    torch.return_types.max(
    values=tensor([0.5480, 0.9679]),
    indices=tensor([1, 1]))
    torch.return_types.max(
    values=tensor([0.4750, 0.9679]),
    indices=tensor([0, 1]))

x = torch.rand(2, 2)
print(x)
print(x.min(dim=0))
print(x.min(dim=1))

>>  tensor([[0.0934, 0.3758],
            [0.1591, 0.9207]])
    torch.return_types.min(
    values=tensor([0.0934, 0.3758]),
    indices=tensor([0, 0]))
    torch.return_types.min(
    values=tensor([0.0934, 0.1591]),
    indices=tensor([0, 0]))


x = torch.rand(2, 2)
print(x)
y = torch.rand(2,2)
print(y)

>>  tensor([[0.7581, 0.5161],
            [0.0705, 0.6911]])
    tensor([[0.4239, 0.8904],
            [0.8143, 0.9730]])
  • torch.add : 덧셈
print(x + y)
print(torch.add(x,y))

>>  tensor([[1.1820, 1.4065],
            [0.8848, 1.6641]])
    tensor([[1.1820, 1.4065],
            [0.8848, 1.6641]])
  • 결과 텐서를 인자로 제공
result = torch.empty(2,4)
torch.add(x,y, out=result)
print(result)

>> tensor([[1.1820, 1.4065],
           [0.8848, 1.6641]])
  • in-place 방식
    • in-place 방식으로 텐서의 값을 변경하는 연산 뒤에는 _ 가 붙음
    • x.copy_(y), x.t_()
print(x)
print(y)
y.add_(x) # 두 덧셈을 앞에 변수로 할당
print(y) 

>>  tensor([[0.7581, 0.5161],
            [0.0705, 0.6911]])
    tensor([[0.4239, 0.8904],
            [0.8143, 0.9730]])
    tensor([[1.1820, 1.4065],
            [0.8848, 1.6641]])
  • torch.sub : 뺄셈
print(x)
print(y)
print(x-y)
print(torch.sub(x,y))
print(x.sub(y))

>>  tensor([[0.7581, 0.5161],
            [0.0705, 0.6911]])
    tensor([[1.1820, 1.4065],
            [0.8848, 1.6641]])
    tensor([[-0.4239, -0.8904],
            [-0.8143, -0.9730]])
    tensor([[-0.4239, -0.8904],
            [-0.8143, -0.9730]])
    tensor([[-0.4239, -0.8904],
            [-0.8143, -0.9730]])
  • torch.mul : 곱셈
print(x)
print(y)
print(x*y)
print(torch.mul(x,y))
print(x.mul(y))

>>  tensor([[0.7581, 0.5161],
            [0.0705, 0.6911]])
    tensor([[1.1820, 1.4065],
            [0.8848, 1.6641]])
    tensor([[0.8961, 0.7260],
            [0.0624, 1.1501]])
    tensor([[0.8961, 0.7260],
            [0.0624, 1.1501]])
    tensor([[0.8961, 0.7260],
            [0.0624, 1.1501]])
  • torch.div : 나눗셈
print(x)
print(y)
print(x/y)
print(torch.div(x,y))
print(x.div(y))

>>  tensor([[0.7581, 0.5161],
            [0.0705, 0.6911]])
    tensor([[1.1820, 1.4065],
            [0.8848, 1.6641]])
    tensor([[0.6414, 0.3670],
            [0.0797, 0.4153]])
    tensor([[0.6414, 0.3670],
            [0.0797, 0.4153]])
    tensor([[0.6414, 0.3670],
            [0.0797, 0.4153]])
  • torch.mm : 내적(dot product)
print(torch.matmul(x,y))
z = torch.mm(x,y)
print(z)
print(torch.svd(z))

>>  tensor([[1.3528, 1.9252],
            [0.6948, 1.2492]])
    tensor([[1.3528, 1.9252],
            [0.6948, 1.2492]])
    torch.return_types.svd(
    U=tensor([[-0.8552, -0.5182],
            [-0.5182,  0.8552]]),
    S=tensor([2.7502, 0.1281]),
    V=tensor([[-0.5516, -0.8341],
            [-0.8341,  0.5516]]))

 

텐서의 조작(Manipulations)

  • 인덱싱(Indexing) : NumPy처럼 인덱싱 형태로 사용가능
x = torch.Tensor([[1,2],
                  [3,4]])

print(x)

print(x[0,0])
print(x[0,1])
print(x[1,0])
print(x[1,1])

print(x[:,0])
print(x[:,1])

print(x[0,:])
print(x[1,:])


>>  tensor([[1., 2.],
            [3., 4.]])
    tensor(1.)
    tensor(2.)
    tensor(3.)
    tensor(4.)
    tensor([1., 3.])
    tensor([2., 4.])
    tensor([1., 2.])
    tensor([3., 4.])
  • view : 텐서의 크기(size)나 모양(shape)을 변경
    • 기본적으로 변경 전과 후에 텐서 안의 원소 개수가 유지되어야 함
    • -1로 설정되면 계산을 통해 해당 크기값을 유추
x = torch.randn(4,5)
print(x)

y = x.view(20)
print(y)

z = x.view(5,-1) # -1로 하면 알아서 계산
print(z)

>>  tensor([[-1.1282,  1.1669,  0.2316, -0.1395,  1.5400],
            [ 0.4419,  0.1169, -0.1603, -0.9421,  0.6196],
            [-1.8255, -0.3314,  0.8283, -0.3065, -2.6763],
            [-1.4101,  0.9791,  1.4486,  1.6158,  0.0582]])
    tensor([-1.1282,  1.1669,  0.2316, -0.1395,  1.5400,  0.4419,  0.1169, -0.1603,
            -0.9421,  0.6196, -1.8255, -0.3314,  0.8283, -0.3065, -2.6763, -1.4101,
             0.9791,  1.4486,  1.6158,  0.0582])
    tensor([[-1.1282,  1.1669,  0.2316, -0.1395],
            [ 1.5400,  0.4419,  0.1169, -0.1603],
            [-0.9421,  0.6196, -1.8255, -0.3314],
            [ 0.8283, -0.3065, -2.6763, -1.4101],
            [ 0.9791,  1.4486,  1.6158,  0.0582]])
  • item : 텐서에 값이 단 하나라도 존재하면 숫자값을 얻을 수 있음
    • 스칼라값 하나만 존재해야 item() 사용 가능
x = torch.randn(1)
print(x)
print(x.item())
print(x.dtype)

>>  tensor([-3.1644])
    -3.1643731594085693
    torch.float32
  • squeeze : 차원을 축소
tensor = torch.rand(1, 3, 3)
print(tensor)
print(tensor.shape)

>>  tensor([[[0.6248, 0.5859, 0.8387],
             [0.3797, 0.7793, 0.1828],
             [0.5774, 0.9446, 0.6532]]])
    torch.Size([1, 3, 3])


t = tensor.squeeze()
print(t)
print(t.shape)

>>  tensor([[0.6248, 0.5859, 0.8387],
            [0.3797, 0.7793, 0.1828],
            [0.5774, 0.9446, 0.6532]])
    torch.Size([3, 3])
  • unsqueeze : 차원을 증가
t = torch.rand(3, 3)
print(t)
print(t.shape)

>>  tensor([[0.4361, 0.1716, 0.9609],
            [0.2392, 0.6470, 0.6706],
            [0.1481, 0.6010, 0.1357]])
    torch.Size([3, 3])

tensor = t.unsqueeze(dim=0)
print(tensor)
print(tensor.shape)

>>  tensor([[[0.4361, 0.1716, 0.9609],
             [0.2392, 0.6470, 0.6706],
             [0.1481, 0.6010, 0.1357]]])
    torch.Size([1, 3, 3])


tensor = t.unsqueeze(dim=2)
print(tensor)
print(tensor.shape)

>>  tensor([[[0.4361],
             [0.1716],
             [0.9609]],

            [[0.2392],
             [0.6470],
             [0.6706]],

            [[0.1481],
             [0.6010],
             [0.1357]]])
    torch.Size([3, 3, 1])
  • stack : 텐서간 결합
x = torch.FloatTensor([1,4])
print(x)
y = torch.FloatTensor([2,5])
print(y)
z = torch.FloatTensor([3,6])
print(z)

print(torch.stack([x, y, z]))


>>  tensor([1., 4.])
    tensor([2., 5.])
    tensor([3., 6.])
    tensor([[1., 4.],
            [2., 5.],
            [3., 6.]])
  • cat : 텐서를 결합하는 메소드(concatenate)
    • 넘파이의 stack과 유사하지만, 쌓을 dim이 존재해야함
    • 해당 차원을 늘려준 후 결합
a = torch.randn(1,3,3)
print(a)
b = torch.randn(1,3,3)
print(b)
c = torch.cat((a,b), dim=0)
print(c)
print(c.size())

>>  tensor([[[-0.4074, -0.6053, -0.4368],
             [ 0.3416,  1.3137,  0.8975],
             [ 0.0699, -1.2002, -2.6423]]])
    tensor([[[ 0.8965, -0.7043, -3.1802],
             [-0.7097, -0.4769, -0.1803],
             [ 0.3862, -0.8335, -0.5471]]])
    tensor([[[-0.4074, -0.6053, -0.4368],
             [ 0.3416,  1.3137,  0.8975],
             [ 0.0699, -1.2002, -2.6423]],

            [[ 0.8965, -0.7043, -3.1802],
             [-0.7097, -0.4769, -0.1803],
             [ 0.3862, -0.8335, -0.5471]]])
    torch.Size([2, 3, 3])


c = torch.cat((a,b), dim=1)
print(c)
print(c.size())

>>  tensor([[[-0.4074, -0.6053, -0.4368],
             [ 0.3416,  1.3137,  0.8975],
             [ 0.0699, -1.2002, -2.6423],
             [ 0.8965, -0.7043, -3.1802],
             [-0.7097, -0.4769, -0.1803],
             [ 0.3862, -0.8335, -0.5471]]])
    torch.Size([1, 6, 3])

c = torch.cat((a,b), dim=2)
print(c)
print(c.size())

>>  tensor([[[-0.4074, -0.6053, -0.4368,  0.8965, -0.7043, -3.1802],
             [ 0.3416,  1.3137,  0.8975, -0.7097, -0.4769, -0.1803],
             [ 0.0699, -1.2002, -2.6423,  0.3862, -0.8335, -0.5471]]])
    torch.Size([1, 3, 6])
  • chunk : 텐서를 여러 개로 나눌 때 사용 (몇 개로 나눌 것인가?)
tensor = torch.rand(3, 6)
print(tensor)

t1, t2, t3 = torch.chunk(tensor, 3, dim=1) 
print(t1)
print(t2)
print(t3)


>>  tensor([[0.6369, 0.0903, 0.5728, 0.6568, 0.7805, 0.1588],
            [0.8261, 0.1895, 0.7192, 0.6303, 0.3786, 0.6664],
            [0.6631, 0.9095, 0.6214, 0.7038, 0.1065, 0.4323]])
    tensor([[0.6369, 0.0903],
            [0.8261, 0.1895],
            [0.6631, 0.9095]])
    tensor([[0.5728, 0.6568],
            [0.7192, 0.6303],
            [0.6214, 0.7038]])
    tensor([[0.7805, 0.1588],
            [0.3786, 0.6664],
            [0.1065, 0.4323]])
  • split : chunk와 동일한 기능이지만 조금 다름 (텐서의 크기는 몇인가?)
tensor = torch.rand(3,6)
t1 , t2 = torch.split(tensor, 3, dim= 1) 

print(tensor)
print(t1)
print(t2)

>>  tensor([[0.4166, 0.6668, 0.2096, 0.7406, 0.1294, 0.0474],
            [0.3829, 0.4303, 0.7670, 0.4424, 0.9527, 0.7197],
            [0.8575, 0.1119, 0.3283, 0.3013, 0.8005, 0.8648]])
    tensor([[0.4166, 0.6668, 0.2096],
            [0.3829, 0.4303, 0.7670],
            [0.8575, 0.1119, 0.3283]])
    tensor([[0.7406, 0.1294, 0.0474],
            [0.4424, 0.9527, 0.7197],
            [0.3013, 0.8005, 0.8648]])
  • torch <--> numpy

    • Torch Tensor(텐서)를 NumPy array(베열)로 변환 가능

      • numpy()
      • from_numpy()
    • Tensor가 CPU상에 있다면 Numpy 배열은 메모리 공간을 공유하므로 하나가 변하면, 다른 하나도 변함

    a = torch.ones(7)
    print(a)
    
    >> tensor([1., 1., 1., 1., 1., 1., 1.])
    
    b = a.numpy()
    print(b)
    
    >> [1. 1. 1. 1. 1. 1. 1.]
    
    a.add_(1)
    print(a)
    print(b)
    
    >> tensor([2., 2., 2., 2., 2., 2., 2.])
       [2. 2. 2. 2. 2. 2. 2.]
    
    

import numpy as np

a = np.ones(7)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)

[2. 2. 2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2., 2., 2.], dtype=torch.float64)



반응형

'Study > Self Education' 카테고리의 다른 글

Pytorch 기본기 - 3  (0) 2024.07.02
Pytorch 기본기 - 2  (0) 2024.07.02
핸즈온 머신러닝 - 14  (0) 2024.06.19
핸즈온 머신러닝 - 13  (0) 2024.06.19
핸즈온 머신러닝 - 12  (0) 2024.06.19