반응형

오늘은 Pytorch를 통해 RNN을 알아보겠습니다. 

 

https://www.youtube.com/watch?v=bPRfnlG6dtU&t=2674s

RNN의 기본구조를 모르시면 위 링크를 보시는걸 추천드립니다.

 

Pytorch document에 RNN을 확인하겠습니다.

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

 

RNN with Pytorch

 

RNN with Book

 

 

1. RNN (default)

 

RNN의 입력은 [sequence, batch_size, input_size] 으로 이루어집니다.

 

import torch
import torch.nn as nn


input = torch.randn(4, 7, 5)
print(input.size())
# 결과 
# torch.Size([4, 7, 5])

sequence = 4차원,

batch_size = 7차원,

input_size = 5차원 인 임의의 input 데이터를 생성했습니다.

 

2. nn.RNN

 

RNN의 기본 인자 값으로 input_size=5, hidden_size=4, num_layer=3 값을 받습니다. 

rnn_layer = nn.RNN(input_size=5, hidden_size=4, num_layers=3)
print(rnn_layer)

# 결과
# RNN(5, 4, num_layers=3, batch_first=True)

input_size는 Input의 input_size의 값을 받으므로, 5로 적어주시면 됩니다.

 

hidden_size는 nn.RNN을 걸치면 나오는 Output으로 볼 수 있으며, 위 그림의 주황색 박스입니다. 

 

hidden_size = 4 이므로 output 또한 4차원으로 만들어집니다. 

 

num_layer는 층으로 보시면 편할 것 같습니다. num_layer = 3 이므로 3개의 층이 생성됩니다. 

 

(output, hidden) = rnn_layer(input)

print("Output size : {}".format(output.size()))
print("Hidden size : {}".format(hidden.size()))

# 결과 
# Output size : torch.Size([4, 7, 4])
# Hidden size : torch.Size([3, 7, 4])

 

 

RNN Structure

RNN을 검색해보셨다면 위 그림은 정말 많이 보셨을거라고 생각합니다. 

 

처음에 RNN을 공부할 때 위 그림이 무슨 말인고 하고 별로 신경쓰지 않았지만, 상당히 중요한 그림입니다. 

 

nn.RNN의 함수를 사용하면 위 코딩처럼 output, hidden의 값을 뱉어냅니다. 

 

2개의 값을 뱉어낸 이유는 그림을 쉽게 이해할 수 있습니다. 

RNN return output, hidden

A 박스에 input X0의 값이 들어가면, output은 h0 의 값을 반환하고 hidden은 다음 Sequnece의 A박스에 값이 들어가므로 output과 hidden의 값을 반환합니다. 

 

Output size : torch.Size[4, 7, 4])

Hidden size : torch.Size[3, 7, 4])

 

값의 size를 찍어보면 이상한 형태로 사이즈가 반환됩니다. 

 

output : [sequence, batch_size, hidden_size] 

hidden : [num_layer, batch_size, hidden_size] 

 

값의 반환은 위처럼 규칙을 따라 모양이 변형됩니다. 

 

batch_size = 7

sequence = 4

input_size = 5

hidden_size =4

num_layer = 3

 

위에서 사용하는 인자들을 보면서 하나씩 봐보면 값이 일치합니다. 

 

조금 더 자세히 보도록 하겠습니다.

 

output[-1], hidden[-1]

output[-1]이란.

output : [sequence, batch_size, hidden_size]  에서 Sequence의 가장 끝을 의미합니다. (보라색 상자)

hidden[-1]이란.

hidden : [num_layer, batch_size, hidden_size]  에서 num_layer의 가장 끝을 의미합니다. (회색 상자)

 

결국 output[-1]과 hidden[-1]이 hT(k)를 지칭하므로, 둘은 같은 값을 의미합니다 한 번 찍어보겠습니다.

print(output[-1])
print(hidden[-1])

# 결과
tensor([[ 0.8153, -0.1394,  0.3829,  0.0173],
        [ 0.8094,  0.2289,  0.4830, -0.2243],
        [ 0.7936, -0.0426,  0.3890, -0.0643],
        [ 0.7714,  0.3094,  0.4685, -0.2558],
        [ 0.8282,  0.1141,  0.4310, -0.1885],
        [ 0.8027, -0.0607,  0.3745, -0.0249],
        [ 0.8292, -0.1473,  0.4938,  0.0935]], grad_fn=<SelectBackward>)

tensor([[ 0.8153, -0.1394,  0.3829,  0.0173],
        [ 0.8094,  0.2289,  0.4830, -0.2243],
        [ 0.7936, -0.0426,  0.3890, -0.0643],
        [ 0.7714,  0.3094,  0.4685, -0.2558],
        [ 0.8282,  0.1141,  0.4310, -0.1885],
        [ 0.8027, -0.0607,  0.3745, -0.0249],
        [ 0.8292, -0.1473,  0.4938,  0.0935]], grad_fn=<SelectBackward>)

 실제로도 들어있는 값들이 같음을 알 수 있습니다. 

 

 

2. batch_first=True ( default는 False이다. )

 

pytorch는 모델에 데이터를 넣을 때는 batch_size를 가장 먼저 앞에 나옵니다. 

 

하지만 RNN이나 LSTM 같은 경우는 batch_size가 아닌 sequence가 가장 먼저 나옵니다.

 

input : [sequence, batch_size, input_size]

 

model에서 나오는 output 또한 sequence가 가장 먼저 나옵니다.

 

output : [sequence, batch_size, hidden_size]

 

이렇게 sequence가 가장 앞에서 사용되면 가끔 데이터 차원이 헷갈립니다. 

 

그럴 때 사용하는 것이 batch_first=True 입니다. default는 False입니다.

 

batch_first를 True로 설정하면 batch_size가 제일 먼자 앞으로 이동합니다. 

 

input : [batch_size, sequence, input_size]

   

output : [batch_size, sequence, hidden_size]

 

hidden은 그대로입니다.

 

사용하는 방법은 간단합니다. 

 

import torch
import torch.nn as nn


input = torch.randn(4, 7, 5)
print(input.size())

rnn_layer = nn.RNN(input_size=5, hidden_size=4, num_layers=3, batch_first=True)
print(rnn_layer)

# 결과 
# RNN(5, 4, num_layers=3, batch_first=True)

 

batch_first를 True하게 되어 batch_size가 가장 앞으로 가게 됩니다. 

 

그렇다면 인자들에 전달된 값 또한 변합니다.

 

batch_size = 4

sequence = 7

input_size = 5

hidden_size =4

num_layer = 3

 

으로 변경됩니다.

 

print("Output size : {}".format(output.size()))
print("Hidden size : {}".format(hidden.size()))

#output : [batch_size, sequence, hidden_size]
#hidden : [num_layer, batch_size, hidden_size] 
# Output size : torch.Size([4, 7, 4])
# Hidden size : torch.Size([3, 4, 4])

모양이 달라졌지만 사이즈 이외에는 크게 바뀌는 것은 없습니다. 

 

indexing 하는 방법을 sequnece, num_layer를 똑같이 적용시켜주면 됩니다.

 

print(output[:, -1, :])
print()
print(hidden[-1])

#결과
tensor([[-0.2105,  0.4423,  0.8115, -0.2838],
        [-0.4891,  0.1518,  0.8839, -0.3675],
        [-0.5495,  0.3221,  0.8500, -0.4782],
        [-0.5822,  0.3100,  0.7938, -0.4242]], grad_fn=<SliceBackward>)

tensor([[-0.2105,  0.4423,  0.8115, -0.2838],
        [-0.4891,  0.1518,  0.8839, -0.3675],
        [-0.5495,  0.3221,  0.8500, -0.4782],
        [-0.5822,  0.3100,  0.7938, -0.4242]], grad_fn=<SelectBackward>)

 

 

728x90
반응형
반응형

안녕하세요. 

 

오늘은 파이썬 기본 문법인 List와 Dict을 활용한 면접 문제 코딩을 하나 작성하도록 하겠습니다. 

 

tuple( ( ) 사용) : 일반적으로 배열(정적할당)처럼 사용된다. 그러므로 불가변적으로 변수를 집어넣을 수 없다.

List( [ ] 사용 ) : 일반적으로 배열(동적할당)처럼 사용된다. 그러므로 가변적으로 변수를 집어 넣을 수 있다.

Dict( { } 사용) : List와 달리 Index도 입력해야한다.

 

그렇다면 Dictionary은 왜 사용하는가? 

 

그 이유는 데이터 처리에 있어 Dict은 프로그래머가 이미 Index를 알고 있어, 바로 해당하는 데이터로 접근합니다.

 

List는 배열 구조로서 크기가 10(0~9)인 List가 있다고 가정하게 되면, 9번 데이터에 접근하기 위해 순차적으로 인덱스가 0부터 8까지 모두 접근을 한 이 후에 9번에 접근하게 됩니다. 

 

List는 9번을 메모리에 들락날락한다면, 

 

DIctionary는 단, 1번으로 자신이 원하는 메모리에 접근할 수 있습니다. 

 

그러므로 List에 비해 DIct의 속도가 더 빠릅니다. 메모리의 사이즈가 더 커진다면 그 속도의 차이는 더욱 커질 것입니다.

 

 

