juice/
layer.rs

1//! Provides the generics and interfaces for the specific Layers.
2//!
3//! See [Layers][layers]
4//! [layers]: ../layers/index.html
5
6use std::cmp;
7use std::collections::{HashMap, HashSet};
8use std::fmt;
9use std::fs::File;
10use std::io::{self, BufReader};
11use std::path::Path;
12use std::rc::Rc;
13use std::sync::{Arc, RwLock};
14
15use crate::capnp_util::*;
16use crate::co::prelude::*;
17use crate::juice_capnp::layer as capnp_layer;
18use crate::juice_capnp::layer_config as capnp_layer_config;
19use crate::juice_capnp::layer_config::layer_type as capnp_layer_type;
20use crate::layers::*;
21use crate::util::{ArcLock, LayerOps};
22use crate::weight::WeightConfig;
23
24#[derive(Debug)]
25/// The generic Layer
26pub struct Layer<B: IBackend> {
27    /// Identifies the Network
28    ///
29    /// The name is mainly used for logging purposes.
30    pub name: String,
31    /// The configuration of the Layer
32    pub config: Box<LayerConfig>,
33    /// The [implementation][1] of the Layer.
34    /// [1]: ../layers/index.html
35    ///
36    /// This is the part that does most of the work ([forward][2]/[backward][3]).
37    /// [2]: ./trait.ILayer.html#method.forward
38    /// [3]: ./trait.ILayer.html#method.backward
39    pub worker: Box<dyn ILayer<B>>,
40
41    backend: Rc<B>,
42
43    /// Determines if layer will skip computations for [backward][1] step.
44    /// [1]: ./trait.ILayer.html#method.backward
45    needs_backward: bool,
46
47    /// The vector that stores shared references to the weights in the form of blobs.
48    pub weights_data: Vec<ArcLock<SharedTensor<f32>>>,
49    /// The vector that stores shared references to the weights in the form of blobs.
50    pub weights_gradient: Vec<ArcLock<SharedTensor<f32>>>,
51    // contains all the learnable weights (does not include bias(?) and shared weights)
52    learnable_weights: Vec<ArcLock<SharedTensor<f32>>>,
53    // learning rate for each weight
54    weights_lr: Vec<Option<f32>>,
55    // weight decay for each weight
56    weights_weight_decay: Vec<Option<f32>>,
57    // display name for each weight
58    weights_display_names: Vec<String>,
59
60    /// Vector indicating whether to compute the diff of each weight blob.
61    ///
62    /// You can safely ignore false values and always compute gradients
63    /// for all weights, but possibly with wasteful computation.
64    ///
65    /// Can be used by some [Layer implementations][1] to optimize performance.
66    /// [1]: ../layers/index.html
67    weight_propagate_down: Vec<bool>,
68
69    /// References to all the input blobs of the layer.
70    pub input_blobs_data: Vec<ArcLock<SharedTensor<f32>>>,
71    /// References to all the input blobs of the layer.
72    pub input_blobs_gradient: Vec<ArcLock<SharedTensor<f32>>>,
73    /// Names for all the input blobs of the layer.
74    pub input_blob_names: Vec<String>,
75    input_need_backwards: Vec<bool>,
76
77    /// References to all the output blobs of the layer.
78    pub output_blobs_data: Vec<ArcLock<SharedTensor<f32>>>,
79    /// References to all the output blobs of the layer.
80    pub output_blobs_gradient: Vec<ArcLock<SharedTensor<f32>>>,
81    output_blob_names: Vec<String>,
82    /// The vector that indicates whether each output blob contributes to
83    /// the [loss][1] of the network and with which weight.
84    /// [1]: http://caffe.berkeleyvision.org/tutorial/loss.html
85    loss: Vec<f32>,
86
87    /// All the blobs of the layer that can be addressed by name.
88    ///
89    /// Does not contain anonymous blobs.
90    pub blob_names: HashMap<String, (ArcLock<SharedTensor<f32>>, ArcLock<SharedTensor<f32>>)>,
91}
92
93impl<B: IBackend> Layer<B> {
94    /// Connect the layer to another layers and set up tensors for intermediate results and weights.
95    ///
96    /// Connects to the outputs provided by other layers via the `registry`.
97    /// Adds output blobs to the layer and then adds them to the `registry`, so the next
98    /// layers can connect them as their inputs.
99    /// In the end it initializes the underlying [layer implementation][2].
100    ///
101    /// [2]: ./trait.ILayer.html
102    ///
103    /// Called during initialization of containter layers.
104    pub fn connect(
105        &mut self,
106        registry: &mut HashMap<String, (ArcLock<SharedTensor<f32>>, ArcLock<SharedTensor<f32>>)>,
107        weight_registry: &mut HashMap<
108            String,
109            (
110                ArcLock<SharedTensor<f32>>,
111                ArcLock<SharedTensor<f32>>,
112                Option<f32>,
113                Option<f32>,
114            ),
115        >,
116    ) {
117        // connect to all required inputs
118        for input_name in &self.config.inputs.clone() {
119            self.connect_input(input_name, registry)
120        }
121        // setup outputs
122        for (output_id, _) in self.config.outputs.clone().iter().rev().enumerate() {
123            self.append_output(output_id, registry);
124        }
125        let config = self.config.clone();
126        for (output_id, _) in self.config.outputs.clone().iter().rev().enumerate() {
127            self.append_weight(&config, weight_registry, 0, output_id);
128        }
129
130        // If the layer specifies that AutoTopBlobs() -> true and the LayerParameter
131        // specified fewer than the required number (as specified by
132        // exact_num_top_blobs() or min_output_blobs()), allocate them here.
133        let auto_output_blobs = self.worker.auto_output_blobs();
134        debug!("Layer {} - auto_output_blobs: {}", &self.name, &auto_output_blobs);
135        let min_output_blobs = self.worker.min_output_blobs();
136        let exact_num_output_blobs = self.worker.exact_num_output_blobs().unwrap_or(0);
137        if auto_output_blobs {
138            let needed_num_outputs = cmp::max(min_output_blobs, exact_num_output_blobs);
139            for _ in 0..(needed_num_outputs - self.output_blobs_data.len()) {
140                // Add "anonymous" output blobs -- do not add to registry
141                // as we don't want these blobs to be usable as input
142                // to other layers.
143                info!("Adding anonymous output blob for layer {}", &self.name);
144                self.create_anonymous_output();
145            }
146        }
147
148        self.worker.init(self.backend.clone());
149        self.reshape();
150        self.worker.resize_shared_workspace(self.backend.clone(), None);
151        for t in &self.output_blobs_data {
152            debug!("Layer {} - output shape: {:?}", self.name, t.read().unwrap().desc());
153        }
154    }
155
156    /// Append blob as [input blob][1] to the Layer.
157    /// [1]: ../layer/index.html
158    ///
159    /// During network initalization the blobs will be appended to the Layers as per their
160    /// [LayerConfig][3]. It is also determined if a output blob skips backpropagation
161    /// from [LayerConfig.propagate_down][3] (see also [init_backprop][5]).
162    ///
163    /// [3]: ../layer/struct.LayerConfig.html
164    /// [5]: #method.init_backprop
165    fn connect_input(
166        &mut self,
167        blob_name: &str,
168        available_blobs: &mut HashMap<String, (ArcLock<SharedTensor<f32>>, ArcLock<SharedTensor<f32>>)>,
169    ) {
170        let input_id = self
171            .config
172            .inputs
173            .iter()
174            .position(|input_name| input_name == blob_name)
175            .unwrap();
176
177        if !available_blobs.contains_key(&*blob_name) {
178            error!(
179                "Unknown input blob {} (layer '{}', input_id: {})",
180                blob_name, self.name, input_id
181            );
182        }
183        info!("Input {:<15} -> Layer {:>15}", blob_name, self.name);
184
185        self.input_blob_names.push(blob_name.to_owned());
186        self.input_blobs_data.push(
187            available_blobs
188                .get(&*blob_name)
189                .expect(&format!("Unknown blob name {}", blob_name))
190                .0
191                .clone(),
192        );
193        self.input_blobs_gradient.push(
194            available_blobs
195                .get(&*blob_name)
196                .expect(&format!("Unknown blob name {}", blob_name))
197                .1
198                .clone(),
199        );
200        // available_blobs.remove(&*blob_name);
201
202        let mut propagate_down = true;
203        // Check if the backpropagation on input_id should be skipped
204        if !self.config.propagate_down.is_empty() {
205            propagate_down = self.config.propagate_down[input_id];
206        }
207        let need_backward = propagate_down;
208        self.input_need_backwards.push(need_backward);
209    }
210
211    /// Append blob as [output blob][1] to the Layer.
212    /// [1]: ../layer/index.html
213    ///
214    /// During network initalization the blobs will be appended to the Layers as per their
215    /// [LayerConfig][2]. It is also determined if computations can be done in-place, in which
216    /// no additional Blob will be allocated.</br>
217    /// Finally, the new blob will be added to the registry, so that the other layers can
218    /// connect it as their input.
219    /// [2]: ../layer/struct.LayerConfig.html
220    fn append_output(
221        &mut self,
222        output_id: usize,
223        registry: &mut HashMap<String, (ArcLock<SharedTensor<f32>>, ArcLock<SharedTensor<f32>>)>,
224    ) {
225        let layer_config = &self.config;
226
227        let blob_name = layer_config.output(output_id).unwrap().clone();
228        let blob_data: ArcLock<SharedTensor<f32>>;
229        let blob_gradient: ArcLock<SharedTensor<f32>>;
230
231        if layer_config.input(output_id).is_some() && *layer_config.input(output_id).unwrap() == blob_name {
232            info!("Layer {:<15} -> Output {:>15} (in-place)", layer_config.name, blob_name);
233            blob_data = registry[&blob_name].0.clone();
234            blob_gradient = registry[&blob_name].1.clone();
235        } else if registry.contains_key(&blob_name) {
236            // If we are not doing in-place computation but have duplicated blobs, raise an
237            // error.
238            error!("Top blob {} produced by multiple sources.", blob_name);
239            return;
240        } else {
241            {
242                info!("Layer {:<15} -> Output {:>15}", self.name, blob_name);
243                info!("Output {} = {}", output_id, blob_name);
244            }
245
246            let backend: Rc<dyn IBackend<F = B::F>> = self.backend.clone();
247            blob_data = Arc::new(RwLock::new(SharedTensor::new(&[1, 1, 1]))); // [1,1,1] for CUDA
248            blob_gradient = Arc::new(RwLock::new(SharedTensor::new(&[1, 1, 1])));
249            // [1,1,1] for CUDA
250        }
251        self.output_blob_names.push(blob_name.clone());
252        self.output_blobs_data.push(blob_data.clone());
253        self.output_blobs_gradient.push(blob_gradient.clone());
254        self.blob_names
255            .insert(blob_name.clone(), (blob_data.clone(), blob_gradient.clone()));
256        registry.insert(blob_name.clone(), (blob_data.clone(), blob_gradient.clone()));
257    }
258
259    /// Append anonymous blob as [output blob][1] to the Layer.
260    /// [1]: ../layer/index.html
261    ///
262    /// [Layer implementations][2] may request creation of anonymous output blobs
263    /// via [auto_output_blobs][3]. Since the blobs are not named, other layers can
264    /// not use them as their input blobs.
265    /// [2]: ./trait.ILayer.html
266    /// [3]: ./trait.ILayer.html#method.auto_output_blobs
267    fn create_anonymous_output(&mut self) {
268        let blob_name = "(automatic)".to_owned();
269
270        info!("{} -> {}", self.name, blob_name);
271
272        let backend: Rc<dyn IBackend<F = B::F>> = self.backend.clone();
273        let output_data = Arc::new(RwLock::new(SharedTensor::new(&[1, 1, 1]))); // [1,1,1] for CUDA
274        let output_gradient = Arc::new(RwLock::new(SharedTensor::new(&[1, 1, 1]))); // [1,1,1] for CUDA
275        self.output_blobs_data.push(output_data);
276        self.output_blobs_gradient.push(output_gradient);
277    }
278
279    fn append_weight(
280        &mut self,
281        layer_config: &LayerConfig,
282        registry: &mut HashMap<
283            String,
284            (
285                ArcLock<SharedTensor<f32>>,
286                ArcLock<SharedTensor<f32>>,
287                Option<f32>,
288                Option<f32>,
289            ),
290        >,
291        layer_id: usize,
292        weight_id: usize,
293    ) {
294        if self.worker.auto_weight_blobs() {
295            info!("Layer {} - appending weight", &layer_config.name);
296            let weights_len = self.weights_data.len();
297            let weight_name = if weights_len > weight_id {
298                layer_config.param(weight_id).unwrap().name.clone()
299            } else {
300                "".to_owned()
301            };
302
303            // use weight_name (or weight_id as a fallback) as display_name
304            let display_name = if !weight_name.is_empty() {
305                weight_name.clone()
306            } else {
307                format!("{}-{}", self.name, weight_id)
308            };
309            self.weights_display_names.push(display_name.clone());
310            // create name for registry
311            let registry_name = format!("SHARED_WEIGHT_{}", display_name);
312
313            // add to tracking vectors
314            let net_weight_id = weights_len;
315            let output_data = self.output_blobs_data[weight_id].read().unwrap();
316            debug!(
317                "Layer {} - creating weight and gradient of size {:?}",
318                &layer_config.name,
319                output_data.desc()
320            );
321            let weight_data = Arc::new(RwLock::new(SharedTensor::new(output_data.desc())));
322            let weight_bias = Arc::new(RwLock::new(SharedTensor::new(output_data.desc())));
323            let weight_gradient = Arc::new(RwLock::new(SharedTensor::new(output_data.desc())));
324            let weight_bias_gradient = Arc::new(RwLock::new(SharedTensor::new(output_data.desc())));
325            self.weights_data.push(weight_data.clone());
326            // Add Bias
327            self.weights_data.push(weight_bias.clone());
328            self.weights_gradient.push(weight_gradient.clone());
329            // Add Bias
330            self.weights_gradient.push(weight_bias_gradient.clone());
331
332            let mut weight_config = &WeightConfig::default();
333            if layer_config.params_len() > weight_id {
334                weight_config = layer_config.param(weight_id).unwrap();
335            }
336            // This layer "owns" this weight blob -- it is either anonymous
337            // (i.e., not given a weight_name) or explicitly given a name that we
338            // haven't already seen.
339            if weight_name.is_empty() || !registry.contains_key(&registry_name) {
340                // self.weight_owners.push(None);
341                if !weight_name.is_empty() {
342                    registry.insert(
343                        weight_name.clone(),
344                        (
345                            weight_data.clone(),
346                            weight_gradient.clone(),
347                            weight_config.lr_mult,
348                            weight_config.decay_mult,
349                        ),
350                    );
351                }
352                let learnable_weight_id = self.learnable_weights.len();
353                self.learnable_weights.push(weight_data.clone());
354                // self.learnable_weight_ids.push(learnable_weight_id);
355                self.weights_lr.push(weight_config.lr_mult);
356                self.weights_weight_decay.push(weight_config.decay_mult);
357            } else {
358                // Named weight blob with name we've seen before: share weights
359
360                let (shared_weight_data, shared_weight_gradient, shared_lr, shared_decay_mult) =
361                    registry.get(&registry_name).unwrap().clone();
362                info!("Sharing weight blob '{}'", weight_name.clone());
363
364                // can only share parameters if both have same lr_mult
365                if let Some(lr_mult) = weight_config.lr_mult {
366                    if let Some(owner_lr_mult) = shared_lr {
367                        if !lr_mult.eq(&owner_lr_mult) {
368                            error!("Shared param '{}' has mismatched lr_mult.", weight_name.clone());
369                        }
370                    } else {
371                        // this is the first shared instance that has a lr_mult value so we take that
372                        registry.remove(&registry_name).unwrap();
373                        registry.insert(
374                            registry_name.clone(),
375                            (
376                                shared_weight_data.clone(),
377                                shared_weight_gradient.clone(),
378                                weight_config.lr_mult,
379                                shared_decay_mult,
380                            ),
381                        );
382                    }
383                }
384                // can only share weights if both have same decay_mult
385                if let Some(decay_mult) = weight_config.decay_mult {
386                    if let Some(owner_decay_mult) = shared_decay_mult {
387                        if !decay_mult.eq(&owner_decay_mult) {
388                            error!("Shared param '{}' has mismatched decay_mult.", weight_name.clone());
389                        }
390                    } else {
391                        // this is the first shared instance that has a decay_mult value so we take that
392                        registry.remove(&registry_name).unwrap();
393                        registry.insert(
394                            registry_name,
395                            (
396                                shared_weight_data.clone(),
397                                shared_weight_gradient.clone(),
398                                shared_lr,
399                                weight_config.decay_mult,
400                            ),
401                        );
402                    }
403                }
404            }
405        }
406    }
407
408    fn reshape(&mut self) {
409        match self.is_using_in_place() {
410            false => {
411                self.worker.reshape(
412                    self.backend.clone(),
413                    &mut self.input_blobs_data,
414                    &mut self.input_blobs_gradient,
415                    &mut self.weights_data,
416                    &mut self.weights_gradient,
417                    &mut self.output_blobs_data,
418                    &mut self.output_blobs_gradient,
419                );
420            }
421            true => {
422                self.worker.reshape(
423                    self.backend.clone(),
424                    &mut vec![],
425                    &mut vec![],
426                    &mut self.weights_data,
427                    &mut self.weights_gradient,
428                    &mut self.output_blobs_data,
429                    &mut self.output_blobs_gradient,
430                );
431            }
432        }
433    }
434
435    /// Initializes layer for [backpropagation][1]
436    /// [1]: https://en.wikipedia.org/wiki/Backpropagation
437    ///
438    /// Go through all the blobs of a layer to determine which blobs contribute to the
439    /// loss of the next layer. We can skip backward computation for blobs that don't contribute
440    /// to the loss.
441    /// If all of the blobs skip backpropagation we set a flag to skip backpropagation
442    /// of the whole layer.
443    pub fn init_backprop(&mut self, blobs_under_loss: &mut HashSet<String>, blobs_skip_backp: &mut HashSet<String>) {
444        let mut layer_contributes_loss = false;
445        let mut layer_skip_propagate_down = true;
446        for (output_id, _) in self.output_blobs_data.iter().enumerate() {
447            let blob_name = self.output_blob_names.get(output_id);
448
449            // layer is a loss layer or under a loss layer
450            if self.loss(output_id).is_some() || blob_name.is_some() && blobs_under_loss.contains(blob_name.unwrap()) {
451                layer_contributes_loss = true;
452            }
453            // layer is not marked to skip backpropagation
454            if blob_name.is_none() || blob_name.is_some() && !blobs_skip_backp.contains(blob_name.unwrap()) {
455                layer_skip_propagate_down = false;
456            }
457            // layer contributes loss to some
458            if layer_contributes_loss && !layer_skip_propagate_down {
459                break;
460            }
461        }
462
463        // If this layer can skip backward computation, also all his input blobs
464        // don't need backpropagation
465        if self.needs_backward && layer_skip_propagate_down {
466            self.needs_backward = false;
467            for (input_id, _) in self.input_blobs_data.iter().enumerate() {
468                self.input_need_backwards[input_id] = false;
469            }
470        }
471        // layer doesn't contribute loss so it does not need to be backpropagated
472        if !layer_contributes_loss {
473            self.needs_backward = false;
474        }
475        {
476            info!("{} needs backward computation: {}", self.name, self.needs_backward);
477        }
478
479        for (input_id, input_name) in self.input_blob_names.iter().enumerate() {
480            if layer_contributes_loss {
481                blobs_under_loss.insert(input_name.clone());
482            } else {
483                self.input_need_backwards[input_id] = false;
484            }
485            if !self.input_need_backwards[input_id] {
486                blobs_skip_backp.insert(input_name.clone());
487            }
488        }
489    }
490
491    /// Set [backpropagation][1] flags to force this layer to backpropagate.
492    /// [1]: https://en.wikipedia.org/wiki/Backpropagation
493    ///
494    /// Is executed during Network initalization if [NetworkConfig][2].force_backward is true.
495    /// Forcing backpropagation is useful for debugging.
496    pub fn init_force_backward(&mut self) {
497        self.needs_backward = true;
498        for (input_id, _) in self.input_need_backwards.clone().iter().enumerate() {
499            self.input_need_backwards[input_id] = *self
500                .input_need_backwards
501                .get(input_id)
502                .unwrap_or(&self.worker.allow_force_backward(input_id));
503        }
504        for (weight_id, _) in self.weights_data.clone().iter().enumerate() {
505            self.set_weight_propagate_down(weight_id, true);
506        }
507    }
508
509    /// Expose the internal inputs of a container layer.
510    fn expose_inputs(&mut self) {
511        if let Some(inputs) = self.worker.inputs_data() {
512            self.input_blobs_data = inputs;
513        }
514        if let Some(gradients) = self.worker.inputs_gradients() {
515            self.input_blobs_gradient = gradients;
516        }
517    }
518
519    /// Expose the internal outputs of a container layer.
520    fn expose_outputs(&mut self) {
521        if let Some(outputs) = self.worker.outputs_data() {
522            self.output_blobs_data = outputs;
523        }
524        if let Some(gradients) = self.worker.outputs_gradients() {
525            self.output_blobs_gradient = gradients;
526        }
527    }
528
529    /// Uses the underlying layer implementation to compute a forward step.
530    ///
531    /// See [ILayer.forward](./trait.ILayer.html#method.forward)
532    pub fn forward(&mut self, inputs: &[ArcLock<SharedTensor<f32>>]) -> Vec<ArcLock<SharedTensor<f32>>> {
533        debug!("LAYER: {:?}", &self.name);
534        for (input_i, input) in inputs.iter().enumerate() {
535            let reshaped_shape = self.input_blobs_data[input_i].read().unwrap().desc().clone();
536            self.input_blobs_data[input_i] = input.clone();
537            // reshape input tensor to the reshaped shape
538            let old_shape = self.input_blobs_data[input_i].read().unwrap().desc().clone();
539            if old_shape.size() != reshaped_shape.size() {
540                panic!(
541                    "Input Shape Mismatch\nExpected {:?}\nActual {:?}",
542                    reshaped_shape, old_shape
543                );
544            }
545            self.input_blobs_data[input_i]
546                .write()
547                .unwrap()
548                .reshape(&reshaped_shape)
549                .unwrap();
550        }
551
552        let forward_time = timeit_loops!(1, {
553            if self.is_using_in_place() {
554                self.worker
555                    .forward(&self.backend, &[], &self.weights_data, &mut self.output_blobs_data);
556            } else {
557                self.worker.forward(
558                    &self.backend,
559                    &self.input_blobs_data,
560                    &self.weights_data,
561                    &mut self.output_blobs_data,
562                );
563            }
564        });
565        debug!("{:<15} - Forward time: {:.5} ms", &self.name, forward_time / 0.001);
566        self.output_blobs_data.clone()
567    }
568
569    /// Uses the underlying layer implementation to compute a backward step.
570    ///
571    /// See [ILayer.backward](./trait.ILayer.html#method.backward)
572    pub fn backward(&mut self, output_gradients: &[ArcLock<SharedTensor<f32>>]) -> Vec<ArcLock<SharedTensor<f32>>> {
573        if self.needs_backward {
574            let input_gradients = self.backward_input(output_gradients);
575            self.backward_parameters();
576            input_gradients
577        } else {
578            vec![]
579        }
580    }
581
582    /// Calculate the gradient w.r.t. input.
583    ///
584    /// This method is mostly used when doing backpropagation.
585    pub fn backward_input(
586        &mut self,
587        output_gradients: &[ArcLock<SharedTensor<f32>>],
588    ) -> Vec<ArcLock<SharedTensor<f32>>> {
589        for (output_i, output) in output_gradients.iter().enumerate() {
590            self.output_blobs_gradient[output_i] = output.clone();
591        }
592
593        if self.is_using_in_place() {
594            self.worker.backward_input(
595                &self.backend,
596                &self.weights_data,
597                &[],
598                &[],
599                &self.input_blobs_data,
600                &mut self.input_blobs_gradient,
601            )
602        } else {
603            self.worker.backward_input(
604                &self.backend,
605                &self.weights_data,
606                &self.output_blobs_data,
607                &self.output_blobs_gradient,
608                &self.input_blobs_data,
609                &mut self.input_blobs_gradient,
610            )
611        }
612
613        self.input_blobs_gradient.clone()
614    }
615
616    /// Calculate the gradient w.r.t. parameters.
617    ///
618    /// "Parameters" here refers to weights and also possibly bias, depending on the layer.
619    ///
620    /// This method is mostly used when doing backpropagation.
621    pub fn backward_parameters(&mut self) {
622        self.worker.backward_parameters(
623            &self.backend,
624            &self.output_blobs_data,
625            &self.output_blobs_gradient,
626            &self.input_blobs_data,
627            &mut self.weights_gradient,
628        )
629    }
630
631    /// Synchronize the layers backend.
632    pub fn synchronize(&self) {
633        self.backend.synchronize().unwrap();
634    }
635
636    /// Updates the [weights][1] with the weight update computed by the [Solver][2].
637    /// [1]: https://en.wikipedia.org/wiki/Synaptic_weight
638    /// [2]: ../solver/struct.Solver.html
639    ///
640    /// Updating the weights is the last step of computing a [Solver][2] minibatch.
641    /// The update value is computed in previous steps according to the [learning rate policy][3]
642    ///
643    /// [3]: ../solver/enum.LRPolicy.html
644    pub fn update_weights<SolverB: IBackend + crate::util::SolverOps<f32>>(&mut self, backend: &SolverB) {
645        // PERF: allocate this scalar once
646        let shared_a = crate::util::native_scalar(-1f32);
647        for (weight_gradient, weight_data) in self
648            .learnable_weights_gradients()
649            .iter()
650            .zip(&mut self.learnable_weights_data())
651        {
652            backend
653                .axpy(
654                    &shared_a,
655                    &weight_gradient.read().unwrap(),
656                    &mut weight_data.write().unwrap(),
657                )
658                .unwrap();
659        }
660    }
661
662    /// Clears the [weights][1] gradients and zero-inits them.
663    /// [1]: https://en.wikipedia.org/wiki/Synaptic_weight
664    ///
665    /// The gradients for the weights accumulate over the backpropagation steps of
666    /// a [Solver][2] minibatch and are cleared between each minibatch
667    /// to start over with a clean slate.
668    ///
669    /// [2]: ../solver/struct.Solver.html
670    pub fn clear_weights_gradients(&mut self) {
671        for weight_gradient in &mut self.learnable_weights_gradients().iter() {
672            let filler = crate::weight::FillerType::Constant { value: 0f32 };
673            filler.fill(&mut weight_gradient.write().unwrap());
674        }
675    }
676
677    /// Serialize the Layer and it's weights to a Cap'n Proto file at the specified path.
678    ///
679    /// You can find the capnp schema [here](../../../../capnp/juice.capnp).
680    ///
681    /// ```
682    /// # #[cfg(feature = "native")]
683    /// # mod native {
684    /// # use std::rc::Rc;
685    /// # use juice::layer::*;
686    /// # use juice::layers::*;
687    /// # use juice::util;
688    /// # pub fn test() {
689    /// #
690    /// let mut net_cfg = SequentialConfig::default();
691    /// // ... set up network ...
692    /// let cfg = LayerConfig::new("network", net_cfg);
693    ///
694    /// let native_backend = Rc::new(util::native_backend());
695    /// let mut layer = Layer::from_config(native_backend, &cfg);
696    /// // ... do stuff with the layer ...
697    /// // ... and save it
698    /// layer.save("mynetwork").unwrap();
699    /// #
700    /// # }}
701    /// #
702    /// # #[cfg(not(feature = "native"))]
703    /// # mod native {
704    /// # pub fn test() {}
705    /// # }
706    /// #
707    /// # fn main() {
708    /// #     if cfg!(feature = "native") {
709    /// #         crate::native::test();
710    /// #    }
711    /// # }
712    /// ```
713    pub fn save<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
714        let path = path.as_ref();
715        let ref mut out = File::create(path)?;
716
717        let mut message = ::capnp::message::Builder::new_default();
718        {
719            let mut layer = message.init_root::<capnp_layer::Builder>();
720            self.write_capnp(&mut layer);
721        }
722        ::capnp::serialize_packed::write_message(out, &message).unwrap();
723
724        Ok(())
725    }
726
727    /// Read a Cap'n Proto file at the specified path and deserialize the Layer inside it.
728    ///
729    /// You can find the capnp schema [here](../../../../capnp/juice.capnp).
730    ///
731    /// ```
732    /// # extern crate juice;
733    /// # extern crate coaster;
734    /// # #[cfg(feature = "native")]
735    /// # mod native {
736    /// # use std::rc::Rc;
737    /// # use juice::layer::*;
738    /// # use juice::layers::*;
739    /// # use juice::util;
740    /// use coaster::prelude::*;
741    /// # pub fn test() {
742    ///
743    /// let native_backend = Rc::new(util::native_backend());
744    /// # let mut net_cfg = SequentialConfig::default();
745    /// # let cfg = LayerConfig::new("network", net_cfg);
746    /// # let mut layer = Layer::from_config(native_backend.clone(), &cfg);
747    /// # layer.save("mynetwork").unwrap();
748    /// // Load layer from file "mynetwork"
749    /// let layer = Layer::<Backend<Native>>::load(native_backend, "mynetwork").unwrap();
750    /// #
751    /// # }}
752    /// #
753    /// # #[cfg(not(feature = "native"))]
754    /// # mod native {
755    /// # pub fn test() {}
756    /// # }
757    /// #
758    /// # fn main() {
759    /// #     if cfg!(feature = "native") {
760    /// #         crate::native::test();
761    /// #    }
762    /// # }
763    /// ```
764    pub fn load<LB: IBackend + LayerOps<f32> + 'static, P: AsRef<Path>>(
765        backend: Rc<LB>,
766        path: P,
767    ) -> io::Result<Layer<LB>> {
768        let path = path.as_ref();
769        let ref mut file = File::open(path)?;
770        let mut reader = BufReader::new(file);
771
772        let message_reader =
773            ::capnp::serialize_packed::read_message(&mut reader, ::capnp::message::ReaderOptions::new()).unwrap();
774        let read_layer = message_reader.get_root::<capnp_layer::Reader>().unwrap();
775
776        let name = read_layer.get_name().unwrap().to_owned();
777        let layer_config = LayerConfig::read_capnp(read_layer.get_config().unwrap());
778        let mut layer = Layer::from_config(backend, &layer_config);
779        layer.name = name;
780
781        let read_weights = read_layer.get_weights_data().unwrap();
782
783        let names = layer.learnable_weights_names();
784        let weights_data = layer.learnable_weights_data();
785
786        let native_backend = Backend::<Native>::default().unwrap();
787        for (i, (name, weight)) in names.iter().zip(weights_data).enumerate() {
788            for j in 0..read_weights.len() {
789                let capnp_weight = read_weights.get(i as u32);
790                if capnp_weight.get_name().unwrap() != name {
791                    continue;
792                }
793
794                let mut weight_lock = weight.write().unwrap();
795
796                let capnp_tensor = capnp_weight.get_tensor().unwrap();
797                let mut shape = Vec::new();
798                let capnp_shape = capnp_tensor.get_shape().unwrap();
799                for k in 0..capnp_shape.len() {
800                    shape.push(capnp_shape.get(k) as usize)
801                }
802                weight_lock.reshape(&shape).unwrap();
803
804                let native_slice = weight_lock
805                    .write_only(native_backend.device())
806                    .unwrap()
807                    .as_mut_slice::<f32>();
808                let data = capnp_tensor.get_data().unwrap();
809                for k in 0..data.len() {
810                    native_slice[k as usize] = data.get(k);
811                }
812            }
813        }
814
815        Ok(layer)
816    }
817
818    /// Sets whether the layer should compute gradients w.r.t. a
819    /// weight at a particular index given by `weight_id`.
820    ///
821    /// See [`weight_propagate_down`][1]
822    /// ./struct.Layer.html
823    pub fn set_weight_propagate_down(&mut self, weight_id: usize, value: bool) {
824        if self.weight_propagate_down.len() <= weight_id {
825            self.weight_propagate_down.resize(weight_id + 1, true);
826        }
827        self.weight_propagate_down[weight_id] = value;
828    }
829
830    /// Returns `true` when the layer is using in-place computation.
831    ///
832    /// For a layer to use in-place computation it needs to support it via `compute_in_place`
833    /// and the names of the first input and output tensor have to match.
834    pub fn is_using_in_place(&self) -> bool {
835        self.worker.compute_in_place()
836            && self.input_blob_names.get(0).is_some()
837            && self.output_blob_names.get(0).is_some()
838            && self.input_blob_names[0] == self.output_blob_names[0]
839    }
840
841    /// Returns the names of all the input blobs.
842    pub fn input_blob_names(&self) -> &[String] {
843        &self.input_blob_names
844    }
845
846    /// Returns the [loss weight][1] associated with the weight blob
847    /// with id `weight_id`.
848    /// [1]: http://caffe.berkeleyvision.org/tutorial/loss.html
849    pub fn loss(&self, weight_id: usize) -> Option<&f32> {
850        self.loss.get(weight_id)
851    }
852
853    /// Returns all the learnable weights in the layer.
854    ///
855    /// If the layer is a container layer it will return all the weights of the
856    /// layers inside it.
857    pub fn learnable_weights_data(&self) -> Vec<ArcLock<SharedTensor<f32>>> {
858        if let Some(weights) = self.worker.learnable_weights() {
859            weights
860        } else {
861            self.weights_data.clone()
862        }
863    }
864
865    /// Returns the gradients for all the learnable weights in the layer.
866    ///
867    /// If the layer is a container layer it will return all the gradients of the
868    /// layers inside it.
869    pub fn learnable_weights_gradients(&self) -> Vec<ArcLock<SharedTensor<f32>>> {
870        if let Some(gradients) = self.worker.learnable_weights_gradients() {
871            gradients
872        } else {
873            self.weights_gradient.clone()
874        }
875    }
876
877    /// Returns the names of all the learnable weights in the layer.
878    ///
879    /// If the layer is a container layer it will return all the names of the
880    /// layers inside it.
881    pub fn learnable_weights_names(&self) -> Vec<String> {
882        if let Some(names) = self.worker.learnable_weights_names() {
883            names
884        } else {
885            self.weights_display_names.clone()
886        }
887    }
888
889    /// Returns the learning rate for all the learnable weights in the layer.
890    ///
891    /// If the layer is a container layer it will return all learning rates of the
892    /// layers inside it.
893    pub fn learnable_weights_lr(&self) -> Vec<Option<f32>> {
894        if let Some(lr) = self.worker.learnable_weights_lr() {
895            lr
896        }
897        // else { self.weights_lr.clone() }
898        else {
899            self.learnable_weights_data()
900                .iter()
901                .map(|_| Some(1f32))
902                .collect::<Vec<_>>()
903        }
904    }
905}
906
907#[allow(unsafe_code)]
908unsafe impl<B: IBackend> Send for Layer<B> {}
909
910impl<'a, B: IBackend> CapnpWrite<'a> for Layer<B> {
911    type Builder = capnp_layer::Builder<'a>;
912
913    /// Write the Layer into a capnp message.
914    fn write_capnp(&self, builder: &mut Self::Builder) {
915        builder.set_name(&self.name);
916        {
917            let mut layer_config = builder.reborrow().init_config();
918            self.config.write_capnp(&mut layer_config);
919        }
920        {
921            let native_backend = Backend::<Native>::default().unwrap();
922            let mut weights = builder
923                .reborrow()
924                .init_weights_data(self.learnable_weights_names().len() as u32);
925            let names = self.learnable_weights_names();
926            let weights_data = self.learnable_weights_data();
927
928            for (i, (name, weight)) in names.iter().zip(weights_data).enumerate() {
929                let mut capnp_weight = weights.reborrow().get(i as u32);
930                capnp_weight.set_name(name);
931
932                let weight_lock = weight.write().unwrap();
933
934                let mut tensor = capnp_weight.init_tensor();
935                {
936                    let mut tensor_shape = tensor.reborrow().init_shape(weight_lock.desc().len() as u32);
937                    for (i, dim) in weight_lock.desc().iter().enumerate() {
938                        tensor_shape.set(i as u32, *dim as u64);
939                    }
940                }
941                {
942                    let native_slice = weight_lock.read(native_backend.device()).unwrap().as_slice::<f32>();
943                    let mut tensor_data = tensor.reborrow().init_data(native_slice.len() as u32);
944                    for (i, datum) in native_slice.iter().enumerate() {
945                        tensor_data.set(i as u32, *datum);
946                    }
947                }
948            }
949        }
950    }
951}
952
953impl<B: IBackend + LayerOps<f32> + crate::coblas::plugin::Copy<f32> + 'static> Layer<B> {
954    /// Creates a new Layer from a [LayerConfig][1].
955    /// [1]: ./struct.LayerConfig.html
956    pub fn from_config(backend: Rc<B>, config: &LayerConfig) -> Layer<B> {
957        let cl = config.clone();
958        let cfg = Box::<LayerConfig>::new(cl);
959        let mut layer = Layer {
960            name: cfg.name.clone(),
961
962            needs_backward: true,
963
964            weights_data: Vec::new(),
965            weights_gradient: Vec::new(),
966            learnable_weights: Vec::new(),
967            weight_propagate_down: Vec::new(),
968            weights_lr: Vec::new(),
969            weights_weight_decay: Vec::new(),
970            weights_display_names: Vec::new(),
971
972            input_blobs_data: Vec::new(),
973            input_blobs_gradient: Vec::new(),
974            input_blob_names: Vec::new(),
975            input_need_backwards: Vec::new(),
976
977            output_blobs_data: Vec::new(),
978            output_blobs_gradient: Vec::new(),
979            output_blob_names: Vec::new(),
980            loss: vec![1f32, 1f32, 1f32],
981
982            blob_names: HashMap::new(),
983
984            backend: backend.clone(),
985
986            worker: Layer::<B>::worker_from_config(backend, &cfg),
987            config: cfg,
988        };
989        layer.expose_inputs();
990        layer.expose_outputs();
991
992        layer
993    }
994
995    /// Helper for [from_config] to match a [LayerType][2] to its [implementation][3].
996    /// [1]: #method.from_config
997    /// [2]: ./enum.LayerType.html
998    /// [3]: ../layers/index.html
999    fn worker_from_config(backend: Rc<B>, config: &LayerConfig) -> Box<dyn ILayer<B>> {
1000        match config.layer_type.clone() {
1001            LayerType::Convolution(layer_config) => Box::new(Convolution::from_config(&layer_config)),
1002            LayerType::Rnn(layer_config) => Box::new(Rnn::from_config(&layer_config)),
1003            LayerType::Linear(layer_config) => Box::new(Linear::from_config(&layer_config)),
1004            LayerType::LogSoftmax => Box::new(LogSoftmax::default()),
1005            LayerType::Pooling(layer_config) => Box::new(Pooling::from_config(&layer_config)),
1006            LayerType::Sequential(layer_config) => Box::new(Sequential::from_config(backend, &layer_config)),
1007            LayerType::Softmax => Box::new(Softmax::default()),
1008            LayerType::ReLU => Box::new(ReLU),
1009            LayerType::TanH => Box::new(TanH),
1010            LayerType::Sigmoid => Box::new(Sigmoid),
1011            LayerType::NegativeLogLikelihood(layer_config) => {
1012                Box::new(NegativeLogLikelihood::from_config(&layer_config))
1013            }
1014            LayerType::MeanSquaredError => Box::new(MeanSquaredError),
1015            LayerType::Reshape(layer_config) => Box::new(Reshape::from_config(&layer_config)),
1016            LayerType::Dropout(layer_config) => Box::new(Dropout::from_config(&layer_config)),
1017        }
1018    }
1019}
1020
1021/// A Layer in a Neural Network that can handle forward and backward of a computation step.
1022pub trait ILayer<B: IBackend>:
1023    ComputeOutput<f32, B> + ComputeInputGradient<f32, B> + ComputeParametersGradient<f32, B>
1024{
1025    /// Initialize the layer for computation.
1026    ///
1027    /// Allows for layer-specific one time setup, e.g. precomputing constant values.
1028    fn init(&mut self, backend: Rc<B>) {}
1029
1030    /// Adjust to shapes of the output blobs to fit the shapes of the input blobs.
1031    ///
1032    /// Should be called during Layer initalization, after [init][2].
1033    ///
1034    /// **Caution**: `input_data` should only be reshaped, but not resized.
1035    ///
1036    /// [2]: #method.init
1037    fn reshape(
1038        &mut self,
1039        backend: Rc<B>,
1040        input_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
1041        input_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
1042        weights_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
1043        weights_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
1044        output_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
1045        output_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
1046    ) {
1047    }
1048
1049    /// Adjust size of shared workspace.
1050    ///
1051    /// Is used by layers that need a workspace.
1052    /// The layer should either:
1053    ///
1054    /// - leave the workspace as is if it bigger than required by this layer
1055    /// - resize the workspace to the required size if smaller
1056    /// - create the workspace if the `workspace` is `None`
1057    ///
1058    /// The reference to the workspace should be saved in the layer.
1059    fn resize_shared_workspace(
1060        &mut self,
1061        backend: Rc<B>,
1062        workspace: Option<ArcLock<SharedTensor<u8>>>,
1063    ) -> Option<ArcLock<SharedTensor<u8>>> {
1064        workspace
1065    }
1066
1067    /// Compute the [feedforward][1] layer output using the provided Backend.
1068    /// [1]: https://en.wikipedia.org/wiki/Feedforward_neural_network
1069    ///
1070    /// Aquires read locks for the input tensors
1071    /// and write locks for the output tensors to ensure sequential computation,
1072    /// and then passes them to computation method specific function ([forward_cpu][4]).
1073    ///
1074    /// [3]: #method.forward_cpu
1075    #[cfg_attr(lint, allow(map_clone))]
1076    fn forward(
1077        &self,
1078        backend: &B,
1079        input_data: &[ArcLock<SharedTensor<f32>>],
1080        weights_data: &[ArcLock<SharedTensor<f32>>],
1081        output_data: &mut [ArcLock<SharedTensor<f32>>],
1082    ) {
1083        // aquire all the locks
1084        let inp: Vec<_> = input_data.iter().map(|b| b.read().unwrap()).collect();
1085        let input_data_: Vec<&SharedTensor<f32>> = inp.iter().map(|val| &**val).collect();
1086
1087        let wgts: Vec<_> = weights_data.iter().map(|w| w.read().unwrap()).collect();
1088        let weights_data_: Vec<&SharedTensor<f32>> = wgts.iter().map(|val| &**val).collect();
1089
1090        let out_ref = output_data.iter().cloned().collect::<Vec<_>>();
1091        let out = &mut out_ref.iter().map(|b| b.write().unwrap()).collect::<Vec<_>>();
1092        let output_w = &mut out.iter_mut().map(|a| a).collect::<Vec<_>>();
1093        let mut output_data_: Vec<&mut SharedTensor<f32>> = output_w.iter_mut().map(|val| &mut ***val).collect();
1094
1095        self.compute_output(backend, &weights_data_, &input_data_, &mut output_data_);
1096    }
1097
1098    /// Compute the [backpropagation][1] input gradient using the provided backend.
1099    /// [1]: https://en.wikipedia.org/wiki/Backpropagation
1100    ///
1101    /// Aquires write locks for the input blobs to ensure sequential computation,
1102    /// and then do a [compute_input_gradient][3].
1103    ///
1104    /// [3]: ./trait.ComputeInputGradient.html#method.compute_input_gradient
1105    #[cfg_attr(lint, allow(map_clone))]
1106    fn backward_input(
1107        &self,
1108        backend: &B,
1109        weights_data: &[ArcLock<SharedTensor<f32>>],
1110        output_data: &[ArcLock<SharedTensor<f32>>],
1111        output_gradients: &[ArcLock<SharedTensor<f32>>],
1112        input_data: &[ArcLock<SharedTensor<f32>>],
1113        input_gradients: &mut [ArcLock<SharedTensor<f32>>],
1114    ) {
1115        let wgts_data: Vec<_> = weights_data.iter().map(|b| b.read().unwrap()).collect();
1116        let weights_data_: Vec<&SharedTensor<f32>> = wgts_data.iter().map(|val| &**val).collect();
1117        let out_data: Vec<_> = output_data.iter().map(|b| b.read().unwrap()).collect();
1118        let output_data_: Vec<&SharedTensor<f32>> = out_data.iter().map(|val| &**val).collect();
1119        let out_gradient: Vec<_> = output_gradients.iter().map(|b| b.read().unwrap()).collect();
1120        let output_gradients_: Vec<&SharedTensor<f32>> = out_gradient.iter().map(|val| &**val).collect();
1121        let inp_data: Vec<_> = input_data.iter().map(|b| b.read().unwrap()).collect();
1122        let input_data_: Vec<&SharedTensor<f32>> = inp_data.iter().map(|val| &**val).collect();
1123        let btm_gradient_ref = input_gradients.iter().cloned().collect::<Vec<_>>();
1124        let btm_gradient = &mut btm_gradient_ref.iter().map(|b| b.write().unwrap()).collect::<Vec<_>>();
1125        let input_gradient = &mut btm_gradient.iter_mut().map(|a| a).collect::<Vec<_>>();
1126        let mut input_gradients_: Vec<&mut SharedTensor<f32>> =
1127            input_gradient.iter_mut().map(|val| &mut ***val).collect();
1128
1129        self.compute_input_gradient(
1130            backend,
1131            &weights_data_,
1132            &output_data_,
1133            &output_gradients_,
1134            &input_data_,
1135            &mut input_gradients_,
1136        );
1137    }
1138
1139    /// Compute the [backpropagation][1] parameters gradient using the provided backend.
1140    /// [1]: https://en.wikipedia.org/wiki/Backpropagation
1141    ///
1142    /// Aquires write locks for the input blobs to ensure sequential computation,
1143    /// and then do a [compute_parameters_gradient][4].
1144    ///
1145    /// [4]: ./trait.ComputeParametersGradient.html#method.compute_parameters_gradient
1146    #[cfg_attr(lint, allow(map_clone))]
1147    fn backward_parameters(
1148        &self,
1149        backend: &B,
1150        output_data: &[ArcLock<SharedTensor<f32>>],
1151        output_gradients: &[ArcLock<SharedTensor<f32>>],
1152        input_data: &[ArcLock<SharedTensor<f32>>],
1153        weights_gradients: &mut [ArcLock<SharedTensor<f32>>],
1154    ) {
1155        let out_data: Vec<_> = output_data.iter().map(|b| b.read().unwrap()).collect();
1156        let output_data_: Vec<&SharedTensor<f32>> = out_data.iter().map(|val| &**val).collect();
1157        let out_gradients: Vec<_> = output_gradients.iter().map(|b| b.read().unwrap()).collect();
1158        let output_gradients_: Vec<&SharedTensor<f32>> = out_gradients.iter().map(|val| &**val).collect();
1159        let inp_data: Vec<_> = input_data.iter().map(|b| b.read().unwrap()).collect();
1160        let input_data_: Vec<&SharedTensor<f32>> = inp_data.iter().map(|val| &**val).collect();
1161        let wgt_gradient_ref = weights_gradients.iter().cloned().collect::<Vec<_>>();
1162        let wgt_gradient = &mut wgt_gradient_ref.iter().map(|b| b.write().unwrap()).collect::<Vec<_>>();
1163        let weights_gradient = &mut wgt_gradient.iter_mut().map(|a| a).collect::<Vec<_>>();
1164        let mut weights_gradients_: Vec<&mut SharedTensor<f32>> =
1165            weights_gradient.iter_mut().map(|val| &mut ***val).collect();
1166
1167        self.compute_parameters_gradient(
1168            backend,
1169            &output_data_,
1170            &output_gradients_,
1171            &input_data_,
1172            &mut weights_gradients_,
1173        );
1174    }
1175
1176    /// Return whether "anonymous" output blobs are created automatically for the layer.
1177    ///
1178    /// If this method returns true, Network::init will create enough "anonymous" output
1179    /// blobs to fulfill the requirement specified by [exact_num_output_blobs][1] or
1180    /// [min_output_blobs][2].
1181    /// [1]: #method.exact_num_output_blobs
1182    /// [2]: #method.min_output_blobs
1183    fn auto_output_blobs(&self) -> bool {
1184        false
1185    }
1186    /// Returns the minimum number of output blobs required by the layer,
1187    /// or 0 if no minimum number is required.
1188    ///
1189    /// This method should be overridden to return a positive value if your
1190    /// layer expects some minimum number of output blobs.
1191    fn min_output_blobs(&self) -> usize {
1192        0
1193    }
1194    /// Returns the exact number of output blobs required by the layer,
1195    /// or `None` if no exact number is required.
1196    ///
1197    /// This method should be overridden to return a positive value if your
1198    /// layer expects some exact number of output blobs.
1199    fn exact_num_output_blobs(&self) -> Option<usize> {
1200        None
1201    }
1202    /// Return whether weight blobs are created automatically for the layer.
1203    ///
1204    /// If this method returns true, Network::init will create a weight blob
1205    /// for every output blob.
1206    fn auto_weight_blobs(&self) -> bool {
1207        false
1208    }
1209    /// Returns the exact number of input blobs required by the layer,
1210    /// or `None` if no exact number is required.
1211    ///
1212    /// This method should be overridden to return a positive value if your
1213    /// layer expects some exact number of input blobs.
1214    fn exact_num_input_blobs(&self) -> Option<usize> {
1215        None
1216    }
1217    /// Return whether to allow force_backward for a given input blob index.
1218    ///
1219    /// If allow_force_backward(i) == false, we will ignore the force_backward
1220    /// setting and backpropagate to blob i only if it needs gradient information
1221    /// (as is done when force_backward == false).
1222    fn allow_force_backward(&self, input_id: usize) -> bool {
1223        true
1224    }
1225    /// Return wether a simple native backend should be used to [sync][1] instead of the default backend.
1226    /// [1]: #method.sync
1227    ///
1228    /// If `false` is returned the default backend will be used, otherwise a new native backend
1229    /// will be created and provided as argument to `sync`.
1230    fn sync_native(&self) -> bool {
1231        false
1232    }
1233    /// Return wether the computations of a layer should be done in-place (the output will be written where the input was read from).
1234    ///
1235    /// Doing computations in place reduces the memory required for layers.
1236    ///
1237    /// If `false` is returned the layer behaves as normal, otherwise
1238    /// if a layer is provided a identiacla "input" and "output", it will only be supplied an
1239    /// "output_data" when doing a `compute_output`.
1240    fn compute_in_place(&self) -> bool {
1241        false
1242    }
1243
1244    /// Return wether the layer is a container.
1245    ///
1246    /// This turns of certain behaviour for containers which would lead to problems:
1247    /// - RwLocks will not be aquired for forward/backward since it would lead to deadlocks.
1248    fn is_container(&self) -> bool {
1249        false
1250    }
1251
1252    /// Return the associated loss weight for a given output blob index.
1253    ///
1254    /// If loss_weight(i) == `None`, no loss will be calculated for the output blob.
1255    ///
1256    /// This is usually overridden by loss layers.
1257    fn loss_weight(&self, output_id: usize) -> Option<f32> {
1258        None
1259    }
1260
1261    /// Return the input tensors of the layer.
1262    ///
1263    /// This should only be overridden by container layers,
1264    /// where the tensors are not easily exposable.
1265    fn inputs_data(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1266        None
1267    }
1268
1269    /// Return the gradients of the input tensors of the layer.
1270    ///
1271    /// This should only be overridden by container layers,
1272    /// where the tensors are not easily exposable.
1273    fn inputs_gradients(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1274        None
1275    }
1276
1277    /// Return the output tensors of the layer.
1278    ///
1279    /// This should only be overridden by container layers,
1280    /// where the tensors are not easily exposable.
1281    fn outputs_data(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1282        None
1283    }
1284
1285    /// Return the gradients of the output tensors of the layer.
1286    ///
1287    /// This should only be overridden by container layers,
1288    /// where the tensors are not easily exposable.
1289    fn outputs_gradients(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1290        None
1291    }
1292
1293    /// Return the learnable weights inside the layer.
1294    ///
1295    /// This should only be overridden by container layers,
1296    /// where the weights are not easily exposable.
1297    fn learnable_weights(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1298        None
1299    }
1300
1301    /// Return the gradients for the learnable weights inside the layer.
1302    ///
1303    /// This should only be overridden by container layers,
1304    /// where the weights are not easily exposable.
1305    fn learnable_weights_gradients(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1306        None
1307    }
1308
1309    /// Return the names of the learnable weights inside the layer.
1310    ///
1311    /// This should only be overridden by container layers,
1312    /// where the weights are not easily exposable.
1313    fn learnable_weights_names(&self) -> Option<Vec<String>> {
1314        None
1315    }
1316
1317    /// Return the learning rates for the learnable weights inside the layer.
1318    ///
1319    /// This should only be overridden by container layers,
1320    /// where the weights are not easily exposable.
1321    fn learnable_weights_lr(&self) -> Option<Vec<Option<f32>>> {
1322        None
1323    }
1324}
1325
1326/// A Layer that can compute the output for a given input.
1327pub trait ComputeOutput<T, B: IBackend> {
1328    /// Compute output for given input and write them into `output_data`.
1329    fn compute_output(
1330        &self,
1331        backend: &B,
1332        weights_data: &[&SharedTensor<T>],
1333        input_data: &[&SharedTensor<T>],
1334        output_data: &mut [&mut SharedTensor<T>],
1335    );
1336}
1337
1338/// A Layer that can compute the gradient with respect to its input.
1339pub trait ComputeInputGradient<T, B: IBackend> {
1340    /// Compute gradients with respect to the inputs and write them into `input_gradients`.
1341    fn compute_input_gradient(
1342        &self,
1343        backend: &B,
1344        weights_data: &[&SharedTensor<T>],
1345        output_data: &[&SharedTensor<T>],
1346        output_gradients: &[&SharedTensor<T>],
1347        input_data: &[&SharedTensor<T>],
1348        input_gradients: &mut [&mut SharedTensor<T>],
1349    );
1350}
1351
1352/// A Layer that can compute the gradient with respect to its parameters (= weights, bias, etc.).
1353pub trait ComputeParametersGradient<T, B: IBackend> {
1354    /// Compute gradients with respect to the parameters and write them into `parameters_gradients`.
1355    fn compute_parameters_gradient(
1356        &self,
1357        backend: &B,
1358        output_data: &[&SharedTensor<T>],
1359        output_gradients: &[&SharedTensor<T>],
1360        input_data: &[&SharedTensor<T>],
1361        parameters_gradients: &mut [&mut SharedTensor<T>],
1362    ) {
1363    }
1364}
1365
1366impl<B: IBackend> fmt::Debug for dyn ILayer<B> {
1367    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1368        write!(f, "({})", "ILayer")
1369    }
1370}
1371
1372#[derive(Debug, Clone)]
1373/// Layer Configuration Struct
1374pub struct LayerConfig {
1375    /// The name of the Layer
1376    pub name: String,
1377
1378    /// The type of the Layer
1379    pub layer_type: LayerType,
1380
1381    /// The name for each output Blob
1382    pub outputs: Vec<String>,
1383
1384    /// The name for each input Blob
1385    pub inputs: Vec<String>,
1386
1387    /// Specifies training configuration for each weight blob.
1388    pub params: Vec<WeightConfig>,
1389
1390    /// Specifies on which inputs the backpropagation should be skipped.
1391    /// The size must be either 0 or equal to the number of inputs.
1392    pub propagate_down: Vec<bool>,
1393}
1394
1395#[derive(Debug, Clone)]
1396/// The Layer Types
1397pub enum LayerType {
1398    // Common layers
1399    /// Convolution Layer
1400    Convolution(ConvolutionConfig),
1401    /// RNN Layer
1402    Rnn(RnnConfig),
1403    /// Linear Layer
1404    Linear(LinearConfig),
1405    /// LogSoftmax Layer
1406    LogSoftmax,
1407    /// Pooling Layer
1408    Pooling(PoolingConfig),
1409    /// Sequential Layer
1410    Sequential(SequentialConfig),
1411    /// Softmax Layer
1412    Softmax,
1413    /// Dropout
1414    Dropout(DropoutConfig),
1415    // Activation layers
1416    /// ReLU Layer
1417    ReLU,
1418    /// TanH Layer
1419    TanH,
1420    /// Sigmoid Layer
1421    Sigmoid,
1422    // Loss layers
1423    /// NegativeLogLikelihood Layer
1424    NegativeLogLikelihood(NegativeLogLikelihoodConfig),
1425    /// MeanSquaredError Layer
1426    MeanSquaredError,
1427    // Utility layers
1428    /// Reshape Layer
1429    Reshape(ReshapeConfig),
1430}
1431
1432// TODO get rid of this, each implementation has to state if this
1433// TODO an in place operation or not, this thing here makes no sense whatsoever
1434impl LayerType {
1435    /// Returns wether the LayerType supports in-place operations.
1436    pub fn supports_in_place(&self) -> bool {
1437        match *self {
1438            LayerType::Linear(_) => false,
1439            LayerType::LogSoftmax => false,
1440            LayerType::Sequential(_) => false,
1441            LayerType::Softmax => false,
1442            LayerType::ReLU => true,
1443            LayerType::TanH => true,
1444            LayerType::Sigmoid => true,
1445            LayerType::NegativeLogLikelihood(_) => false,
1446            LayerType::MeanSquaredError => false,
1447            LayerType::Reshape(_) => true,
1448            LayerType::Convolution(_) => false,
1449            LayerType::Rnn(_) => false,
1450            LayerType::Pooling(_) => false,
1451            LayerType::Dropout(_) => false,
1452        }
1453    }
1454}
1455
1456impl<'a> CapnpWrite<'a> for LayerType {
1457    type Builder = capnp_layer_type::Builder<'a>;
1458
1459    /// Write the LayerType into a capnp message.
1460    fn write_capnp(&self, builder: &mut Self::Builder) {
1461        match self {
1462            &LayerType::Linear(ref cfg) => {
1463                let ref mut config = builder.reborrow().init_linear();
1464                cfg.write_capnp(config);
1465            }
1466            &LayerType::LogSoftmax => builder.set_log_softmax(()),
1467            &LayerType::Sequential(ref cfg) => {
1468                let ref mut config = builder.reborrow().init_sequential();
1469                cfg.write_capnp(config);
1470            }
1471            &LayerType::Softmax => builder.set_softmax(()),
1472            &LayerType::ReLU => builder.set_relu(()),
1473            &LayerType::TanH => builder.set_tanh(()),
1474            &LayerType::Sigmoid => builder.set_sigmoid(()),
1475            &LayerType::NegativeLogLikelihood(ref cfg) => {
1476                let ref mut config = builder.reborrow().init_negative_log_likelihood();
1477                cfg.write_capnp(config);
1478            }
1479            &LayerType::MeanSquaredError => builder.set_mean_squared_error(()),
1480            &LayerType::Reshape(ref cfg) => {
1481                let ref mut config = builder.reborrow().init_reshape();
1482                cfg.write_capnp(config);
1483            }
1484            &LayerType::Convolution(ref cfg) => {
1485                let ref mut config = builder.reborrow().init_convolution();
1486                cfg.write_capnp(config);
1487            }
1488            &LayerType::Rnn(ref cfg) => {
1489                let ref mut config = builder.reborrow().init_rnn();
1490                cfg.write_capnp(config);
1491            }
1492            &LayerType::Pooling(ref cfg) => {
1493                let ref mut config = builder.reborrow().init_pooling();
1494                cfg.write_capnp(config);
1495            }
1496            &LayerType::Dropout(ref cfg) => {
1497                let ref mut config = builder.reborrow().init_dropout();
1498                cfg.write_capnp(config);
1499            }
1500        }
1501    }
1502}
1503
1504impl<'a> CapnpRead<'a> for LayerType {
1505    type Reader = capnp_layer_type::Reader<'a>;
1506
1507    fn read_capnp(reader: Self::Reader) -> Self {
1508        match reader.which().unwrap() {
1509            capnp_layer_type::Which::Linear(read_config) => {
1510                let config = LinearConfig::read_capnp(read_config.unwrap());
1511                LayerType::Linear(config)
1512            }
1513            capnp_layer_type::Which::LogSoftmax(read_config) => LayerType::LogSoftmax,
1514            capnp_layer_type::Which::Sequential(read_config) => {
1515                let config = SequentialConfig::read_capnp(read_config.unwrap());
1516                LayerType::Sequential(config)
1517            }
1518            capnp_layer_type::Which::Softmax(_) => LayerType::Softmax,
1519            capnp_layer_type::Which::Relu(_) => LayerType::ReLU,
1520            capnp_layer_type::Which::Tanh(_) => LayerType::TanH,
1521            capnp_layer_type::Which::Sigmoid(_) => LayerType::Sigmoid,
1522            capnp_layer_type::Which::NegativeLogLikelihood(read_config) => {
1523                let config = NegativeLogLikelihoodConfig::read_capnp(read_config.unwrap());
1524                LayerType::NegativeLogLikelihood(config)
1525            }
1526            capnp_layer_type::Which::MeanSquaredError(_) => LayerType::MeanSquaredError,
1527            capnp_layer_type::Which::Reshape(read_config) => {
1528                let config = ReshapeConfig::read_capnp(read_config.unwrap());
1529                LayerType::Reshape(config)
1530            }
1531            capnp_layer_type::Which::Pooling(read_config) => {
1532                let config = PoolingConfig::read_capnp(read_config.unwrap());
1533                LayerType::Pooling(config)
1534            }
1535            capnp_layer_type::Which::Convolution(read_config) => {
1536                let config = ConvolutionConfig::read_capnp(read_config.unwrap());
1537                LayerType::Convolution(config)
1538            }
1539            capnp_layer_type::Which::Rnn(read_config) => {
1540                let config = RnnConfig::read_capnp(read_config.unwrap());
1541                LayerType::Rnn(config)
1542            }
1543            capnp_layer_type::Which::Dropout(read_config) => {
1544                let config = DropoutConfig::read_capnp(read_config.unwrap());
1545                LayerType::Dropout(config)
1546            }
1547        }
1548    }
1549}
1550
1551impl LayerConfig {
1552    /// Creates a new LayerConfig
1553    pub fn new<L: Into<LayerType>>(name: &str, layer_type: L) -> LayerConfig {
1554        LayerConfig {
1555            name: name.to_owned(),
1556            layer_type: layer_type.into(),
1557
1558            outputs: Vec::new(),
1559            inputs: Vec::new(),
1560
1561            params: Vec::new(),
1562            propagate_down: Vec::new(),
1563        }
1564    }
1565
1566    /// Returns the Name of the requested output Blob
1567    pub fn output(&self, output_id: usize) -> Option<&String> {
1568        self.outputs.get(output_id)
1569    }
1570
1571    /// Returns the number of output Blobs
1572    pub fn outputs_len(&self) -> usize {
1573        self.outputs.len()
1574    }
1575
1576    /// Add a output by name
1577    pub fn add_output(&mut self, output_name: &str) {
1578        self.outputs.push(output_name.to_owned());
1579    }
1580
1581    /// Returns the Name of the requested input Blob
1582    pub fn input(&self, input_id: usize) -> Option<&String> {
1583        self.inputs.get(input_id)
1584    }
1585
1586    /// Returns the number of input Blobs
1587    pub fn inputs_len(&self) -> usize {
1588        self.inputs.len()
1589    }
1590
1591    /// Add a input by name
1592    pub fn add_input(&mut self, input_name: &str) {
1593        self.inputs.push(input_name.to_owned());
1594    }
1595
1596    /// Returns the requested WeightConfig
1597    pub fn param(&self, param_id: usize) -> Option<&WeightConfig> {
1598        self.params.get(param_id)
1599    }
1600
1601    /// Returns the number of params
1602    pub fn params_len(&self) -> usize {
1603        self.params.len()
1604    }
1605
1606    /// Check if the configured parameters make sense.
1607    pub fn validate(&self) -> Result<(), &'static str> {
1608        self.validate_propagate_down_len()?;
1609        Ok(())
1610    }
1611
1612    /// Checks if propagate down length makes sense.
1613    fn validate_propagate_down_len(&self) -> Result<(), &'static str> {
1614        if self.propagate_down.is_empty() || self.propagate_down.len() == self.inputs_len() {
1615            Ok(())
1616        } else {
1617            Err("propagate_down config must be specified either 0 or inputs_len times")
1618        }
1619    }
1620}
1621
1622impl<'a> CapnpWrite<'a> for LayerConfig {
1623    type Builder = capnp_layer_config::Builder<'a>;
1624
1625    /// Write the LayerConfig into a capnp message.
1626    fn write_capnp(&self, builder: &mut Self::Builder) {
1627        builder.set_name(&self.name);
1628        {
1629            let mut layer_type = builder.reborrow().init_layer_type();
1630            self.layer_type.write_capnp(&mut layer_type);
1631        }
1632        {
1633            let mut outputs = builder.reborrow().init_outputs(self.outputs.len() as u32);
1634            for (i, output) in self.outputs.iter().enumerate() {
1635                outputs.set(i as u32, &output);
1636            }
1637        }
1638        {
1639            let mut inputs = builder.reborrow().init_inputs(self.inputs.len() as u32);
1640            for (i, input) in self.inputs.iter().enumerate() {
1641                inputs.set(i as u32, &input);
1642            }
1643        }
1644        {
1645            let mut params = builder.reborrow().init_params(self.params.len() as u32);
1646            for (i, param) in self.params.iter().enumerate() {
1647                let ref mut capnp_param = params.reborrow().get(i as u32);
1648                param.write_capnp(capnp_param);
1649            }
1650        }
1651        {
1652            let mut propagate_down = builder.reborrow().init_propagate_down(self.propagate_down.len() as u32);
1653            for (i, input) in self.propagate_down.iter().enumerate() {
1654                propagate_down.set(i as u32, *input);
1655            }
1656        }
1657    }
1658}
1659
1660impl<'a> CapnpRead<'a> for LayerConfig {
1661    type Reader = capnp_layer_config::Reader<'a>;
1662
1663    fn read_capnp(reader: Self::Reader) -> Self {
1664        let name = reader.get_name().unwrap().to_owned();
1665        let layer_type = LayerType::read_capnp(reader.get_layer_type());
1666
1667        let read_outputs = reader.get_outputs().unwrap();
1668        let mut outputs = Vec::new();
1669        for i in 0..read_outputs.len() {
1670            outputs.push(read_outputs.get(i).unwrap().to_owned())
1671        }
1672        let read_inputs = reader.get_inputs().unwrap();
1673        let mut inputs = Vec::new();
1674        for i in 0..read_inputs.len() {
1675            inputs.push(read_inputs.get(i).unwrap().to_owned())
1676        }
1677
1678        let read_params = reader.get_params().unwrap();
1679        let mut params = Vec::new();
1680        for i in 0..read_params.len() {
1681            params.push(WeightConfig::read_capnp(read_params.get(i)))
1682        }
1683
1684        let read_propagate_down = reader.get_propagate_down().unwrap();
1685        let mut propagate_down = Vec::new();
1686        for i in 0..read_propagate_down.len() {
1687            propagate_down.push(read_propagate_down.get(i))
1688        }
1689
1690        LayerConfig {
1691            name: name,
1692            layer_type: layer_type,
1693            outputs: outputs,
1694            inputs: inputs,
1695            params: params,
1696            propagate_down: propagate_down,
1697        }
1698    }
1699}