梳理caffe代码python_layer(十五)

这一层使用python来调用数据什么的,先看看一些科普知识:

boost::python库是pyhon和c++相互交互的框架,可以再python中调用c++的类和方法,也可以让c++调用python的类和方法python自身提供了一个Python/C API用来实现python和c++的交互,boost::python是Python/C API的包装,所以用起来更简单一些。Python对一个动态类型的语言,C++是一个静态类型的语言,对于Python中的变量类型,Boost.Python都有相应的类对应,他们都是boost::python::object的子类。boost::python::object 包装了PyObject *,关于Object的详细成员函数和变量可以看官网:here。

PyObject

在Python 中,所有的东西都是对象,而所有的对象都拥有一些相同的内容,这些内容在PyObject 中定义,PyObject 是整个Python 对象机制的核心。

 [object.h]
typedef struct _object {
PyObject_HEAD
} PyObject;
这个结构体是Python 对象机制的核心基石,从代码中可以看到,Python 对象的秘密都隐藏在PyObject_HEAD 这个宏中。
[object.h]
#ifdef Py_TRACE_REFS
/* Define pointers to support a doubly-
linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA \
struct _object *_ob_next; \
struct _object *_ob_prev;
#define _PyObject_EXTRA_INIT 0, 0,
#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif
/* PyObject_HEAD defines the initial
segment of every PyObject. */
#define PyObject_HEAD \
_PyObject_HEAD_EXTRA \
int ob_refcnt; \
struct _typeobject *ob_type;
在实际发布的Python 中,PyObject 的定义非常简单:
 [object.h]
typedef struct _object {
int ob_refcnt;
struct _typeobject *ob_type;
} PyObject;

在PyObject 的定义中,整型变量ob_refcnt 与Python 的内存管理机制有关,它实现了基于引用计数的垃圾收集机制。对于某一个对象A,当有一个新的PyObject *引用该对象时,A 的引用计数应该增加;而当这个PyObject *被删除时,A 的引用计数应该减少。当A 的引用计数减少到0 时,A 就可以从堆上被删除,以释放出内存供别的对象使用。在ob_refcnt 之外,我们注意到ob_type 是一个指向_typeobject 结构体的指针,那么这个结构体是一个什么东西呢?实际上这个结构体对应着Python 内部的一种特殊对象,它是用来指定一个对象类型的类型对象。这个类型对象我们将在后边详细地分析。现在我们看到了,在Python 中,对象机制的核心其实非常简单,一个是引用计数,一个就是类型信息。

在PyObject 中定义了每一个Python 对象都必须有的内容,这些内容将出现在每一个Python 对象所占有的内存的最开始的字节中。这句话的另一个意思是,每一个Python 对象除了必须有这个PyObject 内容外,似乎还应该占有一些额外的内存,放置些其他的东西。没错,倘若所有的Python 对象都只包含PyObject,那Python 中岂不是只有唯一的一种对象了,这可是大大的不妙。在PyObject 中定义的内容仅仅是每一个Python 对象都必须拥有的一部分内容,以我们将在下一章剖析的整数对象为例子,你可以看到对象中除PyObject 之外“其他的东西”究竟是些什么东西。

 [intobject.h]
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
Python 的整数对象中,除了PyObject,还有一个额外的long 变量,我们说一个整数当然应该有一个值,这个“值”的信息就保存在ob_ival 中。同样,Python 中的字符串对象、list 对象、dict 对象、成千上万的其他对象,都在PyObject 之外保存了属于自己的特殊的信息。通过这种方式c++可以平滑的操作python对象。Boost.Python的主要目标既保持Python的编程风格同时又提供C++和Python的双向映射。
python代码:
  1. def f(x, y):
         if(y =='foo'):
             x[3:7]='bar'
         else:
             x.items += y(3, x)
         return x
    def getfunc():
       return f;
c++重写代码
  1. object f(object x, object y){
         if(y =="foo")
             x.slice(3,7)="bar";
         else
             x.attr("items")+= y(3, x);
         return x;
    }
    object getfunc(){
        return object(f);
    }
Python::Object是一个抽象父类,对Python的每个类型都实现了一个对应的子类。
  • list
  • dict
  • tuple
  • str
  • long_
  • enum
Python::Object对应一个Python对象,那么c++怎么获取Python对象的值呢,这个需要使用Python::extract方法
  1. double d=python::extract<double>(obj)
通过PyObject*构造一个boost::python::object对象。
boost::python::object o(boost::python::handle<>(pyobj));
这样情况下. o管理pyobj, 不会增加pyobj的引用计数。
  1. boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj)));
这中情况下,会调用Py_INCREF ,当O对象生命周期结束 ,pyobj不会析析构掉
 
怎么从python::object对象中获取PyObject* :
obj.ptr()
python_layer头文件:
#ifndef CAFFE_PYTHON_LAYER_HPP_
#define CAFFE_PYTHON_LAYER_HPP_

#include <boost/python.hpp>
#include <vector>

#include "caffe/layer.hpp"

namespace bp = boost::python;

namespace caffe {

template <typename Dtype>
class PythonLayer : public Layer<Dtype> {
 public:
//通过PyObject,输入参数的内容
  PythonLayer(PyObject* self, const LayerParameter& param)
      : Layer<Dtype>(param), self_(bp::handle<>(bp::borrowed(self))) { }
//输入数据
  virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
    self_.attr("param_str") = bp::str(
        this->layer_param_.python_param().param_str());
    self_.attr("setup")(bottom, top);
  }
//调整数据的形状
  virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
    self_.attr("reshape")(bottom, top);
  }
//采用并行线程
  virtual inline bool ShareInParallel() const {
    return this->layer_param_.python_param().share_in_parallel();
  }

  virtual inline const char* type() const { return "Python"; }

 protected:
//前向传播
  virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
    self_.attr("forward")(bottom, top);
  }
//后向传播
  virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
    self_.attr("backward")(top, propagate_down, bottom);
  }

 private:
//私有变量,不允许更改
  bp::object self_;
};

}  // namespace caffe

#endif

你可能感兴趣的:(梳理caffe代码python_layer(十五))