convolver 0.1.2 → 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: 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: