-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathsom.py
76 lines (60 loc) · 2.57 KB
/
som.py
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
"""
Much of the code is modified from:
- https://codesachin.wordpress.com/2015/11/28/self-organizing-maps-with-googles-tensorflow/
"""
import torch
import torch.nn as nn
import numpy as np
from torch.autograd import Variable
class SOM(nn.Module):
"""
2-D Self-Organizing Map with Gaussian Neighbourhood function
and linearly decreasing learning rate.
"""
def __init__(self, m, n, dim, niter, alpha=None, sigma=None):
super(SOM, self).__init__()
self.m = m
self.n = n
self.dim = dim
self.niter = niter
if alpha is None:
self.alpha = 0.3
else:
self.alpha = float(alpha)
if sigma is None:
self.sigma = max(m, n) / 2.0
else:
self.sigma = float(sigma)
self.weights = torch.randn(m*n, dim)
self.locations = torch.LongTensor(np.array(list(self.neuron_locations())))
self.pdist = nn.PairwiseDistance(p=2)
def get_weights(self):
return self.weights
def get_locations(self):
return self.locations
def neuron_locations(self):
for i in range(self.m):
for j in range(self.n):
yield np.array([i, j])
def map_vects(self, input_vects):
to_return = []
for vect in input_vects:
min_index = min([i for i in range(len(self.weights))],
key=lambda x: np.linalg.norm(vect-self.weights[x]))
to_return.append(self.locations[min_index])
return to_return
def forward(self, x, it):
dists = self.pdist(torch.stack([x for i in range(self.m*self.n)]), self.weights)
_, bmu_index = torch.min(dists, 0)
bmu_loc = self.locations[bmu_index,:]
bmu_loc = bmu_loc.squeeze()
learning_rate_op = 1.0 - it/self.niter
alpha_op = self.alpha * learning_rate_op
sigma_op = self.sigma * learning_rate_op
bmu_distance_squares = torch.sum(torch.pow(self.locations.float() - torch.stack([bmu_loc for i in range(self.m*self.n)]).float(), 2), 1)
neighbourhood_func = torch.exp(torch.neg(torch.div(bmu_distance_squares, sigma_op**2)))
learning_rate_op = alpha_op * neighbourhood_func
learning_rate_multiplier = torch.stack([learning_rate_op[i:i+1].repeat(self.dim) for i in range(self.m*self.n)])
delta = torch.mul(learning_rate_multiplier, (torch.stack([x for i in range(self.m*self.n)]) - self.weights))
new_weights = torch.add(self.weights, delta)
self.weights = new_weights