caffe 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 87a24cb6239268eff1a716f0f770edf6b708d0f3
4
+ data.tar.gz: 4e589a9b416d7191567d6d07bc7b127d6bded9d4
5
+ SHA512:
6
+ metadata.gz: 768510fe5634d31bd847593679836ee2b123264693ce3698dd421c30129fa76b7c26194939669e4e55c904c5def2825b5941a9cafec8df0cc2f756a9d146ac15
7
+ data.tar.gz: b3a6c3de6efe2190be72ac7637c81f300182b7c5b4417fedbfff28eaf42a5f02eab71dc00c17aadf752f104ad60ec1a6110f983d1c78f786a1b1e8f9629da2cb
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Tiny Tiny
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,110 @@
1
+ # Ruby Caffe #
2
+
3
+ A ruby wrapper for the deep learning framework
4
+
5
+ ## Linking caffe ##
6
+
7
+ There is a linking problem since `caffe` doesn't provide an official installation plan, but everything in its build path / distribute path instead of somewhere like `/usr` or `/usr/local`
8
+
9
+ Now `extconf.rb` only checks for `cblas.h` (or `mkl.h` if you are using Intel MKL), `-lcaffe` and `caffe/caffe.hpp`, other dependent headers of `caffe` (such as `leveldb`) should be installed in default search path (`/usr/include` or `/usr/local/include`), or you can use `pkg-config` to add additional options in `LDFLAGS` & `CFLAGS` directly (see below)
10
+
11
+ There are three options to specify the path of the libraries & headers:
12
+
13
+ ### `pkg-config` ###
14
+
15
+ Ruby `mkmf` provide convenient use of `pkg-config`, which is included in `extconf.rb`. It will search for `caffe.pc` in `pkg-config` search paths (typically `/usr/lib/pkgconfig` and `/usr/local/lib/pkgconfig`)
16
+
17
+ However `caffe` doesn't provide a `.pc` file, but you can write one yourself, here is an example:
18
+
19
+ ```
20
+ prefix=/usr/local/caffe
21
+ libdir=${prefix}/lib
22
+ includedir=${prefix}/include
23
+ blasinclude=/usr/local/openblas/include
24
+ otherflags=-DCPU_ONLY
25
+
26
+ Name: caffe
27
+ Description: caffe C++ lib
28
+ Version: 1.0.0-rc4
29
+ Libs: -L${libdir} -lcaffe
30
+ CFlags: ${otherflags} -I${includedir} -I${blasinclude}
31
+ ```
32
+
33
+ Note that `pkg-config` directly adds `LDFLAGS` & `CFLAGS`, so you can add flags other than what `extconf.rb` specifies
34
+
35
+ ### Build Flags ###
36
+
37
+ Build flags can be passed to `extconf.rb` to specify the `caffe` path and other configuration:
38
+
39
+ - `--with-caffe-dir=<path>`: specify the caffe path, in which `<path>/include` contains the headers and `<path>/lib` contains the library
40
+ - `--with-caffe-include` & `--with-caffe-lib`: specify the caffe header and lib path separately
41
+ - `--with-blas-include=<path>`: specify the path that contains the blas headers
42
+ - `--with-blas-dir=<path>`: the same as `--with-blas-include=<path>/include`
43
+ - `--enable-gpu` & `--disable-gpu`: specify GPU mode of caffe, enabled by default
44
+ - `--enable-mkl` & `--disable-mkl`: specify if Intel MKL is used as blas library, if neither flags are set `extconf.rb` will search for `cblas.h` first and then `mkl.h` if fails
45
+
46
+ If `rake` is used to build the extension, use:
47
+
48
+ ```shell
49
+ $ rake compile -- <build flags>
50
+ ```
51
+
52
+ If installing from `gem`, use:
53
+
54
+ ```shell
55
+ $ gem install caffe -- <build flags>
56
+ ```
57
+
58
+ If installing from `bundler`, use:
59
+
60
+ ```shell
61
+ $ bundle config build.caffe <build flags>
62
+
63
+ $ bundle install
64
+ ```
65
+
66
+ ### Put everything in search path ###
67
+
68
+ If you put all the headers and libs required in default search path (like `/usr/local` & `/usr`), and use the default setting (with GPU mode) then everything should be ok
69
+
70
+ ## Build ##
71
+
72
+ Now the project is not a gem project, so it can be built by `rake`
73
+
74
+ First, use `bundler` to install all the dependencies:
75
+
76
+ ```shell
77
+ $ bundle install
78
+ ```
79
+
80
+ Then, use `rake` to build:
81
+
82
+ ```shell
83
+ $ rake compile -- <build flags>
84
+ ```
85
+
86
+ Test with:
87
+
88
+ ```shell
89
+ $ rake test
90
+ ```
91
+
92
+ or after compilation:
93
+
94
+ ```shell
95
+ $ rake spec
96
+ ```
97
+
98
+ require the lib with:
99
+
100
+ ```ruby
101
+ require './lib/caffe'
102
+ ```
103
+
104
+ ## Author ##
105
+
106
+ Tiny Tiny
107
+
108
+ ## License ##
109
+
110
+ MIT
@@ -0,0 +1,145 @@
1
+ #include "blob.hpp"
2
+ #include "util.hpp"
3
+ #include <rice/Data_Type.hpp>
4
+ #include <rice/Constructor.hpp>
5
+ #include <rice/Module.hpp>
6
+ #include <stdexcept>
7
+ #include <algorithm>
8
+
9
+ using namespace Rice;
10
+
11
+ BlobCursor::BlobCursor(Object blob, bool diff) : diff(diff) {
12
+ ref = from_ruby<Blob *>(blob);
13
+ }
14
+
15
+ void BlobCursor::checkValid() const {
16
+ int n = indices.size();
17
+ const std::vector<int> &shape = ref -> shape();
18
+ if (n > shape.size()) throw std::logic_error("Invalid BlobCursor!");
19
+ for (int i = 0; i < n; ++i) {
20
+ if (shape[i] <= indices[i]) {
21
+ throw std::out_of_range("Index out of range!");
22
+ }
23
+ }
24
+ }
25
+
26
+ BlobCursor BlobCursor::next(int index) const {
27
+ BlobCursor ret = *this;
28
+ ret.indices.push_back(index);
29
+ ret.checkValid();
30
+ return ret;
31
+ }
32
+
33
+ Object BlobCursor::get(int index) const {
34
+ BlobCursor next = this -> next(index);
35
+ if (next.indices.size() == ref -> shape().size()) {
36
+ return to_ruby(*next.begin());
37
+ } else {
38
+ return to_ruby(next);
39
+ }
40
+ }
41
+
42
+ Object BlobCursor::set(int index, Object data) {
43
+ BlobCursor next = this -> next(index);
44
+ if (next.indices.size() == ref -> shape().size()) {
45
+ *next.mbegin() = from_ruby<float>(data);
46
+ return data;
47
+ } else {
48
+ throw std::logic_error("Not implemented!");
49
+ }
50
+ }
51
+
52
+ const float *BlobCursor::begin() {
53
+ std::vector<int> full = indices;
54
+ full.resize(ref -> shape().size());
55
+ const float *base = diff ? ref -> cpu_diff() : ref -> cpu_data();
56
+
57
+ return base + ref -> offset(full);
58
+ }
59
+
60
+ const float *BlobCursor::end() {
61
+ return begin() + count();
62
+ }
63
+
64
+ float *BlobCursor::mbegin() {
65
+ std::vector<int> full = indices;
66
+ full.resize(ref -> shape().size());
67
+ float *base = diff ? ref -> mutable_cpu_diff() : ref -> mutable_cpu_data();
68
+
69
+ return base + ref -> offset(full);
70
+ }
71
+
72
+ float *BlobCursor::mend() {
73
+ return mbegin() + count();
74
+ }
75
+
76
+ int BlobCursor::count() const {
77
+ const std::vector<int> &shape = ref -> shape();
78
+ int n = shape.size();
79
+ int ans = 1;
80
+ for (int k = indices.size(); k < n; ++k) {
81
+ ans *= shape[k];
82
+ }
83
+ return ans;
84
+ }
85
+
86
+ int BlobCursor::copy(Array data) {
87
+ int n = std::min(int(data.size()), count());
88
+ float *base = mbegin();
89
+ for (int i = 0; i < n; ++i) {
90
+ base[i] = from_ruby<float>(data[i]);
91
+ }
92
+ return n;
93
+ }
94
+
95
+ static Object getBlobData(Object self) {
96
+ return to_ruby(BlobCursor(self));
97
+ }
98
+
99
+ static Object getBlobDiff(Object self) {
100
+ return to_ruby(BlobCursor(self, true));
101
+ }
102
+
103
+ static Array getBlobShape(Object self) {
104
+ const std::vector<int> &shape = from_ruby<Blob *>(self) -> shape();
105
+ return Array(shape.begin(), shape.end());
106
+ }
107
+
108
+ static Array setBlobShape(Object self, Array shape) {
109
+ if (shape.size() > 4) {
110
+ throw std::invalid_argument("Shape dimension exceeds 4!");
111
+ }
112
+ Blob *blob = from_ruby<Blob *>(self);
113
+ blob -> Reshape(arrayToVector<int>(shape));
114
+ return shape;
115
+ }
116
+
117
+ struct BlobConstructor {
118
+ static void construct(Object self, Array shape) {
119
+ if (shape.size() > 4) {
120
+ throw std::invalid_argument("Shape dimension exceeds 4!");
121
+ }
122
+ DATA_PTR(self.value()) = new Blob(arrayToVector<int>(shape));
123
+ }
124
+ };
125
+
126
+ void Init_blob() {
127
+ Module rb_mCaffe = define_module("Caffe");
128
+
129
+ Data_Type<Blob> rb_cBlob = rb_mCaffe
130
+ .define_class<Blob>("Blob")
131
+ .define_constructor(BlobConstructor())
132
+ .define_method("data", getBlobData)
133
+ .define_method("diff", getBlobDiff)
134
+ .define_method("shape", getBlobShape)
135
+ .define_method("shape=", setBlobShape);
136
+
137
+ Data_Type<BlobCursor> rb_cCursor = rb_cBlob
138
+ .define_class<BlobCursor>("Cursor")
139
+ .define_constructor(Constructor<BlobCursor, Object, bool>())
140
+ .define_method("[]", &BlobCursor::get)
141
+ .define_method("[]=", &BlobCursor::set)
142
+ .define_method("size", &BlobCursor::count)
143
+ .define_iterator(&BlobCursor::begin, &BlobCursor::end)
144
+ .define_method("copy_from!", &BlobCursor::copy);
145
+ }
@@ -0,0 +1,32 @@
1
+ #ifndef __BLOB
2
+ #define __BLOB
3
+
4
+ #include <rice/Class.hpp>
5
+ #include <rice/Array.hpp>
6
+ #include <caffe/caffe.hpp>
7
+ #include <vector>
8
+ #include <stdexcept>
9
+
10
+ typedef caffe::Blob<float> Blob;
11
+
12
+ class BlobCursor {
13
+ std::vector<int> indices;
14
+ Blob *ref;
15
+ bool diff;
16
+ void checkValid(void) const;
17
+ public:
18
+ BlobCursor(Rice::Object blob, bool diff = false);
19
+ BlobCursor next(int index) const;
20
+ Rice::Object get(int index) const;
21
+ Rice::Object set(int index, Rice::Object data);
22
+ const float *begin(void);
23
+ const float *end(void);
24
+ float *mbegin(void);
25
+ float *mend(void);
26
+ int count(void) const;
27
+ int copy(Rice::Array data);
28
+ };
29
+
30
+ void Init_blob(void);
31
+
32
+ #endif
@@ -0,0 +1,13 @@
1
+ #include <caffe/caffe.hpp>
2
+ #include "common.hpp"
3
+ #include "blob.hpp"
4
+ #include "net.hpp"
5
+
6
+ extern "C"
7
+ void Init_caffe() {
8
+ ::google::InitGoogleLogging("ruby-caffe");
9
+
10
+ Init_common();
11
+ Init_blob();
12
+ Init_net();
13
+ }
@@ -0,0 +1,36 @@
1
+ #include "common.hpp"
2
+ #include <rice/Module.hpp>
3
+ #include <rice/Class.hpp>
4
+ #include <caffe/caffe.hpp>
5
+
6
+ using namespace Rice;
7
+
8
+ #define EnumCast(type, classname) template<> \
9
+ type from_ruby<type>(Object self) { \
10
+ int num = from_ruby<int>(self.call("to_i")); \
11
+ return type(num); \
12
+ } \
13
+ template<> \
14
+ Object to_ruby<type>(const type &self) { \
15
+ int num = int(self); \
16
+ Object cl = (classname); \
17
+ return cl.call("fetch", num); \
18
+ }
19
+
20
+ EnumCast(caffe::Phase, define_module("Caffe")
21
+ .const_get("Phase"));
22
+ EnumCast(caffe::Caffe::Brew, Class(define_module("Caffe")
23
+ .const_get("SolverParameter"))
24
+ .const_get("SolverMode"));
25
+
26
+ void Init_common() {
27
+ Module rb_mCaffe = define_module("Caffe")
28
+ .define_module_function("mode", caffe::Caffe::mode)
29
+ .define_module_function("mode=", caffe::Caffe::set_mode)
30
+ .define_module_function("solver_count", caffe::Caffe::solver_count)
31
+ .define_module_function("solver_count=", caffe::Caffe::set_solver_count)
32
+ .define_module_function("solver_rank", caffe::Caffe::solver_rank)
33
+ .define_module_function("solver_rank=", caffe::Caffe::set_solver_rank)
34
+ .define_module_function("multiprocess", caffe::Caffe::multiprocess)
35
+ .define_module_function("multiprocess=", caffe::Caffe::set_multiprocess);
36
+ }
@@ -0,0 +1,17 @@
1
+ #ifndef __COMMON
2
+ #define __COMMON
3
+
4
+ #include <caffe/caffe.hpp>
5
+ #include <rice/Data_Type.hpp>
6
+
7
+ #define DefineEnumCast(type) template<> \
8
+ type from_ruby<type>(Rice::Object); \
9
+ template<> \
10
+ Rice::Object to_ruby<type>(const type &)
11
+
12
+ DefineEnumCast(caffe::Phase);
13
+ DefineEnumCast(caffe::Caffe::Brew);
14
+
15
+ void Init_common(void);
16
+
17
+ #endif
@@ -0,0 +1,39 @@
1
+ require File.expand_path '../mkmf_cxx', __FILE__
2
+
3
+ @libdir_basename = 'lib'
4
+
5
+ dir_config 'caffe'
6
+ dir_config 'blas'
7
+
8
+ checking_for 'caffe.pc' do
9
+ pkg_config 'caffe'
10
+ end
11
+
12
+ $libs = ''
13
+
14
+ $defs.push '-DCPU_ONLY' unless enable_config 'gpu', true
15
+
16
+ mkl = enable_config 'mkl', nil
17
+
18
+ if mkl == true || !have_header('cblas.h')
19
+ $defs.push '-DUSE_MKL'
20
+ if mkl == false || !have_header('mkl.h')
21
+ puts <<MSG
22
+ blas header not found.
23
+ use build flag "--with-blas-dir=/path/to/blas" to specify the blas path.
24
+ or use "--with-blas-include" to specify the include path.
25
+ MSG
26
+ raise
27
+ end
28
+ end
29
+
30
+ unless library?('caffe') && header_cxx?('caffe/caffe.hpp')
31
+ puts <<MSG
32
+ caffe not found.
33
+ use build flag "--with-caffe-dir=/path/to/caffe" to specify the caffe path.
34
+ or use "--with-caffe-include" & "--with-caffe-lib" to specify include path & lib path separately.
35
+ MSG
36
+ raise
37
+ end
38
+
39
+ create_makefile 'caffe/caffe'
@@ -0,0 +1,158 @@
1
+ require 'mkmf-rice'
2
+
3
+ $CXXFLAGS = ''
4
+
5
+ TRY_LINK.sub!(/^#{Regexp.quote($CXX)}/, '$(CXX)')
6
+ $LDSHARED_CXX.sub!(/^#{Regexp.quote($CXX)}/, '$(CXX)')
7
+ $CXX = '$(CXX)'
8
+
9
+ if CONFIG['target_os'] == 'mswin32' && $RICE_USING_MINGW32
10
+ init_rice_mkmf_cross_compile_mingw2_for_vc6
11
+ end
12
+
13
+ def configuration(srcdir)
14
+ configuration = configuration_orig(srcdir)
15
+ configuration.each do |config|
16
+ # Make sure we link the extension using the C++ compiler
17
+ config.gsub!(/^LDSHARED\s*=.*$/, "LDSHARED = #{$LDSHARED_CXX}")
18
+
19
+ # Make sure set the C++ flags correctly
20
+ config.gsub!(/^CXXFLAGS\s*=.*$/, "CXXFLAGS = $(CFLAGS) #{$CXXFLAGS}")
21
+ end
22
+ configuration
23
+ end
24
+
25
+ RbConfig::CONFIG['CXXPP'] = RbConfig::CONFIG['CXX'] + ' -E'
26
+ CONFTEST_CC = "#{CONFTEST}.cc".freeze
27
+
28
+ def create_tmpsrc_cxx(src)
29
+ src = "#{COMMON_HEADERS}\n#{src}"
30
+ src = yield(src) if block_given?
31
+ src.gsub!(/[ \t]+$/, '')
32
+ src.gsub!(/\A\n+|^\n+$/, '')
33
+ src.sub!(/[^\n]\z/, "\\&\n")
34
+ count = 0
35
+ begin
36
+ open(CONFTEST_CC, 'wb') do |cfile|
37
+ cfile.print src
38
+ end
39
+ rescue Errno::EACCES
40
+ if (count += 1) < 5
41
+ sleep 0.2
42
+ retry
43
+ end
44
+ end
45
+ src
46
+ end
47
+
48
+ def try_do_cxx(src, command, *opts, &b)
49
+ unless have_devel?
50
+ raise <<MSG
51
+ The compiler failed to generate an executable file.
52
+ You have to install development tools first.
53
+ MSG
54
+ end
55
+ begin
56
+ src = create_tmpsrc_cxx(src, &b)
57
+ xsystem(command, *opts)
58
+ ensure
59
+ log_src(src)
60
+ MakeMakefile.rm_rf "#{CONFTEST}.dSYM"
61
+ end
62
+ end
63
+
64
+ def link_command(ldflags, opt = '', libpath = $DEFLIBPATH | $LIBPATH)
65
+ librubyarg = $extmk ? $LIBRUBYARG_STATIC : '$(LIBRUBYARG)'
66
+ conf = RbConfig::CONFIG.merge('hdrdir' => $hdrdir.quote,
67
+ 'src' => CONFTEST_CC,
68
+ 'arch_hdrdir' => $arch_hdrdir.quote,
69
+ 'top_srcdir' => $top_srcdir.quote,
70
+ 'INCFLAGS' => $INCFLAGS,
71
+ 'CPPFLAGS' => $CPPFLAGS,
72
+ 'CXXFLAGS' => $CXXFLAGS,
73
+ 'CFLAGS' => $CFLAGS,
74
+ 'ARCH_FLAG' => $ARCH_FLAG,
75
+ 'LDFLAGS' => "#{$LDFLAGS} #{ldflags}",
76
+ 'LOCAL_LIBS' => "#{$LOCAL_LIBS} #{$libs}",
77
+ 'LIBS' => "#{librubyarg} #{opt} #{$LIBS}")
78
+ conf['LIBPATH'] = libpathflag(libpath.map do |s|
79
+ RbConfig.expand(s.dup, conf)
80
+ end)
81
+ RbConfig.expand(TRY_LINK.dup, conf)
82
+ end
83
+
84
+ def try_link0(src, opt = '', *opts, &b)
85
+ cmd = link_command('', opt)
86
+ if $universal
87
+ require 'tmpdir'
88
+ Dir.mktmpdir('mkmf_', oldtmpdir = ENV['TMPDIR']) do |tmpdir|
89
+ begin
90
+ ENV['TMPDIR'] = tmpdir
91
+ try_do_cxx(src, cmd, *opts, &b)
92
+ ensure
93
+ ENV['TMPDIR'] = oldtmpdir
94
+ end
95
+ end
96
+ else
97
+ try_do_cxx(src, cmd, *opts, &b)
98
+ end && File.executable?(CONFTEST + $EXEEXT)
99
+ end
100
+
101
+ def cxxpp_command(outfile, opt = '')
102
+ conf = RbConfig::CONFIG.merge('hdrdir' => $hdrdir.quote,
103
+ 'srcdir' => $srcdir.quote,
104
+ 'arch_hdrdir' => $arch_hdrdir.quote,
105
+ 'top_srcdir' => $top_srcdir.quote)
106
+ if $universal && (arch_flag = conf['ARCH_FLAG']) && !arch_flag.empty?
107
+ conf['ARCH_FLAG'] = arch_flag.gsub(/(?:\G|\s)-arch\s+\S+/, '')
108
+ end
109
+ flags = [$INCFLAGS, $CPPFLAGS, $CFLAGS, opt].join ' '
110
+ RbConfig.expand("$(CXXPP) #{flags} #{CONFTEST_CC} #{outfile}", conf)
111
+ end
112
+
113
+ def try_cxxpp(src, opt = '', *opts, &b)
114
+ try_do_cxx(src, cxxpp_command(CPPOUTFILE, opt), *opts, &b) &&
115
+ File.file?('conftest.i')
116
+ ensure
117
+ MakeMakefile.rm_f 'conftest*'
118
+ end
119
+
120
+ def trans_opt(opt)
121
+ [[:to_str], [:join, ' '], [:to_s]].each do |meth, *args|
122
+ return opt.send(meth, *args) if opt.respond_to?(meth)
123
+ end
124
+ end
125
+
126
+ def header_cxx?(header, preheaders = nil, opt = '', &b)
127
+ opt = "#{trans_opt opt} #{trans_opt $defs}"
128
+ checking_for header do
129
+ if try_cxxpp(cpp_include(preheaders) + cpp_include(header), opt, &b)
130
+ $defs.push(format('-DHAVE_%s', header.tr_cpp))
131
+ true
132
+ else
133
+ false
134
+ end
135
+ end
136
+ end
137
+
138
+ def try_library(libs, opt = '', &b)
139
+ opt = "#{trans_opt opt} #{libs}"
140
+ try_link(MAIN_DOES_NOTHING, opt, &b)
141
+ end
142
+
143
+ def library?(lib, opt = '', &b)
144
+ lib = with_config(lib + 'lib', lib)
145
+ checking_for format(LIBARG, lib) do
146
+ if COMMON_LIBS.include?(lib)
147
+ true
148
+ else
149
+ libs = append_library($libs, lib)
150
+ if try_library(libs, opt, &b)
151
+ $libs = libs
152
+ true
153
+ else
154
+ false
155
+ end
156
+ end
157
+ end
158
+ end