convolver 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/convolver.png)](http://badge.fury.io/rb/convolver)
|
3
4
|
[![Build Status](https://travis-ci.org/neilslater/convolver.png?branch=master)](http://travis-ci.org/neilslater/convolver)
|
5
|
+
[![Dependency Status](https://gemnasium.com/neilslater/convolver.png)](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
|