Skip to content

Commit 5916dc8

Browse files
committed
Reduce llama-quantize BF16 memory residency
1 parent 70cc4e1 commit 5916dc8

1 file changed

Lines changed: 78 additions & 39 deletions

File tree

src/llama-quant.cpp

Lines changed: 78 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,9 @@ struct tensor_metadata {
209209
// dequantization
210210
//
211211

212-
static void llama_tensor_dequantize_impl(
212+
static void llama_tensor_dequantize_chunk_impl(
213213
ggml_tensor * tensor, std::vector<no_init<float>> & output, std::vector<std::thread> & workers,
214-
const size_t nelements, const int nthread
214+
const int64_t start, const size_t nelements, const int nthread
215215
) {
216216
if (output.size() < nelements) {
217217
output.resize(nelements);
@@ -228,19 +228,6 @@ static void llama_tensor_dequantize_impl(
228228
throw std::runtime_error(format("cannot dequantize/convert tensor type %s", ggml_type_name(tensor->type)));
229229
}
230230

231-
if (nthread < 2) {
232-
if (tensor->type == GGML_TYPE_F16) {
233-
ggml_fp16_to_fp32_row((ggml_fp16_t *)tensor->data, f32_output, nelements);
234-
} else if (tensor->type == GGML_TYPE_BF16) {
235-
ggml_bf16_to_fp32_row((ggml_bf16_t *)tensor->data, f32_output, nelements);
236-
} else if (ggml_is_quantized(tensor->type)) {
237-
qtype->to_float(tensor->data, f32_output, nelements);
238-
} else {
239-
GGML_ABORT("fatal error"); // unreachable
240-
}
241-
return;
242-
}
243-
244231
size_t block_size;
245232
if (tensor->type == GGML_TYPE_F16 ||
246233
tensor->type == GGML_TYPE_BF16) {
@@ -249,9 +236,27 @@ static void llama_tensor_dequantize_impl(
249236
block_size = (size_t)ggml_blck_size(tensor->type);
250237
}
251238

239+
GGML_ASSERT(start >= 0);
240+
GGML_ASSERT((size_t) start % block_size == 0);
241+
GGML_ASSERT(nelements % block_size == 0);
242+
252243
size_t block_size_bytes = ggml_type_size(tensor->type);
244+
const size_t input_offset = ((size_t) start / block_size) * block_size_bytes;
245+
uint8_t * input_data = (uint8_t *) tensor->data + input_offset;
246+
247+
if (nthread < 2) {
248+
if (tensor->type == GGML_TYPE_F16) {
249+
ggml_fp16_to_fp32_row((ggml_fp16_t *) input_data, f32_output, nelements);
250+
} else if (tensor->type == GGML_TYPE_BF16) {
251+
ggml_bf16_to_fp32_row((ggml_bf16_t *) input_data, f32_output, nelements);
252+
} else if (ggml_is_quantized(tensor->type)) {
253+
qtype->to_float(input_data, f32_output, nelements);
254+
} else {
255+
GGML_ABORT("fatal error"); // unreachable
256+
}
257+
return;
258+
}
253259

254-
GGML_ASSERT(nelements % block_size == 0);
255260
size_t nblocks = nelements / block_size;
256261
size_t blocks_per_thread = nblocks / nthread;
257262
size_t spare_blocks = nblocks - (blocks_per_thread * nthread); // if blocks aren't divisible by thread count
@@ -264,7 +269,7 @@ static void llama_tensor_dequantize_impl(
264269
size_t thr_elems = thr_blocks * block_size; // number of elements for this thread
265270
size_t thr_block_bytes = thr_blocks * block_size_bytes; // number of input bytes for this thread
266271

267-
auto compute = [qtype] (ggml_type typ, uint8_t * inbuf, float * outbuf, int nels) {
272+
auto compute = [qtype] (ggml_type typ, uint8_t * inbuf, float * outbuf, int64_t nels) {
268273
if (typ == GGML_TYPE_F16) {
269274
ggml_fp16_to_fp32_row((ggml_fp16_t *)inbuf, outbuf, nels);
270275
} else if (typ == GGML_TYPE_BF16) {
@@ -273,14 +278,21 @@ static void llama_tensor_dequantize_impl(
273278
qtype->to_float(inbuf, outbuf, nels);
274279
}
275280
};
276-
workers.emplace_back(compute, tensor->type, (uint8_t *) tensor->data + in_buff_offs, f32_output + out_buff_offs, thr_elems);
281+
workers.emplace_back(compute, tensor->type, input_data + in_buff_offs, f32_output + out_buff_offs, thr_elems);
277282
in_buff_offs += thr_block_bytes;
278283
out_buff_offs += thr_elems;
279284
}
280285
for (auto & w : workers) { w.join(); }
281286
workers.clear();
282287
}
283288

289+
static void llama_tensor_dequantize_impl(
290+
ggml_tensor * tensor, std::vector<no_init<float>> & output, std::vector<std::thread> & workers,
291+
const size_t nelements, const int nthread
292+
) {
293+
llama_tensor_dequantize_chunk_impl(tensor, output, workers, 0, nelements, nthread);
294+
}
295+
284296
//
285297
// do we allow this tensor to be quantized?
286298
//
@@ -1208,43 +1220,70 @@ static void llama_model_quantize_impl(const std::string & fname_inp, const std::
12081220
throw std::runtime_error(format("Missing importance matrix for tensor %s in a very low-bit quantization", tensor->name));
12091221
}
12101222

1211-
float * f32_data;
1212-
1213-
if (tensor->type == GGML_TYPE_F32) {
1214-
f32_data = (float *) tensor->data;
1215-
} else if (ggml_is_quantized(tensor->type) && !params->allow_requantize) {
1216-
throw std::runtime_error(format("requantizing from type %s is disabled", ggml_type_name(tensor->type)));
1217-
} else {
1218-
llama_tensor_dequantize_impl(tensor, f32_conv_buf, workers, nelements, nthread);
1219-
f32_data = (float *) f32_conv_buf.data();
1220-
}
1221-
12221223
LLAMA_LOG_INFO("converting to %s .. ", ggml_type_name(new_type));
12231224
fflush(stdout);
12241225

1225-
if (work.size() < (size_t)nelements * 4) {
1226-
work.resize(nelements * 4); // upper bound on size
1227-
}
1228-
new_data = work.data();
1229-
12301226
const int64_t n_per_row = tensor->ne[0];
12311227
const int64_t nrows = tensor->ne[1];
1228+
const size_t row_size = ggml_row_size(new_type, n_per_row);
1229+
const size_t work_size = row_size * nrows * tensor->ne[2];
1230+
1231+
if (work.size() < work_size) {
1232+
work.resize(work_size);
1233+
}
1234+
new_data = work.data();
12321235

12331236
static const int64_t min_chunk_size = 32 * 512;
12341237
const int64_t chunk_size = (n_per_row >= min_chunk_size ? n_per_row : n_per_row * ((min_chunk_size + n_per_row - 1)/n_per_row));
12351238

12361239
const int64_t nelements_matrix = tensor->ne[0] * tensor->ne[1];
12371240
const int64_t nchunk = (nelements_matrix + chunk_size - 1)/chunk_size;
12381241
const int64_t nthread_use = nthread > 1 ? std::max((int64_t)1, std::min((int64_t)nthread, nchunk)) : 1;
1242+
const bool stream_source = tensor->type == GGML_TYPE_F16 || tensor->type == GGML_TYPE_BF16;
12391243

12401244
// quantize each expert separately since they have different importance matrices
12411245
new_size = 0;
1242-
for (int64_t i03 = 0; i03 < tensor->ne[2]; ++i03) {
1243-
const float * f32_data_03 = f32_data + i03 * nelements_matrix;
1244-
void * new_data_03 = (char *)new_data + ggml_row_size(new_type, n_per_row) * i03 * nrows;
1245-
const float * imatrix_03 = imatrix ? imatrix + i03 * n_per_row : nullptr;
1246+
if (stream_source) {
1247+
static const int64_t stream_chunk_size = 32 * 1024 * 1024;
1248+
const int64_t rows_per_stream_chunk = std::max<int64_t>(1, std::max(chunk_size, stream_chunk_size) / n_per_row);
12461249

1247-
new_size += llama_tensor_quantize_impl(new_type, f32_data_03, new_data_03, chunk_size, nrows, n_per_row, imatrix_03, workers, nthread_use);
1250+
for (int64_t i03 = 0; i03 < tensor->ne[2]; ++i03) {
1251+
void * new_data_03 = (char *)new_data + row_size * i03 * nrows;
1252+
const float * imatrix_03 = imatrix ? imatrix + i03 * n_per_row : nullptr;
1253+
1254+
for (int64_t first_row = 0; first_row < nrows; first_row += rows_per_stream_chunk) {
1255+
const int64_t this_nrow = std::min(nrows - first_row, rows_per_stream_chunk);
1256+
const int64_t start = i03 * nelements_matrix + first_row * n_per_row;
1257+
const size_t chunk_nelements = this_nrow * n_per_row;
1258+
1259+
llama_tensor_dequantize_chunk_impl(tensor, f32_conv_buf, workers, start, chunk_nelements, nthread);
1260+
1261+
void * new_data_chunk = (char *) new_data_03 + row_size * first_row;
1262+
const int64_t chunk_nchunk = (chunk_nelements + chunk_size - 1) / chunk_size;
1263+
const int64_t chunk_nthread = nthread > 1 ? std::max((int64_t)1, std::min((int64_t)nthread, chunk_nchunk)) : 1;
1264+
1265+
new_size += llama_tensor_quantize_impl(new_type, (float *) f32_conv_buf.data(), new_data_chunk, chunk_size, this_nrow, n_per_row, imatrix_03, workers, chunk_nthread);
1266+
}
1267+
}
1268+
} else {
1269+
float * f32_data;
1270+
1271+
if (tensor->type == GGML_TYPE_F32) {
1272+
f32_data = (float *) tensor->data;
1273+
} else if (ggml_is_quantized(tensor->type) && !params->allow_requantize) {
1274+
throw std::runtime_error(format("requantizing from type %s is disabled", ggml_type_name(tensor->type)));
1275+
} else {
1276+
llama_tensor_dequantize_impl(tensor, f32_conv_buf, workers, nelements, nthread);
1277+
f32_data = (float *) f32_conv_buf.data();
1278+
}
1279+
1280+
for (int64_t i03 = 0; i03 < tensor->ne[2]; ++i03) {
1281+
const float * f32_data_03 = f32_data + i03 * nelements_matrix;
1282+
void * new_data_03 = (char *)new_data + row_size * i03 * nrows;
1283+
const float * imatrix_03 = imatrix ? imatrix + i03 * n_per_row : nullptr;
1284+
1285+
new_size += llama_tensor_quantize_impl(new_type, f32_data_03, new_data_03, chunk_size, nrows, n_per_row, imatrix_03, workers, nthread_use);
1286+
}
12481287
}
12491288
LLAMA_LOG_INFO("size = %8.2f MiB -> %8.2f MiB\n", tensor_size/1024.0/1024.0, new_size/1024.0/1024.0);
12501289
}

0 commit comments

Comments
 (0)