Kaggle猫狗大战准确率Top 2%webapp部署

GitHub项目地址:Mr.Miaow GitHub 如果对你有帮助欢迎 Star 或者 Fork
机器学习深度学习面试题总结

项目介绍

本项目是优达学城的其中一个纳米学位毕业项目 -- 猫狗大战。

项目要求使用深度学习方法识别一张图片是猫还是狗

  • 输入:一张彩色图片
  • 输出:是猫还是狗

注意:本项目代码只供参考,严禁用于其他用途,如果使用请说明出处。

项目概述

本项目使用的卷积神经网络(Convolutional Neural Network, CNN),卷积神经网络是深度学习技术中极具代表的网络结构之一,在图像处理领域取得了很大的成功,在国际标准的 ImageNet 数据集上,许多成功的模型都是基于 CNN 的。CNN 相较于传统的图像处理算法的优点之一在于,避免了对图像复杂的前期预处理过程(提取人工特征等),可以直接输入原始图像。CNN 网络对图片进行多次卷基层和池化层处理,在输出层给出两个节点并进行 softmax 计算得到两个类别各自的概率。

本项目最终需要训练基于 CNN 的机器学习模型,对测试样本进行分类,并将最终结果上传 kaggle 进行最终评判。

本项目同时也实现了使用 Keras 和 Flask 搭建部署一个简单易用的深度学习图像网页应用,可以通过网页导入一张彩色猫或者狗的图片预测是猫或者狗的概率。

问题称述

  • 数据集中大部分图片是正常的,有少部分异常图片和低分辨率图片,对于训练集来说这些异常数据是要剔除掉的。

  • 数据集中的文件名是以 type.num.jpg 方式命名的,比如 cat.0.jpg。使用 Keras 的 ImageDataGenerator 需要将不同种类的图片分在不同的文件夹中。

  • 数据集中的图像大小是不固定的,但是神经网络输入节点的个数是固定的。所以在将图像的像素作为输入之前,需要将图像的大小进行 resize。

评价指标

对数损失(Log loss)亦被称为逻辑回归损失(Logistic regression loss)或交叉熵损失(Cross-entropy loss)。 交叉熵是常用的评价方式之一,它实际上刻画的是两个概率分布之间的距离,是分类问题中使用广泛的一种损失函数。

本文实际上是二分类问题, 因此可以采用 logloss 损失函数作为评价指标, 计算公式如下:

LogLoss = -\frac{1}{n}\sum_{i=1}^n [y_ilog(\hat{y}_i)+(1-y_i)log(1- \hat{y}_i)]

其中:

  • n 是测试集中图片数量

  • \hat{y}_i 是图片预测为狗的概率

  • y_i 如果图像是狗,则为1,如果是猫,则为0

  • log() 是自然(基数 e)对数

采用交叉熵作为损失函数可以有效的解决梯度消失和梯度爆炸的问题。

交叉熵损失越小,代表模型的性能越好。上述评估指标可用于评估该项目的解决方案以及基准模型。

II. 分析

数据的探索

下载 kaggle 猫狗数据集解压后分为 3 个文件 train.zip、 test.zip 和 sample_submission.csv。

train 训练集包含了 25000 张猫狗的图片,猫狗各一半,每张图片包含图片本身和图片名。命名规则根据 “type.num.jpg” 方式命名。

test 测试集包含了 12500 张猫狗的图片,没有标定是猫还是狗,每张图片命名规则根据 “num.jpg”,需要注意的是测试集编号从 1 开始,而训练集的编号从 0 开始。

sample_submission.csv 需要将最终测试集的测试结果写入.csv 文件中,上传至 kaggle 进行打分。

ls_data.png

从训练集中随机提取图片可视化如下:

train_range_img.png

训练集中图片的尺寸散点分布图:

train_scatter_diagram.png

测试集中图片的尺寸散点分布图:

test_scatter_diagram.png

通过对图片中的色彩-像素比进行 IQR 分析,可以发现很多分辨率低、无关的图片,下面是其中一些不合格的图片:

train_low_resolution_pictures.png

经过观察数据,数据集中大部分图片是正常的,有少部分异常图片,对于训练集来说这些异常数据是要剔除掉的。

算法和技术

问题分析

