ResNet(Residual Neural Network)由微软研究院的Kaiming He等人提出,通过使用ResNet Unit成功训练出了152层的神经网络,并在ILSVRC2015比赛中取得冠军,ResNet在网络结构上做了大创新,而不再是简单的堆积层数,ResNet在卷积神经网络的新思路,绝对是深度学习发展历程上里程碑式的事件。

ResNet

闪光点:

  • 层数非常深,已经超过百层
  • 引入残差单元来解决退化问题

1 简要概括

ResNet的主要思想是在网络中增加了直连通道,即Highway Network的思想。此前的网络结构是性能输入做一个非线性变换,而Highway Network则允许保留之前网络层的一定比例的输出。ResNet的思想和Highway Network的思想也非常类似,允许原始输入信息直接传到后面的层中,如下图所示。

这样的话这一层的神经网络可以不用学习整个的输出,而是学习上一个网络输出的残差,因此ResNet又叫做残差网络。

随着网络深度增加,网络的准确度应该同步增加,当然要注意过拟合问题。但是网络深度增加的一个问题在于这些增加的层是参数更新的信号,因为梯度是从后向前传播的,增加网络深度后,比较靠前的层梯度会很小。这意味着这些层基本上学习停滞了,这就是梯度消失问题。深度网络的第二个问题在于训练,当网络更深时意味着参数空间更大,优化问题变得更难,因此简单地去增加网络深度反而出现更高的训练误差,深层网络虽然收敛了,但网络却开始退化了,即增加网络层数却导致更大的误差,比如上图,一个56层的网络的性能却不如20层的性能好,这不是因为过拟合(训练集训练误差依然很高),这就是烦人的退化问题。残差网络ResNet设计一种残差模块让我们可以训练更深的网络。

从下图可以看出,数据经过了两条路线,一条是常规路线,另一条则是捷径(shortcut),直接实现单位映射的直接连接的路线,这有点类似与电路中的“短路”。通过实验,这种带有shortcut的结构确实可以很好地应对退化问题。我们把网络中的一个模块的输入和输出关系看作是y=H(x),那么直接通过梯度方法求H(x)就会遇到上面提到的退化问题,如果使用了这种带shortcut的结构,那么可变参数部分的优化目标就不再是H(x),若用F(x)来代表需要优化的部分的话,则H(x)=F(x)+x,也就是F(x)=H(x)-x。因为在单位映射的假设中y=x就相当于观测值,所以F(x)就对应着残差,因而叫残差网络。为啥要这样做,因为作者认为学习残差F(X)比直接学习H(X)简单!设想下,现在根据我们只需要去学习输入和输出的差值就可以了,绝对量变为相对量(H(x)-x 就是输出相对于输入变化了多少),优化起来简单很多。

考虑到x的维度与F(X)维度可能不匹配情况,需进行维度匹配。这里论文中采用两种方法解决这一问题(其实是三种,但通过实验发现第三种方法会使performance急剧下降,故不采用):

  • zero_padding:对恒等层进行0填充的方式将维度补充完整。这种方法不会增加额外的参数
  • projection:在恒等层采用1x1的卷积核来增加维度。这种方法会增加额外的参数

