use intricate_macros::FromForAllUnnamedVariants;
use opencl3::{device::cl_float, error_codes::ClError, memory::Buffer};
use crate::{
optimizers::{OptimizationError, Optimizer},
types::{KernelNotFoundError, ProgramNotFoundError, SyncDataError, ModelLayer},
utils::{
opencl::{BufferConversionError, BufferOperationError, EnsureKernelsAndProgramError},
BufferOperations, OpenCLState,
},
};
pub mod activations;
pub mod conv2d;
pub mod dense;
pub mod initializers;
pub use dense::Dense;
pub use conv2d::Conv2D;
use self::{activations::compile_activations, conv2d::compile_conv2d, dense::compile_dense, initializers::Initializer};
pub(crate) fn compile_layers(
opencl_state: &mut OpenCLState,
) -> Result<(), EnsureKernelsAndProgramError> {
compile_dense(opencl_state)?;
compile_activations(opencl_state)?;
compile_conv2d(opencl_state)?;
Ok(())
}
#[derive(Debug)]
pub struct Gradient {
pub parameter_id: String,
pub value: Buffer<cl_float>,
pub optimizable: bool,
}
#[derive(Debug, FromForAllUnnamedVariants)]
pub enum UpdateVectorsComputationError {
OpenCL(ClError),
Optimizer(OptimizationError),
BufferOperation(BufferOperationError),
}
pub(crate) fn compute_update_vectors<'a>(
optimizer: &mut dyn Optimizer<'a>,
all_gradients: &[Gradient],
layer_index: usize,
timestep: usize,
state: &OpenCLState,
) -> Result<Vec<Buffer<cl_float>>, UpdateVectorsComputationError> {
let mut update_vectors: Vec<Buffer<cl_float>> = Vec::with_capacity(all_gradients.len());
for gradients in all_gradients.iter() {
if gradients.optimizable {
update_vectors.push(optimizer.compute_update_vectors(
&gradients.value,
gradients.parameter_id.to_string(),
timestep,
layer_index,
)?);
} else {
update_vectors.push(gradients.value.clone(state)?);
}
}
Ok(update_vectors)
}
#[derive(Debug, FromForAllUnnamedVariants)]
pub enum LayerPropagationError {
OpenCL(ClError),
ProgramNotFound(ProgramNotFoundError),
KernelNotFound(KernelNotFoundError),
BufferOperation(BufferOperationError),
BufferConversion(BufferConversionError),
InputsDontMatchExpectedShape,
NoCommandQueueFound,
NoDeviceFound,
LayerNotInitialized,
}
#[derive(Debug, FromForAllUnnamedVariants)]
pub enum LayerGradientComputationError {
OpenCL(ClError),
ProgramNotFound(ProgramNotFoundError),
KernelNotFound(KernelNotFoundError),
BufferConversionError(BufferConversionError),
BufferOperation(BufferOperationError),
DerivativesDontMatchExpectedShape,
HasNotPropagatedBeforeCalculation,
NoCommandQueueFound,
NoDeviceFound,
LayerNotInitialized,
}
#[derive(Debug, FromForAllUnnamedVariants)]
pub enum LayerGradientApplicationError {
OpenCL(ClError),
ProgramNotFound(ProgramNotFoundError),
KernelNotFound(KernelNotFoundError),
BufferOperation(BufferOperationError),
UpdateVectorsComputation(UpdateVectorsComputationError),
GradientsDontMatchExpectedShape,
NoCommandQueueFound,
NoDeviceFound,
LayerNotInitialized,
}
#[derive(Debug, FromForAllUnnamedVariants)]
pub enum LayerLossToInputDifferentiationError {
OpenCL(ClError),
ProgramNotFound(ProgramNotFoundError),
KernelNotFound(KernelNotFoundError),
MissingParameter(&'static str),
DerivativesDontMatchExpectedShape,
HasNotPropagatedBeforeCalculation,
NoCommandQueueFound,
LayerNotInitialized,
}
#[derive(Debug, FromForAllUnnamedVariants)]
pub enum ParametersOptimizationError {
Optimization(OptimizationError),
EmptyParameter(String),
}
#[derive(Debug, FromForAllUnnamedVariants)]
pub enum LayerInitializationError {
BufferConversion(BufferConversionError),
MissingParameterInitializer(&'static str),
NoCommandQueue,
}
pub trait Layer<'a> {
fn get_initializer_for_parameter<'b>(&'b self, parameter: &str) -> Option<&'b Initializer>;
fn set_initializer_for_parameter(self, initializer: Initializer, parameter: &'a str) -> ModelLayer<'a>;
fn get_flattened_parameter_data(&self, parameter: &str) -> Option<Vec<f32>>;
fn get_last_inputs(&self) -> Option<&Buffer<cl_float>>;
fn get_last_outputs(&self) -> Option<&Buffer<cl_float>>;
fn get_inputs_amount(&self) -> usize;
fn get_outputs_amount(&self) -> usize;
fn clean_up_gpu_state(&mut self) -> ();
fn sync_data_from_buffers_to_host(&mut self) -> Result<(), SyncDataError>;
fn init(&mut self, opencl_state: &'a OpenCLState) -> Result<(), LayerInitializationError>;
fn propagate(
&mut self,
inputs: &Buffer<cl_float>,
) -> Result<&Buffer<cl_float>, LayerPropagationError>;
fn compute_gradients(
&self,
layer_output_to_error_derivative: &Buffer<cl_float>,
) -> Result<Vec<Gradient>, LayerGradientComputationError>;
fn optimize_parameters(
&mut self,
optimizer: &dyn Optimizer<'a>,
layer_index: usize,
timestep: usize,
) -> Result<(), ParametersOptimizationError>;
fn apply_gradients(
&mut self,
per_parameter_type_gradients: &[Gradient],
optimizer: &mut dyn Optimizer<'a>,
layer_model_index: usize,
timestep: usize,
) -> Result<(), LayerGradientApplicationError>;
fn compute_loss_to_input_derivatives(
&self,
layer_loss_to_output_derivatives: &Buffer<cl_float>,
) -> Result<Buffer<cl_float>, LayerLossToInputDifferentiationError>;
}