-
机器学习记录5——深度残差网络
2019-07-29 11:55:34机器学习记录5——深度残差网络 主要参考博客 残差网络(Deep Residual Learning for Image Recognition) 相关基础—— 第三方实现 反向传播(Back Propagation)机器学习记录5——深度残差网络
主要参考博客残差网络(Deep Residual Learning for Image Recognition)
相关基础——
第三方实现 反向传播(Back Propagation) -
深度学习残差网络ResNet
2018-03-11 09:01:04非常好的深度学习模型,高校及工业界广泛使用,适合机器学习、计算机视觉和深度学习。 -
机器学习笔记 - 深度残差网络ResNet
2020-12-26 10:12:21深度残差网络 显而易见,更深的神经网络更难训练。 所以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
-
深度残差网络_百面机器学习笔记 | 第九章:前向神经网络 | 06 深度残差网络
2020-12-17 11:10:25随着大数据时代的到来,数据规模日益增加,这使得我们有可能训练更大容量的模型,不断地提升...为了改善这一问 题,深度学习领域的研究员们在过去十几年间尝试了许多方法,包括改进训练算 法、利用正则化、设计特殊...随着大数据时代的到来,数据规模日益增加,这使得我们有可能训练更大容量的模型,不断地提升模型的表示能力和精度。深度神经网络的层数决定了模型的容量,然而随着神经网络层数的加深,优化函数越来越陷入局部最优解。同时,随着网络层数的增加,梯度消失的问题更加严重,这是因为梯度在反向传播时会逐渐衰减。
为了改善这一问 题,深度学习领域的研究员们在过去十几年间尝试了许多方法,包括改进训练算 法、利用正则化、设计特殊的网络结构等。其中,深度残差网络(Deep Residual Network,ResNet)是一种非常有效的网络结构改进,极大地提高了可以有效训练 的深度神经网络层数。如今,我们可以利用深度残差网络训练一个拥有成百上千网络层的模型。
ResNet的提出背景和核心理论是什么?
ResNet的提出背景是解决或缓解深层的神经网络训练中的梯度消失问题。假设有一个
层的深度神经网络,如果我们在上面加入一层,直观来讲得到的
层 深度神经网络的效果应该至少不会比L层的差。因为我们简单地设最后一层为前一层的拷贝(用一个恒等映射即可实现),并且其他层维持原来的参数即可。然而在进行反向传播时,我们很难找到这种形式的解。实际上,通过实验发现,层数更深的神经网络反而会具有更大的训练误差。在CIFAR-10数据集上的一个结果如下图所示,56层的网络反而比20层的网络训练误差更大,这很大程度上归结于深度神经网络的梯度消失问题。
20层网络和56层网络在CIFAR-10数据集上的训练误差和测试误差 为了解释梯度消失问题是如何产生的。回顾第3节推导出的误差传播公式:
下式是前向传播的公式:
将上式展开一层:
可以看到误差传播可以写成
、
以及导数
、
连乘的形式。当误差由第L层传播到除了输入以外的第一个隐含层的时候,会涉及非常多的参数和导数的连乘,这时误差很容易产生消失或者膨胀,影响该层参数的正确的学习。因此深度神经网络的拟合和泛化能力较差,有时甚至不如浅层的神经网络模型精度更高。
ResNet调整了网络结构。首先考虑两层神经网络的简单叠加,这时,输入
经过两个网络层的变换得到
,激活函数采用ReLU。反向传播时,梯度将涉及两层参数的交叉相乘,可能会在离输入近的网络层中产生梯度消失的现象。
ResNet把网络结构调整为:既然离输入近的神经网络层较难训练,那么我们可以将它短接到更靠近输入的层。输入
经过两个神经网络的变换得到
,同时也短接到两层之后,最后这个包含两 层的神经网络模块输出
。这样一来,
被设计为只需要拟合输入
与
目标输出 的残差 ,残差网络的名称也因此而来。如果某一层的输出已经较好的拟合了期望结果,那么多加入一层不会使得模型变得更差,因为该层的输出将直接被短接到两层之后,相当于直接学习了一个恒等映射,而跳过的两层只需要拟合上层输出和目标之间的残差即可。
ResNet结构示意图 -
resnet50代码_机器学习-深度残差网络(ResNet)论文学习(附代码实现)
2020-11-21 21:40:59本文结合50层深度残差网络的实现学习何博士的大作-Deep Residual Learning for Image Recognition。理论上,深层网络结构包含了浅层网络结构所有可能的解空间,但是实际网络训练中,随着网络深度的增加,网络的准确...本文结合50层深度残差网络的实现学习何博士的大作-Deep Residual Learning for Image Recognition。理论上,深层网络结构包含了浅层网络结构所有可能的解空间,但是实际网络训练中,随着网络深度的增加,网络的准确度出现饱和,甚至下降的现象,这个现象可以在下图直观看出来:56层的网络比20层网络效果还要差。但是这种退化并不是因为过拟合导致的,因为56层的神经网络的训练误差同样高。
这就是神经网络的退化现象。何博士提出的残差学习的方法解决了解决了神经网络的退化问题,在深度学习领域取得了巨大的成功。
1.Residual Networks
各个深度的神经网络的结构如下:
50层网络的结构实际上是把34层网络的2个3x3的卷积层替换成3个卷积层:1x1、3x3、1x1,可以看到50层的网络相对于34层的网络,效果上有不小的提升。
代码实现
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的下采样的工作。
代码实现
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。
代码实现:
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表达公式如下:
x是Layer Input, y是未经过Relu激活函数的Layer Output, 是待学习的残差映射。
上式仅仅能处理F(x, wi)和x维度相同的情况,当二者维度不同的情况下应该怎么处理呢?
作者提出了两种处理方式: zero padding shortcut和 projection shortcut。并在实验中构造三种shortcut的方式:
A) 当数据维度增加时,采用zero padding进行数据填充;
B) 当数据维度增加时,采用projection的方式;数据维度不变化时,直接使用恒等映射;
C) 数据维度增加与否都采用projection的方式;
三种方式的对比效果如下:
可以看到效果排序如下: 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与残差网络】deeplearning.ai course4 2nd week programming(tensorflow2.0实现)
2021-01-31 01:21:17Keras入门与残差网络的搭建1 keras 入门导入库函数加载数据1.2 使用Keras框架搭建模型测试2 残差网络的搭建导入库函数2.2.1 恒等块2.2.2 卷积块2.3 构建50层的残差网络加载数据训练模型加载模型2.4 用自己的图片测试... -
深度残差网络
2018-12-14 19:43:01深度残差网络: 深度残差网络的设计就是为了克服这种由于网络深度加深而产生的学习效率变低,...这种本质问题是由于出现了信息丢失而产生的过拟合问题(overfitting,所建的机器学习模型或者是深度学习模型在训练... -