python-ldl 0.0.2__py3-none-any.whl → 0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,18 +9,22 @@ from ._ensemble import DF_LDL, AdaBoostLDL
9
9
  from ._ldlf import LDLF
10
10
  from ._ldl_scl import LDL_SCL
11
11
  from ._ldl_lrr import LDL_LRR
12
+ from ._ldl_dpa import LDL_DPA
12
13
 
13
14
  from ._ssg_ldl import SSG_LDL
14
15
 
15
16
  from ._label_enhancement import FCM, KM, LP, ML, GLLE, LEVI, LIBLE
16
17
 
18
+ from ._ldl_da import LDL_DA
19
+
17
20
 
18
21
  __all__ = ["SA_BFGS", "SA_IIS", "AA_KNN", "AA_BP", "PT_Bayes", "PT_SVM",
19
22
  "CPNN", "BCPNN", "ACPNN", "LDSVR",
20
- "LDLF", "LDL_SCL", "LDL_LRR", "CAD", "QFD2", "CJS",
23
+ "LDLF", "LDL_SCL", "LDL_LRR", "LDL_DPA", "CAD", "QFD2", "CJS",
21
24
  "DF_LDL", "AdaBoostLDL",
22
25
  "LDL4C", "LDL_HR", "LDLM",
23
26
  "IncomLDL",
24
27
  "SSG_LDL",
25
28
  "FCM", "KM", "LP", "ML", "GLLE",
26
- "LEVI", 'LIBLE']
29
+ "LEVI", "LIBLE",
30
+ "LDL_DA"]
@@ -1,128 +1,74 @@
1
1
  import numpy as np
2
2
  from sklearn.neighbors import NearestNeighbors
3
- from sklearn.preprocessing import OneHotEncoder
4
3
 
5
4
  import keras
6
5
  import tensorflow as tf
7
6
  from keras import backend as K
8
7
 
9
- from pyldl.algorithms.base import BaseLDL, BaseDeepLDL
8
+ from pyldl.algorithms.base import BaseLDL, BaseDeepLDL, BaseGD, BaseAdam
10
9
 
11
10
 
12
11
  class AA_KNN(BaseLDL):
13
12
 
14
- def __init__(self,
15
- k=5,
16
- random_state=None):
17
-
18
- super().__init__(random_state)
19
-
20
- self.k = k
21
- self._model = NearestNeighbors(n_neighbors=self.k)
22
-
23
- def fit(self, X, y):
13
+ def fit(self, X, y, k=5):
24
14
  super().fit(X, y)
25
- self._model.fit(self._X)
15
+ self._model = NearestNeighbors(n_neighbors=k).fit(self._X)
16
+ return self
26
17
 
27
18
  def predict(self, X):
28
19
  _, inds = self._model.kneighbors(X)
29
20
  return np.average(self._y[inds], axis=1)
30
21
 
31
22
 
32
- class AA_BP(BaseDeepLDL):
23
+ class AA_BP(BaseGD, BaseDeepLDL):
24
+ pass
33
25
 
34
- def __init__(self, n_hidden=None, n_latent=None, random_state=None):
35
- super().__init__(n_hidden, n_latent, random_state)
36
26
 
37
- @tf.function
38
- def _loss_function(self, y, y_pred):
39
- return tf.math.reduce_mean(keras.losses.mean_squared_error(y, y_pred))
40
-
41
- def fit(self, X, y, learning_rate=5e-3, epochs=3000, batch_size=32,
42
- model=None, activation='sigmoid', optimizer='SGD', X_test=None, y_test=None):
43
- super().fit(X, y)
44
-
45
- self._batch_size = batch_size
46
-
47
- if self._n_hidden is None:
48
- self._n_hidden = self._n_features * 3 // 2
49
-
50
- self._model = model
51
- if self._model is None:
52
- self._model = keras.Sequential([keras.layers.InputLayer(input_shape=(self._n_features,)),
53
- keras.layers.Dense(self._n_hidden, activation=activation),
54
- keras.layers.Dense(self._n_outputs, activation='softmax')])
55
- self._optimizer = eval(f'keras.optimizers.{optimizer}({learning_rate})')
56
- data = tf.data.Dataset.from_tensor_slices((self._X, self._y)).batch(self._batch_size)
57
-
58
- for _ in range(epochs):
59
- total_loss = 0.
60
- for batch in data:
61
- with tf.GradientTape() as tape:
62
- y_pred = self._model(batch[0])
63
- loss = self._loss_function(batch[1], y_pred)
64
- gradients = tape.gradient(loss, self.trainable_variables)
65
- self._optimizer.apply_gradients(zip(gradients, self.trainable_variables))
66
- total_loss += loss
67
-
68
- def predict(self, X):
69
- return self._model(X)
70
-
71
-
72
- class CAD(AA_BP):
27
+ class CAD(BaseAdam, BaseDeepLDL):
73
28
 
29
+ @staticmethod
74
30
  @tf.function
75
- def _loss_function(self, y, y_pred):
31
+ def loss_function(y, y_pred):
76
32
  def _CAD(y, y_pred):
77
33
  return tf.reduce_mean(tf.abs(
78
34
  tf.cumsum(y, axis=1) - tf.cumsum(y_pred, axis=1)
79
35
  ), axis=1)
80
36
  return tf.math.reduce_sum(
81
37
  tf.map_fn(lambda i: _CAD(y[:, :i], y_pred[:, :i]),
82
- tf.range(1, self._n_outputs + 1),
38
+ tf.range(1, y.shape[1] + 1),
83
39
  fn_output_signature=tf.float32)
84
40
  )
85
41
 
86
- def fit(self, X, y, learning_rate=1e-4, epochs=500,
87
- activation='relu', optimizer='Adam'):
88
- return super().fit(X, y, learning_rate, epochs, activation, optimizer)
89
-
90
42
 
91
- class QFD2(AA_BP):
43
+ class QFD2(BaseAdam, BaseDeepLDL):
92
44
 
45
+ @staticmethod
93
46
  @tf.function
94
- def _loss_function(self, y, y_pred):
47
+ def _loss_function(y, y_pred):
95
48
  Q = y - y_pred
96
- j = tf.reshape(tf.range(self._n_outputs), [self._n_outputs, 1])
97
- k = tf.reshape(tf.range(self._n_outputs), [1, self._n_outputs])
98
- A = tf.cast(1 - tf.abs(j - k) / (self._n_outputs - 1), dtype=tf.float32)
49
+ j = tf.reshape(tf.range(y.shape[1]), [y.shape[1], 1])
50
+ k = tf.reshape(tf.range(y.shape[1]), [1, y.shape[1]])
51
+ A = tf.cast(1 - tf.abs(j - k) / (y.shape[1] - 1), dtype=tf.float32)
99
52
  return tf.math.reduce_mean(
100
53
  tf.linalg.diag_part(tf.matmul(tf.matmul(Q, A), tf.transpose(Q)))
101
54
  )
102
55
 
103
- def fit(self, X, y, learning_rate=1e-4, epochs=500,
104
- activation='relu', optimizer='Adam'):
105
- return super().fit(X, y, learning_rate, epochs, activation, optimizer)
106
56
 
57
+ class CJS(BaseAdam, BaseDeepLDL):
107
58
 
108
- class CJS(AA_BP):
109
-
59
+ @staticmethod
110
60
  @tf.function
111
- def _loss_function(self, y, y_pred):
61
+ def loss_function(y, y_pred):
112
62
  def _CJS(y, y_pred):
113
63
  m = 0.5 * (y + y_pred)
114
64
  js = 0.5 * (keras.losses.kl_divergence(y, m) + keras.losses.kl_divergence(y_pred, m))
115
65
  return tf.reduce_mean(js)
116
66
  return tf.math.reduce_sum(
117
67
  tf.map_fn(lambda i: _CJS(y[:, :i], y_pred[:, :i]),
118
- tf.range(1, self._n_outputs + 1),
68
+ tf.range(1, y.shape[1] + 1),
119
69
  fn_output_signature=tf.float32)
120
70
  )
121
71
 
122
- def fit(self, X, y, learning_rate=1e-4, epochs=500,
123
- activation='relu', optimizer='Adam'):
124
- return super().fit(X, y, learning_rate, epochs, activation, optimizer)
125
-
126
72
 
127
73
  class RProp(keras.optimizers.Optimizer):
128
74
 
@@ -134,6 +80,10 @@ class RProp(keras.optimizers.Optimizer):
134
80
  self.min_alpha = K.variable(min_alpha, name='min_alpha')
135
81
  self.max_alpha = K.variable(max_alpha, name='max_alpha')
136
82
 
83
+ def apply_gradients(self, grads_and_vars):
84
+ grads, trainable_variables = zip(*grads_and_vars)
85
+ self.get_updates(trainable_variables, grads)
86
+
137
87
  def get_updates(self, params, gradients):
138
88
  grads = gradients
139
89
  shapes = [K.int_shape(p) for p in params]
@@ -183,12 +133,12 @@ class RProp(keras.optimizers.Optimizer):
183
133
  return dict(list(base_config.items()) + list(config.items()))
184
134
 
185
135
 
186
- class CPNN(BaseDeepLDL):
136
+ class CPNN(BaseGD, BaseDeepLDL):
187
137
 
188
138
  def _not_proper_mode(self):
189
139
  raise ValueError("The argument 'mode' can only be 'none', 'binary' or 'augment'.")
190
140
 
191
- def __init__(self, mode='none', v=5, n_hidden=None, n_latent=None, random_state=None):
141
+ def __init__(self, mode='none', v=5, n_hidden=64, n_latent=None, random_state=None):
192
142
  super().__init__(n_hidden, n_latent, random_state)
193
143
  if mode == 'none' or mode == 'binary' or mode == 'augment':
194
144
  self._mode = mode
@@ -196,37 +146,34 @@ class CPNN(BaseDeepLDL):
196
146
  self._not_proper_mode()
197
147
  self._v = v
198
148
 
199
- def fit(self, X, y, learning_rate=5e-3, epochs=3000):
200
- super().fit(X, y)
149
+ @staticmethod
150
+ @tf.function
151
+ def loss_function(y, y_pred):
152
+ return tf.math.reduce_mean(keras.losses.kl_divergence(y, y_pred))
201
153
 
202
- self._optimizer = RProp(init_alpha=learning_rate)
154
+ def _get_default_model(self):
155
+ input_shape = (self._n_features + (1 if self._mode == 'none' else self._n_outputs),)
156
+ return keras.Sequential([keras.layers.InputLayer(input_shape=input_shape),
157
+ keras.layers.Dense(self._n_hidden, activation='sigmoid'),
158
+ keras.layers.Dense(1, activation=None)])
203
159
 
204
- if self._n_hidden is None:
205
- self._n_hidden = self._n_features * 3 // 2
160
+ def _get_default_optimizer(self):
161
+ return RProp()
206
162
 
163
+ def _before_train(self):
207
164
  if self._mode == 'augment':
165
+ n = self._X.shape[0]
208
166
  one_hot = tf.one_hot(tf.math.argmax(self._y, axis=1), self.n_outputs)
209
167
  self._X = tf.repeat(self._X, self._v, axis=0)
210
168
  self._y = tf.repeat(self._y, self._v, axis=0)
211
169
  one_hot = tf.repeat(one_hot, self._v, axis=0)
212
- v = tf.reshape(tf.tile([1 / (i + 1) for i in range(self._v)], [X.shape[0]]), (-1, 1))
170
+ v = tf.reshape(tf.tile([1 / (i + 1) for i in range(self._v)], [n]), (-1, 1))
213
171
  self._y += self._y * one_hot * v
214
172
 
215
- input_shape = (self._n_features + (1 if self._mode == 'none' else self._n_outputs),)
216
- self._model = keras.Sequential([keras.layers.InputLayer(input_shape=input_shape),
217
- keras.layers.Dense(self._n_hidden, activation='sigmoid'),
218
- keras.layers.Dense(1, activation=None)])
219
-
220
- for _ in range(epochs):
221
- with tf.GradientTape() as tape:
222
- loss = self._loss(self._X, self._y)
223
- gradients = tape.gradient(loss, self.trainable_variables)
224
- self._optimizer.get_updates(self.trainable_variables, gradients)
225
-
226
173
  def _make_inputs(self, X):
227
174
  temp = tf.reshape(tf.tile([i + 1 for i in range(self._n_outputs)], [X.shape[0]]), (-1, 1))
228
175
  if self._mode != 'none':
229
- temp = OneHotEncoder(sparse=False).fit_transform(temp)
176
+ temp = tf.one_hot(tf.reshape(temp, (-1, )) - 1, depth=self._n_outputs)
230
177
  return tf.concat([tf.cast(tf.repeat(X, self._n_outputs, axis=0), dtype=tf.float32),
231
178
  tf.cast(temp, dtype=tf.float32)],
232
179
  axis=1)
@@ -238,12 +185,6 @@ class CPNN(BaseDeepLDL):
238
185
  b = tf.reshape(-tf.math.log(tf.math.reduce_sum(tf.math.exp(results), axis=1)), (-1, 1))
239
186
  return tf.math.exp(b + results)
240
187
 
241
- def _loss(self, X, y):
242
- return tf.math.reduce_mean(keras.losses.kl_divergence(y, self._call(X)))
243
-
244
- def predict(self, X):
245
- return self._call(X)
246
-
247
188
 
248
189
  class BCPNN(CPNN):
249
190
 
@@ -1,114 +1,89 @@
1
1
  import keras
2
2
  import tensorflow as tf
3
3
 
4
- from pyldl.metrics import score
5
- from pyldl.algorithms.base import BaseDeepLDL, BaseDeepLDLClassifier, DeepBFGS
4
+ from pyldl.algorithms.base import BaseDeepLDLClassifier, BaseGD, BaseBFGS
6
5
 
7
6
 
8
- class LDL4C(BaseDeepLDLClassifier, DeepBFGS):
9
-
10
- def __init__(self, n_hidden=None, n_latent=None, random_state=None):
11
- super().__init__(n_hidden, n_latent, random_state)
7
+ class LDL4C(BaseBFGS, BaseDeepLDLClassifier):
8
+ """LDL4C is proposed in paper Classification with Label Distribution Learning.
9
+ """
12
10
 
13
11
  @tf.function
14
- def _loss(self, X, y):
15
- y_pred = self._model(X)
12
+ def _loss(self, params_1d):
13
+ y_pred = keras.activations.softmax(self._X @ self._params2model(params_1d)[0])
16
14
  top2 = tf.gather(y_pred, self._top2, axis=1, batch_dims=1)
17
15
  margin = tf.reduce_sum(tf.maximum(0., 1. - (top2[:, 0] - top2[:, 1]) / self._rho))
18
- mae = keras.losses.mean_absolute_error(y, y_pred)
19
- return tf.reduce_sum(self._entropy * mae) + self._alpha * margin + self._beta * BaseDeepLDL._l2_reg(self._model)
20
-
21
- def fit(self, X, y, max_iterations=50, alpha=1e-2, beta=1e-6, rho=1e-2):
22
- super().fit(X, y)
23
-
24
- self._alpha = alpha
25
- self._beta = beta
26
- self._rho = rho
16
+ mae = keras.losses.mean_absolute_error(self._y, y_pred)
17
+ return tf.reduce_sum(self._entropy * mae) + self._alpha * margin + self._beta * self._l2_reg(self._model)
27
18
 
19
+ def _before_train(self):
28
20
  self._top2 = tf.math.top_k(self._y, k=2)[1]
29
21
  self._entropy = tf.cast(-tf.reduce_sum(self._y * tf.math.log(self._y) + 1e-7, axis=1), dtype=tf.float32)
30
22
 
31
- self._model = keras.Sequential(
32
- [keras.layers.InputLayer(input_shape=self._n_features),
33
- keras.layers.Dense(self._n_outputs, activation="softmax")])
34
-
35
- self._optimize_bfgs(self._model, self._loss, self._X, self._y, max_iterations=max_iterations)
36
-
23
+ def fit(self, X, y, alpha=1e-2, beta=1e-6, rho=1e-2, **kwargs):
24
+ self._alpha = alpha
25
+ self._beta = beta
26
+ self._rho = rho
27
+ return super().fit(X, y, **kwargs)
37
28
 
38
- class LDL_HR(BaseDeepLDLClassifier, DeepBFGS):
39
29
 
40
- def __init__(self, n_hidden=None, n_latent=None, random_state=None):
41
- super().__init__(n_hidden, n_latent, random_state)
30
+ class LDL_HR(BaseBFGS, BaseDeepLDLClassifier):
31
+ """LDL-HR is proposed in paper Learn the Highest Label and Rest Label Description Degrees.
32
+ """
42
33
 
43
34
  @tf.function
44
- def _loss(self, X, y):
45
- y_pred = self._model(X)
46
-
35
+ def _loss(self, params_1d):
36
+ y_pred = keras.activations.softmax(self._X @ self._params2model(params_1d)[0])
37
+
47
38
  highest = tf.gather(y_pred, self._highest, axis=1, batch_dims=1)
48
39
  rest = tf.gather(y_pred, self._rest, axis=1, batch_dims=1)
49
40
  margin = tf.reduce_sum(tf.maximum(0., 1. - (highest - rest) / self._rho))
50
41
 
51
- real_rest = tf.gather(y, self._rest, axis=1, batch_dims=1)
42
+ real_rest = tf.gather(self._y, self._rest, axis=1, batch_dims=1)
52
43
  rest_mae = tf.reduce_sum(keras.losses.mean_absolute_error(real_rest, rest))
53
44
 
54
45
  mae = tf.reduce_sum(keras.losses.mean_absolute_error(self._l, y_pred))
55
46
 
56
- return mae + self._alpha * margin + self._beta * rest_mae + self._gamma * BaseDeepLDL._l2_reg(self._model)
57
-
58
- def fit(self, X, y, max_iterations=50, alpha=1e-2, beta=1e-2, gamma=1e-6, rho=1e-2):
59
- super().fit(X, y)
60
-
61
- self._alpha = alpha
62
- self._beta = beta
63
- self._gamma = gamma
64
- self._rho = rho
47
+ return mae + self._alpha * margin + self._beta * rest_mae + self._gamma * self._l2_reg(self._model)
65
48
 
49
+ def _before_train(self):
66
50
  temp = tf.math.top_k(self._y, k=self._n_outputs)[1]
67
51
  self._highest = temp[:, 0:1]
68
52
  self._rest = temp[:, 1:]
69
-
70
53
  self._l = tf.one_hot(tf.reshape(self._highest, -1), self._n_outputs)
71
54
 
72
- self._model = keras.Sequential(
73
- [keras.layers.InputLayer(input_shape=self._n_features),
74
- keras.layers.Dense(self._n_outputs, activation="softmax")])
75
-
76
- self._optimize_bfgs(self._model, self._loss, self._X, self._y, max_iterations=max_iterations)
77
-
55
+ def fit(self, X, y, alpha=1e-2, beta=1e-2, gamma=1e-6, rho=1e-2, **kwargs):
56
+ self._alpha = alpha
57
+ self._beta = beta
58
+ self._gamma = gamma
59
+ self._rho = rho
60
+ return super().fit(X, y, **kwargs)
78
61
 
79
- class LDLM(BaseDeepLDLClassifier):
80
62
 
81
- def __init__(self, n_hidden=None, n_latent=None, random_state=None):
82
- super().__init__(n_hidden, n_latent, random_state)
63
+ class LDLM(BaseGD, BaseDeepLDLClassifier):
64
+ """LDLM is proposed in paper Label Distribution Learning Machine.
65
+ """
83
66
 
84
67
  @tf.function
85
- def _loss(self, X, y):
68
+ def _loss(self, X, y, start, end):
86
69
  y_pred = self._model(X)
87
70
 
