Naver boostcamp -ai tech/week 02

PyTorch Tensor(텐서)

끵뀐꿩긘 2022. 9. 29. 17:58
import torch
torch.__version__

>>> '1.12.1+cu113'

Tensor란

 - 다차원 Array를 표현하는 PyTorch 클래스, 이를 사용하여 모델의 입력, 출력 그리고 모델의 매개변수들을 부호화한다

 - 배열(array)나 행렬(matrix)와 매우 유사한 특수한 자료구조 마치 Numpy의 ndarray

 - GPU나 다른 하드웨어 가속기에서 실행할 수 있으며, 자동미분에 최적화 되어있다

 

# 텐서의 사이즈 반환
torch.Tensor.shape # torch.shape[0] # 0차원의 size
torch.Tensor.size() # torch.size(0) # 0차원의 size

torch.Tensor.dim() # 차원의 개수
torch.is_tensor(torch.tensor([1])) # 텐서인가? true
torch.numel(torch.zeros(4,4)) # 텐서의 총 요소 개수 반환 , 16
torch.is_nonzero([0.]) # 0이 아닌 단일 요소 텐서이면 True, torch.numel() != 1d이면 error

torch.Tensor.detach().clone() # 텐서 복사

 

 

Tensor 초기화/ 선언

- 데이터로부터 직접 생성하기

data = [[1,2], [3,4]]
torch.tensor(data)
>>>tensor([[1, 2],
        [3, 4]])

torch.tensor가 데이터의 자료형을 자동으로 유추한다

 

- Numpy 배열로부터 생성하기

np_array = np.array(data)
torch.from_numpy(np_array)
>>>tensor([[1, 2],
        [3, 4]])

- 다른 텐서로부터 생성하기

# x_data의 속성 유지, x_data와 shape이 같은 1로 채워진 텐서 반환
x_ones = torch.ones_like(x_data) 
print(f'Ones Tensor: \n {x_ones} \n')
>>> Ones Tensor:
 	tensor([[1, 1],
        	[1, 1]])

 

torch.tensor(data, *, dtype=None, device=None, requires_grad=False, pin_memory=False)  Tensor

https://pytorch.org/docs/stable/generated/torch.tensor.html#torch.tensor

 

torch.tensor — PyTorch 1.12 documentation

Shortcuts

pytorch.org

dtype: 텐서의 데이터타입

device: 텐서가 CPU에 생성될지 GPU에 생성될지

requires_grad: 자동미분을 하기 위해 추적할지 

pin_mermory: 텐서를 pin memory 할당할 것인지 

 

*pin_memory: 

https://mopipe.tistory.com/191

 

[pytorch, 딥러닝] pin_memory 란 무엇인가?

