caffe 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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