Simple self-organizing-map code (not optimized for performance)
import numpy as np | |
class SelfOrganizingMap(object): | |
def __init__(self, map_dims, input_dim): | |
self.map_dims = map_dims | |
self.input_dim = input_dim | |
self.weights = np.random.uniform(size=(map_dims + [input_dim]), low=0.0, high=1.0) | |
def __call__(self, input_batch, training=False): | |
# Compute how similar each vector in the map is to the input vectors | |
activations = np.array([np.sum(np.square(self.weights - b), axis=-1) for b in input_batch]) | |
if training: | |
num_batch = np.shape(input_batch)[0] | |
num_indices = np.product(self.map_dims) | |
# Loop through all vectors on the input batch | |
for b in range(num_batch): | |
# Find which point on the map has the vector that is closest to the input | |
best_matching_unit = np.argmax(activations[b], axis=None) | |
x0 = np.unravel_index(best_matching_unit, self.map_dims) | |
# Determine a radius of influence | |
r = 5.0 * np.exp(-1.0 * b / num_batch) | |
# Update all vectors associated with the points in the vicinity of the best-matching-unit | |
for i in range(num_indices): | |
# Compute the squared Euclidean distance between points on the map | |
x = np.unravel_index(i, self.map_dims) | |
dist2 = np.sum(np.square(np.array(list(x)) - np.array(list(x0)))) | |
# Set the update strength to be a Gaussian, centered at the best matching unit | |
w = 1.0 * np.exp(-dist2 / (2 * r**2)) | |
# Update weights | |
self.weights[x] = (1.0 - w) * self.weights[x] + w * input_batch[b] | |
return activations | |
if __name__ == '__main__': | |
# Example: Self-organizing map for 1000 colors (reducing 3 to 2 dimensions) | |
import matplotlib.pyplot as plt | |
som = SelfOrganizingMap([12, 12], 3) | |
colors = np.random.uniform(0.0, 1.0, size=[1000, 3]) | |
som(colors, training=True) | |
plt.imshow(som.weights) | |
plt.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment