본문 바로가기
AI

파이토치

by 코낄2 2024. 1. 7.

1.파이토치(Pytorch)

파이토치(PyTorch)는 머신러닝과 딥러닝 분야에서 가장 널리 사용되는 오픈 소스 프레임워크 중 하나로, TensorFlow와 더불어 대중적으로 활용되고 있습니다. 초기에는 "Torch"라는 이름으로 루아(Lua) 언어를 기반으로 만들어졌으나, 파이썬 기반으로 변경된 것이 파이토치입니다. 이 프레임워크는 뉴욕대학교와 페이스북(현재는 메타로 알려져 있음)이 공동으로 개발하였으며, 현재는 머신러닝 및 딥러닝 업계에서 가장 대중적인 도구 중 하나로 자리매김하고 있습니다.

import torch

print(torch.__version__) // 2.1.0+cu121

 

 2. 텐서(Tensor)

텐서(Tensor) 다차원 배열로, 스칼라, 벡터, 행렬을 포함한 여러 차원의 숫자 데이터를 표현하는 수학적인 개념입니다. 텐서는 데이터를 효과적으로 표현하고 다루기 위한 중요한 도구로서 머신러닝과 딥러닝에서 널리 사용됩니다.

2-1. 스칼라

스칼라(Scalar)는 크기만 있고 방향이 없는 양을 나타내는 수학적 개념입니다. 스칼라는 하나의 실수 값으로만 표현되며, 크기만을 가지고 있어서 벡터나 행렬과 달리 방향이나 위치 정보가 없습니다.

var1 = torch.tensor([1])
var1 // tensor([1])
type(var1) // torch.Tensor

var2 = torch.tensor([10.4])
var2 // tensor([10.4000])
# 두 스칼라의 사칙 연산
print(var1 + var2) // tensor([11.4000])
print(var1 - var2) // tensor([-9.4000])
print(var1 * var2) // tensor([10.4000])
print(var1 / var2) // tensor([0.0962])

2-2. 벡터(Vector)

벡터(Vector)는 크기와 방향을 가지는 양을 나타내는 수학적 개념입니다. 벡터는 화살표로 시각적으로 나타낼 수 있으며, 화살표의 길이가 벡터의 크기를, 화살표의 방향이 벡터의 방향을 나타냅니다. 스칼라는 단일 데이터라면, 상수가 두개 이상 나열된 경우를 벡터라고 할 수 있습니다.

vec1 = torch.tensor([1,2,3])
vec1 // tensor([1, 2, 3])

vec2 = torch.tensor([1.5,2.4,3.3])
vec2 // tensor([1.5000, 2.4000, 3.3000])

print(vec1 + vec2) // tensor([2.5000, 4.4000, 6.3000])
print(vec1 - vec2) // tensor([-0.5000, -0.4000, -0.3000])
print(vec1 * vec2) // tensor([1.5000, 4.8000, 9.9000])
print(vec1 / vec2) // tensor([0.6667, 0.8333, 0.9091])
vec3 = torch.tensor([5, 10, 20, 30])
vec3 // tensor([ 5, 10, 20, 30])
#print(vec1 + vec3)

# 요소의 갯수가 맞지 않아서 에러 발생

# RuntimeError: The size of tensor a (3) must match the size of tensor b (4) at non-singleton dimension 0

vec3 + var1 // tensor([ 6, 11, 21, 31])

# 벡터에 스칼라를 사칙연산 할 경우 벡터의 각 성분에 스칼라를 대입

2-3. 행렬(Matrix)

2개 이상의 벡터값을 가지고 만들어진 값으로 행(row)과 열(column)로 이루어져 있습니다.

mat1 = torch.tensor([[1,2], [3,4]])
print(mat1)
tensor([[1, 2],
        [3, 4]])
        
mat2 = torch.tensor([[7,8], [9,10]])
print(mat2)
tensor([[ 7,  8],
        [ 9, 10]])
print(mat1 + mat2)
tensor([[ 8, 10],
        [12, 14]])
print(mat1 - mat2)
tensor([[-6, -6],
        [-6, -6]])
print(mat1 * mat2)
tensor([[ 7, 16],
        [27, 40]])
print(mat1 / mat2)
tensor([[0.1429, 0.2500],
        [0.3333, 0.4000]])
  1. 스칼라 곱셈: 행렬의 각 원소에 스칼라를 곱합니다.
  2. 행렬 곱셈 (Matrix Multiplication): 두 행렬 A와 B가 곱해질 때, A의 열과 B의 행의 크기가 일치해야 합니다. 결과 행렬 C의 는 A의 i번째 행과 B의 j번째 열의 내적입니다.

2-4. 텐서(Tensor)

텐서는 다차원 배열로, 여러 차원의 데이터를 효과적으로 표현하고 연산할 수 있는 도구로 활용됩니다. 텐서는 여러 개의 행렬이 모여 있는 자료구조로, 배열이나 행렬과 유사한 형태를 갖춘 특수한 데이터 형식입니다. 파이토치(PyTorch)는 모델의 입력과 출력, 그리고 모델의 매개변수들을 처리하기 위해 텐서를 사용합니다.

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

        [[5, 6],
         [7, 8]]])
         
tensor2 = torch.tensor([[[9,10],[11,12]],[[13,14],[15,16]]])
tensor([[[ 9, 10],
         [11, 12]],

        [[13, 14],
         [15, 16]]])
tensor3 = torch.tensor([[[[9, 10], [11, 12]], [[13, 14], [15, 16]]],[[[1,2],[3,4]], [[5,6],[7,8]]] ])

print(tensor3)
tensor([[[[ 9, 10],
          [11, 12]],

         [[13, 14],
          [15, 16]]],


        [[[ 1,  2],
          [ 3,  4]],

         [[ 5,  6],
          [ 7,  8]]]])
          
print(tensor3[0])
# = print(tensor3[0, :, :, :])
tensor([[[ 9, 10],
         [11, 12]],

        [[13, 14],
         [15, 16]]])
         
print(tensor3[1])
tensor([[[1, 2],
         [3, 4]],

        [[5, 6],
         [7, 8]]])
         
print(tensor3[0][0])
tensor([[ 9, 10],
        [11, 12]])
        
print(tensor3[0][0][0][0]) # 4차원
tensor(9)
print(tensor1 + tensor2)
tensor([[[10, 12],
         [14, 16]],

        [[18, 20],
         [22, 24]]])
         
print(tensor1 - tensor2)
tensor([[[-8, -8],
         [-8, -8]],

        [[-8, -8],
         [-8, -8]]])
         
print(tensor1 * tensor2)
tensor([[[  9,  20],
         [ 33,  48]],

        [[ 65,  84],
         [105, 128]]])
         
print(tensor1 / tensor2)
tensor([[[0.1111, 0.2000],
         [0.2727, 0.3333]],

        [[0.3846, 0.4286],
         [0.4667, 0.5000]]])
print(torch.add(tensor1,tensor2))
tensor([[[10, 12],
         [14, 16]],

        [[18, 20],
         [22, 24]]])
         
print(torch.subtract(tensor1,tensor2))
tensor([[[-8, -8],
         [-8, -8]],

        [[-8, -8],
         [-8, -8]]])
         
print(torch.multiply(tensor1,tensor2))
tensor([[[  9,  20],
         [ 33,  48]],

        [[ 65,  84],
         [105, 128]]])
         
print(torch.divide(tensor1,tensor2))
tensor([[[0.1111, 0.2000],
         [0.2727, 0.3333]],

        [[0.3846, 0.4286],
         [0.4667, 0.5000]]])
         
print(torch.matmul(tensor1,tensor2)) # 행렬곱
tensor([[[ 31,  34],
         [ 71,  78]],

        [[155, 166],
         [211, 226]]])

# inplace 사칙연산 함수.

# tensor1에 결과를 다시 저장. 모든 사칙연산자에 _를 붙이면 inplace가 된다.

print(tensor1.add_(tensor2)) # inplace함수. add_ 적용된 값이 저장이 된다.
tensor([[[10, 12],
         [14, 16]],

        [[18, 20],
         [22, 24]]])
         
print(tensor1)
tensor([[[10, 12],
         [14, 16]],

        [[18, 20],
         [22, 24]]])

3. 텐서의 변환

import numpy as np
data = [[1,2], [3,4]]
print(data) // [[1, 2], [3, 4]]
print(type(data)) // <class 'list'>

x_data = torch.tensor(data)
print(x_data) // tensor([[1, 2],
        		[3, 4]])
np_array = np.array(x_data)
np_array // array([[1, 2],
       		   [3, 4]])
               
x_np_1 = torch.tensor(np_array)
x_np_1 // tensor([[1, 2],
        	  [3, 4]])
x_np_1[0,0] = 100
x_np_1
tensor([[100,   2],
        [  3,   4]])
        
np_array
array([[1, 2],
       [3, 4]])

 

✔️ as_tensorfrom_numpy 함수

- torch.as_tensor : 파이썬 리스트, NumPy 배열, 또는 다른 array-like 객체를 PyTorch 텐서로 변환합니다. 주어진 데이터의 메모리를 공유하며 텐서를 생성합니다. 따라서 원본 데이터의 변화는 새로운 텐서에도 영향을 미칩니다.

- torch.from_numpy : NumPy 배열을 PyTorch 텐서로 변환합니다. NumPy 배열과 PyTorch 텐서 사이에서 데이터를 공유합니다. 따라서 원본 NumPy 배열의 데이터가 변경되면 PyTorch 텐서에도 영향을 미칩니다.

# as_tensor: ndarray와 동일한 메모리 주소를 가리키는 뷰를 만듦
# 자료구조가 다양하게 들어갈 수 있음
x_np_2 = torch.as_tensor(np_array)
print(x_np_2)
tensor([[1, 2],
        [3, 4]])
        
x_np_2[0,0] = 200
print(x_np_2)
tensor([[200,   2],
        [  3,   4]])
        
print(np_array)
[[200   2]
 [  3   4]]
# from_numpy: ndarray와 동일한 메모리 주소를 가리키는 뷰를 만듦
# ndarray형식만 넣을 수 있음
x_np_3 = torch.from_numpy(np_array)
print(x_np_3)
tensor([[200,   2],
        [  3,   4]])
        
x_np_3[0,0] = 300
print(x_np_3)
tensor([[300,   2],
        [  3,   4]])
        
print(np_array)
[[300   2]
 [  3   4]]

.numpy()는 PyTorch 텐서를 NumPy 배열로 변환하는 메서드입니다. 이 메서드를 호출하면 PyTorch 텐서와 NumPy 배열이 같은 메모리를 공유하게 됩니다. 따라서 .numpy()를 통해 얻은 NumPy 배열을 수정하면 해당 변경 사항이 원래의 PyTorch 텐서에도 반영됩니다.

np_again = x_np_1.numpy()
print(np_again, type(np_again))
[[100   2]
 [  3   4]] <class 'numpy.ndarray'>

4.파이토치 주요 함수

a = torch.ones(2,3)
print(a)
tensor([[1., 1., 1.],
        [1., 1., 1.]])
        
b = torch.zeros(2,3)
print(b)
tensor([[0., 0., 0.],
        [0., 0., 0.]])
        
c = torch.full((2,3),10)
print(c)
tensor([[10, 10, 10],
        [10, 10, 10]])
        
d = torch.empty(2,3)
print(d)
tensor([[1.0812e-05, 1.3000e+22, 2.1707e-18],
        [4.5447e+30, 7.0062e+22, 2.1715e-18]])
#초기화되지 않은 상태이기 때문에 그 안에 들어있는 값은 메모리 상의 이전 데이터나 쓰레기 값
# 가로,세로 같은 정방행렬만 만듬
e = torch.eye(5)
print(e)
tensor([[1., 0., 0., 0., 0.],
        [0., 1., 0., 0., 0.],
        [0., 0., 1., 0., 0.],
        [0., 0., 0., 1., 0.],
        [0., 0., 0., 0., 1.]])
        
f = torch.arange(10)
print(f) // tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

g = torch.rand(2,3)
print(g)
tensor([[0.8342, 0.6067, 0.6443],
        [0.3586, 0.4334, 0.7566]]) # random값(0~1사이)을 채움
        
# 정규분포식을 따르는 난수 생성
h = torch.randn(2,3)
print(h)
tensor([[-1.2786, -0.5648, -0.7582],
        [ 0.1961, -0.3943,  0.9738]])
        
i = torch.arange(16).reshape(2,2,4)  # 맨 앞이 면, 뒤가 행렬
print(i)
tensor([[[ 0,  1,  2,  3],
         [ 4,  5,  6,  7]],

        [[ 8,  9, 10, 11],
         [12, 13, 14, 15]]]) 
# 각 "면"에는 2개의 "행렬"이 있고, 각 "행렬"에는 2개의 "행"과 4개의 "열"이 있음
         
print(i.shape) // torch.Size([2, 2, 4])
# 차원을 지정한 인덱스로 변환
# 2, 2, 4
j = i.permute((2,0,1)) # 2, 2, 4 -> 4, 2, 2

print(j, j.shape)
tensor([[[ 0,  4],
         [ 8, 12]],

        [[ 1,  5],
         [ 9, 13]],

        [[ 2,  6],
         [10, 14]],

        [[ 3,  7],
         [11, 15]]]) torch.Size([4, 2, 2])
# 안에 요소 들어가는 방향은 세로 열방향으로 감

5. 텐서의 인덱싱과 슬라이싱

✔️ 인덱싱은 차원이 낮아지고, 슬라이싱은 유지된다.

a = torch.arange(1,13).reshape(3,4)
print(a)
tensor([[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9, 10, 11, 12]])
        
print(a[1]) // tensor([5, 6, 7, 8])

print(a[0, -1]) // tensor(4)

print(a[1:-1]) //tensor([[5, 6, 7, 8]])
# 차원 유지

print(a[:2, 2:]) // tensor([[3, 4],
        		   [7, 8]])

6. 코랩의 GPU 사용

✔️코랩에서 device 변경하는 방법
[상단 메뉴 -> 런타임 -> 런타임 유형변경 -> 하드웨어 가속기를 GPU로 변경 -> 저장 -> 세션 다시 시작 및 모두 실행]

tensor = torch.rand(3,4)
print(f'shape: {tensor.shape}') // shape: torch.Size([3, 4])
print(f'dtype: {tensor.dtype}') // dtype: torch.float32
print(f'device: {tensor.device}') // device: cpu
# is_available() : gpu 사용할 수 있는지 여부
tensor = tensor.reshape(4,3)
tensor = tensor.int()

if torch.cuda.is_available():
    print('GPU를 사용할 수 있음')
    tensor = tensor.to('cuda') # GPU로 보내줘야 GPU에서 연산
// GPU를 사용할 수 있음

print(f'shape: {tensor.shape}') // shape: torch.Size([4, 3])
print(f'dtype: {tensor.dtype}') // dtype: torch.int32
print(f'device: {tensor.device}') // device: cuda:0

'AI' 카테고리의 다른 글

기온에 따른 지면 온도 예측  (0) 2024.01.08
파이토치로 구현한 선형회귀  (1) 2024.01.08
KMeans  (0) 2024.01.05
다양한 모델 적용  (1) 2024.01.05
lightGBM  (1) 2024.01.01