-
Notifications
You must be signed in to change notification settings - Fork 0
/
conv_layer.go
61 lines (49 loc) · 1.53 KB
/
conv_layer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package robonet
import (
"errors"
"fmt"
"log"
)
//ConvLayer basic type for a convolutional layer
//The layer will compute the output of neurons that are connected to local regions in the input,
//each computing a dot product between their weights and a small region they are connected to in
//the input volume. This may result in volume such as [32x32x12] if we decided to use 12 filters.
type ConvLayer struct {
LayerFields
kernels []Kernel
strideR int
strideC int
}
//AddKernel adds a kernel to a layer
func (l *ConvLayer) AddKernel(kern Kernel, strideR, strideC int) {
l.kernels = append(l.kernels, kern)
if l.strideC == 0 || l.strideR == 0 {
if strideC == 0 || strideR == 0 {
log.Fatal(errors.New("robonet.ConvLayer: invalid stride for kernel"))
}
l.strideC = strideC
l.strideR = strideR
} else {
if l.strideC != strideC || l.strideR != strideR {
log.Fatal(errors.New("robonet.ConvLayer: invalid stride for kernel, already set"))
}
}
}
//Calculate applys all Kernels to a given Volume
func (l *ConvLayer) Calculate() {
l.output = New(l.input.Rows()/l.strideR, l.input.Collumns()/l.strideC, len(l.kernels))
res := l.output
for k, v := range l.kernels {
fmt.Println(" Calculating Kernel ", k)
for r := 0; r < l.output.Rows(); r++ {
for c := 0; c < l.output.Collumns(); c++ {
res.SetAt(r, c, k, v.Apply(l.input.SubVolumePadded(r*l.strideR, c*l.strideC, v.Rows(), v.Collumns())))
}
}
}
l.output = res
}
//Kernels returns the kernels of the layer
func (l ConvLayer) Kernels() []Kernel {
return l.kernels
}