convolver 0.2.0 → 0.3.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 +13 -11
- data/ext/convolver/convolver.c +2 -56
- data/ext/convolver/narray_shared.c +21 -2
- data/lib/convolver/version.rb +1 -1
- metadata +2 -6
- data/ext/convolver/cnn_components.c +0 -52
- data/ext/convolver/cnn_components.h +0 -14
- data/spec/nn_run_layer_spec.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 914f6026eed57b309e6a10b58b865b92cce1216c
|
4
|
+
data.tar.gz: 4d2eff7796eddaf75629ec5d90fe1e4e68681d39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fd430b3292eef1f7246bfb681eb0532d5826b91937c1b9db2c9ccec1dc03f9379c25b863d24a1e531c2922ca032ec290e102371f2d8cff8df149babd0297ca6
|
7
|
+
data.tar.gz: fe553601923c635c3f186676d4571c644b5bd6978654176acce4bdeeadeac77dae1eaae796c4b2059c0aacfdec044c7d4e4381cebd0d93436844dd6ff2a26818
|
data/README.md
CHANGED
@@ -1,21 +1,18 @@
|
|
1
1
|
# Convolver
|
2
2
|
|
3
|
+
[](http://badge.fury.io/rb/convolver)
|
3
4
|
[](http://travis-ci.org/neilslater/convolver)
|
5
|
+
[](https://gemnasium.com/neilslater/convolver)
|
4
6
|
|
5
|
-
Calculates discrete convolution between two multi-dimensional arrays.
|
7
|
+
Calculates discrete convolution between two multi-dimensional arrays of floats.
|
6
8
|
See http://en.wikipedia.org/wiki/Convolution
|
7
9
|
|
8
|
-
## Planned features
|
9
|
-
|
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.
|
13
|
-
|
14
10
|
## Installation
|
15
11
|
|
16
12
|
### Dependency: FFTW3
|
17
13
|
|
18
|
-
Before you install *convolver*, you should install FFTW3
|
14
|
+
Before you install *convolver*, you should install the FFTW3 library on your system.
|
15
|
+
See http://www.fftw.org/ for details.
|
19
16
|
|
20
17
|
### Installing the gem
|
21
18
|
|
@@ -41,10 +38,10 @@ Basic convolution:
|
|
41
38
|
=> NArray.float(2): [ 0.19, 0.27 ]
|
42
39
|
|
43
40
|
* Convolver only works on single-precision floats internally. It will cast NArray types to this, if
|
44
|
-
possible, prior to calculating.
|
41
|
+
possible, prior to calculating. For best speed, use NArray.sfloat arrays.
|
45
42
|
|
46
|
-
* The output is smaller than the input,
|
47
|
-
kernel in
|
43
|
+
* The output is smaller than the input, it only contains fully-calculated values. The output size
|
44
|
+
is the original size, minus the kernel size, plus 1, in each dimension.
|
48
45
|
|
49
46
|
* Convolver expects input a and kernel b to have the same rank, and for the kernel to be same size
|
50
47
|
or smaller in all dimensions as the input.
|
@@ -54,6 +51,11 @@ small convolutions are processed directly by multiplying out all combinations an
|
|
54
51
|
and large convolutions are processed using FFTW3 to convert to frequency space where convolution
|
55
52
|
is simpler and faster to calculate, then convert back.
|
56
53
|
|
54
|
+
## Convolutional Neural Nets
|
55
|
+
|
56
|
+
Code for CNNs in Ruby, based on the convolve_basic method from this gem, is planned for a
|
57
|
+
new gem.
|
58
|
+
|
57
59
|
## Contributing
|
58
60
|
|
59
61
|
1. Fork it
|
data/ext/convolver/convolver.c
CHANGED
@@ -7,7 +7,6 @@
|
|
7
7
|
|
8
8
|
#include "narray_shared.h"
|
9
9
|
#include "convolve_raw.h"
|
10
|
-
#include "cnn_components.h"
|
11
10
|
|
12
11
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
13
12
|
|
@@ -111,63 +110,10 @@ static VALUE narray_convolve( VALUE self, VALUE a, VALUE b ) {
|
|
111
110
|
return val_c;
|
112
111
|
}
|
113
112
|
|
114
|
-
/* @overload nn_run_layer( inputs, weights, thresholds )
|
115
|
-
* Calculates activations of a fully-connected neural network layer. The transfer function after
|
116
|
-
* summing weights and applying threshold is a "ReLU", equivalent to
|
117
|
-
* y = x < 0.0 ? 0.0 : x
|
118
|
-
* this is less sophisticated than many other neural net functions (such as sigma), but is fast to
|
119
|
-
* calculate and to train.
|
120
|
-
* @param [NArray] inputs must be rank 1 array of floats
|
121
|
-
* @param [NArray] weights must be rank 2 array of floats, with first dimension size of inputs, and second dimension size equal to number of outputs
|
122
|
-
* @param [NArray] thresholds must be rank 1 array of floats, size equal to number of outputs desired
|
123
|
-
* @return [NArray] neuron activations
|
124
|
-
*/
|
125
|
-
static VALUE narray_nn_run_single_layer( VALUE self, VALUE inputs, VALUE weights, VALUE thresholds ) {
|
126
|
-
struct NARRAY *na_inputs, *na_weights, *na_thresholds, *na_outputs;
|
127
|
-
volatile VALUE val_inputs, val_weights, val_thresholds, val_outputs;
|
128
|
-
int input_size, output_size;
|
129
|
-
int output_shape[1];
|
130
|
-
|
131
|
-
val_inputs = na_cast_object(inputs, NA_SFLOAT);
|
132
|
-
GetNArray( val_inputs, na_inputs );
|
133
|
-
if ( na_inputs->rank != 1 ) {
|
134
|
-
rb_raise( rb_eArgError, "input must be array of rank 1" );
|
135
|
-
}
|
136
|
-
input_size = na_inputs->total;
|
137
|
-
|
138
|
-
val_weights = na_cast_object(weights, NA_SFLOAT);
|
139
|
-
GetNArray( val_weights, na_weights );
|
140
|
-
if ( na_weights->rank != 2 ) {
|
141
|
-
rb_raise( rb_eArgError, "weights must be array of rank 2" );
|
142
|
-
}
|
143
|
-
if ( na_weights->shape[0] != input_size ) {
|
144
|
-
rb_raise( rb_eArgError, "weights shape mismatch, expected %d across, got %d", input_size, na_weights->shape[0] );
|
145
|
-
}
|
146
|
-
output_size = na_weights->shape[1];
|
147
|
-
|
148
|
-
val_thresholds = na_cast_object(thresholds, NA_SFLOAT);
|
149
|
-
GetNArray( val_thresholds, na_thresholds );
|
150
|
-
if ( na_thresholds->rank != 1 ) {
|
151
|
-
rb_raise( rb_eArgError, "thresholds must be narray of rank 1" );
|
152
|
-
}
|
153
|
-
if ( na_thresholds->shape[0] != output_size ) {
|
154
|
-
rb_raise( rb_eArgError, "thresholds expected size %d, but got %d", output_size, na_thresholds->shape[0] );
|
155
|
-
}
|
156
|
-
|
157
|
-
output_shape[0] = output_size;
|
158
|
-
val_outputs = na_make_object( NA_SFLOAT, 1, output_shape, CLASS_OF( val_inputs ) );
|
159
|
-
GetNArray( val_outputs, na_outputs );
|
160
|
-
|
161
|
-
nn_run_layer_raw( input_size, output_size, (float*) na_inputs->ptr, (float*) na_weights->ptr,
|
162
|
-
(float*) na_thresholds->ptr, (float*) na_outputs->ptr );
|
163
|
-
|
164
|
-
return val_outputs;
|
165
|
-
}
|
166
|
-
|
167
|
-
|
168
113
|
void Init_convolver() {
|
169
114
|
Convolver = rb_define_module( "Convolver" );
|
170
115
|
rb_define_singleton_method( Convolver, "convolve_basic", narray_convolve, 2 );
|
171
|
-
|
116
|
+
|
117
|
+
// private method
|
172
118
|
rb_define_singleton_method( Convolver, "fit_kernel_backwards", narray_fit_backwards, 2 );
|
173
119
|
}
|
@@ -21,6 +21,25 @@ void na_quick_pos_to_idxs( int rank, int *shape, int pos, int *idxs ) {
|
|
21
21
|
return;
|
22
22
|
}
|
23
23
|
|
24
|
+
// This is copied from na_array.c, with safety checks and temp vars removed
|
25
|
+
inline int na_inline_idxs_to_pos( int rank, int *shape, int *idxs ) {
|
26
|
+
int i, pos = 0;
|
27
|
+
for ( i = rank - 1; i >= 0; i-- ) {
|
28
|
+
pos = pos * shape[i] + idxs[i];
|
29
|
+
}
|
30
|
+
return pos;
|
31
|
+
}
|
32
|
+
|
33
|
+
// This is inverse of above
|
34
|
+
inline void na_inline_pos_to_idxs( int rank, int *shape, int pos, int *idxs ) {
|
35
|
+
int i;
|
36
|
+
for ( i = 0; i < rank; i++ ) {
|
37
|
+
idxs[ i ] = pos % shape[i];
|
38
|
+
pos /= shape[i];
|
39
|
+
}
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
|
24
43
|
// used to place kernel data into array for FFTW3 processing
|
25
44
|
void fit_backwards_raw( int rank, int *dst_shape, float *dst, int *src_shape, float *src, int *shift_shape ) {
|
26
45
|
int i, j, size, x;
|
@@ -30,13 +49,13 @@ void fit_backwards_raw( int rank, int *dst_shape, float *dst, int *src_shape, fl
|
|
30
49
|
for ( j = 0; j < rank; j++ ) { size *= src_shape[j]; }
|
31
50
|
|
32
51
|
for ( i = 0; i < size; i++ ) {
|
33
|
-
|
52
|
+
na_inline_pos_to_idxs( rank, src_shape, i, k_idx );
|
34
53
|
for ( j = 0; j < rank; j++ ) {
|
35
54
|
x = src_shape[j] - shift_shape[j] - k_idx[j] - 1;
|
36
55
|
if ( x < 0 ) x = x + dst_shape[j];
|
37
56
|
dst_idx[j] = x;
|
38
57
|
}
|
39
|
-
dst[
|
58
|
+
dst[ na_inline_idxs_to_pos( rank, dst_shape, dst_idx ) ] = src[i];
|
40
59
|
}
|
41
60
|
return;
|
42
61
|
}
|
data/lib/convolver/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: convolver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Neil Slater
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: narray
|
@@ -137,8 +137,6 @@ files:
|
|
137
137
|
- README.md
|
138
138
|
- Rakefile
|
139
139
|
- convolver.gemspec
|
140
|
-
- ext/convolver/cnn_components.c
|
141
|
-
- ext/convolver/cnn_components.h
|
142
140
|
- ext/convolver/convolve_raw.c
|
143
141
|
- ext/convolver/convolve_raw.h
|
144
142
|
- ext/convolver/convolver.c
|
@@ -151,7 +149,6 @@ files:
|
|
151
149
|
- spec/convolve_fftw3_spec.rb
|
152
150
|
- spec/convolve_spec.rb
|
153
151
|
- spec/helpers.rb
|
154
|
-
- spec/nn_run_layer_spec.rb
|
155
152
|
homepage: http://github.com/neilslater/convolver
|
156
153
|
licenses:
|
157
154
|
- MIT
|
@@ -181,5 +178,4 @@ test_files:
|
|
181
178
|
- spec/convolve_fftw3_spec.rb
|
182
179
|
- spec/convolve_spec.rb
|
183
180
|
- spec/helpers.rb
|
184
|
-
- spec/nn_run_layer_spec.rb
|
185
181
|
has_rdoc:
|
@@ -1,52 +0,0 @@
|
|
1
|
-
// ext/convolver/cnn_components.c
|
2
|
-
|
3
|
-
#include <xmmintrin.h>
|
4
|
-
#include "cnn_components.h"
|
5
|
-
|
6
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////
|
7
|
-
//
|
8
|
-
// Run a single fully-connected layer, calculating output from input
|
9
|
-
//
|
10
|
-
// Benchmark: 1024 inputs, 256 outputs. 1000 iterations. 0.56 seconds
|
11
|
-
//
|
12
|
-
//
|
13
|
-
|
14
|
-
void nn_run_layer_raw( int in_size, int out_size,
|
15
|
-
float *in_ptr, float *weights, float *thresholds, float *out_ptr ) {
|
16
|
-
int i, j, in_aligned_size, out_aligned_size, offset;
|
17
|
-
__m128 simd_x, simd_y, simd_t;
|
18
|
-
|
19
|
-
in_aligned_size = 4 * ( in_size/4 );
|
20
|
-
out_aligned_size = 4 * ( out_size/4 );
|
21
|
-
|
22
|
-
// Calculate activation
|
23
|
-
for ( i = 0; i < out_size; i++ ) {
|
24
|
-
|
25
|
-
float t = 0.0;
|
26
|
-
simd_t = _mm_setzero_ps();
|
27
|
-
offset = i * in_size;
|
28
|
-
|
29
|
-
// Use SIMD for all the aligned values in groups of 4
|
30
|
-
for ( j = 0; j < in_aligned_size; j +=4 ) {
|
31
|
-
simd_x = _mm_load_ps( in_ptr + j );
|
32
|
-
// Weights might not align to 16 bytes due to size of layers
|
33
|
-
simd_y = _mm_loadu_ps( weights + (offset + j) );
|
34
|
-
simd_x = _mm_mul_ps( simd_x, simd_y );
|
35
|
-
simd_t = _mm_add_ps( simd_x, simd_t );
|
36
|
-
}
|
37
|
-
|
38
|
-
// Complete any remaining 1,2 or 3 items one at a time
|
39
|
-
for ( j = in_aligned_size; j < in_size; j++ ) {
|
40
|
-
t += in_ptr[ j ] * weights[ offset + j ];
|
41
|
-
}
|
42
|
-
|
43
|
-
out_ptr[i] = simd_t[0] + simd_t[1] + simd_t[2] + simd_t[3] + t;
|
44
|
-
}
|
45
|
-
|
46
|
-
for ( i = 0; i < out_size; i++ ) {
|
47
|
-
out_ptr[i] -= thresholds[i];
|
48
|
-
if ( out_ptr[i] < 0.0 ) { out_ptr[i] = 0.0; }
|
49
|
-
}
|
50
|
-
|
51
|
-
return;
|
52
|
-
}
|
@@ -1,14 +0,0 @@
|
|
1
|
-
// ext/convolver/cnn_components.h
|
2
|
-
|
3
|
-
////////////////////////////////////////////////////////////////////////////////////////////////
|
4
|
-
//
|
5
|
-
// Declarations of narray helper functions
|
6
|
-
//
|
7
|
-
|
8
|
-
#ifndef CNN_COMPONENTS_H
|
9
|
-
#define CNN_COMPONENTS_H
|
10
|
-
|
11
|
-
void nn_run_layer_raw( int in_size, int out_size,
|
12
|
-
float *in_ptr, float *weights, float *thresholds, float *out_ptr );
|
13
|
-
|
14
|
-
#endif
|
data/spec/nn_run_layer_spec.rb
DELETED
@@ -1,25 +0,0 @@
|
|
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
|