在给定一张图片,系统需要预测出图像属于预先定义类别中的哪一类。在计算机视觉领域,目前解决这类问题的核心技术框架是深度学习(Deep Learning),特别地,针对图像类型的数据,是深度学习中的卷积神经网络(Convolutional Neural Networks, ConvNets)架构。常见的卷积神经网络架构如下:

CNNs_framwork.png

卷积神经网络中卷积层和池化层主要是对图片的几何特征进行抽取,比如浅层的卷积池化层可以抽取出一些直线,角点等简单的抽象信息,深层的卷积池化层可以抽取人脸等复杂的抽象信息,最后的全连接层才是对图片分类的关键处理。

因此可以利用已经训练好的卷积神经网络提取图片中复杂的几何特征,即将原始图片用已经训练好的卷积神经网络处理之后的输出,作为新的输入,然后加上自己的全连接层,去进行分类。在模型训练的过程中,只改变新加的全连接层的权重。

总的来说,卷积神经网络是一种特殊的神经网络结构,即通过卷积操作可以实现对图像特征的自动学习,选取那些有用的视觉特征以最大化图像分类的准确率。

cat_dog_classify.gif

上图给出了一个简单的猫狗识别的卷积神经网络结构,在最底下(同时也是最大的)的点块表示的是网络的输入层(Input Layer),通常这一层作用是读入图像作为网络的数据输入。在最上面的点块是网络的输出层(Output Layer),其作用是预测并输出读入图像的类别,在这里由于只需要区分猫和狗,因此输出层只有 2 个神经计算单元。而位于输入和输出层的,都称之为隐含层(Hidden Layer),图中有 3 个隐含层,图像分类的隐含层都是由卷积操作完成的,因此这样的隐含层也成为卷积层(Convolutional Layer)。因此,输入层、卷积层、输出层的结构及其对应的参数就构成了一个典型的卷积神经网络。

当然,在实际中使用的卷积神经网络要比这个示例的结构更加复杂,自 2012 年的 ImageNet 比赛起,几乎每一年都会有新的网络结构诞生,已经被大家认可的常见网络有 AlexNet, VGG-Net, GoogLeNet, Inception V2-V4, ResNet 等等。这些卷积神经网络都是在 ImageNet 数据集上表现非常优异的神经网络,具体准确率和模型大小如下图所示。

nnarch1-1.png

模型选择及技术

由于每一种神经网络提取的特征都不一样,因此本项目将多个神经网络处理的结果拼接,作为最后一层全连接层的输入,这样做可以有效地降低方差。

本项目迁移学习部分使用 Keras 实现,而 Keras 中可以导入的模型有 Xception,VGG16,VGG19,ResNet50,InceptionV3,InceptionResNet -V2,MobileNet. 综合考虑模型的分类准确率和大小,选用迁移学习的基础模型为 ResNet50,InceptionV3 和 Xception。

卷积神经网络结构演化图:

cnns_model.png

ResNet:

ResNet引入了残差网络结构(residual network),通过这种残差网络结构,可以把网络层弄的很深(据说目前可以达到 1000 多层),并且最终的分类效果也非常好,残差网络的基本结构如下图所示,很明显,该图是带有跳跃结构的:

ResNet_model.png

残差网络借鉴了高速网络(Highway Network)的跨层链接思想,但对其进行改进(残差项原本是带权值的,但 ResNet 用恒等映射代替之)。

假定某段神经网络的输入是 x​,期望输出是 H(x)​,即 H(x)​ 是期望的复杂潜在映射,如果是要学习这样的模型,则训练难度会比较大;回想前面的假设,如果已经学习到较饱和的准确率(或者当发现下层的误差变大时),那么接下来的学习目标就转变为恒等映射的学习,也就是使输入 x​ 近似于输出 H(x)​,以保持在后面的层次中不会造成精度下降。

在上图的残差网络结构图中,通过“shortcut connections(捷径连接)”的方式,直接把输入x传到输出作为初始结果,输出结果为 H(x)=F(x)+x,当 F(x)=0 时,那么 H(x)=x,也就是上面所提到的恒等映射。于是,ResNet 相当于将学习目标改变了,不再是学习一个完整的输出,而是目标值 H(X)x 的差值,也就是所谓的残差 F(x) := H(x)-x,因此,后面的训练目标就是要将残差结果逼近于 0,使到随着网络加深,准确率不下降。

这种残差跳跃式的结构,打破了传统的神经网络 n-1 层的输出只能给 n 层作为输入的惯例,使某一层的输出可以直接跨过几层作为后面某一层的输入,其意义在于为叠加多层网络而使得整个学习模型的错误率不降反升的难题提供了新的方向。

在此之前,深度神经网络常常会有梯度消失问题的困扰,即来自误差函数的梯度信号会在反向传播回更早的层时指数级地下降。本质上讲,在误差信号反向回到更早的层时,它们会变得非常小以至于网络无法学习。但是,因为 ResNet 的梯度信号可以直接通过捷径连接回到更早的层,所以一下子就可以构建 50 层、101 层、152 层甚至 1000 层以上的网络了,而且它们的表现依然良好。那时候,这在当时最佳的基础上实现了巨大的飞跃——这个 22 层的网络赢得了 ILSVRC 2014 挑战赛。

Inception V3:

Inception 模块之间特征图的缩小,主要有下面两种方式:

Inception_model_01.png

右图是先进行 Inception 操作,再进行池化来下采样,但是这样参数量明显多于左图(比较方式同前文的降维后 Inception 模块),因此 v2 采用的是左图的方式,即在不同的 Inception 之间(35/17/8 的梯度)采用池化来进行下采样。

但是,左图这种操作会造成表达瓶颈问题,也就是说特征图的大小不应该出现急剧的衰减(只经过一层就骤降)。如果出现急剧缩减,将会丢失大量的信息,对模型的训练造成困难。

因此,在2015年12月提出的 Inception V3结构借鉴 Inception 的结构设计了采用一种并行的降维结构,如下图:

Inception_model_02.png

经过优化后的inception v3网络与其他网络识别误差率对比如表所示:

Inception_model_03.png

Inception V3 一个最重要的改进是分解(Factorization),将 7x7 分解成两个一维的卷积(1x7,7x1)3x3 也是一样(1x3,3x1),这样的好处,既可以加速计算,又可以将 1 个卷积拆成 2 个卷积,使得网络深度进一步增加,增加了网络的非线性(每增加一层都要进行 ReLU)。
另外,网络输入从 224*224 变为了 299*299

Xception:

Xception 实际上采用了类似于 ResNet 的网络结构,主体部分采用了模块化设计。如下图所示:

Xception_01.png

Xception 是 google 继 Inception 后提出的对 Inception v3 的另一种改进,主要是采用 depthwise separable convolution 来替换原来Inception v3中的卷积操作。

Xception 取名的由来是 "Extreme Inception",Inception V3 的演进过程:

Xception_02.png

"极端形式"同 SeparableConv 的区别主要有两点:

  • 3x3 卷积和 1x1 卷积的先后顺序。 原来的 Inception 结构是先 1x1 卷积,后 3x3 卷积。作者认为这里的区别并不重要。

  • 两个卷积层之间是否有激活函数。 原来的 Inception 中间是有 ReLU 激活的。 但实验结果证明不加激活效果更好。

基准模型

本项目的最低要求是 kaggle Public Leaderboard 前 10%。在 kaggle 上,总共有 1314 只队伍参加了比赛,所以需要最终的结果排在 131 位之前,131 位的得分是 0.06127,所以目标是模型预测结果要小于 0.06127。

III. 方法

数据预处理

对于异常数据的清理采用 优达学习笔记 提供的“预处理模型”方法实现异常数据清洗。

评价 ImageNet 有指标 Top-1 和 Top-5:

imagenet_info.png

本项目使用 InceptionV3 top-10 训练train训练集。训练过程中将图片的名称和预测 top-10 的结果保存到字典里,训练结束后保存字典为 train_decode_predictions.csv。将模型预测结果与 ImageNetClasses.csv 进行异常数据排查。具体实现代码参考 outlier_detection.ipynb

使用 InceptionV3 模型排查出的异常图片总数为:131张,其中有些图片是正常的,经过筛选后选出 43 张异常图片作为本试验要清理的异常图片。这些异常图片如下图:

outlier_detection.png

去除异常数据后数据分布如下:

new_data_distribution.png

数据集清洗后,猫的数量:12482,狗的数量:12475,测试集图片数量:12500。

由于我们的数据集的文件名是以 type.num.jpg 这样的方式命名的,比如 cat.0.jpg,但是使用 Keras 的 ImageDataGenerator 需要将不同种类的图片分在不同的文件夹中,因此我们需要对数据集进行预处理。这里我们采取的思路是创建符号链接(symbol link),这样的好处是不用复制一遍图片,占用不必要的空间。

