Repository: ollama/ollama
Pull request: convert: support new Gemma4 audio_tower tensor naming


Changed files:
filename: convert/convert_gemma4.go
patch: @@ -450,21 +450,31 @@ func (p *gemma4Model) Replacements() []string {
 		"model.audio_tower.subsample_conv_projection.conv_0.norm", "a.conv1d.0.norm",
 		"model.audio_tower.subsample_conv_projection.conv_1.conv", "a.conv1d.1",
 		"model.audio_tower.subsample_conv_projection.conv_1.norm", "a.conv1d.1.norm",
+		"model.audio_tower.subsample_conv_projection.layer0.conv", "a.conv1d.0",
+		"model.audio_tower.subsample_conv_projection.layer0.norm", "a.conv1d.0.norm",
+		"model.audio_tower.subsample_conv_projection.layer1.conv", "a.conv1d.1",
+		"model.audio_tower.subsample_conv_projection.layer1.norm", "a.conv1d.1.norm",
 		"model.audio_tower.subsample_conv_projection.input_proj_linear", "a.pre_encode.out",
 
 		// Audio conformer blocks
 		"model.audio_tower.conformer", "a.blk",
+		"model.audio_tower.layers", "a.blk",
 
 		// Audio conformer attention
 		"attention.attn.relative_position_embedding.pos_proj", "linear_pos",
+		"self_attn.relative_k_proj", "linear_pos",
 		"attention.attn.per_dim_key_scale", "per_dim_k_scale",
 		"attention.attn.per_dim_scale", "per_dim_scale",
+		"self_attn.per_dim_scale", "per_dim_scale",
 		"attention.attn.q_proj", "attn_q",
 		"attention.attn.k_proj", "attn_k",
 		"attention.attn.v_proj", "attn_v",
 		"attention.pre_attn_norm", "ln1",
 		"attention.post_norm", "ln2",
 		"attention.post", "attn_out",
+		"self_attn.post", "attn_out",
+		"norm_pre_attn", "ln1",
+		"norm_post_attn", "ln2",
 
 		// Audio conformer feedforward
 		"ffw_layer_start.pre_layer_norm", "ffn_norm",
@@ -475,6 +485,14 @@ func (p *gemma4Model) Replacements() []string {
 		"ffw_layer_end.post_layer_norm", "ffn_post_norm_1",
 		"ffw_layer_end.ffw_layer_1", "ffn_up_1",
 		"ffw_layer_end.ffw_layer_2", "ffn_down_1",
+		"feed_forward1.pre_layer_norm", "ffn_norm",
+		"feed_forward1.post_layer_norm", "ffn_post_norm",
+		"feed_forward1.ffw_layer_1", "ffn_up",
+		"feed_forward1.ffw_layer_2", "ffn_down",
+		"feed_forward2.pre_layer_norm", "ffn_norm_1",
+		"feed_forward2.post_layer_norm", "ffn_post_norm_1",
+		"feed_forward2.ffw_layer_1", "ffn_up_1",
+		"feed_forward2.ffw_layer_2", "ffn_down_1",
 
 		// Audio conformer lightweight conv1d
 		"lconv1d.depthwise_conv1d", "conv_dw",

filename: convert/convert_gemma4_test.go
patch: @@ -40,6 +40,16 @@ func TestGemma4AudioReplacements(t *testing.T) {
 			"model.audio_tower.subsample_conv_projection.input_proj_linear.bias",
 			"a.pre_encode.out.bias",
 		},
+		{
+			"sscp layer0 conv weight (new naming)",
+			"model.audio_tower.subsample_conv_projection.layer0.conv.weight",
+			"a.conv1d.0.weight",
+		},
+		{
+			"sscp layer1 norm weight (new naming)",
+			"model.audio_tower.subsample_conv_projection.layer1.norm.weight",
+			"a.conv1d.1.norm.weight",
+		},
 
 		// Conformer attention
 		{
@@ -92,6 +102,31 @@ func TestGemma4AudioReplacements(t *testing.T) {
 			"model.audio_tower.conformer.0.attention.attn.per_dim_key_scale",
 			"a.blk.0.per_dim_k_scale",
 		},
+		{
+			"attn relative k proj (new naming)",
+			"model.audio_tower.layers.0.self_attn.relative_k_proj.weight",
+			"a.blk.0.linear_pos.weight",
+		},
+		{
+			"attn pre norm (new naming)",
+			"model.audio_tower.layers.0.norm_pre_attn.weight",
+			"a.blk.0.ln1.weight",
+		},
+		{
+			"attn post norm (new naming)",
+			"model.audio_tower.layers.0.norm_post_attn.weight",
+			"a.blk.0.ln2.weight",
+		},
+		{
+			"attn out clamp output_max (new naming)",
+			"model.audio_tower.layers.0.self_attn.post.output_max",
+			"a.blk.0.attn_out.output_max",
+		},
+		{
+			"per dim scale (new naming)",
+			"model.audio_tower.layers.0.self_attn.per_dim_scale",
+			"a.blk.0.per_dim_scale",
+		},
 
 		// Conformer feedforward start
 		{
@@ -136,6 +171,26 @@ func TestGemma4AudioReplacements(t *testing.T) {
 			"model.audio_tower.conformer.0.ffw_layer_end.post_layer_norm.weight",
 			"a.blk.0.ffn_post_norm_1.weight",
 		},
+		{
+			"ffn up output_max (new naming)",
+			"model.audio_tower.layers.10.feed_forward1.ffw_layer_1.output_max",
+			"a.blk.10.ffn_up.output_max",
+		},
+		{
+			"ffn down output_min (new naming)",
+			"model.audio_tower.layers.0.feed_forward1.ffw_layer_2.output_min",
+			"a.blk.0.ffn_down.output_min",
+		},
+		{
+			"ffn up 1 input_max (new naming)",
+			"model.audio_tower.layers.0.feed_forward2.ffw_layer_1.input_max",
+			"a.blk.0.ffn_up_1.input_max",
+		},
+		{
+			"ffn norm 1 (new naming)",
+			"model.audio_tower.layers.0.feed_forward2.pre_layer_norm.weight",
+			"a.blk.0.ffn_norm_1.weight",
+		},
 
 		// Conformer lightweight conv1d
 		{