Comment :
Udaicty Deep Learning - RNN - Project 3. TV Script Generation, 즉 TV 시트콤 대본 생성 RNN 모델을 만드는 과정에서
np.roll()
이란 함수를 보았고 해당 함수를 간단하게 학습 및 정리하려 한다.
상황 :
[+] TV Script Generation에서의 상황은... 훈련이 완료된 모델에 Prime 단어를 하나 입력해서 추후에 예측되는 단어를 쭈루룩, 즉 대본(Script)을 생성하려한다.
모델에 들어갈 입력 Tensor의 사이즈는
(batch_size, seq_length)
인데,훈련이 아닌실사용에서는batch_size
는 의미가 없으므로(1, seq_length)
사이즈의 Tensor가 입력 데이터가 된다.Prime 단어가
jerry:
이고 Padding word가<Pad>
라고 하면, 맨처음 입력으로 쓰일 Tensor는 아래와 같다.
tensor[ <Pad>, <Pad>, ... , <Pad>, jerry:]
length : =seq_length
RNN의 기본 개념은 이전, 이이전 Timestep의 값들을 기억하여 다음, 다다음 값을 예측하는 것이므로
만약 위의 입력 Tensor를 통해 예측된 단어가How
라면 두번째 입력으로 쓰일 Tensor는 아래와 같아야 할 것이다.
tensor[ <Pad>, <Pad>, ... , jerry:, How]
이렇게 NumPy Array(지금은 Tensor이지만 바로 np.roll에 적용해도 되긴한다!)속 요소를 '굴리는', 즉 특정방향으로 어렸을적 자물쇠 돌리기 or 큐브 돌리기처럼 나란히 이동시키는 것을 NumPy roll로 할 수 있다.
참고 : NumPy roll() manual
numpy.roll(a, shift, axis=None)
Roll array elements along a given axis.
Elements that roll beyond the last position are re-introduced at the first.
Array의 요소들을 주어진 axis에 따라 Roll한다.
Array의 사이즈, 즉 범위를 넘는 요소들은 첫번째로 다시 돌아온다
Parameters
a
: input arrayshift
: int or tuple, 요소들이 이동할 위치 개수(대충 몇칸 움직이는지...) tuple로 주어졌을때에는axis
도 tuple로 받아야하며 두 tuple은 서로 대응하여aixs
tuple의 i번째 축으로shift
tuple의 i번째 값만큼 이동함 /shift
는 하나의 int값인데axis
가 tuple로 주어질 경우axis
tuple내 모든 축에서shift
값만큼 이동axis
: int or tuple, Axis or axes along which elements are shifted. By default, the array is flattened before shifting
Return
- Output array, with the same shape as
a
글로 보니깐 확 와닿지 않는다, 코드로 한번 봐보자
x = np.arange(10)
x
>>>
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# x array의 요소들을 뒤로 2칸씩 이동시켜라
np.roll(x,2)
>>>
array([8, 9, 0, 1, 2, 3, 4, 5, 6, 7])
-----------------------------------
# x array의 요소들을 앞으로 2칸씩 이동시켜라
np.roll(x,-2)
>>>
array([2, 3, 4, 5, 6, 7, 8, 9, 0, 1])
[!] (위에 메뉴얼대로) Array의 범위를 넘는 요소들은 다시 첫번째 또는 마지막으로 들어온다
x2 = np.reshape(x, (2,5))
x2
>>>
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
# x2 array의 요소들을 뒤로 1칸씩 이동시켜라
np.roll(x2,1)
>>>
array([[9, 0, 1, 2, 3],
[4, 5, 6, 7, 8]])
[!] axis
, 즉 shift될 축을 따로 지정하지 않았으므로 (위에 메뉴얼대로) 1차원으로 flatten된 array를 1칸씩 이동시킨것과 같다
# x2 array의 요소들을 axis=0, 즉 Row를 잡아 1칸씩 이동시켜라
np.roll(x2, 1, axis=0)
>>>
array([[5, 6, 7, 8, 9],
[0, 1, 2, 3, 4]])
# 아예 그냥 모든 요소들의 Row위치만 1칸씩 이동시킴
# x2 array의 요소들을 axis=1, 즉 Column을 잡아 1칸씩 이동시켜라
np.roll(x2, 1, axis=1)
>>>
array([[4, 0, 1, 2, 3],
[9, 5, 6, 7, 8]])
# Column위치만 1칸씩 이동시킴
# x2 array의 요소들을
# axis=1 기준으로 -1칸
# axis=0 기준으로 1칸 이동시켜라
np.roll(x2, (-1,1), axis=(1,0)
>>>
# 1번 : Column 기준으로 -1칸
array([[1, 2, 3, 4, 0],
6, 7, 8, 9, 5]])
# 2번 : Row 기준으로 1칸
array([[6, 7, 8, 9, 5],
1, 2, 3, 4, 0]])
x3 = np.arange(1,28).reshape((3,3,3))
x3
>>>
array([[[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[19, 20, 21],
[22, 23, 24],
[25, 26, 27]]])
# x3 array의 요소들을 axis=0, 즉 depth 기준으로 1칸씩 이동시켜라
np.roll(x3, 1, axis=0)
>>>
array([[[19, 20, 21],
[22, 23, 24],
[25, 26, 27]],
[[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]]])
(3,3,3)
사이즈의 Cube의 (0,0,0)
번째 요소만 7이고 나머지는 모두 0이다
cube = np.zeros( (3,3,3) )
cube[0][0][0] = 7
cube
>>>
array([[[7., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]]])
이와 같은 3D Array에서 저 7 요소를 (2,2,2)
, 즉 맨 구석 맨 뒤로 보내려면 어떻게 해야할까?
np.roll(cube, 2, axis=(0,1,2))
>>>
array([[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 7.]]])
[!] axis
는 tuple인데 이동할 칸수, 즉 shift
가 1개의 정수값일 경우 모든 axis에 대해서 shift
정수값만큼 이동한다. 즉 (0,0,0)
에 있던 7 요소를 (2,2,2)
로 이동시킴