텐서 곱셈(tensor product)이라고도 부르는 (원소별 곱셈과 혼동하지 마세요) 점곱 연산(dot operation)은 가장 널리 사용되고 유용한 텐서 연산입니다. 원소별 연산과 반대로 입련 텐서의 원소들을 결합시킵니다.
넘파이, 케라스, 씨아노, 텐서플로에서 원소별 곱셈은 * 연산자를 사용합니다. 텐서플로에서는 dot 연산자가 다르지만 넘파이와 케라스는 점곱 연산에 보편적인 dot연산자를 사용합니다.
import numpy as np
z = np.dot(x, y)
z = x . y
점곱 연산은 수학에서 어떤일을 할까요? 2개의 벡터 x 와 y의 점곱은 다음과 같이 계산을 합니다.
def naive_vector_dot(x, y):
assert len(x.shape) == 1........... x는 넘파이 벡터입니다.
assert len(y.shape) == 1........... y는 넘파이 벡터입니다.
z = 0.
for i in range(x.shape[0]):
z += x[i] * y[i]
return z
여기서 볼 수 있듯이 두 벡터의 점곱은 스칼라가 되므로 원소 개수가 같은 벡터끼리 점곱이 가능합니다.
행렬 x와 벡터 y사이에서도 점곱이 가능합니다. y와 x의 행 사이에서 점곱이 일어나므로 벡터가 반환됩니다. 다음과 같이 구현할 수 있습니다.
import numpy as np
def naive_matrix_vector_dot(x, y)
assert len(x.shape) == 2 .......... x는 넘파이 행렬입니다.
assert len(y.shape) == 1............ y는 넘파이 벡터입니다.
assert x.shape[1] == y.shape[0] ......... x의 두 번째 차원이 y의 첫번째 차원과 같아야 합니다.
z = np.zeros(x.shape[0]) .....이 연산은 x의 행과 같은 크기의 0이 채워진 벡터를 만듭니다.
for i in range(x.shape[0]):
for j in range(x.shape[1]):
z[i] += x[i,j] * y[j]
return z
행렬-벡터 점곱과 벡터-벡터 점곱 사이의 관계를 부각하기 위해 앞에ㅐ서 만든 함수르 재사용하겠습니다.
def naive_matrix_vector_dot(x,y):
z = np.zeros(x.shape[0])
for i in range(x.shape[0])
z[i] = naive_vector_dot(x[i, :], y)
return z
두 텐서 중 하나라도 ndim이 1보다 크면 dot 연산에 교환 법칙이 성립되지 않습니다. 다시 말하면 dot(x, y)와 dot(y, x)가 같지 않습니다.
물론 점곱은 임의의 축 개수를 가진 텐서에 일반화됩니다. 가장 일반적인 용도는 두 행렬 간의 점곱일 것입니다. x.shape[1] == y.shape[0]일 때 두 행렬 x와 y의 점곱(dot(x, y))이 성립됩니다. x의 행과 y의 열 사이 백터 점곱으로 인해(x.shape[0], y.shape[1]) 크기의 행렬이 됩니다. 다음은 단순한 구현 예 입니다.
def naive_matrix_dot(x, y):
assert len(x.shape) == 2 .......... x는 넘파이 행렬입니다.
assert len(y.shape) == 2 .......... y는 넘파이 행렬입니다.
assert x.shape[1] == y.shape[0] ........ x 의 두 번째 차원이 y의 첫번째 차원과 같아야 합니다!
z = np.zeros((x.shape[0], y.shape[1])) ........ 이 연산은 0이 채워진 특정 크기의 벡터를 만듭니다.
for i in range (x.shape[0]): ...... x의 행을 반복합니다.
for j in range(y.shape[1]): ..... y의 열을 반복합니다.
row_x = x[i, :]
column_y = y[:, j]
z[i, j] = naive_vector_dot(row_x, column_y)
return z
그림 2-5 와 같이 입력과 출력을 배치해 보면 어떤 크기의 점곱이 가능하지 이해하는데 도움이 됩니다.
x, y, z는 직사각형 모양으로 그려져 있습니다(원소들이 채워진 박스라고 생각하면 됩니다). x의 행 벡터와 y의 열 벡터가 같은 크기여야 하므로 자동으로 x의 너비는 y의 놉이와 동일해야 합니다. 새로운 머신 러닝 알고리즘을 개발할 때 이런 그림을 자주 그리게 될 것 입니다.
더 일반적으로 앞서 설명한 2D의 경우 처럼 크기를 맞추는 동일한 규칙을 따르면 다음과 같이 고차원 텐서 간의 점곱을 할 수 있습니다.
(a, b, c, d) . (d,) -> (a, b, c)
(a, b, c, d) . (d, e) -> (a , b, c, e)
댓글 없음:
댓글 쓰기