요약하자면, Usul-cpp는 제가 C++로 작성한 라이브러리입니다. 이 라이브러리는 데이터 과학자들이 TensorFlow와 같은 무거운 라이브러리 없이도 모델을 만들 수 있도록 하며, 단순히 수학적 표현만으로 모델을 정의하면 Usul이 나머지 과정을 처리합니다. 내장된 텐서(tensor) 지원, 자동 미분(auto-grad), 역전파(back-prop) 기능을 갖추고 있으며 상당히 빠릅니다. 제가 이 라이브러리를 작성한 이유는, 무언가를 수행한다고 주장하는 임의의 클래스를 읽는 것보다 수학적 표현을 읽는 것이 덜 신비롭다고 느꼈기 때문입니다. 저는 정확성을 강조하고 싶었기 때문에 처음부터 C++ (23)로 직접 작성했지만, 미묘하게는 xtensor를 기반으로 구축되었습니다. 작동하는 모습을 확인해 보세요.
#include <usul.hpp>
using namespace std;
int main() {
double LR = 0.1;
int EPOCH = 5000;
// 순전파(forward pass)를 작성해 봅시다.
Tensor X = { {0.0, 0.0}, // 이것이 입력되는 값입니다
{0.0, 1.0},
{1.0, 0.0},
{1.0, 1.0}, }; // 이것이 우리가 얻고자 하는 결과입니다
Tensor Y_true = { 0.0, // xor{0.0, 0.0} = 0.0
1.0, // xor{0.0, 1.0} = 1.0
1.0, // xor{1.0, 0.0} = 1.0
0.0 // xor{1.0, 1.0} = 0.0
};
Y_true.reshape({4, 1}); // 이제 단일 레이어, 이중 뉴런 네트워크를 생성할 것입니다.
// 각 레이어는 바이어스(bias)와 가중치(weights) 텐서를 갖게 됩니다.
auto W1 = generate_random_matrix({2, 4}, -1.0, 1.0); auto B1 = generate_random_matrix({1, 4}, -1.0, 1.0); auto W2 = generate_random_matrix({4, 1}, -1.0, 1.0); auto B2 = generate_random_matrix({1, 1}, -1.0, 1.0);
// 이 코드는 (int i = 0; i < EPOCH; i++)에 대한 학습 루프입니다.
{ // 순전파(forward pass)를 수행합니다
// 첫 번째 레이어
auto Z1 = X % W1 + B1;
auto A = Z1.ReLU(); // ReLU 활성화 함수 적용
// 두 번째 레이어
auto Z2 = A % W2 + B2; // 활성화 전 값
// 활성화(activation)는 다음과 같아야 합니다.
auto S = Z2.activate(Activate::Sigmoid);
auto S = Z2.Sigmoid(); // Sigmoid 함수 적용
// 손실(Loss)은 다음과 같아야 합니다.
auto Loss = S.loss(Loss::MSE); // Mean Squared Error (MSE) 사용
auto loss = (S - Y_true) * (S - Y_true);
loss = loss.mean();
cout << "Loss: " << loss << "\n";
cout << "guesses: " << "\n" << S << "\n";
cout << "should be: " << Y_true << "\n";
loss.backwards(); // 역전파(Backpropagation)
W1.step(LR); // 가중치 업데이트
B1.step(LR);
W2.step(LR);
B2.step(LR);
}
}
이 코드는 다음과 같은 출력을 생성합니다:
Guesses: Tensor({{ 0.027546}, { 0.963592}, { 0.964138}, { 0.038964}}, shape=(4,1))
should be: Tensor({{ 0.}, { 1.}, { 1.}, { 0.}}, shape=(4,1))
Loss: Tensor( 0.001222, shape=())
수학 공식만 작성하면 Usul-cpp가 나머지를 처리합니다. 이 라이브러리는 매우 가볍고 전체 라이브러리가 메모리 안전성을 보장합니다. 그리고 이름이 Usul인 이유는 제가 Dune의 열렬한 팬이기 때문입니다. 프로젝트는 https://github.com/crushr3sist/Usul-cpp에서 확인하실 수 있습니다. 다음으로 무엇을 할지에 대한 모든 아이디어가 환영합니다. 또한 이 프로젝트를 개선할 수 있다고 생각하는 기능을 직접 가져와서 구현해 주셔도 좋습니다. (분위기만 좋은 PR은 삼가주세요, 이 프로젝트는 분위기로 돌아가는 것이 아닙니다)
아래에 배경 정보를 공유하고 싶습니다. 수학은 항상 저와 신경망을 작성하는 방법을 배우는 것 사이에 장애물로 존재했습니다. 깊은 신경망(deep neural network)의 모든 노드 간 연결 다이어그램을 본 이후로 저는 항상 그것들에 매료되어 왔습니다.
저는 고등학교 수학 수업 트라우마 때문에 이러한 개념들을 이해하는 것을 포기하지 않았습니다. 펜과 종이를 꺼내 수치적 하강법(numerical descent), 해석적 하강법(analytical descent), 역전파(backwards propagation), 컴퓨트 그래프(compute graph)가 무엇인지 등 이 모든 주제를 독학했습니다. 몇 가지 산술 연산 사이에서 손실을 수동으로 역전파하는 수준에 이르렀고, 이것이 스칼라 레벨 신경망과 간단한 미적분학 수행으로 이어졌으며, 스칼라로 XOR 게이트 문제를 풀 수 있게 되었습니다. 이후 행렬 미적분학(matrix calculus)까지 독학했고... 결국 xtensor를 사용하여 행렬 구문으로 XOR 게이트 문제를 직접 손으로 작성했습니다. 그리고 AI의 도움 없이 순전히 손으로, XOR 게이트 문제에 대한 오차 역전파와 자동 미분(automatic differentiation)을 수동으로 수행해 보았습니다.
이 과정은 또한 LLM 의존성으로부터 일종의 디톡스 효과를 가져왔습니다. 저는 코딩에 LLM을 자주 사용하지 않지만, 이것이 제 일상생활에서 너무 중심적인 역할을 하고 있고 Google에서 Gemini로 마이그레이션하면서, 즉각적인 정보 접근을 위해 LLM을 사용하는 것이 제 정신과 정보 습득 능력에 영향을 주기 시작했기 때문입니다. 이 라이브러리가 저에게 그랬던 것처럼 여러분 중 누군가에게도 유용하기를 진심으로 바랍니다. 그리고 혹시 이 라이브러리로 다음에 무엇을 할 수 있을지에 대한 아이디어가 있다면 정말 듣고 싶습니다. 읽어주셔서 감사합니다. 정말 감사드립니다.
제출자: /u/Exact-Contact-3837 [링크] [댓글]