AlexNet 介绍

AlexNet 介绍

AlexNet 架构

首先论文中的原始图像大小有误,应该是 227 * 227,但是作者写成了 224 * 224。

第一层:原始图像大小为 227 * 227 * 3(长宽为 227 像素,rgb三通道)。使用的卷积核大小为 11 * 11 * 3,stride(步长)为 4,一共使用 96 个卷积核。得到的数据大小为 55 * 55 * 96 ( (227-11)/4+1=55 )。这里图中显示为 48 的原因是论文中将程序放在了两个 GPU上执行,并只在某些层(第三层和最后的全连接层)在两个 GPU 间进行通信。之后使用大小为 3 * 3 的核,步长为 2,进行最大池化操作,得到数据大小 27 * 27 * 96 ( (55-3)/2+1=27 )。最后使用大小为 5 * 5 的核进行归一化操作,得到第二层的输入大小为 27 * 27 * 96。

第二层:输入大小为 27 * 27 * 48(分到了两个GPU上运行,相当于只考虑了得到的一半特性的相关性,这样只是相当于对求得的特性的重新排列。唯一可能的影响是收敛的速度可能会下降)。使用的卷积核大小为 5 * 5 * 48,步长为 1,pad(填充)为 2,一共使用 256 个卷积核。得到的数据大小为 27 * 27 * 256 ( (27-5+2*2)/1+1=27 )。之后使用大小为 3 * 3 的核,步长为 2,进行最大池化操作,得到数据大小 13 * 13 * 256 ( (27-3)/2+1=13 )。最后使用大小为 5 * 5 的核进行归一化操作,得到第三层的输入大小为 13 * 13 * 256。

第三层:输入大小为 13 * 13 * 256(这里GPU之间进行通信,所以对所有提取的特征进行处理,不需要除2)。使用的卷积核大小为 3 * 3 * 256,步长为 1,pad(填充)为 1,一共使用 384 个卷积核。得到的数据大小为 13 * 13 * 384 ( (13-3+1*2)/1+1=13 )。这一层没有进行池化和归一化操作,因此第四层的输入为 13 * 13 * 384。

第四层:输入大小为 13 * 13 * 192(每个GPU)。使用的卷积核大小为 3 * 3 * 192,步长为 1,填充为 1,一共使用 192 个卷积核。得到的数据大小为 13 * 13 * 192 ( (13-3+1*2)/1+1=13 )。同样没有池化和归一化操作,因此第四层的输入为 13 * 13 * 384。

第五层:输入大小为 13 * 13 * 192(每个GPU)。使用的卷积核大小为 3 * 3 * 192,步长为 1,填充为 1,一共使用 128 个卷积核。得到的数据大小为 13 * 13 * 128 ( (13-3+2*1)/1+1=13 )。之后使用大小为 3 * 3 的核,步长为 2,进行最大池化操作,得到数据大小 6 * 6 * 128 ( (13-3)/2+1=6 )。不进行归一化操作,得到第六层的输入为 6 * 6 * 256。

第六层:输入大小为 6 * 6 * 256(两个GPU间通信)。使用包含 4096 个神经元的全连接网络,相当于将输入拉平,即上一层网络包含 6 * 6 * 256 = 9216 个神经元。得到第七层输入为 1 *  4096。这里为了限制网络大小,防止过拟合使用了 dropout。

第七层:输入大小为 1 *  4096(两GPU间通信)。同样使用包含 4096 个神经元的全连接网络,得到第八层输入为 1 *  4096。这里为了限制网络大小,防止过拟合,同样使用了 dropout。

第八层:输入大小为 1 *  4096(两GPU间通信)。由于是最后的输出层,且最后的分类数为 1000 类,因此使用包含 1000 个神经元的全连接网络,得到原始图片属于这 1000 类的可能性,最后可以通过连接 softmax 层得到最后的分类概率。

总体的逻辑还是比较清楚的,理解了卷积和池化操作的逻辑应该就不难理解了。需要注意的就是由于之中涉及两个 GPU 的操作,所以有些地方可能有些不同。

Python AlexNet实现

# coding: UTF-8
'''''''''''''''''''''''''''''''''''''''''''''''''''''
   file name: alexnet.py

   create time: 2017年03月29日 星期三 17时13分01秒
   author: Jipeng Huang
   e-mail: [email protected]
   github: https://github.com/hjptriplebee
'''''''''''''''''''''''''''''''''''''''''''''''''''''
# based on Frederik Kratzert's alexNet with tensorflow
import tensorflow as tf
import numpy as np
# define different layer functions
# we usually don't do convolution and pooling on batch and channel
def maxPoolLayer(x, kHeight, kWidth, strideX, strideY, name, padding = "SAME"):
    """max-pooling"""
    return tf.nn.max_pool(x, ksize=[1, kHeight, kWidth, 1],
                          strides=[1, strideX, strideY, 1], padding = padding, name = name)

def dropout(x, keepPro, name = None):
    """dropout"""
    return tf.nn.dropout(x, keepPro, name)

def LRN(x, R, alpha, beta, name = None, bias = 1.0):
    """LRN"""
    return tf.nn.local_response_normalization(x, depth_radius=R, alpha=alpha,
                                              beta = beta, bias=bias, name=name)

def fcLayer(x, inputD, outputD, reluFlag, name):
    """fully-connect"""
    with tf.variable_scope(name) as scope:
        w = tf.get_variable("w", shape=[inputD, outputD], dtype="float")
        b = tf.get_variable("b", [outputD], dtype="float")
        out = tf.nn.xw_plus_b(x, w, b, name=scope.name)
        if reluFlag:
            return tf.nn.relu(out)
        else:
            return out

def convLayer(x, kHeight, kWidth, strideX, strideY,
              featureNum, name, padding="SAME", groups=1):
    """convolution"""
    channel = int(x.get_shape()[-1])
    conv = lambda a, b: tf.nn.conv2d(a, b, strides=[1, strideY, strideX, 1], padding=padding)
    with tf.variable_scope(name) as scope:
        w = tf.get_variable("w", shape=[kHeight, kWidth, channel/groups, featureNum])
        b = tf.get_variable("b", shape=[featureNum])

        xNew = tf.split(value=x, num_or_size_splits=groups, axis=3)
        wNew = tf.split(value=w, num_or_size_splits=groups, axis=3)

        featureMap = [conv(t1, t2) for t1, t2 in zip(xNew, wNew)]
        mergeFeatureMap = tf.concat(axis=3, values=featureMap)
        # print mergeFeatureMap.shape
        out = tf.nn.bias_add(mergeFeatureMap, b)
        return tf.nn.relu(tf.reshape(out, mergeFeatureMap.get_shape().as_list()), name=scope.name)

class alexNet(object):
    """alexNet model"""
    def __init__(self, x, keepPro, classNum, skip, modelPath="bvlc_alexnet.npy"):
        self.X = x
        self.KEEPPRO = keepPro
        self.CLASSNUM = classNum
        self.SKIP = skip
        self.MODELPATH = modelPath
        #build CNN
        self.buildCNN()

    def buildCNN(self):
        """build model"""
        conv1 = convLayer(self.X, 11, 11, 4, 4, 96, "conv1", "VALID")
        lrn1 = LRN(conv1, 2, 2e-05, 0.75, "norm1")
        pool1 = maxPoolLayer(lrn1, 3, 3, 2, 2, "pool1", "VALID")

        conv2 = convLayer(pool1, 5, 5, 1, 1, 256, "conv2", groups=2)
        lrn2 = LRN(conv2, 2, 2e-05, 0.75, "lrn2")
        pool2 = maxPoolLayer(lrn2, 3, 3, 2, 2, "pool2", "VALID")

        conv3 = convLayer(pool2, 3, 3, 1, 1, 384, "conv3")

        conv4 = convLayer(conv3, 3, 3, 1, 1, 384, "conv4", groups=2)

        conv5 = convLayer(conv4, 3, 3, 1, 1, 256, "conv5", groups=2)
        pool5 = maxPoolLayer(conv5, 3, 3, 2, 2, "pool5", "VALID")

        fcIn = tf.reshape(pool5, [-1, 256 * 6 * 6])
        fc1 = fcLayer(fcIn, 256 * 6 * 6, 4096, True, "fc6")
        dropout1 = dropout(fc1, self.KEEPPRO)

        fc2 = fcLayer(dropout1, 4096, 4096, True, "fc7")
        dropout2 = dropout(fc2, self.KEEPPRO)

        self.fc3 = fcLayer(dropout2, 4096, self.CLASSNUM, True, "fc8")

    def loadModel(self, sess):
        """load model"""
        wDict = np.load(self.MODELPATH, encoding="bytes").item()
        #for layers in model
        for name in wDict:
            if name not in self.SKIP:
                with tf.variable_scope(name, reuse=True):
                    for p in wDict[name]:
                        if len(p.shape) == 1:
                            #bias
                            sess.run(tf.get_variable('b', trainable=False).assign(p))
                        else:
                            #weights
                            sess.run(tf.get_variable('w', trainable=False).assign(p))

下面是测试代码

#!/usr/bin/env python
# coding: UTF-8
'''''''''''''''''''''''''''''''''''''''''''''''''''''
   file name: testModel.py
   create time: 2017年03月31日 星期五 15时48分05秒
   author: Jipeng Huang
   e-mail: [email protected]
   github: https://github.com/hjptriplebee
'''''''''''''''''''''''''''''''''''''''''''''''''''''
import os
import urllib.request
import argparse
import sys
import alexnet
import cv2
import tensorflow as tf
import numpy as np
import caffe_classes

parser = argparse.ArgumentParser(description='Classify some images.')
parser.add_argument('-m', '--mode', choices=['folder', 'url'], default='folder')
parser.add_argument('-p', '--path', help='Specify a path [e.g. testModel]', default='testModel')
args = parser.parse_args(sys.argv[1:])

if args.mode == 'folder':
    #get testImage
    withPath = lambda f: '{}/{}'.format(args.path, f)
    testImg = dict((f, cv2.imread(withPath(f))) for f in os.listdir(args.path) if os.path.isfile(withPath(f)))
elif args.mode == 'url':
    def url2img(url):
        '''url to image'''
        resp = urllib.request.urlopen(url)
        image = np.asarray(bytearray(resp.read()), dtype="uint8")
        image = cv2.imdecode(image, cv2.IMREAD_COLOR)
        return image
    testImg = {args.path:url2img(args.path)}

# noinspection PyUnboundLocalVariable
if testImg.values():
    #some params
    dropoutPro = 1
    classNum = 1000
    skip = []

    imgMean = np.array([104, 117, 124], np.float)
    x = tf.placeholder("float", [1, 227, 227, 3])

    model = alexnet.alexNet(x, dropoutPro, classNum, skip)
    score = model.fc3
    softmax = tf.nn.softmax(score)

    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        model.loadModel(sess)

        for key, img in testImg.items():
            #img preprocess
            resized = cv2.resize(img.astype(np.float), (227, 227)) - imgMean
            maxx = np.argmax(sess.run(softmax, feed_dict={x: resized.reshape((1, 227, 227, 3))}))
            res = caffe_classes.class_names[maxx]

            font = cv2.FONT_HERSHEY_SIMPLEX
            cv2.putText(img, res, (int(img.shape[0]/3), int(img.shape[1]/3)), font, 1, (0, 255, 0), 2)
            print("{}: {}\n----".format(key, res))
            cv2.imshow("demo", img)
            cv2.waitKey(0)

光有这两个文件无法运行,具体的项目可以参考: https://github.com/hjptriplebee/AlexNet_with_tensorflow

你可能感兴趣的:(深度学习,AlexNet)