精华内容
下载资源
问答
  • 机器学习记录5——深度残差网络 主要参考博客 残差网络(Deep Residual Learning for Image Recognition) 相关基础—— 第三方实现 反向传播(Back Propagation)

    机器学习记录5——深度残差网络


    主要参考博客

    残差网络(Deep Residual Learning for Image Recognition)

    相关基础——
    第三方实现 反向传播(Back Propagation)

    展开全文
  • 非常好的深度学习模型,高校及工业界广泛使用,适合机器学习、计算机视觉和深度学习。
  • 深度残差网络 显而易见,更深的神经网络更难训练。 所以Microsoft Research提出了一种残差的学习框架,以简化比以前使用的网络更深入的网络训练。 显式地将层重新构造为参考层输入学习剩余函数,而不是学习未参考...

    深度残差网络

    显而易见,更深的神经网络更难训练。 所以Microsoft Research提出了一种残差的学习框架,以简化比以前使用的网络更深入的网络训练。 显式地将层重新构造为参考层输入学习剩余函数,而不是学习未参考函数。 提供了全面的经验证据,表明这些残差网络更易于优化,并且可以从中获得准确性深度大大增加。 在ImageNet数据集上,评估深度最大为152层的残差网络-比VGG网络要深8倍,但复杂性仍然较低。这些残留网络的整体在ImageNet测试仪上实现了3.57%的误差。 该结果在ILSVRC 2015分类任务中获得第一名。

    残留网络比它们的“普通”对应网络要深得多,但是它们需要类似数量的参数(权重)。

    参考文档下载:https://download.csdn.net/download/bashendixie5/13786712

    Keras API上的 ResNet-50

    ResNet-50是一个深达50层的卷积神经网络。 您可以从ImageNet数据库中加载对一百万个图像进行培训的网络的预培训版本。 预先训练的网络可以将图像分类为1000个对象类别,例如键盘,鼠标,铅笔和许多动物。

    tf.keras.applications.ResNet50(
        include_top=True, weights="imagenet",
        input_tensor=None, input_shape=None, pooling=None, classes=1000, **kwargs
    )

    实例参考IdenProf

    IdenProf是一个包含十个职业人员图像的数据集。每个类别有1100张图像,其中900张图像用于训练,200张图像用于测试。

    github地址:https://github.com/OlafenwaMoses/IdenProf

    # 深度残差网络—ResNet ResNet50
    from __future__ import print_function
    
    from keras.preprocessing.image import ImageDataGenerator
    from keras.callbacks import LearningRateScheduler
    import os
    from keras.callbacks import ModelCheckpoint
    from io import open
    import requests
    import shutil
    from zipfile import ZipFile
    import keras
    from keras.layers import Dense, Activation, Conv2D, MaxPool2D, GlobalAvgPool2D, BatchNormalization, add, Input
    from keras.models import Model
    from tensorflow.python.keras.preprocessing import image
    import numpy as np
    import json
    
    execution_path = os.getcwd()
    
    # ----------------- The Section Responsible for Downloading the Dataset ---------------------
    
    
    SOURCE_PATH = "https://github.com/OlafenwaMoses/IdenProf/releases/download/v1.0/idenprof-jpg.zip"
    FILE_DIR = os.path.join(execution_path, "idenprof-jpg.zip")
    DATASET_DIR = os.path.join(execution_path, "idenprof")
    DATASET_TRAIN_DIR = "D:/Project/DeepLearn/1dataset/idenprof-jpg/train" #os.path.join(DATASET_DIR, "train")
    DATASET_TEST_DIR = "D:/Project/DeepLearn/1dataset/idenprof-jpg/test" #os.path.join(DATASET_DIR, "test")
    
    
    def download_idenprof():
        if (os.path.exists(FILE_DIR) == False):
            print("Downloading idenprof-jpg.zip")
            data = requests.get(SOURCE_PATH, stream=True)
            with open(FILE_DIR, "wb") as file:
                shutil.copyfileobj(data.raw, file)
            del data
    
            extract = ZipFile(FILE_DIR)
            extract.extractall(execution_path)
            extract.close()
    
    
    # ----------------- The Section Responsible for Training ResNet50 on the IdenProf dataset ---------------------
    
    # Directory in which to create models
    save_direc = os.path.join(os.getcwd(), 'idenprof_models')
    
    # Name of model files
    model_name = 'idenprof_weight_model.{epoch:03d}-{val_acc}.h5'
    
    # Create Directory if it doesn't exist
    if not os.path.isdir(save_direc):
        os.makedirs(save_direc)
    # Join the directory with the model file
    modelpath = os.path.join(save_direc, model_name)
    
    # Checkpoint to save best model
    checkpoint = ModelCheckpoint(filepath=modelpath,
                                 monitor='val_acc',
                                 verbose=1,
                                 save_best_only=True,
                                 save_weights_only=True,
                                 period=1)
    
    
    # Function for adjusting learning rate and saving dummy file
    def lr_schedule(epoch):
        """
        Learning Rate Schedule
        """
        # Learning rate is scheduled to be reduced after 80, 120, 160, 180  epochs. Called  automatically  every
        #  epoch as part  of  callbacks  during  training.
    
    
    
        lr = 1e-3
        if epoch > 180:
            lr *= 1e-4
        elif epoch > 160:
            lr *= 1e-3
        elif epoch > 120:
            lr *= 1e-2
        elif epoch > 80:
            lr *= 1e-1
    
        print('Learning rate: ', lr)
        return lr
    
    
    lr_scheduler = LearningRateScheduler(lr_schedule)
    
    
    def resnet_module(input, channel_depth, strided_pool=False):
        residual_input = input
        stride = 1
    
        if (strided_pool):
            stride = 2
            residual_input = Conv2D(channel_depth, kernel_size=1, strides=stride, padding="same",
                                    kernel_initializer="he_normal")(residual_input)
            residual_input = BatchNormalization()(residual_input)
    
        input = Conv2D(int(channel_depth / 4), kernel_size=1, strides=stride, padding="same",
                       kernel_initializer="he_normal")(input)
        input = BatchNormalization()(input)
        input = Activation("relu")(input)
    
        input = Conv2D(int(channel_depth / 4), kernel_size=3, strides=1, padding="same", kernel_initializer="he_normal")(
            input)
        input = BatchNormalization()(input)
        input = Activation("relu")(input)
    
        input = Conv2D(channel_depth, kernel_size=1, strides=1, padding="same", kernel_initializer="he_normal")(input)
        input = BatchNormalization()(input)
    
        input = add([input, residual_input])
        input = Activation("relu")(input)
    
        return input
    
    
    def resnet_first_block_first_module(input, channel_depth):
        residual_input = input
        stride = 1
    
        residual_input = Conv2D(channel_depth, kernel_size=1, strides=1, padding="same", kernel_initializer="he_normal")(
            residual_input)
        residual_input = BatchNormalization()(residual_input)
    
        input = Conv2D(int(channel_depth / 4), kernel_size=1, strides=stride, padding="same",
                       kernel_initializer="he_normal")(input)
        input = BatchNormalization()(input)
        input = Activation("relu")(input)
    
        input = Conv2D(int(channel_depth / 4), kernel_size=3, strides=stride, padding="same",
                       kernel_initializer="he_normal")(input)
        input = BatchNormalization()(input)
        input = Activation("relu")(input)
    
        input = Conv2D(channel_depth, kernel_size=1, strides=stride, padding="same", kernel_initializer="he_normal")(input)
        input = BatchNormalization()(input)
    
        input = add([input, residual_input])
        input = Activation("relu")(input)
    
        return input
    
    
    def resnet_block(input, channel_depth, num_layers, strided_pool_first=False):
        for i in range(num_layers):
            pool = False
            if (i == 0 and strided_pool_first):
                pool = True
            input = resnet_module(input, channel_depth, strided_pool=pool)
    
        return input
    
    
    def ResNet50(input_shape, num_classes=10):
        input_object = Input(shape=input_shape)
        layers = [3, 4, 6, 3]
        channel_depths = [256, 512, 1024, 2048]
    
        output = Conv2D(64, kernel_size=7, strides=2, padding="same", kernel_initializer="he_normal")(input_object)
        output = BatchNormalization()(output)
        output = Activation("relu")(output)
    
        output = MaxPool2D(pool_size=(3, 3), strides=(2, 2))(output)
        output = resnet_first_block_first_module(output, channel_depths[0])
    
        for i in range(4):
            channel_depth = channel_depths[i]
            num_layers = layers[i]
    
            strided_pool_first = True
            if (i == 0):
                strided_pool_first = False
                num_layers = num_layers - 1
            output = resnet_block(output, channel_depth=channel_depth, num_layers=num_layers,
                                  strided_pool_first=strided_pool_first)
    
        output = GlobalAvgPool2D()(output)
        output = Dense(num_classes)(output)
        output = Activation("softmax")(output)
    
        model = Model(inputs=input_object, outputs=output)
    
        return model
    
    
    def train_network():
        #download_idenprof()
    
        #print(os.listdir(os.path.join(execution_path, "idenprof")))
    
        optimizer = keras.optimizers.Adam(lr=0.01, decay=1e-4)
        batch_size = 32
        num_classes = 10
        epochs = 200
    
        model = ResNet50((224, 224, 3), num_classes=num_classes)
        model.compile(loss="categorical_crossentropy", optimizer=optimizer, metrics=["accuracy"])
        model.summary()
    
        print("Using real time Data Augmentation")
        train_datagen = ImageDataGenerator(rescale=1. / 255, horizontal_flip=True)
    
        test_datagen = ImageDataGenerator(rescale=1. / 255)
    
        train_generator = train_datagen.flow_from_directory(DATASET_TRAIN_DIR, target_size=(224, 224),
                                                            batch_size=batch_size, class_mode="categorical")
        test_generator = test_datagen.flow_from_directory(DATASET_TEST_DIR, target_size=(224, 224), batch_size=batch_size,
                                                          class_mode="categorical")
    
        model.fit_generator(train_generator, steps_per_epoch=int(9000 / batch_size), epochs=epochs,
                            validation_data=test_generator,
                            validation_steps=int(2000 / batch_size), callbacks=[checkpoint, lr_scheduler])
    
    
    # ----------------- The Section Responsible for Inference ---------------------
    CLASS_INDEX = None
    
    MODEL_PATH = os.path.join(execution_path, "idenprof_061-0.7933.h5")
    JSON_PATH = os.path.join(execution_path, "idenprof_model_class.json")
    
    
    def preprocess_input(x):
        x *= (1. / 255)
    
        return x
    
    
    def decode_predictions(preds, top=5, model_json=""):
        global CLASS_INDEX
    
        if CLASS_INDEX is None:
            CLASS_INDEX = json.load(open(model_json))
        results = []
        for pred in preds:
            top_indices = pred.argsort()[-top:][::-1]
            for i in top_indices:
                each_result = []
                each_result.append(CLASS_INDEX[str(i)])
                each_result.append(pred[i])
                results.append(each_result)
    
        return results
    
    
    def run_inference():
        model = ResNet50(input_shape=(224, 224, 3), num_classes=10)
        model.load_weights(MODEL_PATH)
        picture = os.path.join(execution_path, "Haitian-fireman.jpg")
        image_to_predict = image.load_img(picture, target_size=(224, 224))
        image_to_predict = image.img_to_array(image_to_predict, data_format="channels_last")
        image_to_predict = np.expand_dims(image_to_predict, axis=0)
        image_to_predict = preprocess_input(image_to_predict)
        prediction = model.predict(x=image_to_predict, steps=1)
        predictiondata = decode_predictions(prediction, top=int(5), model_json=JSON_PATH)
        for result in predictiondata:
            print(str(result[0]), " : ", str(result[1] * 100))
    
    
    # run_inference()
    train_network()

    police  :  99.38194155693054
    doctor  :  0.32554694917052984
    engineer  :  0.26046386919915676
    pilot  :  0.023799733025953174
    waiter  :  0.007678849215153605

     

    展开全文
  • 随着大数据时代的到来,数据规模日益增加,这使得我们有可能训练更大容量的模型,不断地提升...为了改善这一问 题,深度学习领域的研究员们在过去十几年间尝试了许多方法,包括改进训练算 法、利用正则化、设计特殊...

    0b1bf33d597a894f5d531b4936d1462f.png

    随着大数据时代的到来,数据规模日益增加,这使得我们有可能训练更大容量的模型,不断地提升模型的表示能力和精度。深度神经网络的层数决定了模型的容量,然而随着神经网络层数的加深,优化函数越来越陷入局部最优解。同时,随着网络层数的增加,梯度消失的问题更加严重,这是因为梯度在反向传播时会逐渐衰减。

    为了改善这一问 题,深度学习领域的研究员们在过去十几年间尝试了许多方法,包括改进训练算 法、利用正则化、设计特殊的网络结构等。其中,深度残差网络(Deep Residual Network,ResNet)是一种非常有效的网络结构改进,极大地提高了可以有效训练 的深度神经网络层数。如今,我们可以利用深度残差网络训练一个拥有成百上千网络层的模型。

    ResNet的提出背景和核心理论是什么?

    ResNet的提出背景是解决或缓解深层的神经网络训练中的梯度消失问题。假设有一个

    层的深度神经网络,如果我们在上面加入一层,直观来讲得到的
    层 深度神经网络的效果应该至少不会比L层的差。因为我们简单地设最后一层为前一层的拷贝(用一个恒等映射即可实现),并且其他层维持原来的参数即可。然而在进行反向传播时,我们很难找到这种形式的解。实际上,通过实验发现,层数更深的神经网络反而会具有更大的训练误差。在CIFAR-10数据集上的一个结果如下图所示,56层的网络反而比20层的网络训练误差更大,这很大程度上归结于深度神经网络的梯度消失问题。

    f2258b8002cb1ecf3e58be5b56bcdfa4.png
    20层网络和56层网络在CIFAR-10数据集上的训练误差和测试误差

    为了解释梯度消失问题是如何产生的。回顾第3节推导出的误差传播公式:

    66252ae811cd5dc971ed7b2196a6f0f3.png

    下式是前向传播的公式:

    9e90fefa227d310f5919deee02ed88ab.png

    将上式展开一层:

    89387d3d383cc859099f9fd498c20a3b.png

    可以看到误差传播可以写成

    以及导数
    连乘的形式。当误差由第L层传播到除了输入以外的第一个隐含层的时候,会涉及非常多的参数和导数的连乘,这时误差很容易产生消失或者膨胀,影响该层参数的正确的学习。因此深度神经网络的拟合和泛化能力较差,有时甚至不如浅层的神经网络模型精度更高。

    ResNet调整了网络结构。首先考虑两层神经网络的简单叠加,这时,输入

    经过两个网络层的变换得到
    ,激活函数采用ReLU。反向传播时,梯度将涉及两层参数的交叉相乘,可能会在离输入近的网络层中产生梯度消失的现象。

    ResNet把网络结构调整为:既然离输入近的神经网络层较难训练,那么我们可以将它短接到更靠近输入的层。输入

    经过两个神经网络的变换得到
    ,同时也短接到两层之后,最后这个包含两 层的神经网络模块输出
    。这样一来,
    被设计为只需要拟合输入
    目标输出 的残差 ,残差网络的名称也因此而来。如果某一层的输出已经较好的拟合了期望结果,那么多加入一层不会使得模型变得更差,因为该层的输出将直接被短接到两层之后,相当于直接学习了一个恒等映射,而跳过的两层只需要拟合上层输出和目标之间的残差即可。

    54e86ddb42c18e91f514ec5cf0732db6.png
    ResNet结构示意图
    展开全文
  • 本文结合50层深度残差网络的实现学习何博士的大作-Deep Residual Learning for Image Recognition。理论上,深层网络结构包含了浅层网络结构所有可能的解空间,但是实际网络训练中,随着网络深度的增加,网络的准确...

    本文结合50层深度残差网络的实现学习何博士的大作-Deep Residual Learning for Image Recognition。理论上,深层网络结构包含了浅层网络结构所有可能的解空间,但是实际网络训练中,随着网络深度的增加,网络的准确度出现饱和,甚至下降的现象,这个现象可以在下图直观看出来:56层的网络比20层网络效果还要差。但是这种退化并不是因为过拟合导致的,因为56层的神经网络的训练误差同样高。

    6a17869577b7e445156813b758ccda5b.png

    这就是神经网络的退化现象。何博士提出的残差学习的方法解决了解决了神经网络的退化问题,在深度学习领域取得了巨大的成功。

    1.Residual Networks

    各个深度的神经网络的结构如下:

    51dbdb17805aa72325b22f8feb0bd48b.png

    50层网络的结构实际上是把34层网络的2个3x3的卷积层替换成3个卷积层:1x1、3x3、1x1,可以看到50层的网络相对于34层的网络,效果上有不小的提升。

    19ce5a27765298c276f258aa9d358d32.png

    代码实现

    ResNet 50代码实现的网络结构与上图50层的网络架构完全一致。对于深度较深的神经网络,BN必不可少,关于BN的介绍和实现可以参考以前的文章。

    class ResNet50(object):

    def __init__(self, inputs, num_classes=1000, is_training=True,

    scope="resnet50"):

    self.inputs =inputs

    self.is_training = is_training

    self.num_classes = num_classes

    with tf.variable_scope(scope):

    # construct the model

    net = conv2d(inputs, 64, 7, 2, scope="conv1") # -> [batch, 112, 112, 64]

    net = tf.nn.relu(batch_norm(net, is_training=self.is_training, scope="bn1"))

    net = max_pool(net, 3, 2, scope="maxpool1") # -> [batch, 56, 56, 64]

    net = self._block(net, 256, 3, init_stride=1, is_training=self.is_training,

    scope="block2") # -> [batch, 56, 56, 256]

    net = self._block(net, 512, 4, is_training=self.is_training, scope="block3")

    # -> [batch, 28, 28, 512]

    net = self._block(net, 1024, 6, is_training=self.is_training, scope="block4")

    # -> [batch, 14, 14, 1024]

    net = self._block(net, 2048, 3, is_training=self.is_training, scope="block5")

    # -> [batch, 7, 7, 2048]

    net = avg_pool(net, 7, scope="avgpool5") # -> [batch, 1, 1, 2048]

    net = tf.squeeze(net, [1, 2], name="SpatialSqueeze") # -> [batch, 2048]

    self.logits = fc(net, self.num_classes, "fc6") # -> [batch, num_classes]

    self.predictions = tf.nn.softmax(self.logits)

    2.Building Block

    每个Block中往往包含多个子Block,每个子Block又有多个卷积层组成。每个Block的第一个子Block的第一个卷积层的stride=2,完成Feature Map的下采样的工作。

    ae11aed9c96038b28aab06dc4ad7790e.png

    代码实现

    def _block(self, x, n_out, n, init_stride=2, is_training=True, scope="block"):

    with tf.variable_scope(scope):

    h_out = n_out // 4

    out = self._bottleneck(x, h_out, n_out, stride=init_stride,

    is_training=is_training, scope="bottlencek1")

    for i in range(1, n):

    out = self._bottleneck(out, h_out, n_out, is_training=is_training,

    scope=("bottlencek%s" % (i + 1)))

    return out

    3. Bottleneck Architectures

    在更深层(esNet-50/101/152)的神经网络中为了节省计算耗时, 作者对神经网络的架构进行了改造,将原有的两层3x3卷积层改造为三层卷积层:1x1,3x3,1x1。

    The three layers are 1×1, 3×3, and 1×1 convolutions, where the 1×1 layers are responsible for reducing and then increasing (restoring)dimensions, leaving the 3×3 layer a bottleneck with smaller input/output dimensions。

    8564aaf1769985c1b2f89f1892693ae7.png

    代码实现:

    x: 是输入数据,格式为[BatchSize, ImageHeight,ImageWidth, ChannelNum];

    h_out: 卷积核个数;

    n_out: Block的输出的卷积核个数;

    stride: 卷积步长;

    is_training: 用于Batch Normalization;

    def _bottleneck(self, x, h_out, n_out, stride=None, is_training=True, scope="bottleneck"):

    """ A residual bottleneck unit"""

    n_in = x.get_shape()[-1]

    if stride is None:

    stride = 1 if n_in == n_out else 2

    with tf.variable_scope(scope):

    h = conv2d(x, h_out, 1, stride=stride, scope="conv_1")

    h = batch_norm(h, is_training=is_training, scope="bn_1")

    h = tf.nn.relu(h)

    h = conv2d(h, h_out, 3, stride=1, scope="conv_2")

    h = batch_norm(h, is_training=is_training, scope="bn_2")

    h = tf.nn.relu(h)

    h = conv2d(h, n_out, 1, stride=1, scope="conv_3")

    h = batch_norm(h, is_training=is_training, scope="bn_3")

    if n_in != n_out:

    shortcut = conv2d(x, n_out, 1, stride=stride, scope="conv_4")

    shortcut = batch_norm(shortcut, is_training=is_training, scope="bn_4")

    else:

    shortcut = x

    return tf.nn.relu(shortcut + h)

    4. Shortcuts

    Identity Mapping是深度残差网络的一个核心思想,深度残差网络中Building Block表达公式如下:

    fd37c5b9047f643ac4980f8845e5323e.png

    x是Layer Input, y是未经过Relu激活函数的Layer Output, 是待学习的残差映射。

    上式仅仅能处理F(x, wi)和x维度相同的情况,当二者维度不同的情况下应该怎么处理呢?

    作者提出了两种处理方式: zero padding shortcut和 projection shortcut。并在实验中构造三种shortcut的方式:

    A) 当数据维度增加时,采用zero padding进行数据填充;

    B) 当数据维度增加时,采用projection的方式;数据维度不变化时,直接使用恒等映射;

    C) 数据维度增加与否都采用projection的方式;

    三种方式的对比效果如下:

    49f75b5927e96319595a13339c8c8cda.png

    可以看到效果排序如下: A < B < C,但是三者的差别并不是很大,所以作者得出一个结论: projection shortcut并不是解决退化问题的关键,所以为了避免projection带来的计算负担,论文中很少采用C作为shortcut的方案。上述代码中使用projection shortcut结合Identity shortcut的映射方案。

    5.其它辅助函数的实现

    5.1 变量初始化

    fc_initializer = tf.contrib.layers.xavier_initializer

    conv2d_initializer = tf.contrib.layers.xavier_initializer_conv2d

    5.2 创建变量的辅助函数

    # create weight variable

    def create_var(name, shape, initializer, trainable=True):

    return tf.get_variable(name, shape=shape, dtype=tf.float32,

    initializer=initializer, trainable=trainable)

    5.3 卷积辅助函数

    # conv2d layer

    def conv2d(x, num_outputs, kernel_size, stride=1, scope="conv2d"):

    num_inputs = x.get_shape()[-1]

    with tf.variable_scope(scope):

    kernel = create_var("kernel

    展开全文
  • Keras入门与残差网络的搭建1 keras 入门导入库函数加载数据1.2 使用Keras框架搭建模型测试2 残差网络的搭建导入库函数2.2.1 恒等块2.2.2 卷积块2.3 构建50层的残差网络加载数据训练模型加载模型2.4 用自己的图片测试...
  • 深度残差网络

    2018-12-14 19:43:01
    深度残差网络: 深度残差网络的设计就是为了克服这种由于网络深度加深而产生的学习效率变低,...这种本质问题是由于出现了信息丢失而产生的过拟合问题(overfitting,所建的机器学习模型或者是深度学习模型在训练...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 125
精华内容 50
关键字:

机器学习残差网络