텐서(Tensor)란?
넘파이 라이브러리의 ndarray 클래스와 유사한 구조로 배열이나 행렬과 유사한 자료 구조(자료형)이다. 파이토치에서는 텐서를 사용하여 모델의 입출력뿐만 아니라 모델의 매개변수를 부호화(Encode)하고 GPU를 활용해 연산을 가속화 할 수 있다.
공통점
수학 계산, 선형 대수 연산을 비롯해 전치, 인덱싱, 슬라이싱, random 샘플링 등 다양한 텐서 연산을 진핼할 수 있다.
차이점
CPU에서 사용하는 텐서와 GPU에서 사용하는 텐서의 선언 방식에 있다. 파이토치는 CPU 텐서와 GPU 텐서로 나눠지고, 각각의 텐서를 상호 변환하거나 GPU 사용 여부를 설정한다.
텐서 생성
텐서 생성 방법
- torch.tensor()
- 입력된 데이터를 복사해 텐서로 변환하는 함수
- 데이터를 복사하기 때문에 값이 무조건 존재해야 하며 입력된 데이터의 형식에 가장 적합한 텐서 자료형을 변환
- torch.Tensor()
- 위와는 달리 대문자로 텐서의 기본형으로 텐서 인스턴스를 생성하는 클래스
- 인스턴스를 생성하기 때문에 값을 입력하지 않는 경우 비어 있는 텐서를 생성
import torch
print(torch.tensor([1, 2, 3]))
print(torch.Tensor([[1, 2, 3], [4, 5, 6]]))
print(torch.LongTensor([1, 2, 3]))
print(torch.FloatTensor([1, 2, 3]))
출력 결과
tensor([1, 2, 3])
tensor([[1., 2., 3.],
[4., 5., 6.]])
tensor([1, 2, 3])
tensor([1., 2., 3.])
- torch.tensor()는 자동으로 자료형을 할당하므로 입력된 데이터 형식을 참조해 Int 형식으로 할당
- torch.Tensor()는 입력된 데이터 형식이 Int형이지만 기본 유형이 Float이므로 정수형을 할당하더라도 소수점 형태로 변환됨
- 나머지는 torch.Tensor 클래스를 상속받은 데이터 형식으로 데이터 형식이 미리 선언된 클래스
텐서 속성
tensor의 attribute는 크게 shape, dtype, device가 존재한다. device는 텐서의 GPU 가속 여부를 의미한다.
tensor = torch.rand(1, 2)
print(tensor)
print(tensor.shape)
print(tensor.dtype)
print(tensor.device)
출력 결과
tensor([[0.8762, 0.3570]])
torch.Size([1, 2])
torch.float32
cpu
- torch.rand()는 [0, 1) 범위 무작위 수를 균등 분포로 생성하는 함수
- 매개변수로 사용한 1, 2는 생성하려는 텐서의 shape
- GPU 가속 여부를 설정하지 않았기 때문에 CPU 장치를 사용해 연산
차원 변환
tensor = torch.rand(1, 2)
print(tensor)
print(tensor.shape)
tensor = tensor.reshape(2, 1)
print(tensor)
print(tensor.shape)
출력 결과
tensor([[0.2289, 0.6758]])
torch.Size([1, 2])
tensor([[0.2289],
[0.6758]])
torch.Size([2, 1])
- 넘파이와 동일하게 reshape 메서드를 활용
자료형 설정
tensor = torch.rand((3, 3), dtype=torch.float)
print(tensor)
출력 결과
tensor([[0.7365, 0.6395, 0.6307],
[0.4247, 0.4115, 0.1165],
[0.6340, 0.0942, 0.4023]])
- 텐서의 자료형 설정에 입력되는 인수는 torch.* 형태로 할당
- torch.float이 아닌 float을 할당해도 오류 없이 작동하지만, 전자는 32비트 부동 소수점, 후자는 64비트 부동 소수점 형식을 갖는다.
device 설정
device = 'cuda' if torch.cuda.is_available() else 'cpu'
cpu = torch.FloatTensor([1, 2, 3])
gpu = torch.tensor([1, 2, 3], dtype=torch.float, device=device)
tensor = torch.rand((1, 1), device=device)
print(device)
print(cpu)
print(gpu)
print(tensor)
출력 결과
cuda
tensor([1., 2., 3.])
tensor([1., 2., 3.], device='cuda:0')
tensor([[0.5365]], device='cuda:0')
- device 매개변수에 장치 속성을 할당해 설정할 수 있다.
- 추가적으로 책에서는 gpu를 torch.cuda.FloatTensor([1, 2, 3])과 같은 방식으로 사용했는데 warning이 발생했고 torch과 위와 같이 torch.cuda 보다는 device를 직접 할당하는 방식을 권장하였다.
device 변환
cpu = torch.FloatTensor([1, 2, 3])
gpu = cpu.cuda()
gpu2cpu = gpu.cpu()
cpu2gpu = cpu.to(device)
print(cpu)
print(gpu)
print(gpu2cpu)
print(cpu2gpu)
출력 결과
tensor([1., 2., 3.])
tensor([1., 2., 3.], device='cuda:0')
tensor([1., 2., 3.])
tensor([1., 2., 3.], device='cuda:0')
- cpu 텐서를 gpu로 변환하는 방법은 cuda 메서드를 사용하거나 to 메서드로 to('cuda')와 같은 방법으로 사용할 수 있다.
넘파이 배열의 텐서 변환
import numpy as np
ndarray = np.array([1, 2, 3], dtype=np.uint8)
print(torch.tensor(ndarray))
print(torch.Tensor(ndarray))
print(torch.from_numpy(ndarray))
출력 결과
tensor([1, 2, 3], dtype=torch.uint8)
tensor([1., 2., 3.])
tensor([1, 2, 3], dtype=torch.uint8)
텐서의 넘파이 배열 변환
tensor = torch.tensor([1, 2, 3], dtype=torch.float, device=device)
ndarray = tensor.detach().cpu().numpy()
print(ndarray)
print(type(ndarray))
출력 결과
[1. 2. 3.]
<class 'numpy.ndarray'>
- numpy 메서드를 사용
- detach 메서드를 사용하는 이유는 텐서는 기존 데이터 형식과 다르게 학습을 위한 데이터 형식으로 모든 연산을 추적해 기록한다. 따라서 detach 메서드를 사용해 현재 연산 그래프에서 분리된 새로운 텐서를 반환한다.
- GPU 텐서라면 CPU 텐서로 변환한 다음에 넘파이 배열로 변환해야 한다.
'책 > 파이토치 트랜스포머를 활용한 자연어 처리와 컴퓨터비전 심층학습' 카테고리의 다른 글
03 파이토치 기초 (6) 퍼셉트론 (0) | 2024.01.04 |
---|---|
03 파이토치 기초 (5) 활성화 함수 (0) | 2024.01.04 |
03 파이토치 기초 (4) 데이터세트와 데이터로더, 모델 저장 및 불러오기 (0) | 2023.12.19 |
03 파이토치 기초 (3) 손실 함수, 최적화 (0) | 2023.12.16 |
03 파이토치 기초 (2) 가설 (0) | 2023.12.14 |