88
71
  pred_margin = tf.reduce_sum(tf.clip_by_value(
89
- tf.reduce_sum(tf.abs(self._l - y_pred), axis=1) - self._rho,
72
+ tf.reduce_sum(tf.abs(self._l[start:end] - y_pred), axis=1) - self._rho,
90
73
  0., float('inf')))
91
-
92
- highest = tf.gather(y_pred, self._highest, axis=1, batch_dims=1)
93
- rest = tf.gather(y_pred, self._rest, axis=1, batch_dims=1)
74
+
75
+ highest = tf.gather(y_pred, self._highest[start:end], axis=1, batch_dims=1)
76
+ rest = tf.gather(y_pred, self._rest[start:end], axis=1, batch_dims=1)
94
77
  label_margin = tf.reduce_sum(tf.maximum(0., 1. - (highest - rest) / self._rho))
95
78
 
96
79
  second_margin = tf.reduce_sum(tf.clip_by_value(
97
- tf.reduce_sum(tf.abs((y - y_pred) * self._neg_l), axis=1) - self._second_margin,
80
+ tf.reduce_sum(tf.abs((y - y_pred) * self._neg_l[start:end]), axis=1) - self._second_margin[start:end],
98
81
  0., float('inf')))
99
82
 
100
83
  return pred_margin + self._alpha * label_margin + \
101
- self._beta * second_margin + self._gamma * BaseDeepLDL._l2_reg(self._model)
102
-
103
- def fit(self, X, y, learning_rate=5e-4, epochs=1000,
104
- alpha=1e-2, beta=1e-2, gamma=1e-6, rho=1e-2):
105
- super().fit(X, y)
106
-
107
- self._alpha = alpha
108
- self._beta = beta
109
- self._gamma = gamma
110
- self._rho = rho
84
+ self._beta * second_margin + self._gamma * self._l2_reg(self._model)
111
85
 
86
+ def _before_train(self):
112
87
  temp = tf.math.top_k(self._y, k=self._n_outputs)[1]
113
88
  self._highest = temp[:, 0:1]
114
89
  self._rest = temp[:, 1:]
@@ -119,15 +94,12 @@ class LDLM(BaseDeepLDLClassifier):
119
94
  self._l = tf.one_hot(tf.reshape(self._highest, -1), self._n_outputs)
120
95
  self._neg_l = tf.where(tf.equal(self._l, 0.), 1., 0.)
121
96
 
122
- self._model = keras.Sequential(
123
- [keras.layers.InputLayer(input_shape=self._n_features),
124
- keras.layers.Dense(self._n_outputs, activation="softmax")])
125
-
126
- self._optimizer = keras.optimizers.SGD(learning_rate)
127
-
128
- for _ in range(epochs):
129
- with tf.GradientTape() as tape:
130
- loss = self._loss(self._X, self._y)
97
+ def _get_default_model(self):
98
+ return self.get_2layer_model(self._n_features, self._n_outputs)
131
99
 
132
- gradients = tape.gradient(loss, self.trainable_variables)
133
- self._optimizer.apply_gradients(zip(gradients, self.trainable_variables))
100
+ def fit(self, X, y, alpha=1e-2, beta=1e-2, gamma=1e-6, rho=1e-2, **kwargs):
101
+ self._alpha = alpha
102
+ self._beta = beta
103
+ self._gamma = gamma
104
+ self._rho = rho
105
+ return super().fit(X, y, **kwargs)
@@ -1,45 +1,58 @@
1
- import keras
2
- import tensorflow as tf
3
- import tensorflow_addons as tfa
1
+ import numpy as np
4
2
 
5
- from pyldl.metrics import score
6
- from pyldl.algorithms.base import BaseDeepLDL
3
+ from qpsolvers import solve_qp
7
4
 
5
+ from pyldl.algorithms.base import BaseLDL
8
6
 
9
- class IncomLDL(BaseDeepLDL):
10
7
 
11
- def __init__(self, n_hidden=None, n_latent=None, random_state=None):
12
- super().__init__(n_hidden, n_latent, random_state)
8
+ class IncomLDL(BaseLDL):
9
+ """IncomLDL is proposed in paper Incomplete Label Distribution Learning.
10
+ """
13
11
 
