caffe 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 87a24cb6239268eff1a716f0f770edf6b708d0f3
4
- data.tar.gz: 4e589a9b416d7191567d6d07bc7b127d6bded9d4
3
+ metadata.gz: 0a805f3a1f52051590a5a9f99655b5b0484e18c6
4
+ data.tar.gz: 460cb54ae69140bca4900bba9fa721f7658bae6e
5
5
  SHA512:
6
- metadata.gz: 768510fe5634d31bd847593679836ee2b123264693ce3698dd421c30129fa76b7c26194939669e4e55c904c5def2825b5941a9cafec8df0cc2f756a9d146ac15
7
- data.tar.gz: b3a6c3de6efe2190be72ac7637c81f300182b7c5b4417fedbfff28eaf42a5f02eab71dc00c17aadf752f104ad60ec1a6110f983d1c78f786a1b1e8f9629da2cb
6
+ metadata.gz: a1d5e15287db253830036f54bff7a20f6b07e86551ce8cf1d549b66428d130d57b731dfd62b305d843038f9564e0a9330204fff8bda19e29d163dd527160f45c
7
+ data.tar.gz: 4f104903a669231d236056855572c7060a5afed9c61713b20046578e4d1e4081b7d414253a72abb63fc0b62c280d7e93ee3dfc49f71236903d8c07c9aaaecae4
data/README.md CHANGED
@@ -45,21 +45,20 @@ Build flags can be passed to `extconf.rb` to specify the `caffe` path and other
45
45
 
46
46
  If `rake` is used to build the extension, use:
47
47
 
48
- ```shell
48
+ ```
49
49
  $ rake compile -- <build flags>
50
50
  ```
51
51
 
52
52
  If installing from `gem`, use:
53
53
 
54
- ```shell
54
+ ```
55
55
  $ gem install caffe -- <build flags>
56
56
  ```
57
57
 
58
58
  If installing from `bundler`, use:
59
59
 
60
- ```shell
60
+ ```
61
61
  $ bundle config build.caffe <build flags>
62
-
63
62
  $ bundle install
64
63
  ```
65
64
 
@@ -67,39 +66,108 @@ $ bundle install
67
66
 
68
67
  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
68
 
70
- ## Build ##
69
+ ## Installation ##
71
70
 
72
- Now the project is not a gem project, so it can be built by `rake`
71
+ ```
72
+ $ gem install caffe -- <build flags>
73
+ ```
73
74
 
74
- First, use `bundler` to install all the dependencies:
75
+ Using bundler:
75
76
 
76
- ```shell
77
+ ```
78
+ $ bundle config build.caffe <build flags>
77
79
  $ bundle install
78
80
  ```
79
81
 
80
- Then, use `rake` to build:
82
+ Require everything with:
83
+
84
+ ```ruby
85
+ require 'caffe'
86
+ ```
87
+
88
+ ## Development ##
89
+
90
+ First clone this repository:
91
+
92
+ ```
93
+ $ git clone git://github.com/gyf1214/ruby-caffe
94
+ ```
95
+
96
+ Then build all prerequisites for gem & test (proto files & test net):
97
+
98
+ ```
99
+ $ rake build:pre
100
+ ```
101
+
102
+ When building proto files, the caffe path (which contains `proto/caffe.proto`) can be specified by `ENV['CAFFE']`, i.e.
103
+
104
+ ```
105
+ $ CAFFE=/path/to/caffe rake build:pre
106
+ ```
81
107
 
82
- ```shell
108
+ Or by default the path is `.`, so you can just copy / link your `caffe.proto` to `proto/`
109
+
110
+ Compile C++ extension with:
111
+
112
+ ```
83
113
  $ rake compile -- <build flags>
84
114
  ```
85
115
 
86
- Test with:
116
+ Build flags & other methods to link caffe are described above
87
117
 
88
- ```shell
118
+ Test the code with (which include the rubocop code style check):
119
+
120
+ ```
89
121
  $ rake test
90
122
  ```
91
123
 
92
- or after compilation:
124
+ Build the gem with:
125
+
126
+ ```
127
+ $ rake build
128
+ ```
129
+
130
+ Which will run all tests and build the gem in `pkg/caffe-<version>.gem`
131
+
132
+ Install the gem locally with:
133
+
134
+ ```
135
+ $ rake install
136
+ ```
137
+
138
+ ### Other rake tasks ###
139
+
140
+ ```
141
+ $ rake rubocop
142
+ ```
93
143
 
94
- ```shell
144
+ Run the rubocop code style check, you can also run auto correct with `rake rubocop:auto_correct`
145
+
146
+ ```
95
147
  $ rake spec
96
148
  ```
97
149
 
98
- require the lib with:
150
+ Run rspec only, without checking the dependencies, note that `build:pre` & `compile` must be completed before
151
+
152
+ ```
153
+ $ rake build:proto
154
+ $ rake build:test
155
+ ```
156
+
157
+ The two tasks build proto files and trained model for testing respectively. `ENV['CAFFE']` can be specified when building proto
99
158
 
100
- ```ruby
101
- require './lib/caffe'
102
159
  ```
160
+ $ rake clean
161
+ $ rake clobber
162
+ ```
163
+
164
+ The first cleans the temporary files and the second cleans all generated files
165
+
166
+ ```
167
+ $ rake release[remote]
168
+ ```
169
+
170
+ Create a version tag, and push to both git remote & [rubygems.org](https://rubygems.org)
103
171
 
104
172
  ## Author ##
105
173
 
@@ -2,6 +2,7 @@
2
2
  #include "common.hpp"
3
3
  #include "blob.hpp"
4
4
  #include "net.hpp"
5
+ #include "solver.hpp"
5
6
 
6
7
  extern "C"
7
8
  void Init_caffe() {
@@ -10,4 +11,5 @@ void Init_caffe() {
10
11
  Init_common();
11
12
  Init_blob();
12
13
  Init_net();
14
+ Init_solver();
13
15
  }
@@ -36,7 +36,7 @@ static Object getBlobByName(Object self, String name) {
36
36
  static Object forward(Object self) {
37
37
  Net *net = from_ruby<Net *>(self);
38
38
  float loss = .0;
39
- net -> Forward(NULL);
39
+ net -> Forward(&loss);
40
40
  return to_ruby(loss);
41
41
  }
42
42
 
@@ -51,5 +51,7 @@ void Init_net() {
51
51
  .define_method("blob", &getBlobByName)
52
52
  .define_method("reshape!", &Net::Reshape)
53
53
  .define_method("load_trained!", &Net::CopyTrainedLayersFromBinaryProto)
54
- .define_method("forward!", &forward);
54
+ .define_method("forward!", &forward)
55
+ .define_method("forward_backward!", &Net::ForwardBackward)
56
+ .define_method("share_trained!", &Net::ShareTrainedLayersWith);
55
57
  }
@@ -0,0 +1,61 @@
1
+ #include "solver.hpp"
2
+ #include "net.hpp"
3
+ #include "util.hpp"
4
+ #include <iostream>
5
+ #include <rice/Data_Type.hpp>
6
+ #include <rice/Constructor.hpp>
7
+ #include <rice/String.hpp>
8
+
9
+ using namespace Rice;
10
+
11
+ struct SolverConstructor {
12
+ static void construct(Object self, String path) {
13
+ caffe::SolverParameter param;
14
+ caffe::ReadSolverParamsFromTextFileOrDie(path.str(), &param);
15
+ Solver *solver = SolverRegistry::CreateSolver(param);
16
+ DATA_PTR(self.value()) = solver;
17
+ }
18
+ };
19
+
20
+ static Object getNet(Object self) {
21
+ Solver *solver = from_ruby<Solver *>(self);
22
+ Net *net = solver -> net().get();
23
+
24
+ if (net) {
25
+ return objectNoGC(net);
26
+ } else {
27
+ return Qnil;
28
+ }
29
+ }
30
+
31
+ static Object getTestNets(Object self) {
32
+ Solver *solver = from_ruby<Solver *>(self);
33
+ const std::vector<boost::shared_ptr<Net> > &nets = solver -> test_nets();
34
+ return mapArray(nets.begin(), nets.end(),
35
+ sharedToObj<Net, boost::shared_ptr<Net> >);
36
+ }
37
+
38
+ static void restore(Object self, String path) {
39
+ Solver *solver = from_ruby<Solver *>(self);
40
+ solver -> Restore(path.c_str());
41
+ }
42
+
43
+ static void solve(Object self) {
44
+ Solver *solver = from_ruby<Solver *>(self);
45
+ solver -> Solve(NULL);
46
+ }
47
+
48
+ void Init_solver() {
49
+ Module rb_mCaffe = define_module("Caffe");
50
+
51
+ Data_Type<Solver> rb_cSolver = rb_mCaffe
52
+ .define_class<Solver>("Solver")
53
+ .define_constructor(SolverConstructor())
54
+ .define_method("net", getNet)
55
+ .define_method("test_nets", getTestNets)
56
+ .define_method("iter", &Solver::iter)
57
+ .define_method("step!", &Solver::Step)
58
+ .define_method("snapshot", &Solver::Snapshot)
59
+ .define_method("restore!", restore)
60
+ .define_method("solve!", solve);
61
+ }
@@ -0,0 +1,11 @@
1
+ #ifndef __SOLVER
2
+ #define __SOLVER
3
+
4
+ #include <caffe/caffe.hpp>
5
+
6
+ typedef caffe::Solver<float> Solver;
7
+ typedef caffe::SolverRegistry<float> SolverRegistry;
8
+
9
+ void Init_solver(void);
10
+
11
+ #endif
@@ -1,6 +1,7 @@
1
1
  #ifndef __UTIL
2
2
  #define __UTIL
3
3
 
4
+ #include <caffe/caffe.hpp>
4
5
  #include <rice/Data_Type.hpp>
5
6
  #include <rice/Array.hpp>
6
7
  #include <vector>
@@ -17,6 +18,11 @@ Rice::Data_Object<T> objectNoGC(T *obj) {
17
18
  EmptyFreeFunction<T>::free);
18
19
  }
19
20
 
21
+ template<typename T, typename U>
22
+ Rice::Data_Object<T> sharedToObj(U obj) {
23
+ return objectNoGC(obj.get());
24
+ }
25
+
20
26
  template<typename Iter, typename Func>
21
27
  Rice::Array mapArray(Iter begin, Iter end, Func func) {
22
28
  Rice::Array ret;
@@ -1,3 +1,3 @@
1
1
  module Caffe
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
@@ -22,5 +22,8 @@ RSpec.describe Caffe do
22
22
  expect(Caffe.solver_count).to eq(2)
23
23
  expect(Caffe.solver_rank).to eq(1)
24
24
  expect(Caffe.multiprocess).to eq(true)
25
+ Caffe.solver_count = 1
26
+ Caffe.solver_rank = 0
27
+ Caffe.multiprocess = false
25
28
  end
26
29
  end
@@ -12,6 +12,21 @@ layer {
12
12
  }
13
13
  }
14
14
 
15
+ layer {
16
+ name: "label"
17
+ type: "Input"
18
+ top: "label"
19
+ include {
20
+ phase: TRAIN
21
+ }
22
+ input_param {
23
+ shape: {
24
+ dim: 1
25
+ dim: 1
26
+ }
27
+ }
28
+ }
29
+
15
30
  layer {
16
31
  name: "ip1"
17
32
  type: "InnerProduct"
@@ -68,4 +83,18 @@ layer {
68
83
  type: "Softmax"
69
84
  bottom: "ip2"
70
85
  top: "prob"
86
+ include {
87
+ phase: TEST
88
+ }
89
+ }
90
+
91
+ layer {
92
+ name: "loss"
93
+ type: "SoftmaxWithLoss"
94
+ bottom: "ip2"
95
+ bottom: "label"
96
+ top: "loss"
97
+ include {
98
+ phase: TRAIN
99
+ }
71
100
  }
@@ -1,14 +1,14 @@
1
- net: "test_train.prototxt"
1
+ net: "spec/net/test_train.prototxt"
2
2
  test_iter: 100
3
- test_interval: 800
3
+ test_interval: 80
4
4
  base_lr: 0.1
5
5
  momentum: 0.9
6
6
  weight_decay: 0.0005
7
7
  lr_policy: "inv"
8
8
  gamma: 0.0001
9
9
  power: 0.75
10
- display: 800
11
- max_iter: 25600
12
- snapshot: 25600
13
- snapshot_prefix: "test"
10
+ display: 80
11
+ max_iter: 2560
12
+ snapshot: 2560
13
+ snapshot_prefix: "spec/net/test"
14
14
  solver_mode: CPU
@@ -6,7 +6,7 @@ layer {
6
6
  top: "data"
7
7
  top: "label"
8
8
  data_param {
9
- source: "test_data"
9
+ source: "spec/net/test_data"
10
10
  batch_size: 256
11
11
  backend: LMDB
12
12
  }
@@ -1,43 +1,68 @@
1
1
  RSpec.describe Caffe::Net do
2
2
  before :example do
3
3
  Caffe.mode = Caffe::CPU
4
- path = File.expand_path '../net/test.prototxt', __FILE__
5
- @net = Caffe::Net.new path, Caffe::TEST
4
+ @path = File.expand_path '../net/test.prototxt', __FILE__
6
5
  end
7
6
 
8
- it 'can get the input' do
9
- expect(@net.inputs).to be_an(Array)
10
- expect(@net.inputs.size).to eq(1)
11
- input = @net.inputs[0]
12
- expect(input).to be_a(Caffe::Blob)
13
- expect(input.shape).to eq([1, 32])
14
- end
7
+ shared_examples :net do
8
+ before :example do
9
+ @net = Caffe::Net.new @path, @phase
10
+ end
15
11
 
16
- it 'can get blob by name' do
17
- blob = @net.blob('ip1')
18
- expect(blob).to be_a(Caffe::Blob)
19
- expect(blob.shape).to eq([1, 100])
12
+ it 'can get the input' do
13
+ expect(@net.inputs).to be_an(Array)
14
+ expect([1, 2]).to include(@net.inputs.size)
15
+ input = @net.inputs[0]
16
+ expect(input).to be_a(Caffe::Blob)
17
+ expect(input.shape).to eq([1, 32])
18
+ if @net.inputs.size == 2
19
+ input = @net.inputs[1]
20
+ expect(input).to be_a(Caffe::Blob)
21
+ expect(input.shape).to eq([1, 1])
22
+ end
23
+ end
20
24
 
21
- blob = @net.blob('prob')
22
- expect(blob.shape).to eq([1, 2])
23
- end
25
+ it 'can get blob by name' do
26
+ blob = @net.blob('ip1')
27
+ expect(blob).to be_a(Caffe::Blob)
28
+ expect(blob.shape).to eq([1, 100])
24
29
 
25
- it 'can get output' do
26
- expect(@net.outputs).to be_an(Array)
27
- expect(@net.outputs.size).to eq(1)
28
- output = @net.outputs[0]
29
- expect(output).to be_a(Caffe::Blob)
30
- expect(output.shape).to eq([1, 2])
31
- end
30
+ blob = @net.blob('ip2')
31
+ expect(blob.shape).to eq([1, 2])
32
+ end
33
+
34
+ it 'can get output' do
35
+ expect(@net.outputs).to be_an(Array)
36
+ expect(@net.outputs.size).to eq(1)
37
+ output = @net.outputs[0]
38
+ expect(output).to be_a(Caffe::Blob)
39
+ expect([[1, 2], []]).to include(output.shape)
40
+ end
32
41
 
33
- it 'can reshape according to the input size' do
34
- input = @net.inputs[0]
35
- input.shape = [64, 32]
36
- @net.reshape!
37
- expect(@net.outputs[0].shape).to eq([64, 2])
42
+ it 'can reshape according to the input size' do
43
+ @net.inputs.each do |input|
44
+ shape = input.shape
45
+ shape[0] = 64
46
+ input.shape = shape
47
+ end
48
+ @net.reshape!
49
+ expect(@net.blob('ip2').shape).to eq([64, 2])
50
+ end
51
+
52
+ def input_data
53
+ data = Array.new 32 do
54
+ Random.rand 2
55
+ end
56
+ @net.inputs[0].copy_from! data
57
+
58
+ num = data.inject(0) do |i, x|
59
+ 2 * i + x
60
+ end
61
+ num % 1024 > 1024 / 2 ? 1 : 0
62
+ end
38
63
  end
39
64
 
40
- context 'trained net' do
65
+ shared_examples :trained do
41
66
  before :example do
42
67
  path = File.expand_path '../net/test.caffemodel', __FILE__
43
68
  @net.load_trained! path
@@ -47,25 +72,98 @@ RSpec.describe Caffe::Net do
47
72
  input = @net.inputs[0]
48
73
  expect(input.shape).to eq([1, 32])
49
74
  end
75
+ end
50
76
 
51
- it 'can forward' do
52
- data = Array.new 32 do
53
- Random.rand 2
54
- end
55
- input = @net.inputs[0]
56
- input.copy_from! data
77
+ shared_examples :shared_net do
78
+ before :example do
79
+ @src = @net
80
+ @net = Caffe::Net.new @path, Caffe::TEST
81
+ @net.share_trained! @src
82
+ end
57
83
 
84
+ it 'can forward and return the same result' do
85
+ input_data
86
+ @src.inputs[0].copy_from! @net.inputs[0].to_a
58
87
  expect(@net.forward!).to eq(0.0)
59
- output = @net.outputs[0]
60
- expect(output[0][0] + output[0][1]).to be_within(1e-6).of(1.0)
88
+ @src.forward!
61
89
 
62
- label = output[0][1] > output[0][0] ? 1 : 0
63
- num = data.inject(0) do |i, x|
64
- 2 * i + x
90
+ expect(@net.blob('ip1').to_a).to eq(@src.blob('ip1').to_a)
91
+ expect(@net.blob('ip2').to_a).to eq(@src.blob('ip2').to_a)
92
+ end
93
+ end
94
+
95
+ context 'test net' do
96
+ before :example do
97
+ @phase = Caffe::TEST
98
+ end
99
+ include_examples :net
100
+
101
+ context 'shared with another' do
102
+ include_examples :shared_net
103
+ end
104
+
105
+ context 'trained' do
106
+ include_examples :trained
107
+
108
+ context 'share with another' do
109
+ include_examples :shared_net
110
+ end
111
+
112
+ it 'can forward' do
113
+ expected = input_data
114
+
115
+ expect(@net.forward!).to eq(0.0)
116
+ output = @net.outputs[0]
117
+ expect(output[0][0] + output[0][1]).to be_within(1e-6).of(1.0)
118
+
119
+ label = output[0][1] > output[0][0] ? 1 : 0
120
+ expect(label).to eq(expected)
121
+ end
122
+
123
+ it 'can forward then backward' do
124
+ expect(@net.forward_backward!).to eq(0.0)
65
125
  end
66
- expected = num % 1024 > 1024 / 2 ? 1 : 0
126
+ end
127
+ end
128
+
129
+ context 'train net' do
130
+ before :example do
131
+ @mode = Caffe::TRAIN
132
+ end
133
+ include_examples :net
134
+
135
+ context 'share with another' do
136
+ include_examples :shared_net
137
+ end
138
+
139
+ context 'trained' do
140
+ include_examples :trained
67
141
 
68
- expect(label).to eq(expected)
142
+ context 'share with another' do
143
+ include_examples :shared_net
144
+ end
145
+
146
+ it 'can forward' do
147
+ expected = input_data
148
+ @net.inputs[1][0][0] = expected
149
+
150
+ loss = @net.forward!
151
+ expect(loss).not_to eq(0.0)
152
+ expect(loss).to be_within(1e-2).of(0.0)
153
+ end
154
+
155
+ it 'can forward then backward' do
156
+ ip2 = @net.blob 'ip2'
157
+ expect(ip2.diff[0][0]).to eq(0.0)
158
+ expect(ip2.diff[0][1]).to eq(0.0)
159
+
160
+ loss = @net.forward_backward!
161
+ expect(loss).not_to eq(0.0)
162
+ expect(loss).to be_within(1e-2).of(0.0)
163
+
164
+ expect(ip2.diff[0][0]).not_to eq(0.0)
165
+ expect(ip2.diff[0][1]).not_to eq(0.0)
166
+ end
69
167
  end
70
168
  end
71
169
  end
@@ -0,0 +1,66 @@
1
+ RSpec.describe Caffe::Solver do
2
+ before :example do
3
+ path = File.expand_path '../net/test_solver.prototxt', __FILE__
4
+ @solver = Caffe::Solver.new path
5
+ end
6
+
7
+ it '#net returns the train net' do
8
+ net = @solver.net
9
+ expect(net).to be_a(Caffe::Net)
10
+ expect(net.inputs.size).to eq(0)
11
+ expect(net.outputs.size).to eq(1)
12
+ end
13
+
14
+ it '#test_nets returns an array of test nets' do
15
+ nets = @solver.test_nets
16
+ expect(nets).to be_an(Array)
17
+ expect(nets.size).to eq(1)
18
+ net = nets[0]
19
+ expect(net).to be_a(Caffe::Net)
20
+ expect(net.outputs.size).to eq(2)
21
+ end
22
+
23
+ it '#iter returns the current iteration' do
24
+ expect(@solver.iter).to eq(0)
25
+ end
26
+
27
+ it '#step! steps the iteration' do
28
+ net = @solver.net
29
+ loss = net.forward!
30
+ @solver.step! 100
31
+ expect(@solver.iter).to eq(100)
32
+ expect(net.forward!).to be < loss
33
+ end
34
+
35
+ def snapshot_path
36
+ state = File.expand_path "../net/test_iter_#{@solver.iter}.solverstate",
37
+ __FILE__
38
+ model = File.expand_path "../net/test_iter_#{@solver.iter}.caffemodel",
39
+ __FILE__
40
+ [state, model]
41
+ end
42
+
43
+ it '#snapshot & #restore! can save & load the current state' do
44
+ state, model = snapshot_path
45
+ begin
46
+ @solver.snapshot
47
+ expect(File.exist?(state)).to be true
48
+ @solver.restore! state
49
+ ensure
50
+ File.unlink state
51
+ File.unlink model
52
+ end
53
+ end
54
+
55
+ it '#solve! solves the net' do
56
+ begin
57
+ @solver.solve!
58
+ net = @solver.net
59
+ expect(net.forward!).to be_within(1e-2).of(0.0)
60
+ ensure
61
+ state, model = snapshot_path
62
+ File.unlink state
63
+ File.unlink model
64
+ end
65
+ end
66
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caffe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiny Tiny
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-17 00:00:00.000000000 Z
11
+ date: 2017-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rice
@@ -101,6 +101,8 @@ files:
101
101
  - ext/caffe/mkmf_cxx.rb
102
102
  - ext/caffe/net.cc
103
103
  - ext/caffe/net.hpp
104
+ - ext/caffe/solver.cc
105
+ - ext/caffe/solver.hpp
104
106
  - ext/caffe/util.hpp
105
107
  - lib/caffe.rb
106
108
  - lib/caffe/blob.rb
@@ -110,11 +112,11 @@ files:
110
112
  - spec/blob_spec.rb
111
113
  - spec/common_spec.rb
112
114
  - spec/net/gen_data.rb
113
- - spec/net/test.caffemodel
114
115
  - spec/net/test.prototxt
115
116
  - spec/net/test_solver.prototxt
116
117
  - spec/net/test_train.prototxt
117
118
  - spec/net_spec.rb
119
+ - spec/solver_spec.rb
118
120
  - spec/spec_helper.rb
119
121
  homepage: https://github.com/gyf1214/ruby-caffe
120
122
  licenses:
@@ -144,9 +146,9 @@ test_files:
144
146
  - spec/blob_spec.rb
145
147
  - spec/common_spec.rb
146
148
  - spec/net/gen_data.rb
147
- - spec/net/test.caffemodel
148
149
  - spec/net/test.prototxt
149
150
  - spec/net/test_solver.prototxt
150
151
  - spec/net/test_train.prototxt
151
152
  - spec/net_spec.rb
153
+ - spec/solver_spec.rb
152
154
  - spec/spec_helper.rb
Binary file