关于神经网络的思考

神经网络已经被证明它能够拟合任意的函数,所以它的用途十分广泛。任意的输入X,只要它与Y输出有一个对应关系F,即Y=F(X)时,F即是我们要拟合的目标函数。特别是这种对应关系十分复杂时,神经网络就显示出它的强大来。比如语音信号,经过采样之后只是一维的数据,很难直接找到这种从声音到文字的对应关系。如果这种对应关系根本不存在的话,神经网络也没有办法找出一种对应关系。比如输入一张人脸,预测它犯罪的可能性,如果是婴儿,它的准确性一定很低,因为婴儿脸部没有特征可以与犯罪有对应关系。但是成人就不一定,比如长期吸食毒品的人,脸部会出现一些明显变化,肤色或者皮肤纹理或者口歪眼斜等等特征,这就暗示出脸部与犯罪存在一定的联系,这种联系可以用Y=F(X)来表示,这个F就是我们要拟合的目标函数。另外我们的输出Y一定是可分的,如果一个数据集的噪声很大,对于训练神经网络是非常不利的。
CNN的原理随着卷积核(filter)可视化可以稍微窥探一些端倪,一个filter实际上是为了探测一个feature,filter提取的特征是其前一层特征的组合排列,依次向前类推。所以在filter size和步长的选择上会有一定的规律可以遵循。
1.如果选择一个filter的size过大,则非常不利于feature的提取,因为过大的filter会导致输入层的信息损失严重,严重到网络没有办法基于这些过少的特征进行分类。极端情况是filter的size和输入的size一样大,这样整个输入样本经过卷积之后变成只有一维的数据,记作X',这个损失极其严重的X'和Y之间已经不存在对应关系F,目标函数已经不存在了,所以这个神经网络根本没有办法工作。

我做了一个实验,基于minist数据集,代码如下:

    modelCNN = Sequential()
    modelCNN.add(Convolution2D(1, 28, 28, input_shape=(28,28,1)))#这里使用1个filter,每个大小为28x28。输入图片大小28x28 尺寸相同
    modelCNN.add(Flatten())
    modelCNN.add(Dense(output_dim=500))
    modelCNN.add(Activation("sigmoid"))
    modelCNN.add(Dense(output_dim=500))
    modelCNN.add(Activation("sigmoid"))
    modelCNN.add(Dense(output_dim=10))
    modelCNN.add(Activation("sigmoid"))

    modelCNN.compile(loss='categorical_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])

    # input image dimensions
    img_rows, img_cols = 28, 28
    batch_size = 200
    num_classes = 10

    # the data, shuffled and split between train and test sets
    (x_train, y_train), (x_test, y_test) = mnist.load_data()

    if K.image_data_format() == 'channels_first':
        x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
        x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
        input_shape = (1, img_rows, img_cols)
    else:
        x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
        x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
        input_shape = (img_rows, img_cols, 1)

    x_train = x_train.astype('float32')
    x_test = x_test.astype('float32')
    x_train /= 255
    x_test /= 255
    print('x_train shape:', x_train.shape)
    print(x_train.shape[0], 'train samples')
    print(x_test.shape[0], 'test samples')

    # convert class vectors to binary class matrices
    y_train = keras.utils.to_categorical(y_train, num_classes)
    y_test = keras.utils.to_categorical(y_test, num_classes)

    tb_cb = keras.callbacks.TensorBoard(log_dir='./logs', histogram_freq=1, write_graph=True, write_images=False,
                                        embeddings_freq=0, embeddings_layer_names=None, embeddings_metadata=None)
    #es_cb = keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0.09, patience=5, verbose=0, mode='auto')
    cbks = [];
    cbks.append(tb_cb);
    #cbks.append(es_cb);

    modelCNN.fit(x_train, y_train,
              batch_size=batch_size,
              callbacks=cbks,
              epochs=100,
              verbose=1,
              validation_data=(x_test, y_test))
    score = modelCNN.evaluate(x_test, y_test, verbose=0)

这个卷积神经网络是在一个只训练2轮,准确率在94%以上的全连接网络前端加上一个filter进行卷积。只加了一个size为输入样本同样尺寸的filter。结果这个神经网络完全失效。我训练了100轮,结果基本没有效果。参见图1

关于神经网络的思考_第1张图片
图1

这个神经网络在训练100轮中精度基本没有提升,是一条直线,loss只是稍微有一点下降。读者可以检查一下是不是哪里出错了,如果有请帮助指正。
2.如果步长过长会有同样的问题,提取的特征过少,输入X在经过卷积后变成X',在此过程中可以基于分类的有效信息量衰减过大,导致X'不会和输入Y存在目标函数F的对应关系。
3.pooling的过程也会存在同样的问题,会造成有效信息的衰减。如果pooling选择尺寸过大,也会使神经网络的效果下降。李宏毅老师也提到alpha go的算法中,没有使用pooling其实也是这个原因,加入pooling会导致数据损失,而在围棋中就算是用2x2的size进行pooling都会造成严重的数据损失,因为围棋叫吃的时候是可以在3x3的范围内完成的。如果再pooling一下的话,alpha go 估计连基本的叫吃都看不明白了。

在上面的filter实验中,由于filter 的size选择有点极端,不知道keras或者tensorflow会不会产生异常情况,导致准确率不能有效提升。如果错了。。。请不要打脸[\尴尬]

你可能感兴趣的:(关于神经网络的思考)