파이토치(기본)

짬그브·2025년 3월 24일

개요

PyTorch는 2016년 10월에 Python을 위한 오픈소스 머신 러닝 라이브러리이다.
PyTorch는 파이썬 기반의 오픈 소스 머신러닝 라이브러리로, 페이스북 인공지능 연구집단에 의해개발되었다.
간결하고 구현이 빨리되며, 텐서플로우보다 사용자가 익히기 훨씬 쉽다는 특징이있다.
텐서플로우와 Pytorch의 가장 큰 차이점은 딥러닝을 구현하는 패러다임이 다르다는 것이다. 텐서플로우는 Define-and-Run 프레임워크인 반면에, Pytorch는 Define-by-Run이다.
Define and Run는코드를 직접 돌리는 환경인 세션을 만들고, placeholder를 선언하고 이것으로계산 그래프를 만들고(Define), 코드를 실행하는 시점에 데이터를 넣어 실행하는(Run) 방식. 이는 계산 그래프를 명확히 보여주면서 실행시점에 데이터만 바꿔줘도 되는 유연함을 장점으로 갖지만, 그 자체로 비직관적이다. 그래서 딥러닝 프레임워크 중 난이도가 가장 높은 편이다.
Pytorch는 언어 자체에 대한 어려움은 없다. 일반적인 파이썬 코딩과 비슷하기 때문이다. 선언과동시에 데이터를 집어넣고 세션도 필요없이 돌리면 끝이다. 덕분에 코드가 간결하고 난이도가 낮은편이다. 사용자가 아직 적어 구글링으로 공부하기 힘든 환경에 있지만 이는 시간이 해결해 줄 문제이다.

PyTorch

파이토치 설치

https://pytorch.org/

접속후 최신버전말고 이전 버전 사용을 위해

Previous versions of PyTorch 선택

2.4 버전 cpu only 복사

pip install torch==2.4.0 torchvision==0.19.0 torchaudio==2.4.0 --index-url https://download.pytorch.org/whl/cpu

프로젝트 설정에서 파이썬 인터프리터 설치 완료된거 확인

테스트 실행

출력은 되지만 버전 충돌 😅

numpy 버전 바꿔주기 😊

PyTorch 패키지

Torch

main namespace로 tensor 등의 다양한 수학 함수가 패키지에 포함되어 있다.
Numpy와 같은 구조를 가지고 있어서 numpy와 상당히 비슷한 문법 구조를 가지고 있다.

Torch.autograd

자동 미분을 위한 함수가 포함되어 있다.
자동 미분의 on, off를 제어하는 enable_grad 또는 no_grad 나 자체 미분 가능 함수를 정의할 때 사용하는 기반 클래스인 Function등이 포함되어 있다.

Torch.nn

신경망을 구축하기 위한 다양한 데이터 구조나 레이어가 정의되어 있다.
CNN,LSTM, 활성화 함수(ReLu), loss 등이 정의되어 있다.

Torch.optim

SGD 등의 파라미터 최적화 알고리즘 등이 구현되어 있다.

Torch.utils.data

Gradient Descent 계열의 반복 연산을 할 때, 사용하는 미니 배치용 유틸리티 함수가 포함되어 있다.

Torch.onnx

ONNX(Open Neural Network eXchange) 포맷으로 모델을 export 할 때 사용한다.
ONNX는 서로 다른 딥러닝 프레임워크 간에 모델을 공유할 때 사용하는 새로운 포맷이다.

Tensor

텐서는 파이토치의 가장 기본이 되는 데이터 구조와 기능을 제공하는 다차원 배열을 처리하기 위한 데이터 구조이다.
API 형태는 Numpy 의 ndarray 와 비슷하며 GPU를 사용하는 계산도 지원합니다.

텐서는 각 데이터 형태별로 정의되어 있습니다.

torch.FloatTensor : 32비트 부동소수점
torch.DoubleTensor : 64비트 부동소수점
torch.ByteTensor : 8비트 정수
torch.charTensor : 8비트 정수
torch.shortTensor: 16비트 정수
torch.intTensor : 32비트 정수
torch.LongTensor : 64비트 정수

import torch

t1 = torch.FloatTensor([[1,2],[3,4]])
print(t1)
print(type(t1))
print(t1.size())
print()

t2 = torch.tensor([[1,2],[3,4]],dtype=torch.float32)
print(t2)
print(type(t2))
print()

print(t2.numpy())
print(type(t2.numpy()))
print()

import numpy as np

ndata =  np.array([[1,2,3,4],[5,6,7,8]], dtype=np.float32)
t3 = torch.from_numpy(ndata)
print(t3)



tensor([[1., 2.],
        [3., 4.]])
<class 'torch.Tensor'>
torch.Size([2, 2])

tensor([[1., 2.],
        [3., 4.]])
<class 'torch.Tensor'>

[[1. 2.]
 [3. 4.]]
<class 'numpy.ndarray'>

tensor([[1., 2., 3., 4.],
        [5., 6., 7., 8.]])

Tensor 연산

텐서는 Numpy의 ndarray와 같이 다양한 수학 연산이 가능하다.
텐서에서의 사칙연산은 같은 타입의 텐서 간 또는 텐서와 파이썬의 스칼라 값 사이에서만 가능하다.
텐서간이라도 타입이 다르면 연산이 되지 않는다.
FloatTensor와 Double Tensor간의 사칙연산은 오류가 발생한다.
스칼라 값을 연산할 때에는 기본적으로 broadcasting이 지원된다.

import torch

t1 = torch.tensor([1,2,3])
t2 = torch.tensor([5,6,7])
print(t1)
print(t2)
print()

t3 = t1 +30
print(t3)
print()

t4 = t1 + t2
print(t4)
print()

t5 = torch.tensor([[10,20,30],[40,50,60]])
print(t5)
print()

print(t5 + t1)


tensor([1, 2, 3])
tensor([5, 6, 7])

tensor([31, 32, 33])

tensor([ 6,  8, 10])

tensor([[10, 20, 30],
        [40, 50, 60]])

tensor([[11, 22, 33],
        [41, 52, 63]])

수학 함수 적용

텐서에는 다양한 수학 함수가 사용되고 방법은 numpy의 ndarray 와 유사하다.
자주 사용되는 수학 함수 : abs, sin, cos, exp, log, sqrt
집계 함수 : sum, max, min, mean, std
ndarry 와 마찬가지로 dimension을 지정해주면 어떤 기준으로 집계를 할지 정할 수 있다.

import torch

t1 = torch.linspace(0,3,10)
print(t1)
print()
print(torch.exp(t1))
print(torch.log(t1))
print(torch.cos(t1))
print(torch.sqrt(t1))
print(torch.mean(t1))
print(torch.std(t1))
print()

t2 = torch.tensor([[2,4,6],[7,3,5]])
print(t2)
print()

print(torch.max(t2))
print()

print(torch.max(t2, dim=1))  # axis = 1
print()

print(torch.max(t2,dim=1)[0])  # value 값
print(torch.max(t2,dim=1)[1])  # index 값


tensor([0.0000, 0.3333, 0.6667, 1.0000, 1.3333, 1.6667, 2.0000, 2.3333, 2.6667,
        3.0000])

tensor([ 1.0000,  1.3956,  1.9477,  2.7183,  3.7937,  5.2945,  7.3891, 10.3123,
        14.3919, 20.0855])
tensor([   -inf, -1.0986, -0.4055,  0.0000,  0.2877,  0.5108,  0.6931,  0.8473,
         0.9808,  1.0986])
tensor([ 1.0000,  0.9450,  0.7859,  0.5403,  0.2352, -0.0957, -0.4161, -0.6908,
        -0.8893, -0.9900])
tensor([0.0000, 0.5774, 0.8165, 1.0000, 1.1547, 1.2910, 1.4142, 1.5275, 1.6330,
        1.7321])
tensor(1.5000)
tensor(1.0092)

tensor([[2, 4, 6],
        [7, 3, 5]])

tensor(7)

torch.return_types.max(
values=tensor([6, 7]),
indices=tensor([2, 0]))

tensor([6, 7])
tensor([2, 0])

Tensor 차원

텐서의 차원을 변경하는 view나 텐서를 결합하는 stack, cat, 차원을 교환하는 t, transpose 도 사용된다.
View는 numpy의 reshape와 유사하다. 물론 pytorch에도 reshape 기능이 있으므로 view 를 사용하던지 reshape을 사용하던지 사용방법은 같으므로 선택해서 사용하면 된다.
cat은 다른 길이의 텐서를 하나로 묶을 때 사용한다.
transpose는 행렬의 전치 외에도 차원의 순서를 변경할 때에도 사용된다.