Pin memory란 무엇인가?  우리가 모델을 제작을 함에 있어서 GPU를 사용하려면 GPU에 데이터를 로드를 해줘야 하는데, 이때 빠르게 데이터를 옮기기 위해 사용하는 것이 pin memory입니다(대부분의 데

mopipe.tistory.com

GPU를 연산에 사용하기 위해서는 GPU에 데이터를 로드해주어야한다.

하지만 GPU는 DRAM에 할당된 데이터를 사용하지 못하기 때문에 GPU로 데이터를 옮기기 위해서는 pinned 메모리를 사용하여 pinned 메모리로 옮겨준 후 VRAM(GPU 전용 메모리)로 옮겨주어야한다

이 과정이 시간이 오래 걸리기때문에 pin_memory = True를 설정하면 DRAM을 거치지않고 VRAM으로 바로 갈 수 있다

*torch.Tensor()로도 텐서를 선언할 수 있는데

torch.Tensor()를 사용하면, 데이터 자료형을 자동으로 유추하지 않고, 무조건 default_dtype으로 정해진다

print(torch.get_default_dtype()) # torch.float32 = 현재 설정된 기본 자료형

# torch.float32, 기본 자료형이 맞추어 정수형으로 데이터를 입려했음에도 float32로 바뀐다
a = torch.Tensor([1,0])
print(a.dtype) 

torch.set_default_dtype(torch.float64) # float64로 기본 자료형 바꾸기

a = torch.Tensor([1,0])
print(a.dtype) # torch.float64로 저장된다

# b = torch.Tensor([1.00 + 2.00j]) 
# tensor의 기본 자료형이 float64이므로 complex 자료형은 받지 못한다

 

- zeors/ones/empty/full, *_like

a = torch.empty(2,3) # shpae이 (2,3)인 빈공간 tensor 생성
torch.full((2,3),1.45) # shpae이 (2,3)이고, 1.4로 채워진 tensor 생성
torch.zeros(2, 3) # shape이 (2,3)이고, 0으로 채워진 tensor 생성
#tensor([[ 0.,  0.,  0.],
#        [ 0.,  0.,  0.]])
torch.ones(2, 3) # shape이 (2,3)이고, 1으로 채워진 tensor 생성


torch.zeros_like(a) # a와 같은 shape을 가지고 0으로 채워진 tensor 생성
torch.ones_like(a) # a와 같은 shape을 가지고 1으로 채워진 tensor 생성
torch.empty_like(a) # a와 같은 shape을 가지고 빈공간 tensor 생성
torch.full_like(a, 1.45) # a와 같은 shape을 가지고 1.45로 채워진 tensor 생성

- range/arange/linspace/logspace

torch.range(1, 4) # (start, end, step)으로 start ~ end tensor 생성
# tensor([ 1.,  2.,  3.,  4.])
torch.arange(1,4) # (start, end, step)으로 start ~ end -1 tensor 생성
# tensor([ 1,  2,  3])

# (start, end, step)으로 start ~ end 각 요소 사이 길이가 같은 tensor 생성
torch.linspace(3, 10, steps=5) 
# tensor([  3.0000,   4.7500,   6.5000,   8.2500,  10.0000])
# (start, end, step)으로 start ~ end 각 요소 사이 log길이가 같은 tensor 생성
torch.logspace(start=-10, end=10, steps=5)
# tensor([ 1.0000e-10,  1.0000e-05,  1.0000e+00,  1.0000e+05,  1.0000e+10])

- eye / diag / diagonal

torch.eye(3) # 3*3인 대각행렬 생성
# tensor([[ 1.,  0.,  0.],
#        [ 0.,  1.,  0.],
#        [ 0.,  0.,  1.]])

# torch.diag(input, diagonal = 0)
# input이 1d tensor면 input을 대각선으로 하는 2d tensor반환
# input이 2d tensor면 input의 대각값 반환 == torch.diagonal
# diagonal = 0, 주대각선
#diagonal > 0 주대각선 위 대각선, diagonal < 0 주대각선 아래대각선
a = torch.ones(3)
torch.diag(a) # 대각이 1로 채워져있는 3*3 tensor
b = torch.ones(3,3)
torch.diag(b,1) # 주대각선보다 한칸 위에 잇는 대각선의 대각성분

# torch.diagonal(input, offset=0, dim1=0, dim2=1)
# offeset은 torch.diag의 diagonal 파라미터와 같은 역할
# input의 dim1과 dim2의 대각성분
x = torch.randn(2, 5, 4, 2)
torch.diagonal(x, offset=-1, dim1=1, dim2=2)
# x의 1차원과 2차원이 이루는 공간에서, 주대각선의 한칸아래있는 대각성분 # shape(2,2,4)

- random sampling

torch.seed( ) # 랜덤 시드 결정
torch.normal(mean=torch.arange(1., 11.), std=torch.arange(1, 0, -0.1)) # 정규분포
torch.rand(2,3) # (2,3)의 [0,1) 난수 반횐
torch.randint(3,5,(3,)) #(low, high, size) (3,)의 [low, high-1] 정수인 난수 반환
torch.randn(4) # (4,)인 표준정규분포를 따르는 난수 반환
torch.randperm(4) # [0, 4-1]까지 정수 중에 랜덤 반환

rand/randint/randn_like(input) # input의 크기와 같은 규칙을 따르는 난수 반환

torch.Tensor.bernoulli_(), torch.Tensor.log_normal(), torch.poisson()등 여러 분포를 따르는 난수 생성기가 있다

 

Tensor 데이터 타입(dtype):

gpu 연산지원

torch.float16,32 64 : 실수형

torch.int8,16,32,64 : 정수형

torch.uint8 : 부호가 없는 정수형

torch.bool : 불리언형(true, false)

 

gpu 연산지원 x

torch.qint8,32 : 양자화된 정수형

torch.complex32,64:  복소수형

 

 

# .dtype으로 데이터 타입 출력 
a = torch.tensor([2, 2, 2])
print(a.dtype) # torch.int32

# type(), to()로 데이터 타입 casting 
a.type(torch.float64).dtype # torch.float64
a.to(torch.float64).dtype # torch.float64

 

Tensor와 storage:

https://pirunita.dev/2020/01/05/Pytorch-Pytorch2/

 

[PyTorch] 2. It starts with a tensor(1) - basic

PyTorch   Network는 floating-point numbers를 이용하여 information을 다루기 때문에 network가 이해할 수 있는 적절한 표현으로 data를 encoding하고 다시 우리가 이해할 수 있는 표현으로 decoding하여 output을 내

pirunita.dev

 

https://pirunita.dev/2020/01/10/Pytorch-Pytorch3/

 

[PyTorch] 3. It starts with a tensor(2) - size, offset, stride

PyTorch 3. Size, storage offset, strides   Storage에 index를 붙여주기 위해서 tensor는 storage에서 몇 가지 정보를 포함하고 결정한다. 이는 size, storage offset, stride이며 다음과 같이 도식화할 수 있다. Size: Tensor

pirunita.dev

Tensor 내에서 값들은 contiguous 메모리에 할당 되고, 이는 torch.Storage 인스턴스에 의해 관리된다.

storage는 1차원 숫자 배열로 이루어져 있으며, 다차원 배열이 될 수 없다.

points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
points.storage() # storage 배열 확인
>>>
 1.0
 4.0
 2.0
 1.0
 3.0
 5.0
[torch.storage._TypedStorage(dtype=torch.float32, device=cpu) of size 6]

# 1차원 배열로 저장된다

 storage는 언제나 one-dimensional하기 때문에, 2d - tensor의 index를 직접적으로 할 수 없다.

대신 offset과 stride라는 메타 정보를 사용하여 간접적으로  storage에 접근한다

 

offset: 텐서의 첫번째 원소가 storage에 저장되어 있는 인덱스

stride: 텐서 안의 어떤 한 값에서 다음 원소를 얻기 위하여 storage에서 뛰어넘어야 할 인덱스의 개수

points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
points.storage_offset(),points.stride() # offset = 0 stride = (2, 1)
# 텐서의 첫 원소가 시작하는 지점은 storage 배열의 0번째이고,
# dim = 1이 1칸 증가하기 위해서는 stroage index가 1칸,
# dim = 0 이 1칸 증가하기 위해서는 storage index가 2칸 증가해야한다

contigous: 텐서의 실제 storage 배열 index 순서가 텐서의 index 순서와 맞는 경우 contiguous하다고 한다

non-contigous Tensor는 원본 텐서의 메타데이터만 변경하는 함수(view, transpose, permute, narrow)등과 같이 원본 Tensor의 메타데이터만 변경하는 함수들의 결과값으로 나온다. 

함수 목록:

https://pytorch.org/docs/stable/tensor_view.html

 

Tensor Views — PyTorch 1.12 documentation

Shortcuts

pytorch.org

메타데이터만 바뀌고 같은 storage 배열을 가리키고 있으므로 원본 데이터가 바뀌면 추출된 Tensor의 데이터도 바뀐다.

메타데이터만 변경하는 방식을 통해 Tensor를 전치(transpose)시키거나 subtensor를 추출할 때 연산비용을 많이 줄일 수 있다.

non-contigous Tensor로는 주소값 재배열 연산이 필요할 때 사용할수 없으므로 재배치하기 위해서 contiguous()를 사용해야한다. 

points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
points.storage_offset(),points.stride() # (0, (2, 1))
points = points.T # transpose, non-contiguous Tensor가 됨
points.storage_offset(),points.stride()# (0, (1, 2))
points.is_contiguous() # False
points = points.contiguous() # 메모리 재배치, contiguous Tensor가 됨
points.is_contiguous() # True​

 

Tensor Indexing / Slicing / Joining / Mutating

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

t[0, 2] # tensor(3.) # 인덱스 접근
t[:, :2] # tensor([[1., 2.], [4., 5.]]) # 슬라이싱 접근
t[t > 3] = tensor([4., 5., 6.]) # 마스킹 접근
# argwhere
# 0이 아닌 값의 인덱스 반환, input 차원이 n인 경우 (z*n)차원을 반환
t = torch.tensor([1, 0, 1]) 
torch.argwhere(t)
#tensor([[0],
#        [2]])

# cat == concat
# 해당하는 차원에서 두개의 Tensor 합치기
x = torch.rand(batch_size, N, K) # [M, N, K]
y = torch.rand(batch_size, N, K) # [M, N, K]
 
output1 = torch.cat([x,y], dim=1) #[M, N+N, K] # 해당하는 차원의 길이가 증가
output2 = torch.cat([x,y], dim=2) #[M, N, K+K]


## torch.hstack(a,b) == torch.cat((a,b), axis = 1)
## torch.vstack(a,b) == torch.cat((a,b), axis = 0)

# stack
# 해당하는 차원에 Tensor 쌓기, 새로운 차원이 생긴다
# 배열의 shape이 모두 동일해야한다
x = torch.rand(batch_size, N, K) # [M, N, K]
y = torch.rand(batch_size, N, K) # [M, N, K]
 
output = torch.stack([x,y], dim=1) #[M, 2, N, K] # dim 1에 x와 y 두 개의 tensor가 쌓였다

## torch.vstack(a,b) == torch.stack((ab),dim = -1)

# split
# n개씩 자르기
a = torch.arange(10).reshape(5,2)
split(a,2, dim = 0) # dim = 0 축을 따라 2개씩 자른다, 부족한건 그냥 내보냄
#(tensor([[0, 1],
#         [2, 3]]),
# tensor([[4, 5],
#         [6, 7]]),
# tensor([[8, 9]]))

# n에 다차원이 들어갈 수도 있는데 이건 잘 모르겠다;;


# chunk
# n개의 그룹을 내보내기
torch.arange(12).chunk(6, dim = 0) # 12을 2개씩 나누면 6개의 그룹이 만들어진다
torch.arange(13).chunk(6, dim = 0) # 13을 3개씩 나누면 5개의 그룹이 만들어진다 => 3개씩 묶어서 출력
								   # 13을 2개씩 나누면 7개의 그룹이 만들어진다
#(tensor([0, 1, 2]),
# tensor([3, 4, 5]),
# tensor([6, 7, 8]),
# tensor([ 9, 10, 11]),
# tensor([12]))

 - Gather
torch.gather(input, dim, index, *, sparse_grad=False, out=None)
index 값이 각 차원별 input의 idx값이 된다

Gather의 output의 shape은 언제나 index의 shape과 같다

2D에서의 Gather:

out[i][j]= input[index[i][j]][j]  # if dim == 0
out[i][j] = input[i][index[i][j]]  # if dim == 1

index와 같은 shape의 output을 그려주고 위의 규칙에 맞추어 하나씩 채워가면 된다

gather 계산

3D에서의 Gather:

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

 

임의의 크기의 3D tensor에서 대각선 요소 가져와 2D로 반환하는 함수:

import torch
# TODO : 임의의 크기의 3D tensor에서 대각선 요소 가져와 2D로 반환하는 함수를 만드세요! 

def get_diag_element_3D(A): 
    d = A.shape[0] # dim = 0
    
    a = torch.arange(min(A.shape[2],A.shape[1])) # ndim = 1
    a = a.unsqueeze(0) # ndim = 2
    a = a.unsqueeze(0) # ndim = 3
    
    b = a

    for i in range(d-1):
      b = torch.cat((b,a),dim = 0) # 3차원으로 더해주기
      
	# 결과적으로 b는 [[[0,1,2...min(A.shape[2],A.shape[1])]],
					[[0,1,2...min(A.shape[2],A.shape[1])]],
					... dim= 0의 크기만큼 반복]
	  이 된다.
      
    output = A.gather(1,b).squeeze()
    return output

 

