88
99
1010class CachedMultiHeadAttentionTest (TestCase ):
11+ def setUp (self ):
12+ super ().setUp ()
13+ self .batch_size = 2
14+ self .seq_len = 5
15+ self .num_heads = 2
16+ self .key_dim = 4
17+ self .hidden_dim = self .num_heads * self .key_dim
18+
1119 def test_layer_behaviors (self ):
1220 self .run_layer_test (
1321 cls = CachedMultiHeadAttention ,
@@ -26,20 +34,25 @@ def test_layer_behaviors(self):
2634 )
2735
2836 def test_cache_call_is_correct (self ):
29- batch_size = 2
30- seq_len = 5
31- num_heads = 2
32- key_dim = 4
33- hidden_dim = num_heads * key_dim
34-
35- input_shape = (batch_size , seq_len , hidden_dim )
37+ input_shape = (self .batch_size , self .seq_len , self .hidden_dim )
3638 x = random .uniform (shape = input_shape )
37- input_cache = ops .zeros ((batch_size , 2 , seq_len , num_heads , key_dim ))
39+ input_cache = ops .zeros (
40+ (
41+ self .batch_size ,
42+ 2 ,
43+ self .seq_len ,
44+ self .num_heads ,
45+ self .key_dim ,
46+ )
47+ )
3848 # Use a causal mask.
39- mask = ops .tril (ops .ones ((seq_len , seq_len )))
49+ mask = ops .tril (ops .ones ((self . seq_len , self . seq_len )))
4050 outputs = ops .zeros_like (x )
4151
42- layer = CachedMultiHeadAttention (num_heads = num_heads , key_dim = key_dim )
52+ layer = CachedMultiHeadAttention (
53+ num_heads = self .num_heads ,
54+ key_dim = self .key_dim ,
55+ )
4356 no_loop_outputs , no_loop_cache = layer (
4457 x ,
4558 x ,
@@ -50,8 +63,12 @@ def test_cache_call_is_correct(self):
5063
5164 def loop_body (i , outputs , cache ):
5265 # Compute the rest tokens.
53- next_input = ops .slice (x , (0 , i , 0 ), (batch_size , 1 , hidden_dim ))
54- next_mask = ops .slice (mask , (i , 0 ), (1 , seq_len ))
66+ next_input = ops .slice (
67+ x ,
68+ (0 , i , 0 ),
69+ (self .batch_size , 1 , self .hidden_dim ),
70+ )
71+ next_mask = ops .slice (mask , (i , 0 ), (1 , self .seq_len ))
5572 next_output , cache = layer (
5673 query = next_input ,
5774 value = next_input ,
@@ -64,7 +81,7 @@ def loop_body(i, outputs, cache):
6481
6582 def call (outputs , cache ):
6683 _ , outputs , cache = ops .while_loop (
67- cond = lambda i , outputs , cache : i < seq_len ,
84+ cond = lambda i , outputs , cache : i < self . seq_len ,
6885 body = loop_body ,
6986 loop_vars = [0 , outputs , cache ],
7087 )
@@ -75,26 +92,107 @@ def call(outputs, cache):
7592 self .assertAllClose (output , no_loop_outputs )
7693 self .assertAllClose (output_cache , no_loop_cache )
7794
78- def test_training_propagation (self ):
79- batch_size = 2
80- seq_len = 5
81- num_heads = 2
82- key_dim = 4
83- hidden_dim = num_heads * key_dim
95+ def test_return_attention_scores (self ):
96+ x = random .uniform (
97+ shape = (self .batch_size , self .seq_len , self .hidden_dim )
98+ )
99+
100+ layer = CachedMultiHeadAttention (
101+ num_heads = self .num_heads ,
102+ key_dim = self .key_dim ,
103+ )
104+ output , attention_scores = layer (
105+ x ,
106+ x ,
107+ return_attention_scores = True ,
108+ )
109+
110+ self .assertIsNotNone (attention_scores )
111+ self .assertAllEqual (
112+ output .shape ,
113+ [self .batch_size , self .seq_len , self .hidden_dim ],
114+ )
115+ self .assertAllEqual (
116+ attention_scores .shape ,
117+ [
118+ self .batch_size ,
119+ self .num_heads ,
120+ self .seq_len ,
121+ self .seq_len ,
122+ ],
123+ )
124+ score_sums = ops .sum (attention_scores , axis = - 1 )
125+ self .assertAllClose (
126+ score_sums ,
127+ ops .ones_like (score_sums ),
128+ atol = 1e-5 ,
129+ )
84130
85- input_shape = (batch_size , seq_len , hidden_dim )
131+ def test_return_attention_scores_with_cache (self ):
132+ x = random .uniform (
133+ shape = (self .batch_size , self .seq_len , self .hidden_dim )
134+ )
135+ input_cache = ops .zeros (
136+ (
137+ self .batch_size ,
138+ 2 ,
139+ self .seq_len ,
140+ self .num_heads ,
141+ self .key_dim ,
142+ )
143+ )
144+ mask = ops .tril (ops .ones ((self .seq_len , self .seq_len )))
145+
146+ layer = CachedMultiHeadAttention (
147+ num_heads = self .num_heads ,
148+ key_dim = self .key_dim ,
149+ )
150+ output , attention_scores , output_cache = layer (
151+ x ,
152+ x ,
153+ cache = input_cache ,
154+ cache_update_index = 0 ,
155+ attention_mask = mask ,
156+ return_attention_scores = True ,
157+ )
158+
159+ self .assertIsNotNone (attention_scores )
160+ self .assertAllEqual (
161+ output .shape ,
162+ [self .batch_size , self .seq_len , self .hidden_dim ],
163+ )
164+ self .assertAllEqual (
165+ attention_scores .shape ,
166+ [
167+ self .batch_size ,
168+ self .num_heads ,
169+ self .seq_len ,
170+ self .seq_len ,
171+ ],
172+ )
173+ self .assertAllEqual (output_cache .shape , input_cache .shape )
174+
175+ def test_training_propagation (self ):
176+ input_shape = (self .batch_size , self .seq_len , self .hidden_dim )
86177 x = random .uniform (shape = input_shape )
87178
88179 layer = CachedMultiHeadAttention (
89- num_heads = num_heads ,
90- key_dim = key_dim ,
180+ num_heads = self . num_heads ,
181+ key_dim = self . key_dim ,
91182 dropout = 0.99999 , # Zeros out the outputs after the dropout layer
92183 )
93184 outputs = layer (x , x , training = True )
94185
95186 # Custom computation with dropout rate sets to about 1.0
96187 value = layer ._value_dense (x )
97- attention_scores = ops .zeros ((batch_size , num_heads , seq_len , seq_len ))
188+ attention_scores = ops .zeros (
189+ (
190+ self .batch_size ,
191+ self .num_heads ,
192+ self .seq_len ,
193+ self .seq_len ,
194+ )
195+ )
98196 attention_output = ops .einsum (
99197 layer ._combine_equation , attention_scores , value
100198 )
0 commit comments