首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

FANN 庫實戰:用 C 語言訓練神經網絡學會簡單加法

     編輯:關於C語言

FANN(Fast Artificial Neural Network Library)是一個輕量、跨平台的 C 語言神經網絡庫,適合嵌入式與桌面應用快速原型開發。本文以「學會兩數相加」為例,完整演示從訓練數據生成、網絡創建、訓練、保存到推理的全流程代碼與關鍵參數解析。

完整代碼結構

// fann_test.c
#include "../fann-2.0.0/src/include/doublefann.h"

#ifdef _DEBUG
#pragma comment(lib, "../fann-2.0.0/MicrosoftWindowsDll/bin/fanndoubleMTd.lib")
#else
#pragma comment(lib, "../fann-2.0.0/MicrosoftWindowsDll/bin/fanndoubleMT.lib")
#endif

// ========== 訓練階段 ==========
void train() {
    const unsigned int num_input = 2;      // 輸入節點:a, b
    const unsigned int num_output = 1;     // 輸出節點:c
    const unsigned int num_layers = 3;     // 輸入層、隱藏層、輸出層
    const unsigned int num_neurons_hidden = 3; // 隱藏層神經元數
    const float desired_error = 0.00000001f; // 目標誤差
    const unsigned int max_epochs = 500000;  // 最大訓練輪數
    const unsigned int epochs_between_reports = 10000; // 日誌間隔

    struct fann *ann = fann_create_standard(num_layers, num_input, num_neurons_hidden, num_output);
    fann_set_activation_function_hidden(ann, FANN_LINEAR); // 隱藏層線性激活
    fann_set_activation_function_output(ann, FANN_LINEAR); // 輸出層線性激活

    // 生成訓練文件 add.fann
    FILE *fp; fopen_s(&fp, "add.fann", "w");
    int Num = 200; float Mf = Num * 3.0f;
    fprintf_s(fp, "%d 2 1\n", Num); // 樣本數 輸入數 輸出數
    for (int i = 1; i <= Num; i++) {
        double a = i / Mf;
        double b = (i + 1) / Mf;
        double c = a + b;
        fprintf_s(fp, "%lf %lf\n%lf\n", a, b, c);
    }
    fclose(fp);

    fann_train_on_file(ann, "add.fann", max_epochs, epochs_between_reports, desired_error);
    fann_save(ann, "add.fann.net"); // 保存模型
    fann_destroy(ann);
}

// ========== 推理階段 ==========
void exec(double a, double b) {
    struct fann *ann = fann_create_from_file("add.fann.net");
    fann_type input[2] = {a, b};
    fann_type *calc_out = fann_run(ann, input);
    printf("a=%f\nb=%f\nc=%f\n期望值 c=%f\n\n", input[0], input[1], calc_out[0], input[0] + input[1]);
    fann_destroy(ann);
}

int main() {
    // train(); // 僅需運行一次,之後註釋
    exec(0.354, 0.58934);
    exec(0.21469, 0.3914968);
    exec(0.130, 0.44);
    exec(-0.3654, 0.58455);
    exec(0.365420, -0.95);
    return 0;
}

關鍵設計決策解析

1. 為什麼選 LINEAR 激活函數?

加法是線性映射:c = a + b。若用 Sigmoid 等非線性激活,網絡需花費大量容量去擬合線性關係,收斂慢且精度受限。FANN_LINEAR 讓神經元直接輸出加權和,單層感知機即可完美解決。

2. 輸入數據歸一化到 (0,1)

代碼中 a = i/Mf, b = (i+1)/Mf 確保輸入落在 (0, 1) 區間。神經網絡對輸入尺度敏感,歸一化能加速收斂、避免梯度爆炸/消失。

3. 訓練文件格式(FANN 專用)

樣本數 輸入數 輸出數
輸入1 輸入2 ... 輸入N
輸出1 輸出2 ... 輸出M
...

每組樣本佔兩行:第一行所有輸入,第二行所有輸出。

4. 雙精度版本

代碼包含 doublefann.h 並鏈接 fanndoubleMT.lib,使用 fann_type(即 double)提高數值精度,適合科學計算場景。

訓練與推理分離模式

  • 訓練:耗時、需標籤數據、產出 .net 模型文件。僅在模型更新時運行。
  • 推理:極快、無依賴訓練庫、僅載入 .net 執行前向傳播。部署時只需分發模型文件與推理代碼。

常見問題與調優

現象可能原因對策
誤差不收斂學習率過大/隱藏層太小/激活函數不當改 LINEAR、增隱藏神經元、調學習率
測試集表現差過擬合/訓練數據分布不覆蓋測試域擴大訓練範圍、增加樣本、正則化
負數輸入失敗訓練數據僅含正數訓練集補充負數樣本(代碼已含)

總結

FANN 以極簡 API 實現了完整的神經網絡生命周期。通過「加法」這一線性任務,我們驗證了:正確選擇激活函數 + 數據歸一化 + 足夠網絡容量 是讓神經網絡快速收斂的鐵三角。這套流程可直接遷移至更複雜的非線性回歸、分類任務,只需替換激活函數、調整網絡結構與數據預處理即可。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved