Merge remote-tracking branch 'upstream/master' into eval-thread-count
This commit is contained in:
commit
a333c3a56b
17 changed files with 1108 additions and 294 deletions
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
|
@ -81,7 +81,6 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
sanitizer: [ADDRESS, THREAD, UNDEFINED]
|
sanitizer: [ADDRESS, THREAD, UNDEFINED]
|
||||||
build_type: [Debug, Release]
|
build_type: [Debug, Release]
|
||||||
accelerate: [ON, OFF]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
|
@ -99,7 +98,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DLLAMA_SANITIZE_${{ matrix.sanitizer }}=ON -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DLLAMA_ACCELERATE=${{ matrix.accelerate }}
|
cmake .. -DLLAMA_SANITIZE_${{ matrix.sanitizer }}=ON -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||||
cmake --build . --config ${{ matrix.build_type }}
|
cmake --build . --config ${{ matrix.build_type }}
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
|
|
|
@ -307,7 +307,7 @@ add_library(ggml OBJECT
|
||||||
|
|
||||||
target_include_directories(ggml PUBLIC .)
|
target_include_directories(ggml PUBLIC .)
|
||||||
target_compile_features(ggml PUBLIC c_std_11) # don't bump
|
target_compile_features(ggml PUBLIC c_std_11) # don't bump
|
||||||
target_link_libraries(ggml PRIVATE Threads::Threads ${LLAMA_EXTRA_LIBS})
|
target_link_libraries(ggml PUBLIC Threads::Threads ${LLAMA_EXTRA_LIBS})
|
||||||
if (BUILD_SHARED_LIBS)
|
if (BUILD_SHARED_LIBS)
|
||||||
set_target_properties(ggml PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
set_target_properties(ggml PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
10
Makefile
10
Makefile
|
@ -101,11 +101,13 @@ ifdef LLAMA_OPENBLAS
|
||||||
LDFLAGS += -lopenblas
|
LDFLAGS += -lopenblas
|
||||||
endif
|
endif
|
||||||
ifdef LLAMA_CUBLAS
|
ifdef LLAMA_CUBLAS
|
||||||
CFLAGS += -DGGML_USE_CUBLAS -I/usr/local/cuda/include
|
CFLAGS += -DGGML_USE_CUBLAS -I/usr/local/cuda/include
|
||||||
LDFLAGS += -lcublas_static -lculibos -lcudart_static -lcublasLt_static -lpthread -ldl -L/usr/local/cuda/lib64
|
LDFLAGS += -lcublas -lculibos -lcudart -lcublasLt -lpthread -ldl -lrt -L/usr/local/cuda/lib64
|
||||||
OBJS += ggml-cuda.o
|
OBJS += ggml-cuda.o
|
||||||
|
NVCC = nvcc
|
||||||
|
NVCCFLAGS = --forward-unknown-to-host-linker -arch=native
|
||||||
ggml-cuda.o: ggml-cuda.cu ggml-cuda.h
|
ggml-cuda.o: ggml-cuda.cu ggml-cuda.h
|
||||||
nvcc -arch=native -c -o $@ $<
|
$(NVCC) $(NVCCFLAGS) $(CXXFLAGS) -c $< -o $@
|
||||||
endif
|
endif
|
||||||
ifdef LLAMA_GPROF
|
ifdef LLAMA_GPROF
|
||||||
CFLAGS += -pg
|
CFLAGS += -pg
|
||||||
|
|
20
SHA256SUMS
20
SHA256SUMS
|
@ -1,12 +1,27 @@
|
||||||
700df0d3013b703a806d2ae7f1bfb8e59814e3d06ae78be0c66368a50059f33d models/7B/consolidated.00.pth
|
700df0d3013b703a806d2ae7f1bfb8e59814e3d06ae78be0c66368a50059f33d models/7B/consolidated.00.pth
|
||||||
|
666a4bb533b303bdaf89e1b6a3b6f93535d868de31d903afdc20983dc526c847 models/7B/ggml-model-f16.bin
|
||||||
|
fcb7664c2e69776920b526362a243e912f73c36b1ec892eb354bab940f5edb5a models/7B/ggml-model-q4_0.bin
|
||||||
|
cc061458339a3eb8bcecbf0a825e9924fb7d1a8150f63cd5d091caa99215aafe models/7B/ggml-model-q4_1.bin
|
||||||
|
1bc7484c24a87612726d756f1761890e7acf5f412e23378577ce50fbe789b5b8 models/7B/ggml-model-q4_2.bin
|
||||||
|
3429bf198ec771886cf81a574df45245f3ebf04f0ce0956b73ef5d0ab01ff48b models/7B/ggml-model-q4_3.bin
|
||||||
7e89e242ddc0dd6f060b43ca219ce8b3e8f08959a72cb3c0855df8bb04d46265 models/7B/params.json
|
7e89e242ddc0dd6f060b43ca219ce8b3e8f08959a72cb3c0855df8bb04d46265 models/7B/params.json
|
||||||
745bf4e29a4dd6f411e72976d92b452da1b49168a4f41c951cfcc8051823cf08 models/13B/consolidated.00.pth
|
745bf4e29a4dd6f411e72976d92b452da1b49168a4f41c951cfcc8051823cf08 models/13B/consolidated.00.pth
|
||||||
d5ccbcc465c71c0de439a5aeffebe8344c68a519bce70bc7f9f92654ee567085 models/13B/consolidated.01.pth
|
d5ccbcc465c71c0de439a5aeffebe8344c68a519bce70bc7f9f92654ee567085 models/13B/consolidated.01.pth
|
||||||
|
2b206e9b21fb1076f11cafc624e2af97c9e48ea09312a0962153acc20d45f808 models/13B/ggml-model-f16.bin
|
||||||
|
4b69e4d6b6e3275230955997b90407fceca7e5ab3daf2e63a2c9e7270a8e1e3e models/13B/ggml-model-q4_0.bin
|
||||||
|
d9581b5b88e5622532fe897c9f9b0e67a317d22dd27a6f90fa4ab8c6d23ccdbb models/13B/ggml-model-q4_1.bin
|
||||||
|
8d55a2077317ec9a928c7851d6a43e08e51f7e9e08360f2a7a7e1deefea3134f models/13B/ggml-model-q4_2.bin
|
||||||
|
4208cdec9788ffa48dc1a17af2c36a0299f5bf3eb0e2b87889dda7fad591fca3 models/13B/ggml-model-q4_3.bin
|
||||||
4ab77bec4d4405ccb66a97b282574c89a94417e3c32e5f68f37e2876fc21322f models/13B/params.json
|
4ab77bec4d4405ccb66a97b282574c89a94417e3c32e5f68f37e2876fc21322f models/13B/params.json
|
||||||
e23294a58552d8cdec5b7e8abb87993b97ea6eced4178ff2697c02472539d067 models/30B/consolidated.00.pth
|
e23294a58552d8cdec5b7e8abb87993b97ea6eced4178ff2697c02472539d067 models/30B/consolidated.00.pth
|
||||||
4e077b7136c7ae2302e954860cf64930458d3076fcde9443f4d0e939e95903ff models/30B/consolidated.01.pth
|
4e077b7136c7ae2302e954860cf64930458d3076fcde9443f4d0e939e95903ff models/30B/consolidated.01.pth
|
||||||
24a87f01028cbd3a12de551dcedb712346c0b5cbdeff1454e0ddf2df9b675378 models/30B/consolidated.02.pth
|
24a87f01028cbd3a12de551dcedb712346c0b5cbdeff1454e0ddf2df9b675378 models/30B/consolidated.02.pth
|
||||||
1adfcef71420886119544949767f6a56cb6339b4d5fcde755d80fe68b49de93b models/30B/consolidated.03.pth
|
1adfcef71420886119544949767f6a56cb6339b4d5fcde755d80fe68b49de93b models/30B/consolidated.03.pth
|
||||||
|
7e1b524061a9f4b27c22a12d6d2a5bf13b8ebbea73e99f218809351ed9cf7d37 models/30B/ggml-model-f16.bin
|
||||||
|
7a679908ce31c9d6ae2e38d6059bcd4d0ad3a870cd58cc1c8f7b36f2b2f51c73 models/30B/ggml-model-q4_0.bin
|
||||||
|
7b75ac615fa369ee593493a7e6ef87542bf0350255db928b22c5a24f6d598bcd models/30B/ggml-model-q4_1.bin
|
||||||
|
2c82b4954a94a6a284f452f6011c1e4f0d20362c194a0b1eb5737f5fd8a20fb3 models/30B/ggml-model-q4_2.bin
|
||||||
|
a6188660199dbcb8d5658abe7d89169869e50423494385830d9e6b330ea7fc33 models/30B/ggml-model-q4_3.bin
|
||||||
2c07118ea98d69dbe7810d88520e30288fa994751b337f8fca02b171955f44cb models/30B/params.json
|
2c07118ea98d69dbe7810d88520e30288fa994751b337f8fca02b171955f44cb models/30B/params.json
|
||||||
135c563f6b3938114458183afb01adc9a63bef3d8ff7cccc3977e5d3664ecafe models/65B/consolidated.00.pth
|
135c563f6b3938114458183afb01adc9a63bef3d8ff7cccc3977e5d3664ecafe models/65B/consolidated.00.pth
|
||||||
9a600b37b19d38c7e43809485f70d17d1dc12206c07efa83bc72bb498a568bde models/65B/consolidated.01.pth
|
9a600b37b19d38c7e43809485f70d17d1dc12206c07efa83bc72bb498a568bde models/65B/consolidated.01.pth
|
||||||
|
@ -16,5 +31,10 @@ e7babf7c5606f165a3756f527cb0fedc4f83e67ef1290391e52fb1cce5f26770 models/65B/con
|
||||||
a287c0dfe49081626567c7fe87f74cce5831f58e459b427b5e05567641f47b78 models/65B/consolidated.05.pth
|
a287c0dfe49081626567c7fe87f74cce5831f58e459b427b5e05567641f47b78 models/65B/consolidated.05.pth
|
||||||
72b4eba67a1a3b18cb67a85b70f8f1640caae9b40033ea943fb166bd80a7b36b models/65B/consolidated.06.pth
|
72b4eba67a1a3b18cb67a85b70f8f1640caae9b40033ea943fb166bd80a7b36b models/65B/consolidated.06.pth
|
||||||
d27f5b0677d7ff129ceacd73fd461c4d06910ad7787cf217b249948c3f3bc638 models/65B/consolidated.07.pth
|
d27f5b0677d7ff129ceacd73fd461c4d06910ad7787cf217b249948c3f3bc638 models/65B/consolidated.07.pth
|
||||||
|
60758f2384d74e423dffddfd020ffed9d3bb186ebc54506f9c4a787d0f5367b0 models/65B/ggml-model-f16.bin
|
||||||
|
c671fe1bce71499ac732ec999770ebe53ac486623a7891e42c9dfdb6962d2c64 models/65B/ggml-model-q4_0.bin
|
||||||
|
4743a28aac3e5f32a6e838a815f51d3779de44fbbe251d745251e66c23c5950f models/65B/ggml-model-q4_1.bin
|
||||||
|
4a145a210c56982389b1ed34387e0590c3e0d7325fa9be4f2284fe4d244a3633 models/65B/ggml-model-q4_2.bin
|
||||||
|
305e91a4608b4f627b9b8ad5b4af75187d2684254bfd76dcb9db571618ef293c models/65B/ggml-model-q4_3.bin
|
||||||
999ed1659b469ccc2a941714c0a9656fa571d17c9f7c8c7589817ca90edef51b models/65B/params.json
|
999ed1659b469ccc2a941714c0a9656fa571d17c9f7c8c7589817ca90edef51b models/65B/params.json
|
||||||
9e556afd44213b6bd1be2b850ebbbd98f5481437a8021afaf58ee7fb1818d347 models/tokenizer.model
|
9e556afd44213b6bd1be2b850ebbbd98f5481437a8021afaf58ee7fb1818d347 models/tokenizer.model
|
||||||
|
|
|
@ -264,7 +264,7 @@ int main(int argc, char ** argv) {
|
||||||
// infinite text generation via context swapping
|
// infinite text generation via context swapping
|
||||||
// if we run out of context:
|
// if we run out of context:
|
||||||
// - take the n_keep first tokens from the original prompt (via n_past)
|
// - take the n_keep first tokens from the original prompt (via n_past)
|
||||||
// - take half of the last (n_ctx - n_keep) tokens and recompute the logits in a batch
|
// - take half of the last (n_ctx - n_keep) tokens and recompute the logits in batches
|
||||||
if (n_past + (int) embd.size() > n_ctx) {
|
if (n_past + (int) embd.size() > n_ctx) {
|
||||||
const int n_left = n_past - params.n_keep;
|
const int n_left = n_past - params.n_keep;
|
||||||
|
|
||||||
|
@ -282,13 +282,21 @@ int main(int argc, char ** argv) {
|
||||||
//printf("\n---\n");
|
//printf("\n---\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (llama_eval(ctx, embd.data(), embd.size(), n_past, params.n_threads, params.n_ethreads)) {
|
// evaluate tokens in batches
|
||||||
fprintf(stderr, "%s : failed to eval\n", __func__);
|
// embd is typically prepared beforehand to fit within a batch, but not always
|
||||||
return 1;
|
for (int i = 0; i < (int) embd.size(); i += params.n_batch) {
|
||||||
|
int n_eval = (int) embd.size() - i;
|
||||||
|
if (n_eval > params.n_batch) {
|
||||||
|
n_eval = params.n_batch;
|
||||||
|
}
|
||||||
|
if (llama_eval(ctx, &embd[i], n_eval, n_past, params.n_threads, params.n_ethreads)) {
|
||||||
|
fprintf(stderr, "%s : failed to eval\n", __func__);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
n_past += n_eval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n_past += embd.size();
|
|
||||||
embd.clear();
|
embd.clear();
|
||||||
|
|
||||||
if ((int) embd_inp.size() <= n_consumed && !is_interacting) {
|
if ((int) embd_inp.size() <= n_consumed && !is_interacting) {
|
||||||
|
|
|
@ -54,7 +54,13 @@ void perplexity(llama_context * ctx, const gpt_params & params) {
|
||||||
auto end_t = std::chrono::high_resolution_clock::now();
|
auto end_t = std::chrono::high_resolution_clock::now();
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
const float seconds = std::chrono::duration<float>(end_t - start_t).count();
|
const float seconds = std::chrono::duration<float>(end_t - start_t).count();
|
||||||
printf("%.2f seconds per pass - ETA %.2f hours\n", seconds, (seconds * seq_count) / (60.0*60.0));
|
printf("%.2f seconds per pass - ETA ", seconds);
|
||||||
|
int total_seconds = (int)(seconds * seq_count);
|
||||||
|
if (total_seconds >= 60*60) {
|
||||||
|
printf("%d hours ", total_seconds / (60*60));
|
||||||
|
total_seconds = total_seconds % (60*60);
|
||||||
|
}
|
||||||
|
printf("%d minutes\n", total_seconds / 60);
|
||||||
}
|
}
|
||||||
// We get the logits for all the tokens in the context window (params.n_ctx)
|
// We get the logits for all the tokens in the context window (params.n_ctx)
|
||||||
// from llama_eval above. Now, based on https://huggingface.co/docs/transformers/perplexity,
|
// from llama_eval above. Now, based on https://huggingface.co/docs/transformers/perplexity,
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
struct quantize_stats_params {
|
struct quantize_stats_params {
|
||||||
std::string model = "models/7B/ggml-model-f16.bin";
|
std::string model = "models/7B/ggml-model-f16.bin";
|
||||||
|
@ -27,7 +29,6 @@ struct quantize_stats_params {
|
||||||
std::vector<enum ggml_type> include_types;
|
std::vector<enum ggml_type> include_types;
|
||||||
};
|
};
|
||||||
|
|
||||||
const int64_t SCRATCH_ELEMENTS = 32*32;
|
|
||||||
const size_t HISTOGRAM_BUCKETS = 150;
|
const size_t HISTOGRAM_BUCKETS = 150;
|
||||||
const double HISTOGRAM_RANGE = 0.03;
|
const double HISTOGRAM_RANGE = 0.03;
|
||||||
|
|
||||||
|
@ -90,6 +91,13 @@ void update_error_stats(int64_t nelements, const float * input, const float * ou
|
||||||
stats.num_samples += nelements;
|
stats.num_samples += nelements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void combine_error_stats(error_stats & into, const error_stats & from) {
|
||||||
|
into.num_samples += from.num_samples;
|
||||||
|
into.total_error += from.total_error;
|
||||||
|
if (from.max_error > into.max_error) into.max_error = from.max_error;
|
||||||
|
for (size_t i=0; i<HISTOGRAM_BUCKETS; ++i) into.error_histogram[i] += from.error_histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
double find_quantile(const error_stats & stats, double quantile) {
|
double find_quantile(const error_stats & stats, double quantile) {
|
||||||
double sum = std::accumulate(std::begin(stats.error_histogram), std::end(stats.error_histogram), 0.0);
|
double sum = std::accumulate(std::begin(stats.error_histogram), std::end(stats.error_histogram), 0.0);
|
||||||
|
|
||||||
|
@ -130,6 +138,36 @@ static bool tensor_is_contiguous(const struct ggml_tensor * tensor) {
|
||||||
tensor->nb[3] == tensor->nb[2]*tensor->ne[2];
|
tensor->nb[3] == tensor->nb[2]*tensor->ne[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_roundtrip_on_chunk(
|
||||||
|
const ggml_tensor * layer,
|
||||||
|
int64_t offset,
|
||||||
|
int64_t chunk_size,
|
||||||
|
const quantize_fns_t & qfns,
|
||||||
|
bool use_reference,
|
||||||
|
float * input_scratch,
|
||||||
|
char * quantized_scratch,
|
||||||
|
float * output_scratch,
|
||||||
|
error_stats & stats) {
|
||||||
|
|
||||||
|
if (layer->type == GGML_TYPE_F16) {
|
||||||
|
for (int i = 0; i < chunk_size; i++) {
|
||||||
|
input_scratch[i] = ggml_get_f32_1d(layer, i + offset);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
input_scratch = ggml_get_data_f32(layer) + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_reference) {
|
||||||
|
qfns.quantize_row_q_reference(input_scratch, quantized_scratch, chunk_size);
|
||||||
|
} else {
|
||||||
|
qfns.quantize_row_q(input_scratch, quantized_scratch, chunk_size);
|
||||||
|
}
|
||||||
|
qfns.dequantize_row_q(quantized_scratch, output_scratch, chunk_size);
|
||||||
|
|
||||||
|
update_error_stats(chunk_size, input_scratch, output_scratch, stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Run quantization function for a single layer and update error stats
|
// Run quantization function for a single layer and update error stats
|
||||||
void test_roundtrip_on_layer(
|
void test_roundtrip_on_layer(
|
||||||
std::string & name,
|
std::string & name,
|
||||||
|
@ -137,40 +175,61 @@ void test_roundtrip_on_layer(
|
||||||
const quantize_fns_t & qfns,
|
const quantize_fns_t & qfns,
|
||||||
bool use_reference,
|
bool use_reference,
|
||||||
const ggml_tensor * layer,
|
const ggml_tensor * layer,
|
||||||
float * input_scratch,
|
std::vector<float> & input_scratch,
|
||||||
char *quantized_scratch,
|
std::vector<char> & quantized_scratch,
|
||||||
float * output_scratch,
|
std::vector<float> & output_scratch,
|
||||||
error_stats & total_error) {
|
error_stats & total_error,
|
||||||
|
int max_thread = 0) {
|
||||||
|
|
||||||
assert(tensor_is_contiguous(layer));
|
assert(tensor_is_contiguous(layer));
|
||||||
error_stats layer_error {};
|
error_stats layer_error {};
|
||||||
int64_t nelements = ggml_nelements(layer);
|
uint64_t nelements = ggml_nelements(layer);
|
||||||
|
|
||||||
for (int64_t offset = 0; offset < nelements; offset += SCRATCH_ELEMENTS) {
|
float* input_scratch_ptr = nullptr;
|
||||||
int64_t chunk_size = std::min(SCRATCH_ELEMENTS, nelements - offset);
|
if (layer->type == GGML_TYPE_F16) {
|
||||||
|
if (input_scratch.size() < nelements) input_scratch.resize(nelements);
|
||||||
if (layer->type == GGML_TYPE_F16) {
|
input_scratch_ptr = input_scratch.data();
|
||||||
for (int i = 0; i < chunk_size; i++) {
|
|
||||||
input_scratch[i] = ggml_get_f32_1d(layer, i + offset);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
input_scratch = ggml_get_data_f32(layer) + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (use_reference) {
|
|
||||||
qfns.quantize_row_q_reference(input_scratch, quantized_scratch, chunk_size);
|
|
||||||
} else {
|
|
||||||
qfns.quantize_row_q(input_scratch, quantized_scratch, chunk_size);
|
|
||||||
}
|
|
||||||
qfns.dequantize_row_q(quantized_scratch, output_scratch, chunk_size);
|
|
||||||
|
|
||||||
update_error_stats(chunk_size, input_scratch, output_scratch, total_error);
|
|
||||||
if (print_layer_stats) {
|
|
||||||
update_error_stats(chunk_size, input_scratch, output_scratch, layer_error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (quantized_scratch.size() < 4*nelements) quantized_scratch.resize(4*nelements);
|
||||||
|
if (output_scratch.size() < nelements) output_scratch.resize(nelements);
|
||||||
|
|
||||||
|
if (max_thread < 1) max_thread = std::thread::hardware_concurrency();
|
||||||
|
int chunk_size = 32*512;
|
||||||
|
int num_chunks = (nelements + chunk_size - 1)/chunk_size;
|
||||||
|
|
||||||
|
if (num_chunks < 2 || max_thread < 2) {
|
||||||
|
test_roundtrip_on_chunk(layer, 0, nelements, qfns, use_reference, input_scratch_ptr, quantized_scratch.data(),
|
||||||
|
output_scratch.data(), print_layer_stats ? layer_error : total_error);
|
||||||
|
} else {
|
||||||
|
auto & stats = print_layer_stats ? layer_error : total_error;
|
||||||
|
std::mutex mutex;
|
||||||
|
uint64_t counter = 0;
|
||||||
|
auto compute = [&mutex, &counter, &stats, &qfns, nelements, layer, use_reference, input_scratch_ptr,
|
||||||
|
&quantized_scratch, &output_scratch, chunk_size] () {
|
||||||
|
error_stats local_stats {};
|
||||||
|
while (true) {
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
uint64_t offset = counter; counter += chunk_size;
|
||||||
|
if (offset >= nelements) {
|
||||||
|
combine_error_stats(stats, local_stats);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lock.unlock();
|
||||||
|
uint64_t chunk = offset + chunk_size < nelements ? chunk_size : nelements - offset;
|
||||||
|
test_roundtrip_on_chunk(layer, offset, chunk, qfns, use_reference, input_scratch_ptr + offset,
|
||||||
|
quantized_scratch.data() + 4*offset, output_scratch.data() + offset, local_stats);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
int nthread = std::min(num_chunks, max_thread);
|
||||||
|
std::vector<std::thread> workers(nthread-1);
|
||||||
|
for (auto& w : workers) w = std::thread(compute);
|
||||||
|
compute();
|
||||||
|
for (auto& w : workers) w.join();
|
||||||
|
}
|
||||||
|
|
||||||
if (print_layer_stats) {
|
if (print_layer_stats) {
|
||||||
print_error_stats(name, layer_error, false);
|
print_error_stats(name, layer_error, false);
|
||||||
|
combine_error_stats(total_error, layer_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,6 +240,7 @@ int main(int argc, char ** argv) {
|
||||||
|
|
||||||
// read command line
|
// read command line
|
||||||
|
|
||||||
|
int max_thread = 0;
|
||||||
bool invalid_param = false;
|
bool invalid_param = false;
|
||||||
std::string arg;
|
std::string arg;
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
|
@ -230,6 +290,12 @@ int main(int argc, char ** argv) {
|
||||||
fprintf(stderr, "error: %s not in list of types\n", argv[i]);
|
fprintf(stderr, "error: %s not in list of types\n", argv[i]);
|
||||||
invalid_param = true;
|
invalid_param = true;
|
||||||
}
|
}
|
||||||
|
} else if (arg == "-n" || arg == "--num-threads") {
|
||||||
|
if (++i >= argc) {
|
||||||
|
invalid_param = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
max_thread = atoi(argv[i]);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "error: unknown argument: %s\n", arg.c_str());
|
fprintf(stderr, "error: unknown argument: %s\n", arg.c_str());
|
||||||
quantize_stats_print_usage(argc, argv);
|
quantize_stats_print_usage(argc, argv);
|
||||||
|
@ -295,9 +361,9 @@ int main(int argc, char ** argv) {
|
||||||
}
|
}
|
||||||
printf("testing %d layers with max size %" PRId64 "\n", included_layers, max_nelements);
|
printf("testing %d layers with max size %" PRId64 "\n", included_layers, max_nelements);
|
||||||
// allocate scratch space
|
// allocate scratch space
|
||||||
std::vector<float> input_scratch(SCRATCH_ELEMENTS);
|
std::vector<float> input_scratch;
|
||||||
std::vector<char> quantized_scratch(SCRATCH_ELEMENTS*4);
|
std::vector<char> quantized_scratch;
|
||||||
std::vector<float> output_scratch(SCRATCH_ELEMENTS);
|
std::vector<float> output_scratch;
|
||||||
|
|
||||||
// loop throught quantization types
|
// loop throught quantization types
|
||||||
for (int i = 0; i < GGML_TYPE_COUNT; i++) {
|
for (int i = 0; i < GGML_TYPE_COUNT; i++) {
|
||||||
|
@ -328,10 +394,11 @@ int main(int argc, char ** argv) {
|
||||||
qfns,
|
qfns,
|
||||||
params.reference,
|
params.reference,
|
||||||
kv_tensor.second,
|
kv_tensor.second,
|
||||||
input_scratch.data(),
|
input_scratch,
|
||||||
quantized_scratch.data(),
|
quantized_scratch,
|
||||||
output_scratch.data(),
|
output_scratch,
|
||||||
global_stats
|
global_stats,
|
||||||
|
max_thread
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,12 @@
|
||||||
int main(int argc, char ** argv) {
|
int main(int argc, char ** argv) {
|
||||||
ggml_time_init();
|
ggml_time_init();
|
||||||
|
|
||||||
if (argc != 4) {
|
if (argc < 4) {
|
||||||
fprintf(stderr, "usage: %s model-f32.bin model-quant.bin type\n", argv[0]);
|
fprintf(stderr, "usage: %s model-f32.bin model-quant.bin type [nthread]\n", argv[0]);
|
||||||
fprintf(stderr, " type = %d - q4_0\n", LLAMA_FTYPE_MOSTLY_Q4_0);
|
fprintf(stderr, " type = %d - q4_0\n", LLAMA_FTYPE_MOSTLY_Q4_0);
|
||||||
fprintf(stderr, " type = %d - q4_1\n", LLAMA_FTYPE_MOSTLY_Q4_1);
|
fprintf(stderr, " type = %d - q4_1\n", LLAMA_FTYPE_MOSTLY_Q4_1);
|
||||||
fprintf(stderr, " type = %d - q4_2\n", LLAMA_FTYPE_MOSTLY_Q4_2);
|
fprintf(stderr, " type = %d - q4_2\n", LLAMA_FTYPE_MOSTLY_Q4_2);
|
||||||
|
fprintf(stderr, " type = %d - q4_3\n", LLAMA_FTYPE_MOSTLY_Q4_3);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ int main(int argc, char ** argv) {
|
||||||
const std::string fname_out = argv[2];
|
const std::string fname_out = argv[2];
|
||||||
|
|
||||||
const enum llama_ftype ftype = (enum llama_ftype)atoi(argv[3]);
|
const enum llama_ftype ftype = (enum llama_ftype)atoi(argv[3]);
|
||||||
|
int nthread = argc > 4 ? atoi(argv[4]) : 0;
|
||||||
|
|
||||||
const int64_t t_main_start_us = ggml_time_us();
|
const int64_t t_main_start_us = ggml_time_us();
|
||||||
|
|
||||||
|
@ -38,7 +40,7 @@ int main(int argc, char ** argv) {
|
||||||
{
|
{
|
||||||
const int64_t t_start_us = ggml_time_us();
|
const int64_t t_start_us = ggml_time_us();
|
||||||
|
|
||||||
if (llama_model_quantize(fname_inp.c_str(), fname_out.c_str(), ftype)) {
|
if (llama_model_quantize(fname_inp.c_str(), fname_out.c_str(), ftype, nthread)) {
|
||||||
fprintf(stderr, "%s: failed to quantize model from '%s'\n", __func__, fname_inp.c_str());
|
fprintf(stderr, "%s: failed to quantize model from '%s'\n", __func__, fname_inp.c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
138
ggml-cuda.cu
138
ggml-cuda.cu
|
@ -1,5 +1,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <cuda_fp16.h>
|
#include <cuda_fp16.h>
|
||||||
|
#include <atomic>
|
||||||
#include "ggml-cuda.h"
|
#include "ggml-cuda.h"
|
||||||
|
|
||||||
typedef uint16_t ggml_fp16_t;
|
typedef uint16_t ggml_fp16_t;
|
||||||
|
@ -22,11 +24,18 @@ static_assert(sizeof(block_q4_1) == sizeof(float) * 2 + QK4_1 / 2, "wrong q4_1 b
|
||||||
|
|
||||||
#define QK4_2 16
|
#define QK4_2 16
|
||||||
typedef struct {
|
typedef struct {
|
||||||
__half d; // delta
|
__half d; // delta
|
||||||
uint8_t qs[QK4_2 / 2]; // nibbles / quants
|
uint8_t qs[QK4_2 / 2]; // nibbles / quants
|
||||||
} block_q4_2;
|
} block_q4_2;
|
||||||
static_assert(sizeof(block_q4_2) == sizeof(ggml_fp16_t) + QK4_2 / 2, "wrong q4_2 block size/padding");
|
static_assert(sizeof(block_q4_2) == sizeof(ggml_fp16_t) + QK4_2 / 2, "wrong q4_2 block size/padding");
|
||||||
|
|
||||||
|
#define QK4_3 16
|
||||||
|
typedef struct {
|
||||||
|
__half d; // delta
|
||||||
|
__half m; // min
|
||||||
|
uint8_t qs[QK4_3 / 2]; // nibbles / quants
|
||||||
|
} block_q4_3;
|
||||||
|
static_assert(sizeof(block_q4_3) == 2 * sizeof(ggml_fp16_t) + QK4_3 / 2, "wrong q4_3 block size/padding");
|
||||||
|
|
||||||
static __global__ void dequantize_block_q4_0(const void * vx, float * y) {
|
static __global__ void dequantize_block_q4_0(const void * vx, float * y) {
|
||||||
const block_q4_0 * x = (const block_q4_0 *) vx;
|
const block_q4_0 * x = (const block_q4_0 *) vx;
|
||||||
|
@ -98,19 +107,122 @@ static __global__ void dequantize_block_q4_2(const void * vx, float * y) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
static __global__ void dequantize_block_q4_3(const void * vx, float * y) {
|
||||||
__host__ void dequantize_row_q4_0_cuda(const void * vx, float * y, int k, cudaStream_t stream) {
|
const block_q4_3 * x = (const block_q4_3 *) vx;
|
||||||
const int nb = k / QK4_0;
|
|
||||||
dequantize_block_q4_0<<<nb, 1, 0, stream>>>(vx, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
__host__ void dequantize_row_q4_1_cuda(const void * vx, float * y, int k, cudaStream_t stream) {
|
const int i = blockIdx.x;
|
||||||
const int nb = k / QK4_1;
|
|
||||||
dequantize_block_q4_1<<<nb, 1, 0, stream>>>(vx, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
__host__ void dequantize_row_q4_2_cuda(const void * vx, float * y, int k, cudaStream_t stream) {
|
const float d = x[i].d;
|
||||||
const int nb = k / QK4_2;
|
const float m = x[i].m;
|
||||||
dequantize_block_q4_2<<<nb, 1, 0, stream>>>(vx, y);
|
|
||||||
|
const uint8_t * pp = x[i].qs;
|
||||||
|
|
||||||
|
for (int l = 0; l < QK4_3; l += 2) {
|
||||||
|
const uint8_t vi = pp[l/2];
|
||||||
|
|
||||||
|
const int8_t vi0 = vi & 0xf;
|
||||||
|
const int8_t vi1 = vi >> 4;
|
||||||
|
|
||||||
|
const float v0 = vi0*d + m;
|
||||||
|
const float v1 = vi1*d + m;
|
||||||
|
|
||||||
|
y[i*QK4_3 + l + 0] = v0;
|
||||||
|
y[i*QK4_3 + l + 1] = v1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dequantize_row_q4_0_cuda(const void * vx, float * y, int k, cudaStream_t stream) {
|
||||||
|
const int nb = k / QK4_0;
|
||||||
|
dequantize_block_q4_0<<<nb, 1, 0, stream>>>(vx, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dequantize_row_q4_1_cuda(const void * vx, float * y, int k, cudaStream_t stream) {
|
||||||
|
const int nb = k / QK4_1;
|
||||||
|
dequantize_block_q4_1<<<nb, 1, 0, stream>>>(vx, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dequantize_row_q4_2_cuda(const void * vx, float * y, int k, cudaStream_t stream) {
|
||||||
|
const int nb = k / QK4_2;
|
||||||
|
dequantize_block_q4_2<<<nb, 1, 0, stream>>>(vx, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dequantize_row_q4_3_cuda(const void * vx, float * y, int k, cudaStream_t stream) {
|
||||||
|
const int nb = k / QK4_3;
|
||||||
|
dequantize_block_q4_3<<<nb, 1, 0, stream>>>(vx, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffer pool for cuda
|
||||||
|
#define MAX_CUDA_BUFFERS 16
|
||||||
|
|
||||||
|
struct scoped_spin_lock {
|
||||||
|
std::atomic_flag& lock;
|
||||||
|
scoped_spin_lock(std::atomic_flag& lock) : lock(lock) {
|
||||||
|
while (lock.test_and_set(std::memory_order_acquire)) {
|
||||||
|
; // spin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~scoped_spin_lock() {
|
||||||
|
lock.clear(std::memory_order_release);
|
||||||
|
}
|
||||||
|
scoped_spin_lock(const scoped_spin_lock&) = delete;
|
||||||
|
scoped_spin_lock& operator=(const scoped_spin_lock&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cuda_buffer {
|
||||||
|
void * ptr = nullptr;
|
||||||
|
size_t size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static cuda_buffer g_cuda_buffer_pool[MAX_CUDA_BUFFERS];
|
||||||
|
static std::atomic_flag g_cuda_pool_lock = ATOMIC_FLAG_INIT;
|
||||||
|
|
||||||
|
void * ggml_cuda_pool_malloc(size_t size, size_t * actual_size) {
|
||||||
|
scoped_spin_lock lock(g_cuda_pool_lock);
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_CUDA_BUFFERS; ++i) {
|
||||||
|
cuda_buffer& b = g_cuda_buffer_pool[i];
|
||||||
|
if (b.size >= size && b.ptr != nullptr) {
|
||||||
|
void * ptr = b.ptr;
|
||||||
|
*actual_size = b.size;
|
||||||
|
b.ptr = nullptr;
|
||||||
|
b.size = 0;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void * ptr;
|
||||||
|
CUDA_CHECK(cudaMalloc((void **) &ptr, size));
|
||||||
|
*actual_size = size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ggml_cuda_pool_free(void * ptr, size_t size) {
|
||||||
|
scoped_spin_lock lock(g_cuda_pool_lock);
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_CUDA_BUFFERS; ++i) {
|
||||||
|
cuda_buffer& b = g_cuda_buffer_pool[i];
|
||||||
|
if (b.ptr == nullptr) {
|
||||||
|
b.ptr = ptr;
|
||||||
|
b.size = size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "WARNING: cuda buffer pool full, increase MAX_CUDA_BUFFERS\n");
|
||||||
|
CUDA_CHECK(cudaFree(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
cublasHandle_t g_cublasH = NULL;
|
||||||
|
cudaStream_t g_cudaStream = NULL;
|
||||||
|
|
||||||
|
void ggml_init_cublas(void) {
|
||||||
|
if (g_cublasH == NULL) {
|
||||||
|
// create cublas handle, bind a stream
|
||||||
|
CUBLAS_CHECK(cublasCreate(&g_cublasH));
|
||||||
|
|
||||||
|
CUDA_CHECK(cudaStreamCreateWithFlags(&g_cudaStream, cudaStreamNonBlocking));
|
||||||
|
|
||||||
|
CUBLAS_CHECK(cublasSetStream(g_cublasH, g_cudaStream));
|
||||||
|
|
||||||
|
// configure logging to stdout
|
||||||
|
// CUBLAS_CHECK(cublasLoggerConfigure(1, 1, 0, NULL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
30
ggml-cuda.h
30
ggml-cuda.h
|
@ -1,10 +1,40 @@
|
||||||
|
#include <cublas_v2.h>
|
||||||
|
#include <cuda_runtime.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define CUDA_CHECK(err) \
|
||||||
|
do { \
|
||||||
|
cudaError_t err_ = (err); \
|
||||||
|
if (err_ != cudaSuccess) { \
|
||||||
|
fprintf(stderr, "CUDA error %d at %s:%d: %s\n", err_, __FILE__, __LINE__, \
|
||||||
|
cudaGetErrorString(err_)); \
|
||||||
|
exit(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CUBLAS_CHECK(err) \
|
||||||
|
do { \
|
||||||
|
cublasStatus_t err_ = (err); \
|
||||||
|
if (err_ != CUBLAS_STATUS_SUCCESS) { \
|
||||||
|
fprintf(stderr, "cuBLAS error %d at %s:%d\n", err_, __FILE__, __LINE__); \
|
||||||
|
exit(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
extern cublasHandle_t g_cublasH;
|
||||||
|
extern cudaStream_t g_cudaStream;
|
||||||
|
|
||||||
|
void ggml_init_cublas(void);
|
||||||
|
void * ggml_cuda_pool_malloc(size_t size, size_t * actual_size);
|
||||||
|
void ggml_cuda_pool_free(void * ptr, size_t size);
|
||||||
|
|
||||||
void dequantize_row_q4_0_cuda(const void * vx, float * y, int k, cudaStream_t stream);
|
void dequantize_row_q4_0_cuda(const void * vx, float * y, int k, cudaStream_t stream);
|
||||||
void dequantize_row_q4_1_cuda(const void * vx, float * y, int k, cudaStream_t stream);
|
void dequantize_row_q4_1_cuda(const void * vx, float * y, int k, cudaStream_t stream);
|
||||||
void dequantize_row_q4_2_cuda(const void * vx, float * y, int k, cudaStream_t stream);
|
void dequantize_row_q4_2_cuda(const void * vx, float * y, int k, cudaStream_t stream);
|
||||||
|
void dequantize_row_q4_3_cuda(const void * vx, float * y, int k, cudaStream_t stream);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
11
ggml.h
11
ggml.h
|
@ -205,7 +205,8 @@ enum ggml_type {
|
||||||
GGML_TYPE_Q4_0 = 2,
|
GGML_TYPE_Q4_0 = 2,
|
||||||
GGML_TYPE_Q4_1 = 3,
|
GGML_TYPE_Q4_1 = 3,
|
||||||
GGML_TYPE_Q4_2 = 4,
|
GGML_TYPE_Q4_2 = 4,
|
||||||
GGML_TYPE_Q8_0 = 5,
|
GGML_TYPE_Q4_3 = 5,
|
||||||
|
GGML_TYPE_Q8_0 = 6,
|
||||||
GGML_TYPE_I8,
|
GGML_TYPE_I8,
|
||||||
GGML_TYPE_I16,
|
GGML_TYPE_I16,
|
||||||
GGML_TYPE_I32,
|
GGML_TYPE_I32,
|
||||||
|
@ -360,6 +361,8 @@ const char * ggml_type_name(enum ggml_type type);
|
||||||
|
|
||||||
size_t ggml_element_size(const struct ggml_tensor * tensor);
|
size_t ggml_element_size(const struct ggml_tensor * tensor);
|
||||||
|
|
||||||
|
bool ggml_is_quantized(enum ggml_type type);
|
||||||
|
|
||||||
struct ggml_context * ggml_init(struct ggml_init_params params);
|
struct ggml_context * ggml_init(struct ggml_init_params params);
|
||||||
void ggml_free(struct ggml_context * ctx);
|
void ggml_free(struct ggml_context * ctx);
|
||||||
|
|
||||||
|
@ -627,7 +630,8 @@ struct ggml_tensor * ggml_soft_max(
|
||||||
|
|
||||||
// rotary position embedding
|
// rotary position embedding
|
||||||
// in-place, returns view(a)
|
// in-place, returns view(a)
|
||||||
// if mode == 1, skip n_past elements
|
// if mode & 1 == 1, skip n_past elements
|
||||||
|
// if mode & 2 == 1, GPT-NeoX style
|
||||||
// TODO: avoid creating a new tensor every time
|
// TODO: avoid creating a new tensor every time
|
||||||
struct ggml_tensor * ggml_rope(
|
struct ggml_tensor * ggml_rope(
|
||||||
struct ggml_context * ctx,
|
struct ggml_context * ctx,
|
||||||
|
@ -808,6 +812,9 @@ enum ggml_opt_result ggml_opt(
|
||||||
size_t ggml_quantize_q4_0(const float * src, void * dst, int n, int k, int64_t * hist);
|
size_t ggml_quantize_q4_0(const float * src, void * dst, int n, int k, int64_t * hist);
|
||||||
size_t ggml_quantize_q4_1(const float * src, void * dst, int n, int k, int64_t * hist);
|
size_t ggml_quantize_q4_1(const float * src, void * dst, int n, int k, int64_t * hist);
|
||||||
size_t ggml_quantize_q4_2(const float * src, void * dst, int n, int k, int64_t * hist);
|
size_t ggml_quantize_q4_2(const float * src, void * dst, int n, int k, int64_t * hist);
|
||||||
|
size_t ggml_quantize_q4_3(const float * src, void * dst, int n, int k, int64_t * hist);
|
||||||
|
|
||||||
|
size_t ggml_quantize_chunk(enum ggml_type type, const float * src, void * dst, int start, int n, int64_t * hist);
|
||||||
|
|
||||||
//
|
//
|
||||||
// system info
|
// system info
|
||||||
|
|
78
llama.cpp
78
llama.cpp
|
@ -24,6 +24,9 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#define LLAMA_USE_SCRATCH
|
#define LLAMA_USE_SCRATCH
|
||||||
#define LLAMA_MAX_SCRATCH_BUFFERS 16
|
#define LLAMA_MAX_SCRATCH_BUFFERS 16
|
||||||
|
@ -479,6 +482,7 @@ struct llama_file_loader {
|
||||||
case GGML_TYPE_Q4_0:
|
case GGML_TYPE_Q4_0:
|
||||||
case GGML_TYPE_Q4_1:
|
case GGML_TYPE_Q4_1:
|
||||||
case GGML_TYPE_Q4_2:
|
case GGML_TYPE_Q4_2:
|
||||||
|
case GGML_TYPE_Q4_3:
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
throw format("unrecognized tensor type %u\n", shard.type);
|
throw format("unrecognized tensor type %u\n", shard.type);
|
||||||
|
@ -552,6 +556,7 @@ struct llama_file_saver {
|
||||||
case GGML_TYPE_Q4_0:
|
case GGML_TYPE_Q4_0:
|
||||||
case GGML_TYPE_Q4_1:
|
case GGML_TYPE_Q4_1:
|
||||||
case GGML_TYPE_Q4_2:
|
case GGML_TYPE_Q4_2:
|
||||||
|
case GGML_TYPE_Q4_3:
|
||||||
break;
|
break;
|
||||||
default: LLAMA_ASSERT(false);
|
default: LLAMA_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
@ -841,6 +846,7 @@ static const char *llama_ftype_name(enum llama_ftype ftype) {
|
||||||
case LLAMA_FTYPE_MOSTLY_Q4_1_SOME_F16:
|
case LLAMA_FTYPE_MOSTLY_Q4_1_SOME_F16:
|
||||||
return "mostly Q4_1, some F16";
|
return "mostly Q4_1, some F16";
|
||||||
case LLAMA_FTYPE_MOSTLY_Q4_2: return "mostly Q4_2";
|
case LLAMA_FTYPE_MOSTLY_Q4_2: return "mostly Q4_2";
|
||||||
|
case LLAMA_FTYPE_MOSTLY_Q4_3: return "mostly Q4_3";
|
||||||
default: return "unknown, may not work";
|
default: return "unknown, may not work";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1571,15 +1577,20 @@ static llama_vocab::id llama_sample_top_p_top_k(
|
||||||
// quantization
|
// quantization
|
||||||
//
|
//
|
||||||
|
|
||||||
static void llama_model_quantize_internal(const std::string & fname_inp, const std::string & fname_out, enum llama_ftype ftype) {
|
static void llama_model_quantize_internal(const std::string & fname_inp, const std::string & fname_out, enum llama_ftype ftype, int nthread) {
|
||||||
ggml_type quantized_type;
|
ggml_type quantized_type;
|
||||||
switch (ftype) {
|
switch (ftype) {
|
||||||
case LLAMA_FTYPE_MOSTLY_Q4_0: quantized_type = GGML_TYPE_Q4_0; break;
|
case LLAMA_FTYPE_MOSTLY_Q4_0: quantized_type = GGML_TYPE_Q4_0; break;
|
||||||
case LLAMA_FTYPE_MOSTLY_Q4_1: quantized_type = GGML_TYPE_Q4_1; break;
|
case LLAMA_FTYPE_MOSTLY_Q4_1: quantized_type = GGML_TYPE_Q4_1; break;
|
||||||
case LLAMA_FTYPE_MOSTLY_Q4_2: quantized_type = GGML_TYPE_Q4_2; break;
|
case LLAMA_FTYPE_MOSTLY_Q4_2: quantized_type = GGML_TYPE_Q4_2; break;
|
||||||
|
case LLAMA_FTYPE_MOSTLY_Q4_3: quantized_type = GGML_TYPE_Q4_3; break;
|
||||||
default: throw format("invalid output file type %d\n", ftype);
|
default: throw format("invalid output file type %d\n", ftype);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (nthread <= 0) {
|
||||||
|
nthread = std::thread::hardware_concurrency();
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<llama_model_loader> model_loader(new llama_model_loader(fname_inp.c_str(), /*use_mmap*/ false,
|
std::unique_ptr<llama_model_loader> model_loader(new llama_model_loader(fname_inp.c_str(), /*use_mmap*/ false,
|
||||||
/*vocab_only*/ false));
|
/*vocab_only*/ false));
|
||||||
llama_file_saver file_saver(fname_out.c_str(), model_loader->file_loaders.at(0).get(), ftype);
|
llama_file_saver file_saver(fname_out.c_str(), model_loader->file_loaders.at(0).get(), ftype);
|
||||||
|
@ -1588,6 +1599,9 @@ static void llama_model_quantize_internal(const std::string & fname_inp, const s
|
||||||
size_t total_size_new = 0;
|
size_t total_size_new = 0;
|
||||||
std::vector<int64_t> hist_all(1 << 4, 0);
|
std::vector<int64_t> hist_all(1 << 4, 0);
|
||||||
|
|
||||||
|
std::vector<std::thread> workers;
|
||||||
|
std::mutex mutex;
|
||||||
|
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
for (llama_load_tensor & tensor : model_loader->tensors_map.tensors) {
|
for (llama_load_tensor & tensor : model_loader->tensors_map.tensors) {
|
||||||
llama_buffer read_data;
|
llama_buffer read_data;
|
||||||
|
@ -1606,6 +1620,11 @@ static void llama_model_quantize_internal(const std::string & fname_inp, const s
|
||||||
// quantize only 2D tensors
|
// quantize only 2D tensors
|
||||||
quantize &= (tensor.ne.size() == 2);
|
quantize &= (tensor.ne.size() == 2);
|
||||||
|
|
||||||
|
// uncomment this to keep the output layer in FP16
|
||||||
|
//if (tensor.name == "output.weight") {
|
||||||
|
// quantize = false;
|
||||||
|
//}
|
||||||
|
|
||||||
enum ggml_type new_type;
|
enum ggml_type new_type;
|
||||||
void * new_data;
|
void * new_data;
|
||||||
size_t new_size;
|
size_t new_size;
|
||||||
|
@ -1641,21 +1660,37 @@ static void llama_model_quantize_internal(const std::string & fname_inp, const s
|
||||||
new_data = work.addr;
|
new_data = work.addr;
|
||||||
std::vector<int64_t> hist_cur(1 << 4, 0);
|
std::vector<int64_t> hist_cur(1 << 4, 0);
|
||||||
|
|
||||||
switch (new_type) {
|
int chunk_size = 32 * 512;
|
||||||
case GGML_TYPE_Q4_0:
|
const int nchunk = (nelements + chunk_size - 1)/chunk_size;
|
||||||
{
|
const int nthread_use = nthread > 1 ? std::max(1, std::min(nthread, nchunk)) : 1;
|
||||||
new_size = ggml_quantize_q4_0(f32_data, new_data, nelements, (int) tensor.ne.at(0), hist_cur.data());
|
if (nthread_use < 2) {
|
||||||
} break;
|
new_size = ggml_quantize_chunk(new_type, f32_data, new_data, 0, nelements, hist_cur.data());
|
||||||
case GGML_TYPE_Q4_1:
|
} else {
|
||||||
{
|
size_t counter = 0;
|
||||||
new_size = ggml_quantize_q4_1(f32_data, new_data, nelements, (int) tensor.ne.at(0), hist_cur.data());
|
new_size = 0;
|
||||||
} break;
|
auto compute = [&mutex, &counter, &hist_cur, &new_size, new_type, f32_data, new_data, nelements, chunk_size] () {
|
||||||
case GGML_TYPE_Q4_2:
|
std::vector<int64_t> local_hist;
|
||||||
{
|
size_t local_size = 0;
|
||||||
new_size = ggml_quantize_q4_2(f32_data, new_data, nelements, (int) tensor.ne.at(0), hist_cur.data());
|
while (true) {
|
||||||
} break;
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
default:
|
size_t first = counter; counter += chunk_size;
|
||||||
LLAMA_ASSERT(false);
|
if (first >= nelements) {
|
||||||
|
if (!local_hist.empty()) {
|
||||||
|
for (int j=0; j<int(local_hist.size()); ++j) hist_cur[j] += local_hist[j];
|
||||||
|
new_size += local_size;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lock.unlock();
|
||||||
|
size_t last = std::min(nelements, first + chunk_size);
|
||||||
|
if (local_hist.empty()) local_hist.resize(hist_cur.size(), 0);
|
||||||
|
local_size += ggml_quantize_chunk(new_type, f32_data, new_data, first, last - first, local_hist.data());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (int(workers.size()) < nthread_use - 1) workers.resize(nthread_use - 1);
|
||||||
|
for (int it = 0; it < nthread_use - 1; ++it) workers[it] = std::thread(compute);
|
||||||
|
compute();
|
||||||
|
for (int it = 0; it < nthread_use - 1; ++it) workers[it].join();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("size = %8.2f MB -> %8.2f MB | hist: ", tensor.size/1024.0/1024.0, new_size/1024.0/1024.0);
|
printf("size = %8.2f MB -> %8.2f MB | hist: ", tensor.size/1024.0/1024.0, new_size/1024.0/1024.0);
|
||||||
|
@ -1777,9 +1812,10 @@ void llama_free(struct llama_context * ctx) {
|
||||||
int llama_model_quantize(
|
int llama_model_quantize(
|
||||||
const char * fname_inp,
|
const char * fname_inp,
|
||||||
const char * fname_out,
|
const char * fname_out,
|
||||||
enum llama_ftype ftype) {
|
enum llama_ftype ftype,
|
||||||
|
int nthread) {
|
||||||
try {
|
try {
|
||||||
llama_model_quantize_internal(fname_inp, fname_out, ftype);
|
llama_model_quantize_internal(fname_inp, fname_out, ftype, nthread);
|
||||||
return 0;
|
return 0;
|
||||||
} catch (const std::string & err) {
|
} catch (const std::string & err) {
|
||||||
fprintf(stderr, "%s: failed to quantize: %s\n", __func__, err.c_str());
|
fprintf(stderr, "%s: failed to quantize: %s\n", __func__, err.c_str());
|
||||||
|
@ -1965,7 +2001,7 @@ int llama_apply_lora_from_file_internal(struct llama_context * ctx, const char *
|
||||||
base_t = dest_t;
|
base_t = dest_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base_t->type == GGML_TYPE_Q4_0 || base_t->type == GGML_TYPE_Q4_1 || base_t->type == GGML_TYPE_Q4_2) {
|
if (ggml_is_quantized(base_t->type)) {
|
||||||
if (!warned) {
|
if (!warned) {
|
||||||
fprintf(stderr, "%s: warning: using a lora adapter with a quantized model may result in poor quality, "
|
fprintf(stderr, "%s: warning: using a lora adapter with a quantized model may result in poor quality, "
|
||||||
"use a f16 or f32 base model with --lora-base\n", __func__);
|
"use a f16 or f32 base model with --lora-base\n", __func__);
|
||||||
|
@ -2058,7 +2094,11 @@ void llama_set_kv_cache(
|
||||||
int n_token_count) {
|
int n_token_count) {
|
||||||
// Make sure we have the same kv cache setup
|
// Make sure we have the same kv cache setup
|
||||||
LLAMA_ASSERT(ctx->model.kv_self.buf.size == n_size);
|
LLAMA_ASSERT(ctx->model.kv_self.buf.size == n_size);
|
||||||
|
void * k_data = ctx->model.kv_self.k->data; // remember data pointers
|
||||||
|
void * v_data = ctx->model.kv_self.v->data; // because their value is stored in buf and overwritten by memcpy
|
||||||
memcpy(ctx->model.kv_self.buf.addr, kv_cache, n_size);
|
memcpy(ctx->model.kv_self.buf.addr, kv_cache, n_size);
|
||||||
|
ctx->model.kv_self.k->data = k_data; // restore correct data pointers
|
||||||
|
ctx->model.kv_self.v->data = v_data;
|
||||||
ctx->model.kv_self.n = n_token_count;
|
ctx->model.kv_self.n = n_token_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
5
llama.h
5
llama.h
|
@ -73,6 +73,7 @@ extern "C" {
|
||||||
LLAMA_FTYPE_MOSTLY_Q4_1 = 3, // except 1d tensors
|
LLAMA_FTYPE_MOSTLY_Q4_1 = 3, // except 1d tensors
|
||||||
LLAMA_FTYPE_MOSTLY_Q4_1_SOME_F16 = 4, // tok_embeddings.weight and output.weight are F16
|
LLAMA_FTYPE_MOSTLY_Q4_1_SOME_F16 = 4, // tok_embeddings.weight and output.weight are F16
|
||||||
LLAMA_FTYPE_MOSTLY_Q4_2 = 5, // except 1d tensors
|
LLAMA_FTYPE_MOSTLY_Q4_2 = 5, // except 1d tensors
|
||||||
|
LLAMA_FTYPE_MOSTLY_Q4_3 = 6, // except 1d tensors
|
||||||
};
|
};
|
||||||
|
|
||||||
LLAMA_API struct llama_context_params llama_context_default_params();
|
LLAMA_API struct llama_context_params llama_context_default_params();
|
||||||
|
@ -92,10 +93,12 @@ extern "C" {
|
||||||
|
|
||||||
// TODO: not great API - very likely to change
|
// TODO: not great API - very likely to change
|
||||||
// Returns 0 on success
|
// Returns 0 on success
|
||||||
|
// nthread - how many threads to use. If <=0, will use std::thread::hardware_concurrency(), else the number given
|
||||||
LLAMA_API int llama_model_quantize(
|
LLAMA_API int llama_model_quantize(
|
||||||
const char * fname_inp,
|
const char * fname_inp,
|
||||||
const char * fname_out,
|
const char * fname_out,
|
||||||
enum llama_ftype ftype);
|
enum llama_ftype ftype,
|
||||||
|
int nthread);
|
||||||
|
|
||||||
// Apply a LoRA adapter to a loaded model
|
// Apply a LoRA adapter to a loaded model
|
||||||
// path_base_model is the path to a higher quality model to use as a base for
|
// path_base_model is the path to a higher quality model to use as a base for
|
||||||
|
|
17
llama_util.h
17
llama_util.h
|
@ -21,6 +21,9 @@
|
||||||
#if defined(_POSIX_MAPPED_FILES)
|
#if defined(_POSIX_MAPPED_FILES)
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(_POSIX_MEMLOCK_RANGE)
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -303,8 +306,18 @@ struct llama_mlock {
|
||||||
if (!mlock(addr, size)) {
|
if (!mlock(addr, size)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "warning: failed to mlock %zu-byte buffer (after previously locking %zu bytes): %s\n" MLOCK_SUGGESTION,
|
char* errmsg = std::strerror(errno);
|
||||||
size, this->size, std::strerror(errno));
|
bool suggest = (errno == ENOMEM);
|
||||||
|
|
||||||
|
// Check if the resource limit is fine after all
|
||||||
|
struct rlimit lock_limit;
|
||||||
|
if (suggest && getrlimit(RLIMIT_MEMLOCK, &lock_limit))
|
||||||
|
suggest = false;
|
||||||
|
if (suggest && (lock_limit.rlim_max > lock_limit.rlim_cur + size))
|
||||||
|
suggest = false;
|
||||||
|
|
||||||
|
fprintf(stderr, "warning: failed to mlock %zu-byte buffer (after previously locking %zu bytes): %s\n%s",
|
||||||
|
size, this->size, errmsg, suggest ? MLOCK_SUGGESTION : "");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,3 +2,8 @@ set(TARGET vdot)
|
||||||
add_executable(${TARGET} vdot.cpp)
|
add_executable(${TARGET} vdot.cpp)
|
||||||
target_link_libraries(${TARGET} PRIVATE common llama ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(${TARGET} PRIVATE common llama ${CMAKE_THREAD_LIBS_INIT})
|
||||||
target_compile_features(${TARGET} PRIVATE cxx_std_11)
|
target_compile_features(${TARGET} PRIVATE cxx_std_11)
|
||||||
|
|
||||||
|
set(TARGET q8dot)
|
||||||
|
add_executable(${TARGET} q8dot.cpp)
|
||||||
|
target_link_libraries(${TARGET} PRIVATE common llama ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
target_compile_features(${TARGET} PRIVATE cxx_std_11)
|
||||||
|
|
172
pocs/vdot/q8dot.cpp
Normal file
172
pocs/vdot/q8dot.cpp
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
#include <cstdio>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
#include <random>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <array>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <ggml.h>
|
||||||
|
|
||||||
|
constexpr int kVecSize = 1 << 16;
|
||||||
|
|
||||||
|
// Copy-pasted from ggml.c
|
||||||
|
#define QK4_0 32
|
||||||
|
typedef struct {
|
||||||
|
float d; // delta
|
||||||
|
uint8_t qs[QK4_0 / 2]; // nibbles / quants
|
||||||
|
} block_q4_0;
|
||||||
|
static_assert(sizeof(block_q4_0) == sizeof(float) + QK4_0 / 2, "wrong q4_0 block size/padding");
|
||||||
|
|
||||||
|
#define QK4_1 32
|
||||||
|
typedef struct {
|
||||||
|
float d; // delta
|
||||||
|
float m; // min
|
||||||
|
uint8_t qs[QK4_1 / 2]; // nibbles / quants
|
||||||
|
} block_q4_1;
|
||||||
|
static_assert(sizeof(block_q4_1) == sizeof(float) * 2 + QK4_1 / 2, "wrong q4_1 block size/padding");
|
||||||
|
|
||||||
|
// Copy-pasted from ggml.c
|
||||||
|
#define QK8_0 32
|
||||||
|
typedef struct {
|
||||||
|
float d; // delta
|
||||||
|
float s; // d * sum(qs[i])
|
||||||
|
int8_t qs[QK8_0]; // quants
|
||||||
|
} block_q8_0;
|
||||||
|
static_assert(sizeof(block_q8_0) == 2*sizeof(float) + QK8_0, "wrong q8_0 block size/padding");
|
||||||
|
|
||||||
|
static_assert(QK4_1 == QK8_0, "QK4_1 and QK8_0 must be the same");
|
||||||
|
static_assert(QK4_0 == QK8_0, "QK4_0 and QK8_0 must be the same");
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void fillQ4blocks(std::vector<T>& blocks, std::mt19937& rndm) {
|
||||||
|
for (auto& b : blocks) {
|
||||||
|
b.d = 1;
|
||||||
|
for (int i=0; i<QK4_1/2; ++i) {
|
||||||
|
uint8_t v1 = rndm() >> 28;
|
||||||
|
uint8_t v2 = rndm() >> 28;
|
||||||
|
b.qs[i] = v1 | (v2 << 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillQ80blocks(std::vector<block_q8_0>& blocks, std::mt19937& rndm) {
|
||||||
|
for (auto& b : blocks) {
|
||||||
|
b.d = 1;
|
||||||
|
int sum = 0;
|
||||||
|
for (int i=0; i<QK8_0; ++i) {
|
||||||
|
b.qs[i] = (rndm() >> 24) - 128;
|
||||||
|
sum += b.qs[i];
|
||||||
|
}
|
||||||
|
b.s = b.d * sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float simpleDot(const block_q4_0& x, const block_q8_0& y) {
|
||||||
|
int s1 = 0; //, s2 = 0;
|
||||||
|
for (int i=0; i<QK4_1/2; i+=2) {
|
||||||
|
int v1 = x.qs[i+0] & 0xf;
|
||||||
|
int v2 = x.qs[i+0] >> 4;
|
||||||
|
int v3 = x.qs[i+1] & 0xf;
|
||||||
|
int v4 = x.qs[i+1] >> 4;
|
||||||
|
int j = 2*i;
|
||||||
|
s1 += v1*y.qs[j] + v2*y.qs[j+1] + v3*y.qs[j+2] + v4*y.qs[j+3];
|
||||||
|
//s2 += y.qs[j] + y.qs[j+1] + y.qs[j+2] + y.qs[j+3];
|
||||||
|
}
|
||||||
|
return y.d * x.d * s1 - 8 * x.d * y.s;
|
||||||
|
//return y.d * x.d * (s1 - 8 * s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
float simpleDot(const block_q4_1& x, const block_q8_0& y) {
|
||||||
|
int s1 = 0; //, s2 = 0;
|
||||||
|
for (int i=0; i<QK4_1/2; i+=2) {
|
||||||
|
int v1 = x.qs[i+0] & 0xf;
|
||||||
|
int v2 = x.qs[i+0] >> 4;
|
||||||
|
int v3 = x.qs[i+1] & 0xf;
|
||||||
|
int v4 = x.qs[i+1] >> 4;
|
||||||
|
int j = 2*i;
|
||||||
|
s1 += v1*y.qs[j] + v2*y.qs[j+1] + v3*y.qs[j+2] + v4*y.qs[j+3];
|
||||||
|
//s2 += y.qs[j] + y.qs[j+1] + y.qs[j+2] + y.qs[j+3];
|
||||||
|
}
|
||||||
|
return y.d * x.d * s1 + y.s * x.m;
|
||||||
|
//return y.d * (x.d * s1 + x.m * s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Stat {
|
||||||
|
double sum = 0, sumt = 0, sumt2 = 0, maxt = 0;
|
||||||
|
int nloop = 0;
|
||||||
|
void addResult(double s, double t) {
|
||||||
|
sum += s;
|
||||||
|
sumt += t; sumt2 += t*t; maxt = std::max(maxt, t);
|
||||||
|
++nloop;
|
||||||
|
}
|
||||||
|
void reportResult(const char* title) const {
|
||||||
|
if (nloop < 1) {
|
||||||
|
printf("%s(%s): no result\n",__func__,title);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("============ %s\n",title);
|
||||||
|
printf("<dot> = %g\n",sum/nloop);
|
||||||
|
auto t = sumt/nloop, dt = sumt2/nloop - t*t;
|
||||||
|
if (dt > 0) dt = sqrt(dt);
|
||||||
|
printf("<time> = %g +/- %g us. Max. time = %g us.\n",t,dt,maxt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
|
int nloop = argc > 1 ? atoi(argv[1]) : 10;
|
||||||
|
int type = argc > 2 ? atoi(argv[2]) : 1;
|
||||||
|
|
||||||
|
std::mt19937 rndm(1234);
|
||||||
|
|
||||||
|
std::vector<block_q4_1> x41;
|
||||||
|
std::vector<block_q4_0> x40;
|
||||||
|
std::vector<block_q8_0> y(kVecSize);
|
||||||
|
if (type == 0) x40.resize(kVecSize);
|
||||||
|
else {
|
||||||
|
x41.resize(kVecSize);
|
||||||
|
for (auto& b : x41) b.m = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ggml_type = type == 0 ? GGML_TYPE_Q4_0 : GGML_TYPE_Q4_1;
|
||||||
|
|
||||||
|
auto funcs = ggml_internal_get_quantize_fn(ggml_type);
|
||||||
|
|
||||||
|
Stat simple, ggml;
|
||||||
|
|
||||||
|
for (int iloop=0; iloop<nloop; ++iloop) {
|
||||||
|
|
||||||
|
if (type == 0) fillQ4blocks(x40, rndm);
|
||||||
|
else fillQ4blocks(x41, rndm);
|
||||||
|
fillQ80blocks(y, rndm);
|
||||||
|
|
||||||
|
auto t1 = std::chrono::high_resolution_clock::now();
|
||||||
|
double s = 0;
|
||||||
|
if (type == 0) for (int i=0; i<kVecSize; ++i) s += simpleDot(x40[i], y[i]);
|
||||||
|
else for (int i=0; i<kVecSize; ++i) s += simpleDot(x41[i], y[i]);
|
||||||
|
auto t2 = std::chrono::high_resolution_clock::now();
|
||||||
|
auto t = 1e-3*std::chrono::duration_cast<std::chrono::nanoseconds>(t2-t1).count();
|
||||||
|
if (iloop > 3) simple.addResult(s, t);
|
||||||
|
|
||||||
|
t1 = std::chrono::high_resolution_clock::now();
|
||||||
|
float fs;
|
||||||
|
if (type == 0) funcs.vec_dot_q(kVecSize * QK4_1, &fs, x40.data(), y.data());
|
||||||
|
else funcs.vec_dot_q(kVecSize * QK4_1, &fs, x41.data(), y.data());
|
||||||
|
t2 = std::chrono::high_resolution_clock::now();
|
||||||
|
t = 1e-3*std::chrono::duration_cast<std::chrono::nanoseconds>(t2-t1).count();
|
||||||
|
if (iloop > 3) ggml.addResult(fs, t);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report the time (and the average of the dot products so the compiler does not come up with the idea
|
||||||
|
// of optimizing away the function calls after figuring that the result is not used).
|
||||||
|
simple.reportResult("Simple");
|
||||||
|
ggml.reportResult("ggml");
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue