tiny_cnn源码阅读(4)-convolutional_layer

原创 2016年06月02日 22:39:45

convolutional_layer是用来计算卷积的。

connection_table

connecction_table是一个二维数组,(x,y)的值(true/false)表示x和y是否关联,即是用来判断和那几个feature_map连接的。在其实现中,内部数据结构为一个bool类型队列,函数is_connected判断是否关联

bool is_connected(cnn_size_t x, cnn_size_t y) const {//判断x,y位置的值即可。如果connection table为空,那么一直为真
        return is_empty() ? true : connected_[y * cols_ + x];
    }

index3d

这个数据结构只是记录图像尺寸,即宽-高-深度,实际上并不持有数据

template <typename T>
struct index3d {//用来保存图像的数据结构,实际上并不保存数据,宽-高-深度,共三个参数
    index3d(T width, T height, T depth) {
        reshape(width, height, depth);
    }

    index3d() : width_(0), height_(0), depth_(0) {}

    void reshape(T width, T height, T depth) {
        width_ = width;
        height_ = height;
        depth_ = depth;

        if ((long long) width * height * depth > std::numeric_limits<T>::max())
            throw nn_error(
            format_str("error while constructing layer: layer size too large for tiny-cnn\nWidthxHeightxChannels=%dx%dx%d >= max size of [%s](=%d)",
            width, height, depth, typeid(T).name(), std::numeric_limits<T>::max()));
    }

    T get_index(T x, T y, T channel) const {
        assert(x >= 0 && x < width_);
        assert(y >= 0 && y < height_);
        assert(channel >= 0 && channel < depth_);
        return (height_ * channel + y) * width_ + x; 
    }

    T area() const {
        return width_ * height_;
    }

    T size() const {
        return width_ * height_ * depth_;
    }

    T width_;
    T height_;
    T depth_;
};

convolutional_layer

convolutional_layer用来计算卷积,先看一下其成员变量:

const vec_t* prev_out_padded_[CNN_TASK_SIZE];//指针,pad_type_ == padding::same时,填充用
    vec_t* prev_out_buf_[CNN_TASK_SIZE];
    vec_t  prev_delta_padded_[CNN_TASK_SIZE];//用来填充prev_delta_
    vec_t  prev_delta2_padded_;//用来填充prev_delta2_

    connection_table tbl_;//connection_table
    index3d<cnn_size_t> in_;//输入数据大小
    index3d<cnn_size_t> in_padded_;//填充大小,用来内存对齐
    index3d<cnn_size_t> out_;//输出大小
    index3d<cnn_size_t> weight_;//权重大小
    padding pad_type_;//枚举变量,输出大小是原图像大小还是卷积后:原图像-卷积核+1
    size_t w_stride_;//stride表示窗口移动的大小。卷积时窗口每次滑动1,但是pooling时每次滑动的大小为卷积核大小
    size_t h_stride_;

pad_type_表示填充类型。卷积时,如果如果不填充,卷积核每次滑动距离w_stride_h_stride_都为1,那么卷积后图像:高=原高度-卷积核高+1;宽=原宽度-卷积核宽度+1。

卷积层重点是卷积,看一下卷积函数

 virtual const vec_t& forward_propagation(const vec_t& in_raw, size_t worker_index) override
    {
        copy_and_pad_input(in_raw, static_cast<int>(worker_index));

        vec_t &a = a_[worker_index]; // w*x,输出
        vec_t &out = output_[worker_index]; // output
        const vec_t &in = *(prev_out_padded_[worker_index]); // input

        std::fill(a.begin(), a.end(), float_t(0));

        for_i(parallelize_, out_.depth_, [&](int o) {
            for (cnn_size_t inc = 0; inc < in_.depth_; inc++) {
                if (!tbl_.is_connected(o, inc)) continue;//通过connection_table判断是否有关联,connection_table为空则全部关联

                const float_t *pw = &this->W_[weight_.get_index(0, 0, in_.depth_ * o + inc)];//权重
                const float_t *pi = &in[in_padded_.get_index(0, 0, inc)];//输入
                float_t *pa = &a[out_.get_index(0, 0, o)];//pa用来保存计算结果

                //计算输出的值
                for (cnn_size_t y = 0; y < out_.height_; y++) {
                    for (cnn_size_t x = 0; x < out_.width_; x++) {
                        const float_t * ppw = pw;//指向权重,下面ppi指向输入数据
                        const float_t * ppi = pi + (y * h_stride_) * in_padded_.width_ + x * w_stride_;
                        float_t sum = float_t(0);

                        //下面是计算卷积
                        // should be optimized for small kernel(3x3,5x5)
                        for (cnn_size_t wy = 0; wy < weight_.height_; wy++) {
                            for (cnn_size_t wx = 0; wx < weight_.width_; wx++) {
                                sum += *ppw++ * ppi[wy * in_padded_.width_ + wx];//卷积为:sum(权重x某一像素)
                            }
                        }
                        pa[y * out_.width_ + x] += sum;//结果保存到输出
                    }
                }
            }
            //bias不为空时还要加上bias
            if (!this->b_.empty()) {
                float_t *pa = &a[out_.get_index(0, 0, o)];
                float_t b = this->b_[o];
                std::for_each(pa, pa + out_.width_ * out_.height_, [&](float_t& f) { f += b; });
            }
        });

        for_i(parallelize_, out_size_, [&](int i) {
            out[i] = h_.f(a, i);
        });

        CNN_LOG_VECTOR(in_raw, "[pc]in");
        CNN_LOG_VECTOR(W_, "[pc]w");
        CNN_LOG_VECTOR(a, "[pc]a");
        CNN_LOG_VECTOR(out, "[pc]forward");

        return next_ ? next_->forward_propagation(out, worker_index) : out;//后面有网络,就再计算下一层
    }

