KoopmanESNModel.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import reservoirpy as rpy
  2. import torch
  3. from numpy.linalg import eigvals
  4. from reservoirpy.nodes import Reservoir, Ridge
  5. import numpy as np
  6. from dataclasses import dataclass
  7. @dataclass
  8. class KoopmanESNConfig:
  9. units: int
  10. lr: float
  11. sr: float
  12. sp: float
  13. ridge: float
  14. train_start: int
  15. train_len: int
  16. train_warmup: int
  17. predict_warmup: int
  18. predict_len: int
  19. state_dim: int
  20. class KoopmanESN:
  21. def __init__(self, A, config: KoopmanESNConfig):
  22. super().__init__()
  23. self.esn_model = None
  24. self.config = config
  25. self.A = A
  26. def W_initial(self, A):
  27. # W_res = np.random.randn(self.config.units, self.config.units)
  28. # mask = np.random.rand(self.config.units, self.config.units) > self.config.sp
  29. # W_res[mask] = 0
  30. # W_res = self.config.sr * (W_res / np.max(np.abs(eigvals(W_res)))) # 归一化谱半径
  31. # 2. 生成对齐矩阵U和V(通过SVD或随机投影)
  32. # U = np.random.randn(self.config.units, self.config.state_dim)
  33. # V = np.random.randn(self.config.units, self.config.state_dim)
  34. #
  35. # W_koop = U @ A @ V.T
  36. W_koop = A
  37. # # SVD分解
  38. # U, S, Vt = np.linalg.svd(A)
  39. #
  40. # # 生成随机投影矩阵,但与SVD的主方向对齐
  41. # P = np.random.randn(self.config.units, U.shape[0]) # (100,5)
  42. # Q = np.random.randn(self.config.units, Vt.shape[1]) # (100,5)
  43. #
  44. # U_aligned = P @ U # 随机旋转后的U
  45. # V_aligned = Q @ Vt.T # 随机旋转后的V
  46. #
  47. # # 构造耦合项
  48. # W_koop = U_aligned @ np.diag(S) @ V_aligned.T # (100,100)
  49. # 4. 耦合W_res和W_koop
  50. # lambda_coupling = 0.1
  51. # W = W_res + lambda_coupling * W_koop
  52. W = W_koop
  53. # 5. 调整谱半径
  54. current_radius = np.max(np.abs(eigvals(W)))
  55. W = (self.config.sr / current_radius) * W
  56. return W
  57. def koopmanesn_train(self, data_train):
  58. rpy.verbosity(0)
  59. rpy.set_seed(42)
  60. W = self.W_initial(self.A)
  61. Win = np.eye(self.config.units, self.config.units)
  62. reservoir = Reservoir(
  63. units=self.config.units,
  64. lr=self.config.lr,
  65. sr=self.config.sr,
  66. W=W,
  67. input_scaling=1.0,
  68. Win=Win,
  69. activation='identity'
  70. )
  71. readout = Ridge(ridge=self.config.ridge)
  72. esn_model = reservoir >> readout
  73. data_train_in = data_train[:-1, :]
  74. data_train_out = data_train[1:, :]
  75. self.esn_model = esn_model.fit(
  76. data_train_in,
  77. data_train_out,
  78. warmup=self.config.train_warmup
  79. )
  80. def predict(self, data_warm):
  81. warmup_data = self.esn_model.run(data_warm, reset=True)
  82. x = warmup_data[-1, :].reshape(1, -1)
  83. data_pre = np.empty((self.config.predict_len, self.config.state_dim))
  84. for i in range(self.config.predict_len):
  85. data_pre[i, :] = x
  86. x = self.esn_model(x)
  87. return data_pre