@@ -14,6 +14,7 @@ You may obtain a copy of the License at
1414 limitations under the License.
1515******************************************************************************/
1616
17+ using NumSharp ;
1718using System ;
1819using System . Collections . Generic ;
1920using System . Text ;
@@ -65,7 +66,7 @@ public class DigitRecognitionCNN : IExample
6566
6667
6768 Tensor x , y ;
68- Tensor loss , accuracy ;
69+ Tensor loss , accuracy , cls_prediction ;
6970 Operation optimizer ;
7071
7172 int display_freq = 100 ;
@@ -90,47 +91,148 @@ public Graph BuildGraph()
9091 {
9192 var graph = new Graph ( ) . as_default ( ) ;
9293
93- // Placeholders for inputs (x) and outputs(y)
94- x = tf . placeholder ( tf . float32 , shape : ( - 1 , img_size_flat ) , name : "X" ) ;
95- y = tf . placeholder ( tf . float32 , shape : ( - 1 , n_classes ) , name : "Y" ) ;
94+ with ( tf . name_scope ( "Input" ) , delegate
95+ {
96+ // Placeholders for inputs (x) and outputs(y)
97+ x = tf . placeholder ( tf . float32 , shape : ( - 1 , img_h , img_w , n_channels ) , name : "X" ) ;
98+ y = tf . placeholder ( tf . float32 , shape : ( - 1 , n_classes ) , name : "Y" ) ;
99+ } ) ;
96100
97- // Create a fully-connected layer with h1 nodes as hidden layer
98- var fc1 = fc_layer ( x , h1 , "FC1" , use_relu : true ) ;
99- // Create a fully-connected layer with n_classes nodes as output layer
101+ var conv1 = conv_layer ( x , filter_size1 , num_filters1 , stride1 , name : "conv1" ) ;
102+ var pool1 = max_pool ( conv1 , ksize : 2 , stride : 2 , name : "pool1" ) ;
103+ var conv2 = conv_layer ( pool1 , filter_size2 , num_filters2 , stride2 , name : "conv2" ) ;
104+ var pool2 = max_pool ( conv2 , ksize : 2 , stride : 2 , name : "pool2" ) ;
105+ var layer_flat = flatten_layer ( pool2 ) ;
106+ var fc1 = fc_layer ( layer_flat , h1 , "FC1" , use_relu : true ) ;
100107 var output_logits = fc_layer ( fc1 , n_classes , "OUT" , use_relu : false ) ;
101- // Define the loss function, optimizer, and accuracy
102- var logits = tf . nn . softmax_cross_entropy_with_logits ( labels : y , logits : output_logits ) ;
103- loss = tf . reduce_mean ( logits , name : "loss" ) ;
104- optimizer = tf . train . AdamOptimizer ( learning_rate : learning_rate , name : "Adam-op" ) . minimize ( loss ) ;
105- var correct_prediction = tf . equal ( tf . argmax ( output_logits , 1 ) , tf . argmax ( y , 1 ) , name : "correct_pred" ) ;
106- accuracy = tf . reduce_mean ( tf . cast ( correct_prediction , tf . float32 ) , name : "accuracy" ) ;
107108
108- // Network predictions
109- var cls_prediction = tf . argmax ( output_logits , axis : 1 , name : "predictions" ) ;
109+ with ( tf . variable_scope ( "Train" ) , delegate
110+ {
111+ with ( tf . variable_scope ( "Loss" ) , delegate
112+ {
113+ loss = tf . reduce_mean ( tf . nn . softmax_cross_entropy_with_logits ( labels : y , logits : output_logits ) , name : "loss" ) ;
114+ } ) ;
115+
116+ with ( tf . variable_scope ( "Optimizer" ) , delegate
117+ {
118+ optimizer = tf . train . AdamOptimizer ( learning_rate : learning_rate , name : "Adam-op" ) . minimize ( loss ) ;
119+ } ) ;
120+
121+ with ( tf . variable_scope ( "Accuracy" ) , delegate
122+ {
123+ var correct_prediction = tf . equal ( tf . argmax ( output_logits , 1 ) , tf . argmax ( y , 1 ) , name : "correct_pred" ) ;
124+ accuracy = tf . reduce_mean ( tf . cast ( correct_prediction , tf . float32 ) , name : "accuracy" ) ;
125+ } ) ;
126+
127+ with ( tf . variable_scope ( "Prediction" ) , delegate
128+ {
129+ cls_prediction = tf . argmax ( output_logits , axis : 1 , name : "predictions" ) ;
130+ } ) ;
131+ } ) ;
110132
111133 return graph ;
112134 }
113135
114- private Tensor fc_layer ( Tensor x , int num_units , string name , bool use_relu = true )
136+ /// <summary>
137+ /// Create a 2D convolution layer
138+ /// </summary>
139+ /// <param name="x">input from previous layer</param>
140+ /// <param name="filter_size">size of each filter</param>
141+ /// <param name="num_filters">number of filters(or output feature maps)</param>
142+ /// <param name="stride">filter stride</param>
143+ /// <param name="name">layer name</param>
144+ /// <returns>The output array</returns>
145+ private Tensor conv_layer ( Tensor x , int filter_size , int num_filters , int stride , string name )
146+ {
147+ return with ( tf . variable_scope ( name ) , delegate {
148+
149+ var num_in_channel = x . shape [ x . NDims - 1 ] ;
150+ var shape = new [ ] { filter_size , filter_size , num_in_channel , num_filters } ;
151+ var W = weight_variable ( "W" , shape ) ;
152+ // var tf.summary.histogram("weight", W);
153+ var b = bias_variable ( "b" , new [ ] { num_filters } ) ;
154+ // tf.summary.histogram("bias", b);
155+ var layer = tf . nn . conv2d ( x , W ,
156+ strides : new [ ] { 1 , stride , stride , 1 } ,
157+ padding : "SAME" ) ;
158+ layer += b ;
159+ return tf . nn . relu ( layer ) ;
160+ } ) ;
161+
162+ }
163+
164+ /// <summary>
165+ /// Create a max pooling layer
166+ /// </summary>
167+ /// <param name="x">input to max-pooling layer</param>
168+ /// <param name="ksize">size of the max-pooling filter</param>
169+ /// <param name="stride">stride of the max-pooling filter</param>
170+ /// <param name="name">layer name</param>
171+ /// <returns>The output array</returns>
172+ private Tensor max_pool ( Tensor x , int ksize , int stride , string name )
115173 {
116- var in_dim = x . shape [ 1 ] ;
174+ return tf . nn . max_pool ( x ,
175+ ksize : new [ ] { 1 , ksize , ksize , 1 } ,
176+ strides : new [ ] { 1 , stride , stride , 1 } ,
177+ padding : "SAME" ,
178+ name : name ) ;
179+ }
117180
181+ /// <summary>
182+ /// Flattens the output of the convolutional layer to be fed into fully-connected layer
183+ /// </summary>
184+ /// <param name="layer">input array</param>
185+ /// <returns>flattened array</returns>
186+ private Tensor flatten_layer ( Tensor layer )
187+ {
188+ return with ( tf . variable_scope ( "Flatten_layer" ) , delegate
189+ {
190+ var layer_shape = layer . TensorShape ;
191+ var num_features = layer_shape [ new Slice ( 1 , 4 ) ] . Size ;
192+ var layer_flat = tf . reshape ( layer , new [ ] { - 1 , num_features } ) ;
193+
194+ return layer_flat ;
195+ } ) ;
196+ }
197+
198+ private Tensor weight_variable ( string name , int [ ] shape )
199+ {
118200 var initer = tf . truncated_normal_initializer ( stddev : 0.01f ) ;
119- var W = tf . get_variable ( "W_" + name ,
120- dtype : tf . float32 ,
121- shape : ( in_dim , num_units ) ,
122- initializer : initer ) ;
201+ return tf . get_variable ( name ,
202+ dtype : tf . float32 ,
203+ shape : shape ,
204+ initializer : initer ) ;
205+ }
123206
124- var initial = tf . constant ( 0f , num_units ) ;
125- var b = tf . get_variable ( "b_" + name ,
126- dtype : tf . float32 ,
127- initializer : initial ) ;
207+ /// <summary>
208+ /// Create a bias variable with appropriate initialization
209+ /// </summary>
210+ /// <param name="name"></param>
211+ /// <param name="shape"></param>
212+ /// <returns></returns>
213+ private Tensor bias_variable ( string name , int [ ] shape )
214+ {
215+ var initial = tf . constant ( 0f , shape : shape , dtype : tf . float32 ) ;
216+ return tf . get_variable ( name ,
217+ dtype : tf . float32 ,
218+ initializer : initial ) ;
219+ }
220+
221+ private Tensor fc_layer ( Tensor x , int num_units , string name , bool use_relu = true )
222+ {
223+ return with ( tf . variable_scope ( name ) , delegate
224+ {
225+ var in_dim = x . shape [ 1 ] ;
128226
129- var layer = tf . matmul ( x , W ) + b ;
130- if ( use_relu )
131- layer = tf . nn . relu ( layer ) ;
227+ var W = weight_variable ( "W_" + name , shape : new [ ] { in_dim , num_units } ) ;
228+ var b = bias_variable ( "b_" + name , new [ ] { num_units } ) ;
132229
133- return layer ;
230+ var layer = tf . matmul ( x , W ) + b ;
231+ if ( use_relu )
232+ layer = tf . nn . relu ( layer ) ;
233+
234+ return layer ;
235+ } ) ;
134236 }
135237
136238 public Graph ImportGraph ( ) => throw new NotImplementedException ( ) ;
0 commit comments