文件目录结构如下:

image/
├── test 
├── img_test
│   ├── test -> ../test/
├── train 
├── img_train
│   ├── cat 
│   └── dog 

执行过程

生成迁移学习特征向量

Xception,InceptionV3 和 ResNet50 这三个模型对于输入数据都有各自的默认值,比如在输入图片大小维度上,Xception 和 InceptionV3 默认输入图片大小是 299*299,ResNet50 默认输入图片大小是 224*224;在输入数值维度上,Xception 和 InceptionV3 默认输入数值在 (-1, 1) 范围内。当要输入与默认图片大小不同的图片时,只需传入当前图片大小即可。ResNet50 需要对图片进行中心化处理,由于载入的 ResNet50 模型是在 ImageNet 数据上训练出来的,所以在预处理中每个像素点都要减去 ImageNet 均值。当要输入与默认图片大小不同的图片时,只需传入当前图片大小即可。当输入数值不符合默认要求时,使用每个模型的预处理函数 preprocess_input 即可将输入图片处理成该模型的标准输入。

常见的卷积神经网络结构在前面的若干层都是卷积池化层及其各种变种,后面几层都是全连接层,这些全连接层之前的网络层被称为瓶颈层 (bottleneck). 将新的图片通过训练好的卷积神经网络直到瓶颈层的过程可以看做是对图像进行特征提取的过程。一般情况下,为了减少内存的消耗, 加快计算的过程,再将瓶颈层的结果输入全连接层之前,做一次全局平均 池化,比如 ResNet50 瓶颈层输出结果是 7*7*2048,如果直接输入到全连接层,参数会非常多,所以进行一次全局平均池化,将输出矩阵调整为 1*1*2048,这么做还有一个好处,那就是可以降低过拟合的程度。

在 Keras 中载入模型并进行全局平均池化,只需要在载入模型的时候,设置 include_top=False, pooling='avg'. 每个模型都将图片处理成一个 1*2048 的行向量,将这三个行向量进行拼接,得到一个 1*6144 的行向量,作为数据预处理的结果。

def write_gap(MODEL, image_size, lambda_func=None):
    width = image_size[0]
    height = image_size[1]
    input_tensor = Input((height, width, 3))
    x = input_tensor
    if lambda_func:
        x = Lambda(lambda_func)(x)
    
    base_model = MODEL(input_tensor=x, weights='imagenet', include_top=False, pooling='avg')
    model = Model(base_model.input, GlobalAveragePooling2D()(base_model.output))
    
    gen = ImageDataGenerator()
    train_generator = gen.flow_from_directory("img_train", image_size, shuffle=False, 
                                              batch_size=16)
    test_generator = gen.flow_from_directory("img_test", image_size, shuffle=False, 
                                             batch_size=16, class_mode=None)

    train = model.predict_generator(train_generator, train_generator.nb_sample)
    test = model.predict_generator(test_generator, test_generator.nb_sample)

    with h5py.File("gap_%s.h5"%MODEL.__name__) as h:
        h.create_dataset("train", data=train)
        h.create_dataset("test", data=test)
        h.create_dataset("label", data=train_generator.classes)

载入特征向量

经过上面的代码以后,我们获得了三个特征向量文件,分别是:

  • gap_ResNet50.h5
  • gap_InceptionV3.h5
  • gap_Xception.h5

这里需要载入这些特征向量,并且将它们合成一条特征向量,然后记得把 X 和 y 打乱,不然之后设置 validation_split 的时候会出问题。这里设置了 numpy 的随机数种子为 2018。

np.random.seed(2018)

X_train = []
X_test = []

for filename in ["gap_ResNet50.h5", "gap_Xception.h5", "gap_InceptionV3.h5"]:
    with h5py.File(filename, 'r') as h:
        X_train.append(np.array(h['train']))
        X_test.append(np.array(h['test']))
        y_train = np.array(h['label'])

X_train = np.concatenate(X_train, axis=1)
X_test = np.concatenate(X_test, axis=1)

X_train, y_train = shuffle(X_train, y_train)

构建模型

载入预处理的数据之后,先进行一次概率为 0.5 的 dropout,然后直接连接输出层,激活函数为 Sigmoid,优化器为 Adadelta,输出一个零维张量,表示某张图片中有狗的概率。

input_tensor = Input(X_train.shape[1:])
x = input_tensor
x = Dropout(0.5)(x)
x = Dense(1, activation='sigmoid')(x)
model = Model(input_tensor, x)

model.compile(optimizer='adadelta',
              loss='binary_crossentropy',
              metrics=['accuracy'])

整个迁移学习的神经网格结构如下所示:

model.png

训练模型

模型构件好了以后,我们就可以进行训练了,这里我们设置验证集大小为 20% ,也就是说训练集是 19964 张图,验证集是 4991 张图。

model_history = model.fit(X_train, 
                    y_train,
                    batch_size=128,
                    nb_epoch=8,
                    verbose=1,
                    validation_split=0.2,
                    callbacks = [TensorBoard(log_dir='./Graph')])

model.save('model.h5')

保存模型为:model.h5

完善

  • 本项目通过对图片中的色彩-像素比进行 IQR 分析,经人工筛选后剔除了分辨率低、无关的图片,这种方法并不能把所有的异常图片都剔除掉。比如还有一些图片被别的物体遮挡,对训练造成干扰等等。后期可以考虑多方面对图片做筛选处理

  • 图片中猫狗的拍摄角度不尽相同,而且猫狗占整张图片的比例也有所差别。为了让模型尽量不受这些因素的干扰,增强模型的泛化能力,需要对原始图片进行一些随机操作,比如旋转、剪切变换、缩放、水平翻转等。Keras 提供的图片生成器 ImageDataGenerator 可以很方便地对图片进行提升

  • 对模型参数的优化,通过不同的优化器的尝试得到更好的优化结果

IV. 结果

模型的评价与验证

train_data_info.png

我们可以看到,训练的过程很快,十秒以内就能训练完,准确率也很高,在验证集上最高达到了99.4%的准确率,这相当于一千张图只错了6张,可以说比我还厉害。

训练过中的 loss 和 accuracy 如下:

train_acc_loss.png

将测试集的处理结果提交到kaggle上,loss为0.04150,和验证集的loss近似。

cat_vs_dog_kaggle_score.png

合理性分析

单个 ResNet50 模型 5 次迭代训练结果:

  • 训练集loss:0.0755,验证集loss:0.0419。

使用 Xception,InceptionV3 和 ResNet50 这三个模型进行迁移学习 5 次迭代训练结果:

  • 训练集loss:0.0152,验证集loss:0.0170。

原始的 Xception 有 126 层,原始的 InceptionV3 有 159 层,原始的 ResNet50 有 168 层,更多的层数,不同的卷积核各种各样的的组合,可以更好的抽取图片中的泛化特征,这样既可以提高分类的准确率,又可以降低模型的过拟合风险,所以现在在各种比赛中斩头露角的神经网络层数都非常的多,深度很深,这也是类似的神经网络被称为深度学习的一个主要原因。

Xception,InceptionV3 和 ResNet50 这三个模型进行组合迁移学习,效果比先单个神经网络模型效果好。这里利用了 bagging 的思想,通过多个模型处理数据并进行组合,可以有效降低模型的方差,减少过拟合程度,提高分类准确率。

V. 项目结论

结果可视化

下图是使用优化之前的 ResNet50 模型进行预测的结果展示,可以看到都是正确的结果,只是精度达不到项目要求。使用了知乎上优达学城官方方法进行了实现,完全能达到项目的要求。

test_predict_score.png

对项目的思考

深度学习毫无疑问是处理图像问题最佳的机器模型,近年来各大赛的前几名均是通过深度学习获取了前几名的好成绩。但是相比于传统的机器学习模型,深度学习需要更多的数据,更强大的算力和资源。本项目在训练迁移学习模型使用的是自己的 Mac,足足跑了三天训练完,泪崩。建议在使用的时候用云计算平台去训练。

kaggle 上猫狗大战前几名的 loss 达到了 0.0330,相比于本文中的 0.0415,绝对值减少了 0.0085,说明还是有较大的改进空间。本文只是使用的 Xception,InceptionV3 和 ResNet50 这三个模型进行了提取特征向量,然后将特征向量直接拼接,忽略了特征之间的位置关系。除了这三个模型,还可以增加更多新的模型,或者使用stacking的方法进行模型融合,进一步降低方差,提高分类的准确率。还可以从原始样本上入手,有些图片的分类概率正确,但是不够确定,可以先做一部分处理,然后让模型更加确定。

