# 更深的 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}) ``` 训练该模型可能需要几个小时,因此您可能希望在下一节之前立即开始。