Create main.cpp
Browse files
main.cpp
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// project_natal/src/main.cpp
|
| 2 |
+
#include <iostream>
|
| 3 |
+
#include <vector>
|
| 4 |
+
#include <cmath>
|
| 5 |
+
#include <chrono>
|
| 6 |
+
#include <string>
|
| 7 |
+
#include <memory>
|
| 8 |
+
|
| 9 |
+
// Einfache Emulation von BF16 (Brain Floating Point 16) für die Aktivierungen
|
| 10 |
+
struct bf16_t {
|
| 11 |
+
uint16_t bits;
|
| 12 |
+
float to_float() const {
|
| 13 |
+
uint32_t val_32 = uint32_t(bits) << 16;
|
| 14 |
+
return *reinterpret_cast<float*>(&val_32);
|
| 15 |
+
}
|
| 16 |
+
static bf16_t from_float(float f) {
|
| 17 |
+
uint32_t val_32 = *reinterpret_cast<uint32_t*>(&f);
|
| 18 |
+
bf16_t out;
|
| 19 |
+
out.bits = uint16_t(val_32 >> 16);
|
| 20 |
+
return out;
|
| 21 |
+
}
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
// Struktur für einen optimierten Ternary-Tensor (Project Natal Format)
|
| 25 |
+
struct NatalTernaryTensor {
|
| 26 |
+
std::string name;
|
| 27 |
+
std::vector<int8_t> weights; // Enthält NUR -1, 0, oder +1
|
| 28 |
+
std::vector<float> scales; // Skalierungsfaktoren pro Kanal (Zeile)
|
| 29 |
+
int rows;
|
| 30 |
+
int cols;
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
class NatalEngine {
|
| 34 |
+
public:
|
| 35 |
+
NatalEngine() {
|
| 36 |
+
std::cout << "[Project Natal] Kernkomponenten geladen. Initialisiere Hardware-Pipelines...\n";
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
// Das Herzstück: 1.58-Bit Matrix-Vektor-Multiplikation via CPU-Additionen
|
| 40 |
+
void mat_vec_multiply_158(const NatalTernaryTensor& matrix, const std::vector<bf16_t>& vec_in, std::vector<float>& vec_out) {
|
| 41 |
+
if (matrix.cols != (int)vec_in.size()) {
|
| 42 |
+
std::cerr << "[Natal - ERROR] Dimensionskonflikt im Kernel! Matrix: "
|
| 43 |
+
<< matrix.cols << ", Vektor: " << vec_in.size() << "\n";
|
| 44 |
+
return;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
vec_out.assign(matrix.rows, 0.0f);
|
| 48 |
+
|
| 49 |
+
// OpenMP Direktive für einfache CPU-Parallelisierung über die Kerne
|
| 50 |
+
#pragma omp parallel for
|
| 51 |
+
for (int r = 0; r < matrix.rows; ++r) {
|
| 52 |
+
float sum = 0.0f;
|
| 53 |
+
int row_offset = r * matrix.cols;
|
| 54 |
+
float current_scale = matrix.scales[r];
|
| 55 |
+
|
| 56 |
+
// Hauptschleife: Keine Multiplikationen! Nur Verzweigungen/Additionen.
|
| 57 |
+
for (int c = 0; c < matrix.cols; ++c) {
|
| 58 |
+
int8_t weight = matrix.weights[row_offset + c];
|
| 59 |
+
|
| 60 |
+
if (weight == 0) {
|
| 61 |
+
continue; // Experte/Kanal inaktiv -> Überspringen spart massig CPU-Zyklen
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
float activation = vec_in[c].to_float();
|
| 65 |
+
|
| 66 |
+
if (weight == 1) {
|
| 67 |
+
sum += activation; // Reine Addition
|
| 68 |
+
} else if (weight == -1) {
|
| 69 |
+
sum -= activation; // Reine Subtraktion
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
// Erst am Ende der Zeile wird einmalig mit dem Skalierungsfaktor multipliziert
|
| 74 |
+
vec_out[r] = sum * current_scale;
|
| 75 |
+
}
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
// Inferenz-Simulation für einen fusionierten QKV-Attention-Schritt
|
| 79 |
+
void process_fused_qkv(const NatalTernaryTensor& fused_qkv, const std::vector<bf16_t>& hidden_states) {
|
| 80 |
+
std::vector<float> qkv_output;
|
| 81 |
+
|
| 82 |
+
auto start = std::chrono::high_resolution_clock::now();
|
| 83 |
+
|
| 84 |
+
// Führe die beschleunigte 1.58-Bit Berechnung auf dem Fused-Tensor aus
|
| 85 |
+
mat_vec_multiply_158(fused_qkv, hidden_states, qkv_output);
|
| 86 |
+
|
| 87 |
+
auto end = std::chrono::high_resolution_clock::now();
|
| 88 |
+
std::chrono::duration<double, std::milli> elapsed = end - start;
|
| 89 |
+
|
| 90 |
+
std::cout << "[Natal - Engine] Fused-QKV Matrix (" << fused_qkv.rows << "x" << fused_qkv.cols
|
| 91 |
+
<< ") verarbeitet in " << elapsed.count() << " ms.\n";
|
| 92 |
+
std::cout << "[Natal - Performance] Durchsatz stabil bei hoher Token-Frequenz.\n";
|
| 93 |
+
}
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
int main() {
|
| 97 |
+
std::cout << "==================================================\n";
|
| 98 |
+
std::cout << " PROJECT NATAL - TERNARY INFERENCE ENGINE \n";
|
| 99 |
+
std::cout << "==================================================\n\n";
|
| 100 |
+
|
| 101 |
+
NatalEngine engine;
|
| 102 |
+
|
| 103 |
+
// Erstelle simulierte Daten für ein extrahiertes MiMo-Modellfragment (z.B. ein Layer)
|
| 104 |
+
// Dimensionen: hidden_dim = 4096. Fused QKV hat die 3-fache Ausgabezeilen-Anzahl (12288)
|
| 105 |
+
int hidden_dim = 4096;
|
| 106 |
+
int fused_rows = hidden_dim * 3;
|
| 107 |
+
|
| 108 |
+
NatalTernaryTensor mock_qkv;
|
| 109 |
+
mock_qkv.name = "layers.0.attention.attn_qkv";
|
| 110 |
+
mock_qkv.rows = fused_rows;
|
| 111 |
+
mock_qkv.cols = hidden_dim;
|
| 112 |
+
mock_qkv.weights.assign(fused_rows * hidden_dim, 0); // Mit 0 initialisieren
|
| 113 |
+
mock_qkv.scales.assign(fused_rows, 0.05f); // Beispielhafte Skalierung
|
| 114 |
+
|
| 115 |
+
// Fülle den Tensor mit pseudozufälligen Ternary-Werten (-1, 0, 1)
|
| 116 |
+
for (size_t i = 0; i < mock_qkv.weights.size(); ++i) {
|
| 117 |
+
if (i % 3 == 0) mock_qkv.weights[i] = 1;
|
| 118 |
+
else if (i % 7 == 0) mock_qkv.weights[i] = -1;
|
| 119 |
+
// Rest bleibt 0
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
// Simuliere Eingabe-Aktivierungen vom vorherigen Layer
|
| 123 |
+
std::vector<bf16_t> mock_hidden_states(hidden_dim);
|
| 124 |
+
for (int i = 0; i < hidden_dim; ++i) {
|
| 125 |
+
mock_hidden_states[i] = bf16_t::from_float(1.0f + std::sin(i * 0.1f));
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
// Starte den Benchmark-Lauf
|
| 129 |
+
engine.process_fused_qkv(mock_qkv, mock_hidden_states);
|
| 130 |
+
|
| 131 |
+
std::cout << "\n[Project Natal] Testlauf erfolgreich absolviert. System bereit für echte Shards.\n";
|
| 132 |
+
return 0;
|
| 133 |
+
}
|