1use 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)]
25pub struct Layer<B: IBackend> {
27 pub name: String,
31 pub config: Box<LayerConfig>,
33 pub worker: Box<dyn ILayer<B>>,
40
41 backend: Rc<B>,
42
43 needs_backward: bool,
46
47 pub weights_data: Vec<ArcLock<SharedTensor<f32>>>,
49 pub weights_gradient: Vec<ArcLock<SharedTensor<f32>>>,
51 learnable_weights: Vec<ArcLock<SharedTensor<f32>>>,
53 weights_lr: Vec<Option<f32>>,
55 weights_weight_decay: Vec<Option<f32>>,
57 weights_display_names: Vec<String>,
59
60 weight_propagate_down: Vec<bool>,
68
69 pub input_blobs_data: Vec<ArcLock<SharedTensor<f32>>>,
71 pub input_blobs_gradient: Vec<ArcLock<SharedTensor<f32>>>,
73 pub input_blob_names: Vec<String>,
75 input_need_backwards: Vec<bool>,
76
77 pub output_blobs_data: Vec<ArcLock<SharedTensor<f32>>>,
79 pub output_blobs_gradient: Vec<ArcLock<SharedTensor<f32>>>,
81 output_blob_names: Vec<String>,
82 loss: Vec<f32>,
86
87 pub blob_names: HashMap<String, (ArcLock<SharedTensor<f32>>, ArcLock<SharedTensor<f32>>)>,
91}
92
93impl<B: IBackend> Layer<B> {
94 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 for input_name in &self.config.inputs.clone() {
119 self.connect_input(input_name, registry)
120 }
121 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 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 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 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 let mut propagate_down = true;
203 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 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 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]))); blob_gradient = Arc::new(RwLock::new(SharedTensor::new(&[1, 1, 1])));
249 }
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 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]))); let output_gradient = Arc::new(RwLock::new(SharedTensor::new(&[1, 1, 1]))); 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 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 let registry_name = format!("SHARED_WEIGHT_{}", display_name);
312
313 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 self.weights_data.push(weight_bias.clone());
328 self.weights_gradient.push(weight_gradient.clone());
329 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 if weight_name.is_empty() || !registry.contains_key(®istry_name) {
340 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.weights_lr.push(weight_config.lr_mult);
356 self.weights_weight_decay.push(weight_config.decay_mult);
357 } else {
358 let (shared_weight_data, shared_weight_gradient, shared_lr, shared_decay_mult) =
361 registry.get(®istry_name).unwrap().clone();
362 info!("Sharing weight blob '{}'", weight_name.clone());
363
364 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 registry.remove(®istry_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 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 registry.remove(®istry_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 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 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 if blob_name.is_none() || blob_name.is_some() && !blobs_skip_backp.contains(blob_name.unwrap()) {
455 layer_skip_propagate_down = false;
456 }
457 if layer_contributes_loss && !layer_skip_propagate_down {
459 break;
460 }
461 }
462
463 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 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 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 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 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 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 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 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 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 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 pub fn synchronize(&self) {
633 self.backend.synchronize().unwrap();
634 }
635
636 pub fn update_weights<SolverB: IBackend + crate::util::SolverOps<f32>>(&mut self, backend: &SolverB) {
645 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 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 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 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 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 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 pub fn input_blob_names(&self) -> &[String] {
843 &self.input_blob_names
844 }
845
846 pub fn loss(&self, weight_id: usize) -> Option<&f32> {
850 self.loss.get(weight_id)
851 }
852
853 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 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 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 pub fn learnable_weights_lr(&self) -> Vec<Option<f32>> {
894 if let Some(lr) = self.worker.learnable_weights_lr() {
895 lr
896 }
897 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 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 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 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
1021pub trait ILayer<B: IBackend>:
1023 ComputeOutput<f32, B> + ComputeInputGradient<f32, B> + ComputeParametersGradient<f32, B>
1024{
1025 fn init(&mut self, backend: Rc<B>) {}
1029
1030 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 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 #[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 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 #[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 #[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 fn auto_output_blobs(&self) -> bool {
1184 false
1185 }
1186 fn min_output_blobs(&self) -> usize {
1192 0
1193 }
1194 fn exact_num_output_blobs(&self) -> Option<usize> {
1200 None
1201 }
1202 fn auto_weight_blobs(&self) -> bool {
1207 false
1208 }
1209 fn exact_num_input_blobs(&self) -> Option<usize> {
1215 None
1216 }
1217 fn allow_force_backward(&self, input_id: usize) -> bool {
1223 true
1224 }
1225 fn sync_native(&self) -> bool {
1231 false
1232 }
1233 fn compute_in_place(&self) -> bool {
1241 false
1242 }
1243
1244 fn is_container(&self) -> bool {
1249 false
1250 }
1251
1252 fn loss_weight(&self, output_id: usize) -> Option<f32> {
1258 None
1259 }
1260
1261 fn inputs_data(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1266 None
1267 }
1268
1269 fn inputs_gradients(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1274 None
1275 }
1276
1277 fn outputs_data(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1282 None
1283 }
1284
1285 fn outputs_gradients(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1290 None
1291 }
1292
1293 fn learnable_weights(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1298 None
1299 }
1300
1301 fn learnable_weights_gradients(&self) -> Option<Vec<ArcLock<SharedTensor<f32>>>> {
1306 None
1307 }
1308
1309 fn learnable_weights_names(&self) -> Option<Vec<String>> {
1314 None
1315 }
1316
1317 fn learnable_weights_lr(&self) -> Option<Vec<Option<f32>>> {
1322 None
1323 }
1324}
1325
1326pub trait ComputeOutput<T, B: IBackend> {
1328 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
1338pub trait ComputeInputGradient<T, B: IBackend> {
1340 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
1352pub trait ComputeParametersGradient<T, B: IBackend> {
1354 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)]
1373pub struct LayerConfig {
1375 pub name: String,
1377
1378 pub layer_type: LayerType,
1380
1381 pub outputs: Vec<String>,
1383
1384 pub inputs: Vec<String>,
1386
1387 pub params: Vec<WeightConfig>,
1389
1390 pub propagate_down: Vec<bool>,
1393}
1394
1395#[derive(Debug, Clone)]
1396pub enum LayerType {
1398 Convolution(ConvolutionConfig),
1401 Rnn(RnnConfig),
1403 Linear(LinearConfig),
1405 LogSoftmax,
1407 Pooling(PoolingConfig),
1409 Sequential(SequentialConfig),
1411 Softmax,
1413 Dropout(DropoutConfig),
1415 ReLU,
1418 TanH,
1420 Sigmoid,
1422 NegativeLogLikelihood(NegativeLogLikelihoodConfig),
1425 MeanSquaredError,
1427 Reshape(ReshapeConfig),
1430}
1431
1432impl LayerType {
1435 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 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 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 pub fn output(&self, output_id: usize) -> Option<&String> {
1568 self.outputs.get(output_id)
1569 }
1570
1571 pub fn outputs_len(&self) -> usize {
1573 self.outputs.len()
1574 }
1575
1576 pub fn add_output(&mut self, output_name: &str) {
1578 self.outputs.push(output_name.to_owned());
1579 }
1580
1581 pub fn input(&self, input_id: usize) -> Option<&String> {
1583 self.inputs.get(input_id)
1584 }
1585
1586 pub fn inputs_len(&self) -> usize {
1588 self.inputs.len()
1589 }
1590
1591 pub fn add_input(&mut self, input_name: &str) {
1593 self.inputs.push(input_name.to_owned());
1594 }
1595
1596 pub fn param(&self, param_id: usize) -> Option<&WeightConfig> {
1598 self.params.get(param_id)
1599 }
1600
1601 pub fn params_len(&self) -> usize {
1603 self.params.len()
1604 }
1605
1606 pub fn validate(&self) -> Result<(), &'static str> {
1608 self.validate_propagate_down_len()?;
1609 Ok(())
1610 }
1611
1612 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 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}