728x90
반응형
SMALL

지난 블로그에서는 계단 함수와 함께 활성화 함수에 대하여 알아보았습니다. 

2023.08.18 - [Programming/Deep Learning] - [Python/DeepLearning] #3. 활성화 함수의 기본

 

[Python/DeepLearning] #3. 활성화 함수의 기본

앞서 퍼셉트론에 대하여 알아보며, 단층 & 다층 퍼셉트론에 대한 이야기를 나눠 보았습니다. 2023.08.16 - [Programming/Deep Learning] - [Python/DeepLearning] #2. 퍼셉트론 (단층 & ) [Python/DeepLearning] #2. 퍼셉트론

yuja-k.tistory.com

이번 블로그에서는 차원의 수에 대하여 알아보도록 하겠습니다.

다차원 배열

차원수가 많아도 일단 배열은 숫자의 집합이라는 점이 가장 중요합니다!

Python을 활용한 차원 계산은 numpy 모듈을 이용하면 손쉽게 다차원 배열을 만들 수 있고, 계산할 수 있습니다.

먼저, 1차원 배열을 통해 여러 가지 배열 정보를 확인해 보겠습니다.

import numpy as np

A = np.array([1,2,3,4])
print("배열의 원소 : {}".format(A))              # [1,2,3,4] 출력
print("배열의 차원수 : {}".format(np.ndim(A)))   # 1차원
print("배열의 모양 : {}".format(A.shape))        # (4,) 출력

다음은 2차원 배열 입니다.

# 2차원 배열
B = np.array([[1,2],[3,4],[5,6]])
print("배열의 원소 :\n{}".format(B))
# [[1 2]
#  [3 4]
#  [5 6]]  의 결과값 출력
print("배열의 차원수 : {}".format(np.ndim(B)))    # 2차원
print("배열의 모양 : {}".format(B.shape))        # (3,2)

2차원 배열은 보통 행렬(matrix)라고 부르고, 가로 방향을 행(row), 세로 방향을 열(column)이라고 이야기합니다.


행렬의 내적 "행렬 곱"

2차원 배열인 행렬의 내적을 구하는 방법에 대해 알아보겠습니다. 예를 들어 2 x 2 행렬의 내적은 다음과 같이 구할 수 있습니다.

핼렬 곱

위의 수식처럼 행렬 내적은 왼쪽 행렬의 행(가로)과 오른쪽 행렬의 열(세로)을 원소별로 곱하고 그 값들을 더해서 계산합니다. 그리고 계산 결과가 새로운 다차원 배열의 원소가 되는 것이 확인됩니다. 파이썬에서의 변수 표기에서 행렬은 일반 변숫값(스칼라값 이라고도 합니다.)과는 다르게 대문자로 표기하는 것이 관례입니다.

A = np.array([[1,2],[3,4]])
print("행렬 A의 shape : {}".format(A.shape))

B = np.array([[5,6],[7,8]])
print("행렬 B의 shape : {}".format(B.shape))

위의 행렬에서 𝐴×𝐵 는 계산이 가능하다. WHY? A.shape [1]과 B.shape [0]이 같기 때문에 가능!

# numpy의 dot 함수를 이용해 행렬의 내적을 구할 수 있다
print("A X B = \n{}".format(np.dot(A, B)))
print("B X A = \n{}".format(np.dot(B ,A)))

여기서 중요한 점은 행렬의 내적은 교환법칙이 성립하지 않는다. (BUT 단위행렬 제외)

위와 같이 2 X 2 형태의 행렬을 곱하는 예를 확인해 보았습니다.

shape 가 다른 행렬끼리 곱할 수 있는데, 이때 주의 해야 할 것은 첫 번째 행렬(A)의 첫 번째 차원의 원소 수(열의 수)와 두 번째 행렬(B)의 0번째 차원의 원소 수(행의 수)가 같아야 한다는 점입니다.

그렇다면, double check를 위해 이번에는 원소 수가 일치하는 경우와,

A = np.array([[1, 2, 3],
              [4, 5, 6]])

B = np.array([[1, 2],
              [3, 4],
              [5, 6]])

print("행렬 A의 shape : {}".format(A.shape))
print("행렬 B의 shape : {}".format(B.shape))

print(" A X B : \n{}\n".format( np.dot(A, B)))
print(" B X A : \n{}".format( np.dot(B, A)))

# 행렬 A의 1 번째 차원 원소 수 3,
# 행렬 B의 0 번째 차원 원소 수 3  =>  행의 수가 같기 때문에 계산 가능!

A[1] == 3 & B[0] == 3 (계산 가능)

다음처럼 원소 수가 일치하지 않을 때의 경우를 확인해 보도록 하겠습니다!

C = np.array([[1, 2],
              [3, 4]])

print("행렬 C의 shape : {}".format(C.shape))
print("행렬 A의 shape : {}".format(A.shape))

print("A X C = \n{}".format(np.dot(A, C)))
# A의 1번째 차원의 원소 수가 3, 
# C의 0번째 차원의 원소 수가 2  =>  #오류  계산 불가능!

이처럼, A X C의 계산에서 원소수가 맞지 않아서 계산이 되지 않고 오류가 나타나는 걸 볼 수 있습니다.

하지만! C X A의 형태의 계산은 가능합니다.

print(" C X A : \n{}".format(np.dot(C, A)))
# C의 1번째 원소수가 2, 
# A의 0번째 원소수가 2  => 계산 가능!

다시 말해, 차원 수가 다른 경우의 계산도 가능합니다.

A = np.array([[1, 2],
              [3, 4],
              [5, 6]])

B = np.array([7, 8])

print("행렬 A의 shape : {}".format(A.shape))
print("행렬 B의 shape : {}".format(B.shape))

print(" A X B : \n{}".format(np.dot(A, B)))
 # A와 B의 차원 수는 다르지만, 내적에서 대응되는 차원의 원소수가 같기 때문에 계산 가능

print(" B X A : \n{}".format(np.dot(B, A)))

즉, 뒤에 오는 행렬의 대응되는 차원의 원소의 수만 일치 시켜주면 상관 없다는 것을 알 수 있습니다!

원소의 수 == 행의 수를 잘 고려하여 다차원 계산을 하면 조금 더 쉬운 계산이 될 것 같습니다.

다음 블로그에서는 행렬과 신경망에 대하여 알아보도록 하겠습니다!

728x90
반응형
LIST

+ Recent posts