19.md 5.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
# 更深的 CNN

在本节中,我们将向模型添加另一个卷积层。 不用担心,我们将逐步遍历参数以使尺寸调整一致,并且我们将学习什么是 dropout 训练。

## 将 CNN 的一层添加到另一层

与往常一样,在启动新模型时,进行一个新的 IPython 会话并执行直到`num_filters1`的代码。 太好了,现在您都可以开始学习了。 让我们跳入卷积模型。

我们为何不抱有雄心,将第一个卷积层设置为具有`16`过滤器,远远超过旧模型中的`4`。 但是,这次我们将使用较小的窗口大小。 只有 3x3。 另请注意,我们将某些变量名称(例如`num_filters`更改为`num_filters1`)。 这是因为我们将在短时间内拥有另一个卷积层,并且我们可能希望在每个卷积层上使用不同数量的过滤器。 该层的其余部分与以前完全一样,我们可以进行卷积并进行 2x2 max 池化,并使用整流的线性激活单元。

现在,我们添加另一个卷积层。 一些模型先进行几次卷积,然后再进行池化,另一些模型先进行一次卷积,再进行一次池化,再进行一次卷积,依此类推。 我们在这里做后者。 假设您需要四个滤镜和一个 3x3 的窗口。 这很容易产生权重; 与上一层的唯一大不同是我们现在有许多输入通道,请参见`num_filters1`

```py
# Conv layer 2
num_filters2 = 4
winx2 = 3
winy2 = 3
W2 = tf.Variable(tf.truncated_normal(
    [winx2, winy2, num_filters1, num_filters2],
    stddev=1./math.sqrt(winx2*winy2)))
b2 = tf.Variable(tf.constant(0.1,
     shape=[num_filters2]))
```

这是因为我们有`16`输入通道来自上一层。 如果我们使用`num_filters1 = 8`,则只有`8`输入通道。 将此视为我们将要建立的低级特征。 请记住,通道的数量和输入就像颜色的数量一样,因此,如果您要这样考虑,可能会有所帮助。

当我们进行实际的第二个卷积层时,请确保传入第一个池化层`p1`的输出。 现在,这可以进入新的`relu`激活函数,然后是另一个池化层。 像往常一样,我们使用有效填充进行最大 2x2 的池化:

```py
# 3x3 convolution, pad with zeros on edges
p1w2 = tf.nn.conv2d(p1, W2,
       strides=[1, 1, 1, 1], padding='SAME')
h1 = tf.nn.relu(p1w2 + b2)
# 2x2 Max pooling, no padding on edges
p2 = tf.nn.max_pool(h1, ksize=[1, 2, 2, 1],
     strides=[1, 2, 2, 1], padding='VALID')
```

展平卷积的池化输出也遵循与最后一个模型相同的过程。 但是,这次,我们当然致力于合并输出 2。 将其所有参数从窗口中的所有特征转换为一个大向量:

```py
# Need to flatten convolutional output
p2_size = np.product(
        [s.value for s in p2.get_shape()[1:]])
p2f = tf.reshape(p2, [-1, p2_size ])
```

现在,就像在前面的部分中所做的那样,将密集连接的层插入到我们的神经网络中。 只要确保更新变量名即可。

```py
# Dense layer
num_hidden = 32
W3 = tf.Variable(tf.truncated_normal(
     [p2_size, num_hidden],
     stddev=2./math.sqrt(p2_size)))
b3 = tf.Variable(tf.constant(0.2,
     shape=[num_hidden]))
h3 = tf.nn.relu(tf.matmul(p2f,W3) + b3)
```

现在,我们看到了与我们使用的相同的`tf.nn.dropout`,但在上一个模型中没有解释:

```py
# Drop out training
keep_prob = tf.placeholder("float")
h3_drop = tf.nn.dropout(h3, keep_prob)
```

dropout 是一种从模型中暂时切断神经元的方法。 我们在训练过程中这样做是为了避免过拟合。 每批 TensorFlow 将在此连接层选择不同的神经元输出以进行删除。 面对训练期间的细微变化,这有助于模型变得健壮。 `keep_prob`是保持特定神经元输出的概率。 在训练过程中通常将其设置为`0.5`

再一次,最终的逻辑回归层和训练节点代码与之前的相同:

```py
# Output Layer
W4 = tf.Variable(tf.truncated_normal(
     [num_hidden, 5],
     stddev=1./math.sqrt(num_hidden)))
b4 = tf.Variable(tf.constant(0.1,shape=[5]))

# Just initialize
sess.run(tf.initialize_all_variables())

# Define model
y = tf.nn.softmax(tf.matmul(h3_drop,W4) + b4)

### End model specification, begin training code

# Climb on cross-entropy
cross_entropy = tf.reduce_mean(
        tf.nn.softmax_cross_entropy_with_logits(
        y + 1e-50, y_))

# How we train
train_step = tf.train.GradientDescentOptimizer(
             0.01).minimize(cross_entropy)

# Define accuracy
correct_prediction = tf.equal(tf.argmax(y,1),
                              tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(
           correct_prediction, "float"))
```

您现在可以执行该操作。 现在,我们可以训练我们的完整卷积神经网络,这是到目前为止建模的顶点:

```py
# Actually train
epochs = 6000
train_acc = np.zeros(epochs//10)
test_acc = np.zeros(epochs//10)
for i in tqdm(range(epochs), ascii=True):
    # Record summary data, and the accuracy
    if i % 10 == 0:  
        # Check accuracy on train set
        A = accuracy.eval(feed_dict={x: train,
            y_: onehot_train, keep_prob: 1.0})
        train_acc[i//10] = A
        # And now the validation set
        A = accuracy.eval(feed_dict={x: test,
            y_: onehot_test, keep_prob: 1.0})
        test_acc[i//10] = A
    train_step.run(feed_dict={x: train,\
        y_: onehot_train, keep_prob: 0.5})
```

训练该模型可能需要几个小时,因此您可能希望在下一节之前立即开始。