NeuralNetworks 0.2.0__py3-none-any.whl → 0.2.2__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.
- NeuralNetworks/Dependances/__init__.py +75 -0
- NeuralNetworks/Dependances/matplot.py +25 -0
- NeuralNetworks/Dependances/pytorch.py +111 -0
- NeuralNetworks/MLP/FourierFeatures.py +89 -0
- NeuralNetworks/MLP/Layers.py +31 -0
- NeuralNetworks/MLP/__init__.py +99 -0
- NeuralNetworks/MLP/inference.py +26 -0
- NeuralNetworks/Trainer/__init__.py +51 -0
- NeuralNetworks/Trainer/dynamic_learning_rate.py +79 -0
- NeuralNetworks/Trainer/sample_data.py +19 -0
- NeuralNetworks/Trainer/train.py +75 -0
- NeuralNetworks/UI/Learnings.py +45 -0
- NeuralNetworks/UI/Losses.py +45 -0
- NeuralNetworks/UI/__init__.py +9 -0
- NeuralNetworks/__init__.py +7 -111
- {neuralnetworks-0.2.0.dist-info → neuralnetworks-0.2.2.dist-info}/METADATA +70 -66
- neuralnetworks-0.2.2.dist-info/RECORD +24 -0
- NeuralNetworks/Dependances.py +0 -319
- NeuralNetworks/Latent.py +0 -51
- NeuralNetworks/MLP.py +0 -601
- neuralnetworks-0.2.0.dist-info/RECORD +0 -13
- {neuralnetworks-0.2.0.dist-info → neuralnetworks-0.2.2.dist-info}/WHEEL +0 -0
- {neuralnetworks-0.2.0.dist-info → neuralnetworks-0.2.2.dist-info}/licenses/LICENSE +0 -0
- {neuralnetworks-0.2.0.dist-info → neuralnetworks-0.2.2.dist-info}/top_level.txt +0 -0
NeuralNetworks/MLP.py
DELETED
|
@@ -1,601 +0,0 @@
|
|
|
1
|
-
# NeuralNetworksBeta - Multi-Layer Perceptrons avec encodage Fourier
|
|
2
|
-
# Copyright (C) 2025 Alexandre Brun
|
|
3
|
-
# This program is free software: you can redistribute it and/or modify
|
|
4
|
-
# it under the terms of the GNU General Public License as published by
|
|
5
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
-
# (at your option) any later version.
|
|
7
|
-
|
|
8
|
-
from .Dependances import *
|
|
9
|
-
|
|
10
|
-
class MLP():
|
|
11
|
-
"""
|
|
12
|
-
Multi-Layer Perceptron (MLP) avec encodage optionnel Fourier (RFF),
|
|
13
|
-
suivi automatique des pertes, visualisation et compilation PyTorch.
|
|
14
|
-
|
|
15
|
-
Cette classe fournit :
|
|
16
|
-
- Un MLP entièrement configurable (dimensions, normalisation, activation),
|
|
17
|
-
- Option d'encodage Fourier (Random Fourier Features) sur les entrées,
|
|
18
|
-
- Méthodes pour entraîner le réseau avec mini-batchs et AMP (Automatic Mixed Precision),
|
|
19
|
-
- Visualisation de l'architecture via visualtorch,
|
|
20
|
-
- Suivi et affichage de la perte d'entraînement,
|
|
21
|
-
- Accès aux poids, biais et nombre de paramètres,
|
|
22
|
-
- Compilation du modèle via `torch.compile` pour accélérer l'inférence,
|
|
23
|
-
- Méthode `__call__` permettant l'utilisation directe comme une fonction (`y = net(x)`).
|
|
24
|
-
|
|
25
|
-
Parameters
|
|
26
|
-
----------
|
|
27
|
-
layers : list[int], optional
|
|
28
|
-
Dimensions successives du réseau (entrée → couches cachées → sortie).
|
|
29
|
-
Exemple : [in_features, hidden1, hidden2, ..., out_features].
|
|
30
|
-
Default: [1, 1, 1]
|
|
31
|
-
init_lr : float, optional
|
|
32
|
-
Taux d’apprentissage initial pour l’optimiseur.
|
|
33
|
-
Default: 1e-3
|
|
34
|
-
Fourier : list[float] or None, optional
|
|
35
|
-
Liste de valeurs sigma pour appliquer plusieurs encodages RFF
|
|
36
|
-
(Random Fourier Features).
|
|
37
|
-
Si None : aucune transformation, l’entrée est passée via nn.Identity().
|
|
38
|
-
Chaque sigma ajoute un encodage distinct et double la dimension d’entrée.
|
|
39
|
-
optim : str, optional
|
|
40
|
-
Nom de l’optimiseur à utiliser (doit exister dans `optim_list`).
|
|
41
|
-
Default: "ADAM"
|
|
42
|
-
crit : str, optional
|
|
43
|
-
Fonction de perte à utiliser (doit exister dans `crit_list`).
|
|
44
|
-
Default: "MSE"
|
|
45
|
-
norm : str, optional
|
|
46
|
-
Type de normalisation / activation pour les couches cachées (ex: "Relu").
|
|
47
|
-
Default: "Relu"
|
|
48
|
-
name : str, optional
|
|
49
|
-
Nom du réseau pour identification ou affichage.
|
|
50
|
-
Default: "Net"
|
|
51
|
-
Iscompiled : bool, optional
|
|
52
|
-
Si True, compile le modèle via `torch.compile` pour accélérer l’inférence.
|
|
53
|
-
Default: True
|
|
54
|
-
|
|
55
|
-
Attributes
|
|
56
|
-
----------
|
|
57
|
-
losses : list[torch.Tensor]
|
|
58
|
-
Historique des pertes cumulées lors de l'entraînement.
|
|
59
|
-
layers : list[int]
|
|
60
|
-
Dimensions du réseau, ajustées si encodage Fourier actif.
|
|
61
|
-
encodings : list[nn.Module]
|
|
62
|
-
Liste de modules RFF GaussianEncoding ou Identity appliqués aux entrées.
|
|
63
|
-
Un module par valeur sigma dans `Fourier`.
|
|
64
|
-
norm : nn.Module
|
|
65
|
-
Normalisation ou activation utilisée dans les couches cachées.
|
|
66
|
-
crit : nn.Module
|
|
67
|
-
Fonction de perte PyTorch sur le device spécifié.
|
|
68
|
-
model : nn.Sequential
|
|
69
|
-
MLP complet construit dynamiquement.
|
|
70
|
-
optim : torch.optim.Optimizer
|
|
71
|
-
Optimiseur associé au MLP.
|
|
72
|
-
name : str
|
|
73
|
-
Nom du réseau.
|
|
74
|
-
|
|
75
|
-
Methods
|
|
76
|
-
-------
|
|
77
|
-
__init__(...)
|
|
78
|
-
Initialise le réseau, configure l’encodage, la fonction de perte et l’optimiseur.
|
|
79
|
-
__repr__()
|
|
80
|
-
Affiche un schéma visuel du MLP et ses dimensions (avec compression si nécessaire).
|
|
81
|
-
__call__(x)
|
|
82
|
-
Applique l’encodage et le MLP sur un input x, retourne la prédiction en ndarray.
|
|
83
|
-
Create_MLP(layers)
|
|
84
|
-
Construit un nn.Sequential avec les couches linéaires, activations et normalisations.
|
|
85
|
-
plot(inputs, img_array)
|
|
86
|
-
Affiche l’image originale, l’image prédite et la courbe des pertes.
|
|
87
|
-
train(inputs, outputs, num_epochs=1500, batch_size=1024)
|
|
88
|
-
Entraîne le MLP avec mini-batchs et AMP, stocke les pertes.
|
|
89
|
-
params()
|
|
90
|
-
Retourne tous les poids du MLP sous forme de liste d’ndarray.
|
|
91
|
-
neurons()
|
|
92
|
-
Retourne tous les biais du MLP sous forme de liste d’ndarray.
|
|
93
|
-
nb_params()
|
|
94
|
-
Calcule le nombre total de paramètres (poids uniquement) du réseau.
|
|
95
|
-
|
|
96
|
-
Notes
|
|
97
|
-
-----
|
|
98
|
-
- La classe supporte un entraînement sur GPU via `device`.
|
|
99
|
-
- Les fonctions de visualisation utilisent matplotlib et visualtorch.
|
|
100
|
-
- Les sorties sont compatibles avec des images normalisées entre 0 et 1.
|
|
101
|
-
- Le suivi des pertes permet d’afficher l’évolution du training loss.
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
def __init__(self, layers=[1,1,1], init_lr=1e-3, Fourier=None,
|
|
105
|
-
optim="Adam", crit="MSE", norm="Relu",
|
|
106
|
-
name="Net", Iscompiled=False):
|
|
107
|
-
"""
|
|
108
|
-
Initialise un réseau MLP flexible avec support multi-encodage Fourier,
|
|
109
|
-
choix d’activation, perte, optimiseur, et compilation optionnelle.
|
|
110
|
-
|
|
111
|
-
Parameters
|
|
112
|
-
----------
|
|
113
|
-
layers : list[int], optional
|
|
114
|
-
Dimensions successives du réseau (entrée → couches cachées → sortie).
|
|
115
|
-
Le premier élément est utilisé comme input_size avant encodage Fourier.
|
|
116
|
-
Default: [1, 1, 1]
|
|
117
|
-
init_lr : float, optional
|
|
118
|
-
Taux d’apprentissage initial pour l’optimiseur.
|
|
119
|
-
Default: 1e-3
|
|
120
|
-
Fourier : list[float] or None, optional
|
|
121
|
-
Liste de valeurs sigma pour appliquer plusieurs encodages RFF
|
|
122
|
-
(Random Fourier Features).
|
|
123
|
-
Si None : aucune transformation, l’entrée est passée via nn.Identity().
|
|
124
|
-
Chaque sigma ajoute un encodage distinct et double la dimension d’entrée.
|
|
125
|
-
optim : str, optional
|
|
126
|
-
Nom de l’optimiseur (doit appartenir à `optim_list(self, init_lr)`).
|
|
127
|
-
Default: "Adam"
|
|
128
|
-
crit : str, optional
|
|
129
|
-
Nom de la fonction de perte (doit appartenir à `crit_list`).
|
|
130
|
-
Default: "MSE"
|
|
131
|
-
norm : str, optional
|
|
132
|
-
Nom de la fonction d’activation entre couches cachées
|
|
133
|
-
(doit appartenir à `norm_list`).
|
|
134
|
-
Default: "Relu"
|
|
135
|
-
name : str, optional
|
|
136
|
-
Nom du modèle, utilisé pour l’identification.
|
|
137
|
-
Default: "Net"
|
|
138
|
-
Iscompiled : bool, optional
|
|
139
|
-
Si True, compile le MLP avec `torch.compile` pour accélérer l’inférence.
|
|
140
|
-
Si GCC est absent, la compilation est automatiquement désactivée.
|
|
141
|
-
Default: False
|
|
142
|
-
|
|
143
|
-
Attributes
|
|
144
|
-
----------
|
|
145
|
-
losses : list
|
|
146
|
-
Historique des pertes pendant l’entraînement.
|
|
147
|
-
layers : list[int]
|
|
148
|
-
Dimensions du réseau, modifiées si un encodage Fourier est appliqué
|
|
149
|
-
(l’entrée devient 2 * encoded_size).
|
|
150
|
-
encodings : list[nn.Module]
|
|
151
|
-
Liste de modules RFF GaussianEncoding ou Identity appliqués aux entrées.
|
|
152
|
-
Un module par valeur sigma dans `Fourier`.
|
|
153
|
-
norm : nn.Module
|
|
154
|
-
Fonction d’activation utilisée dans les couches cachées.
|
|
155
|
-
crit : nn.Module
|
|
156
|
-
Fonction de perte PyTorch.
|
|
157
|
-
model : nn.Sequential
|
|
158
|
-
Réseau MLP construit dynamiquement via `Create_MLP()`.
|
|
159
|
-
optim : torch.optim.Optimizer
|
|
160
|
-
Optimiseur associé au MLP.
|
|
161
|
-
name : str
|
|
162
|
-
Nom du réseau.
|
|
163
|
-
f : nn.Linear
|
|
164
|
-
Couche linéaire appliquée après le MLP, prenant en entrée
|
|
165
|
-
(nb_encodings * layers[-1]) et renvoyant layers[-1].
|
|
166
|
-
Utilisée pour agréger les sorties des différents encodages.
|
|
167
|
-
"""
|
|
168
|
-
|
|
169
|
-
super().__init__()
|
|
170
|
-
|
|
171
|
-
# --- Initialisation des attributs de base ---
|
|
172
|
-
self.losses, self.layers, self.Fourier = [], layers.copy(), Fourier
|
|
173
|
-
self.name = name
|
|
174
|
-
|
|
175
|
-
# --- Encodage Fourier (RFF) ou passthrough ---
|
|
176
|
-
self.encodings = []
|
|
177
|
-
if self.Fourier is None:
|
|
178
|
-
self.encodings.append(nn.Identity().to(device)) # passthrough si pas de Fourier
|
|
179
|
-
else:
|
|
180
|
-
for sigma_val in Fourier:
|
|
181
|
-
self.encodings.append(rff.layers.GaussianEncoding(
|
|
182
|
-
sigma=sigma_val,
|
|
183
|
-
input_size=self.layers[0],
|
|
184
|
-
encoded_size=self.layers[1]
|
|
185
|
-
).to(device))
|
|
186
|
-
self.layers[0] = self.layers[1] * 2 # chaque entrée est doublée après encodage
|
|
187
|
-
|
|
188
|
-
# --- Sélection du normalisateur / activation ---
|
|
189
|
-
self.norm = norm_list.get(norm)
|
|
190
|
-
if self.norm is None:
|
|
191
|
-
print("")
|
|
192
|
-
print (f"{norm} n'est pas reconnu")
|
|
193
|
-
self.norm = norm_list.get("Relu")
|
|
194
|
-
print (f"Retour au paramètre par défaut: 'Relu'")
|
|
195
|
-
|
|
196
|
-
# --- Fonction de perte ---
|
|
197
|
-
self.crit = crit_list.get(crit)
|
|
198
|
-
if self.crit is None:
|
|
199
|
-
print("")
|
|
200
|
-
print (f"{crit} n'est pas reconnu")
|
|
201
|
-
self.crit = crit_list.get("MSE")
|
|
202
|
-
print (f"Retour au paramètre par défaut: 'MSE'")
|
|
203
|
-
# --- Construction du MLP ---
|
|
204
|
-
self.model = self.Create_MLP(self.layers)
|
|
205
|
-
|
|
206
|
-
# --- Sélection de l’optimiseur ---
|
|
207
|
-
self.optim = optim_list(self, init_lr).get(optim)
|
|
208
|
-
if self.optim is None:
|
|
209
|
-
print("")
|
|
210
|
-
print (f"{optim} n'est pas reconnu")
|
|
211
|
-
self.optim = optim_list(self, init_lr).get("Adam")
|
|
212
|
-
print (f"Retour au paramètre par défaut: 'Adam'")
|
|
213
|
-
|
|
214
|
-
# --- Compilation optionnelle du modèle pour accélérer l’inférence ---
|
|
215
|
-
if not has_gcc():
|
|
216
|
-
Iscompiled = False
|
|
217
|
-
|
|
218
|
-
if Iscompiled:
|
|
219
|
-
self.model = torch.compile(
|
|
220
|
-
self.model,
|
|
221
|
-
mode="max-autotune",
|
|
222
|
-
fullgraph=True,
|
|
223
|
-
dynamic=True
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
# --- Envoi du modèle sur le device GPU / CPU ---
|
|
227
|
-
self.model.to(device)
|
|
228
|
-
self.f = nn.Linear(len(self.encodings) * self.layers[-1], self.layers[-1]).to(device)
|
|
229
|
-
|
|
230
|
-
def __repr__(self):
|
|
231
|
-
"""
|
|
232
|
-
Génère un aperçu visuel du MLP et affiche ses dimensions.
|
|
233
|
-
|
|
234
|
-
Cette méthode :
|
|
235
|
-
- crée une version éventuellement "compressée" des dimensions du réseau
|
|
236
|
-
(utile lorsque certaines couches dépassent 30 neurones, afin de
|
|
237
|
-
conserver une visualisation lisible),
|
|
238
|
-
- utilise `visualtorch.graph_view` pour afficher un schéma du MLP,
|
|
239
|
-
- imprime la liste réelle des dimensions du réseau,
|
|
240
|
-
- retourne une chaîne indiquant si un redimensionnement a été appliqué.
|
|
241
|
-
|
|
242
|
-
Notes
|
|
243
|
-
-----
|
|
244
|
-
- Le redimensionnement ne modifie pas le MLP réel. Il ne sert qu'à
|
|
245
|
-
améliorer la lisibilité du graphe affiché.
|
|
246
|
-
- Si Fourier Features sont activées, seule la première dimension est
|
|
247
|
-
recalculée en conséquence.
|
|
248
|
-
"""
|
|
249
|
-
|
|
250
|
-
# Si les couches sont trop grandes, on crée une version réduite
|
|
251
|
-
if max(self.layers) > 30:
|
|
252
|
-
# Mise à l’échelle proportionnelle sur une base max 32
|
|
253
|
-
fakelayers = [int(32 * layer / max(self.layers)) for layer in self.layers]
|
|
254
|
-
|
|
255
|
-
# Ajustement de la couche d’entrée si encodage Fourier
|
|
256
|
-
fakelayers[0] = (
|
|
257
|
-
int(32 * self.layers[0] / max(self.layers))
|
|
258
|
-
if self.Fourier else self.layers[0]
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
# La couche de sortie reste intacte
|
|
262
|
-
fakelayers[-1] = self.layers[-1]
|
|
263
|
-
|
|
264
|
-
else:
|
|
265
|
-
# Sinon, on garde les dimensions réelles
|
|
266
|
-
fakelayers = self.layers
|
|
267
|
-
|
|
268
|
-
# Affichage console des dimensions réelles
|
|
269
|
-
print("Tailles réelles :")
|
|
270
|
-
print(str(self.layers))
|
|
271
|
-
print("")
|
|
272
|
-
print("Tailles affichées :")
|
|
273
|
-
print(str(fakelayers))
|
|
274
|
-
|
|
275
|
-
# --- Visualisation du MLP ---
|
|
276
|
-
fig, ax = plt.subplots(figsize=(12, 6))
|
|
277
|
-
ax.axis("off")
|
|
278
|
-
|
|
279
|
-
# Utilisation de visualtorch pour tracer l’architecture
|
|
280
|
-
ax.imshow(
|
|
281
|
-
visualtorch.graph_view(
|
|
282
|
-
self.Create_MLP(fakelayers),
|
|
283
|
-
(1, fakelayers[0]),
|
|
284
|
-
ellipsize_after=34,
|
|
285
|
-
background_fill=(0, 0, 0, 0),
|
|
286
|
-
opacity=255
|
|
287
|
-
)
|
|
288
|
-
); plt.show(); return ""
|
|
289
|
-
|
|
290
|
-
def __call__(self, x):
|
|
291
|
-
"""
|
|
292
|
-
Effectue une inférence complète en appliquant :
|
|
293
|
-
- chaque encodage d'entrée défini dans `self.encodings`,
|
|
294
|
-
- un passage dans le MLP (`self.model`) pour chaque encodage,
|
|
295
|
-
- une concaténation des sorties,
|
|
296
|
-
- une couche linéaire finale (`self.f`) pour produire la prédiction.
|
|
297
|
-
|
|
298
|
-
Cette méthode permet d’utiliser l’objet comme une fonction :
|
|
299
|
-
y = net(x)
|
|
300
|
-
|
|
301
|
-
Parameters
|
|
302
|
-
----------
|
|
303
|
-
x : array-like
|
|
304
|
-
Entrée(s) à prédire. Peut être un tableau NumPy, une liste Python
|
|
305
|
-
ou un tenseur PyTorch convertible par `tensorise()`.
|
|
306
|
-
|
|
307
|
-
Returns
|
|
308
|
-
-------
|
|
309
|
-
np.ndarray
|
|
310
|
-
Sortie finale du modèle après :
|
|
311
|
-
encodage(s) → MLP → concaténation → couche finale.
|
|
312
|
-
Résultat renvoyé sous forme de tableau NumPy CPU aplati.
|
|
313
|
-
"""
|
|
314
|
-
|
|
315
|
-
# Inférence sans calcul de gradient (plus rapide et évite la construction du graphe)
|
|
316
|
-
with torch.no_grad():
|
|
317
|
-
inputs = tensorise(x)
|
|
318
|
-
if inputs.dim() == 1:
|
|
319
|
-
inputs = inputs.unsqueeze(0)
|
|
320
|
-
|
|
321
|
-
# --- Initialisation du scaler pour l'entraînement en précision mixte ---
|
|
322
|
-
|
|
323
|
-
results_list = []
|
|
324
|
-
for encoding in self.encodings:
|
|
325
|
-
results_list.append(self.model(encoding(inputs)))
|
|
326
|
-
return self.f(torch.cat(results_list, dim=1)).cpu().numpy().flatten()
|
|
327
|
-
|
|
328
|
-
def params(self):
|
|
329
|
-
"""
|
|
330
|
-
Retourne la liste de tous les poids (weights) du MLP.
|
|
331
|
-
|
|
332
|
-
Cette fonction extrait uniquement les matrices de poids des couches
|
|
333
|
-
linéaires, en ignorant les biais.
|
|
334
|
-
Dans un `nn.Linear`, `parameters()` renvoie dans l'ordre :
|
|
335
|
-
- les poids (indice pair),
|
|
336
|
-
- les biais (indice impair).
|
|
337
|
-
|
|
338
|
-
La méthode :
|
|
339
|
-
- parcourt les paramètres du réseau,
|
|
340
|
-
- sélectionne uniquement ceux correspondant aux poids,
|
|
341
|
-
- sépare chaque ligne de la matrice de poids,
|
|
342
|
-
- convertit chaque ligne en ndarray CPU détaché.
|
|
343
|
-
|
|
344
|
-
Returns
|
|
345
|
-
-------
|
|
346
|
-
list[np.ndarray]
|
|
347
|
-
Liste contenant chaque ligne des matrices de poids
|
|
348
|
-
(chaque élément est un vecteur numpy).
|
|
349
|
-
"""
|
|
350
|
-
|
|
351
|
-
list_weights = []
|
|
352
|
-
params = list(self.model.parameters())
|
|
353
|
-
|
|
354
|
-
# Indices pairs → matrices de poids (indices impairs = biais)
|
|
355
|
-
for i in rglen(params):
|
|
356
|
-
if i % 2 == 0:
|
|
357
|
-
weights = list(params[i]) # Chaque élément = ligne de la matrice W
|
|
358
|
-
for j in rglen(weights):
|
|
359
|
-
# On convertit ligne par ligne en numpy pour inspection externe
|
|
360
|
-
list_weights.append(weights[j].detach().cpu().numpy())
|
|
361
|
-
|
|
362
|
-
return list_weights
|
|
363
|
-
|
|
364
|
-
def nb_params(self):
|
|
365
|
-
"""
|
|
366
|
-
Calcule le nombre total de paramètres (poids) du MLP.
|
|
367
|
-
|
|
368
|
-
Cette méthode parcourt les paramètres du modèle et ne compte
|
|
369
|
-
que les **poids** des couches linéaires.
|
|
370
|
-
Dans un nn.Linear, `parameters()` renvoie dans l'ordre :
|
|
371
|
-
- les poids (indice pair),
|
|
372
|
-
- puis les biais (indice impair).
|
|
373
|
-
On ignore donc les biais dans ce comptage.
|
|
374
|
-
|
|
375
|
-
Returns
|
|
376
|
-
-------
|
|
377
|
-
int
|
|
378
|
-
Nombre total de paramètres pondérés (weights) dans le MLP.
|
|
379
|
-
"""
|
|
380
|
-
|
|
381
|
-
sum = 0
|
|
382
|
-
params = list(self.model.parameters())
|
|
383
|
-
|
|
384
|
-
# Les indices pairs correspondent aux matrices de poids
|
|
385
|
-
for i in rglen(params):
|
|
386
|
-
if i % 2 == 0:
|
|
387
|
-
weights = list(params[i])
|
|
388
|
-
# On additionne la longueur de chaque ligne de la matrice de poids
|
|
389
|
-
for j in rglen(weights):
|
|
390
|
-
sum += len(weights[j])
|
|
391
|
-
|
|
392
|
-
return sum
|
|
393
|
-
|
|
394
|
-
def neurons(self):
|
|
395
|
-
"""
|
|
396
|
-
Extrait l'ensemble des neurones (poids) du MLP couche par couche.
|
|
397
|
-
|
|
398
|
-
Cette méthode parcourt les paramètres du modèle et récupère
|
|
399
|
-
uniquement les poids associés aux biais des couches linéaires.
|
|
400
|
-
Dans un nn.Linear, `parameters()` renvoie successivement :
|
|
401
|
-
- les poids (weights),
|
|
402
|
-
- puis les biais (bias).
|
|
403
|
-
Les indices impairs correspondent donc aux biais.
|
|
404
|
-
|
|
405
|
-
Returns
|
|
406
|
-
-------
|
|
407
|
-
list of ndarray
|
|
408
|
-
Liste contenant chaque neurone (chaque valeur de biais),
|
|
409
|
-
converti en array NumPy sur CPU.
|
|
410
|
-
"""
|
|
411
|
-
|
|
412
|
-
list_neurons = []
|
|
413
|
-
params = list(self.model.parameters())
|
|
414
|
-
|
|
415
|
-
# Parcours des paramètres et sélection des biais (indices impairs)
|
|
416
|
-
for i in rglen(params):
|
|
417
|
-
if i % 2 == 1: # Les biais des nn.Linear
|
|
418
|
-
neurons = list(params[i])
|
|
419
|
-
# Extraction individuelle de chaque neurone
|
|
420
|
-
for j in rglen(neurons):
|
|
421
|
-
list_neurons.append(neurons[j].detach().cpu().numpy())
|
|
422
|
-
|
|
423
|
-
return list_neurons
|
|
424
|
-
|
|
425
|
-
def Create_MLP(self, layers):
|
|
426
|
-
"""
|
|
427
|
-
Construit un Multi-Layer Perceptron (MLP) standard composé :
|
|
428
|
-
- d'une succession de couches Linéaires,
|
|
429
|
-
- suivies d'une normalisation (self.norm) après chaque couche cachée,
|
|
430
|
-
- et d'une activation Sigmoid sur la couche de sortie.
|
|
431
|
-
|
|
432
|
-
Parameters
|
|
433
|
-
----------
|
|
434
|
-
layers : list[int]
|
|
435
|
-
Liste des dimensions successives du réseau.
|
|
436
|
-
Exemple : [in_features, hidden1, hidden2, ..., out_features]
|
|
437
|
-
|
|
438
|
-
Returns
|
|
439
|
-
-------
|
|
440
|
-
nn.Sequential
|
|
441
|
-
Le MLP complet sous forme de séquence PyTorch.
|
|
442
|
-
|
|
443
|
-
Notes
|
|
444
|
-
-----
|
|
445
|
-
- La couche finale applique systématiquement une Sigmoid, adaptée à des
|
|
446
|
-
sorties dans [0, 1].
|
|
447
|
-
"""
|
|
448
|
-
|
|
449
|
-
layer_list = []
|
|
450
|
-
|
|
451
|
-
# Ajout des couches cachées : Linear → Normalisation
|
|
452
|
-
# (pour chaque couple consecutive layers[k] → layers[k+1], sauf la dernière)
|
|
453
|
-
for k in range(len(layers) - 2):
|
|
454
|
-
layer_list.extend([
|
|
455
|
-
nn.Linear(layers[k], layers[k+1]),
|
|
456
|
-
self.norm
|
|
457
|
-
])
|
|
458
|
-
|
|
459
|
-
# Ajout de la couche finale : Linear
|
|
460
|
-
layer_list.extend([
|
|
461
|
-
nn.Linear(layers[-2], layers[-1])
|
|
462
|
-
])
|
|
463
|
-
|
|
464
|
-
return nn.Sequential(*layer_list)
|
|
465
|
-
|
|
466
|
-
def train(self, inputs, outputs, num_epochs=1500, batch_size=1024):
|
|
467
|
-
"""
|
|
468
|
-
Entraîne le modèle en utilisant un schéma mini-batch et la précision
|
|
469
|
-
mixte (AMP). Chaque batch subit :
|
|
470
|
-
|
|
471
|
-
encodages multiples → MLP → concaténation → couche finale → perte
|
|
472
|
-
|
|
473
|
-
Ce training met également à jour dynamiquement le learning rate.
|
|
474
|
-
|
|
475
|
-
Parameters
|
|
476
|
-
----------
|
|
477
|
-
inputs : array-like or torch.Tensor
|
|
478
|
-
Données d'entrée, shape (N, input_dim). Sont converties en
|
|
479
|
-
tenseur PyTorch et envoyées sur `device`.
|
|
480
|
-
outputs : array-like or torch.Tensor
|
|
481
|
-
Cibles correspondantes, shape (N, output_dim).
|
|
482
|
-
num_epochs : int, optional
|
|
483
|
-
Nombre total d'époques d'entraînement.
|
|
484
|
-
Default: 1500.
|
|
485
|
-
batch_size : int, optional
|
|
486
|
-
Taille des mini-batchs. Default: 1024.
|
|
487
|
-
|
|
488
|
-
Notes
|
|
489
|
-
-----
|
|
490
|
-
- Utilise `torch.amp.autocast` et `GradScaler` pour un entraînement
|
|
491
|
-
accéléré et stable en précision mixte (FP16/FP32).
|
|
492
|
-
- Pour chaque mini-batch :
|
|
493
|
-
* chaque module dans `self.encodings` est appliqué aux entrées,
|
|
494
|
-
* chaque encodage passe dans `self.model`,
|
|
495
|
-
* les sorties sont concaténées,
|
|
496
|
-
* la couche finale `self.f` produit la prédiction,
|
|
497
|
-
* la perte est évaluée via `self.crit`.
|
|
498
|
-
- Le learning rate est ajusté après chaque époque.
|
|
499
|
-
- Les pertes d'époques sont enregistrées dans `self.losses`.
|
|
500
|
-
"""
|
|
501
|
-
|
|
502
|
-
# --- Conversion en tensors et récupération du nombre d'échantillons ---
|
|
503
|
-
inputs, outputs = tensorise(inputs).to(device), tensorise(outputs).to(device)
|
|
504
|
-
self.model = self.model.to(device)
|
|
505
|
-
n_samples = inputs.size(0)
|
|
506
|
-
|
|
507
|
-
# --- Initialisation du scaler pour l'entraînement en précision mixte ---
|
|
508
|
-
dev = str(device)
|
|
509
|
-
scaler = GradScaler(dev)
|
|
510
|
-
|
|
511
|
-
def update_lr(optimizer, loss):
|
|
512
|
-
for param_group in optimizer.param_groups:
|
|
513
|
-
param_group['lr'] = 0.005*np.where(loss <=0, 0,
|
|
514
|
-
np.where(loss >=1, 1,
|
|
515
|
-
np.sqrt(loss)/(2 - loss**2)))
|
|
516
|
-
|
|
517
|
-
# --- Boucle principale sur les époques ---
|
|
518
|
-
for epoch in tqdm(range(num_epochs), desc="train epoch"):
|
|
519
|
-
# Génération d'un ordre aléatoire des indices
|
|
520
|
-
perm = torch.randperm(n_samples, device=device)
|
|
521
|
-
epoch_loss = 0.0
|
|
522
|
-
|
|
523
|
-
# --- Parcours des mini-batchs ---
|
|
524
|
-
for i in range(0, n_samples, batch_size):
|
|
525
|
-
idx = perm[i:i+batch_size]
|
|
526
|
-
|
|
527
|
-
# Fonction interne calculant la perte et les gradients
|
|
528
|
-
def closure():
|
|
529
|
-
self.optim.zero_grad(set_to_none=True)
|
|
530
|
-
with autocast(dev): # AMP
|
|
531
|
-
results_list = []
|
|
532
|
-
for encoding in self.encodings:
|
|
533
|
-
results_list.append(self.model(encoding(inputs[idx])))
|
|
534
|
-
loss = self.crit(self.f(torch.cat(results_list, dim=1)),outputs[idx])
|
|
535
|
-
scaler.scale(loss).backward()
|
|
536
|
-
return loss
|
|
537
|
-
|
|
538
|
-
# Calcul de la perte et mise à jour des poids
|
|
539
|
-
loss = closure()
|
|
540
|
-
scaler.step(self.optim)
|
|
541
|
-
scaler.update()
|
|
542
|
-
|
|
543
|
-
# Accumulation de la perte pour l'époque
|
|
544
|
-
epoch_loss += loss.item()
|
|
545
|
-
|
|
546
|
-
# --- Stockage de la perte de l'époque ---
|
|
547
|
-
self.losses.append(epoch_loss)
|
|
548
|
-
update_lr(self.optim,self.losses[-1])
|
|
549
|
-
|
|
550
|
-
def losses(*nets):
|
|
551
|
-
"""
|
|
552
|
-
Affiche les courbes de pertes (training loss) de plusieurs réseaux MLP.
|
|
553
|
-
|
|
554
|
-
Parameters
|
|
555
|
-
----------
|
|
556
|
-
nets : MLP
|
|
557
|
-
Un ou plusieurs réseaux possédant un attribut `.losses`
|
|
558
|
-
contenant l'historique des pertes (liste de float).
|
|
559
|
-
|
|
560
|
-
Notes
|
|
561
|
-
-----
|
|
562
|
-
- L’axe X correspond aux itérations (epochs ou steps).
|
|
563
|
-
- L’axe Y correspond à la valeur de la perte.
|
|
564
|
-
- La fonction utilise matplotlib en mode interactif pour affichage dynamique.
|
|
565
|
-
"""
|
|
566
|
-
|
|
567
|
-
# --- Initialisation de la figure ---
|
|
568
|
-
fig = plt.figure(figsize=(5, 5))
|
|
569
|
-
|
|
570
|
-
# --- Définition des limites des axes ---
|
|
571
|
-
all_losses = [[loss for loss in net.losses] for net in nets]
|
|
572
|
-
if max(len(lst) for lst in all_losses) == 1:
|
|
573
|
-
lenlosses = 2
|
|
574
|
-
else:
|
|
575
|
-
lenlosses = max(len(lst) for lst in all_losses)
|
|
576
|
-
plt.xlim(1, lenlosses)
|
|
577
|
-
|
|
578
|
-
# --- Tracé des courbes de pertes pour chaque réseau ---
|
|
579
|
-
for k, net in enumerate(nets):
|
|
580
|
-
steps = np.linspace(1, len(net.losses), len(net.losses)) # epochs
|
|
581
|
-
plt.plot(np.arange(1, len(all_losses[k])+1), all_losses[k],label = net.name)
|
|
582
|
-
plt.yscale('log', nonpositive='mask')
|
|
583
|
-
# --- Affichage ---
|
|
584
|
-
plt.legend()
|
|
585
|
-
plt.xlabel("Epoch")
|
|
586
|
-
plt.ylabel("Résidus")
|
|
587
|
-
fig.canvas.draw_idle()
|
|
588
|
-
plt.tight_layout()
|
|
589
|
-
plt.ion() # mode interactif
|
|
590
|
-
plt.show()
|
|
591
|
-
|
|
592
|
-
losses.help = fPrintDoc(losses)
|
|
593
|
-
|
|
594
|
-
MLP.__init__.help = fPrintDoc(MLP.__init__)
|
|
595
|
-
MLP.__repr__.help = fPrintDoc(MLP.__repr__)
|
|
596
|
-
MLP.__call__.help = fPrintDoc(MLP.__call__)
|
|
597
|
-
MLP.help = fPrintDoc(MLP)
|
|
598
|
-
MLP.params.help = fPrintDoc(MLP.params)
|
|
599
|
-
MLP.nb_params.help = fPrintDoc(MLP.nb_params)
|
|
600
|
-
MLP.neurons.help = fPrintDoc(MLP.neurons)
|
|
601
|
-
MLP.train.help = fPrintDoc(MLP.train)
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
NeuralNetworks/Dependances.py,sha256=gtuEuktxDL9fHwPET58k2vGSqWJd7AAZCHW4DPHyc18,8508
|
|
2
|
-
NeuralNetworks/Latent.py,sha256=JjHncjlNOuEiwJTv5T8LgqUDCCKJzF5bIrUMPWK6QE8,1867
|
|
3
|
-
NeuralNetworks/MLP.py,sha256=3jz7mZ9U0WrQArY8djohElBtt_a-erRrH82iXmK0skU,23754
|
|
4
|
-
NeuralNetworks/__init__.py,sha256=YL7m1LcHGp3R_WNLLPyG2H76M81VMpBeF0B705EuXHg,4664
|
|
5
|
-
NeuralNetworks/tools/AirfRANS.py,sha256=UaCT3cuMz4_SPtgk9a7ZGB12l8dnDHjoAkD2ovLrAWk,1412
|
|
6
|
-
NeuralNetworks/tools/MNIST.py,sha256=1lcB-dmlvpcxvQmjjHW2d5wR84uWB5rzYP6VC6CMoN4,4333
|
|
7
|
-
NeuralNetworks/tools/VKI-LS59.py,sha256=OZqrJvR5QDcPEtuL7H0UoxpFwkjmWmOmfVWoV1d8fIs,354
|
|
8
|
-
NeuralNetworks/tools/image.py,sha256=dtohmcOtGJ0rK3uXxy9O2zhhTE_DZDoZKmUSnBNkv0Q,8952
|
|
9
|
-
neuralnetworks-0.2.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
10
|
-
neuralnetworks-0.2.0.dist-info/METADATA,sha256=Z9dEBzq3NrcLlY68ggbCH7Pei7GwijVRfKWR_nK4QqE,12070
|
|
11
|
-
neuralnetworks-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
-
neuralnetworks-0.2.0.dist-info/top_level.txt,sha256=h18nmC1BX7avyAAwKh0OQWezxgXmOpmVtbFq-8Mcbms,15
|
|
13
|
-
neuralnetworks-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|