mirror of
https://github.com/ollama/ollama.git
synced 2025-08-27 19:38:41 +02:00
Increase performance for Gemma3n models on NVGPUs by enabling CUDA Graph execution (#11525)
* Enable CUDA Graphs for gemma3n. Similar to https://github.com/ggml-org/llama.cpp/pull/14741, though ollama has a slightly different model graph than llama.cpp which requires different workaround checks. * Remove residual check by reshaping differently in gemma3n model This should make the heuristics more robust
This commit is contained in:
@@ -16,7 +16,7 @@ ggml-ci
|
|||||||
2 files changed, 67 insertions(+), 14 deletions(-)
|
2 files changed, 67 insertions(+), 14 deletions(-)
|
||||||
|
|
||||||
diff --git a/ggml/src/ggml-metal/ggml-metal.m b/ggml/src/ggml-metal/ggml-metal.m
|
diff --git a/ggml/src/ggml-metal/ggml-metal.m b/ggml/src/ggml-metal/ggml-metal.m
|
||||||
index ee4f2dcb..f20f5615 100644
|
index a9eeebc6..110c9ece 100644
|
||||||
--- a/ggml/src/ggml-metal/ggml-metal.m
|
--- a/ggml/src/ggml-metal/ggml-metal.m
|
||||||
+++ b/ggml/src/ggml-metal/ggml-metal.m
|
+++ b/ggml/src/ggml-metal/ggml-metal.m
|
||||||
@@ -489,6 +489,7 @@ enum ggml_metal_kernel_type {
|
@@ -489,6 +489,7 @@ enum ggml_metal_kernel_type {
|
||||||
|
@@ -52,7 +52,7 @@ index 64fb4ff4..5b9a0fe3 100644
|
|||||||
static __device__ __forceinline__ float warp_reduce_max(float x) {
|
static __device__ __forceinline__ float warp_reduce_max(float x) {
|
||||||
#pragma unroll
|
#pragma unroll
|
||||||
diff --git a/ggml/src/ggml-cuda/ggml-cuda.cu b/ggml/src/ggml-cuda/ggml-cuda.cu
|
diff --git a/ggml/src/ggml-cuda/ggml-cuda.cu b/ggml/src/ggml-cuda/ggml-cuda.cu
|
||||||
index 4c829153..9e64e5ae 100644
|
index d6960174..2b9fabf4 100644
|
||||||
--- a/ggml/src/ggml-cuda/ggml-cuda.cu
|
--- a/ggml/src/ggml-cuda/ggml-cuda.cu
|
||||||
+++ b/ggml/src/ggml-cuda/ggml-cuda.cu
|
+++ b/ggml/src/ggml-cuda/ggml-cuda.cu
|
||||||
@@ -35,6 +35,7 @@
|
@@ -35,6 +35,7 @@
|
||||||
|
50
llama/patches/0021-Enable-CUDA-Graphs-for-gemma3n.patch
Normal file
50
llama/patches/0021-Enable-CUDA-Graphs-for-gemma3n.patch
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Oliver Simons <osimons@nvidia.com>
|
||||||
|
Date: Tue, 22 Jul 2025 11:02:28 +0200
|
||||||
|
Subject: [PATCH] Enable CUDA Graphs for gemma3n.
|
||||||
|
|
||||||
|
Similar to
|
||||||
|
https://github.com/ggml-org/llama.cpp/pull/14741,
|
||||||
|
though ollama has a slightly different model graph
|
||||||
|
than llama.cpp which requires different workaround
|
||||||
|
checks.
|
||||||
|
---
|
||||||
|
ggml/src/ggml-cuda/ggml-cuda.cu | 16 ++++++++++++----
|
||||||
|
1 file changed, 12 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ggml/src/ggml-cuda/ggml-cuda.cu b/ggml/src/ggml-cuda/ggml-cuda.cu
|
||||||
|
index 2b9fabf4..28ccf4be 100644
|
||||||
|
--- a/ggml/src/ggml-cuda/ggml-cuda.cu
|
||||||
|
+++ b/ggml/src/ggml-cuda/ggml-cuda.cu
|
||||||
|
@@ -2474,6 +2474,9 @@ static bool check_node_graph_compatibility_and_refresh_copy_ops(ggml_backend_cud
|
||||||
|
// Loop over nodes in GGML graph to obtain info needed for CUDA graph
|
||||||
|
cuda_ctx->cuda_graph->cpy_dest_ptrs.clear();
|
||||||
|
|
||||||
|
+ const std::string gemma3n_per_layer_proj_src1_name = " (reshaped)";
|
||||||
|
+ const std::string gemma3n_node_name = "node_";
|
||||||
|
+
|
||||||
|
for (int i = 0; i < cgraph->n_nodes; i++) {
|
||||||
|
ggml_tensor * node = cgraph->nodes[i];
|
||||||
|
|
||||||
|
@@ -2495,12 +2498,17 @@ static bool check_node_graph_compatibility_and_refresh_copy_ops(ggml_backend_cud
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (node->op == GGML_OP_ADD && node->src[1] && node->src[1]->ne[1] > 1) {
|
||||||
|
- // disable CUDA graphs for batch size > 1 for now.
|
||||||
|
- // Changes in batch size or context size can cause changes to the grid size of some kernels.
|
||||||
|
+ // workarounds to exclude Gemma3n's `project_per_layer_input` operation from the batch-size heuristic, specific to ollama's implementation of gemma3n
|
||||||
|
+ // number of layers is different for per_layer_proj between gemma3n:2b and gemma3n:4b, which is why we don't check that value here
|
||||||
|
+ if (node->op == GGML_OP_ADD && node->src[1] && node->src[1]->ne[1] > 1 && !(node->ne[0] == 256
|
||||||
|
+ && node->ne[2] == 1
|
||||||
|
+ && node->ne[3] == 1
|
||||||
|
+ && node->src[0] ? std::string(node->src[0]->name).find(gemma3n_node_name) != std::string::npos : false
|
||||||
|
+ && node->src[1] ? node->src[1]->name == gemma3n_per_layer_proj_src1_name : false)) {
|
||||||
|
+ // Generally, changes in batch size or context size can cause changes to the grid size of some kernels.
|
||||||
|
use_cuda_graph = false;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
- GGML_LOG_DEBUG("%s: disabling CUDA graphs due to batch size > 1 [%s] [%ld %ld %ld %ld]\n", __func__, node->name, node->ne[0], node->ne[1], node->ne[2], node->ne[3]);
|
||||||
|
+ GGML_LOG_INFO("%s: disabling CUDA graphs due to batch size > 1 [%s] [%ld %ld %ld %ld]\n", __func__, node->name, node->ne[0], node->ne[1], node->ne[2], node->ne[3]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
16
ml/backend/ggml/ggml/src/ggml-cuda/ggml-cuda.cu
vendored
16
ml/backend/ggml/ggml/src/ggml-cuda/ggml-cuda.cu
vendored
@@ -2474,6 +2474,9 @@ static bool check_node_graph_compatibility_and_refresh_copy_ops(ggml_backend_cud
|
|||||||
// Loop over nodes in GGML graph to obtain info needed for CUDA graph
|
// Loop over nodes in GGML graph to obtain info needed for CUDA graph
|
||||||
cuda_ctx->cuda_graph->cpy_dest_ptrs.clear();
|
cuda_ctx->cuda_graph->cpy_dest_ptrs.clear();
|
||||||
|
|
||||||
|
const std::string gemma3n_per_layer_proj_src1_name = " (reshaped)";
|
||||||
|
const std::string gemma3n_node_name = "node_";
|
||||||
|
|
||||||
for (int i = 0; i < cgraph->n_nodes; i++) {
|
for (int i = 0; i < cgraph->n_nodes; i++) {
|
||||||
ggml_tensor * node = cgraph->nodes[i];
|
ggml_tensor * node = cgraph->nodes[i];
|
||||||
|
|
||||||
@@ -2495,12 +2498,17 @@ static bool check_node_graph_compatibility_and_refresh_copy_ops(ggml_backend_cud
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->op == GGML_OP_ADD && node->src[1] && node->src[1]->ne[1] > 1) {
|
// workarounds to exclude Gemma3n's `project_per_layer_input` operation from the batch-size heuristic, specific to ollama's implementation of gemma3n
|
||||||
// disable CUDA graphs for batch size > 1 for now.
|
// number of layers is different for per_layer_proj between gemma3n:2b and gemma3n:4b, which is why we don't check that value here
|
||||||
// Changes in batch size or context size can cause changes to the grid size of some kernels.
|
if (node->op == GGML_OP_ADD && node->src[1] && node->src[1]->ne[1] > 1 && !(node->ne[0] == 256
|
||||||
|
&& node->ne[2] == 1
|
||||||
|
&& node->ne[3] == 1
|
||||||
|
&& node->src[0] ? std::string(node->src[0]->name).find(gemma3n_node_name) != std::string::npos : false
|
||||||
|
&& node->src[1] ? node->src[1]->name == gemma3n_per_layer_proj_src1_name : false)) {
|
||||||
|
// Generally, changes in batch size or context size can cause changes to the grid size of some kernels.
|
||||||
use_cuda_graph = false;
|
use_cuda_graph = false;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
GGML_LOG_DEBUG("%s: disabling CUDA graphs due to batch size > 1 [%s] [%ld %ld %ld %ld]\n", __func__, node->name, node->ne[0], node->ne[1], node->ne[2], node->ne[3]);
|
GGML_LOG_INFO("%s: disabling CUDA graphs due to batch size > 1 [%s] [%ld %ld %ld %ld]\n", __func__, node->name, node->ne[0], node->ne[1], node->ne[2], node->ne[3]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -203,10 +203,9 @@ func (a AltUp) Predict(ctx ml.Context, hiddenStates ml.Tensor, opts *TextOptions
|
|||||||
coefficients := a.PredictionCoefficient.Forward(ctx, modalities)
|
coefficients := a.PredictionCoefficient.Forward(ctx, modalities)
|
||||||
coefficients = coefficients.Reshape(ctx, opts.altupInputs, opts.altupInputs, coefficients.Dim(1), coefficients.Dim(2))
|
coefficients = coefficients.Reshape(ctx, opts.altupInputs, opts.altupInputs, coefficients.Dim(1), coefficients.Dim(2))
|
||||||
|
|
||||||
hiddenStates = hiddenStates.Permute(ctx, 1, 2, 0, 3).Contiguous(ctx)
|
predictions := coefficients.Mulmat(ctx, hiddenStates.Permute(ctx, 1, 2, 0, 3).Contiguous(ctx))
|
||||||
predictions := coefficients.Mulmat(ctx, hiddenStates)
|
predictions = predictions.Permute(ctx, 2, 0, 1, 3).Contiguous(ctx)
|
||||||
predictions = predictions.Add(ctx, hiddenStates)
|
return predictions.Add(ctx, hiddenStates)
|
||||||
return predictions.Permute(ctx, 2, 0, 1, 3).Contiguous(ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AltUp) Correct(ctx ml.Context, predictions, activated, one ml.Tensor, opts *TextOptions) ml.Tensor {
|
func (a AltUp) Correct(ctx ml.Context, predictions, activated, one ml.Tensor, opts *TextOptions) ml.Tensor {
|
||||||
|
Reference in New Issue
Block a user