문제 : List : 사과, 바나나, 딸기, 키위, 복숭아의 갯수가 몇개인가? 

 

#list
fruits = ["사과", "사과", "바나나", "바나나", "딸기", "키위", "복숭아", "복숭아", "복숭아"]

#dict
dict = {}

for fruit in fruits:
	if fruit in dict:
    		dict[fruit] = d[fruit] +1
	else:
		dict[fruit] = 1
        
print(dict)

#결과 : {'사과': 2, '바나나': 2, '딸기': 1,'키위': 1, '복숭아': 3}

 

 

처음에  정답을 봤을 때, 정말 간단한 코딩이지만 List와 Dict에 정확히 이해해야만 풀 수 있는 문제입니다.

 

학기를 시작하여 매일은 아니지만 주에 몇 번씩 파이썬 면접문제를 몇 개씩 올려서 풀어볼려고 합니다.

728x90
반응형
반응형
type(nums)

pytorch1.ipynb
0.01MB

안녕하세요. 이제 파이토치로 딥러닝할 준비가 다 되었습니다.

이제 딥러닝을 하기 전에 파이토치 문법 구조에 대해서 알아보겠습니다.

 

텐서플로우는 numpyarray를 기본으로 텐서(3차 이상)를 사용한답니다. 

우리들이 공부할 파이토치는 torch를 가지고 놉니다. 

 

그냥 numpy = torch 이렇게 보시면 될 것 같습니다. 

이번 시간에 파이토치의 기본인 torch는 데이터 전처리 과정이라고 볼 수 있습니다. 

 

수천 수만 데이터를 다루기 위해서는 전처리 과정을 거쳐야 합니다. 

모델을 구상하고, 반복, 학습만큼 데이터 전처리 과정은 상당히 중요합니다. 

 

1. 기본 구조

import torch
import numpy as np

nums = torch.arange(9)
nums

 

tensor([0, 1, 2, 3, 4, 5, 6, 7, 8])

 

nums.shape

 

torch.Size([9])

 

type(nums)

 

torch.Tensor

 

 nums.numpy()

 

array([0, 1, 2, 3, 4, 5, 6, 7, 8], dtype=int64)

 

nums.reshape(3,3) # 데이터 전처리하는데 가장 많이 사용

 

tensor([[0, 1, 2],

           [3, 4, 5],

           [6, 7, 8]])

 

randoms = torch.rand((3,3))
randoms

 

tensor([[0.5127, 0.8462, 0.1646],

           [0.1679, 0.7492, 0.1046],

           [0.6169, 0.6014, 0.1144]])

 

zeros = torch.zeros((3,3))
zeros

 

tensor([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]])

 

ones = torch.ones((3,3))
ones

 

tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]])

 

torch.zeros_like(ones)

 

tensor([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]])

 

 

2. 연산

import torch
import numpy as np

nums = torch.arange(9)
nums * 3

 

tensor([ 0, 3, 6, 9, 12, 15, 18, 21, 24])

 

nums = nums.reshape((3,3))
nums + nums

 

tensor([[ 0, 2, 4],

          [ 6, 8, 10],

          [12, 14, 16]])

 

result = torch.add(nums, 10)

 

array([[10, 11, 12],

        [13, 14, 15],

        [16, 17, 18]], dtype=int64)

 

 

그 외 사칙연산은 이 방법과 전부 일치합니다. 

 

하지만 조금 연산에 주의해야 하는 부분은 곱셈 쪽입니다.

torch는 하나의 행렬(1, 2차)이며, 텐서(3차, dim = 3, rank = 3)로 볼 수 있습니다.

 

  • * : 스칼라 곱
  • dot : 벡터 내적
  • mv : 행렬과 벡터의 곱
  • mm : 행렬과 행렬의 곱
  • matmul : 인수의 종류에 따라서 자동으로 dot, mv, mm을 선택

곱셈의 종류가 상당합니다. 

스칼라 곱, 행렬 곱은 우리들이 공부했던 고등수학에 나오는 것과 일치합니다.

 

하지만 dot은 어떻게 할까요?

dot은 2차에서는 행렬의 곱과 똑같으나 3차 이상에서는 계산이 많이 달라집니다. 

 

수학적인 부분도 중요하나, 저는 코딩 쪽에 비중을 두면서 공부하도록 하겠습니다.  

 

좀 정리하고 보니 별로네요..

코드블럭을 처음 써봤는데 이상하기도 하고,

다음 글은 좀 더 필요하고 유용한 필요한 부분만 써야할 것 같습니다.

728x90
반응형

+ Recent posts