下图展示了两种形态的残差模块,左图是常规残差模块,有两个3×3卷积核卷积核组成,但是随着网络进一步加深,这种残差结构在实践中并不是十分有效。针对这问题,右图的“瓶颈残差模块”(bottleneck residual block)可以有更好的效果,它依次由1×1、3×3、1×1这三个卷积层堆积而成,这里的1×1的卷积能够起降维或升维的作用,从而令3×3的卷积可以在相对较低维度的输入上进行,以达到提高计算效率的目的。

    # coding:utf8# %%# Copyright 2016 The TensorFlow Authors. All Rights Reserved.## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##     http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.# =============================================================================="""Typical use:from tensorflow.contrib.slim.nets import resnet_v2ResNet-101 for image classification into 1000 classes:# inputs has shape [batch, 224, 224, 3]with slim.arg_scope(resnet_v2.resnet_arg_scope(is_training)):net, end_points = resnet_v2.resnet_v2_101(inputs, 1000)ResNet-101 for semantic segmentation into 21 classes:# inputs has shape [batch, 513, 513, 3]with slim.arg_scope(resnet_v2.resnet_arg_scope(is_training)):net, end_points = resnet_v2.resnet_v2_101(inputs,21,global_pool=False,output_stride=16)"""import collectionsimport tensorflow as tfslim = tf.contrib.slimclass Block(collections.namedtuple('Block', ['scope', 'unit_fn', 'args'])):'''使用collections.namedtuple设计ResNet基本的Block模块组的named tuple只包含数据结构,包含具体方法需要传入三个参数[scope,unit_fn,args]以Block('block1',bottleneck,[(256,64,1)]x2 + [(256,64,2)])为例scope = 'block1' 这个Block的名称就是block1unit_fn = bottleneck,  就是ResNet的残差学习单元args = [(256,64,1)]x2 + [(256,64,2)]args是一个列表,每个元素都对应一个bottleneck残差学习单元前面两个元素都是(256,64,1),后一个元素是(256,64,2)每个元素都是一个三元的tuple,代表(depth,depth_bottleneck,stride)例如(256,64,2)代表构建的bottleneck残差学习单元(每个残差学习单元里面有三个卷积层)中,第三层输出通道数depth为256,前两层输出通道数depth_bottleneck为64,且中间层的步长stride为2.这个残差学习单元的结构为[(1x1/s1,64),(3x3/s2,64),(1x1/s1,256)]整个block1中有三个bottleneck残差学习单元,结构为[(1x1/s1,64),(3x3/s2,64),(1x1/s1,256)][(1x1/s1,64),(3x3/s2,64),(1x1/s1,256)][(1x1/s1,64),(3x3/s2,64),(1x1/s1,256)]'''"""A named tuple describing a ResNet block.Its parts are:scope: The scope of the `Block`.unit_fn: The ResNet unit function which takes as input a `Tensor` andreturns another `Tensor` with the output of the ResNet unit.args: A list of length equal to the number of units in the `Block`. The listcontains one (depth, depth_bottleneck, stride) tuple for each unit in theblock to serve as argument to unit_fn."""def subsample(inputs, factor, scope=None):'''降采样方法,如果factor=1,则不做修改返回inputs,不为1,则使用slim.max_pool2d最大池化实现,:param inputs::param factor: 采样因子:param scope::return:'''"""Subsamples the input along the spatial dimensions.Args:inputs: A `Tensor` of size [batch, height_in, width_in, channels].factor: The subsampling factor.scope: Optional variable_scope.Returns:output: A `Tensor` of size [batch, height_out, width_out, channels] with theinput, either intact (if factor == 1) or subsampled (if factor > 1)."""if factor == 1:return inputselse:return slim.max_pool2d(inputs, [1, 1], stride=factor, scope=scope)def conv2d_same(inputs, num_outputs, kernel_size, stride, scope=None):'''如果步长为1,直接使用slim.conv2d,使用conv2d的padding='SAME'如果步长大于1,需要显式的填充0(size已经扩大了),在使用conv2d取padding='VALID'(或者先直接SAME,再调用上面的subsample下采样):param inputs:  [batch, height_in, width_in, channels].:param num_outputs:  An integer, the number of output filters.:param kernel_size: An int with the kernel_size of the filters.:param stride: An integer, the output stride.:param scope::return:'''"""Strided 2-D convolution with 'SAME' padding.When stride > 1, then we do explicit zero-padding, followed by conv2d with'VALID' padding.Note thatnet = conv2d_same(inputs, num_outputs, 3, stride=stride)is equivalent tonet = slim.conv2d(inputs, num_outputs, 3, stride=1, padding='SAME')net = subsample(net, factor=stride)whereasnet = slim.conv2d(inputs, num_outputs, 3, stride=stride, padding='SAME')is different when the input's height or width is even, which is why we add thecurrent function. For more details, see ResnetUtilsTest.testConv2DSameEven().Args:inputs: A 4-D tensor of size [batch, height_in, width_in, channels].num_outputs: An integer, the number of output filters.kernel_size: An int with the kernel_size of the filters.stride: An integer, the output stride.rate: An integer, rate for atrous convolution.scope: Scope.Returns:output: A 4-D tensor of size [batch, height_out, width_out, channels] withthe convolution output."""if stride == 1:return slim.conv2d(inputs, num_outputs, kernel_size, stride=1,padding='SAME', scope=scope)else:# kernel_size_effective = kernel_size + (kernel_size - 1) * (rate - 1)pad_total = kernel_size - 1pad_beg = pad_total // 2pad_end = pad_total - pad_beginputs = tf.pad(inputs,[[0, 0], [pad_beg, pad_end], [pad_beg, pad_end], [0, 0]])return slim.conv2d(inputs, num_outputs, kernel_size, stride=stride,padding='VALID', scope=scope)@slim.add_arg_scopedef stack_blocks_dense(net, blocks,outputs_collections=None):'''定义堆叠Blocks函数,:param net:  为输入  [batch, height, width, channels]:param blocks:  blocks为之前定义好的Blocks的class的列表,:param outputs_collections: 用来收集各个end_points和collections:return:使用两层循环,逐个Block,逐个Residual unit堆叠先使用variable_scope将残差单元命名改为block/unit_%d的形式在第二层,我们拿到每个Blocks中的Residual Unit的args,并展开再使用unit_fn残差学习单元生成函数顺序地创建并连接所有的残差学习单元最后,我们使用slim.utils.collect_named_outputs函数将输出net添加到collection'''"""Stacks ResNet `Blocks` and controls output feature density.First, this function creates scopes for the ResNet in the form of'block_name/unit_1', 'block_name/unit_2', etc.Args:net: A `Tensor` of size [batch, height, width, channels].blocks: A list of length equal to the number of ResNet `Blocks`. Eachelement is a ResNet `Block` object describing the units in the `Block`.outputs_collections: Collection to add the ResNet block outputs.Returns:net: Output tensor"""for block in blocks:with tf.variable_scope(block.scope, 'block', [net]) as sc:for i, unit in enumerate(block.args):with tf.variable_scope('unit_%d' % (i + 1), values=[net]):unit_depth, unit_depth_bottleneck, unit_stride = unitnet = block.unit_fn(net,depth=unit_depth,depth_bottleneck=unit_depth_bottleneck,stride=unit_stride)net = slim.utils.collect_named_outputs(outputs_collections, sc.name, net)return netdef resnet_arg_scope(is_training=True,weight_decay=0.0001,batch_norm_decay=0.997,batch_norm_epsilon=1e-5,batch_norm_scale=True):'''这里创建ResNet通过的arg_scope,用来定义某些函数的参数默认值先设置好BN的各项参数,然后通过slim.arg_scope将slim.conv2d的几个默认参数设置好::param is_training::param weight_decay:  权重衰减率:param batch_norm_decay: BN衰减率默认为0.997:param batch_norm_epsilon::param batch_norm_scale::return:'''"""Defines the default ResNet arg scope.TODO(gpapan): The batch-normalization related default values above areappropriate for use in conjunction with the reference ResNet modelsreleased at https://github.com/KaimingHe/deep-residual-networks. Whentraining ResNets from scratch, they might need to be tuned.Args:is_training: Whether or not we are training the parameters in the batchnormalization layers of the model.weight_decay: The weight decay to use for regularizing the model.batch_norm_decay: The moving average decay when estimating layer activationstatistics in batch normalization.batch_norm_epsilon: Small constant to prevent division by zero whennormalizing activations by their variance in batch normalization.batch_norm_scale: If True, uses an explicit `gamma` multiplier to scale theactivations in the batch normalization layer.Returns:An `arg_scope` to use for the resnet models."""batch_norm_params = {'is_training': is_training,'decay': batch_norm_decay,'epsilon': batch_norm_epsilon,'scale': batch_norm_scale,'updates_collections': tf.GraphKeys.UPDATE_OPS,}'''通过slim.arg_scope将slim.conv2d默认参数权重设置为L2正则权重初始化/激活函数设置/BN设置'''with slim.arg_scope([slim.conv2d],weights_regularizer=slim.l2_regularizer(weight_decay),weights_initializer=slim.variance_scaling_initializer(),activation_fn=tf.nn.relu,normalizer_fn=slim.batch_norm,normalizer_params=batch_norm_params):with slim.arg_scope([slim.batch_norm], **batch_norm_params):# The following implies padding='SAME' for pool1, which makes feature# alignment easier for dense prediction tasks. This is also used in# https://github.com/facebook/fb.resnet.torch. However the accompanying# code of 'Deep Residual Learning for Image Recognition' uses# padding='VALID' for pool1. You can switch to that choice by setting# slim.arg_scope([slim.max_pool2d], padding='VALID').with slim.arg_scope([slim.max_pool2d], padding='SAME') as arg_sc:return arg_sc@slim.add_arg_scopedef bottleneck(inputs, depth, depth_bottleneck, stride,outputs_collections=None, scope=None):'''bottleneck残差学习单元,这是ResNet V2论文中提到的Full Preactivation Residual Unit的一个变种, 它和V1中的残差学习单元的主要区别有两点:1. 在每一层前都用了Batch Normalization2. 对输入进行preactivation,而不是在卷积进行激活函数处理:param inputs::param depth::param depth_bottleneck::param stride::param outputs_collections::param scope::return:'''"""Bottleneck residual unit variant with BN before convolutions.This is the full preactivation residual unit variant proposed in [2]. SeeFig. 1(b) of [2] for its definition. Note that we use here the bottleneckvariant which has an extra bottleneck layer.When putting together two consecutive ResNet blocks that use this unit, oneshould use stride = 2 in the last unit of the first block.Args:inputs: A tensor of size [batch, height, width, channels].depth: The depth of the ResNet unit output.depth_bottleneck: The depth of the bottleneck layers.stride: The ResNet unit's stride. Determines the amount of downsampling ofthe units output compared to its input.rate: An integer, rate for atrous convolution.outputs_collections: Collection to add the ResNet unit output.scope: Optional variable_scope.Returns:The ResNet unit's output."""with tf.variable_scope(scope, 'bottleneck_v2', [inputs]) as sc:# 获取输入的最后一个维度,即输出通道数depth_in = slim.utils.last_dimension(inputs.get_shape(), min_rank=4)#先做BN操作,在使用ReLU做preactivationpreact = slim.batch_norm(inputs, activation_fn=tf.nn.relu, scope='preact')# 定义shortcut,如果残差单元的输入通道数depth_in和输出通道数depth一致,那么使用subsample#按步长为stride对inputs进行空间上的降采样(确保空间尺寸和残差一致,因为残差中间那层的卷积步长为stride)# 如果输入/输出通道数不一样,我们用步长stride的1*1卷积改变其通道数,使得与输出通道数一致if depth == depth_in:shortcut = subsample(inputs, stride, 'shortcut')else:shortcut = slim.conv2d(preact, depth, [1, 1], stride=stride,normalizer_fn=None, activation_fn=None,scope='shortcut')# 然后定义residual,这里residual有3层,先是一个1*1尺寸/步长为1/输出通道数为depth_bottleneck的卷积# 然后是一个3*3尺寸 -->最后还是一个1*1# 最终得到的residual,注意最后一层没有正则化也没有激活函数# 最后将residual和shortcut相加,得到最后的output,再添加到collectionresidual = slim.conv2d(preact, depth_bottleneck, [1, 1], stride=1,scope='conv1')residual = conv2d_same(residual, depth_bottleneck, 3, stride,scope='conv2')residual = slim.conv2d(residual, depth, [1, 1], stride=1,normalizer_fn=None, activation_fn=None,scope='conv3')output = shortcut + residualreturn slim.utils.collect_named_outputs(outputs_collections,sc.name,output)def resnet_v2(inputs,blocks,num_classes=None,global_pool=True,include_root_block=True,reuse=None,scope=None):''':param inputs::param blocks::param num_classes::param global_pool::param include_root_block::param reuse::param scope::return:'''"""Generator for v2 (preactivation) ResNet models.This function generates a family of ResNet v2 models. See the resnet_v2_*()methods for specific model instantiations, obtained by selecting differentblock instantiations that produce ResNets of various depths.Args:inputs: A tensor of size [batch, height_in, width_in, channels].blocks: A list of length equal to the number of ResNet blocks. Each elementis a resnet_utils.Block object describing the units in the block.num_classes: Number of predicted classes for classification tasks. If Nonewe return the features before the logit layer.include_root_block: If True, include the initial convolution followed bymax-pooling, if False excludes it. If excluded, `inputs` should be theresults of an activation-less convolution.reuse: whether or not the network and its variables should be reused. To beable to reuse 'scope' must be given.scope: Optional variable_scope.Returns:net: A rank-4 tensor of size [batch, height_out, width_out, channels_out].If global_pool is False, then height_out and width_out are reduced by afactor of output_stride compared to the respective height_in and width_in,else both height_out and width_out equal one. If num_classes is None, thennet is the output of the last ResNet block, potentially after globalaverage pooling. If num_classes is not None, net contains the pre-softmaxactivations.end_points: A dictionary from components of the network to the correspondingactivation.Raises:ValueError: If the target output_stride is not valid."""with tf.variable_scope(scope, 'resnet_v2', [inputs], reuse=reuse) as sc:end_points_collection = sc.original_name_scope + '_end_points'with slim.arg_scope([slim.conv2d, bottleneck,stack_blocks_dense],outputs_collections=end_points_collection):net = inputsif include_root_block:# We do not include batch normalization or activation functions in conv1# because the first ResNet unit will perform these. Cf. Appendix of [2].with slim.arg_scope([slim.conv2d],activation_fn=None, normalizer_fn=None):net = conv2d_same(net, 64, 7, stride=2, scope='conv1')net = slim.max_pool2d(net, [3, 3], stride=2, scope='pool1')net = stack_blocks_dense(net, blocks)# This is needed because the pre-activation variant does not have batch# normalization or activation functions in the residual unit output. See# Appendix of [2].net = slim.batch_norm(net, activation_fn=tf.nn.relu, scope='postnorm')if global_pool:# Global average pooling.net = tf.reduce_mean(net, [1, 2], name='pool5', keep_dims=True)if num_classes is not None:net = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,normalizer_fn=None, scope='logits')# Convert end_points_collection into a dictionary of end_points.end_points = slim.utils.convert_collection_to_dict(end_points_collection)if num_classes is not None:end_points['predictions'] = slim.softmax(net, scope='predictions')return net, end_pointsdef resnet_v2_50(inputs,num_classes=None,global_pool=True,reuse=None,scope='resnet_v2_50'):"""ResNet-50 model of [1]. See resnet_v2() for arg and return description."""blocks = [Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),Block('block2', bottleneck, [(512, 128, 1)] * 3 + [(512, 128, 2)]),Block('block3', bottleneck, [(1024, 256, 1)] * 5 + [(1024, 256, 2)]),Block('block4', bottleneck, [(2048, 512, 1)] * 3)]return resnet_v2(inputs, blocks, num_classes, global_pool,include_root_block=True, reuse=reuse, scope=scope)def resnet_v2_101(inputs,num_classes=None,global_pool=True,reuse=None,scope='resnet_v2_101'):"""ResNet-101 model of [1]. See resnet_v2() for arg and return description."""blocks = [Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),Block('block2', bottleneck, [(512, 128, 1)] * 3 + [(512, 128, 2)]),Block('block3', bottleneck, [(1024, 256, 1)] * 22 + [(1024, 256, 2)]),Block('block4', bottleneck, [(2048, 512, 1)] * 3)]return resnet_v2(inputs, blocks, num_classes, global_pool,include_root_block=True, reuse=reuse, scope=scope)def resnet_v2_152(inputs,num_classes=None,global_pool=True,reuse=None,scope='resnet_v2_152'):"""ResNet-152 model of [1]. See resnet_v2() for arg and return description."""blocks = [Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),Block('block2', bottleneck, [(512, 128, 1)] * 7 + [(512, 128, 2)]),Block('block3', bottleneck, [(1024, 256, 1)] * 35 + [(1024, 256, 2)]),Block('block4', bottleneck, [(2048, 512, 1)] * 3)]return resnet_v2(inputs, blocks, num_classes, global_pool,include_root_block=True, reuse=reuse, scope=scope)def resnet_v2_200(inputs,num_classes=None,global_pool=True,reuse=None,scope='resnet_v2_200'):"""ResNet-200 model of [2]. See resnet_v2() for arg and return description."""blocks = [Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),Block('block2', bottleneck, [(512, 128, 1)] * 23 + [(512, 128, 2)]),Block('block3', bottleneck, [(1024, 256, 1)] * 35 + [(1024, 256, 2)]),Block('block4', bottleneck, [(2048, 512, 1)] * 3)]return resnet_v2(inputs, blocks, num_classes, global_pool,include_root_block=True, reuse=reuse, scope=scope)from datetime import datetimeimport mathimport timedef time_tensorflow_run(session, target, info_string):num_steps_burn_in = 10total_duration = 0.0total_duration_squared = 0.0for i in range(num_batches + num_steps_burn_in):start_time = time.time()_ = session.run(target)duration = time.time() - start_timeif i >= num_steps_burn_in:if not i % 10:print ('%s: step %d, duration = %.3f' %(datetime.now(), i - num_steps_burn_in, duration))total_duration += durationtotal_duration_squared += duration * durationmn = total_duration / num_batchesvr = total_duration_squared / num_batches - mn * mnsd = math.sqrt(vr)print ('%s: %s across %d steps, %.3f +/- %.3f sec / batch' %(datetime.now(), info_string, num_batches, mn, sd))batch_size = 32height, width = 224, 224inputs = tf.random_uniform((batch_size, height, width, 3))with slim.arg_scope(resnet_arg_scope(is_training=False)):net, end_points = resnet_v2_152(inputs, 1000)init = tf.global_variables_initializer()sess = tf.Session()sess.run(init)num_batches = 100time_tensorflow_run(sess, net, "Forward")

