Skip to content

Commit e9510c0

Browse files
committed
update
1 parent 2d31c89 commit e9510c0

3 files changed

Lines changed: 58 additions & 25 deletions

File tree

tfts/layers/attention_layer.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def call(
5252
training: Optional[bool] = None,
5353
return_attention_scores: bool = False,
5454
use_causal_mask: bool = False,
55+
**kwargs,
5556
):
5657
"""use query and key generating an attention multiplier for value, multi_heads to repeat it
5758
@@ -110,12 +111,31 @@ def get_config(self):
110111
return dict(list(base_config.items()) + list(config.items()))
111112

112113
def compute_output_shape(self, input_shape):
113-
if isinstance(input_shape, (list, tuple)) and len(input_shape) == 3:
114-
q_shape = input_shape[0]
115-
else:
116-
raise ValueError("Expected input_shape to be a list or tuple of three elements (q, k, v)")
114+
if isinstance(input_shape, tuple) and len(input_shape) == 3:
115+
batch_size, seq_len, _ = input_shape
116+
return (batch_size, seq_len, self.hidden_size)
117+
118+
elif isinstance(input_shape, (list, tuple)) and len(input_shape) == 3:
119+
q_shape, k_shape, v_shape = input_shape
120+
121+
# Validate that all shapes are tuples with 3 dimensions
122+
if not all(isinstance(shape, tuple) and len(shape) == 3 for shape in [q_shape, k_shape, v_shape]):
123+
raise ValueError(
124+
"Each input shape must be a tuple of length 3 (batch_size, seq_len, features). "
125+
f"Got shapes: q={q_shape}, k={k_shape}, v={v_shape}"
126+
)
127+
128+
# Output shape is based on query sequence length
129+
batch_size, seq_q_len, _ = q_shape
130+
return (batch_size, seq_q_len, self.hidden_size)
117131

118-
return (q_shape[0], q_shape[1], self.hidden_size)
132+
else:
133+
raise ValueError(
134+
"Expected input_shape to be either:\n"
135+
"1. A single tuple (batch_size, seq_len, features) for self-attention, or\n"
136+
"2. A list/tuple of 3 shapes [(q_shape), (k_shape), (v_shape)] for cross-attention.\n"
137+
f"Got: {input_shape}"
138+
)
119139

120140

121141
class SelfAttention(tf.keras.layers.Layer):

tfts/models/seq2seq.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -214,29 +214,35 @@ def __init__(
214214
self.num_attention_heads = num_attention_heads
215215
self.attention_probs_dropout_prob = attention_probs_dropout_prob
216216

217-
def build(self, input_shape):
218-
super().build(input_shape)
219-
rnn_input_size = input_shape[-1] + 1 # due to in call, concat an initial value
217+
def build(self, decoder_features_shape, decoder_init_input_shape, init_state_shape, **kwargs):
218+
rnn_input_size = decoder_features_shape[-1] + decoder_init_input_shape[-1]
219+
220+
if self.use_attention:
221+
encoder_output_shape = kwargs.get("encoder_output_shape")
222+
if encoder_output_shape is None:
223+
raise ValueError("encoder_output_shape must be provided for attention mechanism.")
224+
self.attention = Attention(
225+
hidden_size=self.attention_size,
226+
num_attention_heads=self.num_attention_heads,
227+
attention_probs_dropout_prob=self.attention_probs_dropout_prob,
228+
)
229+
self.attention.build(encoder_output_shape)
230+
231+
# Add attention output size to RNN input size
232+
rnn_input_size += encoder_output_shape[-1]
233+
220234
if self.rnn_type == "gru":
221235
self.rnn_cell = GRUCell(self.rnn_size)
222-
self.rnn_cell.build([None, rnn_input_size])
223236
elif self.rnn_type == "lstm":
224237
self.rnn_cell = LSTMCell(units=self.rnn_size)
225-
self.rnn_cell.build([None, rnn_input_size])
226238
else:
227-
raise ValueError(f"No supported rnn type of {self.rnn_type}")
239+
raise ValueError(f"Unsupported rnn type: {self.rnn_type}")
240+
241+
self.rnn_cell.build([None, rnn_input_size])
228242

229243
self.dense = Dense(units=1, activation=None)
230244
self.dense.build([None, self.rnn_size])
231-
232-
if self.use_attention:
233-
self.attention = Attention(
234-
hidden_size=self.attention_size,
235-
num_attention_heads=self.num_attention_heads,
236-
attention_probs_dropout_prob=self.attention_probs_dropout_prob,
237-
)
238-
self.attention.build(input_shape)
239-
self.built = True
245+
super().build(decoder_features_shape)
240246

241247
def call(
242248
self,

tfts/models/wavenet.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,24 +200,31 @@ def __init__(
200200
self.dilation_rates = dilation_rates
201201
self.dense_hidden_size = dense_hidden_size
202202

203-
def build(self, input_shape):
204-
super().build(input_shape)
205-
batch_size, _, decoder_feature_dim = input_shape
206-
decoder_input_size = input_shape[-1] + 1 # due to in call, concat an initial value
203+
def build(self, decoder_features_shape, decoder_init_input_shape, encoder_outputs_shape=None, **kwargs):
204+
batch_size = decoder_features_shape[0]
205+
decoder_input_size = decoder_features_shape[-1] + decoder_init_input_shape[-1]
206+
207207
self.dense1 = Dense(self.filters, activation="tanh")
208208
self.dense1.build([batch_size, decoder_input_size])
209+
209210
self.dense2 = Dense(2 * self.filters, use_bias=True)
210211
self.dense2.build([batch_size, self.filters])
212+
211213
self.dense3 = Dense(2 * self.filters, use_bias=False)
212214
self.dense3.build([batch_size, self.filters])
215+
213216
self.dense4 = Dense(2 * self.filters)
214217
self.dense4.build([batch_size, self.filters])
215-
self.dense5 = Dense(self.dense_hidden_size, activation="relu")
218+
216219
total_skips = self.filters * len(self.dilation_rates)
220+
self.dense5 = Dense(self.dense_hidden_size, activation="relu")
217221
self.dense5.build([batch_size, total_skips])
222+
218223
self.dense6 = Dense(1)
219224
self.dense6.build([batch_size, self.dense_hidden_size])
220225

226+
super().build(decoder_features_shape)
227+
221228
def call(
222229
self,
223230
decoder_features,

0 commit comments

Comments
 (0)