import torch

t1 = torch.tensor([1,2,3,4,5,6])
print(t1)
print()

t2 = t1.view(2,3)
print(t2)
print()

print(t1.reshape(2,3))
print()

t3 = torch.tensor([[1,2],[3,4],[5,6]])
print(t3)
print(t3.size())
print()
print(t3.view(-1))
print()
print(t3.view(1,-1))
print()
print(t3.view(2,-1))
print()
print(t3.view(3,-1))
print()

t4 = torch.tensor([[[1,2],[4,5]],[[5,6],[7,8]]])
print(t4)
print(t4.size())
print()
print(t4.view(-1))
print()
print(t4.view(1,-1))
print()
print(t4.view(2,-1))
print()
print(t4.view(4,-1))
print()
print(t4.view(2,4,-1))
print()
print(t4.view(2,2,-1))
print()

tensor([1, 2, 3, 4, 5, 6])

tensor([[1, 2, 3],
        [4, 5, 6]])

tensor([[1, 2, 3],
        [4, 5, 6]])

tensor([[1, 2],
        [3, 4],
        [5, 6]])
torch.Size([3, 2])

tensor([1, 2, 3, 4, 5, 6])

tensor([[1, 2, 3, 4, 5, 6]])

tensor([[1, 2, 3],
        [4, 5, 6]])

tensor([[1, 2],
        [3, 4],
        [5, 6]])

tensor([[[1, 2],
         [4, 5]],

        [[5, 6],
         [7, 8]]])
torch.Size([2, 2, 2])

tensor([1, 2, 4, 5, 5, 6, 7, 8])

tensor([[1, 2, 4, 5, 5, 6, 7, 8]])

tensor([[1, 2, 4, 5],
        [5, 6, 7, 8]])

tensor([[1, 2],
        [4, 5],
        [5, 6],
        [7, 8]])

tensor([[[1],
         [2],
         [4],
         [5]],

        [[5],
         [6],
         [7],
         [8]]])

tensor([[[1, 2],
         [4, 5]],

        [[5, 6],
         [7, 8]]])

선형 대수

dot : 벡터 내적
mv : 행렬과 벡터의 곱
mm : 행렬과 행렬의 곱
matmul : 인수의 종류에 따라서 자동으로 dot,mv,mm을 선택한다.

import torch

t1 = torch.tensor([1,2,3,4,5,6]).view(3,2)
t2 = torch.tensor([7,8,9,10,11,12]).view(2,3)
print(t1)
print()
print(t2)
print()

t3 = torch.mm(t1, t2)
print(t3)
print()

t4 = torch.matmul(t1, t2)
print(t4)
print()

tensor([[1, 2],
        [3, 4],
        [5, 6]])

tensor([[ 7,  8,  9],
        [10, 11, 12]])

tensor([[ 27,  30,  33],
        [ 61,  68,  75],
        [ 95, 106, 117]])

tensor([[ 27,  30,  33],
        [ 61,  68,  75],
        [ 95, 106, 117]])

slicing

slicing 기능은 Tensor를 몇개의 부분으로 나누는 기능이다.

torch.chunk(tensor, chunks, dim=0) 또는 torch.split(tensor,split_size,dim=0) 함수를 이용하여 Tensor을 나눌 수 있다.

import torch

t1 = torch.tensor([[1,2,3],[4,5,6]])
print(t1)
print()

print(t1[:,:2])
print()

print(t1 > 4)
print()

print(t1[t1 > 4])
print()

t1[:,2] = 40
print(t1)
print()

t1[t1 > 4] = 100
print(t1)
print()

t2 = torch.tensor([[1,2,3],[5,6,7]])
t3 = torch.tensor([[8,9,10],[11,22,33]])
print(t2)
print()
print(t3)
print()

t4 = torch.cat([t2,t3],dim=0)
print(t4)
print()

# print(torch.chunk(t4,4,dim=0)
for c in torch.chunk(t4, 4, dim=0):
    print(c,end='\n\n')
print()

