- 시작.
이번에는 Numpy & torch.tensor를 가지고 기본적인 연산을 해보겠습니다.
제가 class를 써서 계속 구현해보는 이유는
- 기본적으로 모든 framework가 class를 통해 이루어져 있기 때문입니다.
- 우리는 class에 익숙해지고, 각 인자의 흐름을 정확하게 파악할 필요가 있습니다.
- 그에 대한 적응력을 기르고자 항상 무언가를 새로 배우면, class와 접목시켜보는 것이 중요합니다.
그리고 이번에는 간단한 bfs알고리즘을 함수 인자로 구현해보는 시도도 해보겠습니다.
즉 이번에는 자료 구조 + 알고리즘 + class + torch.tensor + Numpy 의 활용입니다.
시작합니다.
Pytorch Basic arithmetics.
1. Numpy array, torch.tensor 조작하기
import numpy as np
import torch
from collections import deque
torch.tensor에서 주로 쓰는 자료형.
- FloatTensor : 32비트 float형
- DoubleTensor : 64비트 float형
- ByteTensor : 8비트 integer형 True / Flase 당연히 integer는 0,1이니까
- LongTensro : 64비트 integer형
그런데 뒤에서 다루겠지만, 앵간하면 FloatTensor나 DoubleTensor를 쓰기 권장합니다.
알고리즘 문제를 풀 때에는 보통 자료형에 대해 직접적으로 물어보거나, 혹은 사이즈 문제로 인해(주로 dp나 greedy) float나 long long int, long long float 를 써야 할 때 제외하고 대부분은 int만 써도 거의 무방했는데 말이죠.
seed = np.array([1.,2.,3.,4.])
f_tensor = torch.FloatTensor(seed)
print(f_tensor)
d_tensor = torch.DoubleTensor(seed)
print(d_tensor)
b_tensor = torch.ByteTensor(seed)
print(b_tensor)
l_tensor = torch.LongTensor(seed)
print(l_tensor)
bool_tensor = torch.ByteTensor([True,False])
print(bool_tensor)
# 결과
tensor([1., 2., 3., 4.])
tensor([1., 2., 3., 4.], dtype=torch.float64)
tensor([1, 2, 3, 4], dtype=torch.uint8)
tensor([1, 2, 3, 4])
tensor([1, 0], dtype=torch.uint8)
2. 사칙 연산
element-wise한 연산을 하거나, 내장 module 등을 사용할 수도 있습니다.
- 행렬의 성질 : AE == EA == A
E = torch.tensor([[1,0],[0,1]])
tensor1 = torch.tensor([[3,5],[6,1]])
tensor2 = torch.tensor([[8,1],[1,1]])
위처럼 두 주어진 2 * 2 크기의 행렬이 있을 때
res = torch.tensor(np.dot(E,tensor1))
print(res)
print(tensor1)
flag=1
for x in range(len(res)):
for y in range(len(res[x])):
if res[x][y]==tensor1[x][y]:
continue
else:
flag=0
break
if flag==0:
break
if flag==1:
print("the two tensor is same")
else:
print("The two tensor is different each other")
# 결과
tensor([[3, 5],
[6, 1]])
tensor([[3, 5],
[6, 1]])
the two tensor is same
element-wise
addres = tensor1+tensor2
print(addres)
address = tensor1.add(tensor2)
print(address)
#결과
tensor([[11, 6],
[ 7, 2]])
tensor([[11, 6],
[ 7, 2]])
- 곱셈의 경우 조금 사정이 다릅니다.
1) element-wise한 곱셈 : 각 위치에 대응되는 원소와의 곱 결과를 리턴합니다.
mulress = tensor1 * tensor2
print(mulress)
#결과.
[[29. 8.]
[49. 7.]]
2) 고등학교 시절 배운 행렬 곱셈.
- IF A !=B and A not E and B not E: AB !=BA
tensor1 = torch.tensor([[3.,5.],[6.,1.]])
tensor2 = torch.tensor([[8.,1.],[1.,1.]])
matrixres = np.dot(tensor1,tensor2)
print(matrixres)
#결과
[[29. 8.]
[49. 7.]]
3. 평균 계산
- 흠 여기에서 다시 위에서 언급한 torch.tensor의 자료형이 중요하게 다가왔습니다.
tensor1 = torch.tensor([[3.,5.],[6.,1.]])
tensor2 = torch.tensor([[3,5],[6,1]])
print("{:.2f}".format(tensor1.mean()))
print("{:.2d}".format(tensor2.mean()))
tensor1의 경우 원소 뒤에 .을 찍어 자료형을 int가 아닌 float형으로 만들어주었고, 결과 역시 잘 나왔지만
tensor2의 경우 int형으로 선언하였고 int에 대한 평균을 구하려고 했더니 잘 되지 않습니다.
#결과.
3.75
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
/tmp/ipykernel_66196/1870130014.py in <module>
3 print("{:.2f}".format(tensor1.mean()))
4
----> 5 print("{:.2d}".format(tensor2.mean()))
RuntimeError: mean(): input dtype should be either floating point or complex dtypes. Got Long instead
앵간하면 그러니 float를 위주로 다루는 것이 좋겠습니다.
- dim
- dim = 0 으로 설정하면 n차원 행렬의 세로 행에 대한 평균만을 구하고
print("{}".format(tensor1.mean(dim=0)))
print("{}".format(tensor2.mean(dim=1)))
print("{}".format(tensor1.mean(dim=0)))
print("{}".format(tensor2.mean(dim=1)))
#결과
tensor([4.5000, 3.0000])
tensor([4.5000, 1.0000])
tensor([4.5000, 3.0000])
tensor([4.5000, 1.0000])
그런데 왜 {:.2f}를 쓸 수 없는 지 궁금하네요.
tensor3 = torch.tensor([[1,2],[3,4]])
print("{:.2f}".format(tensor3.mean()))
#결과.
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
/tmp/ipykernel_66196/1599467410.py in <module>
1 tensor3 = torch.tensor([[1,2],[3,4]])
----> 2 print("{:.2f}".format(tensor3.mean()))
RuntimeError: mean(): input dtype should be either floating point or complex dtypes. Got Long instead.
4. 클래스와 결합.
- 기본적인 사칙연산을 구현해보세요.
- 출력 함수 구현 시, 부모 클래스와 자식 클래스의 호출을 구분하세요.
- 간단한 2차원 지도가 torch.tensor로 주어지면, 이를 통해 bfs를 구현해보세요. 시작점은 좌측 상단이고, 도착점은 우측 하단입니다. 시작점에서 도착점으로 가는 최소 경로를 구하세요.
- 'kwargs'키워드를 사용해보세요.
- super를 써서 상속을 받을 때, 현재 상속을 받는 클래스를 명시하세요.
https://www.acmicpc.net/problem/2178
2178번: 미로 탐색
첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.
www.acmicpc.net
요 문제를 각색해 보았습니다.
- 부모 클래스
class basic:
def __init__(self,tensor1,tensor2):
self.tensor1 = tensor1
self.tensor2 = tensor2
print("basic parents class is called")
#self.basic_tensor = torch.tensor(self.tensor1+1)
def show(self):
print("basic : tensor showing :")
print('tensor1')
for x in range(len(self.tensor1)):
for y in range(len(self.tensor1[x])):
print(self.tensor1[x][y],end=' ')
print()
print()
print('tensor2')
for x in range(len(self.tensor2)):
for y in range(len(self.tensor2[x])):
print(self.tensor2[x][y],end=' ')
print()
print()
- 자식 클래스
class specific(basic):
#private
queue = deque()
#일단 specific에 대한 생성자를 먼저 생성해야겠지?
def __init__(self,**kwargs):
self.tensor1 = kwargs['tensor1']
self.tensor2 = kwargs['tensor2']
self.map = kwargs['map']
self.visited = [[False]*len(kwargs['map'][0]) for _ in range(len(kwargs['map']))]
print("specific class is called")
#basic 클래스가 만들어질 때 자동대로 basic에 대한 self가 만들어지기 때문에
# 인자로 self.tensor1,self.tensor2만 보내주면 됩니다.
super(specific,self).__init__(self.tensor1,self.tensor2)
def torch_bfs(self):
dx = [1,-1,0,0]
dy = [0,0,1,-1]
self.queue.append([0,0])
self.visited[0][0]=True
cnt=0
while self.queue:
curx,cury = self.queue.popleft()
for i in range(4):
nx = curx+dx[i]
ny = cury+dy[i]
if nx>=0 and nx<len(self.map) and ny>=0 and ny<len(self.map[0]):
if self.visited[nx][ny]==False and self.map[nx][ny]==0:
self.visited[nx][ny]=True
self.queue.append([nx,ny])
cnt+=1
return cnt
#두 행렬에 대한 dot product를 리턴
def torch_dot(self):
res = torch.tensor(np.dot(tensor1,tensor2))
return res
def torch_multiple(self):
res = torch.tensor(tensor1 * tensor2)
return res
- Input
x = torch.tensor([[1.,2.],[7.,3.]])
y = torch.tensor([[6.,3.],[8.,2.]])
mapp = torch.tensor([ [0,1,1,1,1], [0,0,0,1,0],[1,0,0,1,1],[1,0,0,0,0]])
specific_ = specific(tensor1 = x, tensor2 = y, map=mapp)
- Output
specific_.show()
# 결과
basic : tensor showing :
tensor1
tensor(1.) tensor(2.)
tensor(7.) tensor(3.)
tensor2
tensor(6.) tensor(3.)
tensor(8.) tensor(2.)
specific_.torch_bfs()
#결과
9
specific_.torch_dot()
#결과
tensor([[8., 1.],
[1., 1.]], dtype=torch.float64)
specific_.torch_multiple()
#결과
tensor([[8., 0.],
[0., 1.]])
이상입니다.
간단한 구현이었지만 class, 자료구조, 알고리즘, torch, numpy 연산을 한꺼번에 공부할 수 있어서
재미있는데, 또 나만 재미있는 거겠죠?
'ML & DL > Pytorch(base)' 카테고리의 다른 글
'찐비전공자를 위한' : Pytorch 기초 다루기 - Numpy & Tensor (0) | 2022.02.24 |
---|