From 5b41cd7e5db78616387392872de15299a2432617 Mon Sep 17 00:00:00 2001 From: LoganDark Date: Sat, 3 Jun 2023 03:44:50 -0700 Subject: [PATCH] Add capability for extra binaries to be built with rwkv.cpp (#87) * Add capability for examples This also adds a quantizer that works without python. in the future, we might be able to convert from pytorch as well, without python. * example implied code style * rename examples to tools * rename cpuinfo.c to cpu_info.c * include ggml header again * Return EXIT_FAILURE on help * done with this * final name: extras * going To have a seizure * wait literal double n --- CMakeLists.txt | 1 + extras/CMakeLists.txt | 10 ++++++++ extras/cpu_info.c | 7 ++++++ extras/quantize.c | 58 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 extras/CMakeLists.txt create mode 100644 extras/cpu_info.c create mode 100644 extras/quantize.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 38931e5..38497c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -286,3 +286,4 @@ endif() enable_testing() add_subdirectory(tests) +add_subdirectory(extras) diff --git a/extras/CMakeLists.txt b/extras/CMakeLists.txt new file mode 100644 index 0000000..ff634df --- /dev/null +++ b/extras/CMakeLists.txt @@ -0,0 +1,10 @@ +function(rwkv_add_extra source) + get_filename_component(EXTRA_TARGET ${source} NAME_WE) + add_executable(rwkv_${EXTRA_TARGET} ${source}) + target_link_libraries(rwkv_${EXTRA_TARGET} PRIVATE ggml rwkv) +endfunction() + +file(GLOB extras *.c) +foreach (extra ${extras}) + rwkv_add_extra(${extra}) +endforeach() \ No newline at end of file diff --git a/extras/cpu_info.c b/extras/cpu_info.c new file mode 100644 index 0000000..115caf8 --- /dev/null +++ b/extras/cpu_info.c @@ -0,0 +1,7 @@ +#include "rwkv.h" + +#include + +int main() { + printf("%s", rwkv_get_system_info_string()); +} \ No newline at end of file diff --git a/extras/quantize.c b/extras/quantize.c new file mode 100644 index 0000000..ed98ac3 --- /dev/null +++ b/extras/quantize.c @@ -0,0 +1,58 @@ +#include "ggml.h" +#include "rwkv.h" + +#include +#include +#include + +enum ggml_type type_from_string(const char* string) { + if (strcmp(string, "Q4_0") == 0) return GGML_TYPE_Q4_0; + if (strcmp(string, "Q4_1") == 0) return GGML_TYPE_Q4_1; + if (strcmp(string, "Q5_0") == 0) return GGML_TYPE_Q5_0; + if (strcmp(string, "Q5_1") == 0) return GGML_TYPE_Q5_1; + if (strcmp(string, "Q8_0") == 0) return GGML_TYPE_Q8_0; + return GGML_TYPE_COUNT; +} + +#ifdef _WIN32 +bool QueryPerformanceFrequency(uint64_t* lpFrequency); +bool QueryPerformanceCounter(uint64_t* lpPerformanceCount); + +#define time_t uint64_t +#define time_calibrate(freq) do { QueryPerformanceFrequency(&freq); freq /= 1000; } while (0) +#define time_measure(x) QueryPerformanceCounter(&x) +#define TIME_DIFF(freq, start, end) (double) ((end - start) / freq) / 1000. +#else +#include + +#define time_t struct timespec +#define time_calibrate(freq) (void) freq +#define time_measure(x) clock_gettime(CLOCK_MONOTONIC, &x) +#define TIME_DIFF(freq, start, end) (double) ((end.tv_nsec - start.tv_nsec) / 1000000) / 1000 +#endif + +int main(int argc, char* argv[]) { + if (argc != 4 || type_from_string(argv[3]) == GGML_TYPE_COUNT) { + fprintf(stderr, "Usage: %s INPUT OUTPUT FORMAT\n\nAvailable formats: Q4_0 Q4_1 Q5_0 Q5_1 Q8_0\n", argv[0]); + return EXIT_FAILURE; + } + + time_t freq, start, end; + time_calibrate(freq); + + fprintf(stderr, "Quantizing ...\n"); + + time_measure(start); + bool success = rwkv_quantize_model_file(argv[1], argv[2], argv[3]); + time_measure(end); + + double diff = TIME_DIFF(freq, start, end); + + if (success) { + fprintf(stderr, "Succeeded in %.3fs\n", diff); + return EXIT_SUCCESS; + } else { + fprintf(stderr, "Error in %.3fs: 0x%.8X\n", diff, rwkv_get_last_error(NULL)); + return EXIT_FAILURE; + } +} \ No newline at end of file