diff --git a/ml/src/tft/quantized_attention.rs b/ml/src/tft/quantized_attention.rs index 933c2b007..44b65f3a2 100644 --- a/ml/src/tft/quantized_attention.rs +++ b/ml/src/tft/quantized_attention.rs @@ -139,16 +139,24 @@ impl QuantizedTemporalAttention { // Dequantize all weights let q_weight = self .quantizer - .dequantize_tensor(self.q_weights.as_ref().unwrap())?; + .dequantize_tensor(self.q_weights.as_ref().ok_or_else(|| { + MLError::ModelError("quantized Q weights not initialized".to_string()) + })?)?; let k_weight = self .quantizer - .dequantize_tensor(self.k_weights.as_ref().unwrap())?; + .dequantize_tensor(self.k_weights.as_ref().ok_or_else(|| { + MLError::ModelError("quantized K weights not initialized".to_string()) + })?)?; let v_weight = self .quantizer - .dequantize_tensor(self.v_weights.as_ref().unwrap())?; + .dequantize_tensor(self.v_weights.as_ref().ok_or_else(|| { + MLError::ModelError("quantized V weights not initialized".to_string()) + })?)?; let o_weight = self .quantizer - .dequantize_tensor(self.o_weights.as_ref().unwrap())?; + .dequantize_tensor(self.o_weights.as_ref().ok_or_else(|| { + MLError::ModelError("quantized O weights not initialized".to_string()) + })?)?; // Store in cache self.attention_cache = Some(AttentionWeightCache { @@ -229,7 +237,9 @@ impl QuantizedTemporalAttention { // In production, cache should be built once after weight initialization self.compute_projections_slow(x)? } else { - let cache = self.attention_cache.as_ref().unwrap(); + let cache = self.attention_cache.as_ref().ok_or_else(|| { + MLError::ModelError("attention weight cache not built".to_string()) + })?; // Reshape 3D input to 2D for batch matmul let dims = x.dims(); @@ -312,7 +322,9 @@ impl QuantizedTemporalAttention { // Step 8: Output projection let output = if self.cache_enabled && self.attention_cache.is_some() { - let cache = self.attention_cache.as_ref().unwrap(); + let cache = self.attention_cache.as_ref().ok_or_else(|| { + MLError::ModelError("attention weight cache not built".to_string()) + })?; // Reshape attended to 2D for matmul, then reshape back let attended_2d = attended.reshape(&[batch_size * seq_len, self.hidden_dim])?; let output_2d = attended_2d.matmul(&cache.o_weight.t()?)?; @@ -320,7 +332,9 @@ impl QuantizedTemporalAttention { } else { let o_weight = self .quantizer - .dequantize_tensor(self.o_weights.as_ref().unwrap())?; + .dequantize_tensor(self.o_weights.as_ref().ok_or_else(|| { + MLError::ModelError("quantized O weights not initialized".to_string()) + })?)?; // Reshape attended to 2D for matmul, then reshape back let attended_2d = attended.reshape(&[batch_size * seq_len, self.hidden_dim])?; let output_2d = attended_2d.matmul(&o_weight.t()?)?; @@ -334,13 +348,19 @@ impl QuantizedTemporalAttention { fn compute_projections_slow(&self, x: &Tensor) -> Result<(Tensor, Tensor, Tensor), MLError> { let q_weight = self .quantizer - .dequantize_tensor(self.q_weights.as_ref().unwrap())?; + .dequantize_tensor(self.q_weights.as_ref().ok_or_else(|| { + MLError::ModelError("quantized Q weights not initialized".to_string()) + })?)?; let k_weight = self .quantizer - .dequantize_tensor(self.k_weights.as_ref().unwrap())?; + .dequantize_tensor(self.k_weights.as_ref().ok_or_else(|| { + MLError::ModelError("quantized K weights not initialized".to_string()) + })?)?; let v_weight = self .quantizer - .dequantize_tensor(self.v_weights.as_ref().unwrap())?; + .dequantize_tensor(self.v_weights.as_ref().ok_or_else(|| { + MLError::ModelError("quantized V weights not initialized".to_string()) + })?)?; // Reshape 3D input to 2D for batch matmul: [batch, seq_len, hidden_dim] -> [batch * seq_len, hidden_dim] // Candle doesn't support direct 3D x 2D matmul, so we flatten the batch and sequence dimensions @@ -466,7 +486,9 @@ mod tests { attention.build_cache()?; // Manually verify attention weights sum to 1.0 - let cache = attention.attention_cache.as_ref().unwrap(); + let cache = attention.attention_cache.as_ref().ok_or_else(|| { + MLError::ModelError("attention weight cache not built".to_string()) + })?; let num_heads = 8; let head_dim = hidden_dim / num_heads;