LeNet在caffe中的实现分析

本文主要是对Caffe中mnist数据集上训练的LeNet模型进行结构分析和可视化。

import caffe
import numpy as np
import matplotlib.pyplot as plt

# 定义LeNet模型信息
deploy = 'lenet.prototxt'
model = 'lenet_iter_10000.caffemodel'

# 加载模型
net = caffe.Net(deploy, model, caffe.TEST)

# 计算均值
# blob = caffe.proto.caffe_pb2.BlobProto()
# bin_mean = open(mean_file, 'rb' ).read()
# blob.ParseFromString(bin_mean)
# arr = np.array(caffe.io.blobproto_to_array(blob))
# npy_mean = arr[0]
# mu = npy_mean.mean(1).mean(1)

# init transformer
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
transformer.set_transpose('data', (2, 0, 1))
# transformer.set_mean('data', mu)
transformer.set_raw_scale('data', 255)
# transformer.set_channel_swap('data', (2, 1, 0))

# get certain layer feature
def init(pimg, lay_name):
    global transformer
    global net
    image = caffe.io.load_image(pimg, color = False)
    image
    transformed_image = transformer.preprocess('data', image)
    net.blobs['data'].data[...] = transformed_image
    output = net.forward()
    result = output[lay_name]
    return result
# Test
result = init('test.jpg', 'prob')
print result.shape
print result
(1, 10)
[[ 1.  0.  0.  0.  0.  0.  0.  0.  0.  0.]]

LeNet网络的所有layer以及layer的输出数据 data: 输入图片数据大小为28*28 conv1: 20个卷积核,卷积之后feature map大小24*24 pool1: pooling后feature map大小变为12*12, 共20层 conv2: 50个卷积核, 卷积之后feature map大小为8*8 pool2: pooling后feature map大小变为4*4, 共50层 ip1: 全连接层一, 500个结点 ip2: 全连接层二, 10个结点 prob: 对ip2进行softmax

备注: conv1之后得到20个feature map, conv2有50个卷积核, 每个卷积核在20个feature map卷积之后, 20个卷积之后的feature map对应位置上的点的数据累加之后取激活函数(ReLU)得到该卷积核的对应的feature map, 因此conv2执行之后的feature map个数为50, 而不是50*20.

# all layer name and blob shape
# blob shape is (batch_size, channel_dim, height, width).
for layer_name, blob in net.blobs.iteritems():
    print layer_name + '\t' + str(blob.data.shape)
data  (1, 1, 28, 28)
conv1 (1, 20, 24, 24)
pool1 (1, 20, 12, 12)
conv2 (1, 50, 8, 8)
pool2 (1, 50, 4, 4)
ip1 (1, 500)
ip2 (1, 10)
prob  (1, 10)

LeNet网络的权重(weights + biases) conv1: 20个卷积核, weights大小为5*5, 20个biases conv2: 50个卷积核, weights大小为5*5, 50个biases ip1: conv2之后得到50个4*4大小的feature map, 排列起来大小为800, 与ip1的500个结点进行全连接, weights个数为500*800, biases个数为500 ip2: ip1的500个结点与ip2的10个结点进行全连接, weights个数为500*10, biases个数为10

# all layer name and parameters shape
# param[0] is weights, param[1] is biases
# weights shape is (output_channels, input_channels, filter_height, filter_width)
# biases shape is (output_channels,)
for layer_name, param in net.params.iteritems():
    print layer_name + '\t' + str(param[0].data.shape) + '\t' + str(param[1].data.shape)
conv1 (20, 1, 5, 5) (20,)
conv2 (50, 20, 5, 5)  (50,)
ip1 (500, 800)  (500,)
ip2 (10, 500) (10,)

numpy pad padding分为四部分 第一部分: (0, n ** 2 - data.shape[0]), 补充方阵的缺少的部分, 0表示前面不补, 后面补n ** 2 - data.shape[0]列 第二部分: (0, 1)表示每个filter的前面不补, 后面补1列, filter补了一行 第三部分: (0, 1)表示每个filter的前面不补, 后面补1列, filter补了一列 第四部分: (0, 0)剩下的不补充数据

# param(weights) visualization
def visualization(data):
    # normalize data for display
    data = (data - data.min()) / (data.max() - data.min())

    # force the number of filters to be square
    n = int(np.ceil(np.sqrt(data.shape[0])))

    # add some space between filters
    padding = (((0, n ** 2 - data.shape[0]), (0, 1), (0, 1)) + ((0, 0),) * (data.ndim - 3)) 
    data = np.pad(data, padding, mode = 'constant', constant_values = 1)

    # tile the filters into an image
    data = data.reshape((n, n) + data.shape[1:]).transpose((0, 2, 1, 3) + tuple(range(4, data.ndim + 1)))
    data = data.reshape((n * data.shape[1], n * data.shape[3]) + data.shape[4:])
    plt.imshow(data, cmap='gray')
    plt.axis('off')
    plt.show()
# feature map visualization
feature_map = net.blobs['conv1'].data[0]
visualization(feature_map)
# filter visualization
filters = net.params['conv1'][0].data
visualization(filters.reshape(20, 5, 5))

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏懒人开发

(11.1)James Stewart Calculus 5th Edition:Sequences

我们可以发现分母是 5^n, 符号是 (-1)^(n+1), 分子是 (n+2) 所以有

612
来自专栏PPV课数据科学社区

译:支持向量机(SVM)及其参数调整的简单教程(Python和R)

一、介绍 数据分类是机器学习中非常重要的任务。支持向量机(SVM)广泛应用于模式分类和非线性回归领域。 SVM算法的原始形式由Vladimir N.Vapnik...

4338
来自专栏marsggbo

使用numpy解决图像维度变换问题

在机器学习中经常会碰到各种图像数据集,有的是按照num*height*width*channel来存储的,而有的则是num*channel*height*wid...

411
来自专栏AI科技评论

干货 | 一篇文章教你用TensorFlow写名著

前言 最近看完了 LSTM 的一些外文资料,主要参考了 Colah 的 blog以及 Andrej Karpathy blog的一些关于 RNN 和 LST...

3588
来自专栏机器学习和数学

[机智的机器在学习] 利用TensorFlow实现多元线性回归分类器

从今天的推文开始,我打算把经典的机器学习算法,都用tf实现一遍。这样一来可以熟悉一下机器学习算法,二来可以对tf有比较好的掌握,如果你是新手,那就跟着我的节奏,...

3078
来自专栏AI研习社

干货 | 一篇文章教你用TensorFlow写名著

前言 最近看完了 LSTM 的一些外文资料,主要参考了 Colah 的 blog以及 Andrej Karpathy blog的一些关于 RNN 和 LST...

3465
来自专栏杨熹的专栏

Logistic regression 为什么用 sigmoid ?

1193
来自专栏https://www.cnblogs.com/L

【TensorFlow篇】--Tensorflow框架实现SoftMax模型识别手写数字集

本文讲述用Tensorflow框架实现SoftMax模型识别手写数字集,来实现多分类。

771
来自专栏决胜机器学习

机器学习(十一) ——神经网络基础

机器学习(十一)——神经网络基础 (原创内容,转载请注明来源,谢谢) 一、概述 神经网络,可以理解为输入的内容,经过一系列的内部的处理,得到输出的假设函数。简...

3426

在Python中用一个长短期记忆网络来演示记忆

长期短期记忆(LSTM)网络是一种能够在长序列上学习的递归神经网络。

54511

扫码关注云+社区