https://github.com/smilies-polito/Spiker git clone https://github.com/soerenab/AudioMNIST.git 1. **從 pip 套件庫安裝** 執行以下指令即可安裝: ```bash pip install spikerplus pip install spikerplus --break-system-packages pip3 install torch torchvision torchaudio tonic ``` 2. **從 GitHub 原始碼庫安裝最新版** 如果你想安裝最新版本,可以依照下列步驟操作: 方法 A: ```bash git clone https://github.com/smilies-polito/Spiker.git cd Spiker/spiker pip install . ``` 方法 B(等價於方法 A): ```bash git clone https://github.com/smilies-polito/Spiker.git cd Spiker/spiker python setup.py install ``` 以下是如何使用 **spiker** 框架的概述,假設你已經完成安裝與設置。這個 Python 套件旨在將從高階網路描述建立、訓練、優化到生成用於 FPGA 實作脈衝神經網路(SNN)加速器的 VHDL 描述的過程最小化所需的工作量。主要組件包括: - **NetBuilder** 將高階(以 Python 字典描述)網路結構轉換為一個基於 snnTorch 可訓練的脈衝神經網路。 - **Trainer** 負責訓練網路,可使用 PyTorch 的 dataloader 提供訓練與測試資料。 - **Optimizer** 將網路內部參數轉換為可在目標硬體(如 FPGA)上實作的固定點格式,透過格點搜尋(grid search)探索不同位寬配置,並記錄每組配置的損失與準確率。 - **VHDL Generator** 將優化且訓練完成的網路轉換成對應的 VHDL 描述,以供硬體實作。 以下是一個逐步的使用指南與示例程式碼: --- ### 1. 設定日誌 為了在執行過程中顯示進度訊息,請先配置 Python 內建的 logging 模組: ```python import logging logging.basicConfig(level=logging.INFO) ``` --- ### 2. 建立網路 首先,以 Python 字典描述你的網路結構。例如: ```python net_dict = { "n_cycles": 73, "n_inputs": 40, "layer_0": { "neuron_model": "lif", "n_neurons": 128, "alpha": None, "learn_alpha": False, "beta": 0.9375, "learn_beta": False, "threshold": 1.0, "learn_threshold": False, "reset_mechanism": "subtract" }, "layer_1": { "neuron_model": "lif", "n_neurons": 10, "alpha": None, "learn_alpha": False, "beta": 0.9375, "learn_beta": False, "threshold": 1.0, "learn_threshold": False, "reset_mechanism": "none" } } ``` 然後,使用 **NetBuilder** 建立網路: ```python from spikerplus import NetBuilder net_builder = NetBuilder(net_dict) snn = net_builder.build() ``` --- ### 3. 訓練網路 接下來,利用 **Trainer** 進行網路的訓練。Trainer 需要兩個 PyTorch 的 dataloader(分別用於訓練與測試)。例如: ```python from spikerplus import Trainer # 請根據你的資料集定義 train_loader 和 test_loader trainer = Trainer(snn) trainer.train(train_loader, test_loader) ``` *注意:* 請確保你的 dataloader 已正確設置。你可以參考相關教學或 snnTorch 的文件來建立 dataloader。 --- ### 4. 優化網路 訓練完成後,使用 **Optimizer** 將網路的參數轉換成適合硬體實作的固定點格式。首先,定義優化配置的字典: ```python optim_config = { "weights_bw": { "min": 5, "max": 6 }, "neurons_bw": { "min": 5, "max": 6 }, "fp_dec": { "min": 2, "max": 3 } } ``` 然後,執行優化: ```python from spikerplus import Optimizer opt = Optimizer(snn, net_dict, optim_config) opt.optimize(test_loader) ``` 在此步驟中,Optimizer 將探索不同的量化配置,並記錄每個配置下的損失與準確率。 --- ### 5. 產生 VHDL 程式碼 最後,根據優化器的結果選擇最符合需求的權衡設定,並定義硬體參數: ```python optim_params = { "weights_bw": 6, "neurons_bw": 8, "fp_dec": 4 } ``` 使用 **VhdlGenerator** 生成對應的 VHDL 描述: ```python from spikerplus import VhdlGenerator vhdl_generator = VhdlGenerator(snn, optim_params) vhdl_snn = vhdl_generator.generate() # 印出生成的 VHDL 程式碼 print(vhdl_snn.code()) ``` 這段 VHDL 程式碼可以作為後續綜合(synthesizable)你的 FPGA 加速器的基礎。 --- ### 總結 1. **匯入套件:** ```python import spikerplus ``` 2. **設定日誌:** ```python import logging logging.basicConfig(level=logging.INFO) ``` 3. **使用 Python 字典定義網路,並透過 `NetBuilder` 建立網路。** 4. **利用 `Trainer` 並搭配合適的 dataloader 進行網路訓練。** 5. **使用 `Optimizer` 透過格點搜尋優化並量化網路參數。** 6. **藉由 `VhdlGenerator` 指定固定點參數生成 VHDL 程式碼。** 按照以上步驟,你就可以有效地使用 spiker 框架來設計、訓練、優化並生成 FPGA 加速器所需的脈衝神經網路硬體描述。 整體流程: ``` import os import sys import logging import argparse # --------------------------- # 1. 停用 IPython/Spyder 的 autoreload(若有) # --------------------------- try: from IPython import get_ipython ip = get_ipython() if ip is not None: ip.run_line_magic("autoreload", "0") except Exception: pass # --------------------------- # 2. 檢查工作目錄中是否有與 torchvision 同名的檔案或資料夾 # --------------------------- if os.path.exists(os.path.join(os.getcwd(), "torchvision")): print("Error: 發現工作目錄中有名為 'torchvision' 的檔案或資料夾。") print("請將其重新命名或移除,以避免與官方 torchvision 套件衝突。") sys.exit(1) # --------------------------- # 3. 檢查 tonic 模組是否已安裝(spikerplus 所需) # --------------------------- try: import tonic except ModuleNotFoundError: print("Error: 模組 'tonic' 尚未安裝!請在命令提示字元中執行:") print(" pip install tonic") sys.exit(1) # --------------------------- # 4. 匯入 spikerplus 所需模組 # --------------------------- from spikerplus.dataloaders import AudioMnistDL from spikerplus import NetBuilder, Trainer, Optimizer, VhdlGenerator from spikerplus.vhdl import write_vhdl, compile_vhdl # 設定日誌層級為 INFO logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True) def main(): parser = argparse.ArgumentParser( description="使用 AudioMNIST 資料集訓練 SNN、優化參數及生成 VHDL 程式碼") parser.add_argument('--epochs', type=int, default=3, help="設定訓練的 Epoch 數量") args = parser.parse_args() # --------------------------- # 資料集載入 # --------------------------- batch_size = 64 # 使用原始字串指定 Windows 路徑,避免反斜線轉義問題 data_dir = r"C:\Users\Potter Wang\Desktop\SNN\AudioMNIST-master\AudioMNIST-master\data" data_loader = AudioMnistDL(data_dir=data_dir) train_loader, test_loader = data_loader.load(batch_size=batch_size) # 取得資料中每筆的時間步數與輸入維度 n_cycles = next(iter(train_loader))[0].shape[1] n_inputs = next(iter(train_loader))[0].shape[2] # --------------------------- # SNN 網路參數設定 # --------------------------- net_dict = { "n_cycles": n_cycles, "n_inputs": n_inputs, "layer_0": { "neuron_model": "lif", "n_neurons": 128, "alpha": None, "learn_alpha": False, "beta": 0.9375, "learn_beta": False, "threshold": 1.0, "learn_threshold": False, "reset_mechanism": "subtract" }, "layer_1": { "neuron_model": "lif", "n_neurons": 10, "alpha": None, "learn_alpha": False, "beta": 0.9375, "learn_beta": False, "threshold": 1.0, "learn_threshold": False, "reset_mechanism": "none" } } # 建立 SNN 網路 net_builder = NetBuilder(net_dict) snn = net_builder.build() logging.info("Network configured: %s", net_dict) logging.info("Network ready: %s", snn) # --------------------------- # SNN 訓練 # --------------------------- trainer = Trainer(snn) for epoch in range(args.epochs): logging.info("Epoch %d/%d", epoch + 1, args.epochs) train_loss, train_acc = trainer.train_one_epoch(train_loader) try: val_loss, val_acc = trainer.validate(test_loader) logging.info("Train loss: %.4f, Train acc: %.4f, Val loss: %.4f, Val acc: %.4f", train_loss, train_acc, val_loss, val_acc) except AttributeError: logging.info("Train loss: %.4f, Train acc: %.4f", train_loss, train_acc) # --------------------------- # SNN 優化(固定點格式轉換) # --------------------------- optim_config = { "weights_bw": {"min": 8, "max": 8}, "neurons_bw": {"min": 16, "max": 16}, "fp_dec": {"min": 6, "max": 8} } optimizer = Optimizer(snn, net_dict, optim_config) optimizer.optimize(test_loader) optim_params = { "weights_bw": 8, "neurons_bw": 16, "fp_dec": 6 } # --------------------------- # 產生 VHDL 程式碼 # --------------------------- vhdl_generator = VhdlGenerator(snn, optim_params) vhdl_snn = vhdl_generator.generate(functional=False, interface=True) # 輸出 VHDL 程式碼並寫入指定目錄 print(vhdl_snn.code()) write_vhdl(vhdl_snn, output_dir="Spiker", rm=True) # 若需要,可使用 compile_vhdl 進行編譯: # compile_vhdl(vhdl_snn, output_dir="Spiker") if __name__ == "__main__": main() ``` ``` import os import torch import sys import logging import argparse # --------------------------- # 1. 停用 IPython/Spyder 的 autoreload(若有) # --------------------------- try: from IPython import get_ipython ip = get_ipython() if ip is not None: ip.run_line_magic("autoreload", "0") except Exception: pass # --------------------------- # 2. 檢查工作目錄中是否有與 torchvision 同名的檔案或資料夾 # --------------------------- if os.path.exists(os.path.join(os.getcwd(), "torchvision")): print("Error: 發現工作目錄中有名為 'torchvision' 的檔案或資料夾。") print("請將其重新命名或移除,以避免與官方 torchvision 套件衝突。") sys.exit(1) # --------------------------- # 4. 匯入 spikerplus 所需模組 # --------------------------- from spikerplus.dataloaders import AudioMnistDL from spikerplus import NetBuilder, Trainer, Optimizer, VhdlGenerator from spikerplus.vhdl import write_vhdl, compile_vhdl from spikerplus.vhdl import NetworkSimulator # 設定日誌層級為 INFO logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True) def main(): # --------------------------- # 資料集載入 # --------------------------- batch_size = 64 data_dir = r"C:\Users\Potter Wang\Desktop\SNN\AudioMNIST-master\AudioMNIST-master\data" data_loader = AudioMnistDL(data_dir=data_dir) train_loader, test_loader = data_loader.load(batch_size=batch_size) n_cycles = next(iter(train_loader))[0].shape[1] n_inputs = next(iter(train_loader))[0].shape[2] # --------------------------- # SNN 網路參數設定 # --------------------------- net_dict = { "n_cycles": n_cycles, "n_inputs": n_inputs, "layer_0": { # 隱藏層 "neuron_model": "lif", "n_neurons": 128, #"alpha": None, #"learn_alpha": False, "beta": 0.9375, #"learn_beta": False, "n_exc_inputs": n_inputs, "threshold": 1.0, #"learn_threshold": False, "reset_mechanism": "subtract" }, "layer_1": { # 輸出層 "neuron_model": "lif", "n_neurons": 10, #"alpha": None, #"learn_alpha": False, "beta": 0.9375, #"learn_beta": False, "threshold": 1.0, #"learn_threshold": False, "reset_mechanism": "none" } } optim_config = { "weights_bw": {"min": 8, "max": 8}, "neurons_bw": {"min": 16, "max": 16}, "fp_dec": {"min": 8, "max": 8} } optim_params = { "weights_bw": 8, "neurons_bw": 16, "fp_dec": 6 } net_builder = NetBuilder(net_dict) snn = net_builder.build() """ trainer = Trainer(snn) #, readout_type="spk" trainer.train(train_loader, test_loader, n_epochs=1, store=True) """ if os.path.exists("Trained/trained_state_dict.pt"): state_dict = torch.load("Trained/trained_state_dict.pt") snn.load_state_dict(state_dict) else: logging.info("權重檔案不存在,將從頭開始訓練。") """ optimizer = Optimizer(snn, net_dict, optim_config) optimizer.optimize(test_loader) """ vhdl_generator = VhdlGenerator(snn, optim_params) vhdl_snn = vhdl_generator.generate(functional=True, interface=False) write_vhdl(vhdl_snn, output_dir="Spiker") #, rm=True compile_vhdl(vhdl_snn, output_dir="Spiker") # 如需要,可編譯 VHDL vhdl_sim = NetworkSimulator(vhdl_snn) vhdl_sim.simulate(test_loader,sim_duration="200us")#,sim_duration="1000us" if __name__ == "__main__": main() ```