157.md 6.4 KB
Newer Older
W
wizardforcel 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
# 使用 TensorFlow 的用于 MNIST 的 LeNet CNN

在 TensorFlow 中,应用以下步骤为 MNIST 数据构建基于 LeNet 的 CNN 模型:

1.  定义超参数,以及 x 和 y 的占位符(输入图像和输出标签) :

```py
n_classes = 10 # 0-9 digits
n_width = 28
n_height = 28
n_depth = 1
n_inputs = n_height * n_width * n_depth # total pixels
learning_rate = 0.001
n_epochs = 10
batch_size = 100
n_batches = int(mnist.train.num_examples/batch_size)

# input images shape: (n_samples,n_pixels)
x = tf.placeholder(dtype=tf.float32, name="x", shape=[None, n_inputs]) 
# output labels
y = tf.placeholder(dtype=tf.float32, name="y", shape=[None, n_classes])
```

将输入 x 重塑为形状(`n_samples``n_width``n_height``n_depth`):

```py
x_ = tf.reshape(x, shape=[-1, n_width, n_height, n_depth])
```

1.  使用形状为 4 x 4 的 32 个内核定义第一个卷积层,从而生成 32 个特征图。

*   首先,定义第一个卷积层的权重和偏差。我们使用正态分布填充参数:

```py
layer1_w = tf.Variable(tf.random_normal(shape=[4,4,n_depth,32],
            stddev=0.1),name='l1_w')
layer1_b = tf.Variable(tf.random_normal([32]),name='l1_b')
```

*   接下来,用 `tf.nn.conv2d`函数定义卷积层。函数参数`stride`定义了内核张量在每个维度中应该滑动的元素。维度顺序由`data_format`确定,可以是`'NHWC'``'NCHW'`(默认为`'NHWC'`)。
    通常,`stride`中的第一个和最后一个元素设置为“1”。函数参数`padding`可以是`SAME``VALID``SAME` `padding`表示输入将用零填充,以便在卷积后输出与输入的形状相同。使用`tf.nn.relu()`函数添加`relu`激活:

```py
layer1_conv = tf.nn.relu(tf.nn.conv2d(x_,layer1_w,
                                      strides=[1,1,1,1],
                                      padding='SAME'
                                     ) + 
                         layer1_b 
                        )
```

*   使用 `tf.nn.max_pool()` 函数定义第一个池化层。参数 `ksize` 表示使用 2×2×1 个区域的合并操作,参数 `stride` 表示将区域滑动 2×2×1 个像素。因此,区域彼此不重叠。由于我们使用 `max_pool` ,池化操作选择 2 x 2 x 1 区域中的最大值:

```py
layer1_pool = tf.nn.max_pool(layer1_conv,ksize=[1,2,2,1],
                 strides=[1,2,2,1],padding='SAME')
```

第一个卷积层产生 32 个大小为 28 x 28 x 1 的特征图,然后池化成 32 x 14 x 14 x 1 的数据。

1.  定义第二个卷积层,它将此数据作为输入并生成 64 个特征图。

*   首先,定义第二个卷积层的权重和偏差。我们用正态分布填充参数:

```py
layer2_w = tf.Variable(tf.random_normal(shape=[4,4,32,64],
           stddev=0.1),name='l2_w')
layer2_b = tf.Variable(tf.random_normal([64]),name='l2_b')
```

*   接下来,用 `tf.nn.conv2d`函数定义卷积层:

```py
layer2_conv = tf.nn.relu(tf.nn.conv2d(layer1_pool,
                                      layer2_w,
                                      strides=[1,1,1,1],
                                      padding='SAME'
                                     ) + 
                          layer2_b
                        )
```

*`tf.nn.max_pool`函数定义第二个池化层:

```py
layer2_pool = tf.nn.max_pool(layer2_conv,
                             ksize=[1,2,2,1],
                             strides=[1,2,2,1],
                             padding='SAME'
                            )
```

第二卷积层的输出形状为 64 ×14×14×1,然后池化成 64×7×7×1 的形状的输出。

1.  在输入 1024 个神经元的完全连接层之前重新整形此输出,以产生大小为 1024 的扁平输出:

```py
layer3_w = tf.Variable(tf.random_normal(shape=[64*7*7*1,1024],
                       stddev=0.1),name='l3_w')
layer3_b = tf.Variable(tf.random_normal([1024]),name='l3_b')
layer3_fc = tf.nn.relu(tf.matmul(tf.reshape(layer2_pool,
            [-1, 64*7*7*1]),layer3_w) + layer3_b)
```

1.  完全连接层的输出馈入具有 10 个输出的线性输出层。我们在这一层没有使用 softmax,因为我们的损失函数自动将 softmax 应用于输出:

```py
layer4_w = tf.Variable(tf.random_normal(shape=[1024, n_classes],
                                        stddev=0.1),name='l)
layer4_b = tf.Variable(tf.random_normal([n_classes]),name='l4_b')
layer4_out = tf.matmul(layer3_fc,layer4_w)+layer4_b
```

这创建了我们保存在变量`model`中的第一个 CNN 模型:

```py
model = layer4_out
```

鼓励读者探索具有不同超参数值的 TensorFlow 中可用的不同卷积和池操作符。

为了定义损失,我们使用`tf.nn.softmax_cross_entropy_with_logits`函数,对于优化器,我们使用`AdamOptimizer`函数。您应该尝试探索 TensorFlow 中可用的不同优化器函数。

```py
entropy = tf.nn.softmax_cross_entropy_with_logits(logits=model, labels=y)
loss = tf.reduce_mean(entropy)
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss)
```

最后,我们通过迭代`n_epochs`来训练模型,并且在`n_batches`上的每个周期列中,每批`batch_size`的大小:

```py
with tf.Session() as tfs:
    tf.global_variables_initializer().run()
    for epoch in range(n_epochs):
        total_loss = 0.0
        for batch in range(n_batches):
            batch_x,batch_y = mnist.train.next_batch(batch_size)
            feed_dict={x:batch_x, y: batch_y}
            batch_loss,_ = tfs.run([loss, optimizer],
                                   feed_dict=feed_dict)
            total_loss += batch_loss 
        average_loss = total_loss / n_batches
        print("Epoch: {0:04d} loss = {1:0.6f}".format(epoch,average_loss))
    print("Model Trained.")

    predictions_check = tf.equal(tf.argmax(model,1),tf.argmax(y,1))
    accuracy = tf.reduce_mean(tf.cast(predictions_check, tf.float32))
    feed_dict = {x:mnist.test.images, y:mnist.test.labels}
    print("Accuracy:", accuracy.eval(feed_dict=feed_dict))
```

我们得到以下输出:

```py
Epoch: 0000   loss = 1.418295
Epoch: 0001   loss = 0.088259
Epoch: 0002   loss = 0.055410
Epoch: 0003   loss = 0.042798
Epoch: 0004   loss = 0.030471
Epoch: 0005   loss = 0.023837
Epoch: 0006   loss = 0.019800
Epoch: 0007   loss = 0.015900
Epoch: 0008   loss = 0.012918
Epoch: 0009   loss = 0.010322
Model Trained.
Accuracy: 0.9884
```

现在,与我们在前几章中看到的方法相比,这是一个非常好的准确性。从图像数据中学习 CNN 模型是不是很神奇?