반응형
PyTorch를 위한 배경지식
- 표본분산
- 연속 균등 분포
- 표준 정규 분포
- 상관 관계
PyTorch 자료형과 Tensor
Data Type
- 텐서 생성시 다음과 같이 데이터 타입을 지정할 수 있다.
t = torch.tensor(10.2, dtype=torch.float64)
- Type Casting (타입 변환)은 다음과 같다.Tensor
t = t.type(torch.IntTensor) # torch.FloatTensor, torch.DoubleTensor
- 0D tensor (=Scalar)
- 1D tensor (=Vector)
- 2D tensor (=Matrix)
- 3D tensor
- 4,5,6...D tensor
Tensor Basic Functions
min(), max(), sum(), prod(), mean(), var(), std()
prod()
는 모든 요소의 곱을 반환한다.var()
과std()
는 지정한 차원에 대한 분산과 표준편차를 계산한다.
Tensor 생성, 복제, 삭제
Tensor 생성
- 직접 생성
t = torch.tensor([[1, 2, 3], [4, 5, 6]])
- 특정 값을 초기화
t = torch.zeros(5) # (5) 크기의 0로 초기화된 Tensor t = torch.ones([3, 2]) # (3,2) 크기의 1로 초기화된 Tensor
- 특정 구간으로 초기화
# 0에서 10까지 1씩 증가하는 1-D Tensor t = torch.arange(start=0,end=10,step=1) # t.shape: torch.Size([10])
- 난수로 초기화
torch.rand(size) # 연속 균등 분포를 따르는 난수 Tensor torch.randn(size) # 표준 정규 분포를 따르는 난수 Tensor torch.randint(low,high,size) # [low, high) 범위의 정수 난수 Tensor
torch.rand_like(t) # t와 동일한 형태의 연속 균등 분포 난수 Tensor
torch.randn_like(t) # t와 동일한 형태의 표준 정규 분포 난수 Tensor
- list, numpy에서 가져오기
```python
s = [1, 2, 3, 4, 5, 6]
t = torch.tensor(s)
import numpy as np
s = np.array([[0, 1],[2, 3]])
v = torch.from_numpy(s)
- 초기화하지 않고 생성
목적: 성능 향상, 메모리 최적화
t = torch.empty([2, 4])
Tensor 복제
torch.clone()
- 복사한 텐서를 새로운 메모리에 할당(
deepcopy()
와 유사) - 기존 계산 그래프를 유지
- e.g. 딥러닝 모델 계산에서 분기를 만드는 경우에 같은 데이터가 서로 다른 layer로 들어갈 때, 이러한 구조의 가독성을 높이기 위해 사용할 수 있음
- 복사한 텐서를 새로운 메모리에 할당(
torch.detach()
- 복사 대상 텐서와 메모리를 공유
- gradient 전파가 안되는 텐서 생성 (
no_grad()
적용한 텐서와 기능적으로 동일) - e.g. 딥러닝 모델로 부터 받은 output 값 평가를 위해 특정 메트릭을 적용하여 사용되는 연산에 포함되지 않도록 하기 위해 사용할 수 있음
torch.clone().detach()
- 기존 텐서를 복사한 새로운 텐서를 생성하지만 기울기에 영향을 주지는 않겠다는 의미
Tensor 삭제(메모리 해제)
torch.cuda.empty_cache()
를 통해 사용되지 않은 GPU상의 cache를 정리del
함수를 사용하여 메모리에서 해제torch.cuda.empty_cache() t = torch.tensor(\[\[1, 2, 3\], \[4, 5, 6\]\]) del t
Tensor indexing & slicing
- 1차원 tensor는 python list와 동일하다.
- 2차원 tensor 조작은 다음과 같다.
t = torch.tensor([[1, 2, 3], [4, 5, 6]])
t[1, 2] # 1행, 2열의 요소에 접근 -> tensor(6)
t[0, 1:] # 0행, 1열 부터 끝열(2열)까지 -> tensor([2, 3])
t[:, -2:] # 전체 행, 뒤에서부터 두번째 열(1열) 부터 끝열(2열)까지 -> tensor([[2, 3], [5, 6]])
t[-1, ...] # 뒤에서부터 첫번째 행(1행), 전체 열 -> tensor([4, 5, 6])
Tensor 모양 변경
contiguous
, storage
에 대한 이해
t = torch.tensor([[1, 2, 3],[4, 5, 6]])
new_t = t[:2, :2] # tensor([[1, 2], [4, 5]])
new_t.is_contiguous() # False
new_t_cont = new_t.contiguous()
new_t_cont.is_contiguous() # True
contiguous()
를 사용하면 연속체로 만들어 주는데, 만약 연속체가 아닌 경우 새로운 storage
를 만들어 할당한다.
view()
입력
t = torch.tensor([[1, 2, 3],[4, 5, 6]])
print(t.view(1, -1))
print(t.view(2,-1))
print(t.view(3, -1))
print(t.view(6, -1))
출력
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]])
- shape이 [2,3] 인 Tensor 't'에 대해
s = t[:2, :1]
일 때, view를 사용해 s의 모양을 변경할 수 있는 이유
PyTorch에서는 텐서의 슬라이스 연산를 통해 생성된 텐서가 메모리 연속성을 유지하고 있다면(슬라이스를 얻는 과정에서 데이터의 순서가 바뀌지 않았다면) 자동으로 메모리에서 연속적인 형태로 다뤄질 수 있다.- 슬라이스 연산의 연속성 유지: t[:2, :1]과 같은 슬라이스 연산이 메모리에서 연속적인 영역을 참조하는 경우, PyTorch는 이를 자동으로 인식하고 s를 연속적인 텐서로 처리한다.
- 데이터의 실제 복사 없음: 슬라이스 연산은 원본 텐서의 데이터를 복사하지 않고 참조만 한다. 원본 텐서가 연속적이었고, 슬라이스된 텐서가 메모리에서 연속적인 영역을 참조하는 경우, 슬라이스된 텐서도 연속성을 가지게 된다. 따라서 view를 사용할 수 있다.
view를 사용하려면 텐서가 연속적이어야 하지만, 슬라이스 연산으로 얻어진 텐서가 메모리에서 연속적인 부분을 참조하고 있다면 PyTorch는 이를 연속적으로 간주한다. 따라서 t[:2, :1]으로 생성된 s가 연속적인 텐서로 다뤄지기 때문에 view를 사용할 수 있다.
- 정리:
view()
메소드를 사용할 수 있는데is_contiguous()
메소드가 False를 반환하는 이유is_contiguous()
는 실제로 메모리 공간에서 인접한가를 판단하는 것이기 때문에t[0][0]
의 다음 원소인t[0][1]
은 인접하지만s1[0][0]
의 다음 원소인s1[1][0]
은 인접하지 않다.view()
는 stride(보폭)이 일정하면 연속적으로 참조할 수 있기 때문에 실제로 메모리 공간에서 인접하다면 사용 가능하고, 실제로 인접하지 않더라도 폭이 일정하다면 사용할 수 있다.
입력
t = torch.tensor([[1, 2, 3], [4, 5, 6]])
s1 = t[:2,:1]
print(s1)
print(s1.is_contiguous())
print(s1.view(1,-1))
print(t.untyped_storage().data_ptr() == s1.untyped_storage().data_ptr())
출력
tensor([[1],
[4]])
False
tensor([[1, 4]])
True
입력
s2 = t[:, :2]
print(s2)
print(s2.is_contiguous())
print(s2.view(1,-1))
print(t.untyped_storage().data_ptr() == s2.untyped_storage().data_ptr())
출력
tensor([[1, 2],
[4, 5]])
False
RuntimeError: view size is not compatible with input tensor's size and stride
True
flatten()
- tensor 평탄화
입력 t = torch.tensor([[1, 2, 3], [4, 5, 6]])
t.flatten() # 또는 torch.flatten(t)
출력
``` python
tensor([1, 2, 3, 4, 5, 6])
- tensor 특정 차원 평탄화
입력 t = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print(t.flatten(0))
print(t.flatten(1))
print(t.flatten(2))
출력
``` python
tensor([1, 2, 3, 4, 5, 6, 7, 8])
tensor([[1, 2, 3, 4],
[5, 6, 7, 8]])
tensor([[[1, 2],
[3, 4]],
[[5, 6],
[7, 8]]])
reshape()
reshape()
vsview()
view()
메서드와 달리 메모리가 연속적이지 않아도 사용 가능
입력
t = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(t.reshape(1, 6))
print(t.reshape(3,2))
print(t.reshape(6, 1))
출력
tensor([[1, 2, 3, 4, 5, 6]])
tensor([[1, 2],
[3, 4],
[5, 6]])
tensor([[1],
[2],
[3],
[4],
[5],
[6]])
transpose()
- 특정한 두 차원의 축을 서로 바꾸는 메서드
t = torch.tensor([[1, 2, 3], [4, 5, 6]]) t.transpose(0,1) >>> tensor([[1, 2], [3, 4], [5, 6]])
squeeze()
& unsqueeze()
squeeze()
는 지정한 차원에 대해 크기가 1이라면 축소시키고, 따로 dim을 지정하지 않으면 모든 차원에 대해 수행한다.unsqueeze()
는 지정한 차원에 크기가 1인 차원을 추가하여 확장한다.t = torch.tensor([[1, 2, 3], [4, 5, 6]]) t.squeeze(dim=1) >>> tensor([[1, 2], [3, 4], [5, 6]])
Tensor 결합
stack()
- Tensor들을 새로운 차원으로 결합 - 차원의 개수가 증가
t1 = torch.zeros(2, 2)
t2 = torch.ones(2, 2)
t3 = torch.stack([t1, t2], dim=0)
t4 = torch.stack([t1, t2], dim=1)
print(t3)
>>> tensor([[[1., 1.],
[1., 1.]],
[[0., 0.],
[0., 0.]]])
print(t3.shape)
>>> torch.Size([2, 2, 2])
print(t4)
>>> tensor([[[1., 1.],
[0., 0.]],
[[1., 1.],
[0., 0.]]])
print(t4.shape)
>>> torch.Size([2, 2, 2])
cat()
- Tensor들을 주어진 차원에 맞춰 연결 - 개수가 유지되고 해당 차원이 늘어남
dim
옵션에 따라 concat 되는 방향 설정
t1 = torch.ones(2, 2)
t2 = torch.zeros(2, 2)
t3 = torch.cat([t1, t2], dim=0)
t4 = torch.cat([t1, t2], dim=1)
print(t3)
>>> tensor([[1., 1.],
[1., 1.],
[0., 0.],
[0., 0.]])
print(t3.shape)
>>> torch.Size([4, 2])
print(t4)
>>> tensor([[1., 1., 0., 0.],
[1., 1., 0., 0.]])
print(t4.shape)
>>> torch.Size([2, 4])
이미지 출처: https://sanghyu.tistory.com/85
Tensor 확장
expand()
- 주어진 Tensor의 차원 중 일부의 크기가 1일 때, 해당 차원의 크기를 확장
repeat()
- Tensor의 요소들을 반복하는 방식으로 크기 확장
Tensor 연산 1
기본 연산
add()
더하기sub()
빼기mul()
곱하기 (스칼라 또는 요소별 곱)div()
나누기pow()
거듭 제곱, 거듭 제곱근
비교 연산
eq(v,w)
대응 요소들이 같은지를 비교ne(v,w)
대응 요소들이 다른지를 비교gt(v,w)
텐서 v의 요소들이 텐서 w의 대응 요소들보다 큰지를 비교ge(v,w)
텐서 v의 요소들이 텐서 w의 대응 요소들보다 크거나 같은지를 비교lt(v,w)
텐서 v의 요소들이 텐서 w의 대응 요소들보다 작은지를 비교le(v,w)
텐서 v의 요소들이 텐서 w의 대응 요소들보다 작거나 같은지를 비교
논리 연산
torch.logical_and(x,y)
AND(논리곱) 연산torch.logical_or(x,y)
OR(논리합) 연산torch.logical_xor(x,y)
XOR(배타적 논리합) 연산
in-place 연산 vs out-of-place 연산
add_()
는 in-place operation 이고add()
는 out-of-place operation이다. in-place는 메모리의 값을 바꿔주고, out-of-place는 연산 결과를 반환한다.
크기가 다른 Tensor 연산
- 같은 크기가 되도록 확장하여 연산이 이루어짐
Tensor 연산 2
Tensor Norm (노름, 놈)
- L1 Norm (Manhatten norm)
- L2 Norm (euclidean norm)
- L∞ Norm (infinite norm)
t = torch.tensor([4, 3], dtype=torch.float32)
torch.norm(t, p=1)
>>> 7.0
t = torch.tensor(\[4, 3\], dtype=torch.float32)
torch.norm(t, p=2)
> > > 5.0
t = torch.tensor(\[4, 3\], dtype=torch.float32)
torch.norm(t, p=float('inf')) # torch.max(t.abs())와 같음
> > > 4.0
유사도 계산
- manhattan similarity (맨해튼 유사도)
- euclidean similarity (유클리드 유사도)
- cosine similarity (코사인 유사도)
t1 = torch.tensor([1, 0, 2], dtype=torch.float32)
t2= torch.tensor([0, 1, 2], dtype=torch.float32)
# 맨해튼 유사도
manhattan_distance = torch.norm(t1 - t2, p = 1)
manhattan_similarity = 1 / (1 + manhattan_distance)
manhattan_similarity
>>> 0.3333333432674408
# 유클리드 유사도
euclidean_distance = torch.norm(t1 - t2, p = 2)
euclidean_similarity = 1 / (1 + euclidean_distance)
euclidean_similarity
>>> 0.41421353816986084
# 코사인 유사도
dot_product = torch.dot(t1, t2)
norm_t1 = torch.norm(t1, p = 2)
norm_t2 = torch.norm(t2, p = 2)
cosine_similarity = dot_product / (norm_t1 * norm_t2)
cosine_similarity
>>> 0.800000011920929
행렬의 곱셈
matmul()
,mm()
,@
matmul()
은 broadcasting을 지원mm()
은 broadcasting을 지원X- Broadcasting: 텐서 연산을 수행할 때 자동적으로 크기를 맞춰서 연산을 수행하는 기능
- Broadcasting은 의도와 다르게 연산이 동작할 수 있어 주의가 필요하다(
mm()
이 비교적 안전)
weight = torch.randn(out_features, in_features)
bias = torch.randn(out_features)
x @ weight.t() + bias
x.matmul(weight.t()) + bias
x.mm(weight.t()) + bias
반응형
'네이버 부스트캠프 AI Tech 7기 > Machine Learning Basic' 카테고리의 다른 글
정형 데이터 전처리 (0) | 2024.08.23 |
---|---|
PyTorch로 직접 구현하는 Linear Regression (0) | 2024.08.19 |
Numpy로 직접 구현하는 Linear Regression (0) | 2024.08.18 |
댓글