dropout_example/
dropout_example.rs

1use ndarray::{Array2, Array4};
2use rand::prelude::*;
3use rand::rngs::SmallRng;
4use rand::SeedableRng;
5use scirs2_neural::layers::{BatchNorm, Conv2D, Dense, Dropout, Layer, PaddingMode};
6
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("Dropout Example");
9
10    // Initialize random number generator with a fixed seed for reproducibility
11    let mut rng = SmallRng::seed_from_u64(42);
12
13    // 1. Example: Simple dropout on a vector
14    println!("\nExample 1: Simple dropout on a vector");
15
16    // Create a vector of ones
17    let n_features = 20;
18    let input = Array2::<f32>::from_elem((1, n_features), 1.0);
19
20    // Create a dropout layer with dropout probability 0.5
21    let dropout = Dropout::new(0.5, &mut rng)?;
22
23    // Apply dropout in training mode
24    let output = dropout.forward(&input.into_dyn())?;
25
26    // Count elements that were dropped
27    let mut dropped_count = 0;
28    for i in 0..n_features {
29        let val = output.slice(ndarray::s![0, i]).into_scalar();
30        if *val == 0.0 {
31            dropped_count += 1;
32        }
33    }
34
35    // Print results
36    println!("Input: Array of {} ones", n_features);
37    println!(
38        "Output after dropout (p=0.5): {} elements dropped",
39        dropped_count
40    );
41    println!(
42        "Dropout rate: {:.2}%",
43        (dropped_count as f32 / n_features as f32) * 100.0
44    );
45
46    // 2. Example: Using dropout in a neural network to prevent overfitting
47    println!("\nExample 2: Using dropout in a simple neural network");
48
49    // Create a simple neural network with dropout
50    // 1. Create dense layer (input -> hidden)
51    let input_dim = 10;
52    let hidden_dim = 100;
53    let output_dim = 2;
54    let dense1 = Dense::new(input_dim, hidden_dim, Some("relu"), &mut rng)?;
55
56    // 2. Create dropout layer (after first dense layer)
57    let dropout1 = Dropout::new(0.2, &mut rng)?;
58
59    // 3. Create second dense layer (hidden -> output)
60    let dense2 = Dense::new(hidden_dim, output_dim, None, &mut rng)?;
61
62    // Generate a random input
63    let batch_size = 16;
64    let mut input_data = Array2::<f32>::zeros((batch_size, input_dim));
65    for i in 0..batch_size {
66        for j in 0..input_dim {
67            input_data[[i, j]] = rng.random_range(-1.0..1.0);
68        }
69    }
70
71    // Forward pass through the network with dropout
72    println!("Running forward pass with dropout...");
73    let hidden_output = dense1.forward(&input_data.clone().into_dyn())?;
74    let hidden_dropped = dropout1.forward(&hidden_output)?;
75    let final_output = dense2.forward(&hidden_dropped)?;
76
77    println!("Input shape: {:?}", input_data.shape());
78    println!("Hidden layer shape: {:?}", hidden_output.shape());
79    println!("Output shape: {:?}", final_output.shape());
80
81    // 3. Example: Dropout in a CNN architecture
82    println!("\nExample 3: Dropout in a CNN architecture");
83
84    // Create a sample CNN architecture with dropout
85
86    // 1. Create convolutional layer
87    let in_channels = 3; // RGB input
88    let out_channels = 16;
89    let conv1 = Conv2D::new(
90        in_channels,
91        out_channels,
92        (3, 3),
93        (1, 1),
94        PaddingMode::Same,
95        &mut rng,
96    )?;
97
98    // 2. Create batch normalization layer
99    let bn1 = BatchNorm::new(out_channels, 0.9, 1e-5, &mut rng)?;
100
101    // 3. Create dropout layer for spatial dropout (dropping entire feature maps)
102    let dropout_conv = Dropout::new(0.25, &mut rng)?;
103
104    // 4. Create flattened dense layer
105    let height = 32;
106    let width = 32;
107    let flattened_size = out_channels * height * width;
108    let dense3 = Dense::new(flattened_size, output_dim, None, &mut rng)?;
109
110    // Generate random input image
111    let mut image_input = Array4::<f32>::zeros((batch_size, in_channels, height, width));
112    for n in 0..batch_size {
113        for c in 0..in_channels {
114            for h in 0..height {
115                for w in 0..width {
116                    image_input[[n, c, h, w]] = rng.random_range(-1.0..1.0);
117                }
118            }
119        }
120    }
121
122    // Forward pass through CNN with dropout
123    println!("Running forward pass through CNN with dropout...");
124    let conv_output = conv1.forward(&image_input.clone().into_dyn())?;
125    let bn_output = bn1.forward(&conv_output)?;
126    let dropout_output = dropout_conv.forward(&bn_output)?;
127
128    // Reshape for dense layer (flatten spatial and channel dimensions)
129    let mut flattened = Array2::<f32>::zeros((batch_size, flattened_size));
130    for n in 0..batch_size {
131        let mut idx = 0;
132        for c in 0..out_channels {
133            for h in 0..height {
134                for w in 0..width {
135                    flattened[[n, idx]] =
136                        *dropout_output.slice(ndarray::s![n, c, h, w]).into_scalar();
137                    idx += 1;
138                }
139            }
140        }
141    }
142
143    let cnn_output = dense3.forward(&flattened.into_dyn())?;
144
145    println!("CNN output shape: {:?}", cnn_output.shape());
146
147    // 4. Example: Switching between training and inference modes
148    println!("\nExample 4: Switching between training and inference modes");
149
150    // Create dropout layer with p=0.5
151    let mut switchable_dropout = Dropout::new(0.5, &mut rng)?;
152
153    // Create some input data
154    let test_input = Array2::<f32>::from_elem((1, 10), 1.0);
155
156    // Training mode (default)
157    let training_output = switchable_dropout.forward(&test_input.clone().into_dyn())?;
158
159    // Count non-zero elements in training mode
160    let training_nonzero = training_output.iter().filter(|&&x| x != 0.0).count();
161
162    // Switch to inference mode
163    switchable_dropout.set_training(false);
164    let inference_output = switchable_dropout.forward(&test_input.clone().into_dyn())?;
165
166    // Count non-zero elements in inference mode
167    let inference_nonzero = inference_output.iter().filter(|&&x| x != 0.0).count();
168
169    println!("Training mode: {} of 10 elements kept", training_nonzero);
170    println!("Inference mode: {} of 10 elements kept", inference_nonzero);
171
172    // In inference mode, all elements should be preserved
173    assert_eq!(inference_nonzero, 10);
174
175    println!("\nDropout implementation demonstration completed successfully!");
176
177    Ok(())
178}