-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathpool_2d.go
131 lines (119 loc) · 3.89 KB
/
pool_2d.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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package cnns
import (
"math"
"gonum.org/v1/gonum/mat"
)
// Pool2D Pooling of matrix with defined window: windowSize/stride/pooling_type. See ref. https://en.wikipedia.org/wiki/Convolutional_neural_network#Pooling_layer
/*
matrix - source matrix
outRows - number of output rows
outCols - number of output columns
channels - number of input channels
windowsSize - size of "kernel"
stride - step
ptype - type of pooling (max/min/avg)
returnMasks - return masks ??? (for training mode)
*/
func Pool2D(matrix *mat.Dense, outRows, outCols, channels, windowSize, stride int, ptype poolingType, returnMasks bool) (*mat.Dense, *mat.Dense, [][][2]int) {
sourceR, sourceC := matrix.Dims()
flattenSlice := []float64{}
if !returnMasks {
for c := 0; c < channels; c++ {
partialSlice := make([]float64, outRows*outCols)
tmpMatrix := ExtractChannel(matrix, sourceR, sourceC, channels, c)
for y := 0; y < outRows; y++ {
startYi := y * stride
startYj := startYi + windowSize
pool2D(tmpMatrix, partialSlice, y, startYi, startYj, outCols, windowSize, stride, ptype)
}
flattenSlice = append(flattenSlice, partialSlice...)
}
return mat.NewDense(outRows*channels, outCols, flattenSlice), nil, nil
}
masks := &mat.Dense{}
masksIndices := [][][2]int{}
for c := 0; c < channels; c++ {
partialSlice := make([]float64, outRows*outCols)
tmpMatrix := ExtractChannel(matrix, sourceR, sourceC, channels, c)
tmpR, tmpC := tmpMatrix.Dims()
partialMasks := mat.NewDense(tmpR, tmpC, nil)
partialMasks.Zero()
partialMasksIndices := make([][][2]int, outRows)
for y := 0; y < outRows; y++ {
startYi := y * stride
startYj := startYi + windowSize
pool2DWithMasks(tmpMatrix, partialMasks, partialMasksIndices, partialSlice, y, startYi, startYj, outCols, windowSize, stride, ptype)
}
if masks.IsEmpty() {
masks = partialMasks
} else {
tmp := &mat.Dense{}
tmp.Stack(masks, partialMasks)
masks = tmp
}
flattenSlice = append(flattenSlice, partialSlice...)
masksIndices = append(masksIndices, partialMasksIndices...)
}
return mat.NewDense(outRows*channels, outCols, flattenSlice), masks, masksIndices
}
// pool2D See ref. Pool2D()
func pool2D(matrix *mat.Dense, flattenMatrix []float64, y, startYi, startYj, outCols, windowSize, stride int, ptype poolingType) {
for x := 0; x < outCols; x++ {
startX := x * stride
part := matrix.Slice(startYi, startYj, startX, startX+windowSize)
switch ptype {
case poolMAX:
flattenMatrix[y*outCols+x] = maxPool(part)
break
case poolMIN:
panic("poolMIN is not implemented")
case poolAVG:
panic("poolAVG is not implemented")
default:
panic("default behaviour for pool_%TYPE% is not implemented")
}
}
}
func pool2DWithMasks(matrix, masks *mat.Dense, partialMasksIndices [][][2]int, flattenMatrix []float64, y, startYi, startYj, outCols, windowSize, stride int, ptype poolingType) {
partialMasks := make([][2]int, outCols)
for x := 0; x < outCols; x++ {
startX := x * stride
part := matrix.Slice(startYi, startYj, startX, startX+windowSize).(*mat.Dense)
partMask := masks.Slice(startYi, startYj, startX, startX+windowSize).(*mat.Dense)
switch ptype {
case poolMAX:
maxX, maxY, k := maxPoolIdx(part)
partMask.Set(maxX, maxY, 1)
partialMasks[x] = [2]int{maxX, maxY}
flattenMatrix[y*outCols+x] = k
break
case poolMIN:
panic("poolMIN is not implemented (with masks)")
case poolAVG:
panic("poolAVG is not implemented (with masks)")
default:
panic("default behaviour for pool_%TYPE% is not implemented (with masks)")
}
}
partialMasksIndices[y] = partialMasks
}
func maxPoolIdx(m mat.Matrix) (int, int, float64) {
max := math.Inf(-1)
maxi := -1
maxj := -1
rows, cols := m.Dims()
for x := 0; x < rows; x++ {
for y := 0; y < cols; y++ {
val := m.At(x, y)
if val > max {
max = val
maxi = x
maxj = y
}
}
}
return maxi, maxj, max
}
func maxPool(m mat.Matrix) float64 {
return mat.Max(m)
}