1- #include " arg.h"
2- #include " common.h"
3- #include " log.h"
4- #include " llama.h"
5-
1+ #include < algorithm>
62#include < chrono>
73#include < cmath>
84#include < cstdio>
95#include < cstring>
106#include < ctime>
11- #include < thread>
12- #include < mutex>
13- #include < vector>
147#include < fstream>
8+ #include < mutex>
9+ #include < numeric>
10+ #include < thread>
1511#include < unordered_map>
16- #include < algorithm>
12+ #include < vector>
13+
14+ #include " arg.h"
15+ #include " common.h"
16+ #include " llama.h"
17+ #include " log.h"
1718
1819#if defined(_MSC_VER)
1920#pragma warning(disable: 4244 4267) // possible loss of data
@@ -33,10 +34,18 @@ struct Stats {
3334 int ncall = 0 ;
3435};
3536
36- struct Tally {
37+ struct tensor_statistics {
3738 std::string tensor;
38- double bias = 0 ;
39- int count = 0 ;
39+ float total = 0 ;
40+ float mean = 0 ;
41+ float max = 0 ;
42+ float min = 0 ;
43+ float stddev = 0 ;
44+ float cv = 0 ;
45+ float zd = 0 ;
46+ float active = 0 ;
47+ float entropy = 0 ;
48+ int elements = 0 ;
4049};
4150
4251class IMatrixCollector {
@@ -45,7 +54,7 @@ class IMatrixCollector {
4554 void set_params (common_params params) { m_params = std::move (params); }
4655 bool collect_imatrix (struct ggml_tensor * t, bool ask, void * user_data);
4756 void save_imatrix (int ncall = -1 ) const ;
48- bool load_imatrix (const char * fname, std::vector<Tally > * tally = nullptr );
57+ bool load_imatrix (const char * fname, std::vector<tensor_statistics > * tstats = nullptr );
4958private:
5059 std::unordered_map<std::string, Stats> m_stats;
5160 common_params m_params;
@@ -323,7 +332,7 @@ void IMatrixCollector::save_imatrix(int ncall) const {
323332 LOG_DBGV (1 , " %s: stored collected data after %d chunks in %s\n " , __func__, m_last_call, fname.c_str ());
324333}
325334
326- bool IMatrixCollector::load_imatrix (const char * fname, std::vector<Tally > * tally ) {
335+ bool IMatrixCollector::load_imatrix (const char * fname, std::vector<tensor_statistics > * ts ) {
327336 std::ifstream in (fname, std::ios::binary);
328337 if (!in) {
329338 LOG_ERR (" %s: failed to open %s\n " ,__func__, fname);
@@ -370,21 +379,58 @@ bool IMatrixCollector::load_imatrix(const char * fname, std::vector<Tally> * tal
370379 }
371380
372381 // Recreate the state as expected by save_imatrix(), and correct for weighted sum.
373- double total = 0 ;
382+ std::vector<float > activations;
383+ activations.reserve (nval);
384+
374385 for (int i = 0 ; i < nval; i++) {
375386 e.values [i] += tmp[i];
376387 e.counts [i] += ncall;
377- const double avg_sq = (1.0 * e.values [i]) / e.counts [i];
378- total += avg_sq;
388+ activations.push_back (e.values [i] / static_cast <float >(e.counts [i]));
379389 }
380390 e.ncall += ncall;
381391
382- if (tally) {
383- tally->emplace_back ();
384- auto & [tensor, bias, count] = (*tally)[i];
392+ if (ts) {
393+ float total_bias = std::accumulate (activations.begin (), activations.end (), 0 .0f );
394+ float max_bias = * std::max_element (activations.begin (), activations.end ());
395+ float min_bias = * std::min_element (activations.begin (), activations.end ());
396+ float mean_bias = total_bias / activations.size ();
397+ float sq_total_bias = std::inner_product (activations.begin (), activations.end (), activations.begin (), 0 .0f );
398+ float dev = std::sqrt ((sq_total_bias / activations.size ()) - (mean_bias * mean_bias));
399+ float rmsd = mean_bias > 0 .0f ? dev / mean_bias : 0 .0f ;
400+
401+ float threshold = 1e-6f ;
402+ int inactive_count = std::count_if (activations.begin (), activations.end (), [threshold](const float v) { return fabs (v) < threshold; });
403+ float active_ratio = 1 - (static_cast <float >(inactive_count) / activations.size ());
404+
405+ float ent = 0 .0f ;
406+ if (total_bias > 0 ) {
407+ for (auto act : activations) {
408+ if (float p = act / total_bias; p > 0 ) {
409+ ent -= p* std::log2 (p);
410+ }
411+ }
412+ }
413+
414+ int z_score = 0 ;
415+ for (auto act : activations) {
416+ if (float p = (act - mean_bias) / dev; p > 1 ) {
417+ z_score++;
418+ }
419+ }
420+
421+ ts->emplace_back ();
422+ auto & [tensor, total, mean, max, min, stddev, cv, zd, active, entropy, elements] = (*ts)[i];
385423 tensor = name_as_vec.data ();
386- bias = total;
387- count = nval;
424+ total = total_bias;
425+ mean = mean_bias;
426+ max = max_bias;
427+ min = min_bias;
428+ stddev = dev;
429+ cv = rmsd;
430+ active = active_ratio;
431+ entropy = ent;
432+ elements = static_cast <int >(activations.size ());
433+ zd = static_cast <float >(z_score) / static_cast <float >(elements);
388434 }
389435 }
390436 return true ;
@@ -633,42 +679,35 @@ int main(int argc, char ** argv) {
633679 return 1 ;
634680 }
635681
636- std::vector<Tally> tallies ;
682+ std::vector<tensor_statistics> ts ;
637683
638684 if (params.show_statistics ) {
639685 if (params.in_files .empty () || params.in_files .size () > 1 ) {
640686 LOG_ERR (" \n Error: a single imatrix file is required to compute tensor statistics\n\n " );
641687 return 1 ;
642688 }
643- if (!g_collector.load_imatrix (params.in_files [0 ].c_str (), & tallies )) {
689+ if (!g_collector.load_imatrix (params.in_files [0 ].c_str (), & ts )) {
644690 LOG_ERR (" \n Error: %s is not a valid imatrix file\n\n " , params.in_files [0 ].c_str ());
645691 return 1 ;
646692 }
647- if (tallies .empty ()) {
693+ if (ts .empty ()) {
648694 LOG_ERR (" Error: cannot compute statistics for %s\n\n " , params.in_files [0 ].c_str ());
649695 return 1 ;
650696 }
651- double total = 0 ;
652- for (const auto & tallie : tallies) {
653- total += tallie.bias ;
654- }
655697
656- struct tally_sort {
657- bool operator ()(const Tally& x, const Tally & y) const {
658- return x.bias > y.bias ;
659- }
660- };
661- std::sort (tallies.begin (), tallies.end (), tally_sort ());
662-
663- LOG_INF (" \n Computing statistics for %s (%d tensors)\n " , params.in_files [0 ].c_str (), static_cast <int >(tallies.size ()));
664- LOG_INF (" \n Layer\t Tensor\t Total Bias\t Avg Bias\t Contribution\n " );
665- LOG_INF (" ===============================================================================================\n " );
666- for (const auto & [tensor, bias, count] : tallies) {
698+ std::sort (ts.begin (), ts.end (), [](const tensor_statistics &a, const tensor_statistics &b) { return a.total > b.total ; });
699+ LOG_INF (" \n Computing statistics for %s (%d tensors)\n " , params.in_files [0 ].c_str (), static_cast <int >(ts.size ()));
700+ LOG_INF (" \n %5s\t %-20s\t %10s\t %7s\t %12s\t %9s\t %10s\t %9s\t %6s\t %12s\t %7s\t %10s\n " ,
701+ " Layer" , " Tensor" , " Σ(Bias)" , " Min" , " Max" , " μ" , " σ" , " % Active" , " N" , " Entropy" , " E (norm)" , " ZD Score" );
702+ LOG_INF (" ==========================================================================================================================================================================\n " );
703+ for (const auto & [tensor, total, mean, max, min, stddev, cv, zd, active, entropy, elements] : ts) {
667704 std::string layer, name;
668705 process_tensor_name (tensor, layer, name);
669- LOG_INF (" %5s\t %30s\t %15.2f\t %15.4f\t %19.4f%%\n " , layer.c_str (), name.c_str (), bias, bias / count, 100.0 * bias / total);
706+ LOG_INF (" %5s\t %-20s\t %10.2f\t %7.4f\t %12.4f\t %8.4f\t %9.4f\t %8.2f%%\t %6d\t %12.4f\t %7.2f%%\t %10.4f\n " ,
707+ layer.c_str (), name.c_str (), total, min, max, mean, stddev, active * 100 .0f , elements, entropy, 100 .0f * (entropy / std::log2 (elements)), 1000 .0f * zd);
670708 }
671709 LOG_INF (" \n " );
710+
672711 return 0 ;
673712 }
674713
0 commit comments