diff --git a/tests/tsom/tsom3/allclose_tsom3_ishida_vs_another.py b/tests/tsom/tsom3/allclose_tsom3_ishida_vs_another.py index b7988ce..18698c4 100644 --- a/tests/tsom/tsom3/allclose_tsom3_ishida_vs_another.py +++ b/tests/tsom/tsom3/allclose_tsom3_ishida_vs_another.py @@ -23,10 +23,10 @@ def test_ishida_vs_another(self): # set learning parameter nb_epoch = 60 latent_dim = [2, 2,2] - resolution = [5, 5,5] - sigma_max = [2.0, 2.0,2.0] - sigma_min = [0.2, 0.2,0.2] - tau = [50, 50,50] + resolution = [15,10,5] + sigma_max = [1.0, 2.0,1.5] + sigma_min = [0.1, 0.2,0.3] + tau = [15, 25,35] ## prepare init Z1init = np.random.rand(X.shape[0], latent_dim[0]) @@ -44,14 +44,17 @@ def test_ishida_vs_another(self): init=init) # learn tsom3_ishida.fit(nb_epoch=nb_epoch) - - tsom3_another.fit(nb_epoch=nb_epoch) # test np.testing.assert_allclose(tsom3_ishida.history['y'], tsom3_another.history['y']) - + np.testing.assert_allclose(tsom3_ishida.history['z1'], tsom3_another.history['z1']) + np.testing.assert_allclose(tsom3_ishida.history['z2'], tsom3_another.history['z2']) + np.testing.assert_allclose(tsom3_ishida.history['z3'], tsom3_another.history['z3']) + np.testing.assert_allclose(tsom3_ishida.history['sigma1'], tsom3_another.history['sigma1']) + np.testing.assert_allclose(tsom3_ishida.history['sigma2'], tsom3_another.history['sigma2']) + np.testing.assert_allclose(tsom3_ishida.history['sigma3'], tsom3_another.history['sigma3']) if __name__ == "__main__": diff --git a/tests/tsom/tsom3_weighted/__init__.py b/tests/tsom/tsom3_weighted/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/tsom/tsom3_weighted/allclose_tsom3_weighted_harada_vs_another.py b/tests/tsom/tsom3_weighted/allclose_tsom3_weighted_harada_vs_another.py new file mode 100644 index 0000000..82b2441 --- /dev/null +++ b/tests/tsom/tsom3_weighted/allclose_tsom3_weighted_harada_vs_another.py @@ -0,0 +1,70 @@ +#TSOM3のペアプロ用のファイル +import unittest +import numpy as np +from libs.models.tsom3 import TSOM3 +from tests.tsom.tsom3_weighted.tsom3_weighted import wTSOM3 +from tests.tsom.tsom3_weighted.tsom3_weighted_ishida import wTSOM3_ishida + + +# class TestTSOM3(unittest.TestCase): +# def test_harada_vs_another(self): + +# random seed setting +seed = 100 +np.random.seed(seed) + +# prepare observed data +nb_samples1 = 5 +nb_samples2 = 15 +nb_samples3 = 20 +nb_observed_dim=4 + +X = np.random.normal(0, 1, (nb_samples1, nb_samples2, nb_samples3, nb_observed_dim)) + +# set learning parameter +nb_epoch = 20 +latent_dim = [2, 2, 2] +resolution = [5, 5, 5] +sigma_max = [2.0, 2.0, 2.0] +sigma_min = [0.2, 0.2, 0.2] +tau = [50, 50, 50] + +## prepare init +Z1init = np.random.rand(X.shape[0], latent_dim[0]) +Z2init = np.random.rand(X.shape[1], latent_dim[1]) +Z3init = np.random.rand(X.shape[2], latent_dim[2]) +init = [Z1init, Z2init, Z3init] + +# generate tsom instance +tsom3_harada = wTSOM3(X, latent_dim=latent_dim, resolution=resolution, +SIGMA_MAX=sigma_max, SIGMA_MIN=sigma_min, TAU=tau, init=init) + +tsom3_ishida = wTSOM3_ishida(X, latent_dim=latent_dim, resolution=resolution, +SIGMA_MAX=sigma_max, SIGMA_MIN=sigma_min, TAU=tau, init=init) + +# learn +tsom3_harada.fit(nb_epoch=nb_epoch) + +tsom3_ishida.fit(nb_epoch=nb_epoch) + + +# test +# np.testing.assert_allclose(tsom3_harada.H1, tsom3_ishida.H1, rtol=1e-4, atol=0) +print("h1", np.allclose(tsom3_harada.H1, tsom3_ishida.H1)) +print("h2", np.allclose(tsom3_harada.H2, tsom3_ishida.H2)) +print("h3", np.allclose(tsom3_harada.H3, tsom3_ishida.H3)) +print("k1", np.allclose(tsom3_harada.k_star1, tsom3_ishida.k_star1)) +print("k2", np.allclose(tsom3_harada.k_star2, tsom3_ishida.k_star2)) +print("k3", np.allclose(tsom3_harada.k_star3, tsom3_ishida.k_star3)) +# print("u1", np.allclose(tsom3_harada.U1, tsom3_ishida.U1)) +# print("u2", np.allclose(tsom3_harada.U2, tsom3_ishida.U2)) +# print("u3", np.allclose(tsom3_harada.U3, tsom3_ishida.U3)) +print("y", np.allclose(tsom3_harada.Y, tsom3_ishida.Y)) +print("yhist", np.allclose(tsom3_harada.history['y'], tsom3_ishida.history['y'], rtol=1e-4, atol=0)) + +np.testing.assert_allclose(tsom3_harada.history['y'], tsom3_ishida.history['y'], rtol=1e-4, atol=0) + + + +# if __name__ == "__main__": +# unittest.main() diff --git a/tests/tsom/tsom3_weighted/datatsom.txt b/tests/tsom/tsom3_weighted/datatsom.txt new file mode 100644 index 0000000..19b51da --- /dev/null +++ b/tests/tsom/tsom3_weighted/datatsom.txt @@ -0,0 +1,109 @@ +-1.000000 -1.000000 0.000000 +-1.000000 -0.777778 0.395062 +-1.000000 -0.555556 0.691358 +-1.000000 -0.333333 0.888889 +-1.000000 -0.111111 0.987654 +-1.000000 0.111111 0.987654 +-1.000000 0.333333 0.888889 +-1.000000 0.555556 0.691358 +-1.000000 0.777778 0.395062 +-1.000000 1.000000 0.000000 + +-0.777778 -1.000000 -0.395062 +-0.777778 -0.777778 0.000000 +-0.777778 -0.555556 0.296296 +-0.777778 -0.333333 0.493827 +-0.777778 -0.111111 0.592593 +-0.777778 0.111111 0.592593 +-0.777778 0.333333 0.493827 +-0.777778 0.555556 0.296296 +-0.777778 0.777778 0.000000 +-0.777778 1.000000 -0.395062 + +-0.555556 -1.000000 -0.691358 +-0.555556 -0.777778 -0.296296 +-0.555556 -0.555556 0.000000 +-0.555556 -0.333333 0.197531 +-0.555556 -0.111111 0.296296 +-0.555556 0.111111 0.296296 +-0.555556 0.333333 0.197531 +-0.555556 0.555556 0.000000 +-0.555556 0.777778 -0.296296 +-0.555556 1.000000 -0.691358 + +-0.333333 -1.000000 -0.888889 +-0.333333 -0.777778 -0.493827 +-0.333333 -0.555556 -0.197531 +-0.333333 -0.333333 0.000000 +-0.333333 -0.111111 0.098765 +-0.333333 0.111111 0.098765 +-0.333333 0.333333 0.000000 +-0.333333 0.555556 -0.197531 +-0.333333 0.777778 -0.493827 +-0.333333 1.000000 -0.888889 + +-0.111111 -1.000000 -0.987654 +-0.111111 -0.777778 -0.592593 +-0.111111 -0.555556 -0.296296 +-0.111111 -0.333333 -0.098765 +-0.111111 -0.111111 0.000000 +-0.111111 0.111111 0.000000 +-0.111111 0.333333 -0.098765 +-0.111111 0.555556 -0.296296 +-0.111111 0.777778 -0.592593 +-0.111111 1.000000 -0.987654 + +0.111111 -1.000000 -0.987654 +0.111111 -0.777778 -0.592593 +0.111111 -0.555556 -0.296296 +0.111111 -0.333333 -0.098765 +0.111111 -0.111111 0.000000 +0.111111 0.111111 0.000000 +0.111111 0.333333 -0.098765 +0.111111 0.555556 -0.296296 +0.111111 0.777778 -0.592593 +0.111111 1.000000 -0.987654 + +0.333333 -1.000000 -0.888889 +0.333333 -0.777778 -0.493827 +0.333333 -0.555556 -0.197531 +0.333333 -0.333333 -0.000000 +0.333333 -0.111111 0.098765 +0.333333 0.111111 0.098765 +0.333333 0.333333 0.000000 +0.333333 0.555556 -0.197531 +0.333333 0.777778 -0.493827 +0.333333 1.000000 -0.888889 + +0.555556 -1.000000 -0.691358 +0.555556 -0.777778 -0.296296 +0.555556 -0.555556 0.000000 +0.555556 -0.333333 0.197531 +0.555556 -0.111111 0.296296 +0.555556 0.111111 0.296296 +0.555556 0.333333 0.197531 +0.555556 0.555556 0.000000 +0.555556 0.777778 -0.296296 +0.555556 1.000000 -0.691358 + +0.777778 -1.000000 -0.395062 +0.777778 -0.777778 -0.000000 +0.777778 -0.555556 0.296296 +0.777778 -0.333333 0.493827 +0.777778 -0.111111 0.592593 +0.777778 0.111111 0.592593 +0.777778 0.333333 0.493827 +0.777778 0.555556 0.296296 +0.777778 0.777778 0.000000 +0.777778 1.000000 -0.395062 + +1.000000 -1.000000 0.000000 +1.000000 -0.777778 0.395062 +1.000000 -0.555556 0.691358 +1.000000 -0.333333 0.888889 +1.000000 -0.111111 0.987654 +1.000000 0.111111 0.987654 +1.000000 0.333333 0.888889 +1.000000 0.555556 0.691358 +1.000000 0.777778 0.395062 +1.000000 1.000000 0.000000 \ No newline at end of file diff --git a/tests/tsom/tsom3_weighted/tsom3_learning_main.py b/tests/tsom/tsom3_weighted/tsom3_learning_main.py new file mode 100644 index 0000000..2b3d827 --- /dev/null +++ b/tests/tsom/tsom3_weighted/tsom3_learning_main.py @@ -0,0 +1,39 @@ + +import numpy as np +from tsom3_weighted import wTSOM3 +from tsom3_weighted_ishida import wTSOM3_ishida +from libs.models.tsom3 import TSOM3 + +X = np.loadtxt('datatsom.txt') +X = np.reshape(X, (10, 10, 3, 1)) + +np.random.seed(0) +# prepare init +latent_dim = np.array([2,2,2]) +Z1init = np.random.rand(X.shape[0], latent_dim[0]) +Z2init = np.random.rand(X.shape[1], latent_dim[1]) +Z3init = np.random.rand(X.shape[2], latent_dim[2]) +init = [Z1init, Z2init, Z3init] + +wtsom3harada = wTSOM3(X, latent_dim=2, resolution=5, SIGMA_MAX=2.0, SIGMA_MIN=0.2, TAU=50, init=init) +wtsom3harada.fit(10) + +wtsom3ishida = wTSOM3_ishida(X, latent_dim=2, resolution=5, SIGMA_MAX=2.0, SIGMA_MIN=0.2, TAU=50, init=init) +wtsom3ishida.fit(10) + +tsom3 = TSOM3(X, latent_dim=2, resolution=5, SIGMA_MAX=2.0, SIGMA_MIN=0.2, TAU=50, init=init) +tsom3.fit(10) + +print(np.allclose(wtsom3harada.history['y'], tsom3.history['y'])) +print(np.allclose(wtsom3ishida.history['y'], tsom3.history['y'])) +print(np.allclose(wtsom3harada.history['y'], wtsom3ishida.history['y'])) + +# np.save('tsom3_Y.npy',tsom3.Y) +# np.save('tsom3_k1.npy',tsom3.k1_star) +# np.save('tsom3_k2.npy',tsom3.k2_star) +# np.save('tsom3_k3.npy',tsom3.k3_star) +# np.save('wtsom3_Y.npy',wtsom3.Y) +# np.save('wtsom3_k1.npy',wtsom3.k_star1) +# np.save('wtsom3_k2.npy',wtsom3.k_star2) +# np.save('wtsom3_k3.npy',wtsom3.k_star3) + diff --git a/tests/tsom/tsom3_weighted/tsom3_weighted.py b/tests/tsom/tsom3_weighted/tsom3_weighted.py new file mode 100644 index 0000000..13e6e5e --- /dev/null +++ b/tests/tsom/tsom3_weighted/tsom3_weighted.py @@ -0,0 +1,253 @@ +import numpy as np +from libs.tools.create_zeta import create_zeta +from scipy.spatial import distance as distance +from tqdm import tqdm + +class wTSOM3(): + def __init__(self, X, latent_dim, resolution, SIGMA_MAX, SIGMA_MIN, TAU, gamma='nonweight', init='random'): + + # 入力データXについて + if X.ndim == 3: + self.X = X.reshape((X.shape[0], X.shape[1], X.shape[2], 1)) + self.N1 = self.X.shape[0] + self.N2 = self.X.shape[1] + self.N3 = self.X.shape[2] + self.observed_dim = self.X.shape[3] + elif X.ndim == 4: + self.X = X + self.N1 = self.X.shape[0] + self.N2 = self.X.shape[1] + self.N3 = self.X.shape[2] + self.observed_dim = self.X.shape[3] + else: + raise ValueError("invalid X: {}\nX must be 3d or 4d ndarray".format(X)) + + # 最大近傍半径(SIGMAX)の設定 + if type(SIGMA_MAX) is float: + self.SIGMA1_MAX = SIGMA_MAX + self.SIGMA2_MAX = SIGMA_MAX + self.SIGMA3_MAX = SIGMA_MAX + elif isinstance(SIGMA_MAX, (list, tuple)): + self.SIGMA1_MAX = SIGMA_MAX[0] + self.SIGMA2_MAX = SIGMA_MAX[1] + self.SIGMA3_MAX = SIGMA_MAX[2] + else: + raise ValueError("invalid SIGMA_MAX: {}".format(SIGMA_MAX)) + + # 最小近傍半径(SIGMA_MIN)の設定 + if type(SIGMA_MIN) is float: + self.SIGMA1_MIN = SIGMA_MIN + self.SIGMA2_MIN = SIGMA_MIN + self.SIGMA3_MIN = SIGMA_MIN + elif isinstance(SIGMA_MIN, (list, tuple)): + self.SIGMA1_MIN = SIGMA_MIN[0] + self.SIGMA2_MIN = SIGMA_MIN[1] + self.SIGMA3_MIN = SIGMA_MIN[2] + else: + raise ValueError("invalid SIGMA_MIN: {}".format(SIGMA_MIN)) + + # 時定数(TAU)の設定 + if type(TAU) is int: + self.TAU1 = TAU + self.TAU2 = TAU + self.TAU3 = TAU + elif isinstance(TAU, (list, tuple)): + self.TAU1 = TAU[0] + self.TAU2 = TAU[1] + self.TAU3 = TAU[2] + else: + raise ValueError("invalid TAU: {}".format(TAU)) + + # resolutionの設定 + if type(resolution) is int: + resolution1 = resolution + resolution2 = resolution + resolution3 = resolution + elif isinstance(resolution, (list, tuple)): + resolution1 = resolution[0] + resolution2 = resolution[1] + resolution3 = resolution[2] + else: + raise ValueError("invalid resolution: {}".format(resolution)) + + # 潜在空間の設定 + if type(latent_dim) is int: # latent_dimがintであればどちらのモードも潜在空間の次元は同じ + self.latent_dim1 = latent_dim + self.latent_dim2 = latent_dim + self.latent_dim3 = latent_dim + + elif isinstance(latent_dim, (list, tuple)): + self.latent_dim1 = latent_dim[0] + self.latent_dim2 = latent_dim[1] + self.latent_dim3 = latent_dim[2] + else: + raise ValueError("invalid latent_dim: {}".format(latent_dim)) + self.Zeta1 = create_zeta(-1.0, 1.0, latent_dim=self.latent_dim1, resolution=resolution1, include_min_max=True) + self.Zeta2 = create_zeta(-1.0, 1.0, latent_dim=self.latent_dim2, resolution=resolution2, include_min_max=True) + self.Zeta3 = create_zeta(-1.0, 1.0, latent_dim=self.latent_dim3, resolution=resolution3, include_min_max=True) + + # K1とK2は潜在空間の設定が終わった後がいいよね + self.K1 = self.Zeta1.shape[0] + self.K2 = self.Zeta2.shape[0] + self.K3 = self.Zeta3.shape[0] + + # 勝者ノードの初期化 + self.Z1 = None + self.Z2 = None + self.Z3 = None + if isinstance(init, str) and init in 'random': + self.Z1 = np.random.rand(self.N1, self.latent_dim1) * 2.0 - 1.0 + self.Z2 = np.random.rand(self.N2, self.latent_dim2) * 2.0 - 1.0 + self.Z3 = np.random.rand(self.N3, self.latent_dim3) * 2.0 - 1.0 + elif isinstance(init, (tuple, list)) and len(init) == 3: + if isinstance(init[0], np.ndarray) and init[0].shape == (self.N1, self.latent_dim1): + self.Z1 = init[0].copy() + else: + raise ValueError("invalid inits[0]: {}".format(init)) + if isinstance(init[1], np.ndarray) and init[1].shape == (self.N2, self.latent_dim2): + self.Z2 = init[1].copy() + else: + raise ValueError("invalid inits[1]: {}".format(init)) + if isinstance(init[2], np.ndarray) and init[2].shape == (self.N3, self.latent_dim3): + self.Z3 = init[2].copy() + else: + raise ValueError("invalid inits[2]: {}".format(init)) + else: + raise ValueError("invalid inits: {}".format(init)) + + # 重みテンソルの初期化 + self.gamma = None + if isinstance(gamma, str) and gamma in 'nonweight': + self.gamma = np.ones((self.N1, self.N2, self.N3)) + # elif isinstance(gamma, (tuple, list)) and gamma.ndim == 3: + # self.gamma = gamma + # else: + # raise ValueError("invalid gamma: {}".format(gamma)) + else: + self.gamma = gamma + + self.history = {} + + # デバッグ用 + self.H1 = None + self.H2 = None + self.H3 = None + + self.G1 = None + self.G2 = None + self.G3 = None + + self.k_star1 = None + self.k_star2 = None + self.k_star3 = None + + + def fit(self, nb_epoch=200): + self.history['y'] = np.zeros((nb_epoch, self.K1, self.K2, self.K3, self.observed_dim)) + self.history['z1'] = np.zeros((nb_epoch, self.N1, self.latent_dim1)) + self.history['z2'] = np.zeros((nb_epoch, self.N2, self.latent_dim2)) + self.history['z3'] = np.zeros((nb_epoch, self.N3, self.latent_dim3)) + self.history['sigma1'] = np.zeros(nb_epoch) + self.history['sigma2'] = np.zeros(nb_epoch) + self.history['sigma3'] = np.zeros(nb_epoch) + + for epoch in tqdm(np.arange(nb_epoch)): + # 学習量の決定 + sigma1 = max(self.SIGMA1_MIN, self.SIGMA1_MAX * (1 - (epoch / self.TAU1))) + distance1 = distance.cdist(self.Zeta1, self.Z1, metric='sqeuclidean') # 距離行列をつくるDはK1*N1行列 + H1 = np.exp(-distance1 / (2 * pow(sigma1, 2))) # かっこに気を付ける + self.H1 = np.exp(-distance1 / (2 * pow(sigma1, 2))) + + sigma2 = max(self.SIGMA2_MIN, self.SIGMA2_MAX * (1 - (epoch / self.TAU2))) + distance2 = distance.cdist(self.Zeta2, self.Z2, metric='sqeuclidean') # 距離行列をつくるDはK2*N2行列 + H2 = np.exp(-distance2 / (2 * pow(sigma2, 2))) # かっこに気を付ける + self.H2 = np.exp(-distance2 / (2 * pow(sigma2, 2))) + + sigma3 = max(self.SIGMA3_MIN, self.SIGMA3_MAX * (1 - (epoch / self.TAU3))) + distance3 = distance.cdist(self.Zeta3, self.Z3, metric='sqeuclidean') # 距離行列をつくるDはK3*N3行列 + H3 = np.exp(-distance3 / (2 * pow(sigma3, 2))) # かっこに気を付ける + self.H3 = np.exp(-distance3 / (2 * pow(sigma3, 2))) + + G1 = np.sum( + self.gamma[:, None, :, None, :] * H2[None, :, :, None, None] * H3[None, None, None, :, :], + axis=(2, 4)) # Gは行ごとの重みと掛け合わせて和をとったテンソル n1*k2*k3 + # G1 = np.sum( + # self.gamma[None, None, :, :, :] * H2[:, None, None, :, None] * H3[None, :, None, None, :], + # axis=(3, 4)) # Gは行ごとの重みと掛け合わせて和をとったテンソル k2*k3*n1 + # G1 = np.einsum('ijk,mj,nk->imn',self.gamma,H2,H3) + self.G1 = G1 + G2 = np.sum( + self.gamma[None, :, :, None, :] * H1[:, :, None, None, None] * H3[None, None, None, :, :], + axis=(1, 4)) # Gは行ごとの重みと掛け合わせて和をとったテンソル k1*n2*k3 + # G2 = np.sum( + # self.gamma[None, None, :, :, :] * H1[:, None, :, None, None] * H3[None, : None, None, :], + # axis=(2, 4)) # Gは行ごとの重みと掛け合わせて和をとったテンソル k1*k3*n2 + # G2 = np.einsum('ijk,li,nk->ljn',self.gamma,H1,H3) + self.G2 = G2 + G3 = np.sum( + self.gamma[None, :, None, :, :] * H1[:, :, None, None, None] * H2[None, None, :, :, None], + axis=(1, 3)) # Gは行ごとの重みと掛け合わせて和をとったテンソル k1*k2*n3 + # G3 = np.sum( + # self.gamma[None, None, :, :, :] * H1[:, None, :, None, None] * H2[None, :, None, :, None], + # axis=(2, 3)) # Gは行ごとの重みと掛け合わせて和をとったテンソル k1*k2*n3 + # G3 = np.einsum('ijk,li,mj->lmk',self.gamma,H1,H2) + self.G3 = G3 + # G4 = np.einsum('ijk,li,mj,nk->lmn',self.gamma,H1,H2,H3) + + # 1次モデル,2次モデルの決定 + # データ: i,j,k + # ノード: l,m,n + self.U1 = np.sum( + H2[None, :, :, None, None, None] * H3[None, None, None, :, :, None] * (self.gamma[:, :, :, None] * self.X)[:, None, :, None, :, :] + , axis=(2, 4)) / G1[:, :, :, None] # N1*K2*K3*D + # self.U1 = np.sum( + # H2[:, None, None, :, None, None] * H3[None, :, None, None, :, None] * (self.gamma[:, :, :, None] * self.X)[None, None, :, :, :, :] + # , axis=(3, 4)) / G1[:, :, :, None] # K2*K3*N1*D + # self.U1 = np.einsum('ijk,mj,nk,ijkd->imnd',self.gamma,H2,H3,self.X)/G1[:,:,:,None] + self.U2 = np.sum( + H1[:, :, None, None, None, None] * H3[None, None, None, :, :, None] * (self.gamma[:, :, :, None] * self.X)[None, :, :, None, :, :] + , axis=(1, 4)) / G2[:, :, :, None] # K1*N2*K3*D + # self.U2 = np.sum( + # H1[:, None, :, None, None, None] * H3[None, :, None, None, :, None] * (self.gamma[:, :, :, None] * self.X)[None, None, :, :, :, :] + # , axis=(2, 4)) / G2[:, :, :, None] # K1*K3*N2*D + # self.U2 = np.einsum('ijk,li,nk,ijkd->ljnd',self.gamma,H1,H3,self.X)/G2[:,:,:,None] + self.U3 = np.sum( + H1[:, :, None, None, None, None] * H2[None, None, :, :, None, None] * (self.gamma[:, :, :, None] * self.X)[None, :, None, :, :, :] + , axis=(1, 3)) / G3[:, :, :, None] # K1*K2*N3*D + # self.U3 = np.sum( + # H1[:, None, :, None, None, None] * H2[None, :, None, :, None, None] * (self.gamma[:, :, :, None] * self.X)[None, None, :, :, :, :] + # , axis=(2, 3)) / G3[:, :, :, None] # K1*K2*N3*D + # self.U3 = np.einsum('ijk,li,mj,ijkd->lmkd',self.gamma,H1,H2,self.X)/G3[:,:,:,None] + # 1次モデルを使って2次モデルを更新 + self.Y = np.sum(H1[:, :, None, None, None] * (G1[:, :, :, None] * self.U1)[None, :, :, :, :], + axis=1) / np.sum(H1[:, :, None, None] * G1[None, :, :, :], axis=1)[:, :, :, None] # K1*K2*K3*D + # self.Y = np.sum(H1[:, None, None, :, None] * (G1[:, :, :, None] * self.U1)[None, :, :, :, :], + # axis=3) / np.sum(H1[:, None, None, :, None] * G1[None, :, :, :, None], axis=3) # K1*K2*K3*D + # self.Y = np.einsum('ijk,li,mj,nk,ijkd->lmnd',self.gamma,H1,H2,H3,self.X)/G4[:,:,:,None] # K1*K2*K3*D + + # 勝者決定 + # モード1 + Dist1 = np.square(self.U1[None, :, :, :, :] - self.Y[:, None, :, :, :]) # K1*N1*K2*K3*D + Dist1_sum = np.sum(G1[None, :, :, :, None] * Dist1, axis=(2, 3, 4)) # K1*N1 + self.k_star1 = np.argmin(Dist1_sum, axis=0) # N1*1 + self.Z1 = self.Zeta1[self.k_star1, :] + + # モード2 + Dist2 = np.square(self.U2[:, None, :, :, :] - self.Y[:, :, None, :, :]) # K1*K2*N2*K3*D + Dist2_sum = np.sum(G2[:, None, :, :, None] * Dist2, axis=(0, 3, 4)) # K2*N2 + self.k_star2 = np.argmin(Dist2_sum, axis=0) + self.Z2 = self.Zeta2[self.k_star2, :] + + # モード3 + Dist3 = np.square(self.U3[:, :, None, :, :] - self.Y[:, :, :, None, :]) # K1*K2*K3*N3*D + Dist3_sum = np.sum(G3[:, :, None, :, None] * Dist3, axis=(0, 1, 4)) # K3*N3 + self.k_star3 = np.argmin(Dist3_sum, axis=0) # N3*1 + self.Z3 = self.Zeta3[self.k_star3, :] + + self.history['y'][epoch, :, :, :, :] = self.Y + self.history['z1'][epoch, :] = self.Z1 + self.history['z2'][epoch, :] = self.Z2 + self.history['z3'][epoch, :] = self.Z3 + self.history['sigma1'][epoch] = sigma1 + self.history['sigma2'][epoch] = sigma2 + self.history['sigma3'][epoch] = sigma3 diff --git a/tests/tsom/tsom3_weighted/tsom3_weighted_ishida.py b/tests/tsom/tsom3_weighted/tsom3_weighted_ishida.py new file mode 100644 index 0000000..1c1350f --- /dev/null +++ b/tests/tsom/tsom3_weighted/tsom3_weighted_ishida.py @@ -0,0 +1,244 @@ +import numpy as np +from libs.tools.create_zeta import create_zeta +from scipy.spatial import distance as distance +from tqdm import tqdm + +class wTSOM3_ishida(): + def __init__(self, X, latent_dim, resolution, SIGMA_MAX, SIGMA_MIN, TAU, gamma='nonweight', init='random'): + + # 入力データXについて + if X.ndim == 3: + self.X = X.reshape((X.shape[0], X.shape[1], X.shape[2], 1)) + self.N1 = self.X.shape[0] + self.N2 = self.X.shape[1] + self.N3 = self.X.shape[2] + self.observed_dim = self.X.shape[3] + elif X.ndim == 4: + self.X = X + self.N1 = self.X.shape[0] + self.N2 = self.X.shape[1] + self.N3 = self.X.shape[2] + self.observed_dim = self.X.shape[3] + else: + raise ValueError("invalid X: {}\nX must be 3d or 4d ndarray".format(X)) + + # 最大近傍半径(SIGMAX)の設定 + if type(SIGMA_MAX) is float: + self.SIGMA1_MAX = SIGMA_MAX + self.SIGMA2_MAX = SIGMA_MAX + self.SIGMA3_MAX = SIGMA_MAX + elif isinstance(SIGMA_MAX, (list, tuple)): + self.SIGMA1_MAX = SIGMA_MAX[0] + self.SIGMA2_MAX = SIGMA_MAX[1] + self.SIGMA3_MAX = SIGMA_MAX[2] + else: + raise ValueError("invalid SIGMA_MAX: {}".format(SIGMA_MAX)) + + # 最小近傍半径(SIGMA_MIN)の設定 + if type(SIGMA_MIN) is float: + self.SIGMA1_MIN = SIGMA_MIN + self.SIGMA2_MIN = SIGMA_MIN + self.SIGMA3_MIN = SIGMA_MIN + elif isinstance(SIGMA_MIN, (list, tuple)): + self.SIGMA1_MIN = SIGMA_MIN[0] + self.SIGMA2_MIN = SIGMA_MIN[1] + self.SIGMA3_MIN = SIGMA_MIN[2] + else: + raise ValueError("invalid SIGMA_MIN: {}".format(SIGMA_MIN)) + + # 時定数(TAU)の設定 + if type(TAU) is int: + self.TAU1 = TAU + self.TAU2 = TAU + self.TAU3 = TAU + elif isinstance(TAU, (list, tuple)): + self.TAU1 = TAU[0] + self.TAU2 = TAU[1] + self.TAU3 = TAU[2] + else: + raise ValueError("invalid TAU: {}".format(TAU)) + + # resolutionの設定 + if type(resolution) is int: + resolution1 = resolution + resolution2 = resolution + resolution3 = resolution + elif isinstance(resolution, (list, tuple)): + resolution1 = resolution[0] + resolution2 = resolution[1] + resolution3 = resolution[2] + else: + raise ValueError("invalid resolution: {}".format(resolution)) + + # 潜在空間の設定 + if type(latent_dim) is int: # latent_dimがintであればどちらのモードも潜在空間の次元は同じ + self.latent_dim1 = latent_dim + self.latent_dim2 = latent_dim + self.latent_dim3 = latent_dim + + elif isinstance(latent_dim, (list, tuple)): + self.latent_dim1 = latent_dim[0] + self.latent_dim2 = latent_dim[1] + self.latent_dim3 = latent_dim[2] + else: + raise ValueError("invalid latent_dim: {}".format(latent_dim)) + self.Zeta1 = create_zeta(-1.0, 1.0, latent_dim=self.latent_dim1, resolution=resolution1, include_min_max=True) + self.Zeta2 = create_zeta(-1.0, 1.0, latent_dim=self.latent_dim2, resolution=resolution2, include_min_max=True) + self.Zeta3 = create_zeta(-1.0, 1.0, latent_dim=self.latent_dim3, resolution=resolution3, include_min_max=True) + + # K1とK2は潜在空間の設定が終わった後がいいよね + self.K1 = self.Zeta1.shape[0] + self.K2 = self.Zeta2.shape[0] + self.K3 = self.Zeta3.shape[0] + + # 勝者ノードの初期化 + self.Z1 = None + self.Z2 = None + self.Z3 = None + if isinstance(init, str) and init in 'random': + self.Z1 = np.random.rand(self.N1, self.latent_dim1) * 2.0 - 1.0 + self.Z2 = np.random.rand(self.N2, self.latent_dim2) * 2.0 - 1.0 + self.Z3 = np.random.rand(self.N3, self.latent_dim3) * 2.0 - 1.0 + elif isinstance(init, (tuple, list)) and len(init) == 3: + if isinstance(init[0], np.ndarray) and init[0].shape == (self.N1, self.latent_dim1): + self.Z1 = init[0].copy() + else: + raise ValueError("invalid inits[0]: {}".format(init)) + if isinstance(init[1], np.ndarray) and init[1].shape == (self.N2, self.latent_dim2): + self.Z2 = init[1].copy() + else: + raise ValueError("invalid inits[1]: {}".format(init)) + if isinstance(init[2], np.ndarray) and init[2].shape == (self.N3, self.latent_dim3): + self.Z3 = init[2].copy() + else: + raise ValueError("invalid inits[2]: {}".format(init)) + else: + raise ValueError("invalid inits: {}".format(init)) + + # 重みテンソルの初期化 + self.gamma = None + if isinstance(gamma, str) and gamma in 'nonweight': + self.gamma = np.ones((self.N1, self.N2, self.N3)) + # elif isinstance(gamma, (tuple, list)) and gamma.ndim == 3: + # self.gamma = gamma + # else: + # raise ValueError("invalid gamma: {}".format(gamma)) + else: + self.gamma = gamma + + self.history = {} + + # デバッグ用 + # デバッグ用 + self.H1 = None + self.H2 = None + self.H3 = None + + self.G1 = None + self.G2 = None + self.G3 = None + + self.k_star1 = None + self.k_star2 = None + self.k_star3 = None + + def fit(self, nb_epoch=200): + self.history['y'] = np.zeros((nb_epoch, self.K1, self.K2, self.K3, self.observed_dim)) + self.history['z1'] = np.zeros((nb_epoch, self.N1, self.latent_dim1)) + self.history['z2'] = np.zeros((nb_epoch, self.N2, self.latent_dim2)) + self.history['z3'] = np.zeros((nb_epoch, self.N3, self.latent_dim3)) + self.history['sigma1'] = np.zeros(nb_epoch) + self.history['sigma2'] = np.zeros(nb_epoch) + self.history['sigma3'] = np.zeros(nb_epoch) + + for epoch in tqdm(np.arange(nb_epoch)): + #近傍関数の設計 + sigma1 = max(self.SIGMA1_MIN, self.SIGMA1_MAX * (1 - (epoch / self.TAU1))) + Dist1 = distance.cdist(self.Zeta1, self.Z1, metric="sqeuclidean") + H1 = np.exp(-Dist1 / (2 * pow(sigma1, 2)))#K1*N1 + self.H1 = np.exp(-Dist1 / (2 * pow(sigma1, 2))) + + sigma2 = max(self.SIGMA2_MIN, self.SIGMA2_MAX * (1 - (epoch / self.TAU2))) + Dist2 = distance.cdist(self.Zeta2, self.Z2, metric="sqeuclidean") + H2 = np.exp(-Dist2 / (2 * pow(sigma2, 2)))#K2*N2 + self.H2 = np.exp(-Dist2 / (2 * pow(sigma2, 2))) + + sigma3 = max(self.SIGMA3_MIN, self.SIGMA3_MAX * (1 - (epoch / self.TAU3))) + Dist3 = distance.cdist(self.Zeta3, self.Z3, metric="sqeuclidean") + H3 = np.exp(-Dist3 / (2 * pow(sigma3, 2)))#K3*N3 + self.H3 = np.exp(-Dist3 / (2 * pow(sigma3, 2))) + + #写像の更新 + gammaH2H3=self.gamma[np.newaxis, np.newaxis, :, :, :] * H2[:, np.newaxis, np.newaxis, :, np.newaxis + ] * H3[np.newaxis, :, np.newaxis, np.newaxis, :] # K2*K3*N1*N2*N3 + gammaH1H3=self.gamma[np.newaxis, np.newaxis, :, :, :] * H1[:, np.newaxis, :, np.newaxis, np.newaxis + ] * H3[np.newaxis, :, np.newaxis, np.newaxis, :] # K1*K3*N1*N2*N3 + gammaH1H2=self.gamma[np.newaxis, np.newaxis, :, :, :] * H1[:, np.newaxis, :, np.newaxis, np.newaxis + ] * H2[np.newaxis, :, np.newaxis, :, np.newaxis] # K1*K2*N1*N2*N3 + + G1=np.sum(gammaH2H3,axis=(3,4))#K2*K3*N1 + self.G1 = G1 + G2 = np.sum(gammaH1H3,axis=(2,4))#K1*K3*N2 + self.G2 = G2 + G3 = np.sum(gammaH1H2,axis=(2,3))#K1*K2*N3 + self.G3 = G3 + + #一次モデルの作成 + U1 = np.sum(H2[:, np.newaxis, np.newaxis, :, np.newaxis, np.newaxis] + * H3[np.newaxis, :, np.newaxis, np.newaxis, :, np.newaxis] + * (self.gamma[:, :, :, np.newaxis] * self.X)[np.newaxis, np.newaxis, :, :, :, :], axis=(3, 4)) / G1[:, :, :, np.newaxis]#K2*K3*N1 + self.U1 = U1 + U2 = np.sum(H1[:, np.newaxis, :, np.newaxis, np.newaxis, np.newaxis] + * H3[np.newaxis, :, np.newaxis, np.newaxis, :, np.newaxis] + * (self.gamma[:, :, :, np.newaxis] * self.X)[np.newaxis, np.newaxis, :, :, :, :], axis=(2, 4)) / G2[:, :, :, np.newaxis] # K1*K3*N2 + self.U2 = U2 + U3 = np.sum(H1[:, np.newaxis, :, np.newaxis, np.newaxis, np.newaxis] + * H2[np.newaxis, :, np.newaxis, :, np.newaxis, np.newaxis] + * (self.gamma[:, :, :, np.newaxis] * self.X)[np.newaxis, np.newaxis, :, :, :, :], axis=(2, 3)) / G3[:, :, :, np.newaxis] # K1*K2*N3 + self.U3 = U3 + + #2次モデルの更新 + self.Y = np.sum(H1[:, np.newaxis, np.newaxis, :, np.newaxis]*(G1[:,:,:,np.newaxis]*U1)[np.newaxis,:,:,:,:],axis=3)\ + /np.sum(H1[:,np.newaxis,np.newaxis,:,np.newaxis]*G1[np.newaxis,:,:,:,np.newaxis],axis=3) + + #勝者決定 + compDist1 = np.square(U1[np.newaxis, :, :, :, :] - self.Y[:, :, :, np.newaxis, :])#K1*K2*K3*N1*D + # k_star1 = np.argmin(np.sum(compDist1, axis=(1, 2, 4)), axis=0) # original + k_star1 = np.argmin(np.sum(G1[None, :, :, :, None] * compDist1, axis=(1, 2, 4)), axis=0) + self.Z1 = self.Zeta1[k_star1, :] + + compDist2 = np.square(U2[:, np.newaxis, :, :, :] - self.Y[:, :, :, np.newaxis, :]) # K1*K2*K3*N2*D + # k_star2 = np.argmin(np.sum(compDist2, axis=(0, 2, 4)), axis=0) # original + k_star2 = np.argmin(np.sum(G2[:, None, :, :, None] * compDist2, axis=(0, 2, 4)), axis=0) + self.Z2 = self.Zeta2[k_star2, :] + + compDist3 = np.square(U3[:, :, np.newaxis, :, :] - self.Y[:, :, :, np.newaxis, :]) # K1*K2*K3*N3*D + # k_star3 = np.argmin(np.sum(compDist3, axis=(0, 1, 4)), axis=0) # original + k_star3 = np.argmin(np.sum(G3[:, :, None, :, None] * compDist3, axis=(0, 1, 4)), axis=0) + self.Z3 = self.Zeta3[k_star3, :] + + self.k_star1 = k_star1 + self.k_star2 = k_star2 + self.k_star3 = k_star3 + + self.history['y'][epoch, :, :, :, :] = self.Y + self.history['z1'][epoch, :] = self.Z1 + self.history['z2'][epoch, :] = self.Z2 + self.history['z3'][epoch, :] = self.Z3 + self.history['sigma1'][epoch] = sigma1 + self.history['sigma2'][epoch] = sigma2 + self.history['sigma3'][epoch] = sigma3 + + +# if __name__ == "__main__": +# N1 = 11 +# N2 = 12 +# N3 = 13 +# D = 1 +# X = np.random.rand(N1, N2, N3, D) +# #print(X.shape) +# +# +# tsom3=wTSOM3_ishida(X=X,latent_dim=2,resolution=(10,12,13),SIGMA_MAX=1.0,SIGMA_MIN=0.1,TAU=25,gamma="nonweight") +# +# tsom3.fit(nb_epoch=100) diff --git a/tests/tsom/tsom3_weighted/wtsom3_Y.npy b/tests/tsom/tsom3_weighted/wtsom3_Y.npy new file mode 100644 index 0000000..12eed9a Binary files /dev/null and b/tests/tsom/tsom3_weighted/wtsom3_Y.npy differ diff --git a/tests/tsom/tsom3_weighted/wtsom3_k1.npy b/tests/tsom/tsom3_weighted/wtsom3_k1.npy new file mode 100644 index 0000000..c11460f Binary files /dev/null and b/tests/tsom/tsom3_weighted/wtsom3_k1.npy differ diff --git a/tests/tsom/tsom3_weighted/wtsom3_k2.npy b/tests/tsom/tsom3_weighted/wtsom3_k2.npy new file mode 100644 index 0000000..03a0108 Binary files /dev/null and b/tests/tsom/tsom3_weighted/wtsom3_k2.npy differ diff --git a/tests/tsom/tsom3_weighted/wtsom3_k3.npy b/tests/tsom/tsom3_weighted/wtsom3_k3.npy new file mode 100644 index 0000000..113176b Binary files /dev/null and b/tests/tsom/tsom3_weighted/wtsom3_k3.npy differ