(n,)을 1) 브로드캐스팅을 위해 (1,n), (n,1)로 바꿔줄 수 있다 2)(H,W)의 흑백 이미지가 있다고 할때 tensorflow는 이미지가 (H,W,C) shape으로 무조건 맞춰주기를 규칙으로 한다.
import numpy as np
a = np.arange(9) (9,)
b = a.reshape((1,-1)) (1,9)
c = a.reshape((-1,1)) (9,1)
Reshape은 원소의 개수가 변하지 않는 상태에서 shape을 바꿔주는 연산이다. 따라서 차원을 많이 늘려야하는 상황에서는 코드의 가독성이 떨어질 우려가 있다.
import numpy as np
a = np.arange(9) (9,)
b = a.reshape((1,1,-1)) (1,1,9)
c = a.reshape((1,-1,1)) (1,9,1)
d = a.reshape((-1,1,1)) (9,1,1)
조심할 스타일의 코드
import numpy as np
a = np.random.normal(size=(100,200))
b = a.reshape((1,100,200))
c = a.reshape((100,200,1))
위와 같은 방식으로 차원을 늘려줄 수도 있지만 입력이 100x200에서 다른 값으로 변한다면 b,c 모두 직접 수정해줘야 하는 debugging하기 까다로운 코드가 된다.
다음과 같은 방법으로 해보자 : TUPLE UNPACKING
import numpy as np
a = np.random.normal(size=(100,150))
a.shape (100,150)
*a.shape 100 150
print((1,*a.shape)) (1, 100, 150)
a의 shape을 자동으로 unpacking하여 tuple을 만들어주기 때문에 a가 변하면 나머지 코드도 맞춰서 실행된다.
import numpy as np
a = np.arange(9)
row_vec1 = a[np.newaxis, :] (1,9)
row_vec2 = a[None, :] (1,9)
col_vec1 = a[:, np.newaxis] (9,1)
col_vec2 = a[:,None] (9,1)
b = a[np.newaxis, ...]
c = a[..., np.newaxis]
newaxis는 내부적으로 None이다. 그러나 가독성면에서 a[None,:]보다 이해하기 좋다.
차원을 늘려주기 위한 API이다.
import numpy as np
a = np.arange(9)
b = np.expand_dims(a, axis=0)
c = np.expand_dims(a, axis=1)
a.shape (9,)
b.shape (1,9)
c.shape (9,1)
expand_dims는 원하는 차원을 선택해서 늘려줄 수 있는 장점이 있다.
import numpy as np
a = np.arange(9)
b = np.expand_dims(a, axis=(0,1)) (1,1,9)
c = np.expand_dims(a, axis=(0,2)) (1,9,1)
d = np.expand_dims(a, axis=(1,2)) (9,1,1)
더 고급진 활용은 다음과 같다
import numpy as np
a = np.arange(9).reshape((3,3))
b = np.expand_dims(a, axis=0) (1,3,3)
c = np.expand_dims(a, axis=-1) (3,3,1)
d = np.expand_dims(a, axis=(0,-1)) (1,3,3,1)
(H,W,1)이라는 이미지가 있을 때 1을 없애고 텐서를 정리하는 용도로 사용할 수 있다.
import numpy as np
a = np.ones(shape=(1,10))
b = a.reshape((10,)) (10,)
c = a.reshape((-1,)) (10,)
d = a.flatten()
import numpy as np
a = np.ones(shape=(1,3,4))
b = np.ones(shape=(3,4,1))
c = a.reshape(*a.shape[1:]) (3,4)
d = b.reshape(*b.shape[:-1]) (3,4)
*a.reshape[1:]
은 unpacking된 (1,3,4) tuple을 1번 index부터 끝까지 가져온다는 의미이다. 따라서 1은 안가져오고 (3,4)만 tuple로 가져온다.
*b.reshape[:-1]
도 마찬가지로 마지막 차원 전까지만 tuple로 가져오는 명령이다.
import numpy as np
a = np.arange(9).reshape((3,3))
row, col = a[1,:], a[:,1] -> shape (3,)
a[1,:], a[:,1]은 차원 하나를 indexing하고 나머지는 slicing했다. 이를 통해 차원 하나가 떨어져 나갔다. 왜냐하면 a란? (3,)가 3개 모여있는 ndarray이기 때문이다.
또 다른 indexing을 통한 차원 없애기 예시
import numpy as np
a = np.ones(shape=(1,3,4))
b = np.ones(shape=(3,4,1))
c = a[0,...] (3,4)
d = b[...,0] (3,4)
1을 차원값으로 가지는 차원을 전부다 없애주는 API
import numpy as np
a = np.ones(shape=(1,3,4))
c = np.squeeze(a) (3,4)
d = a.squeeze() (3,4)
여러 개의 1인 차원들이 존재할 때
import numpy as np
a = np.ones(shape=(1,1,3,1,4,1))
c = np.squeeeze(a) (3,4)
d = a.squeeze() (3,4)
index/ slicing등을 이용하여 깔끔하게 만들어주기 쉽지 않고 불편한 케이스이다.
조심할 것
API를 이용하여 차원을 바꿀 위치를 지정해주고 서로 위치를 교체한다.
import numpy as np
a = np.random.normal(size = (3,4,5,6))
b = np.swapaxes(a,0,1) (4,3,5,6)
c = np.swapaxes(a,0,2) (5,4,3,6)
d = np.swapaxes(a,0,3) (6,4,5,3)
swapaxes는 2개의 차원을 서로 바꿔줄 때 유용하게 사용할 수 있는 API이다.
주로 활용하는 방법
import numpy as np
a = np.random.normal(size = (3,200,100))
b = np.swapaxes(a,0,-1)
처음 차원과 마지막 차원을 서롤 바꿔준다.
import numpy as np
a = np.random.normal(size=(3,4,5,6))
b = np.moveaxis(a, source = 0, destination = 1) (4,3,5,6)
c = np.moveaxis(a, source = 0, destination = 2) (4,5,3,6)
d = np.moveaxis(a, source = 0, destination = 3) (4,5,6,3)
source 차원의 값을 destination 차원으로 옮기고 나머지를 옆으로 밀어서 빈자리를 채운다.
import numpy as np
a = np.random.normal(size=(3,4))
b = np.transpose(a) shape (4,3)
c = a.T shape (4,3)
transpose를 알아야할 이유
1. 사람들이 많이 사용하는 API이다.
2. 고차원 텐서를 한번에 순서를 바꿔줄 수 있다.
import numpy as np
a = np.random.normal(size=(3,4,5,6,7))
b = np.transpose(a) shape (7,6,5,4,3)
c = a.T shape (7,6,5,4,3)
np.transpose의 axes 활용
import numpy as np
a = np.random.normal(size = (3,4,5))
b = np.transpose(a, axes = (0,1,2)) (3,4,5)
c = np.transpose(a, axes = (1,2,0)) (4,5,3)
d = np.transpose(a, axes = (2,0,1)) (5,3,4)
e = np.transpose(a, axes = (2,1,0)) (5,4,3)
source array의 index를 이용하여 값들을 원하는 위치에 정렬시킨다.
연습문제
import numpy as np
a = np.random.normal(size=(3,4))
b = np.transpose(a, axes = tuple(range(a.dim))[::-1])
a.dim은 4이고 tuple.range(a.dim)은 (0 1 2 3)을 반환한다. 마지막으로 [::-1]은 (3 2 1 0)으로 바꿔준다.