convolver 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a0f2badf8733818f128a1c6f1456ae37e114f549
4
- data.tar.gz: 81889f084e50d4789ec202082422dd9b24304210
3
+ metadata.gz: 99ab37662a25bbb5d060946aff94c533e336db14
4
+ data.tar.gz: 5ef276e831151248a543a6f33adbb3524c82a37f
5
5
  SHA512:
6
- metadata.gz: 557d6b5738041165a5a22f4ede39d4d0cc7333aa6bfd2937cf3334e16e8daa7c12672ed6377be31003974b90b4a8a942f93fdf812d886202894d46088a2c30a5
7
- data.tar.gz: d598375b28278a5ac14619280068cfaeab82fe2d1c4aac9aeae817bb4b4958c913c1fb6674af1b9f4af901f7844621863e2ffd9d4991dc7ca31e7c8e32818c48
6
+ metadata.gz: c97668640eb1ac262397b20915e2739ec3617d0c13c6e06a70a5e7306f8bcb85553ae7022160dea7e63c2d9a7325e2e45d641f7949de6c694b5a3eff9f73f54b
7
+ data.tar.gz: a3f26841861e48034835af3ed730c1a0cae33d565287c4197f772bf7a1ee6de59cfe0c91abfb75fd5d9789fe54a83f34769fb0700ff22e96302571f0b5715099
data/README.md CHANGED
@@ -2,18 +2,14 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/neilslater/convolver.png?branch=master)](http://travis-ci.org/neilslater/convolver)
4
4
 
5
- Adds a convolve operation to NArray floats. It is around 250 times faster than equivalents
6
- in pure Ruby.
7
-
8
- The gem makes convolution via FFTW3 library available. This is faster for convolutions with
9
- larger kernels and signals. The relationship is complex, but as a rule of thumb, the kernel
10
- needs to be around 1000 entries or larger before it is worth switching to FFTW3-based convolves.
5
+ Calculates discrete convolution between two multi-dimensional arrays.
6
+ See http://en.wikipedia.org/wiki/Convolution
11
7
 
12
8
  ## Planned features
13
9
 
14
- The *convolver* gem will eventually contain a basic kit for creating, training and running convolutional
15
- neural networks. As a side effect of this plan, it will also contain efficient code for
16
- calculating signal convolutions for other types of analysis.
10
+ The *convolver* gem will eventually contain a basic kit for creating, training and running
11
+ convolutional neural networks. As a side effect of this plan, it currently contains code for
12
+ calculating floating-point convolutions for other types of analysis.
17
13
 
18
14
  ## Installation
19
15
 
@@ -53,12 +49,10 @@ kernel in the same dimension.
53
49
  * Convolver expects input a and kernel b to have the same rank, and for the kernel to be same size
54
50
  or smaller in all dimensions as the input.
55
51
 
56
- FFTW3 convolution:
57
-
58
- a = NArray[0.3,0.4,0.5]
59
- b = NArray[1.3, -0.5]
60
- c = Convolver.convolve_fftw3( a, b )
61
- => NArray.float(2): [ 0.19, 0.27 ]
52
+ * Convolver.convolve will try to choose the faster of two approaches it has coded. In general,
53
+ small convolutions are processed directly by multiplying out all combinations and summing them,
54
+ and large convolutions are processed using FFTW3 to convert to frequency space where convolution
55
+ is simpler and faster to calculate, then convert back.
62
56
 
63
57
  ## Contributing
64
58
 
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.add_development_dependency "yard", ">= 0.8.7.2"
20
20
  spec.add_development_dependency "bundler", ">= 1.3"
21
21
  spec.add_development_dependency "rspec", ">= 2.13.0"
22
+ spec.add_development_dependency "mocha", ">= 0.14.0"
22
23
  spec.add_development_dependency "rake", ">= 1.9.1"
23
24
  spec.add_development_dependency "rake-compiler", ">= 0.8.3"
24
25
 
@@ -63,7 +63,7 @@ static VALUE narray_fit_backwards( VALUE self, VALUE a, VALUE b ) {
63
63
  }
64
64
 
65
65
 
66
- /* @overload convolve( signal, kernel )
66
+ /* @overload convolve_basic( signal, kernel )
67
67
  * Calculates convolution of an array of floats representing a signal, with a second array representing
68
68
  * a kernel. The two parameters must have the same rank. The output has same rank, its size in each dimension d is given by
69
69
  * signal.shape[d] - kernel.shape[d] + 1
@@ -167,7 +167,7 @@ static VALUE narray_nn_run_single_layer( VALUE self, VALUE inputs, VALUE weights
167
167
 
168
168
  void Init_convolver() {
169
169
  Convolver = rb_define_module( "Convolver" );
170
- rb_define_singleton_method( Convolver, "convolve", narray_convolve, 2 );
170
+ rb_define_singleton_method( Convolver, "convolve_basic", narray_convolve, 2 );
171
171
  rb_define_singleton_method( Convolver, "nn_run_layer", narray_nn_run_single_layer, 3 );
172
172
  rb_define_singleton_method( Convolver, "fit_kernel_backwards", narray_fit_backwards, 2 );
173
173
  }
@@ -4,6 +4,35 @@ require "convolver/version"
4
4
  require 'fftw3'
5
5
 
6
6
  module Convolver
7
+ # Chooses and calls likely fastest method from #convolve_basic and #convolve_fftw3.
8
+ # The two parameters must have the same rank. The output has same rank, its size in each
9
+ # dimension d is given by
10
+ # signal.shape[d] - kernel.shape[d] + 1
11
+ # If you always perform convolutions of the same size, you may be better off benchmarking your
12
+ # own code using either #convolve_basic or #convolve_fftw3, and have your code use the fastest.
13
+ # @param [NArray] signal must be same size or larger than kernel in each dimension
14
+ # @param [NArray] kernel must be same size or smaller than signal in each dimension
15
+ # @return [NArray] result of convolving signal with kernel
16
+ def self.convolve signal, kernel
17
+ # For small signals or kernels, just go straight to basic
18
+ if signal.size < 1000 || kernel.size < 100
19
+ return convolve_basic( signal, kernel )
20
+ end
21
+
22
+ # If predicted time is less than a millisecond, just do a basic convolve
23
+ basic_time_predicted = predict_convolve_basic_time( signal, kernel )
24
+ if basic_time_predicted < 0.1
25
+ return convolve_basic( signal, kernel )
26
+ end
27
+
28
+ # Factor of two to allow for large uncertainty in predictions for FFTW3
29
+ if predict_convolve_fft_time( signal, kernel ) < 2 * basic_time_predicted
30
+ return convolve_fftw3( signal, kernel )
31
+ end
32
+
33
+ convolve_basic( signal, kernel )
34
+ end
35
+
7
36
  # Uses FFTW3 library to calculate convolution of an array of floats representing a signal,
8
37
  # with a second array representing a kernel. The two parameters must have the same rank.
9
38
  # The output has same rank, its size in each dimension d is given by
@@ -1,3 +1,3 @@
1
1
  module Convolver
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,19 +1,19 @@
1
1
  require 'helpers'
2
2
 
3
3
  describe Convolver do
4
- describe "#convolve" do
4
+ describe "#convolve_basic" do
5
5
 
6
6
  it "should work like the example in the README" do
7
7
  a = NArray[ 0.3, 0.4, 0.5 ]
8
8
  b = NArray[ 1.3, -0.5 ]
9
- c = Convolver.convolve( a, b )
9
+ c = Convolver.convolve_basic( a, b )
10
10
  c.should be_narray_like NArray[ 0.19, 0.27 ]
11
11
  end
12
12
 
13
13
  it "should calculate a 2D convolution" do
14
14
  a = NArray[ [ 0.3, 0.4, 0.5 ], [ 0.6, 0.8, 0.2 ], [ 0.9, 1.0, 0.1 ] ]
15
15
  b = NArray[ [ 1.2, -0.5 ], [ 0.5, -1.3 ] ]
16
- c = Convolver.convolve( a, b )
16
+ c = Convolver.convolve_basic( a, b )
17
17
  c.should be_narray_like NArray[ [ -0.58, 0.37 ], [ -0.53, 1.23 ] ]
18
18
  end
19
19
 
@@ -22,7 +22,7 @@ describe Convolver do
22
22
  [ 0.9, 1.0, 0.1, 0.9, 1.0 ], [ 0.5, 0.9, 0.3, 0.2, 0.8 ], [ 0.7, 0.1, 0.3, 0.0, 0.1 ],
23
23
  [ 0.4, 0.5, 0.6, 0.7, 0.8 ], [ 0.5, 0.4, 0.3, 0.2, 0.1 ] ]
24
24
  b = NArray[ [ 1.2, -0.5, 0.2 ], [ 1.8, 0.5, -1.3 ] ]
25
- c = Convolver.convolve( a, b )
25
+ c = Convolver.convolve_basic( a, b )
26
26
  c.should be_narray_like NArray[ [ 1.48, 0.79, 1.03 ], [ 2.35, 1.7, -0.79 ], [ 1.56, 2.84, -0.53 ],
27
27
  [ 1.13, 1.3, 0.83 ], [ 1.04, 0.26, 0.77 ], [ 1.06, 1.05, 1.04 ] ]
28
28
  end
@@ -43,7 +43,7 @@ describe Convolver do
43
43
  ]
44
44
 
45
45
  # Should be 3x2x1
46
- c = Convolver.convolve( a, b )
46
+ c = Convolver.convolve_basic( a, b )
47
47
  c.should be_narray_like NArray[ [ [ 5.51, 3.04, 4.3 ], [ 3.04, 6.31, 3.87 ] ] ]
48
48
  end
49
49
 
@@ -74,33 +74,11 @@ describe Convolver do
74
74
  [ [ 0.8, 0.2 ], [ 0.5, 0.0 ], [ 1.4, 1.3 ] ] ] ]
75
75
 
76
76
  # Should be 2x2x3x2
77
- c = Convolver.convolve( a, b )
77
+ c = Convolver.convolve_basic( a, b )
78
78
  c.should be_narray_like NArray[
79
79
  [ [ [ 8.5, 8.2 ], [ 11.34, 9.68 ] ], [ [ 7.68, 6.56 ], [ 11.24, 7.16 ] ], [ [ 9.14, 6.54 ], [ 12.44, 9.2 ] ] ],
80
80
  [ [ [ 8.5, 8.2 ], [ 11.34, 9.68 ] ], [ [ 7.68, 6.56 ], [ 11.24, 7.16 ] ], [ [ 9.14, 6.54 ], [ 12.44, 9.2 ] ] ]
81
81
  ]
82
82
  end
83
83
  end
84
-
85
- describe "#nn_run_layer" do
86
- it "should calculate basic layer rules" do
87
- inputs = NArray[ 1.0 ]
88
- weights = NArray[ [ 1.0 ] ]
89
- thresholds = NArray[ 0.0 ]
90
- outputs = Convolver.nn_run_layer( inputs, weights, thresholds );
91
- outputs.should be_narray_like NArray[ 1.0 ]
92
-
93
- inputs = NArray[ 0.5, -0.5 ]
94
- weights = NArray[ [ 1.0, 2.0 ], [ 2.0, 1.0 ] ]
95
- thresholds = NArray[ 0.0, 0.0 ]
96
- outputs = Convolver.nn_run_layer( inputs, weights, thresholds );
97
- outputs.should be_narray_like NArray[ 0.0, 0.5 ]
98
-
99
- inputs = NArray[ 0.3, -0.4, 0.8, -0.7 ]
100
- weights = NArray[ [ 1.0, 0.25, 0.5, -0.5 ], [ -1.0, -0.25, -0.5, 0.5 ] ]
101
- thresholds = NArray[ 0.0, 0.0 ]
102
- outputs = Convolver.nn_run_layer( inputs, weights, thresholds );
103
- outputs.should be_narray_like NArray[ 0.95, 0.0 ]
104
- end
105
- end
106
84
  end
@@ -114,7 +114,7 @@ describe Convolver do
114
114
  (1..signal_length).each do |kernel_length|
115
115
  signal = NArray.sfloat(signal_length).random()
116
116
  kernel = NArray.sfloat(kernel_length).random()
117
- expect_result = Convolver.convolve( signal, kernel )
117
+ expect_result = Convolver.convolve_basic( signal, kernel )
118
118
  got_result = Convolver.convolve_fftw3( signal, kernel )
119
119
  got_result.should be_narray_like expect_result
120
120
  end
@@ -128,7 +128,7 @@ describe Convolver do
128
128
  (1..signal_y).each do |kernel_y|
129
129
  signal = NArray.sfloat(signal_x,signal_y).random()
130
130
  kernel = NArray.sfloat(kernel_x,kernel_y).random()
131
- expect_result = Convolver.convolve( signal, kernel )
131
+ expect_result = Convolver.convolve_basic( signal, kernel )
132
132
  got_result = Convolver.convolve_fftw3( signal, kernel )
133
133
  got_result.should be_narray_like expect_result
134
134
  end
@@ -146,7 +146,7 @@ describe Convolver do
146
146
  (1..signal_z).each do |kernel_z|
147
147
  signal = NArray.sfloat(signal_x,signal_y,signal_z).random()
148
148
  kernel = NArray.sfloat(kernel_x,kernel_y,kernel_z).random()
149
- expect_result = Convolver.convolve( signal, kernel )
149
+ expect_result = Convolver.convolve_basic( signal, kernel )
150
150
  got_result = Convolver.convolve_fftw3( signal, kernel )
151
151
  got_result.should be_narray_like expect_result
152
152
  end
@@ -0,0 +1,31 @@
1
+ require 'helpers'
2
+
3
+ describe Convolver do
4
+ describe "#convolve" do
5
+
6
+ it "should work like the example in the README" do
7
+ a = NArray[ 0.3, 0.4, 0.5 ]
8
+ b = NArray[ 1.3, -0.5 ]
9
+ c = Convolver.convolve( a, b )
10
+ c.should be_narray_like NArray[ 0.19, 0.27 ]
11
+ end
12
+
13
+ it "should choose #convolve_basic for small inputs" do
14
+ a = NArray.sfloat(50,50).random()
15
+ b = NArray.sfloat(10,10).random()
16
+ Convolver.expects( :convolve_basic ).once
17
+ Convolver.expects( :convolve_fftw3 ).never
18
+ c = Convolver.convolve( a, b )
19
+ end
20
+
21
+ it "should choose #convolve_fftw3 for large inputs" do
22
+ a = NArray.sfloat(500,500).random()
23
+ b = NArray.sfloat(100,100).random()
24
+ Convolver.expects( :convolve_basic ).never
25
+ Convolver.expects( :convolve_fftw3 ).once
26
+ c = Convolver.convolve( a, b )
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -1,5 +1,6 @@
1
1
  # convolver/spec/helpers.rb
2
2
  require 'convolver'
3
+ require 'mocha/api'
3
4
 
4
5
  # Matcher compares NArrays numerically
5
6
  RSpec::Matchers.define :be_narray_like do |expected_narray|
@@ -0,0 +1,25 @@
1
+ require 'helpers'
2
+
3
+ describe Convolver do
4
+ describe "#nn_run_layer" do
5
+ it "should calculate basic layer rules" do
6
+ inputs = NArray[ 1.0 ]
7
+ weights = NArray[ [ 1.0 ] ]
8
+ thresholds = NArray[ 0.0 ]
9
+ outputs = Convolver.nn_run_layer( inputs, weights, thresholds );
10
+ outputs.should be_narray_like NArray[ 1.0 ]
11
+
12
+ inputs = NArray[ 0.5, -0.5 ]
13
+ weights = NArray[ [ 1.0, 2.0 ], [ 2.0, 1.0 ] ]
14
+ thresholds = NArray[ 0.0, 0.0 ]
15
+ outputs = Convolver.nn_run_layer( inputs, weights, thresholds );
16
+ outputs.should be_narray_like NArray[ 0.0, 0.5 ]
17
+
18
+ inputs = NArray[ 0.3, -0.4, 0.8, -0.7 ]
19
+ weights = NArray[ [ 1.0, 0.25, 0.5, -0.5 ], [ -1.0, -0.25, -0.5, 0.5 ] ]
20
+ thresholds = NArray[ 0.0, 0.0 ]
21
+ outputs = Convolver.nn_run_layer( inputs, weights, thresholds );
22
+ outputs.should be_narray_like NArray[ 0.95, 0.0 ]
23
+ end
24
+ end
25
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: convolver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neil Slater
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: 2.13.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: mocha
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: 0.14.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 0.14.0
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: rake
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -122,8 +136,6 @@ files:
122
136
  - LICENSE.txt
123
137
  - README.md
124
138
  - Rakefile
125
- - benchmarks/convolve_benchmark.rb
126
- - benchmarks/nn_layer_benchmark.rb
127
139
  - convolver.gemspec
128
140
  - ext/convolver/cnn_components.c
129
141
  - ext/convolver/cnn_components.h
@@ -135,9 +147,11 @@ files:
135
147
  - ext/convolver/narray_shared.h
136
148
  - lib/convolver.rb
137
149
  - lib/convolver/version.rb
150
+ - spec/convolve_basic_spec.rb
138
151
  - spec/convolve_fftw3_spec.rb
139
- - spec/convolver_spec.rb
152
+ - spec/convolve_spec.rb
140
153
  - spec/helpers.rb
154
+ - spec/nn_run_layer_spec.rb
141
155
  homepage: http://github.com/neilslater/convolver
142
156
  licenses:
143
157
  - MIT
@@ -163,7 +177,9 @@ signing_key:
163
177
  specification_version: 4
164
178
  summary: Convolution for NArray
165
179
  test_files:
180
+ - spec/convolve_basic_spec.rb
166
181
  - spec/convolve_fftw3_spec.rb
167
- - spec/convolver_spec.rb
182
+ - spec/convolve_spec.rb
168
183
  - spec/helpers.rb
184
+ - spec/nn_run_layer_spec.rb
169
185
  has_rdoc: