【深度学习】(三)图像分类_图像分类技术最新发展

ImageNet数据集是ILSVRC竞赛使用的是数据集,由斯坦福大学李飞飞教授主导,包含了超过1400万张全尺寸的有标记图片。ILSVRC比赛会每年从ImageNet数据集中抽出部分样本,以2012年为例,比赛的训练集包含1281167张图片,验证集包含50000张图片,测试集为100000张图片。

卷积神经网络在特征表示上具有极大的优越性,模型提取的特征随着网络深度的增加越来越抽象,越来越能表现图像主题语义,不确定性越少,识别能力越强。AlexNet 的成功证明了CNN 网络能够提升图像分类的效果,其使用了 8 层的网络结构,获得了 2012 年,ImageNet 数据集上图像分类的冠军,为训练深度卷积神经网络模型提供了参考。2014 年,冠军 GoogleNet 另辟蹊径,从设计网络结构的角度来提升识别效果。其主要贡献是设计了 Inception 模块结构来捕捉不同尺度的特征,通过 1×1 的卷积来进行降维。2014 年另外一个工作是 VGG(亚军),进一步证明了网络的深度在提升模型效果方面的重要性。2015 年,最重要的一篇文章是关于深度残差网络 ResNet ,文章提出了拟合残差网络的方法,能够做到更好地训练更深层的网络。 2017年,SENet是ImageNet(ImageNet收官赛)的冠军模型,和ResNet的出现类似,都在很大程度上减小了之前模型的错误率),并且复杂度低,新增参数和计算量小。

历届冠军做法: 请添加图片描述


二、卷积神经网络(CNN)发展

1.网络进化

🎄网络:AlexNet–>VGG–>GoogLeNet–>ResNet
🎨深度:8–>19–>22–>152
✨VGG结构简洁有效

  • 容易修改,迁移到其他任务中
  • 高层任务的基础网络

🖼️性能竞争网络

  • GoogLeNet:Inception v1–>v4
    • Split-transform-merge
  • ResNet:ResNet1024–>ResNeXt
    • 深度、宽度、基数

在这里插入图片描述

2.AlexNet网络

由于受到计算机性能的影响,虽然LeNet在图像分类中取得了较好的成绩,但是并没有引起很多的关注。 知道2012年,Alex等人提出的AlexNet网络在ImageNet大赛上以远超第二名的成绩夺冠,卷积神经网络乃至深度学习重新引起了广泛的关注。

  • AlexNet包含8层网络,有5个卷积层和3个全连接层
  • AlexNet第一层中的卷积核shape为11X11,第二层的卷积核形状缩小到5X5,之后全部采用3X3的卷积核
  • 所有的池化层窗口大小为3X3,步长为2,最大池化采用Relu激活函数,代替sigmoid,梯度计算更简单,模型更容易训练
  • 采用Dropout来控制模型复杂度,防止过拟合采用大量图像增强技术,比如翻转、裁剪和颜色变化,扩大数据集,防止过拟合
    在这里插入图片描述
    代码实现
# 导入工具包
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

# 模型构建
net = keras.models.Sequential([
    # 卷积:卷积核数量96,尺寸11\*11,步长4,激活函数relu
    layers.Conv2D(filters=96, kernel_size=11, strides=4, activation='relu'),
    # 最大池化:尺寸3\*3,步长2
    layers.MaxPool2D(pool_size=3, strides=2),
    # 卷积:卷积核数量256,尺寸5\*5,激活函数relu,same卷积
    layers.Conv2D(filters=256, kernel_size=5, padding='same', activation='relu'),
    # 最大池化:尺寸3\*3,步长3
    layers.MaxPool2D(pool_size=3, strides=2),
    # 卷积:卷积核数量384,尺寸3,激活函数relu,same卷积
    layers.Conv2D(filters=384, kernel_size=3, padding='same', activation='relu'),
    # 卷积:卷积核数量384,尺寸3,激活函数relu,same卷积
    layers.Conv2D(filters=384, kernel_size=3, padding='same', activation='relu'),
    # 卷积:卷积核数量256,尺寸3,激活函数relu,same卷积
    layers.Conv2D(filters=256, kernel_size=3, padding='same', activation='relu'),
    # 最大池化:尺寸3\*3,步长2
    layers.MaxPool2D(pool_size=3, strides=2),
    # 展平特征图
    layers.Flatten(),
    # 全连接:4096神经元,relu
    layers.Dense(4096, activation='relu'),
    # 随机失活
    layers.Dropout(0.5),
    layers.Dense(4096, activation='relu'),
    layers.Dropout(0.5),
    # 输出层:多分类用softmax,二分类用sigmoid
    layers.Dense(10, activation='softmax')],
    name='AlexNet')

# 模拟输入
x = tf.random.uniform((1, 227, 227, 1))
y = net(x)

net.summary()

3.VGG网络

VGG网络是在2014年由牛津大学计算机视觉组和谷歌公司的研究员共同开发的。VGG由5层卷积层、3层全连接层、softmax输出层构成,层与层之间使用最大池化分开,所有隐层的激活单元都采用ReLU函数。通过反复堆叠3X3的小卷积核和2X2的最大池化层,VGGNet成功的搭建了16-19层的深度卷积神经网络。VGG的结构图如下:
在这里插入图片描述
VGGNet 论文中全部使用了3X3的卷积核和2X2的池化核,通过不断加深网络结构来提升性能。下图所示为 VGGNet 各级别的网络结构图,以及随后的每一级别的参数量,从11层的网络一直到19层的网络都有详尽的性能测试。虽然从A到E每一级网络逐渐变深,但是网络的参数量并没有增长很多,这是因为参数量主要都消耗在最后3个全连接层。前面的卷积部分虽然很深,但是消耗的参数量不大,不过训练比较耗时的部分依然是卷积,因其计算量比较大。这其中的D、E也就是我们常说的 VGGNet-16 和 VGGNet-19。C相比B多了几个1X1的卷积层,1X1卷积的意义主要在于线性变换,而输入通道数和输出通道数不变,没有发生降维。

代码实现 VGG11

#tensorflow基于mnist数据集上的VGG11网络,可以直接运行
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
#tensorflow基于mnist实现VGG11
mnist = input_data.read_data_sets('MNIST\_data', one_hot=True)

x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
sess = tf.InteractiveSession()
#Layer1
W_conv1 =tf.Variable(tf.truncated_normal([3, 3, 1, 64],stddev=0.1))
b_conv1 = tf.Variable(tf.constant(0.1,shape=[64]))
#调整x的大小
x_image = tf.reshape(x, [-1,28,28,1])
h_conv1 = tf.nn.relu(tf.nn.conv2d(x_image, W_conv1,strides=[1, 1, 1, 1], padding='SAME') + b_conv1)
#Layer2 pooling
W_conv2 = tf.Variable(tf.truncated_normal([3, 3, 64, 64],stddev=0.1))
b_conv2 = tf.Variable(tf.constant(0.1,shape=[64]))
h_conv2 = tf.nn.relu(tf.nn.conv2d(h_conv1, W_conv2,strides=[1, 1, 1, 1], padding='SAME') + b_conv2)
h_pool2 = tf.nn.max_pool(h_conv2, ksize=[1, 2, 2, 1],
                        strides=[1, 2, 2, 1], padding='SAME')
#Layer3
W_conv3 = tf.Variable(tf.truncated_normal([3, 3, 64, 128],stddev=0.1))
b_conv3 = tf.Variable(tf.constant(0.1,shape=[128]))
h_conv3 = tf.nn.relu(tf.nn.conv2d(h_pool2, W_conv3,strides=[1, 1, 1, 1], padding='SAME') + b_conv3)
#Layer4 pooling
W_conv4 = tf.Variable(tf.truncated_normal([3, 3, 128, 128],stddev=0.1))
b_conv4 = tf.Variable(tf.constant(0.1,shape=[128]))
h_conv4 = tf.nn.relu(tf.nn.conv2d(h_conv3, W_conv4,strides=[1, 1, 1, 1], padding='SAME') + b_conv4)
h_pool4= tf.nn.max_pool(h_conv4, ksize=[1, 2, 2, 1],
                        strides=[1, 2, 2, 1], padding='SAME')
#Layer5
W_conv5 = tf.Variable(tf.truncated_normal([3, 3, 128, 256],stddev=0.1))
b_conv5 = tf.Variable(tf.constant(0.1,shape=[256]))
h_conv5 = tf.nn.relu(tf.nn.conv2d(h_pool4, W_conv5,strides=[1, 1, 1, 1], padding='SAME') + b_conv5)
#Layer6
W_conv6 = tf.Variable(tf.truncated_normal([3, 3, 256, 256],stddev=0.1))
b_conv6 = tf.Variable(tf.constant(0.1,shape=[256]))
h_conv6 = tf.nn.relu(tf.nn.conv2d(h_conv5, W_conv6,strides=[1, 1, 1, 1], padding='SAME') + b_conv6)
#Layer7
W_conv7 = tf.Variable(tf.truncated_normal([3, 3, 256, 256],stddev=0.1))
b_conv7 = tf.Variable(tf.constant(0.1,shape=[256]))
h_conv7 = tf.nn.relu(tf.nn.conv2d(h_conv6, W_conv7,strides=[1, 1, 1, 1], padding='SAME') + b_conv7)
#Layer8
W_conv8 = tf.Variable(tf.truncated_normal([3, 3, 256, 256],stddev=0.1))
b_conv8 = tf.Variable(tf.constant(0.1,shape=[256]))
h_conv8 = tf.nn.relu(tf.nn.conv2d(h_conv7, W_conv8,strides=[1, 1, 1, 1], padding='SAME') + b_conv8)
h_pool8 = tf.nn.max_pool(h_conv8, ksize=[1, 2, 2, 1],
                        strides=[1, 1, 1, 1], padding='SAME')
#Layer9-全连接层
W_fc1 = tf.Variable(tf.truncated_normal([7\*7\*256,1024],stddev=0.1))
b_fc1 = tf.Variable(tf.constant(0.1,shape=[1024]))
#对h\_pool2数据进行铺平
h_pool2_flat = tf.reshape(h_pool8, [-1, 7\*7\*256])
#进行relu计算,matmul表示(wx+b)计算
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
#Layer10-全连接层,这里也可以是[1024,其它],大家可以尝试下
W_fc2 = tf.Variable(tf.truncated_normal([1024,1024],stddev=0.1))
b_fc2 = tf.Variable(tf.constant(0.1,shape=[1024]))
h_fc2 = tf.nn.relu(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
h_fc2_drop = tf.nn.dropout(h_fc2, keep_prob)
#Layer11-softmax层
W_fc3 = tf.Variable(tf.truncated_normal([1024,10],stddev=0.1))
b_fc3 = tf.Variable(tf.constant(0.1,shape=[10]))
y_conv = tf.matmul(h_fc2_drop, W_fc3) + b_fc3
#在这里通过tf.nn.softmax\_cross\_entropy\_with\_logits函数可以对y\_conv完成softmax计算,同时计算交叉熵损失函数
cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))

#定义训练目标以及加速优化器
train_step = tf.train.AdamOptimizer(1e-3).minimize(cross_entropy)
#计算准确率
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
#初始化变量
saver = tf.train.Saver()
sess.run(tf.global_variables_initializer())
for i in range(20000):
  batch = mnist.train.next_batch(10)
  if i%100 == 0:
    train_accuracy = accuracy.eval(feed_dict={
        x:batch[0], y_: batch[1], keep_prob: 1.0})
    print("step %d, training accuracy %g"%(i, train_accuracy))
  train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})

#保存模型
save_path = saver.save(sess, "./model/save\_net.ckpt")

print("test accuracy %g"%accuracy.eval(feed_dict={
    x: mnist.test.images[:3000], y_: mnist.test.labels[:3000], keep_prob: 1.0}))

4.GoogLeNet网络

Google Inception Net通常被称为Google Inception V1,在ILSVRC-2014比赛中由论文<Going deeper with convolutions>提出.
Inception V1有22层,比AlexNet的8层和VGGNet的19层还要深.参数量(500万)仅有AlexNet参数量(6000万)的1/12,但准确率远胜于AlexNet的准确率.
Inception V1降低参数量的目的:

  1. 参数越多模型越庞大,需要模型学习的数据量就越大,且高质量的数据非常昂贵.
  2. 参数越多,消耗的计算资源越多.

Inception V1网络的特点:

  • 模型层数更深(22层),表达能力更强.
  • 去除最后的全连接层,用全局平均池化层(即将图片尺寸变为1X1)来代替它.(借鉴了NIN)
  • 使用Inception Module提高了参数利用效率.
    在这里插入图片描述
    Inception V2网络的特点:
  • Batch Normalization 白化:使每一层的输出都规范化到N(0,1)
  • 解决Interal Covariate Shift问题
  • 允许较高学习率
  • 取代部分Dropout
  • 5X5卷积核–>2个3X3卷积核

在这里插入图片描述
Inception V3网络的特点:

  • 高效的降尺寸
  • 不增加计算量
  • 取消浅层的辅助分类器
  • 深层辅助分类器只在训练后期有用

在这里插入图片描述
GoogLeNet网络结构:
在这里插入图片描述
对于我们搭建的Inception模块,所需要使用到参数有#1x1, #3x3reduce, #3x3, #5x5reduce, #5x5, poolproj,这6个参数,分别对应着所使用的卷积核个数,参数设置如下表所示:
在这里插入图片描述
代码实现 Inception V3

import tensorflow as tf
slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)

# 生成默认参数
def inception\_v3\_arg\_scope(weight_decay=0.00004,                      # L2正则weight\_decay
                           stddev=0.1,                                # 标准差
                           batch_norm_var_collection='moving\_vars'):
    batch_norm_params = {
        'decay': 0.9997,
        'epsilon':0.001,
        'updates\_collections': tf.GraphKeys.UPDATE_OPS,
        'variables\_collections':{
            'beta': None,
            'gamma': None,
            'moving\_mean': [batch_norm_var_collection],
            'moving\_variance': [batch_norm_var_collection],
        }
    }

    # 提供了新的范围名称scope name
    # 对slim.conv2d和slim.fully\_connected两个函数的参数自动赋值
    with slim.arg_scope([slim.conv2d, slim.fully_connected],
                        weights_regularizer=slim.l2_regularizer(weight_decay)):
        with slim.arg_scope(
            [slim.conv2d], # 对卷积层的参数赋默认值
            weights_initializer=tf.truncated_normal_initializer(stddev=stddev), # 权重初始化器
            activation_fn=tf.nn.relu,  # 激活函数用ReLU
            normalizer_params=batch_norm_params) as sc: # 标准化器参数用batch\_norm\_params
            return sc

