@@ -28,16 +28,131 @@ pub struct MLP {
2828}
2929
3030impl MLP {
31+ /// Create a new MLP with given layer sizes.
32+ pub fn new ( input_size : usize , hidden_sizes : Vec < usize > , output_size : usize ) -> Self {
33+ let mut weights = Vec :: new ( ) ;
34+ let mut biases = Vec :: new ( ) ;
35+ let mut prev_size = input_size;
36+
37+ // Initialize weights and biases
38+ for & hidden_size in & hidden_sizes {
39+ let mut layer_weights = vec ! [ vec![ 0.0 ; prev_size] ; hidden_size] ;
40+ let mut seed = 42u64 ;
41+
42+ // Xavier initialization
43+ let limit = ( 6.0 / ( prev_size + hidden_size) as f32 ) . sqrt ( ) ;
44+ for row in & mut layer_weights {
45+ for w in row {
46+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
47+ let rand = ( ( seed / 65536 ) % 32768 ) as f32 / 32768.0 ;
48+ * w = ( rand - 0.5 ) * 2.0 * limit;
49+ }
50+ }
51+
52+ weights. push ( layer_weights) ;
53+ biases. push ( vec ! [ 0.0 ; hidden_size] ) ;
54+ prev_size = hidden_size;
55+ }
56+
57+ // Output layer
58+ let mut output_weights = vec ! [ vec![ 0.0 ; prev_size] ; output_size] ;
59+ let mut seed = 42u64 ;
60+ let limit = ( 6.0 / ( prev_size + output_size) as f32 ) . sqrt ( ) ;
61+ for row in & mut output_weights {
62+ for w in row {
63+ seed = seed. wrapping_mul ( 1103515245 ) . wrapping_add ( 12345 ) ;
64+ let rand = ( ( seed / 65536 ) % 32768 ) as f32 / 32768.0 ;
65+ * w = ( rand - 0.5 ) * 2.0 * limit;
66+ }
67+ }
68+
69+ weights. push ( output_weights) ;
70+ biases. push ( vec ! [ 0.0 ; output_size] ) ;
71+
72+ Self {
73+ input_size,
74+ hidden_sizes,
75+ output_size,
76+ weights,
77+ biases,
78+ }
79+ }
80+
3181 /// FORWARD: Computes the network output for a given input vector.
3282 /// Applies ReLU activation to hidden layers and returns raw logits.
3383 pub fn forward ( & self , input : & [ f32 ] ) -> Vec < f32 > {
34- // ... [Matrix-vector multiplication loop]
84+ let mut activation = input. to_vec ( ) ;
85+
86+ // Forward pass through all layers
87+ for ( i, layer_weights) in self . weights . iter ( ) . enumerate ( ) {
88+ let is_output = i == self . weights . len ( ) - 1 ;
89+ let mut next_activation = self . biases [ i] . clone ( ) ;
90+
91+ // Matrix-vector multiplication
92+ for ( j, weights_row) in layer_weights. iter ( ) . enumerate ( ) {
93+ let mut sum = 0.0 ;
94+ for ( k, w) in weights_row. iter ( ) . enumerate ( ) {
95+ sum += w * activation[ k] ;
96+ }
97+ next_activation[ j] += sum;
98+ }
99+
100+ // Apply activation function
101+ if !is_output {
102+ // ReLU for hidden layers
103+ activation = next_activation. iter ( ) . map ( |& x| x. max ( 0.0 ) ) . collect ( ) ;
104+ } else {
105+ // Linear for output layer
106+ activation = next_activation;
107+ }
108+ }
109+
35110 activation
36111 }
37112
38113 /// SOFTMAX: Normalizes logits into a probability distribution.
39114 /// Returns a vector where `sum(values) == 1.0`.
40115 pub fn softmax ( values : & [ f32 ] ) -> Vec < f32 > {
41- // ... [Exponential normalization implementation]
116+ let max = values. iter ( ) . copied ( ) . fold ( f32:: NEG_INFINITY , f32:: max) ;
117+ let exp_values: Vec < f32 > = values. iter ( ) . map ( |v| ( v - max) . exp ( ) ) . collect ( ) ;
118+ let sum: f32 = exp_values. iter ( ) . sum ( ) ;
119+
120+ if sum > 0.0 {
121+ exp_values. iter ( ) . map ( |e| e / sum) . collect ( )
122+ } else {
123+ exp_values
124+ }
125+ }
126+
127+ /// Compute loss and gradients via backpropagation.
128+ pub fn backward ( & self , input : & [ f32 ] , target : & [ f32 ] ) -> ( f32 , Vec < Vec < Vec < f32 > > > ) {
129+ let output = self . forward ( input) ;
130+
131+ // Cross-entropy loss
132+ let mut loss = 0.0 ;
133+ for ( o, t) in output. iter ( ) . zip ( target. iter ( ) ) {
134+ let o = o. clamp ( 1e-6 , 1.0 - 1e-6 ) ;
135+ loss -= t * o. ln ( ) ;
136+ }
137+
138+ // Placeholder gradients (proper backprop deferred to Phase 2)
139+ let gradients = vec ! [ vec![ vec![ 0.0 ; input. len( ) ] ; self . output_size] ; self . weights. len( ) ] ;
140+
141+ ( loss, gradients)
142+ }
143+
144+ /// Update weights using gradients.
145+ pub fn update ( & mut self , _gradients : & [ Vec < Vec < f32 > > ] , _learning_rate : f32 ) {
146+ // Phase 2 implementation
147+ }
148+
149+ /// Argmax: Return the index of the maximum value.
150+ pub fn argmax ( values : & [ f32 ] ) -> usize {
151+ values
152+ . iter ( )
153+ . enumerate ( )
154+ . max_by ( |( _, a) , ( _, b) | a. partial_cmp ( b) . unwrap_or ( std:: cmp:: Ordering :: Equal ) )
155+ . map ( |( i, _) | i)
156+ . unwrap_or ( 0 )
42157 }
43158}
0 commit comments