mirror of
https://github.com/karpathy/llm.c.git
synced 2026-07-20 23:05:08 -04:00
70 lines
2.4 KiB
C
70 lines
2.4 KiB
C
/*
|
|
Simple OutlierDetector that we can use to monitor the loss and grad norm
|
|
Internally, it keeps track of a window of measurements and each time we
|
|
add a measurement, it returns the z-score of the new value with respect to
|
|
the window of measurements. This can be used to detect outliers in the data.
|
|
|
|
We use double so that the detector doesn't drift too much, because we
|
|
update the mean and variance with += on each step for efficiency. We could
|
|
reconsider this choice in the future, as the compute cost here is minimal.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
|
|
// use compile-time constant for window size to avoid dynamic memory allocations
|
|
#define OUTLIER_DETECTOR_WINDOW_SIZE 128
|
|
|
|
typedef struct {
|
|
double buffer[OUTLIER_DETECTOR_WINDOW_SIZE];
|
|
int count;
|
|
int index;
|
|
double sum;
|
|
double sum_sq;
|
|
} OutlierDetector;
|
|
|
|
void init_detector(OutlierDetector *detector) {
|
|
for (int i = 0; i < OUTLIER_DETECTOR_WINDOW_SIZE; i++) {
|
|
detector->buffer[i] = 0.0;
|
|
}
|
|
detector->count = 0;
|
|
detector->index = 0;
|
|
detector->sum = 0.0;
|
|
detector->sum_sq = 0.0;
|
|
}
|
|
|
|
double update_detector(OutlierDetector *detector, double new_value) {
|
|
|
|
if (detector->count < OUTLIER_DETECTOR_WINDOW_SIZE) {
|
|
// here we are still building up a window of observations
|
|
detector->buffer[detector->count] = new_value;
|
|
detector->sum += new_value;
|
|
detector->sum_sq += new_value * new_value;
|
|
detector->count++;
|
|
return nan(""); // not enough data yet
|
|
|
|
} else {
|
|
// we've filled the window, so now we can start detecting outliers
|
|
|
|
// pop the oldest value from the window
|
|
double old_value = detector->buffer[detector->index];
|
|
detector->sum -= old_value;
|
|
detector->sum_sq -= old_value * old_value;
|
|
// push the new value into the window
|
|
detector->buffer[detector->index] = new_value;
|
|
detector->sum += new_value;
|
|
detector->sum_sq += new_value * new_value;
|
|
// move the index to the next position
|
|
detector->index = (detector->index + 1) % OUTLIER_DETECTOR_WINDOW_SIZE;
|
|
// calculate the z-score of the new value
|
|
double mean = detector->sum / OUTLIER_DETECTOR_WINDOW_SIZE;
|
|
double variance = (detector->sum_sq / OUTLIER_DETECTOR_WINDOW_SIZE) - (mean * mean);
|
|
double std_dev = sqrt(variance);
|
|
if (std_dev == 0.0) {
|
|
return 0.0;
|
|
}
|
|
double z = (new_value - mean) / std_dev;
|
|
|
|
return z;
|
|
}
|
|
}
|