C#使用TensorFlow.NET训练自己的数据集的方法

2020-03-22 20:01:38王冬梅

计算图构建

构建CNN静态计算图,其中学习率每n轮Epoch进行1次递减。

#region BuildGraph
public Graph BuildGraph()
{
 var graph = new Graph().as_default();

 tf_with(tf.name_scope("Input"), delegate
   {
    x = tf.placeholder(tf.float32, shape: (-1, img_h, img_w, n_channels), name: "X");
    y = tf.placeholder(tf.float32, shape: (-1, n_classes), name: "Y");
   });

 var conv1 = conv_layer(x, filter_size1, num_filters1, stride1, name: "conv1");
 var pool1 = max_pool(conv1, ksize: 2, stride: 2, name: "pool1");
 var conv2 = conv_layer(pool1, filter_size2, num_filters2, stride2, name: "conv2");
 var pool2 = max_pool(conv2, ksize: 2, stride: 2, name: "pool2");
 var layer_flat = flatten_layer(pool2);
 var fc1 = fc_layer(layer_flat, h1, "FC1", use_relu: true);
 var output_logits = fc_layer(fc1, n_classes, "OUT", use_relu: false);

 //Some important parameter saved with graph , easy to load later
 var img_h_t = tf.constant(img_h, name: "img_h");
 var img_w_t = tf.constant(img_w, name: "img_w");
 var img_mean_t = tf.constant(img_mean, name: "img_mean");
 var img_std_t = tf.constant(img_std, name: "img_std");
 var channels_t = tf.constant(n_channels, name: "img_channels");

 //learning rate decay
 gloabl_steps = tf.Variable(0, trainable: false);
 learning_rate = tf.Variable(learning_rate_base);

 //create train images graph
 tf_with(tf.variable_scope("LoadImage"), delegate
   {
    decodeJpeg = tf.placeholder(tf.@byte, name: "DecodeJpeg");
    var cast = tf.cast(decodeJpeg, tf.float32);
    var dims_expander = tf.expand_dims(cast, 0);
    var resize = tf.constant(new int[] { img_h, img_w });
    var bilinear = tf.image.resize_bilinear(dims_expander, resize);
    var sub = tf.subtract(bilinear, new float[] { img_mean });
    normalized = tf.divide(sub, new float[] { img_std }, name: "normalized");
   });

 tf_with(tf.variable_scope("Train"), delegate
   {
    tf_with(tf.variable_scope("Loss"), delegate
      {
       loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels: y, logits: output_logits), name: "loss");
      });

    tf_with(tf.variable_scope("Optimizer"), delegate
      {
       optimizer = tf.train.AdamOptimizer(learning_rate: learning_rate, name: "Adam-op").minimize(loss, global_step: gloabl_steps);
      });

    tf_with(tf.variable_scope("Accuracy"), delegate
      {
       var correct_prediction = tf.equal(tf.argmax(output_logits, 1), tf.argmax(y, 1), name: "correct_pred");
       accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32), name: "accuracy");
      });

    tf_with(tf.variable_scope("Prediction"), delegate
      {
       cls_prediction = tf.argmax(output_logits, axis: 1, name: "predictions");
       prob = tf.nn.softmax(output_logits, axis: 1, name: "prob");
      });
   });
 return graph;
}

/// <summary>
/// Create a 2D convolution layer
/// </summary>
/// <param name="x">input from previous layer</param>
/// <param name="filter_size">size of each filter</param>
/// <param name="num_filters">number of filters(or output feature maps)</param>
/// <param name="stride">filter stride</param>
/// <param name="name">layer name</param>
/// <returns>The output array</returns>
private Tensor conv_layer(Tensor x, int filter_size, int num_filters, int stride, string name)
{
 return tf_with(tf.variable_scope(name), delegate
     {

      var num_in_channel = x.shape[x.NDims - 1];
      var shape = new[] { filter_size, filter_size, num_in_channel, num_filters };
      var W = weight_variable("W", shape);
      // var tf.summary.histogram("weight", W);
      var b = bias_variable("b", new[] { num_filters });
      // tf.summary.histogram("bias", b);
      var layer = tf.nn.conv2d(x, W,
            strides: new[] { 1, stride, stride, 1 },
            padding: "SAME");
      layer += b;
      return tf.nn.relu(layer);
     });
}

/// <summary>
/// Create a max pooling layer
/// </summary>
/// <param name="x">input to max-pooling layer</param>
/// <param name="ksize">size of the max-pooling filter</param>
/// <param name="stride">stride of the max-pooling filter</param>
/// <param name="name">layer name</param>
/// <returns>The output array</returns>
private Tensor max_pool(Tensor x, int ksize, int stride, string name)
{
 return tf.nn.max_pool(x,
       ksize: new[] { 1, ksize, ksize, 1 },
       strides: new[] { 1, stride, stride, 1 },
       padding: "SAME",
       name: name);
}

/// <summary>
/// Flattens the output of the convolutional layer to be fed into fully-connected layer
/// </summary>
/// <param name="layer">input array</param>
/// <returns>flattened array</returns>
private Tensor flatten_layer(Tensor layer)
{
 return tf_with(tf.variable_scope("Flatten_layer"), delegate
     {
      var layer_shape = layer.TensorShape;
      var num_features = layer_shape[new Slice(1, 4)].size;
      var layer_flat = tf.reshape(layer, new[] { -1, num_features });

      return layer_flat;
     });
}

/// <summary>
/// Create a weight variable with appropriate initialization
/// </summary>
/// <param name="name"></param>
/// <param name="shape"></param>
/// <returns></returns>
private RefVariable weight_variable(string name, int[] shape)
{
 var initer = tf.truncated_normal_initializer(stddev: 0.01f);
 return tf.get_variable(name,
       dtype: tf.float32,
       shape: shape,
       initializer: initer);
}

/// <summary>
/// Create a bias variable with appropriate initialization
/// </summary>
/// <param name="name"></param>
/// <param name="shape"></param>
/// <returns></returns>
private RefVariable bias_variable(string name, int[] shape)
{
 var initial = tf.constant(0f, shape: shape, dtype: tf.float32);
 return tf.get_variable(name,
       dtype: tf.float32,
       initializer: initial);
}

/// <summary>
/// Create a fully-connected layer
/// </summary>
/// <param name="x">input from previous layer</param>
/// <param name="num_units">number of hidden units in the fully-connected layer</param>
/// <param name="name">layer name</param>
/// <param name="use_relu">boolean to add ReLU non-linearity (or not)</param>
/// <returns>The output array</returns>
private Tensor fc_layer(Tensor x, int num_units, string name, bool use_relu = true)
{
 return tf_with(tf.variable_scope(name), delegate
     {
      var in_dim = x.shape[1];

      var W = weight_variable("W_" + name, shape: new[] { in_dim, num_units });
      var b = bias_variable("b_" + name, new[] { num_units });

      var layer = tf.matmul(x, W) + b;
      if (use_relu)
       layer = tf.nn.relu(layer);

      return layer;
     });
}
#endregion