Skip to content

2. Tensors


텐서는 배열 및 행렬과 매우 유사한 특수 데이터 구조입니다. PyTorch에서는 텐서를 사용하여 모델의 입력과 출력, 모델의 매개변수를 인코딩합니다.

Tensors are a specialized data structure that are very similar to arrays and matrices. In PyTorch, we use tensors to encode the inputs and outputs of a model, as well as the model’s parameters.

텐서는 GPU 또는 기타 하드웨어 가속기에서 실행할 수 있다는 점을 제외하고 NumPy의 ndarray와 유사합니다. 사실, 텐서와 NumPy 배열은 종종 동일한 기본 메모리를 공유할 수 있으므로 데이터를 복사할 필요가 없습니다. 텐서는 또한 자동 미분에 최적화되어 있습니다. ndarrays에 익숙하다면 Tensor API도 익숙할 것입니다. 그렇지 않다면 따라하세요!

Tensors are similar to NumPy’s ndarrays, except that tensors can run on GPUs or other hardware accelerators. In fact, tensors and NumPy arrays can often share the same underlying memory, eliminating the need to copy data. Tensors are also optimized for automatic differentiation. If you’re familiar with ndarrays, you’ll be right at home with the Tensor API. If not, follow along!

import torch
import numpy as np

Initializing a Tensor

텐서는 다양한 방법으로 초기화할 수 있습니다. 다음 예를 살펴보세요:

Tensors can be initialized in various ways. Take a look at the following examples:

Directly from data

Tensor는 데이터에서 직접 생성할 수 있습니다. 데이터 유형이 자동으로 유추됩니다.

Tensors can be created directly from data. The data type is automatically inferred.

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

From a NumPy array

텐서는 NumPy 배열에서 생성할 수 있습니다.

Tensors can be created from NumPy arrays.

np_array = np.array(data)
x_np = torch.from_numpy(np_array)

From another tensor:

새 텐서는 명시적으로 재정의하지 않는 한 인수 텐서의 속성(모양, 데이터 타입)을 유지합니다.

The new tensor retains the properties (shape, datatype) of the argument tensor, unless explicitly overridden.

x_ones = torch.ones_like(x_data) # retains the properties of x_data
print(f"Ones Tensor: \n {x_ones} \n")

x_rand = torch.rand_like(x_data, dtype=torch.float) # overrides the datatype of x_data
print(f"Random Tensor: \n {x_rand} \n")
Ones Tensor:
 tensor([[1, 1],
        [1, 1]])

Random Tensor:
 tensor([[0.0749, 0.2334],
        [0.8107, 0.2310]])

With random or constant values:

shape은 텐서 차원의 튜플입니다. 아래 함수에서 출력 텐서의 차원을 결정합니다.

shape is a tuple of tensor dimensions. In the functions below, it determines the dimensionality of the output tensor.

shape = (2,3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)

print(f"Random Tensor: \n {rand_tensor} \n")
print(f"Ones Tensor: \n {ones_tensor} \n")
print(f"Zeros Tensor: \n {zeros_tensor}")
Random Tensor:
 tensor([[0.6051, 0.0835, 0.4677],
        [0.8406, 0.9408, 0.4011]])

Ones Tensor:
 tensor([[1., 1., 1.],
        [1., 1., 1.]])

Zeros Tensor:
 tensor([[0., 0., 0.],
        [0., 0., 0.]])



Attributes of a Tensor

Tensor 속성은 모양, 데이터 타입 및 저장된 장치를 설명합니다.

Tensor attributes describe their shape, datatype, and the device on which they are stored.

tensor = torch.rand(3,4)

print(f"Shape of tensor: {tensor.shape}")
print(f"Datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}")
Shape of tensor: torch.Size([3, 4])
Datatype of tensor: torch.float32
Device tensor is stored on: cpu



Operations on Tensors

이러한 각 작업은 GPU에서 실행할 수 있습니다(일반적으로 CPU보다 빠른 속도로). Colab을 사용하는 경우 런타임 > 런타임 유형 변경 > GPU로 이동하여 GPU를 할당합니다.

Each of these operations can be run on the GPU (at typically higher speeds than on a CPU). If you’re using Colab, allocate a GPU by going to Runtime > Change runtime type > GPU.

기본적으로 텐서는 CPU에서 생성됩니다. (GPU 가용성을 확인한 후) .to 메서드를 사용하여 텐서를 GPU로 명시적으로 이동해야 합니다. 장치 간에 큰 텐서를 복사하는 것은 시간과 메모리 면에서 비용이 많이 들 수 있음을 명심하세요!

By default, tensors are created on the CPU. We need to explicitly move tensors to the GPU using .to method (after checking for GPU availability). Keep in mind that copying large tensors across devices can be expensive in terms of time and memory!

# We move our tensor to the GPU if available
if torch.cuda.is_available():
    tensor = tensor.to("cuda")

리스트에서 일부 작업을 시도하세요. NumPy API에 익숙하다면 Tensor API를 사용하기 쉬울 것입니다.

Try out some of the operations from the list. If you’re familiar with the NumPy API, you’ll find the Tensor API a breeze to use.

Standard numpy-like indexing and slicing:

tensor = torch.ones(4, 4)
print(f"First row: {tensor[0]}")
print(f"First column: {tensor[:, 0]}")
print(f"Last column: {tensor[..., -1]}")
tensor[:,1] = 0
print(tensor)
First row: tensor([1., 1., 1., 1.])
First column: tensor([1., 1., 1., 1.])
Last column: tensor([1., 1., 1., 1.])
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])

Joining tensors

torch.cat을 사용하여 주어진 차원을 따라 텐서 시퀀스를 연결할 수 있습니다.

You can use torch.cat to concatenate a sequence of tensors along a given dimension.

t1 = torch.cat([tensor, tensor, tensor], dim=1)
print(t1)
tensor([[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.]])

Arithmetic operations

# This computes the matrix multiplication between two tensors. y1, y2, y3 will have the same value
y1 = tensor @ tensor.T
y2 = tensor.matmul(tensor.T)

y3 = torch.rand_like(y1)
torch.matmul(tensor, tensor.T, out=y3)


# This computes the element-wise product. z1, z2, z3 will have the same value
z1 = tensor * tensor
z2 = tensor.mul(tensor)

z3 = torch.rand_like(tensor)
torch.mul(tensor, tensor, out=z3)
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])

Single-element tensors

예를 들어 텐서의 모든 값을 하나의 값으로 집계하여 요소가 하나인 텐서가 있는 경우 item()을 사용하여 이를 Python 숫자 값으로 변환할 수 있습니다:

If you have a one-element tensor, for example by aggregating all values of a tensor into one value, you can convert it to a Python numerical value using item():

agg = tensor.sum()
agg_item = agg.item()
print(agg_item, type(agg_item))
12.0 <class 'float'>

In-place operations

결과를 피연산자에 저장하는 연산을 인-플레이스라고 합니다. _ 접미사로 표시됩니다. 예: x.copy_(y), x.t_()x를 변경합니다.

Operations that store the result into the operand are called in-place. They are denoted by a _ suffix. For example: x.copy_(y), x.t_(), will change x.

print(f"{tensor} \n")
tensor.add_(5)
print(tensor)
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])

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

Note

인-플레이스 작업은 일부 메모리를 절약하지만 미분을 계산할 때 히스토리의 즉각적인 손실로 인해 문제가 될 수 있습니다. 따라서 사용을 권장하지 않습니다.

In-place operations save some memory, but can be problematic when computing derivatives because of an immediate loss of history. Hence, their use is discouraged.



Bridge with NumPy

CPU 및 NumPy 배열의 텐서는 기본 메모리 위치를 공유할 수 있으며 하나를 변경하면 다른 하나가 변경됩니다.

Tensors on the CPU and NumPy arrays can share their underlying memory locations, and changing one will change the other.

Tensor to NumPy array

t = torch.ones(5)
print(f"t: {t}")
n = t.numpy()
print(f"n: {n}")
t: tensor([1., 1., 1., 1., 1.])
n: [1. 1. 1. 1. 1.]

텐서의 변경 사항은 NumPy 배열에 반영됩니다.

A change in the tensor reflects in the NumPy array.

t.add_(1)
print(f"t: {t}")
print(f"n: {n}")
t: tensor([2., 2., 2., 2., 2.])
n: [2. 2. 2. 2. 2.]

NumPy array to Tensor

n = np.ones(5)
t = torch.from_numpy(n)

NumPy 배열의 변경 사항은 텐서에 반영됩니다.

Changes in the NumPy array reflects in the tensor.

np.add(n, 1, out=n)
print(f"t: {t}")
print(f"n: {n}")
t: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
n: [2. 2. 2. 2. 2.]

References