-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtensor.go
254 lines (225 loc) · 6.39 KB
/
tensor.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
package convnetgo
import (
"errors"
"math"
"math/rand"
)
//Tensor is the basic data structure of convolutional neural networks.
//It can be used for regular neural networks too.
type Tensor struct {
dims []int
stride []int
f32data []float32
nhwc bool
}
const maxdimsize = 4
const mindimsize = 4
//CreateTensorEx creates a tensor and copies data into Tensor if len(data)!=(t*Tensor)Volume() then error will return
//If len(dims) not ==4 an error will return!
func CreateTensorEx(dims []int, data []float32, NHWC bool) (*Tensor, error) {
if len(data) != findvolume(dims) {
return nil, errors.New("CreateTensorEx - len(data) not equal to vol of dims")
}
t, err := CreateTensor(dims, NHWC)
if err != nil {
return nil, err
}
for i := range data {
t.f32data[i] = data[i]
}
return t, nil
}
//Volume returns volume of tensor (num of elements)
func (t *Tensor) Volume() int {
return findvolume(t.dims)
}
//AddAll adds val to all elements in t
func (t *Tensor) AddAll(val float32) {
for i := range t.f32data {
t.f32data[i] += val
}
}
//MultAll multiplies val to all elements in t
func (t *Tensor) MultAll(val float32) {
for i := range t.f32data {
t.f32data[i] *= val
}
}
//Average returns the average of all the elements in t
func (t *Tensor) Average() float32 {
var adder float32
for i := range t.f32data {
adder += t.f32data[i]
}
return adder / (float32)(len(t.f32data))
}
//AddAtoT does is t=t+(alpha1*A)
func (t *Tensor) AddAtoT(A *Tensor, alpha1 float32) error {
if len(t.f32data) != len(A.f32data) {
return errors.New("(t *Tensor)Add length of t, A, B data not equal")
}
for i := range t.f32data {
t.f32data[i] += (A.f32data[i] * alpha1)
}
return nil
}
//Add does a t[i]=t[i]*beta + A[i]*alpha1 +B[i]*alpha2
func (t *Tensor) Add(A, B *Tensor, alpha1, alpha2, beta float32) error {
if len(t.f32data) != len(A.f32data) || len(t.f32data) != len(B.f32data) {
return errors.New("(t *Tensor)Add length of t, A, B data not equal")
}
if beta == 0 {
for i := range t.f32data {
t.f32data[i] = (A.f32data[i] * alpha1) + (B.f32data[i] * alpha2)
}
}
for i := range t.f32data {
t.f32data[i] = t.f32data[i]*beta + (A.f32data[i] * alpha1) + (B.f32data[i] * alpha2)
}
return nil
}
//Mult does a t[i]=t[i]*beta + A[i]*alpha1 *B[i]*alpha2
func (t *Tensor) Mult(A, B *Tensor, alpha1, alpha2, beta float32) error {
if len(t.f32data) != len(A.f32data) || len(t.f32data) != len(B.f32data) {
return errors.New("(t *Tensor)Mult length of t, A, B data not equal")
}
for i := range t.f32data {
t.f32data[i] = t.f32data[i]*beta + A.f32data[i]*alpha1*B.f32data[i]*alpha2
}
return nil
}
//Div does a t[i]=t[i]*beta + A[i]*alpha1 / B[i]*alpha2
func (t *Tensor) Div(A, B *Tensor, alpha1, alpha2, beta float32) error {
if len(t.f32data) != len(A.f32data) || len(t.f32data) != len(B.f32data) {
return errors.New("(t *Tensor)Div length of t, A, B data not equal")
}
if alpha2 == 0 {
return errors.New("(t *Tensor) Div : alpha2 == 0 cant devide by zero")
}
for i := range t.f32data {
t.f32data[i] = t.f32data[i]*beta + A.f32data[i]*alpha1/B.f32data[i]*alpha2
}
return nil
}
//Dims returns a copy of tensor dims
func (t *Tensor) Dims() (dims []int) {
dims = make([]int, len(t.dims))
copy(dims, t.dims)
return dims
}
//Stride returns a copy of tensor stride
func (t *Tensor) Stride() (stride []int) {
stride = make([]int, len(t.stride))
copy(stride, t.stride)
return stride
}
//CreateRandomizedWeightsTensor creates a tensor with randomized weights.
func CreateRandomizedWeightsTensor(wdims, xdims []int, NHWC bool) (*Tensor, error) {
t, err := CreateTensor(wdims, NHWC)
if err != nil {
return nil, err
}
fanin := float64(findvolume(xdims[1:]))
for i := range t.f32data {
t.f32data[i] = (float32)(gauassian(0, 2, fanin))
}
return t, nil
}
//CreateTensor creates a tensor according to the values passed. If len(dims) not ==4 an error will return!
//f64 is a place holder only thing available is float32
func CreateTensor(dims []int, NHWC bool) (*Tensor, error) {
if len(dims) < 4 || len(dims) > 4 {
return nil, errors.New("Not a valid length of dims")
}
//fmt.Println(dims)
return &Tensor{
dims: dims,
stride: findstride(dims),
f32data: make([]float32, findvolume(dims)),
nhwc: NHWC,
}, nil
}
//Set sets the value in the tensor at dim location
func (t *Tensor) Set(value float32, dimlocation []int) {
var location int
for i := range dimlocation {
location += dimlocation[i] * t.stride[i]
}
t.f32data[location] = value
}
//Get returns the value at dim location
func (t *Tensor) Get(dimlocation []int) (value float32) {
var location int
for i := range dimlocation {
location += dimlocation[i] * t.stride[i]
}
value = t.f32data[location]
return value
}
func gauassian(mean, std, ninputelements float64) float64 {
//Polar method
var x, y, z float64
for z >= 1 || z == 0 {
x = (2 * rand.Float64()) - float64(1)
y = (2 * rand.Float64()) - float64(1)
z = x*x + y*y
}
return (mean + std*float64(x*math.Sqrt(-2*math.Log(z)/z))) * (math.Sqrt((2.0) / (ninputelements)))
}
//ZeroClone returns a zeroed out clone of t
func (t *Tensor) ZeroClone() (*Tensor, error) {
return CreateTensor(t.dims, t.nhwc)
}
//SetAll sets all the elments in t to value.
func (t *Tensor) SetAll(value float32) {
for i := range t.f32data {
t.f32data[i] = value
}
}
//LoadFromSlice will load from values into the tensor. It starts at zero til the length of values.
//If values is longer than the volume of the tensor an error will return.
func (t *Tensor) LoadFromSlice(values []float32) (err error) {
if len(values) > len(t.f32data) {
return errors.New("values slice larger than tensor volume")
}
for i := range values {
t.f32data[i] = values[i]
}
return nil
}
func findrecursivelocation(dims, stride []int, val int) (location int) {
if len(dims) == 1 {
val += dims[0] * stride[0]
return val
}
val += dims[0] * stride[0]
return findrecursivelocation(dims[1:], stride[1:], val)
}
func comparedims(xdims, ydims []int) bool {
if len(xdims) != len(ydims) {
return false
}
for i := range xdims {
if xdims[i] != ydims[i] {
return false
}
}
return true
}
//findvolume will save us a lot of trouble.
func findvolume(dims []int) (vol int) {
vol = 1
for i := range dims {
vol *= dims[i]
}
return vol
}
func findstride(dims []int) (stride []int) {
stride = make([]int, len(dims))
strider := int(1)
for i := len(dims) - 1; i >= 0; i-- {
stride[i] = strider
strider *= dims[i]
}
return stride
}