参考链接:

https://blog.csdn.net/u011974639/article/details/76737547

https://blog.csdn.net/u013181595/article/details/80990930

https://www.cnblogs.com/skyfsm/p/8451834.html

CNN网络架构学习:Chapter-5-ResNet(附代码tensorflow)相关推荐

  1. CV之IG:基于CNN网络架构+ResNet网络进行DIY图像生成网络

    CV之IG:基于CNN网络架构+ResNet网络进行DIY图像生成网络 目录 设计思路 实现代码 设计思路 实现代码 # 定义图像生成网络:image, training,两个参数# Less bor ...

  2. 通俗易懂:图解10大CNN网络架构

    作者 | Raimi Karim 译者 | Major 编辑 | 赵雪 出品 | AI科技大本营(ID: rgznai100) 导语:近年来,许多卷积神经网络( CNN )跃入眼帘,而随着其越来越深的 ...

  3. 神经网络模型之CNN网络架构

    CNN网络架构 神经网络架构发展纵览 从1998年开始,近18年来深度神经网络的架构发展情况如下: 上图,横坐标是操作的复杂度,纵坐标是精度. 模型设计一开始的时候模型权重越多模型越大,其精度越高,后 ...

  4. 图解10大CNN网络架构,通俗易懂!

    点击 机器学习算法与Python学习 ,选择加星标 精彩内容不迷路 作者 | Raimi Karim,出品 | AI科技大本营(ID: rgznai100) 本文精心选取了 10 个 CNN 体系结构 ...

  5. 【知乎直播】千奇百怪的CNN网络架构等你来

    大家知道有三从很久很久之前就致力于CNN网络架构相关的研究,至今公众号已经写过很多的文章,知乎也回答过相关的问题,直播也做过几次分享,首先我们回顾一下已有的内容,然后再看看今天发布的新的直播预告! 1 ...

  6. 基于FPGA的一维卷积神经网络CNN的实现(三)训练网络搭建及参数导出(附代码)

    训练网络搭建 环境:Pytorch,Pycham,Matlab. 说明:该网络反向传播是通过软件方式生成,FPGA内部不进行反向传播计算. 该节通过Python获取训练数据集,并通过Pytorch框架 ...

  7. 一文弄懂元学习 (Meta Learing)(附代码实战)《繁凡的深度学习笔记》第 15 章 元学习详解 (上)万字中文综述

    <繁凡的深度学习笔记>第 15 章 元学习详解 (上)万字中文综述(DL笔记整理系列) 3043331995@qq.com https://fanfansann.blog.csdn.net ...

  8. 经典网络架构学习-ResNet

    前言 该论文的四位作者何恺明.张祥雨.任少卿和孙剑如今在人工智能领域里都是响当当的名字,当时他们都是微软亚研的一员.微软亚研是业内为数不多的,能够获得科技巨头持续高投入的纯粹学术机构.ResNet 论 ...

  9. CNN网络架构演进:从LeNet到DenseNet

    原文来源:https://www.cnblogs.com/skyfsm/p/8451834.html 卷积神经网络可谓是现在深度学习领域中大红大紫的网络框架,尤其在计算机视觉领域更是一枝独秀.CNN从 ...

最新文章

  1. YOTO来了!你只需训练一次,谷歌大脑提出调参新trick
  2. 解决WIN7与虚拟机CentOS的文件夹共享问题
  3. Linux C编程--进程介绍5--system函数
  4. iOS 项目中包含多个 FFMPEG 方法冲突的通用解决办法。
  5. BZOJ 2793: [Poi2012]Vouchers(调和级数)
  6. 创建两个相同名称的文件夹
  7. arthas class/classloader相关命令之一:sc、sm
  8. 三维空间长度温度数量_塑料压力和温度对注塑件质量与尺寸的影响研究
  9. 日志分析工具ELK(一)
  10. java用gui如何写退格_emWin(ucGui)的Edit控件退格处理方法 worldsing
  11. Ansible自动化运维笔记3(playbook)
  12. jQuery表格排序组件-tablesorter
  13. 中国精英这才是真相:我们需要信仰,我们需要思想导师
  14. pk8/pem秘钥转keystore格式
  15. Linux基础知识、常用命令和操作
  16. ImportError: cannot import name 'imrotate'
  17. 思维导图 基础篇(06)思维方法-曼陀罗思考法
  18. OSWatcher的安装使用
  19. 小帅哥~小美女~快点进来看看内部类鸭~
  20. IT项目管理:项目前期研究报告

热门文章

  1. 手机芯片战争:英特尔追ARM 联发科战高通
  2. 图解网络:组建一个网络需要用到哪些硬件设备?
  3. 电机振动噪声(NVH)气隙磁场推导
  4. 2021年高级维修电工证考试题库,职业技能鉴定职业资格
  5. pr使用视频素材技巧
  6. 2012意大利之行1:从深圳到罗马
  7. 最新Discuz手机模板NVBING5手机版源码+可封装APP
  8. android APP自动增量更新
  9. jmeter 打开报错_jmeter打开.jmx文件报错的解决办法
  10. Excel制作水滴图和对称条形图