728x90
반응형

인공신경망(Artificial Neural Network, ANN)

 지금까지 퍼셉트론의 개념과 노드에 전달되어 합쳐진 신호들이 다음 노드로 전달될 때, 값이 어떤 방법으로 전달될지를 결정하는 활성화 함수에 대해 학습해보았다.

 앞서 학습했던, 퍼셉트론은 계단 함수를 이용해서 신호를 전달할지(출력값 = 1), 전달하지 않을지(출력 값 = 0)를 정하였으며, XOR 게이트 실현에서 층을 여러 개 쌓자 단일층으로 해결하지 못했던 문제를 해결할 수 있었다.

 여기서, 활성화 함수의 존재와 층을 여러 개 쌓는다. 이 부분에 초점을 맞추면, 인공신경망을 만들 수 있고, 이 인공신경망을 구현하고, 가장 적합한 가중치를 알아서 찾아내는 것이 바로 딥러닝(Deep Learning)이다.

 본격적으로 신경망을 공부하기 전에 단층 퍼셉트론의 연산이 어떻게 이루어지는지 확인해보도록 하자. 단층 퍼셉트론의 연산 방법을 알게 되면, 다층 퍼셉트론의 구현은 이를 쌓아가기만 하면 된다.

 

 

 

1. m : 1 단층 퍼셉트론의 연산

  • 위 그림에서 정보가 전달되는 방식을 수식으로 적어보면 다음과 같다.

$$ Z = w_1*x_1 + w_2*x_2 +b*1 $$

$$ y = h(Z) $$

  • 여기서, $x_1=2, x_2=5, w_1 = 0.4, w_2 = 0.2, b = 0.7$이라고 가정해보자
  • 위 수식에서 $Z$를 가장 빠르게 출력할 수 있는 방법은 백터 연산이다.
  • 활성화 함수를 시그모이드 함수로 해서 구현해보자.
>>> import numpy as np

>>> def sigmoid(x):
>>>     return 1 / (1 + np.exp(-x))

>>> x = np.array([2, 5, 1])
>>> w = np.array([0.4, 0.2, 0.7])
>>> Z = np.sum(x*w)
>>> sigmoid(Z)

0.9241418199787566
  • 도착점이 1개만 있는 경우, 입력층의 노드 수와 곱해지는 가중치 엣지의 수가 서로 동일하기 때문에, 길이가 동일한 벡터가 2개 나온다.
  • 때문에, 벡터연산으로 쉽게 해결할 수 있다.
    (numpy의 벡터 연산은 길이가 같은 벡터끼리 연산 시, 동일한 위치의 원소끼리 연산이 이루어지는 방식이다.)
  • m : 1 퍼셉트론은 이처럼 쉽게 연산이 가능했다. 그렇다면 입력층 노드의 수와 가중치 엣지의 수가 다른 m : n은 어떨까?

 

 

 

 

2. m : n 단층 퍼셉트론의 연산

  • 참고로 위에서 각 엣지(Edge)별 가중치에 써놓은 숫자들이 무슨 뜻인지 이해가 안 갈 수 있으니, 이를 간략히 설명해보겠다.

  • 가중치에서 위 괄호 안에 들어있는 값은 몇 번째 층(Layer)인지를 의미한다.
  • 아래 숫자는 앞은 다음 층, 뒤는 앞 층을 이야기한다.
  • 입력 노드의 값은 위에서부터 순서대로 1, 3, 5 라고 가정하자.
  • 가중치 엣지의 값은 위에서부터 순서대로 0.3, 0.5, 0.4, 0.2, 0.7, 0.3이라고 가정하자.
  • 편향 엣지의 값은 위에서부터 순서대로 0.2, 0.3이라 가정하자.
  • 이를, 벡터 연산으로 구하고자 한다면, 각 벡터의 길이가 다르고, 이를 잘라서 $y_1$, $y_2$를 따로따로 연산하기엔 시간도 많이 걸리고 공식도 지저분해진다.

 

 

 

 

3. 행렬 곱

  • 위와 같은 m : n 퍼셉트론은 행렬 곱을 사용한다면, 한방에 계산을 할 수 있다.
  • 위 퍼셉트론을 수식으로 간소화하면 다음과 같다.

$$ Y = WX + B$$

$$ X = (x_1, x_2, x_3) = (1, 3, 5)$$

$$ B = (b_{1}^{(1)}, b_{2}^{(1)}) = (0.2, 0.3)$$

$$ W=
\begin{pmatrix}
w_{11}^{(1)} & w_{21}^{(1)}\\ 
w_{12}^{(1)} & w_{22}^{(1)}\\ 
w_{13}^{(1)} & w_{23}^{(1)}
\end{pmatrix}
=
\begin{pmatrix}
0.3 & 0.5\\ 
0.4 & 0.2\\ 
0.7 & 0.3
\end{pmatrix} $$

  • 행렬 연산을 하기 위해선, 가장 먼저 배열이 어떻게 생겼는지를 확인해야 한다.
>>> X = np.array([1, 3, 5])
>>> B = np.array([0.2, 0.3])
>>> W = np.array([[0.3, 0.5],[0.4, 0.2],[0.7, 0.3]])

>>> print("X shape:", X.shape)
>>> print("B shape:", B.shape)
>>> print("W shape:", W.shape)

X shape: (3,)
B shape: (2,)
W shape: (3, 2)
  • 여기서 우리는 X와 W를 행렬곱할 것이다.
  • 행렬곱을 간단하게 짚고 가자면 다음과 같다.

  • 위 행렬 곱 방법을 보면, 서로 곱해지는 행렬에서 빨간 부분이 일치해야만 곱해지며, 출력되는 행렬의 녹색 부분이 행의 수, 파란색이 열의 수를 결정한다.
  • 여기서 지금까지의 행렬에 대한 인식을 조금만 틀어보자.
  • 행 = 데이터의 수
  • 열 = 변수의 수
  • 앞으로 이 인식을 하고 행렬 곱을 생각하게 된다면, 뒤에서 나올 n-차원 텐서의 연산에 대해서도 쉽게 이해할 수 있을 것이다(이에 대한 상세한 내용은 나중에 이야기하겠다.)
  • 자, 위 수식을 함수로 구현해보자.
# 단층 퍼셉트론 연산
>>> Z = np.dot(X, W) + B
>>> Z
array([5.2, 2.9])
  • np.dot(A,B): 행렬 A와 행렬 B를 행렬 곱한다.
  • 편향인 B는 행렬 X와 W의 곱과 길이가 동일한 벡터이므로(다음 노드의 수와 동일하다), 쉽게 벡터 합이 된다.
  • 신경망에서 신호가 흘러가는 것은 행렬 연산을 통해 진행되며, 때문에 딥러닝에서 행렬 연산에 매우 유리한 GPU가 사용되는 것이다.
  • 각 노드별 합산된 결과를 시그모이드 함수를 통해서 출력해보자.
# 시그모이드 함수를 활성화 함수로 사용
>>> sigmoid(Z)
array([0.9945137 , 0.94784644])

 

 

 

 

 지금까지 단층 퍼셉트론(SLP)을 이용해서 신경망에서 연산이 어떻게 이루어지는지 확인해보았다. 다음 포스트에서는 다층 퍼셉트론(MLP)을 이용해서 신경망 연산을 학습해보도록 하자.

728x90
반응형
728x90
반응형

저번 포스트에선 행렬 생성과 행과 열의 이름 변경, 행렬의 정보 얻기 등을 공부해보았다.
이번 포스트에선 행렬 데이터 접근, 행렬의 연산에 대해 학습해보자.

 

행렬 데이터 접근하기

  • 행렬은 색인 또는 행과 열의 이름을 통해서 접근할 수 있다.
  • 행렬은 벡터와 같게 [] 대괄호를 이용해서 데이터에 접근한다.
  • 단 행렬은 벡터와 다르게 2개의 차원인 행(Row), 열(Column)으로 구성되어 있으므로, 2개의 index를 부여해야한다.
  • Matrix[행index,열index]로 행렬 데이터에 접근할 수 있다.
  • Indexing 예시는 다음과 같다.
    • Matrix[row_id, col_id]
      : 행렬의 row_id 행과 col_id 열에 지정된 값을 가지고 온다. 이 때, row_id나 col_id에 벡터를 사용하여 여러 값을 지정할 수 있다. row_id나 col_id 둘 중 하나를 생략하면 전체 행이나 열을 뜻한다.
    • Matrix[1:3,]
      : 1~3 행의 데이터를 가지고 온다.
    • Matrix[-3,]
      : 3행의 데이터를 제외하고 모두 가지고 온다.
    • Matrix[c(1,3),]
      : 1, 3 행만 가지고 온다.
    • Matrix[,c("col5", "col3")]
      : 행렬 또한 행과 열에 부여된 이름으로 불러올 수 있다.

      ※ 접근한 행렬의 색인이나 이름의 순서에 따라서 행렬의 배열은 바뀌게 된다!
# 행렬에서 내가 원하는 데이터만 가지고 와보자.
vt = c(80, 60, 70, 75,
       90, 70, 60, 60,
       85, 90, 40, 70,
       80, 75, 90, 80,
       85, 80, 70, 65)
mat <- matrix(vt, nrow = 5, byrow = TRUE, dimnames = list(c("민철", "재성", "기훈", "재빈", "현희"), c("수학", "영어", "국어", "탐구")))
mat

※ 행렬과 같은 형태로 벡터를 생성한다면, 행렬 생성이 보다 편리하다.

##      수학 영어 국어 탐구
## 민철   80   60   70   75
## 재성   90   70   60   60
## 기훈   85   90   40   70
## 재빈   80   75   90   80
## 현희   85   80   70   65
# 행렬에서 민철, 기훈, 현희의 수학 점수와 국어 점수를 가지고 와보자..
mat[c("민철", "기훈", "현희"), c("수학", "국어")]
##      수학 국어
## 민철   80   70
## 기훈   85   40
## 현희   85   70
# 행렬에서 2번 행부터 4번 행까지 가지고 와보자.
mat[2:4,]
##      수학 영어 국어 탐구
## 재성   90   70   60   60
## 기훈   85   90   40   70
## 재빈   80   75   90   80
# 행렬에서 3번째 행만 제외하고 가지고 와보자.
mat[-3,]
##      수학 영어 국어 탐구
## 민철   80   60   70   75
## 재성   90   70   60   60
## 재빈   80   75   90   80
## 현희   85   80   70   65
# 행렬에서 1, 3 행만 가지고 와보자.
mat[c(1,3),]
##      수학 영어 국어 탐구
## 민철   80   60   70   75
## 기훈   85   90   40   70
# 행렬에서 국어 점수와 수학 점수 순서로 가지고 와보자.
mat[,c("국어", "수학")]
##      국어 수학
## 민철   70   80
## 재성   60   90
## 기훈   40   85
## 재빈   90   80
## 현희   70   85

 

 

 

 

행렬의 연산

: 행렬 내부에서 할 수 있는 연산과 행렬과 스칼라 간의 연산, 행렬과 행렬 간의 연산에 대해 알아보자.

행렬 내 연산

  • rowMeans() / colMeans()
    : 행의 평균을 구한다. / 열의 평균을 구한다.
  • rowSums() / colSums()
    : 행의 합을 구한다. / 열의 합을 구한다.
  • 위 행렬을 기반으로 실습을 해보자.
    ※ Indexing과 조합하여 내가 원하는 값만 가지고 와서 연산해보도록 하자.
# 위 행렬이 1반이라고 가정할 때, 1반 학생들 개개인의 총 점수를 구하자.
rowSums(mat)
## 민철 재성 기훈 재빈 현희 
##  285  280  285  325  300
# 1 반 학생들의 과목별 평균 점수를 구하자.
colMeans(mat)
## 수학 영어 국어 탐구 
##   84   75   66   70
# 민철, 기훈, 현희의 평균 점수를 구하자.
rowMeans(mat[c("민철", "기훈", "재빈"),])
##  민철  기훈  재빈 
## 71.25 71.25 81.25
# 재성, 재빈, 현희의 수학, 국어 점수의 평균 점수를 구하자.
rowMeans(mat[c("재성", "재빈", "현희"),c("수학", "국어")])
## 재성 재빈 현희 
## 75.0 85.0 77.5
# 1반의 수학 총점과 평균 점수를 구하자.
math_Vt = mat[,"수학"]
sum(math_Vt)
## [1] 420
mean(math_Vt)
## [1] 84

 

 