14
- def _loss(self, X, y):
15
- y_pred = self._model(X)
16
- trace_norm = 0.
17
- for i in self._model.trainable_variables:
18
- trace_norm += tf.linalg.trace(tf.sqrt(tf.matmul(tf.transpose(i), i)))
19
- fro_norm = tf.reduce_sum(tf.square(self._mask * (y_pred - y)))
20
- return fro_norm / 2. + self._alpha * trace_norm
12
+ @staticmethod
13
+ def svt(A, tau):
14
+ U, S, VT = np.linalg.svd(A, full_matrices=False)
15
+ S_thresh = np.maximum(S - tau, 0)
16
+ return U @ np.diag(S_thresh) @ VT
21
17
 
22
- def fit(self, X, y, mask, alpha=2., learning_rate=5e-2, epochs=5000):
23
- super().fit(X, y)
18
+ def _update_Z(self):
19
+ A = self._X @ self._W + self._V / self._rho
20
+ tau = self._alpha / self._rho
21
+ self._Z = self.svt(A, tau)
24
22
 
25
- self._alpha = alpha
26
- self._mask = tf.where(mask, 0., 1.)
23
+ def _update_W(self):
24
+
25
+ G = -np.eye(self._n_outputs, dtype=np.float64)
26
+ h = np.zeros((self._n_outputs, 1), dtype=np.float64)
27
+ A = np.ones((1, self._n_outputs), dtype=np.float64)
28
+ b = np.array([1.], dtype=np.float64)
27
29
 
28
- self._model = keras.Sequential([keras.layers.InputLayer(input_shape=self._n_features),
29
- keras.layers.Dense(self._n_outputs, activation='softmax', use_bias=False)])
30
- self._optimizer = tfa.optimizers.ProximalAdagrad(learning_rate)
30
+ M = np.zeros_like(self._y)
31
31
 
32
- for _ in range(epochs):
33
- with tf.GradientTape() as tape:
34
- loss = self._loss(self._X, self._y)
32
+ for i in range(self._X.shape[0]):
33
+ P = np.diag((1 + self._rho) * self._mask[i] + self._rho * (1 - self._mask[i])).astype(np.float64)
34
+ ql = (self._V[i] - self._y[i] * self._mask[i] - self._rho * self._Z[i]) * self._mask[i]
35
+ qr = (self._V[i] - self._rho * self._Z[i]) * (1 - self._mask[i])
36
+ q = np.transpose(ql + qr).astype(np.float64)
37
+ M[i] = solve_qp(P, q, G, h, A, b, solver='quadprog')
35
38
 
36
- gradients = tape.gradient(loss, self.trainable_variables)
37
- self._optimizer.apply_gradients(zip(gradients, self.trainable_variables))
38
-
39
- def predict(self, X):
40
- return self._model(X).numpy()
39
+ self._W = np.linalg.pinv(np.transpose(self._X) @ self._X) @ np.transpose(self._X) @ M
40
+
41
+ def _update_V(self):
42
+ self._V = self._V + self._rho * (self._X @ self._W - self._Z)
43
+
44
+ def fit(self, X, y, mask, alpha=1e-3, rho=1., max_iterations=100):
45
+ super().fit(X, y)
46
+ self._alpha = alpha
47
+ self._rho = rho
48
+ self._mask = np.where(mask, 0., 1.)
49
+ self._W = np.ones((self._n_features, self._n_outputs))
50
+ self._Z = np.ones((self._X.shape[0], self._n_outputs))
51
+ self._V = np.ones((self._X.shape[0], self._n_outputs))
52
+ for _ in range(max_iterations):
53
+ self._update_W()
54
+ self._update_Z()
55
+ self._update_V()
41
56
 
42
- def score(self, X, y, metrics=None):
43
- if metrics is None:
44
- metrics = ["chebyshev", "clark", "canberra", "cosine", "intersection"]
45
- return score(y, self.predict(X), metrics=metrics)
57
+ def predict(self, X):
58
+ return X @ self._W