# inputs为输入图片数据的tensor(299x299x3),scope为包含了函数默认参数的环境
def inception\_v3\_base(inputs, scope=None):
    # 保存某些关键节点
    end_points = {}
    # 定义InceptionV3的网络结构
    with tf.variable_scope(scope, 'InceptionV3', [inputs]):
        # 设置卷积/最大池化/平均池化的默认步长为1,padding模式为VALID
        # 设置Inception模块组的默认参数
        with slim.arg_scope([slim.conv2d,       # 创建卷积层
                             slim.max_pool2d,   # 输出的通道数
                             slim.avg_pool2d],  # 卷积核尺寸
                            stride=1,           # 步长
                            padding='VALID'):   # padding模式
            # 经3个3x3的卷积层后,输入数据(299x299x3)变为(35x35x192),空间尺寸降低,输出通道增加
            net = slim.conv2d(inputs, 32, [3,3], stride=2, scope='Conv2d\_1a\_3x3')
            net = slim.conv2d(net, 32, [3, 3], scope='Conv2d\_2a\_3x3')
            net = slim.conv2d(net, 64, [3, 3], padding='SAME', scope='Conv2d\_2b\_3x3')

            net = slim.max_pool2d(net, [3, 3], stride=2, scope='MaxPool\_3a\_3x3')
            net = slim.conv2d(net, 80, [1, 1], scope='Conv2d\_3b\_1x1')
            net = slim.conv2d(net, 192, [3, 3], scope='Conv2d\_4a\_3x3')
            net = slim.max_pool2d(net, [3, 3], stride=2, scope='MaxPool\_5a\_3x3')

        # 设置卷积/最大池化/平均池化的默认步长为1,padding模式为SAME
        # 步长为1,padding模式为SAME,所以图像尺寸不会变,仍为35x35
        with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding='SAME'):
            # 设置Inception Moduel名称为Mixed\_5b
            with tf.variable_scope('Mixed\_5b'):
                # 第1个分支:64输出通道的1x1卷积
                with tf.variable_scope('Branch\_0'):
                    branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d\_0a\_1x1')
                # 第2个分支:48输出通道的1x1卷积,连接64输出通道的5x5卷积
                with tf.variable_scope('Branch\_1'):
                    branch_1 = slim.conv2d(net, 48, [1, 1], scope='Con2d\_0a\_1x1')
                    branch_1 = slim.conv2d(branch_1, 64, [5, 5], scope='Conv2d\_0b\_5x5')
                # 第3个分支:64输出通道的1x1卷积,连接两个96输出通道的3x3卷积
                with tf.variable_scope('Branch\_2'):
                    branch_2 = slim.conv2d(net, 64, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d\_0b\_3x3')
                    branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d\_0c\_3x3')
                # 第4个分支:3x3的平均池化,连接32输出通道的1x1卷积
                with tf.variable_scope('Branch\_3'):
                    branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool\_0a\_3x3')
                    branch_3 = slim.conv2d(branch_3, 32, [1, 1], scope='Conv2d\_0b\_1x1')
                # 4个分支输出通道数之和=64+64+96+32=256,输出tensor为35x35x256
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            # 第1个Inception模块组的第2个Inception Module
            with tf.variable_scope('Mixed\_5c'):
                # 第1个分支:64输出通道的1x1卷积
                with tf.variable_scope('Branch\_0'):
                    branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d\_0a\_1x1')
                # 第2个分支:48输出通道的1x1卷积,连接64输出通道的5x5卷积
                with tf.variable_scope('Branch\_1'):
                    branch_1 = slim.conv2d(net, 48, [1, 1], scope='Conv2d\_0b\_1x1')
                    branch_1 = slim.conv2d(branch_1, 64, [5, 5], scope='Conv2d\_0c\_5x5')
                # 第3个分支:64输出通道的1x1卷积,连接两个96输出通道的3x3卷积
                with tf.variable_scope('Branch\_2'):
                    branch_2 = slim.conv2d(net, 64, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d\_0b\_3x3')
                    branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d\_0c\_3x3')
                # 第4个分支:3x3的平均池化,连接64输出通道的1x1卷积
                with tf.variable_scope('Branch\_3'):
                    branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool\_0a\_3x3')
                    branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d\_0b\_1x1')
                # 输出tensor尺寸为35x35x288
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            # 第1个Inception模块组的第3个Inception Module
            with tf.variable_scope('Mixed\_5d'):
                # 第1个分支:64输出通道的1x1卷积
                with tf.variable_scope('Branch\_0'):
                    branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d\_0a\_1x1')
                # 第2个分支:48输出通道的1x1卷积,连接64输出通道的5x5卷积
                with tf.variable_scope('Branch\_1'):
                    branch_1 = slim.conv2d(net, 48, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_1 = slim.conv2d(branch_1, 64, [5, 5], scope='Conv2d\_0b\_5x5')
                # 第3个分支:64输出通道的1x1卷积,连接两个96输出通道的3x3卷积
                with tf.variable_scope('Branch\_2'):
                    branch_2 = slim.conv2d(net, 64, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d\_0b\_3x3')
                    branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d\_0c\_3x3')
                # 第4个分支:3x3的平均池化,连接64输出通道的1x1卷积
                with tf.variable_scope('Branch\_3'):
                    branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool\_0a\_3x3')
                    branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d\_0b\_1x1')
                # 输出tensor尺寸为35x35x288
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            # 第2个Inception模块组
            with tf.variable_scope('Mixed\_6a'):
                # 第1个分支:3x3卷积,步长为2,padding模式为VALID,因此图像被压缩为17x17
                with tf.variable_scope('Branch\_0'):
                    branch_0 = slim.conv2d(net, 384, [3, 3], stride=2 , padding='VALID', scope='Conv2d\_1a\_1x1')
                # 第2个分支:64输出通道的1x1卷积,连接2个96输出通道的3x3卷积
                with tf.variable_scope('Branch\_1'):
                    branch_1 = slim.conv2d(net, 64, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_1 = slim.conv2d(branch_1, 96, [3, 3], scope='Conv2d\_0b\_3x3')
                    # 步长为2,padding模式为VALID,因此图像被压缩为17x17
                    branch_1 = slim.conv2d(branch_1, 96, [3, 3], stride=2, padding='VALID', scope='Conv2d\_1a\_1x1')
                # 第3个分支:3x3的最大池化层,步长为2,padding模式为VALID,因此图像被压缩为17x17x256
                with tf.variable_scope('Branch\_2'):
                    branch_2 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID', scope='MaxPool\_1a\_3x3')
                net = tf.concat([branch_0, branch_1, branch_2], 3)
            # 第2个Inception模块组,包含5个Inception Module
            with tf.variable_scope('Mixed\_6b'):
                # 第1个分支:192输出通道的1x1卷积
                with tf.variable_scope('Branch\_0'):
                    branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d\_0a\_1x1')
                # 第2个分支:128输出通道的1x1卷积,接128输出通道的1x7卷积,接192输出通道的7x1卷积
                with tf.variable_scope('Branch\_1'):
                    branch_1 = slim.conv2d(net, 128, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_1 = slim.conv2d(branch_1, 128, [1, 7], scope='Conv2d\_0b\_1x7')
                    branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d\_0c\_7x1')
                with tf.variable_scope('Branch\_2'):
                    branch_2 = slim.conv2d(net, 128, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_2 = slim.conv2d(branch_2, 128, [7, 1], scope='Conv2d\_0b\_7x1')
                    branch_2 = slim.conv2d(branch_2, 128, [1, 7], scope='Conv2d\_0c\_1x7')
                    branch_2 = slim.conv2d(branch_2, 128, [7, 1], scope='Conv2d\_0d\_7x1')
                    branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d\_0e\_1x7')
                with tf.variable_scope('Branch\_3'):
                    branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool\_0a\_3x3')
                    branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d\_0b\_1x1')
                # 输出tensor尺寸=17x17x(192+192+192+192)=17x17x768
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            # 经过一个Inception Module输出tensor尺寸不变,但特征相当于被精炼类一遍
            # 第3个Inception模块组
            with tf.variable_scope('Mixed\_6c'):
                with tf.variable_scope('Branch\_0'):
                    branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d\_0a\_1x1')
                with tf.variable_scope('Branch\_1'):
                    branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_1 = slim.conv2d(branch_1, 160, [1, 7], scope='Conv2d\_0b\_1x7')
                    branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d\_0c\_7x1')
                with tf.variable_scope('Branch\_2'):
                    branch_2 = slim.conv2d(net, 160, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d\_0b\_7x1')
                    branch_2 = slim.conv2d(branch_2, 160, [1, 7], scope='Conv2d\_0c\_1x7')
                    branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d\_0d\_7x1')
                    branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d\_0e\_1x7')
                with tf.variable_scope('Branch\_3'):
                    branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool\_0a\_3x3')
                    branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d\_0b\_1x1')
                # 输出tensor尺寸为17x17x768
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            # 第4个Inception模块组
            with tf.variable_scope('Mixed\_6d'):
                with tf.variable_scope('Branch\_0'):
                    branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d\_0a\_1x1')
                with tf.variable_scope('Branch\_1'):
                    branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_1 = slim.conv2d(branch_1, 160, [1, 7], scope='Conv2d\_0b\_1x7')
                    branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d\_0c\_7x1')
                with tf.variable_scope('Branch\_2'):
                    branch_2 = slim.conv2d(net, 160, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d\_0b\_7x1')
                    branch_2 = slim.conv2d(branch_2, 160, [1, 7], scope='Conv2d\_0c\_1x7')
                    branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d\_0d\_7x1')
                    branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d\_0e\_1x7')
                with tf.variable_scope('Branch\_3'):
                    branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool\_0a\_3x3')
                    branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d\_0b\_1x1')
                # 输出tensor尺寸为17x17x768
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            # 第5个Inception模块组
            with tf.variable_scope('Mixed\_6e'):
                with tf.variable_scope('Branch\_0'):
                    branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d\_0a\_1x1')
                with tf.variable_scope('Branch\_1'):
                    branch_1 = slim.conv2d(net, 192, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_1 = slim.conv2d(branch_1, 192, [1, 7], scope='Conv2d\_0b\_1x7')
                    branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d\_0c\_7x1')
                with tf.variable_scope('Branch\_2'):
                    branch_2 = slim.conv2d(net, 192, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_2 = slim.conv2d(branch_2, 192, [7, 1], scope='Conv2d\_0b\_7x1')
                    branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d\_0c\_1x7')
                    branch_2 = slim.conv2d(branch_2, 192, [7, 1], scope='Conv2d\_0d\_7x1')
                    branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d\_0e\_1x7')
                with tf.variable_scope('Branch\_3'):
                    branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool\_0a\_3x3')
                    branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d\_0b\_1x1')
                # 输出tensor尺寸为17x17x768
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            # 将Mixed\_6e存储于end\_points中
            end_points['Mixed\_6e'] = net
            # 第3个Inception模块
            # 第1个Inception模块组
            with tf.variable_scope('Mixed\_7a'):
                # 第1个分支:192输出通道的1x1卷积,接320输出通道的3x3卷积 步长为2
                with tf.variable_scope('Branch\_0'):
                    branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_0 = slim.conv2d(branch_0, 320, [3, 3], stride=2, padding='VALID', scope='Conv2d\_0a\_3x3')
                # 第2个分支:4个卷积层
                with tf.variable_scope('Branch\_1'):
                    # 192输出通道的1x1卷积
                    branch_1 = slim.conv2d(net, 192, [1, 1], scope='Conv2d\_0a\_1x1')
                    # 192输出通道的1x7卷积
                    branch_1 = slim.conv2d(branch_1, 192, [1, 7], scope='Conv2d\_0b\_1x7')
                    # 192输出通道的7x1卷积
                    branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d\_0c\_7x1')
                    # 192输出通道的3x3卷积 步长为2,输出8x8x192
                    branch_1 = slim.conv2d(branch_1, 192, [3, 3], stride=2, padding='VALID', scope='Conv2d\_1a\_3x3')
                # 第3个分支:3x3的最大池化层,输出8x8x768
                with tf.variable_scope('Branch\_2'):
                    branch_2 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID', scope='MaxPool\_1a\_3x3')
                # 输出tensor尺寸:8x8x(320+192+768)=8x8x1280,尺寸缩小,通道数增加
                net = tf.concat([branch_0, branch_1, branch_2], 3)
            # 第2个Inception模块组
            with tf.variable_scope('Mixed\_7b'):
                # 第1个分支:320输出通道的1x1卷积
                with tf.variable_scope('Branch\_0'):
                    branch_0 = slim.conv2d(net, 320, [1, 1], scope='Conv2d\_0a\_1x1')
                # 第2个分支:384输出通道的1x1卷积
                # 分支内拆分为两个分支:384输出通道的1x3卷积+384输出通道的3x1卷积
                with tf.variable_scope('Branch\_1'):
                    branch_1 = slim.conv2d(net, 384, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_1 = tf.concat([
                               slim.conv2d(branch_1, 384, [1, 3], scope='Conv2d\_0b\_1x3'),
                               slim.conv2d(branch_1, 384, [3, 1], scope='Conv2d\_0b\_3x1')], 3)
                # 第3个分支:448输出通道的1x1卷积,接384输出通道的3x3卷积,分支内拆分为两个分支
                with tf.variable_scope('Branch\_2'):
                    branch_2 = slim.conv2d(net, 448, [1, 1], scope='Conv2d\_0a\_1x1')
                    branch_2 = slim.conv2d(branch_2, 384, [3, 3], scope='Conv2d\_0b\_3x3')
                    # 分支内拆分为两个分支:384输出通道的1x3卷积+384输出通道的3x1卷积
                    branch_2 = tf.concat([


![img](https://img-blog.csdnimg.cn/img_convert/0b4e4ee64d83a556370506eeec614836.png)
![img](https://img-blog.csdnimg.cn/img_convert/2889c55d3fe9f99b8dd7690a660789dd.png)
![img](https://img-blog.csdnimg.cn/img_convert/a363b09ea738866e90e20d2a7eda7d0f.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**

 branch_2 = slim.conv2d(branch_2, 384, [3, 3], scope='Conv2d\_0b\_3x3')
                    # 分支内拆分为两个分支:384输出通道的1x3卷积+384输出通道的3x1卷积
                    branch_2 = tf.concat([


[外链图片转存中...(img-iaGGWgF2-1714457106932)]
[外链图片转存中...(img-oV4SLceJ-1714457106933)]
[外链图片转存中...(img-sC6cyKBu-1714457106933)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**

  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本文在深度学习框架的基础上对特征提取方法进行了研究,并通过医学图像、人脸表情的检测和分类对其效果进行了验证。本文的研究内容主要包括以下点:1)提出有约束的高分散主成分分析网络(Constrained High Dispersal PCANet,CHDNet)。本文详细分析了 CHDNet的不同组件对分类性能的影响,针对PCANet的局限性,设计了非线性变化层、多尺度特征池化层,以提高分类性能。将CHDNet应用在医学图像分类中,包括基于Kinect深度图像的人体生理机能自动检测和计算机辅助舌象诊断,取得良好效果。并通过加权的LIBLINEARSVM验证了在正负样本分布严重不均衡的情况下,CHDNet可以学习到稳定的特征表达。2)提出局部线性嵌入网络(Locally Linear Embedding Network,LLENet)。提出利用图像重构集和类内-类间判别矩阵对LLE算法进行改进,并将基于LLE算法的改进嵌入到卷积核的学习、构建过程中,增加了不同类之间特征表达的区分度。LLENet能够更好地保持图像数据原有的流形结构,并在人脸表情数据库(JAFFE和CK+)和人脸识别数据库(Extended Yale B)上,通过实验证明了 LLENet算法的有效性。实验结果表明,LLENet学习的特征表达不仅优于经典的人工设计的特征提取方法,而且比同类的CNN、PCANet深度学习特征提取方法更加有效。3)研究小样本数据集下基于迁移学习和全连接神经网络(Fully Connected Net-work,FCNet)的深度学习方法。分析了将深度卷积神经网络 CNN 模型迁移到小样本数据的方法,通过热度图展示了不同类别的特征,并构建用于分类的全连接分类器FCNet,特征提取和分类可以分段进行,实现了超声图像中的肝纤维化分类,达到93.90%的准确率。综上所述,本文主要研究了基于局部特征卷积核的神经网络:CHDNet和LLENet,以及在应对小样本数据集时的处理方法。通过实验,本文验证了上述算法的有效性及实际应用价值。 知网论文,学习使用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值