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 +4 -4
- data/README.md +9 -15
- data/convolver.gemspec +1 -0
- data/ext/convolver/convolver.c +2 -2
- data/lib/convolver.rb +29 -0
- data/lib/convolver/version.rb +1 -1
- data/spec/{convolver_spec.rb → convolve_basic_spec.rb} +6 -28
- data/spec/convolve_fftw3_spec.rb +3 -3
- data/spec/convolve_spec.rb +31 -0
- data/spec/helpers.rb +1 -0
- data/spec/nn_run_layer_spec.rb +25 -0
- metadata +21 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99ab37662a25bbb5d060946aff94c533e336db14
|
4
|
+
data.tar.gz: 5ef276e831151248a543a6f33adbb3524c82a37f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c97668640eb1ac262397b20915e2739ec3617d0c13c6e06a70a5e7306f8bcb85553ae7022160dea7e63c2d9a7325e2e45d641f7949de6c694b5a3eff9f73f54b
|
7
|
+
data.tar.gz: a3f26841861e48034835af3ed730c1a0cae33d565287c4197f772bf7a1ee6de59cfe0c91abfb75fd5d9789fe54a83f34769fb0700ff22e96302571f0b5715099
|
data/README.md
CHANGED
@@ -2,18 +2,14 @@
|
|
2
2
|
|
3
3
|
[](http://travis-ci.org/neilslater/convolver)
|
4
4
|
|
5
|
-
|
6
|
-
|
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
|
15
|
-
neural networks. As a side effect of this plan, it
|
16
|
-
calculating
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
|
data/convolver.gemspec
CHANGED
@@ -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
|
|
data/ext/convolver/convolver.c
CHANGED
@@ -63,7 +63,7 @@ static VALUE narray_fit_backwards( VALUE self, VALUE a, VALUE b ) {
|
|
63
63
|
}
|
64
64
|
|
65
65
|
|
66
|
-
/* @overload
|
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, "
|
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
|
}
|
data/lib/convolver.rb
CHANGED
@@ -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
|
data/lib/convolver/version.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
require 'helpers'
|
2
2
|
|
3
3
|
describe Convolver do
|
4
|
-
describe "#
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
data/spec/convolve_fftw3_spec.rb
CHANGED
@@ -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.
|
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.
|
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.
|
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
|
data/spec/helpers.rb
CHANGED
@@ -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.
|
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/
|
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/
|
182
|
+
- spec/convolve_spec.rb
|
168
183
|
- spec/helpers.rb
|
184
|
+
- spec/nn_run_layer_spec.rb
|
169
185
|
has_rdoc:
|