use super::{GroupedExpertRows,MoeError,elements,float_tensor,same_device};
use rublas::tensor_grouped::{grouped_matmul_nt_segmented,grouped_matmul_nt_backward_segmented_selected,
GroupedStrategy,GroupedGradientSelection,GroupedBackwardSelected};
use ruda_kernel::{dsl::Runtime,tensor::RudaTensor};
#[derive(Clone,Debug)]
pub struct ExpertProjectionCache<R:Runtime> {rows:GroupedExpertRows<R>,weights:RudaTensor<R>}
pub fn expert_projection<R:Runtime>(rows:&GroupedExpertRows<R>,weights:RudaTensor<R>,strategy:GroupedStrategy)
-> Result<(RudaTensor<R>,ExpertProjectionCache<R>),MoeError> {
float_tensor(&weights)?;same_device(&rows.values,&weights)?;elements(weights.meta.shape())?;
if weights.meta.num_dims()!=3 || weights.meta.shape()[0]!=rows.experts || weights.meta.shape()[1]==0
|| weights.meta.shape()[2]!=rows.values.meta.shape()[1] || weights.dtype!=rows.values.dtype
|| !weights.client.same_execution_queue(&rows.values.client) {
return Err(MoeError("floating expert projection requires actual matching cube width/storage/device/queue"));
}
let output=unsafe {grouped_matmul_nt_segmented(rows.values.clone(),weights.clone(),rows.row_experts.clone(),rows.offsets.clone(),strategy)}?;
Ok((output,ExpertProjectionCache {rows:rows.clone(),weights}))
}
impl<R:Runtime> ExpertProjectionCache<R> {
pub fn backward(self,gradient:RudaTensor<R>,strategy:GroupedStrategy,selection:GroupedGradientSelection) -> Result<GroupedBackwardSelected<R>,MoeError> {
Ok(unsafe {grouped_matmul_nt_backward_segmented_selected(self.rows.values,self.weights,gradient,self.rows.row_experts,self.rows.offsets,strategy,selection)}?)
}
}