728x90
1. Numpy Array 곱연산
스칼라곱(*)
두 Matrix (Array)가 Shape이 같을 때 Cross-Correlation 연산을 사용 (각 원소끼리의 곱의 합을 성분으로 갖는다)
- [n,m] * [n,m] = [n,m]
- Array간 shape이 같을 때 or Broadcasting 가능
- 각 행렬의 원소끼리의 곱을 성분으로 갖는 행렬을 반환
- Broadcasting 가능: Matrix * (column, row) Vector ONLY
- [1,m] * [n,m] = [n,m]
- [m,1] * [m,n] = [m,n]
- [m,n] * [m,1] = [m,n]
- [n,m] * [1,m] = [n,m]
내적(np.dot)
둘 다 1D Vector일 때 np.dot( )으로 내적처리
- Inner Product: $u \cdot v = u^{T}v$
- [n,m].dot([m,k]) = [m,k]
- np.dot([n,m], [m,k]) = [m,k]
행렬곱 (@)
2D Matrix가 하나라도 존재할 때 @ 사용
- i번째 행벡터와 j번째 열벡터의 내적을 성분으로 갖는 행렬을 반환
- 2차원에서는 .dot() & @는 동일한 기능
- 3차원에서는 텐서곱(외적)을 하게 되어 내적과 달라짐
- [n,m] @ [m,k] = [m,k]
np.dot(A, B)
[참고자료] https://jimmy-ai.tistory.com/75
- 1차원 X 1차원: 벡터 내적 (element-wise 방식으로 각 원소를 곱한 값들을 더한 내적 연산)
- np.dot( ) 사용을 권장
- 수식 : 보통 열벡터로 처리 (column vector)
- 코드 : 보통 행벡터로 처리 (row vector)
- Column vector로 들어오면 Transpose해서 Row vector로 처리
- 2차원 X 2차원: 행렬 곱
- @ 사용을 권장
- N차원 X 스칼라: 단순 스칼라배 연산 (* 사용을 권장, np.dot 사용하지 말 것)
- N차원 X 1차원
- 왼쪽이 N차원인 경우 각 행마다 오른쪽의 벡터와 내적을 수행
- 오른쪽이 N차원이면 각 열마다 왼쪽의 벡터와 내적을 수행
- N차원 X M차원
- 왼쪽 array의 각 행, 오른쪽 array의 각 열끼리 순서대로 내적을 수행한 결과를 반환
Caution!!
- 행렬연산을 하기 위해서는 2차원 리스트가 필요함 : [ [ ] ]으로 []를 2번 넣어준다
a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[7, 8], [9, 10], [11, 12]])
dot_product = a.dot(b)
dot_product2 = np.dot(a, b)
print("행렬 내적 결과: ", dot_product, dot_product2, sep="\n")
dot_product3 = a @ b
print("행렬 곱 결과: ", dot_product3, sep="\n")
inner_product = np.inner(a, b.T)
print("np.inner 결과: ", inner_product, sep="\n")
# 행렬 내적 결과:
# [[ 58 64]
# [139 154]]
# [[ 58 64]
# [139 154]]
# 행렬 곱 결과:
# [[ 58 64]
# [139 154]]
# np.inner 결과:
# [[ 58 64]
# [139 154]]
np.inner
- i번째 행벡터와 j번째 행벡터의 내적을 성분으로 갖는 행렬을 반환
- 수학에서는 말하는 내적과는 다르다!
- $ np.inner(u,v) = uv^{T} $이지만 수학에서는 $u \cdot v = u^{T}v$이다!
- np.inner([n,m], [k,m])
2. Caution: np.dot(A, B) vs np.dot(B, A) vs (A @ B) vs (B @ A)
np.dot(A, B) vs np.dot(B, A) vs (A @ B) vs (B @ A)
A, B의 dimension(차원)에 따라 결과가 같을수도, 다를 수도 있다
그렇기 때문에 np.dot( ) 연산이나 @ 연산시 argument의 순서를 반드시 주의할 것!
- A, B 둘다 1차원인 경우 np.dot( )을 순서에 상관없이 사용하고
- A, B 중에 2차원이 있는 경우 @ 연산을 순서를 고려하여 (행렬곱을 고려하여) 사용
A, B가 모두 1차원 (1 - dimension)
- np.dot(A, B) & np.dot(B, A) & A @ B & B @ A: 4가지 경우 모두 동일
- 되도록 np.dot( )을 사용할 것
a = np.array([1, 2, 3])
b = np.array([1, 2, 3])
print(np.dot(a, b))
print(np.dot(b, a))
print(a @ b)
print(b @ a)
14
14
14
14
A, B중 2차원 존재 (2 - dimension exist)
- np.dot(A, B) & np.dot(B, A) & A @ B & B @ A : Matrix Multiplication의 shape이 맞아야 함
- A, B가 (1차원, 2차원), (2차원, 1차원), (2차원, 2차원)인 어떤 경우라도 행렬곱의 shape이 맞아야 함
- 되도록 @ 연산을 사용할 것
- 2차원, 1차원인 경우
a = np.array([[1, 2, 3]])
b = np.array([1, 2, 3])
print(np.dot(a, b))
# print(np.dot(b, a))
print(a @ b)
# print(b @ a)
[14]
[14]
- 모두 2차원인 경우
a = np.array([[1, 2, 3]])
b = np.array([[1, 2, 3]]).reshape(-1, 1)
print(np.dot(a, b))
print(np.dot(b, a))
print(a @ b)
print(b @ a)
[[14]]
[[1 2 3]
[2 4 6]
[3 6 9]]
[[14]]
[[1 2 3]
[2 4 6]
[3 6 9]]
3. Cross-Correlation Operation (*)
두 Matrix(Vector)가 동일한 Shape을 가지고 있을 때 각 원소끼리의 곱의 합을 원소로 가지는 행렬을 반환한다.
Convolution Operation (CNN)이 이러한 예시 중 하나이다.
CNN의 Input에 Filter(Kernel)를 Convolution하려면 Filter를 Reverse & Shift하여 적용해야 한다.
그런데 어차피 Filter(Kernel)의 weight을 학습하려는 것이 목적이기 때문에 Reverse & Shift를 하여 convolution을 하나 그냥 하나 동일하다.즉 학습과 추론 inference시에 필터만 일정하면 된다.
그래서 딥러닝 프레임워크들은 Convolution이 아니고 그냥 Cross-Correlation으로 구현되어 있다.
하지만 관습상 Convolution이라 부른다.
다음은 CNN의 Convolution operation을 Cross-Correlation으로 구현하는 과정이다.
import numpy as np
def convolution(input_matrix, filter_matrix):
# 입력 행렬과 필터 행렬의 크기를 확인
input_rows, input_cols = input_matrix.shape
filter_rows, filter_cols = filter_matrix.shape
# 필터가 입력 행렬보다 작아야 연산 가능
if filter_rows > input_rows or filter_cols > input_cols:
raise ValueError()
# convolution 결과를 저장할 빈 행렬 생성 stride와 padding은 없다고 가정
result_matrix = np.zeros((input_rows - filter_rows + 1, input_cols - filter_cols + 1))
# convolution 연산 수행
for i in range(result_matrix.shape[0]):
for j in range(result_matrix.shape[1]):
result_matrix[i, j] = np.sum(input_matrix[i:i+filter_rows, j:j+filter_cols] * filter_matrix)
return result_matrix
# 예시를 위해 간단한 행렬 생성
input_matrix = np.array([[2, 4, -6, 6, 7],
[-5, 3, -2, 3, 4],
[2, -1, 4, 7, -6],
[4, 10, 1, -2, 2],
[-9, 1, -3, 6, -4]]) # 5X5 행렬로 원하는 값을 넣어주세요
filter_matrix = np.array([[2, 4, 4],
[6, 5, 5],
[5, 2, 1]]) # 3X3 행렬로 원하는 값을 넣어주세요
# convolution 연산 수행
result = convolution(input_matrix, filter_matrix)
print("입력 행렬:")
print(input_matrix)
print("\n필터 행렬:")
print(filter_matrix)
print("\nConvolution 결과:")
print(result)
728x90