Skip to content

Commit 1fa4b46

Browse files
gguf-viewer: filtered histogram generation to drop percentile-clipped outliers and zero-valued spikes
1 parent bfb4645 commit 1fa4b46

File tree

3 files changed

+63
-6
lines changed

3 files changed

+63
-6
lines changed

tools/gguf-viewer/public/common.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,9 @@ const histogramState = {
518518
bins: [],
519519
maxCount: 0,
520520
total: 0,
521+
clippedLow: 0,
522+
clippedHigh: 0,
523+
zeroCount: 0,
521524
rangeMin: Number.NaN,
522525
rangeMax: Number.NaN,
523526
fetching: false,

tools/gguf-viewer/public/statistics.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,18 @@ function updateStatisticsHeader() {
103103
parts.push(`Total ${formatTooltipInteger(histogramState.total)}`);
104104
}
105105

106+
if (Number.isFinite(histogramState.zeroCount) && histogramState.zeroCount > 0) {
107+
parts.push(`Zeros ${formatTooltipInteger(histogramState.zeroCount)}`);
108+
}
109+
110+
const clippedLow = Number.isFinite(histogramState.clippedLow) ? histogramState.clippedLow : 0;
111+
const clippedHigh = Number.isFinite(histogramState.clippedHigh) ? histogramState.clippedHigh : 0;
112+
if (clippedLow > 0 || clippedHigh > 0) {
113+
const lowLabel = formatTooltipInteger(clippedLow);
114+
const highLabel = formatTooltipInteger(clippedHigh);
115+
parts.push(`Outliers ${lowLabel} low / ${highLabel} high`);
116+
}
117+
106118
if (Number.isFinite(histogramState.rangeMin)
107119
&& Number.isFinite(histogramState.rangeMax)
108120
&& histogramState.rangeMax >= histogramState.rangeMin) {
@@ -140,6 +152,9 @@ function syncHistogramToViewport(fetchAfterResize) {
140152
histogramState.bins = [];
141153
histogramState.maxCount = 0;
142154
histogramState.total = 0;
155+
histogramState.clippedLow = 0;
156+
histogramState.clippedHigh = 0;
157+
histogramState.zeroCount = 0;
143158
clearHistogramCanvas();
144159
if (heatmapState.tensor && fetchAfterResize) {
145160
void fetchHistogram();
@@ -197,12 +212,18 @@ async function fetchHistogram() {
197212
const maxCount = Number.isFinite(data.maxCount) ? Number(data.maxCount) : 0;
198213
const rangeMin = Number.isFinite(data.min) ? Number(data.min) : Number.NaN;
199214
const rangeMax = Number.isFinite(data.max) ? Number(data.max) : Number.NaN;
215+
const clippedLow = Number.isFinite(data.clippedLow) ? Number(data.clippedLow) : 0;
216+
const clippedHigh = Number.isFinite(data.clippedHigh) ? Number(data.clippedHigh) : 0;
217+
const zeroCount = Number.isFinite(data.zeroCount) ? Number(data.zeroCount) : 0;
200218
histogramState.tensor = heatmapState.tensor;
201219
histogramState.slice = typeof data.slice === "number" ? data.slice : heatmapState.slice;
202220
histogramState.bins = bins;
203221
histogramState.maxCount = maxCount;
204222
histogramState.rangeMin = rangeMin;
205223
histogramState.rangeMax = rangeMax;
224+
histogramState.clippedLow = clippedLow;
225+
histogramState.clippedHigh = clippedHigh;
226+
histogramState.zeroCount = zeroCount;
206227
if (Number.isFinite(data.total)) {
207228
histogramState.total = Number(data.total);
208229
} else {
@@ -249,6 +270,9 @@ function resetHistogram(message = STATISTICS_DEFAULT_HEADER_MESSAGE) {
249270
histogramState.bins = [];
250271
histogramState.maxCount = 0;
251272
histogramState.total = 0;
273+
histogramState.clippedLow = 0;
274+
histogramState.clippedHigh = 0;
275+
histogramState.zeroCount = 0;
252276
histogramState.rangeMin = Number.NaN;
253277
histogramState.rangeMax = Number.NaN;
254278
histogramState.fetching = false;

tools/gguf-viewer/viewer.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -809,11 +809,14 @@ struct tensor_tile_result {
809809
};
810810

811811
struct tensor_histogram_result {
812-
size_t slice = 0;
813-
uint64_t total = 0;
814-
uint64_t max_bin = 0;
815-
float range_min = 0.0f;
816-
float range_max = 0.0f;
812+
size_t slice = 0;
813+
uint64_t total = 0;
814+
uint64_t max_bin = 0;
815+
uint64_t clipped_lo = 0;
816+
uint64_t clipped_hi = 0;
817+
uint64_t zero_count = 0;
818+
float range_min = 0.0f;
819+
float range_max = 0.0f;
817820
std::vector<uint64_t> bins;
818821
};
819822

@@ -1543,6 +1546,9 @@ bool tensor_slice_histogram(
15431546
out.bins.assign(bin_count, 0);
15441547
out.total = 0;
15451548
out.max_bin = 0;
1549+
out.clipped_lo = 0;
1550+
out.clipped_hi = 0;
1551+
out.zero_count = 0;
15461552
out.range_min = 0.0f;
15471553
out.range_max = 0.0f;
15481554
return true;
@@ -1558,6 +1564,9 @@ bool tensor_slice_histogram(
15581564
out.bins.assign(bin_count, 0);
15591565
out.total = 0;
15601566
out.max_bin = 0;
1567+
out.clipped_lo = 0;
1568+
out.clipped_hi = 0;
1569+
out.zero_count = 0;
15611570
out.range_min = stats.min;
15621571
out.range_max = stats.max;
15631572

@@ -1569,6 +1578,8 @@ bool tensor_slice_histogram(
15691578
const float range_max = stats.max;
15701579
const bool has_valid_range = std::isfinite(range_min) && std::isfinite(range_max);
15711580
const float span = range_max - range_min;
1581+
const bool can_use_range = has_valid_range && span > 0.0f && bin_count > 1;
1582+
const bool can_filter_zero = can_use_range;
15721583

15731584
size_t remaining = slice_count;
15741585
size_t current_off = base_offset;
@@ -1588,8 +1599,24 @@ bool tensor_slice_histogram(
15881599
continue;
15891600
}
15901601

1602+
if (can_use_range) {
1603+
if (value < range_min) {
1604+
out.clipped_lo += 1;
1605+
continue;
1606+
}
1607+
if (value > range_max) {
1608+
out.clipped_hi += 1;
1609+
continue;
1610+
}
1611+
}
1612+
1613+
if (can_filter_zero && value == 0.0f) {
1614+
out.zero_count += 1;
1615+
continue;
1616+
}
1617+
15911618
size_t bin_index = 0;
1592-
if (has_valid_range && span > 0.0f && bin_count > 1) {
1619+
if (can_use_range) {
15931620
float normalized = (value - range_min) / span;
15941621
if (normalized <= 0.0f) {
15951622
bin_index = 0;
@@ -2016,6 +2043,9 @@ void setup_routes(httplib::Server & server, std::shared_ptr<server_state> state)
20162043
body["range"] = { {"min", histogram.range_min}, {"max", histogram.range_max} };
20172044
body["maxCount"] = histogram.max_bin;
20182045
body["total"] = histogram.total;
2046+
body["clippedLow"] = histogram.clipped_lo;
2047+
body["clippedHigh"] = histogram.clipped_hi;
2048+
body["zeroCount"] = histogram.zero_count;
20192049
body["min"] = histogram.range_min;
20202050
body["max"] = histogram.range_max;
20212051
body["bins"] = std::move(bins);

0 commit comments

Comments
 (0)