- scatter:
Tensor.scatter_(dim, index, src, reduce=None)

gather의 역,  index 값이 각 차원별 self의 idx값이 된다

self에 들어가는 값의 개수는 index 배열의 개수와 같다

3D에서의 scatter

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
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)
# (3,5)짜리 빈공간에 idx배열의 개수만큼 값이 들어간다.
# self[index[i][j][k]][j][k] = src[i][j][k]  # if dim == 0
>>> tensor([[1, 0, 0, 4, 0],
            [0, 2, 0, 0, 0],
            [0, 0, 3, 0, 0]])

 

-index_add, index_reduce

Tensor.index_add_( dim , index , source , * , alpha = 1 ) 

인덱스로 고른 차원에 src값 * alpha를 더해준다

self[index[i], :, :] += alpha * src[i, :, :]  # if dim == 0
self[:, index[i], :] += alpha * src[:, i, :]  # if dim == 1
self[:, :, index[i]] += alpha * src[:, :, i]  # if dim == 2

Tensor.index_reduce_( dim , index , source , reduce , * , include_self = True )

인덱스로 고른 차원에 src값 * alpha를 곱해준다

self[index[i], :, :] *= src[i, :, :]  # if dim == 0
self[:, index[i], :] *= src[:, i, :]  # if dim == 1
self[:, :, index[i]] *= src[:, :, i]  # if dim == 2

 

- index_select

torch.index_select( input , dim , index , * , out = None ) 

정해진 차원에 따라 input 값을 index값으로 골라준다

>>> x = torch.randn(3, 4)
>>> x
tensor([[ 0.1427,  0.0231, -0.5414, -1.0009],
        [-0.4664,  0.2647, -0.1228, -1.1068],
        [-1.1734, -0.6571,  0.7230, -0.6004]])
>>> indices = torch.tensor([0, 2]) 
>>> torch.index_select(x, 0, indices) # 차원이 0이므로, 0번째와 2번째 열을 골라준다
tensor([[ 0.1427,  0.0231, -0.5414, -1.0009],
        [-1.1734, -0.6571,  0.7230, -0.6004]])

 

-torch.movedim() == torch.moveaxis()

torch.movedim(input, source, destination)

>>> t = torch.randn(3,2,1)

>>> torch.movedim(t, (1, 2), (0, 1)).shape # 1번 축을 0번과 바꾸고, 2번 축을 1번과 바꾼다
torch.Size([2, 1, 3])

- torch.narrow()

torch.narrow(input, dim, start, length)

>>> x = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> torch.narrow(x, 0, 0, 2) # 0차원에서 0번부터 2개
tensor([[ 1,  2,  3],
        [ 4,  5,  6]])
>>> torch.narrow(x, 1, 1, 2) # 1차원에서 1번부터 2개
tensor([[ 2,  3],
        [ 5,  6],
        [ 8,  9]])

 

-nonzero()

torch.nonzero( input , * , out = None , as_tuple = False )

# as_tuple=False일때, 
>>> torch.nonzero(torch.tensor([1, 1, 1, 0, 1]))
tensor([[ 0],
        [ 1],
        [ 2],
        [ 4]])
>>> torch.nonzero(torch.tensor([[0.6, 0.0, 0.0, 0.0],
...                             [0.0, 0.4, 0.0, 0.0],
...                             [0.0, 0.0, 1.2, 0.0],
...                             [0.0, 0.0, 0.0,-0.4]]))
tensor([[ 0,  0],
        [ 1,  1],
        [ 2,  2],
        [ 3,  3]])
# nonzero인 값들이 xy가 묶여서 나온다

# as_tuple=True일때, 
>>> torch.nonzero(torch.tensor([1, 1, 1, 0, 1]), as_tuple=True)
(tensor([0, 1, 2, 4]),)
>>> torch.nonzero(torch.tensor([[0.6, 0.0, 0.0, 0.0],
...                             [0.0, 0.4, 0.0, 0.0],
...                             [0.0, 0.0, 1.2, 0.0],
...                             [0.0, 0.0, 0.0,-0.4]]), as_tuple=True)
(tensor([0, 1, 2, 3]), tensor([0, 1, 2, 3]))
>>> torch.nonzero(torch.tensor(5), as_tuple=True)
(tensor([0]),)

# nonzero인 값들이 (x,y) 튜플형식으로 x끼리 , y끼리 묶여서 나온다

-torch.permute()

torch.permute(input, dims) 

>>> x = torch.randn(2, 3, 5)
>>> x.size()
torch.Size([2, 3, 5])
>>> torch.permute(x, (2, 0, 1)).size() # 각 차원이 가야하는곳으로 바꿔버림
torch.Size([5, 2, 3])​

-torch.reshape()

torch.reshape(input, shape) 

>>> a = torch.arange(4.)
>>> torch.reshape(a, (2, 2))
tensor([[ 0.,  1.],
        [ 2.,  3.]])
>>> b = torch.tensor([[0, 1], [2, 3]])
>>> torch.reshape(b, (-1,))
tensor([ 0,  1,  2,  3])

# view()와 같은 역할을 하지만, contiguous가 언제나 보장된다

- transpose() == swapdims(), swapaxes()

torch.transpose(input, dim0, dim1)

>>> x = torch.randn(2, 3)
>>> x
tensor([[ 1.0028, -0.9893,  0.5809],
        [-0.1669,  0.7299,  0.4942]])
>>> torch.transpose(x, 0, 1)
tensor([[ 1.0028, -0.1669],
        [-0.9893,  0.7299],
        [ 0.5809,  0.4942]])
# 두 차원을 바꾼다

 

- unsqueeze()

torch.unsqueeze(input, dim) 

>>> x = torch.tensor([1, 2, 3, 4])
>>> torch.unsqueeze(x, 0)
tensor([[ 1,  2,  3,  4]])
>>> torch.unsqueeze(x, 1)
tensor([[ 1],
        [ 2],
        [ 3],
        [ 4]])
        
# dim에 새로운 축 하나를 생성

- squeeze()

torch.squeeze(input, dim=None, *, out=None)

>>> x = torch.zeros(2, 1, 2, 1, 2)
>>> x.size()
torch.Size([2, 1, 2, 1, 2])
>>> y = torch.squeeze(x)
>>> y.size()
torch.Size([2, 2, 2])
>>> y = torch.squeeze(x, 0)
>>> y.size()
torch.Size([2, 1, 2, 1, 2])
>>> y = torch.squeeze(x, 1)
>>> y.size()
torch.Size([2, 2, 1, 2])

# 차원이 1인 것들을 모두 없앤다, dim이 설정되면 그 차원이 1인 경우만 없앤다

 

- torch.tensor.expand()

Tensor.expand(*sizes)

>>> x = torch.tensor([[1], [2], [3]])
>>> x.size()
torch.Size([3, 1])
>>> x.expand(3, 4)
tensor([[ 1,  1,  1,  1],
        [ 2,  2,  2,  2],
        [ 3,  3,  3,  3]])
>>> x.expand(-1, 4)   # -1 means not changing the size of that dimension
tensor([[ 1,  1,  1,  1],
        [ 2,  2,  2,  2],
        [ 3,  3,  3,  3]])
        
# 원래차원과 맞는 차원을 기준으로 늘어난다

 

Tensor to GPU

# tensor를 gpu에 할당하는 3가지 방법 ("cuda" -> default cuda device (default gpu device))
x = torch.tensor([1., 2.], device="cuda") 
x = torch.tensor([1., 2.]).cuda() 
x = torch.tensor([1., 2.]).to("cuda") 

x.is_cuda() #연결되어있으면 True
x.get_device() #gpu에 연결되어 있으면 gpu 번호 반환, 그렇지 않으면 error
x.device # 연결되어있으면 cuda

torch.cuda.is_available() # cuda 가능한지
torch.cuda.device_count() # cuda가 가능한 장비의 개수
torch.cuda.current_device() # 연결된 장치의 인덱스 반환
torch.cuda.get_device_name(0) # 연결된 0번 장치의 이름 반환

 

Math operations

https://pytorch.org/docs/stable/torch.html#math-operations

 

torch — PyTorch 1.12 documentation

Shortcuts

pytorch.org

 

선형대수학 관련

https://pytorch.org/docs/stable/linalg.html#

 

torch.linalg — PyTorch 1.12 documentation

Shortcuts

pytorch.org

 

*inplace operation

연산자 함수 뒤에 _가 붙어있으면 inplace operation이다.

inplace operation은 연산결과가 원본 텐서에 저장된다

x=torch.rand(2) #tensor([0.8284, 0.5539])
print(x)
y=torch.rand(2)
x.add_(y)
print(x)    #tensor([1.1610, 1.3789])

 

* 기울기 저장 -> 자동미분

텐서에 requires_grad = True를 추가해주면 이 텐서에 대한 기울기 저장하게 되고 backward()에서 자동미분이 적용된다.

detach()를 사용하면 더이상 텐서에대해 추적을 하지 않는다.