Tensor
- 데이터 배열 (array)를 의미
- 수학적 연산
- 사칙 연산 :원소단위로 연산이 가능
- 내적 : 1D 텐서 단위에서만 가능
- 행렬 곱 연산 : 두 행렬의 대응하는 행과 열의 원소들을 곱한 뒤 더하는 방식 = 행과 열 단위로 내적
- 계산 상 앞의 행렬의 열과 뒤의 행렬의 행의 길이가 같아야 함 - Broadcasting
- 차원이 다른 두 텐서 혹은 텐서와 스칼라간 연산을 가능하게 해주는 기능 (※ 단, 불가능한 경우 존재)
- 2D 텐서와 1D 텐서의 연산 - Sparse Tensor
- Dense tensor: 배열의 모든 위치에 값을 가지는 텐서
- 생략 가능한 원소까지 모두 저장하여 tensor의 크기와 비례하게 memory 사용 -> Out of memory (OOM) 문제 발생 가능
- 많은 계산량으로 인한 계산 시간 증가
- Sparse tensor: 0 이 아닌 원소와 그 위치를 저장하는 텐서
- Tensor에 0 이 많을 경우, 효율적인 memory 사용으로 dense tensor에 비해 계산 시간이 감소되는 장점 존재
- COO (Coordinate list) 방식과 CSR/CSC (Compressed Sparse Row/Column) 방식 등 여러 방식 존재
- Sparse COO Tensor
- (row_index, column_index, value) 의 형태로 저장하는 방식
- row/column_index : 0 이 아닌 값의 위치 (행/열의 인덱스의 순서 배열 )
- 장점: 직관적
- 단점
- 원소가 위치한 행과 열 인덱스를 별도로 저장하고 있기 때문에, 반복해서 저장되는 값 발생 ⇒ 비효율적인 메모리 사용
- 원소에 접근할 때마다 행-열 인덱스와 값을 찾아야 함 ⇒ 원소를 반복적으로 접근할 때, 연산 성능 저하
- CSR : (row_pointer, column_index, value), CSC : (column_pointer, row_index, value) 의 형태로 저장하는 방식
- column/row_index : 0 이 아닌 값을 가지는 (non-zero) 행/열 원소 순서대로 열/행 인덱스를 정렬한 배열
- row/column_pointer : 경계를 표시하는 배열
Tensor 조작
- 텐서를 생성하고 텐서로 변환하는 방법을 이해 및 실습
# 0부터 1 사이의 값을 랜덤하게 NxM 텐서로 반환
torch.rand(2, 3) # torch.rand(NxM) NxM은 텐서의 크기를 말합니다.
# 가우시안 분포에서 렌덤하게 값을 추출 후, NxM 텐서로 반환
torch.randn(2, 3) # torch.randn(NxM) NxM은 텐서의 크기를 말합니다.
# 범위 내의 정수를 N x M 텐서로 반환
torch.randint(1, 10, (5, 5)) # 생성 가능한 최솟값 : 1, 최댓값 : 9, (5x5) Tensor 크기
torch.zeros(3, 3)
# torch.zeros(*size) 여기서 size 는 ","로 구분하며 차원을 여러개로 늘릴 수 있습니다.
torch.ones(2, 2, 2)
# torch.ones(*size) 여기서 size 는 ","로 구분하며 채널을 여러개로 늘릴 수 있습니다.
torch.full((2, 3), 5)
# torch.full((size),value) => 괄호로 텐서의 크기 (2,3) 를 입력하고, 지정한 값 value (5) 로 모든 요소가 설정됩니다.
torch.eye(3)
# torch.eye(n) (nxn) 크기를 가지는 단위 행렬 반환, 단위행렬 특성 상 정사각행렬 (square matrix)만 가능
# list, tuple, numpy array를 텐서로 바꾸기
ls = [[1, 2, 3, 4, 5],[6, 7, 8, 9, 10]] # sample list 생성
tup = tuple([1, 2, 3]) # sample tuple 생성
arr = np.array([[[1, 2, 3],[4, 5, 6]],[[7, 8, 9],[10, 11, 12]]]) # sample numpy array 생성
# array 를 tensor로 바꾸기 (2)
torch.from_numpy(arr)
# torch.tensor 와 torch.as_tensor 의 차이점 알아보기
print("torch.tensor")
data1 = np.array([1, 2, 3, 4, 5]) # 샘플 데이터 리스트 생성
tensor1 = torch.tensor(data1) # memory 공유 X
data1[0] = 10 # 원본 데이터 변경
print(tensor1) # 원본 데이터의 값 변경에 영향을 받지 않음
print('-------'*10)
print("torch.as_tensor")
data2 = np.array([1, 2, 3, 4, 5])
tensor2 = torch.as_tensor(data2) # memory 공유 O
data2[0] = 10 # 원본 데이터 변경
print(tensor2) # 원본 데이터의 값 변경에 영향을 받음
data = [1, 2, 3, 4, 5]
tensor1 = torch.tensor(data) # list 에서 Tensor 변환
print("torch.tensor")
print("Output:", tensor1)
print("Type", tensor1.dtype) # dtype : Tensor 안의 원소들의 자료형, torch.tensor 는 원본의 데이터 타입을 그대로 따라감
print('-------'*3)
tensor2 = torch.Tensor(data) # list 에서 Tensor 변환
print("torch.Tensor")
print("Output:", tensor2)
print("Type", tensor2.dtype) # torch.tensor 는 float32 타입으로 Tensor 변환
- 텐서에서의 indexing 이해 및 실습
# 1차원 텐서에서 Indexing 하기
tmp_1dim = torch.tensor([i for i in range(10)]) # 0부터 9 까지의 값을 가지는 1차원 텐서 생성
print(tmp_1dim[0]) # 첫번째 원소 값 추출
print(tmp_1dim[5]) # 6번째 원소 값 추출
print(tmp_1dim[-1]) # -1 번째 원소 값 (뒤에서 첫번째) 추출
# 3차원 텐서에서 Indexing 하기
tmp_3dim = torch.randn(4, 3, 2) # 4채널, 3행, 2열
print("Shape : ", tmp_3dim.shape)
print(tmp_3dim)
print('-------'*8)
print(tmp_3dim[:,:,0].shape)
print(tmp_3dim[:,:,0]) # 전체 채널과 전체 행에서 0번째 열만 추출
print('\n') # 줄 띄움
print(tmp_3dim[0,:,1].shape)
print(tmp_3dim[0,:,1]) # 0번째 채널의 전체 행에서 1번째 열만 추출
# index_select
tmp_2dim = torch.tensor([[i for i in range(10)],[i for i in range(10, 20)]])
print(tmp_2dim)
print('\n')
my_index = torch.tensor([0, 2]) # 선택하고자 하는 index 는 텐서 형태이어야 함.
torch.index_select(tmp_2dim, dim=1, index=my_index) # 열을 기준으로 0열과 2열을 추출
# mask 를 이용한 텐서 Indexing (조건에 맞는 값만 추출)
mask = tmp_2dim >= 5 # 5보다 큰 텐서만 추출
tmp_2dim[mask] # 1차원 Tensor 로 반환
torch.masked_select(tmp_2dim, mask = mask) # tmp_2dim[tmp_2dim >= 5] 와 동일
tmp_2dim = torch.tensor([[i for i in range(10)], [i for i in range(10, 20)]])
print(tmp_2dim)
print('\n')
my_index = torch.tensor([0, 15])
torch.take(tmp_2dim, index = my_index)
# Tensor가 1차원으로 늘려졌을 때 기준으로 index 번호로 접근
tmp_2dim = torch.tensor([[i for i in range(10)],[i for i in range(10,20)]])
print(tmp_2dim)
print('\n')
recon_index = torch.tensor([[0 ,1],[9, 8]])
# 0번째 값, 1번 째 값을 0번째 행으로 설정하고, 9번째 값, 8번째 값을 1번째 행으로 설정한다.
dim = 1 # 열 기준
print(recon_index)
print('\n')
torch.gather(tmp_2dim, dim = 1, index = recon_index)
# dim =1 이므로 열 기준, 0행 0열, 0행 1열 선택, 1행 9열, 1행 8열
- 텐서의 shape 을 바꾸는 여러가지 함수 이해 및 실습
a = torch.randn(2, 3, 5) # random 한 값을 가진 (1,3,5) 텐서 생성
a.size() # 차원 크기 확인
a.shape # a.size() 와 동일
# 모양 변경
a = torch.randn(2, 3, 5) # (2,3,5) 크기를 가지는 텐서 생성
print(a)
print("Shape : ", a.size()) # 텐서 모양 반환
print('\n')
reshape_a = a.reshape(5, 6) # 3차원 텐서를 2차원 텐서로 크기 변경 (2,3,5) -> (5,6)
print(reshape_a)
print("Shape : ", reshape_a.size()) # 변경한 텐서 모양 반환
# -1 로 모양 자동 설정
reshape_auto_a = a.reshape(3, -1) # (2,3,5) 크기를 가지는 Tensor를 (3,n)의 모양으로 변경, "-1" 로 크기 자동 계산
print(reshape_auto_a.size()) # 2x3x5 = 3 x n 의 방정식을 푸는 문제로 n 이 자동설정
a.reshape(7, -1) # 2x3x5 = 3 x n 의 방정식의 해가 정수가 아니면 오류 발생
print(a)
print("Shape : ", a.size()) # 텐서 모양 반환
print('\n')
view_a = a.view(5, 6) # reshape 과 동일하게 (2,3,5) 크기를 (5,6) 크기로 변경
print(view_a)
print("Shape : ", view_a.size())
view_auto_a = a.view(3, -1) # reshape 과 동일하게 (3,n)의 모양으로 변경. "-1" 로 크기 자동 계산
print(view_auto_a.size())
tensor_a = torch.randint(1, 10, (3, 2, 5)) # 1 ~ 9의 값을 가지는 (3,2,5) 사이즈의 Tensor 생성
print(tensor_a)
print("Shape : ", tensor_a.size())
print('\n')
# (3,2,5) 를 (2,3,5) 의 크기로 변경
trans_a = tensor_a.transpose(1, 2) # 행과 열을 서로 전치, 서로 전치할 차원 2개를 지정
print(trans_a)
print("Shape : ", trans_a.size())
print(tensor_a)
print("Shape : ", tensor_a.size())
print('\n')
permute_a = tensor_a.permute(0, 2, 1) # (3,2,5)의 모양을 (3,5,2)의 모양으로 변경
print(permute_a)
print("Shape : ", permute_a.size())
- 텐서의 차원을 추가하거나 변경하는 방법에 대한 이해 및 실습
tensor_a = torch.tensor([i for i in range(10)]).reshape(5, 2) # 0부터 9까지의 숫자들을 (5,2) 크기로 변경
print(tensor_a)
print('Shape : ', tensor_a.size())
print('\n')
unsqu_a = tensor_a.unsqueeze(0) # 0번째 차원 하나 추가 (5,2) => (1,5,2)
print(unsqu_a)
print('Shape : ', unsqu_a.size())
unsqu_a2 = tensor_a.unsqueeze(-1) # 마지막번째에 차원 하나 추가 (5,2) => (5,2,1)
print(unsqu_a2)
print('Shape : ', unsqu_a2.size())
print(unsqu_a)
print("Shape : ", unsqu_a.size())
print('\n')
squ = unsqu_a.squeeze() # 차원이 1인 차원을 제거
print(squ)
print("Shape : ", squ.size())
x = torch.zeros(2, 1, 2, 1, 2) # 모든 원소가 0인 (2,1,2,1,2) 크기를 가지는 텐서
print("Shape (original) : ", x.size()) # 원래 텐서 크기
print('\n')
print("Shape (squeeze()) :", x.squeeze().size()) # 차원이 1인 차원이 여러개일 때, 모든 차원이 1인 차원 제거
print('\n')
print("Shape (squeeze(0)) :", x.squeeze(0).size()) # 0번째 차원은 차원의 크기가 1이 아니므로, 변화 없음
print('\n')
print("Shape (squeeze(1)) :", x.squeeze(1).size()) # 1번째 차원은 차원의 크기가 1이므로 제거
print('\n')
print("Shape (squeeze(0,1,3)) :", x.squeeze((0, 1, 3)).size()) # 여러 차원 제거 가능 (0번째 차원은 차원의 크기가 1이 아니기 때문에 무시)
tensor_1dim = torch.tensor([1, 2, 3, 4])
print(tensor_1dim)
print("Shape : ", tensor_1dim.size())
print('\n')
expand_tensor = tensor_1dim.expand(3, 4) # (,4) 를 (3,4) 의 크기로 확장 (값을 반복)
print(expand_tensor)
print("Shape : ", expand_tensor.size())
tensor_2dim = torch.tensor([[1, 2, 3, 4], [1, 2, 3, 4]]) # (2,4) 크기를 가진 Tensor
print(tensor_2dim)
print("Shape : ", tensor_2dim.size())
print('\n')
expand_tensor = tensor_2dim.expand(4,4) # (2,4) 를 (4,8) 의 크기로 확장 (값을 반복)
print(expand_tensor) # 에러 발생
print("Shape : ", expand_tensor.size()) # 에러 발생
tensor_1dim = torch.tensor([1, 2, 3, 4])
print(tensor_1dim)
print("Shape : ", tensor_1dim.size())
print('\n')
repeat_tensor = tensor_1dim.repeat(3, 4) # tensor_1dim 자체를 행으로 3번 반복, 열로 4번 반복
print(repeat_tensor)
print("Shape : ", repeat_tensor.size())
t = torch.tensor([i for i in range(20)]).reshape(2, 5, 2) # 0부터 19까지의 숫자를 4행 5열 Tensor로 구성
print(t)
print("Shape : ", t.size())
print('\n')
flat_tensor = t.flatten() # (2, 5, 2) 의 Tensor를 (20,)로 모양 변경, 1차원으로 변경
print(flat_tensor)
print("Shape : ", flat_tensor.size())
flat_tensor2 = t.flatten(start_dim=1) # flatten을 시작할 차원을 지정할 수 있음. 지정한 차원 이후의 모든 차원을 하나의 차원으로 평면화, 기본값 = 0 (1차원)
print(flat_tensor2)
print(flat_tensor2.size())
t = torch.tensor([i for i in range(20)]).reshape(2, 5, 2) # 0부터 19까지의 숫자를 (2, 5, 2) 크기 Tensor로 구성
print(t)
print("Shape : ", t.size())
print('\n')
ravel_tensor = t.ravel() # flatten 과 동일하게 (2,5,2) 의 텐서를 (20,)로 모양 변경, 1차원으로 변경
print(ravel_tensor)
print("Shape : ", ravel_tensor.size())
t = torch.tensor([i for i in range(20)]).reshape(2, 5, 2) # 0부터 19까지의 숫자를 (2, 5, 2) 크기 Tensor로 구성
print(t)
print("Shape : ", t.size())
print('\n')
ravel_tensor = t.ravel() # flatten 과 동일하게 (2,5,2) 의 텐서를 (20,)로 모양 변경, 1차원으로 변경
print(ravel_tensor)
print("Shape : ", ravel_tensor.size())
- 역할이 비슷한 함수들의 차이 이해 및 실습
reshape_tmp = tmp_t.reshape(-1) # reshape은 contiguous 하지 않아도 동작이 됨
print(reshape_tmp)
print(reshape_tmp.is_contiguous()) # contiguous 하지 않았던 Tensor를 contiguous 하게 변경해 줌
# (view , reshape) vs unsqueeze
tensor_a = torch.randn(2, 3)
# (2, 3) 의 텐서를 (2, 3, 1)의 크기로 변경
view_tensor = tensor_a.view(2, 3, 1) # view 를 이용하여 (2,3,1) 의 크기로 변경
reshape_tensor = tensor_a.reshape(2, 3, 1) # reshape 를 이용하여 (2,3,1) 의 크기로 변경
unsqueeze_tensor = tensor_a.unsqueeze(-1) # unsqueeze 를 이용하여 (2,3,1) 의 크기로 변경
print("View output size : ",view_tensor.size())
print("Reshape output size : ",reshape_tensor.size())
print("Unsqueeze output size : ",unsqueeze_tensor.size())
import torch
tensor_a = torch.randn(2, 3, 2)
transpose_tensor = tensor_a.transpose(2, 1) # 행과 열을 전치
permute_tensor = tensor_a.permute(0, 2, 1) # 행과 열을 바꿈.
print("Transpose tensor shape : ", transpose_tensor.size())
print("Permute tensor shape : ", permute_tensor.size())
import torch
# 원본 텐서 생성
tensor_a = torch.rand(1, 1, 3)
print('Original Tensor Size')
print(tensor_a.size())
print(tensor_a)
print('\n')
# expand 사용하여 (1,1,3) => (4, 1, 3)
expand_tensor = tensor_a.expand(4, 1, -1)
print("Shape of expanded tensor:", expand_tensor.size())
print('\n')
# repeat 사용하여 (1,1,3) => (4, 1, 3)
repeat_tensor = tensor_a.repeat(4, 1, 1)
print("Shape of repeated tensor:", repeat_tensor.size())
print('\n')
# 평면화된 뷰 수정 후 원본 텐서 확인
tensor_a[:] = 0
print("Expanded Tensor")
print(expand_tensor) # 값 변경이 됨
print('\n')
print("Repeated Tensor")
print(repeat_tensor) # 깂 변경 안됨
- 여러 텐서를 합치는 방법에 대한 이해 및 실습
tensor_a = torch.randint(1, 10, (2, 3)) # 1부터 9까지의 무작위 정수가 있는 (2,3) Tensor
tensor_b = torch.rand(5, 3) # 0부터 1까지의 균등분포를 따르는 (5,3) Tensor
print("Tensor A shape : ", tensor_a.size())
print(tensor_a)
print('\n')
print("Tensor B shape : ", tensor_b.size())
print(tensor_b)
print('\n')
a_cat_b_row = torch.cat((tensor_a, tensor_b), dim=0) # dim = 0 (행), Tensor A 와 Tensor B 를 행 기준으로 합친다.
print("Concat Tensor A and B (by row) Shape : ", a_cat_b_row.shape) # (Tensor A 행 개수 + Tensor B 행 개수, Tensor A/B 열 개수)
print(a_cat_b_row)
tensor_a = torch.randint(1, 10, (3, 2)) # 1부터 9까지의 무작위 정수가 있는 (3,2) Tensor
tensor_b = torch.rand(3, 2) # 0부터 1까지의 균등분포를 따르는 (3,2) Tensor
print("Tensor A shape : ", tensor_a.size())
print(tensor_a)
print('\n')
print("Tensor B shape : ", tensor_b.size())
print(tensor_b)
print('\n')
stack_tensor_row = torch.stack([tensor_a, tensor_b], dim=0) # dim = 0, 행을 기준으로 Tensor A 에 Tensor B 를 쌓기
print("Stack A and B (by row): ", stack_tensor_row.size()) # (쌓은 Tensor 개수, Tensor A/B 행 개수, Tensor A/B 열 개수)
print(stack_tensor_row)
- 하나의 텐서를 여러개로 나누는 방법에 대한 이해 및 실습
tensor_a = torch.randint(1, 10, (6, 4)) # (6,4) 텐서
print("Original : ", tensor_a)
print('\n')
chunk_num = 3
chunk_tensor = torch.chunk(tensor_a, chunks = chunk_num, dim=0) # dim = 0 (행), 6개의 행이 3개로 나누어 떨어지므로 3개의 텐서로 분리
print(f'{len(chunk_tensor)} 개의 Tensor로 분리')
print('\n')
for idx,a in enumerate(chunk_tensor):
print(f'{idx} 번째 Tensor \n{a}')
print(f'{idx} 번째 Tensor 크기', a.size())
print('---'*10)
tensor_a = torch.randint(1, 10, (6, 4)) # (6,4) 텐서
print(tensor_a)
print('\n')
split_size = 2
split_tensor = torch.split(tensor_a , split_size_or_sections = split_size, dim=0) # dim = 0 (행), 텐서 A 를 행의 길이가 2 (split_size)인 텐서로 나눔
print(f'{len(split_tensor)} 개의 Tensor로 분리')
print('\n')
for idx,a in enumerate(split_tensor):
print(f'{idx} 번째 Tensor \n{a}')
print(f'{idx} 번째 Tensor 크기', a.size())
print('---'*10)
tensor_a = torch.randint(1, 10, (6, 4)) # (6,4) 텐서
print("Original : ", tensor_a)
print('\n')
split_num = [2, 4]
split_tensor = torch.split(tensor_a, split_size_or_sections = split_num, dim=0) # dim = 0 (행), 텐서 A 를 행의 길이가 (2개인 텐서와 4개인 텐서)로 나눔
print(f'{len(split_tensor)} 개의 Tensor로 분리')
print('\n')
for idx,a in enumerate(split_tensor):
print(f'{idx} 번째 Tensor \n{a}')
print(f'{idx} 번째 Tensor 크기', a.size())
print('---'*10)
- 텐서 간의 계산 실습
tensor_a = torch.tensor([[1, -1], [2, 3]])
tensor_b = torch.tensor([[2, -2] ,[3, 1]])
print('덧셈')
print("a+b : \n", tensor_a + tensor_b)
print('\n')
print("torch.add(a,b) : \n", torch.add(tensor_a, tensor_b))
print('---'*10)
print('뺄셈')
print("a-b : \n", tensor_a - tensor_b)
print('\n')
print("torch.sub(a,b) : \n", torch.sub(tensor_a, tensor_b))
print('---'*10)
print('곱셈')
print("a*b : \n", tensor_a * tensor_b)
print('\n')
print("torch.mul(a,b) : \n", torch.mul(tensor_a, tensor_b))
print('---'*10)
print('나눗셈')
print("a/b : \n", tensor_a / tensor_b)
print('\n')
print("torch.div(a,b) : \n", torch.div(tensor_a, tensor_b))
tensor_a = torch.tensor([[1, 2], [3, 4]])
print(tensor_a)
print("Shape : ", tensor_a.size())
print('\n')
print("dimension 지정 안했을 때 : ", torch.sum(tensor_a)) # 모든 원소의 합을 반환 함
print("dim = 0 일 때 : ", torch.sum(tensor_a, dim=0)) # 행을 기준 (행 인덱스 변화)으로 합함 (0행 0열 + 1행 0열, 0행 1열 + 1행 1열)
print("dim = 1 일 때 : ", torch.sum(tensor_a, dim=1)) # 열을 기준 (열 인덱스 변화)으로 합함 (0행 0열 + 0행 1열, 1행 0열 + 1행 1열)
tensor_a = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32) # mean 은 실수가 나올 수 있으므로 float 로 지정해주어야 함.
print(tensor_a)
print("Shape : ", tensor_a.size())
print('\n')
print("dimension 지정 안했을 때 : ", torch.mean(tensor_a)) # 모든 원소의 평균을 반환 함
print("dim = 0 일 때 : ", torch.mean(tensor_a, dim=0)) # 행을 기준 (행 인덱스 변화)으로 평균 구함 ((0행 0열 + 1행 0열)/2, (0행 1열 + 1행 1열)/2)
print("dim = 1 일 때 : ", torch.mean(tensor_a, dim=1)) # 열을 기준 (열 인덱스 변화)으로 평균 구함 ((0행 0열 + 0행 1열)/2, (1행 0열 + 1행 1열)/2)
import torch
tensor_a = torch.tensor([[1, 2], [3, 4]])
print(tensor_a)
print("Shape : ", tensor_a.size())
print('\n')
print("dimension 지정 안했을 때 : ", torch.max(tensor_a)) # 모든 원소 중 최댓값 반환
print("dim = 0 일 때 : ", torch.max(tensor_a, dim=0).values) # 행을 기준 (행 인덱스 변화)으로 max 비교 (max(0행 0열 , 1행 0열), max(0행 1열 , 1행 1열))
print("dim = 1 일 때 : ", torch.max(tensor_a, dim=1).values) # 열을 기준 (열 인덱스 변화)으로 max 비교 (max(0행 0열 , 0행 1열), max(1행 0열 , 1행 1열))
print('\n')
print("dimension 지정 안했을 때 : ", torch.min(tensor_a)) # 모든 원소의 최솟값 반환 함
print("dim = 0 일 때 : ", torch.min(tensor_a, dim=0).values) # 행을 기준 (행 인덱스 변화)으로 min 비교 (min(0행 0열 , 1행 0열), min(0행 1열 , 1행 1열))
print("dim = 1 일 때 : ", torch.min(tensor_a, dim=1).values) # 열을 기준 (열 인덱스 변화)으로 min 비교 (min(0행 0열 , 0행 1열), min(1행 0열 , 1행 1열))
tensor_a = torch.tensor([[1, 2], [3, 4]])
print(tensor_a)
print("Shape : ",tensor_a.size())
print('\n')
print("dimension 지정 안했을 때 : ", torch.argmax(tensor_a)) # 모든 원소 중 최댓값 위치 반환함
print("dim = 0 일 때 : ", torch.argmax(tensor_a, dim=0)) # 행을 기준 (행 인덱스 변화)으로 max 비교 (max(0행 0열 , 1행 0열), max(0행 1열 , 1행 1열)) => 위치 반환
print("dim = 1 일 때 : ", torch.argmax(tensor_a, dim=1)) # 열을 기준 (열 인덱스 변화)으로 max 비교 (max(0행 0열 , 0행 1열), max(1행 0열 , 1행 1열)) => 위치 반환
print('\n')
print("dimension 지정 안했을 때 : ", torch.argmin(tensor_a)) # 모든 원소의 최솟값 위치 반환 함
print("dim = 0 일 때 : ", torch.argmin(tensor_a, dim=0)) # 행을 기준 (행 인덱스 변화)으로 min 비교 (min(0행 0열 , 1행 0열), min(0행 1열 , 1행 1열)) => 위치 반환
print("dim = 1 일 때 : ", torch.argmin(tensor_a, dim=1)) # 열을 기준 (열 인덱스 변화)으로 min 비교 (min(0행 0열 , 0행 1열), min(1행 0열 , 1행 1열)) => 위치 반환
v1 = torch.tensor([1, 2])
u1 = torch.tensor([3, 4])
print("v1.dot(u1) : ", v1.dot(u1)) # v1 과 u1 내적 (torch.tensor 에도 dot 함수 존재)
print("torch.dot(v1, u1) : ", torch.dot(v1, u1)) # v1 과 u1 내적
A = torch.tensor([[1, 2], [3, 4]]) # (2,2) Tensor
B = torch.tensor([[-1, 2], [1, 0]]) # (2,2) Tensor
print("A: ", A)
print("B: ", B)
print('\n')
print("AB : ", torch.matmul(A, B)) # A에서 B를 행렬곱
print("BA : ", B.matmul(A)) # B에서 A를 행렬곱
- Broadcasting 을 이용한 텐서 값 변경
tensor_a = torch.randn(3, 2)
print("Original : \n", tensor_a)
print('\n')
## 0 행의 모든 열을 10 으로 변경하기
tensor_a[0, :] = 10 # 0행의 모든 열에 broadcasting 을 통한 scalar 값 대입
print("변경된 텐서 : \n", tensor_a)
tensor_a = torch.randn(3, 2)
print("Original : \n", tensor_a)
print('\n')
## 모든 값을 tensor [0,1]로 변경하기
tensor_a[:, :] = torch.tensor([0, 1]) # 모든 값에 접근하여 [0,1] 로 변경
print("변경된 Tensor : \n", tensor_a)
- Broadcasting 을 이용한 차원이 다른 텐서 간의 계산 실습
tensor_a = torch.eye(3)
print("Tensor A : \n",tensor_a)
print('\n')
tensor_b = torch.tensor([1, 2, 3])
print("Tensor B : \n", tensor_b)
print('\n')
print('A + B : \n', tensor_a + tensor_b) # broadcasting을 통해 (3,) 인 B가 (3,3)으로 변환되어 계산 (행의 확장)
tensor_a = torch.eye(3)
print("Tensor A : \n", tensor_a)
print('\n')
tensor_b = torch.tensor([1, 2, 3]).reshape(3, 1) # 행 벡터로 형식으로 변환
print("Tensor B : \n", tensor_b)
print('\n')
print('A + B : \n', tensor_a + tensor_b) # broadcasting을 통해 (3,1) 인 B가 (3,3)으로 변환되어 계산 (열의 확장)
# 차원 생성 후 broadcasting
unseq_mean = mean_a.unsqueeze(-1) # 마지막 축 추가
print(unseq_mean.size())
print('\n')
print(tensor_a - unseq_mean)
- COO Tensor 에 대한 이해 및 실습
a = torch.tensor([[0, 2.], [3, 0]])
a.to_sparse() # COO Sparse tensor 로 변환
indices = torch.tensor([[0, 1, 1],[2, 0, 1]]) # 0이 아닌 값의 (index, column) pairs
values = torch.tensor([4, 5, 6]) # 0 이 아닌 값의 values, values의 사이
sparse_tensor = torch.sparse_coo_tensor(indices = indices, values = values, size=(2, 3)) # (2,3)의 sparse tensor
print(sparse_tensor)
print('\n')
print(sparse_tensor.to_dense())
- CSC/CSR Tensor 에 대한 이해 및 실습
t = torch.tensor([[0, 0, 4, 3], [5, 6, 0, 0]])
print("Shape : ", t.size())
print(t)
print('\n')
t.to_sparse_csr() # Dense Tensor를 CSR Sparse Tensor 형식으로 변환
t = torch.tensor([[0, 0, 4, 3], [5, 6, 0, 0]])
print("Shape : ", t.size())
print(t)
print('\n')
t.to_sparse_csc() # Dense Tensor 를 CSC Spare tensor 형식으로 변환
crow_indices = torch.tensor([0, 2, 2]) # 0이 아닌 행의 위치 (첫번쨰는 무조건 0), 즉 row_pointer
col_indices = torch.tensor([0, 1]) # 0이 아닌 열의 위치
values = torch.tensor([1, 2]) # 0이 아닌 값
csr = torch.sparse_csr_tensor(crow_indices = crow_indices, col_indices = col_indices, values = values)
print(csr)
print('\n')
print(csr.to_dense())
ccol_indices = torch.tensor([0, 2, 2]) # 0이 아닌 열의 위치 (첫번쨰는 무조건 0), 즉 column_pointer
row_indices = torch.tensor([0, 1]) # 0이 아닌 행의 위치
values = torch.tensor([1, 2]) # 0이 아닌 값
csc = torch.sparse_csc_tensor(ccol_indices = ccol_indices, row_indices = row_indices, values = values)
print(csc)
print('\n')
print(csc.to_dense())
- Sparse Tensor의 필요성 이해 및 실습
i = torch.randint(0, 100000, (200000,)).reshape(2, -1)
v = torch.rand(100000)
coo_sparse_tensor = torch.sparse_coo_tensor(indices = i, values = v, size = [100000, 100000]) # COO Sparse Tensor (100000 x 100000)
crow = torch.randint(0, 100000, (100000,))
col = torch.randint(0, 100000, (100000,))
v = torch.rand(100000)
csr_sparse_tensor = torch.sparse_csr_tensor(crow_indices = crow, col_indices = col, values = v) # CSR Sparse Tensor (100000 x 100000)
# COO 형식으로 만들어진 Sparse Tensor 를 Dense Tensor 로 변환 , 메모리 아웃
coo_sparse_tensor.to_dense()
# 커널 재시작 하기에 다시 torch library 로드
import torch
# CSR 형식으로 만들어진 Sparse Tensor 를 Dense Tensor 로 변환 , 메모리 아웃
csr_sparse_tensor.to_dense()
# 커널 재시작 하기에 다시 torch library 로드
import torch
- Sparse Tensor 의 조작 예시
# Sparse 와 Sparse Tensor 간의 연산 (2차원)
a = torch.tensor([[0, 1], [0, 2]], dtype=torch.float)
b = torch.tensor([[1, 0],[0, 0]], dtype=torch.float)
sparse_a = a.to_sparse()
sparse_b = b.to_sparse()
print('덧셈')
print(torch.add(a, b).to_dense() == torch.add(sparse_a, sparse_b).to_dense())
print('\n')
print('곱셈')
print(torch.mul(a, b).to_dense() == torch.mul(sparse_a, sparse_b).to_dense())
print('\n')
print('행렬곱')
print(torch.matmul(a, b).to_dense() == torch.matmul(sparse_a, sparse_b).to_dense())
# Sparse 와 Sparse Tensor 간의 연산 (3차원)
a = torch.tensor([[[0, 1], [0, 2]], [[0, 1], [0, 2]]], dtype=torch.float)
b = torch.tensor([[[1, 0],[0, 0]], [[1, 0], [0, 0]]], dtype=torch.float)
sparse_a = a.to_sparse()
sparse_b = b.to_sparse()
print('덧셈')
print(torch.add(a, b).to_dense() == torch.add(sparse_a, sparse_b).to_dense())
print('\n')
print('곱셈')
print(torch.mul(a, b).to_dense() == torch.mul(sparse_a, sparse_b).to_dense())
print('\n')
print('행렬곱')
print(torch.matmul(a, b).to_dense() == torch.matmul(sparse_a, sparse_b).to_dense()) # 에러 발생
# Dense 와 Sparse Tensor 간의 연산 (2차원)
a = torch.tensor([[0,1],[0,2]],dtype=torch.float)
b = torch.tensor([[1,0],[0,0]],dtype=torch.float).to_sparse()
sparse_b = b.to_sparse()
print('덧셈')
print(torch.add(a, b).to_dense() == torch.add(a, sparse_b).to_dense())
print('\n')
print('곱셈')
print(torch.mul(a, b).to_dense() == torch.mul(a, sparse_b).to_dense())
print('\n')
print('행렬곱')
print(torch.matmul(a, b).to_dense() == torch.matmul(a, sparse_b).to_dense())
a = torch.tensor([[[0, 1], [0, 2]], [[0, 1], [0, 2]]],dtype=torch.float)
b = torch.tensor([[[1, 0], [0, 0]], [[1, 0], [0, 0]]],dtype=torch.float)
sparse_b = b.to_sparse()
print('덧셈')
print(torch.add(a, b).to_dense() == torch.add(a, sparse_b).to_dense())
print('\n')
print('곱셈')
print(torch.mul(a, b).to_dense() == torch.mul(a, sparse_b).to_dense())
print('\n')
print('행렬곱')
print(torch.matmul(a, b).to_dense() == torch.matmul(a, sparse_b).to_dense()) # 에러 발생
a = torch.tensor([[0,1 ], [0, 2]], dtype=torch.float)
b = torch.tensor([[[1, 0], [0, 0]], [[1, 0], [0, 0]]], dtype=torch.float)
sparse_a = a.to_sparse()
sparse_b = b.to_sparse()
print('2차원 Sparse Tensor 인덱싱')
print(a[0] == sparse_a[0].to_dense())
print('\n')
print('3차원 Sprase Tensor 인덱싱')
print(b[0] == sparse_b[0].to_dense())
'Study > 머신러닝' 카테고리의 다른 글
PyTorch 전이학습 (3) | 2024.12.17 |
---|---|
딥러닝과 PyTorch (0) | 2024.12.17 |
Pytorch (0) | 2024.12.16 |
Deep Learning 기본 모델 구조 (2) | 2024.12.16 |
Deep Learning 성능 고도화 학습 (0) | 2024.12.16 |