{"id":25126091,"url":"https://github.com/stephantul/somber","last_synced_at":"2025-07-21T15:05:17.210Z","repository":{"id":16012884,"uuid":"73062513","full_name":"stephantul/somber","owner":"stephantul","description":"Recursive Self-Organizing Map/Neural Gas.","archived":false,"fork":false,"pushed_at":"2022-12-27T15:43:55.000Z","size":509,"stargazers_count":52,"open_issues_count":6,"forks_count":14,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-06-28T11:43:40.798Z","etag":null,"topics":["cython","kohonen","machine-learning","neural-gas","ng","plsom","recsom","recurrent-neural-networks","som","unsupervised"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stephantul.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-07T09:29:20.000Z","updated_at":"2024-08-02T03:01:57.000Z","dependencies_parsed_at":"2023-01-13T18:39:47.605Z","dependency_job_id":null,"html_url":"https://github.com/stephantul/somber","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/stephantul/somber","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephantul%2Fsomber","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephantul%2Fsomber/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephantul%2Fsomber/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephantul%2Fsomber/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stephantul","download_url":"https://codeload.github.com/stephantul/somber/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephantul%2Fsomber/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266324447,"owners_count":23911226,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-21T11:47:31.412Z","response_time":64,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cython","kohonen","machine-learning","neural-gas","ng","plsom","recsom","recurrent-neural-networks","som","unsupervised"],"created_at":"2025-02-08T09:17:56.849Z","updated_at":"2025-07-21T15:05:17.181Z","avatar_url":"https://github.com/stephantul.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"SOMBER\n======\n\n**somber** (Somber Organizes Maps By Enabling Recurrence) is a collection of numpy/python implementations of various kinds of *Self-Organizing Maps* (SOMS), with a focus on SOMs for sequence data.\n\nTo the best of my knowledge, the sequential SOM algorithms implemented in this package haven't been open-sourced yet. If you do find examples, please let me know, so I can compare and link to them.\n\nThe package currently contains implementations of:\n\n  * Regular Som (SOM) (Kohonen, various publications)\n  * Recursive Som (RecSOM) (`Voegtlin, 2002 \u003chttp://www.sciencedirect.com/science/article/pii/S0893608002000722\u003e`_)\n  * Neural Gas (NG) (`Martinetz \u0026 Schulten, 1991 \u003chttps://www.ks.uiuc.edu/Publications/Papers/PDF/MART91B/MART91B.pdf\u003e`_)\n  * Recursive Neural Gas (Voegtlin, 2002)\n  * Parameterless Som (`Berglund \u0026 Sitte, 2007 \u003chttps://arxiv.org/abs/0705.0199\u003e`_)\n\nBecause these various sequential SOMs rely on internal dynamics for convergence, i.e. they do not fixate on some external label like a regular Recurrent Neural Network, processing in a sequential SOM is currently strictly online. This means that every example is processed separately, and weight updates happen after every example. Research into the development of batching and/or multi-threading is currently underway.\n\nIf you need a fast regular SOM, check out `SOMPY \u003chttps://github.com/sevamoo/SOMPY\u003e`_, which is a direct port of the MATLAB Som toolbox.\n\nUsage\n-----\n\nCare has been taken to make SOMBER easy to use, and function like a drop-in replacement for sklearn-like systems.\nThe non-recurrent SOMs take as input ``[M * N]`` arrays, where M is the number of samples and N is the number of features.\nThe recurrent SOMs take as input ``[M * S * N]`` arrays, where M is the number of sequences, S is the number of items per sequence, and N is the number of features.\n\nExamples\n--------\n\nColors\n------\n\nColor clustering is a kind of ``Hello, World`` for Soms, because it nicely demonstrates how SOMs create a continuous mapping.\nThe color dataset comes from this nice `blog \u003chttps://codesachin.wordpress.com/2015/11/28/self-organizing-maps-with-googles-tensorflow\u003e`_\n\n.. code-block:: python\n\n  import numpy as np\n\n  from somber import Som\n\n  X = np.array([[0., 0., 0.],\n                [0., 0., 1.],\n                [0., 0., 0.5],\n                [0.125, 0.529, 1.0],\n                [0.33, 0.4, 0.67],\n                [0.6, 0.5, 1.0],\n                [0., 1., 0.],\n                [1., 0., 0.],\n                [0., 1., 1.],\n                [1., 0., 1.],\n                [1., 1., 0.],\n                [1., 1., 1.],\n                [.33, .33, .33],\n                [.5, .5, .5],\n                [.66, .66, .66]])\n\n  color_names = ['black', 'blue', 'darkblue', 'skyblue',\n                 'greyblue', 'lilac', 'green', 'red',\n                 'cyan', 'violet', 'yellow', 'white',\n                 'darkgrey', 'mediumgrey', 'lightgrey']\n\n  # initialize\n  s = Som((10, 10), learning_rate=0.3)\n\n  # train\n  # 10 updates with 10 epochs = 100 updates to the parameters.\n  s.fit(X, num_epochs=10, updates_epoch=10)\n\n  # predict: get the index of each best matching unit.\n  predictions = s.predict(X)\n  # quantization error: how well do the best matching units fit?\n  quantization_error = s.quantization_error(X)\n  # inversion: associate each node with the exemplar that fits best.\n  inverted = s.invert_projection(X, color_names)\n  # Mapping: get weights, mapped to the grid points of the SOM\n  mapped = s.map_weights()\n\n  import matplotlib.pyplot as plt\n\n  plt.imshow(mapped)\n\nSequences\n---------\n\nIn this example, we will show that the RecursiveSOM is able to memorize short sequences which are generated by a markov chain.\nWe will also demonstrate that the RecursiveSOM can generate sequences which are consistent with the sequences on which it has been trained.\n\n.. code-block:: python\n\n  import numpy as np\n\n  from somber import RecursiveSom\n  from string import ascii_lowercase\n\n  # Dumb sequence generator.\n  def seq_gen(num_to_gen, probas):\n\n      symbols = ascii_lowercase[:probas.shape[0]]\n      identities = np.eye(probas.shape[0])\n      seq = []\n      ids = []\n      r = 0\n      choices = np.arange(probas.shape[0])\n      for x in range(num_to_gen):\n          r = np.random.choice(choices, p=probas[r])\n          ids.append(symbols[r])\n          seq.append(identities[r])\n\n      return np.array(seq), ids\n\n  # Transfer probabilities.\n  # after an A, we have a 50% chance of B or C\n  # after B, we have a 100% chance of A\n  # after C, we have a 50% chance of B or C\n  # therefore, we will never expect sequential A or B, but we do expect\n  # sequential C.\n  probas = np.array(((0.0, 0.5, 0.5),\n                     (1.0, 0.0, 0.0),\n                     (0.0, 0.5, 0.5)))\n\n  X, ids = seq_gen(10000, probas)\n\n  # initialize\n  # alpha = contribution of non-recurrent part to the activation.\n  # beta = contribution of recurrent part to activation.\n  # higher alpha to beta ratio\n  s = RecursiveSom((10, 10),\n                   learning_rate=0.3,\n                   alpha=1.2,\n                   beta=.9)\n\n  # train\n  # show a progressbar.\n  s.fit(X, num_epochs=100, updates_epoch=10, show_progressbar=True)\n\n  # predict: get the index of each best matching unit.\n  predictions = s.predict(X)\n  # quantization error: how well do the best matching units fit?\n  quantization_error = s.quantization_error(X)\n\n  # inversion: associate each node with the exemplar that fits best.\n  inverted = s.invert_projection(X, ids)\n\n  # find which sequences are mapped to which neuron.\n  receptive_field = s.receptive_field(X, ids)\n\n  # generate some data by starting from some position.\n  # the position can be anything, but must have a dimensionality\n  # equal to the number of weights.\n  starting_pos = np.ones(s.num_neurons)\n  generated_indices = s.generate(50, starting_pos)\n\n  # turn the generated indices into a sequence of symbols.\n  generated_seq = inverted[generated_indices]\n\nTODO\n----\n\nSee issues for TODOs/enhancements. If you use SOMBER, feel free to send me suggestions!\n\nContributors\n------------\n\n* Stéphan Tulkens\n\nLICENSE\n-------\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephantul%2Fsomber","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstephantul%2Fsomber","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephantul%2Fsomber/lists"}