基于TensorFlow微调AlexNet

翻译】基于TensorFlow微调AlexNet

(以下均以原博主视角称呼,基本意译,不好的地方还请见谅)

我已更新了使用新数据输入方式的代码仓库。这个新特性来自于版本1.12rc0以上的TensorFlow,可以阅读我的其他博客来进行了解。以下博文里的链接也是指向这里解释的代码。


经过一年多,我终于找到时间和空闲来写我新的博文。这次博文是有关基于TensorFlow 1.0版本微调AlexNet。你可能会说这AlexNet是2012年的网络了,现在都是2017年了!那我就先讲讲我为什么认为这个网络值得我们花力气去微调的原因。

  • 尽管有很多的网络模型微调的教程,但是大部分都是有关于VGG模型或者是Inception模型,并没有AlexNet模型。尽管网络模型微调背后的思想是一样的,但是最大的不同在于TensorFlow(Keras也是)已经含有VGG/Inception类以及相关参数(基于ImageNet数据集预训练得到)。对于AlexNet模型,我们需要自己做一点微小的工作。
  • 另一个原因是,在我大多数的个人项目中,AlexNet模型的效果就相当好了,就没什么理由为了可能提高的0.5%准确度去换一个有着巨量参数的庞大模型。当模型越来越深的时候,它们的计算就会越来越费时间。这在一些项目中是无法接受的。
  • 过去,我主要使用Caffe来微调卷积网络。但是说实话,我发现使用Caffe相当繁琐,例如需要通过.prototxt定义模型、一团的模型结构等等。使用了Keras一段时间后,我最近转移到了TensorFlow上来。现在我想要像以前一样能够在TensorFlow上微调同样的网络模型。
  • 当然,我认为写这个博文的主要原因就是做一个像这样的项目,能够帮助我更好的理解TensorFlow。

无责任声明

After finishing to write this article I ended up having written another very long post(译者翻译不好这句话). 以下基本上分为两个部分:
在第一部分中,我创建了一个类来定义AlexNet模型图,并带有加载预训练参数的函数;
第二部分中讲了针对新的数据集,如何使用这个类来微调AlexNet得到所需要的模型。虽然我推荐阅读第一部分,但是想直接知道如何微调AlexNet可以点击这里跳过第一部分。

另外,本博文并不是TensorFlow的教程也适用于一般卷积网络的微调。我会解释大部分你们需要做的工作,但是你们要懂得关于TensorFlow和机器/深度学习的基本知识来理解文中的东西。

获取预训练权值

不像VGG或Inception那样,TensorFlow中没有预训练好的AlexNet模型。Caffe有,但是将其手动转化到TensorFlow可用的结构实在繁琐。幸运的是,有一个可以用于转化的小工具,可以将任何*prototxt模型定义从caffe转化为python代码和一个TensorFlow模型,同样适用权值。我自己尝试了一下,发现这个效果非常好。不管怎样,你可以在这里下载到已经转换好的参数文件(bvlc_alexnet.npy)。

模型结构

在开始微调AlexNet之前,我们必须先创建所谓的”Graph of the Model”。这和我在上个博客中为BatchNormalization定义的一样,只是这里是针对整个模型。不过不用担心,我们不必亲自做所有的事情。首先让我们先看看原论文中展示模型结构:

Architecture of AlexNet
Architecture of AlexNet, as shown in the original paper (link above).

值得注意的是一些卷积层分为了并列的两个(层二、层四和层五)。这是为了将卷积层的计算分配至两个GPU进行计算(我猜是因为那时候的GPU还不够强大。译者:对,你猜对了,+10分)。尽管如今这可能没有必要,但是为了重现AlexNet的结果,我们还是要定义同样的分割,只不过我们只使用一个GPU。

所以我们开始吧:我们为模型定义一个有如下结构的类(整个代码能够在Github上找到->这里)。Note:查看代码新版本的更新信息。

class AlexNet(object):

    def __init__(self, x, keep_prob, num_classes, skip_layer, weights_path = 'DEFAULT'):
        """
        Inputs:
        - x: tf.placeholder, for the input images
        - keep_prob: tf.placeholder, for the dropout rate
        - num_classes: int, number of classes of the new dataset
        - skip_layer: list of strings, names of the layers you want to reinitialize
        - weights_path: path string, path to the pretrained weights, 
          (if bvlc_alexnet.npy is not in the same folder)
        """
        # Parse input arguments
        self.X = x
        self.NUM_CLASSES = num_classes
        self.KEEP_PROB = keep_prob
        self.SKIP_LAYER = skip_layer
        self.IS_TRAINING = is_training
        if weights_path == 'DEFAULT':
            self.WEIGHTS_PATH = 'bvlc_alexnet.npy'
        else:
            self.WEIGHTS_PATH = weights_path
        # Call the create function to build the computational graph of AlexNet
        self.create()

    def create(self):
        pass

    def load_initial_weights(self):
        pass

__init__函数中,我们将输入元解析为类变量并调用create函数。我们本能够一次写完所有的代码,但是我个人认为这样看起来更清楚。load_initial_weights函数用来将预训练的参数赋给我们创建的变量。

辅助函数

现在我们有了类的基本结构,接下来我们来定义一些用于创建网络层的辅助函数。由于我们要在一个卷积层函数里实现分开的功能与不分开的功能,这个函数可能会‘麻烦’。下面这个函数是caffe-to-tensorflow repo中采用的版本:

def conv(x, filter_height, filter_width, num_filters, stride_y, stride_x, name,padding='SAME', groups=1):
    # Get number of input channels
    input_channels = int(x.get_shape()[-1])

    # Create lambda function for the convolution
    convolve = lambda i, k: tf.nn.conv2d(i, k,
                                        strides = [1, stride_y, stride_x, 1],
                                        padding = padding)

    with tf.variable_scope(name) as scope:
     
  • 8
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 24
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值