上面变量中a_用来保存:wx+b;out用来保存:f(wx+b)
权重保存的W_中,输入数据为函数参数in_raw
卷积时,遍历输出的每个像素点:

//计算输出的值
                for (cnn_size_t y = 0; y < out_.height_; y++) {
                    for (cnn_size_t x = 0; x < out_.width_; x++) {

之后遍历卷积核,卷积某个区域,计算wx:

for (cnn_size_t wy = 0; wy < weight_.height_; wy++) {
                            for (cnn_size_t wx = 0; wx < weight_.width_; wx++) {

随后在加上偏置bias,计算最终结果

版权声明:本文为博主原创文章,未经博主允许不得转载。

tiny-cnn开源库的使用(MNIST)

tiny-cnn开源库的使用(MNIST)
  • fengbingchun
  • fengbingchun
  • 2016年01月24日 15:09
  • 16949

C++卷积神经网络实例:tiny_cnn代码详解(1)——开篇

在之前完成了《C++开发人脸性别识别教程》系列博客的编写之后,我开始将工作重点转移到与我的研究生课题关联更为密切的深度学习上来。深度学习编程有几个经典的框架,首屈一指的当属Caffe,然后还有Matl...
  • u013088062
  • u013088062
  • 2016年03月09日 21:42
  • 16363

Tiny_cnn用自己的数据训练和测试

Tiny_cnn是一个简洁的纯C++11实现的深度学习框架。在Windows系统只需高版本的VS(VS2013或者更高本)+opencv即可,本人用的是VS2013+opencv2.4.11。关于ti...
  • u012507022
  • u012507022
  • 2016年07月03日 17:18
  • 8211

tiny_cnn源码阅读(1)-编译运行源码

机器学习是理论性很强的一门课程,在工程实践时,常常难以把理论和代码结合起来。想通过一个工程来学习一下机器学习中的卷积神经网络。 tiny_cnn是c++写的实现cnn的代码,想通过代码来了解理论,学...
  • KangRoger
  • KangRoger
  • 2016年05月29日 13:31
  • 1749

tiny-cnn配置

参考链接: http://blog.csdn.net/fengbingchun/article/details/50573841 http://blog.csdn.net/linshuhe1/art...
  • threadroc
  • threadroc
  • 2016年12月24日 16:14
  • 693

Tiny_cnn用自己的数据训练和测试

转自:http://blog.csdn.net/u012507022/article/details/51815701 Tiny_cnn是一个简洁的纯C++11实现的深度学习框架。在Wind...
  • haima1998
  • haima1998
  • 2017年06月25日 16:36
  • 401

C++卷积神经网络实例:tiny_cnn代码详解(3)——层间继承关系

在上一篇博文中我们顺利将tiny_cnn的程序调试通过,在这篇博文中我们尝试从整体角度给出对tiny_cnn这个深度学习框架的解读,重点论述一下其各个层直接类封装的继承关系。  一、卷积神经网络快速入...
  • u013088062
  • u013088062
  • 2016年03月11日 21:48
  • 9347

C++卷积神经网络实例:tiny_cnn代码详解(12)——从CNN中看多态性

最近由于在准备论文的相关事宜,导致博客的更新速度有点缓慢,望大家见谅。不过该更新还是要更新的,所以今天我就挤出一点时间来更新一篇。由于之前的博文已经将tiny_cnn中相关的网络层结构介绍的差不多,接...
  • u013088062
  • u013088062
  • 2016年04月02日 09:57
  • 5164

卷积神经网络tiny_cnn代码

  • 2016年12月29日 21:31
  • 12.62MB
  • 下载

tiny-cnn执行过程分析(MNIST)

tiny-cnn执行过程分析(MNIST)
  • fengbingchun
  • fengbingchun
  • 2016年01月31日 17:42
  • 5284
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:tiny_cnn源码阅读(4)-convolutional_layer
举报原因:
原因补充:

(最多只允许输入30个字)