for c in torch.chunk(t4,3,dim=1):
    print(c,end='\n\n')

tensor([[1, 2, 3],
        [4, 5, 6]])

tensor([[1, 2],
        [4, 5]])

tensor([[False, False, False],
        [False,  True,  True]])

tensor([5, 6])

tensor([[ 1,  2, 40],
        [ 4,  5, 40]])

tensor([[  1,   2, 100],
        [  4, 100, 100]])

tensor([[1, 2, 3],
        [5, 6, 7]])

tensor([[ 8,  9, 10],
        [11, 22, 33]])

tensor([[ 1,  2,  3],
        [ 5,  6,  7],
        [ 8,  9, 10],
        [11, 22, 33]])

tensor([[1, 2, 3]])

tensor([[5, 6, 7]])

tensor([[ 8,  9, 10]])

tensor([[11, 22, 33]])


tensor([[ 1],
        [ 5],
        [ 8],
        [11]])

tensor([[ 2],
        [ 6],
        [ 9],
        [22]])

tensor([[ 3],
        [ 7],
        [10],
        [33]])

Initialization

init.uniform 함수를 사용하면 uniform 또는 normal 분포의 초기화 Tensor를 만들 수 있다.

또는 상수 형태를 바로 만들 수도 있다

import torch
import torch.nn.init as init

t1 = init.uniform_(torch.FloatTensor(3,4))
print(t1)
print()

t2 = init.normal_(torch.FloatTensor(3,4), mean=10, std=3)
print(t2)
print()

t3 = torch.FloatTensor(torch.randn(3,4))
print(t3)
print()

t4 = init.constant_(torch.FloatTensor(3,4), 100)
print(t4)

tensor([[0.7733, 0.7128, 0.8233, 0.1200],
        [0.0776, 0.9087, 0.4015, 0.6896],
        [0.9619, 0.5858, 0.8912, 0.2399]])

tensor([[11.9978, 12.4279, 12.9222, 12.9241],
        [ 6.1128,  7.5136,  8.7303, 10.9977],
        [14.2118, 13.4922,  7.6337, 11.0582]])

tensor([[ 1.0217, -0.9942,  1.3620, -0.8305],
        [ 0.0568,  1.0609, -0.1637,  0.4428],
        [ 0.7129, -0.1754, -0.2601,  1.0663]])

tensor([[100., 100., 100., 100.],
        [100., 100., 100., 100.],
        [100., 100., 100., 100.]])

squeezing

squeeze 함수를 사용하면 dimension 중에 1로 되어 있는 것을 압축할 수 있다.

dimension이 1이면 사실 불필요한 차원일 수 있기 때문에 squeeze를 이용하여 압축 시키는 것이 때론 필요할 수 있는데, 그 때 사용하는 함수 이다.

torch.squeeze(input, dim)으로 사용할 수 있고, dim을 지정하지 않으면 dimension이 1인 모든 차원을 압축하고 dim을 지정하면 지정한 dimension만 압축한다.

반면 unsqueeze 함수를 사용하면 dimension을 추가할 수 있다

unsqueeze 함수는 dimension을 반드시 입력 받게 되어 있다.

import torch

t1 = torch.zeros(1,4)
t2 = torch.zeros(4,1)
print(t1)
print()
print(t2)
print()

print(torch.squeeze(t1))
print(torch.squeeze(t2))
print()

t2 = torch.zeros(2,1,3,1,4)
print(t2.size())
print(torch.squeeze(t2).size())
print(torch.squeeze(t2, dim=3).size())
print()

t3 = torch.zeros(2,3)
print(t3.size())
print(torch.unsqueeze(t3, dim=0).size())
print(torch.unsqueeze(t3, dim=1).size())
print(torch.unsqueeze(t3, dim=2).size())



tensor([[0., 0., 0., 0.]])

tensor([[0.],
        [0.],
        [0.],
        [0.]])

tensor([0., 0., 0., 0.])
tensor([0., 0., 0., 0.])

torch.Size([2, 1, 3, 1, 4])
torch.Size([2, 3, 4])
torch.Size([2, 1, 3, 4])

torch.Size([2, 3])
torch.Size([1, 2, 3])
torch.Size([2, 1, 3])
torch.Size([2, 3, 1])
profile
+AI to AI+

0개의 댓글