需要作出的改进

相比 Keras,TensorFlow 真的真的太麻烦了,但是 Google 为什么要把 TensorFlow 做的这么麻烦呢?个人认为是为了运行的高效率和极大的灵活性做出了让步。TensorFlow 是经过工业界实际产品考验过的框架,生态及其丰富,想实现一个功能,有多种写法,学起来有一种 C++ 的感觉,Keras 更像是为了快速出活的框架,如果想做一些改动十分的麻烦,Keras 的默认 backend 就是 TensorFlow,所以 Keras 的执行效率是比 TensorFlow 慢很多的。TensorFlow1.4 里面已经把 tf.contrib.keras 更改为核心模块 tf.keras,所以 TensorFlow 以后用起来应该也会方便很多。最后还想说的是 PyTorch,好多人都推荐,说不仅仅有 TensorFlow 的高效率,而且很 pythonic,可以在任意层和 numpy 数组进行转化。

项目部署

项目使用 Keras 和 Flask 搭建部署一个简单易用的深度学习图像网页应用,可以通过网页导入一张彩色猫或者狗的图片预测是猫或者狗的概率。

项目目录结构:

.
├── README.md
├── ResNet50_image_predict.ipynb
├── app.py
├── environmert.yml
├── static
│   ├── css
│   │   └── main.css
│   └── js
│       └── main.js
├── templates
│   ├── base.html
│   └── index.html
├── models
│   └── ResNet50_catdog_model.h5
├── uploads
│   ├── test01.jpg
│   └── test02.jpg
└── webapp_image_predict.ipynb

环境搭建

$ conda env create -f environmert.yml

运行

$ python app.py

这时候用浏览器打开 http://localhost:5000/ 就可以进行网页导入图片预测图片是狗的概率了。

如果不想搭建环境复现实验结果,可以按照以下操作分分钟复现实验结果:

$ docker pull miaowmiaow/webapp:1.1.0
$ docker run -p 5000:5000 miaowmiaow/webapp:1.1.0

到此就可以在浏览器中输入 http://localhost:5000 就可以使用网页对导入的猫狗图片做预测了。

下图为预测的效果图:

webapp.gif

VI. 参考文献

[1] K. He, X. Zhang, S. Ren, and J. Sun. Deep residual learning for image recognition. arXiv preprint arXiv:1512.03385, 2015.

[2] Christian Szegedy, Wei Liu, Yangqing Jia. Going Deeper with Convolutions arXiv:1409.4842, 2014

[3] François Chollet. Xception: Deep Learning with Depthwise Separable Convolutions arXiv:1610.02357, 2016

[4]手把手教你如何在Kaggle猫狗大战冲到Top2%

[5] Karen Simonyan and Andrew Zisserman. VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE- SCALE IMAGE RECOGNITION. At ICLR,2015.

[6] K. Simonyan and A. Zisserman. Very deep convolutional networks for large-scale image recognition. In ICLR, 2015.

[7] Building powerful image classification models using very little data.

[8] Dogs vs. Cats: Image Classification with Deep Learning using TensorFlow in Python.

[9] ImageNet: VGGNet, ResNet, Inception, and Xception with Keras.

[10] The residual module in ResNet as originally proposed by He et al. in 2015.

[11] An Analysis of Deep Neural Network Models for Practical Applications. arXiv:1605.07678, 2017.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 包括: 理解卷积神经网络 使用数据增强缓解过拟合 使用预训练卷积网络做特征提取 微调预训练网络模型 可视化卷积网络...
    七八音阅读 1,791评论 0 2
  • 周三 闻一多先生的说和做 臧克家 故乡 许巍 没去训练 高代完 明天数分 明月几时有 把酒问青天 不知天上宫阙 今...
    passage_橄榄阅读 180评论 0 0
  • 烈酒喝干 心中烦忧难断 男儿深被情丝缠 痴心渡得白重关 寒酸 寒酸 叹人生长路漫漫 花明柳暗不得绿水青山 问世...
    江小风阅读 732评论 0 0
  • 一直以来想用某种方式去告别,亦或是去祭奠有你的喜悦和悲伤,两年的时光,对我来说如此漫长,纠结和不舍,如今我终于要放...
    毒品613阅读 1,000评论 0 0