행렬과 스칼라 간의 연산

  • 행렬과 스칼라 간의 연산은 아주 간단하다.
  • + - * / ^ 등을 그대로 사용하면 된다.
mat1 = matrix(c(1:12), nrow = 3, byrow = TRUE)
mat1 + 10
##      [,1] [,2] [,3] [,4]
## [1,]   11   12   13   14
## [2,]   15   16   17   18
## [3,]   19   20   21   22
mat1 - 10
##      [,1] [,2] [,3] [,4]
## [1,]   -9   -8   -7   -6
## [2,]   -5   -4   -3   -2
## [3,]   -1    0    1    2
mat1 * 10
##      [,1] [,2] [,3] [,4]
## [1,]   10   20   30   40
## [2,]   50   60   70   80
## [3,]   90  100  110  120
mat1 / 10
##      [,1] [,2] [,3] [,4]
## [1,]  0.1  0.2  0.3  0.4
## [2,]  0.5  0.6  0.7  0.8
## [3,]  0.9  1.0  1.1  1.2

 

 

행렬과 행렬의 연산

  • 행렬과 행렬의 연산은 다양한 전제 조건이 붙는다.
  • 행렬의 합과 차를 하려면 두 행렬의 크기가 서로 같아야 하며, 행렬의 곱을 하려면 앞 행렬과 뒤 행렬의 열과 행의 수가 동일해야한다. 
  • 행렬의 합과 차는 +, -로 기존 연산자와 동일하나 행렬간 곱은 %*%로 연산자가 다르다.
  • 전치행렬을 이용하면 언제든지 행렬 곱을 할 수 있다.
    • 전치행렬은 각 원소의 행과 열을 바꾼 행렬로, 어떤 크기의 행렬이라도 전치 행렬을 만들 수 있다.
    • 전치 행렬은 행과 열을 교환한 것이므로, 언제든지 행렬곱을 할 수 있다.
      보다 엄밀히 말하면, 주대각선을 축으로 하는 반사 대칭을 가하여 얻은 행렬이라고 할 수 있다.
    • 전치 행렬은 t(행렬)을 하면 생성할 수 있다.
mat1 = matrix(c(1:12), nrow = 3, byrow = TRUE)
mat2 = matrix(c(12:1), nrow = 3, byrow = TRUE)

# 행렬간 합과 차를 해보자
mat1 + mat2
##      [,1] [,2] [,3] [,4]
## [1,]   13   13   13   13
## [2,]   13   13   13   13
## [3,]   13   13   13   13
mat1 - mat2
##      [,1] [,2] [,3] [,4]
## [1,]  -11   -9   -7   -5
## [2,]   -3   -1    1    3
## [3,]    5    7    9   11
# 전치행렬 곱을 해보자
mat1 %*%t(mat1)
##      [,1] [,2] [,3]
## [1,]   30   70  110
## [2,]   70  174  278
## [3,]  110  278  446

 

 

 

이번 포스트에서는 행렬의 Indexing과 행렬의 연산 등에 대하여 학습해보았다.

다음 포스트에선 역행렬을 비롯한 약간 독특한 형태의 행렬들에 대해 가볍게 학습해보자.

728x90
반응형

'R > Basic' 카테고리의 다른 글

R(기초) 배열(Array)  (0) 2020.06.19
R(기초) 행렬(Matrix)(3부)  (0) 2020.06.19
R(기초) 행렬(Matrix)(1부)  (0) 2020.06.18
R(기초) 연산자와 변수 타입  (0) 2020.06.18
R(기초) 데이터 타입: 벡터(Vector)(2부)  (0) 2020.06.18

+ Recent posts