@@ -22,6 +22,8 @@ impl Content<'_> {
2222 for ( name, tensor) in tensors {
2323 static QK_REGEX : LazyLock < Regex > =
2424 LazyLock :: new ( || Regex :: new ( r"(attn_q|attn_k|attn_qkv)\.(weight|bias)$" ) . unwrap ( ) ) ;
25+ static QK_NORM_REGEX : LazyLock < Regex > =
26+ LazyLock :: new ( || Regex :: new ( r"(attn_q_norm|attn_k_norm)\.(weight)$" ) . unwrap ( ) ) ;
2527
2628 let tensor = if let Some ( captures) = QK_REGEX . captures ( & name) {
2729 match & captures[ 1 ] {
@@ -35,6 +37,8 @@ impl Content<'_> {
3537 }
3638 _ => unreachable ! ( ) ,
3739 }
40+ } else if QK_NORM_REGEX . is_match ( & name) {
41+ permute_qk_norm ( tensor, !direction)
3842 } else {
3943 tensor
4044 } ;
@@ -73,3 +77,29 @@ fn permute_qk(tensor: Tensor, nh: usize, rev: bool) -> Tensor {
7377 } ) ;
7478 Tensor { ty, shape, data }
7579}
80+
81+ fn permute_qk_norm ( tensor : Tensor , rev : bool ) -> Tensor {
82+ let Tensor { ty, shape, data } = tensor;
83+ let [ r] = match & * shape {
84+ & [ r] => [ r] ,
85+ [ ..] => todo ! ( "permute_qk_norm only supports 1D tensors" ) ,
86+ } ;
87+ let c = ty. size ( ) . elements_to_bytes ( & [ 1 ] ) ;
88+ let r = r as usize ;
89+
90+ let tiles = if rev { [ 2 , r / 2 ] } else { [ r / 2 , 2 ] } ;
91+
92+ type Layout = mem_rearrange:: ndarray_layout:: ArrayLayout < 4 > ;
93+ let src = Layout :: new_contiguous ( & [ c, r] , LittleEndian , 1 )
94+ . tile_le ( 1 , & tiles)
95+ . transpose ( & [ 2 , 1 ] ) ;
96+ let dst = Layout :: new_contiguous ( src. shape ( ) , LittleEndian , 1 ) ;
97+ let rearrange = Rearranging :: new ( & dst, & src, 1 ) . unwrap ( ) ;
98+
99+ let data = DataPromise :: lazy ( move || {
100+ let mut ans = MmapMut :: map_anon ( c * r) . unwrap ( ) ;
101+ unsafe { rearrange. launch ( ans. as_mut_ptr ( ) , data. get ( ) . as_ptr ( ) ) } ;
102+ ans
103+ } ) ;
104+ Tensor { ty, shape, data }
105+ }
0 commit comments