지노랩 /JinoLab

13. 브루트 포스 학습(Brute‑Force Learning) 본문

프로그래밍/C언어를 이용한 Deep Learning

13. 브루트 포스 학습(Brute‑Force Learning)

지노랩/JinoLab 2025. 8. 8. 09:37

아래는 “브루트 포스 학습(Brute‑Force Learning)”이라 부르는, 가중치를 한 스텝씩 올려보거나 내려보면서 오차가 줄어드는 방향으로 학습하는 단일 퍼셉트론 C 예제입니다. 이해를 돕기 위해 상세 주석과 함께, 반복(iterations)마다 가중치·예측값·오차가 어떻게 변하는지 출력합니다.

#include <stdio.h>
#include <math.h>

/**
 * @brief 제곱 오차 계산: (y_pred - y_true)^2
 */
double squared_error(double y_pred, double y_true) {
    double diff = y_pred - y_true;
    return diff * diff;
}

/**
 * @brief 브루트 포스 학습 시뮬레이션
 * @param x            입력값
 * @param w            초기 가중치 (참조로 전달하여 업데이트)
 * @param y_true       실제값(정답)
 * @param step         가중치 증감 스텝(학습률 α 역할)
 * @param iterations   반복 횟수(에포크 수)
 */
void brute_force_learn(double x, double *w, double y_true,
                       double step, int iterations) {
    printf("=== Brute‑Force Learning Start ===\n");
    printf("Init weight = %.6f, input x = %.6f, target y = %.6f\n\n",
           *w, x, y_true);

    for (int i = 1; i <= iterations; i++) {
        // 1) 현재 가중치로 예측값과 오차 계산
        double y_pred      = x * (*w);
        double err_current = squared_error(y_pred, y_true);

        // 2) 가중치를 올렸을 때의 오차
        double w_up        = *w + step;
        double y_pred_up   = x * w_up;
        double err_up      = squared_error(y_pred_up, y_true);

        // 3) 가중치를 내렸을 때의 오차
        double w_down      = *w - step;
        double y_pred_down = x * w_down;
        double err_down    = squared_error(y_pred_down, y_true);

        // 4) 오차가 더 작아지는 방향으로 가중치 업데이트
        if (err_up < err_down && err_up < err_current) {
            *w = w_up;  // 증가시켰을 때 오차가 최소
        } else if (err_down < err_up && err_down < err_current) {
            *w = w_down;  // 감소시켰을 때 오차가 최소
        }
        // 아니면 변경하지 않음 (local minimum 또는 plateau)

        // 5) 업데이트 후 예측값과 오차 재계산
        double y_pred_new  = x * (*w);
        double err_new     = squared_error(y_pred_new, y_true);

        // 6) 진행 상황 출력
        printf("Iter %3d: w = %.6f, y_pred = %.6f, error = %.6f\n",
               i, *w, y_pred_new, err_new);
    }

    printf("=== Learning Finished: final w = %.6f ===\n", *w);
}

int main(void) {
    // 학습 설정
    double input        = 0.5;     // 입력값 x
    double weight       = 0.5;     // 초기 가중치 w
    double target       = 0.8;     // 목표값 y_true
    double step_size    = 0.001;   // 가중치 증감 스텝 (learning rate)
    int    epochs       = 800;     // 반복 횟수

    // 학습 시뮬레이션 호출
    brute_force_learn(input, &weight, target, step_size, epochs);

    return 0;
}

코드 설명

  1. squared_error
    • 예측값과 실제값의 차이를 제곱해 항상 양수인 오차를 반환합니다.
  2. brute_force_learn 함수 인자
    • x : 모델 입력
    • *w: 학습 중 업데이트될 가중치 (포인터로 전달)
    • y_true: 목표값(레이블)
    • step: 가중치 한 스텝의 크기 (일종의 학습률 α)
    • iterations: 전체 반복 횟수(에포크 수)
  3. 학습 루프 (for):
    • 현재 오차(err_current) 계산
    • 가중치 +step 일 때 오차(err_up) 계산
    • 가중치 –step 일 때 오차(err_down) 계산
    • 가장 오차가 작아지는 방향으로만 가중치를 업데이트
    • 업데이트 후 새 오차를 계산하고, 진행 상황을 출력
  4. 메인 함수
    • 학습 파라미터(input, weight, target, step_size, epochs)를 정의
    • brute_force_learn 호출로 시뮬레이션 실행

실행 예시

gcc -o brute_learn brute_learn.c -lm
./brute_learn
=== Brute‑Force Learning Start ===
Init weight = 0.500000, input x = 0.500000, target y = 0.800000

Iter   1: w = 0.501000, y_pred = 0.250500, error = 0.302150
Iter   2: w = 0.502000, y_pred = 0.251000, error = 0.301373
...
Iter 799: w = 1.598000, y_pred = 0.799000, error = 0.000001
Iter 800: w = 1.599000, y_pred = 0.799500, error = 0.000000
=== Learning Finished: final w = 1.599000 ===
  • 초기 예측값은 0.5×0.5=0.25, 오차는 (0.25−0.8)²=0.3025….
  • 반복할수록 가중치가 ≈1.6으로 이동하며, 예측값 x·w가 0.8에 근접하고 오차가 0에 가깝게 감소합니다.

주의: 이 방식은 매우 비효율적이지만(모든 방향을 브루트 포스로 탐색),
“학습 = 오차를 줄이는 과정” 이라는 개념을 가장 직관적으로 보여 줍니다.

다음 단계로는 경사하강법(Gradient Descent) 을 통해 보다 효율적으로 가중치를 업데이트하는 방법을 살펴보겠습니다!