단일 뉴런에서 네트워크로 — 행렬, 레이어 및 순전파 (Forward Pass)
요약
Rust를 사용하여 단일 뉴런을 넘어선 신경망의 핵심 구성 요소인 행렬, 레이어, 순전파 과정을 구현하는 방법을 설명합니다. 행렬 표기법을 통해 다중 입력과 다중 뉴런을 효율적으로 처리하는 원리를 다룹니다.
핵심 포인트
- 행렬(Matrix)을 이용한 다중 특성 및 예시의 효율적 처리
- Rust 언어를 활용한 신경망 구성 요소 구현 가이드
- 행렬 곱셈(@)을 통한 가중 합(Weighted Sum)의 확장 원리
- 입력 데이터(X), 가중치(W), 편향(b)의 구조적 관계 이해
단일 입력만을 가진 뉴런은 직선 하나만을 학습합니다. 실제 문제를 모델링하기 위해서는 더 많은 입력, 더 많은 뉴런, 그리고 이 모든 것을 효율적으로 조직하는 방법이 필요합니다. 이 포스트에서는 Rust를 사용하여 신경망 (Neural Network)을 가능하게 하는 구성 요소인 행렬 (Matrices), 레이어 (Layers), 그리고 순전파 (Forward Pass)를 구축해 보겠습니다.
목차
- 1 서문
- 2 실무에서의 행렬이란 무엇인가
- 3 행렬 곱셈 — 어떤 일이 일어나고 있는가
- 4 레이어 (Layer)란 무엇인가
- 5 순전파 (Forward Pass)
- 6 결론
1. 서문
이전 프로젝트에서는 하나의 가중치 (Weight), 하나의 입력, 하나의 출력을 사용하여 대포알의 거리를 예측하는 단일 뉴런을 다루었습니다. 간단하지만 실제 어떤 문제에도 쓸 수 없는 구조였습니다.
대포알의 거리는 에너지에만 의존하지 않습니다. 바람, 각도, 투사체의 무게 등에 따라 달라집니다. 네트워크는 각 요소가 결과에 어떻게 영향을 미치는지 서로 다른 가중치로 학습해야 합니다. 여러 개의 입력, 여러 개의 뉴런, 그리고 여러 개의 예시가 동시에 존재할 때 행렬 (Matrices)이 등장합니다.
이전의 공식은 거리 = w × 에너지 + b였지만, 여러 입력 (features)이 생기면 모델은 다음과 같이 확장됩니다:
거리 = w₁×에너지 + w₂×바람 + w₃×각도 + b
이는 **행렬 표기법 (Matrix Notation)**으로 요약할 수 있습니다:
Y = X @ W + b
여기서 @는 행렬 곱셈 (Matrix Multiplication)을 의미합니다. 이는 이전과 동일한 가중 합 (Weighted Sum)을 수행하지만, 여러 개의 특성 (Features)과 여러 개의 예시를 동시에 처리할 수 있도록 조직화된 방식입니다.
2. 실무에서의 행렬이란 무엇인가
행렬 (Matrix)은 행 (Rows)과 열 (Columns)로 구성된 숫자 테이블입니다.
X는 입력 데이터셋을 나타내며, **각 행은 하나의 예시(Example)이고 각 열은 하나의 특성(Feature)**입니다. 3개의 특성을 가진 2개의 예시의 경우, X의 형태는 (2×3)이 됩니다:
let x = Matrix::new(2, 3, vec![
10.0, 80.0, 0.30, // 예시 0: 에너지=10, 바람=80, 각도=0.30
20.0, 60.0, 0.25, // 예시 1: 에너지=20, 바람=60, 각도=0.25
...
W 또한 행렬 (Matrix)이 됩니다. 3개의 특징 (Features)과 2개의 출력 뉴런이 있다면, W는 (3×2) 형태를 가지며 각 열(column)이 하나의 뉴런을 나타냅니다:
let w = Matrix::new(3, 2, vec![
0.5, 0.1, // 에너지 가중치 (weights) — 뉴런 1과 2
0.3, 0.4, // 바람 가중치 (weights) — 뉴런 1과 2
...
b는 뉴런당 하나의 값을 갖는 Vec<f64>입니다. 이는 행렬 곱셈에 포함되지 않고 출력에 직접 더해집니다:
let b: Vec<f64> = vec![0.2, 0.1]; // 뉴런당 하나의 편향 (bias)
3. 행렬 곱셈 (Matrix Multiplication) — 내부에서 일어나는 일
이전 프로젝트에서는 하나의 가중치와 하나의 입력을 곱하기 위해 *를 사용했습니다. @는 모든 특징 (features)과 모든 예시 (examples)에 대해 동일한 계산을 한 번에 수행합니다.
1개의 뉴런을 가진 예시 0의 경우:
X[0] = [10.0, 80.0, 0.3]
W = [0.5, 0.3, 0.2]
...
전체 구현은 다음과 같습니다:
pub fn matmul(&self, other: &Matrix) -> Matrix {
assert_eq!(
self.cols, other.rows,
...
assert_eq!는 실행 전 차원 (dimensions)이 일치하는지 보장합니다. 만약 X가 3개의 열을 가진다면, W는 반드시 3개의 행을 가져야 합니다. 그렇지 않으면 루프가 잘못된 결과를 조용히 생성할 수 있기 때문입니다.
4. 레이어 (Layer)란 무엇인가
단일 뉴런의 경우: 1개의 가중치, 1개의 편향 (bias), 1개의 출력을 가집니다. 이는 오직 단순한 선형 관계만을 학습할 수 있습니다.
**레이어 (Layer)**는 동일한 입력에 대해 함께 작동하는 뉴런들의 집합입니다. 사용자가 원하는 뉴런의 수를 정의하면, 레이어는 뉴런당 하나의 열을 갖는 W를 생성합니다:
pub struct Layer {
pub w: Matrix,
pub b: Vec<f64>,
...
W의 값은 0이 아닌 **무작위 (random)**로 초기화됩니다. 만약 모든 가중치가 동일한 값으로 시작한다면, 모든 뉴런이 정확히 똑같은 것을 학습하게 되어 레이어 전체가 무용지물이 될 것입니다.
무작위 값의 스케일 (scale) 또한 중요합니다. 가중치가 너무 크면 레이어를 통과할 때 값이 폭발 (explode)하고, 너무 작으면 사라져 버립니다 (disappear). 이를 위해 우리는 Xavier initialization을 사용합니다. 이 방식의 범위는 입력의 수에 비례합니다:
let scale = (1.0 / in_features as f64).sqrt(); // ≈ 3개의 특징(features)에 대해 0.577
let w_data: Vec<f64> = (0..in_features * out_features)
.map(|_| rng.gen_range(-scale..scale))
...
다음과 같이 제어된 범위 내에서 가중치(weights)를 생성합니다:
W (3×4):
-0.52, 0.18, -0.31, 0.44,
0.57, -0.12, 0.08, -0.49,
...
편향 (bias)은 0에서 시작합니다 — 편향은 가중치와 같은 대칭성(symmetry) 문제를 겪지 않습니다.
5. 순전파 (Forward pass)
forward는 Y = X @ W + b를 적용하는 레이어(layer)의 함수입니다.
단일 뉴런의 경우 이는 y = x * w + b였습니다. 여러 뉴런과 여러 예시를 동시에 처리할 때는 동일한 계산이 행렬 곱셈(matrix multiplication)으로 변합니다:
X (1개 예시, 3개 특징 (features)):
[10.0, 80.0, 0.3]
...
Y의 각 값은 해당 레이어 뉴런의 출력입니다. 구현은 다음과 같습니다:
pub fn forward(&self, input: &Matrix) -> Matrix {
let mut out = input.matmul(&self.w); // X @ W
...
정보가 입력에서 출력까지 네트워크를 통해 앞으로 나아가기 때문에 이를 **순전파 (forward pass)**라고 부릅니다. 나중에 훈련(training) 과정 중에, 가중치를 조정하고 오차를 줄이기 위해 역방향 경로(역전파 (backward pass))를 수행할 것입니다.
6. 결론
이 포스트에서 우리는 하나의 입력이 있는 뉴런에서 시작하여, 여러 특징(features)을 동시에 받는 여러 뉴런이 있는 레이어에 도달했습니다.
구축된 내용:
- 행렬 곱셈 및 차원 검증 기능이 포함된
Matrix구조체 (struct) - Xavier initialization 및
forward기능이 포함된Layer구조체 - 입력(inputs)과 타겟(targets)을 포함한
Dataset구조체 - 두 개의 레이어가 순차적으로 연결된 완전한 순전파 (forward pass)
다음 포스트에서는 활성화 함수 (activation functions), 역전파 (backpropagation), 그리고 네트워크가 실제로 학습하게 만드는 훈련 루프 (training loop)를 다룹니다.
참고 문헌
이 포스트가 이해가 되셨다면, 다음 단계는 층(layers) 사이에 활성화(activation)를 추가하고 네트워크가 스스로의 오류로부터 학습하도록 가르치는 것이며, 이는 시리즈의 다음 포스트에서 다룰 예정입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기