Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

swh:1:snp:00a09dfe75d92a5d9631593944db4c280ca40ab3
  • Code
  • Branches (1)
  • Releases (0)
    • Branches
    • Releases
    • HEAD
    • refs/heads/main
    No releases to show
  • e84a592
  • /
  • src
  • /
  • datasets
  • /
  • pca.py
Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
  • revision
  • snapshot
content badge
swh:1:cnt:03c81f01371c2b74134f06dfdc6ecfae860046c6
directory badge
swh:1:dir:44dbae8a3602ecf2bce3ca35c8b38bcab0f026c0
revision badge
swh:1:rev:9eccfe575524736f25f4f3759fe04648f22554de
snapshot badge
swh:1:snp:00a09dfe75d92a5d9631593944db4c280ca40ab3

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
  • revision
  • snapshot
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
Tip revision: 9eccfe575524736f25f4f3759fe04648f22554de authored by Luke Taylor on 09 April 2024, 14:00:54 UTC
Added brainbox version.
Tip revision: 9eccfe5
pca.py
import os
from pathlib import Path
import shutil

import torch
from sklearn.decomposition import IncrementalPCA

from src import util


class PCBuilder:

    def __init__(self, root, model_name, layer, dataset_name, ntau, nlat, nspan, scale, n_pca):
        self._root = root
        self._model_name = model_name
        self._layer = layer
        self._dataset_name = dataset_name
        self._ntau = ntau
        self._nlat = nlat
        self._nspan = nspan
        self._scale = scale
        self._n_pca = n_pca

        if not os.path.exists(f"{self._root}/data/x/{self.train_name}.pt"):
            self._model = util.get_model(root, model_name, ntau, nlat, nspan, layer)
            self._train_dataset = util.get_dataset(root, dataset_name, "train", ntau, 0, normalise=True, scale=scale)
            self._test_dataset = util.get_dataset(root, dataset_name, "test", ntau, 0, normalise=True, scale=scale)

            self._pca = None

    @property
    def train_name(self):
        return util.get_dataset_x_name(self._model_name, self._dataset_name, "train", self._ntau, self._nlat, self._nspan, self._scale, self._n_pca, self._layer)

    @property
    def test_name(self):
        return util.get_dataset_x_name(self._model_name, self._dataset_name, "test", self._ntau, self._nlat, self._nspan, self._scale, self._n_pca, self._layer)

    def fit_and_transform(self, batch=1000):
        if os.path.exists(f"{self._root}/data/x/{self.train_name}.pt"):
            print(f"Already built for {self.train_name}")
            return

        n_train_batches = self.generate_model_outputs(self._train_dataset, self.train_name, batch)
        n_test_batches = self.generate_model_outputs(self._test_dataset, self.test_name, batch)
        self.fit_pca(self.train_name, n_train_batches)
        train_pcs = self.get_pcs(self.train_name, n_train_batches)
        test_pcs = self.get_pcs(self.test_name, n_test_batches)
        torch.save(train_pcs, f"{self._root}/data/x/{self.train_name}.pt")
        torch.save(test_pcs, f"{self._root}/data/x/{self.test_name}.pt")

        shutil.rmtree(f"{self._root}/data/temp/{self.train_name}")
        shutil.rmtree(f"{self._root}/data/temp/{self.test_name}")

    def generate_model_outputs(self, dataset, name, batch):
        # Create intermediate directory for model activations
        Path(f"{self._root}/data/temp/{name}").mkdir(parents=True, exist_ok=False)

        batch_idx = 0
        n_batches = int(len(dataset) / batch)
        batch_activity_list = []

        for i, (x, _) in enumerate(dataset):
            with torch.no_grad():
                activity = self._model(x)
                if self._nlat == 0:
                    activity = activity[-self._nspan:]
                else:
                    activity = activity[-self._nspan: -self._nlat]
                activity = activity.flatten()
                batch_activity_list.append(activity)

            if len(batch_activity_list) == batch and batch_idx < n_batches - 1:
                activity_batch = torch.stack(batch_activity_list)
                torch.save(activity_batch, f"{self._root}/data/temp/{name}/{batch_idx}.pt")
                batch_idx += 1
                batch_activity_list = []

        if len(batch_activity_list) > 0:
            activity_batch = torch.stack(batch_activity_list)
            torch.save(activity_batch, f"{self._root}/data/temp/{name}/{batch_idx}.pt")

        return n_batches

    def fit_pca(self, name, n_batches):
        self._pca = IncrementalPCA(n_components=self._n_pca)

        for i in range(n_batches):
            activity_batch = torch.load(f"{self._root}/data/temp/{name}/{i}.pt")
            activity_batch = activity_batch.numpy()
            self._pca.partial_fit(activity_batch)
            print(f"Completed fitting pca {i}/{n_batches}...")

    def get_pcs(self, name, n_batches):
        pc_list = []

        for i in range(n_batches):
            activity_batch = torch.load(f"{self._root}/data/temp/{name}/{i}.pt")
            activity_batch = activity_batch.numpy()
            pcs = torch.from_numpy(self._pca.transform(activity_batch))
            pc_list.append(pcs)
            print(f"Completed building pca {i}/{n_batches}...")

        return torch.cat(pc_list)


class PCDataset(torch.utils.data.Dataset):

    def __init__(self, root, model, dataset, split, ntau, nlat, nspan, scale, n_pca, layer=None):
        x_name = util.get_dataset_x_name(model, dataset, split, ntau, nlat, nspan, scale, n_pca, layer)
        y_name = util.get_dataset_y_name(dataset, split, ntau)
        self._x = torch.load(f"{root}/data/x/{x_name}.pt")  # b x n (model neurons)
        self._y = torch.load(f"{root}/data/y/{y_name}.pt").permute(1, 0, 2)  # b x n (real neurons) x repeat
        assert len(self._x) == len(self._y), f"x {self._x.shape} y {self._y.shape}"

        # Normalise
        x_train_name = util.get_dataset_x_name(model, dataset, "train", ntau, nlat, nspan, scale, n_pca, layer)
        x_train = torch.load(f"{root}/data/x/{x_train_name}.pt")
        mean, std = x_train.mean(), x_train.std()
        self._x = (self._x - mean) / std

        self._max_ccs = util.get_dataset_max_ccs(dataset)

    def __getitem__(self, i):
        x, y = self._x[i], self._y[i]
        if len(y.shape) == 2:
            y = y.mean(1)

        return x, y

    def __len__(self):
        return len(self._x)

    @property
    def y(self):
        return self._y

    @property
    def x(self):
        return self._x

    @property
    def max_ccs(self):
        return self._max_ccs

    @property
    def hyperparams(self):
        return {}

back to top

Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API