NeuralNetworks 0.1.12__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 +11 -116
- NeuralNetworks/tools/AirfRANS.py +36 -0
- NeuralNetworks/tools/MNIST.py +118 -0
- NeuralNetworks/tools/VKI-LS59.py +7 -0
- NeuralNetworks/tools/image.py +249 -0
- neuralnetworks-0.2.2.dist-info/METADATA +194 -0
- neuralnetworks-0.2.2.dist-info/RECORD +24 -0
- NeuralNetworks/Dependances.py +0 -319
- NeuralNetworks/Image.py +0 -105
- NeuralNetworks/MLP.py +0 -591
- NeuralNetworks/Plot.py +0 -324
- neuralnetworks-0.1.12.dist-info/METADATA +0 -187
- neuralnetworks-0.1.12.dist-info/RECORD +0 -10
- {neuralnetworks-0.1.12.dist-info → neuralnetworks-0.2.2.dist-info}/WHEEL +0 -0
- {neuralnetworks-0.1.12.dist-info → neuralnetworks-0.2.2.dist-info}/licenses/LICENSE +0 -0
- {neuralnetworks-0.1.12.dist-info → neuralnetworks-0.2.2.dist-info}/top_level.txt +0 -0
NeuralNetworks/MLP.py
DELETED
|
@@ -1,591 +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
|
-
learning_rate : float, optional
|
|
32
|
-
Taux d’apprentissage pour l’optimiseur.
|
|
33
|
-
Default: 1e-3
|
|
34
|
-
Fourier : bool, optional
|
|
35
|
-
Si True, applique un encodage Fourier gaussien (RFF) sur les entrées.
|
|
36
|
-
Default: True
|
|
37
|
-
optim : str, optional
|
|
38
|
-
Nom de l’optimiseur à utiliser (doit exister dans `optim_list`).
|
|
39
|
-
Default: "ADAM"
|
|
40
|
-
crit : str, optional
|
|
41
|
-
Fonction de perte à utiliser (doit exister dans `crit_list`).
|
|
42
|
-
Default: "MSE"
|
|
43
|
-
norm : str, optional
|
|
44
|
-
Type de normalisation / activation pour les couches cachées (ex: "Relu").
|
|
45
|
-
Default: "Relu"
|
|
46
|
-
name : str, optional
|
|
47
|
-
Nom du réseau pour identification ou affichage.
|
|
48
|
-
Default: "Net"
|
|
49
|
-
Iscompiled : bool, optional
|
|
50
|
-
Si True, compile le modèle via `torch.compile` pour accélérer l’inférence.
|
|
51
|
-
Default: True
|
|
52
|
-
|
|
53
|
-
Attributes
|
|
54
|
-
----------
|
|
55
|
-
losses : list[torch.Tensor]
|
|
56
|
-
Historique des pertes cumulées lors de l'entraînement.
|
|
57
|
-
layers : list[int]
|
|
58
|
-
Dimensions du réseau, ajustées si encodage Fourier actif.
|
|
59
|
-
encoding : nn.Module
|
|
60
|
-
Module appliquant l'encodage des entrées (RFF ou identity).
|
|
61
|
-
norm : nn.Module
|
|
62
|
-
Normalisation ou activation utilisée dans les couches cachées.
|
|
63
|
-
crit : nn.Module
|
|
64
|
-
Fonction de perte PyTorch sur le device spécifié.
|
|
65
|
-
model : nn.Sequential
|
|
66
|
-
MLP complet construit dynamiquement.
|
|
67
|
-
optim : torch.optim.Optimizer
|
|
68
|
-
Optimiseur associé au MLP.
|
|
69
|
-
name : str
|
|
70
|
-
Nom du réseau.
|
|
71
|
-
|
|
72
|
-
Methods
|
|
73
|
-
-------
|
|
74
|
-
__init__(...)
|
|
75
|
-
Initialise le réseau, configure l’encodage, la fonction de perte et l’optimiseur.
|
|
76
|
-
__repr__()
|
|
77
|
-
Affiche un schéma visuel du MLP et ses dimensions (avec compression si nécessaire).
|
|
78
|
-
__call__(x)
|
|
79
|
-
Applique l’encodage et le MLP sur un input x, retourne la prédiction en ndarray.
|
|
80
|
-
Create_MLP(layers)
|
|
81
|
-
Construit un nn.Sequential avec les couches linéaires, activations et normalisations.
|
|
82
|
-
plot(inputs, img_array)
|
|
83
|
-
Affiche l’image originale, l’image prédite et la courbe des pertes.
|
|
84
|
-
train(inputs, outputs, num_epochs=1500, batch_size=1024)
|
|
85
|
-
Entraîne le MLP avec mini-batchs et AMP, stocke les pertes.
|
|
86
|
-
params()
|
|
87
|
-
Retourne tous les poids du MLP sous forme de liste d’ndarray.
|
|
88
|
-
neurons()
|
|
89
|
-
Retourne tous les biais du MLP sous forme de liste d’ndarray.
|
|
90
|
-
nb_params()
|
|
91
|
-
Calcule le nombre total de paramètres (poids uniquement) du réseau.
|
|
92
|
-
|
|
93
|
-
Notes
|
|
94
|
-
-----
|
|
95
|
-
- La classe supporte un entraînement sur GPU via `device`.
|
|
96
|
-
- Les fonctions de visualisation utilisent matplotlib et visualtorch.
|
|
97
|
-
- Les sorties sont compatibles avec des images normalisées entre 0 et 1.
|
|
98
|
-
- Le suivi des pertes permet d’afficher l’évolution du training loss.
|
|
99
|
-
"""
|
|
100
|
-
|
|
101
|
-
def __init__(self, layers=[1,1,1], learning_rate=1e-3, Fourier=True,
|
|
102
|
-
optim="Adam", crit="MSE", norm="Relu",
|
|
103
|
-
name="Net", Iscompiled=False):
|
|
104
|
-
"""
|
|
105
|
-
Initialise un réseau MLP avec options avancées : encodage Fourier,
|
|
106
|
-
normalisation, choix d’optimiseur et de fonction de perte, et compilation.
|
|
107
|
-
|
|
108
|
-
Parameters
|
|
109
|
-
----------
|
|
110
|
-
layers : list[int], optional
|
|
111
|
-
Dimensions successives du réseau (entrée → couches cachées → sortie).
|
|
112
|
-
Default: [1, 1, 1]
|
|
113
|
-
learning_rate : float, optional
|
|
114
|
-
Taux d’apprentissage pour l’optimiseur (default: 1e-3).
|
|
115
|
-
Fourier : bool, optional
|
|
116
|
-
Si True, applique un encodage RFF (Random Fourier Features) sur les entrées.
|
|
117
|
-
Default: True
|
|
118
|
-
optim : str, optional
|
|
119
|
-
Nom de l’optimiseur à utiliser (doit être présent dans `optim_list`).
|
|
120
|
-
Default: "Adam"
|
|
121
|
-
crit : str, optional
|
|
122
|
-
Nom de la fonction de perte à utiliser (doit être présent dans `crit_list`).
|
|
123
|
-
Default: "MSE"
|
|
124
|
-
norm : str, optional
|
|
125
|
-
Type de normalisation / activation à appliquer entre les couches cachées.
|
|
126
|
-
Default: "Relu"
|
|
127
|
-
name : str, optional
|
|
128
|
-
Nom du réseau (pour identification et affichage).
|
|
129
|
-
Default: "Net"
|
|
130
|
-
Iscompiled : bool, optional
|
|
131
|
-
Si True, compile le modèle avec `torch.compile` pour accélérer l’inférence.
|
|
132
|
-
Default: True
|
|
133
|
-
|
|
134
|
-
Attributes
|
|
135
|
-
----------
|
|
136
|
-
losses : list
|
|
137
|
-
Historique des pertes durant l’entraînement.
|
|
138
|
-
layers : list[int]
|
|
139
|
-
Dimensions du réseau après ajustement pour encodage Fourier.
|
|
140
|
-
encoding : nn.Module
|
|
141
|
-
Module appliquant l’encodage des entrées (RFF ou identité).
|
|
142
|
-
norm : nn.Module
|
|
143
|
-
Normalisation / activation utilisée entre les couches cachées.
|
|
144
|
-
crit : nn.Module
|
|
145
|
-
Fonction de perte PyTorch sur GPU.
|
|
146
|
-
model : nn.Sequential
|
|
147
|
-
MLP complet construit dynamiquement.
|
|
148
|
-
optim : torch.optim.Optimizer
|
|
149
|
-
Optimiseur associé au MLP.
|
|
150
|
-
name : str
|
|
151
|
-
Nom du réseau.
|
|
152
|
-
"""
|
|
153
|
-
|
|
154
|
-
super().__init__()
|
|
155
|
-
|
|
156
|
-
# --- Initialisation des attributs de base ---
|
|
157
|
-
self.losses, self.layers, self.Fourier = [], layers.copy(), Fourier
|
|
158
|
-
self.name = name
|
|
159
|
-
|
|
160
|
-
# --- Encodage Fourier (RFF) ou passthrough ---
|
|
161
|
-
if self.Fourier:
|
|
162
|
-
self.encoding = rff.layers.GaussianEncoding(
|
|
163
|
-
sigma=10.0,
|
|
164
|
-
input_size=self.layers[0],
|
|
165
|
-
encoded_size=self.layers[1]
|
|
166
|
-
).to(device)
|
|
167
|
-
self.layers[0] = self.layers[1] * 2 # chaque entrée est doublée après encodage
|
|
168
|
-
else:
|
|
169
|
-
self.encoding = nn.Identity().to(device) # passthrough si pas de Fourier
|
|
170
|
-
|
|
171
|
-
# --- Sélection du normalisateur / activation ---
|
|
172
|
-
self.norm = norm_list.get(norm)
|
|
173
|
-
if self.norm is None:
|
|
174
|
-
print("")
|
|
175
|
-
print (f"{norm} n'est pas reconnu")
|
|
176
|
-
self.norm = norm_list.get("Relu")
|
|
177
|
-
print (f"Retour au paramètre par défaut: 'Relu'")
|
|
178
|
-
|
|
179
|
-
# --- Fonction de perte ---
|
|
180
|
-
self.crit = crit_list.get(crit)
|
|
181
|
-
if self.crit is None:
|
|
182
|
-
print("")
|
|
183
|
-
print (f"{crit} n'est pas reconnu")
|
|
184
|
-
self.crit = crit_list.get("MSE")
|
|
185
|
-
print (f"Retour au paramètre par défaut: 'MSE'")
|
|
186
|
-
# --- Construction du MLP ---
|
|
187
|
-
self.model = self.Create_MLP(self.layers)
|
|
188
|
-
|
|
189
|
-
# --- Sélection de l’optimiseur ---
|
|
190
|
-
self.optim = optim_list(self, learning_rate).get(optim)
|
|
191
|
-
if self.optim is None:
|
|
192
|
-
print("")
|
|
193
|
-
print (f"{optim} n'est pas reconnu")
|
|
194
|
-
self.optim = optim_list(self, learning_rate).get("Adam")
|
|
195
|
-
print (f"Retour au paramètre par défaut: 'Adam'")
|
|
196
|
-
|
|
197
|
-
# --- Compilation optionnelle du modèle pour accélérer l’inférence ---
|
|
198
|
-
if not has_gcc():
|
|
199
|
-
Iscompiled = False
|
|
200
|
-
|
|
201
|
-
if Iscompiled:
|
|
202
|
-
self.model = torch.compile(
|
|
203
|
-
self.model,
|
|
204
|
-
mode="max-autotune",
|
|
205
|
-
fullgraph=True,
|
|
206
|
-
dynamic=True
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
# --- Envoi du modèle sur le device GPU / CPU ---
|
|
210
|
-
self.model.to(device)
|
|
211
|
-
|
|
212
|
-
def __repr__(self):
|
|
213
|
-
"""
|
|
214
|
-
Génère un aperçu visuel du MLP et affiche ses dimensions.
|
|
215
|
-
|
|
216
|
-
Cette méthode :
|
|
217
|
-
- crée une version éventuellement "compressée" des dimensions du réseau
|
|
218
|
-
(utile lorsque certaines couches dépassent 30 neurones, afin de
|
|
219
|
-
conserver une visualisation lisible),
|
|
220
|
-
- utilise `visualtorch.graph_view` pour afficher un schéma du MLP,
|
|
221
|
-
- imprime la liste réelle des dimensions du réseau,
|
|
222
|
-
- retourne une chaîne indiquant si un redimensionnement a été appliqué.
|
|
223
|
-
|
|
224
|
-
Notes
|
|
225
|
-
-----
|
|
226
|
-
- Le redimensionnement ne modifie pas le MLP réel. Il ne sert qu'à
|
|
227
|
-
améliorer la lisibilité du graphe affiché.
|
|
228
|
-
- Si Fourier Features sont activées, seule la première dimension est
|
|
229
|
-
recalculée en conséquence.
|
|
230
|
-
"""
|
|
231
|
-
|
|
232
|
-
# Si les couches sont trop grandes, on crée une version réduite
|
|
233
|
-
if max(self.layers) > 30:
|
|
234
|
-
# Mise à l’échelle proportionnelle sur une base max 32
|
|
235
|
-
fakelayers = [int(32 * layer / max(self.layers)) for layer in self.layers]
|
|
236
|
-
|
|
237
|
-
# Ajustement de la couche d’entrée si encodage Fourier
|
|
238
|
-
fakelayers[0] = (
|
|
239
|
-
int(32 * self.layers[0] / max(self.layers))
|
|
240
|
-
if self.Fourier else self.layers[0]
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
# La couche de sortie reste intacte
|
|
244
|
-
fakelayers[-1] = self.layers[-1]
|
|
245
|
-
|
|
246
|
-
else:
|
|
247
|
-
# Sinon, on garde les dimensions réelles
|
|
248
|
-
fakelayers = self.layers
|
|
249
|
-
|
|
250
|
-
# Affichage console des dimensions réelles
|
|
251
|
-
print("Tailles réelles :")
|
|
252
|
-
print(str(self.layers))
|
|
253
|
-
print("")
|
|
254
|
-
print("Tailles affichées :")
|
|
255
|
-
print(str(fakelayers))
|
|
256
|
-
|
|
257
|
-
# --- Visualisation du MLP ---
|
|
258
|
-
fig, ax = plt.subplots(figsize=(12, 6))
|
|
259
|
-
ax.axis("off")
|
|
260
|
-
|
|
261
|
-
# Utilisation de visualtorch pour tracer l’architecture
|
|
262
|
-
ax.imshow(
|
|
263
|
-
visualtorch.graph_view(
|
|
264
|
-
self.Create_MLP(fakelayers),
|
|
265
|
-
(1, fakelayers[0]),
|
|
266
|
-
ellipsize_after=34,
|
|
267
|
-
background_fill=(0, 0, 0, 0),
|
|
268
|
-
opacity=255
|
|
269
|
-
)
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
plt.show()
|
|
273
|
-
return ""
|
|
274
|
-
|
|
275
|
-
def __call__(self, x):
|
|
276
|
-
"""
|
|
277
|
-
Effectue une inférence complète : encodage éventuel, passage
|
|
278
|
-
dans le MLP, puis retour en numpy.
|
|
279
|
-
|
|
280
|
-
Cette méthode permet d’utiliser l’objet comme une fonction
|
|
281
|
-
directement : `y = net(x)`.
|
|
282
|
-
|
|
283
|
-
Paramètres
|
|
284
|
-
----------
|
|
285
|
-
x : array-like
|
|
286
|
-
Entrée(s) à prédire. Peut être un tableau numpy, une liste,
|
|
287
|
-
ou déjà un tenseur compatible.
|
|
288
|
-
|
|
289
|
-
Returns
|
|
290
|
-
-------
|
|
291
|
-
np.ndarray
|
|
292
|
-
Sortie du MLP après encodage et propagation avant,
|
|
293
|
-
convertie en tableau numpy sur CPU.
|
|
294
|
-
"""
|
|
295
|
-
|
|
296
|
-
# Inférence sans calcul de gradient (plus rapide et évite la construction du graphe)
|
|
297
|
-
with torch.no_grad():
|
|
298
|
-
return self.model(
|
|
299
|
-
self.encoding(tensorise(x))
|
|
300
|
-
).cpu().numpy()
|
|
301
|
-
|
|
302
|
-
def params(self):
|
|
303
|
-
"""
|
|
304
|
-
Retourne la liste de tous les poids (weights) du MLP.
|
|
305
|
-
|
|
306
|
-
Cette fonction extrait uniquement les matrices de poids des couches
|
|
307
|
-
linéaires, en ignorant les biais.
|
|
308
|
-
Dans un `nn.Linear`, `parameters()` renvoie dans l'ordre :
|
|
309
|
-
- les poids (indice pair),
|
|
310
|
-
- les biais (indice impair).
|
|
311
|
-
|
|
312
|
-
La méthode :
|
|
313
|
-
- parcourt les paramètres du réseau,
|
|
314
|
-
- sélectionne uniquement ceux correspondant aux poids,
|
|
315
|
-
- sépare chaque ligne de la matrice de poids,
|
|
316
|
-
- convertit chaque ligne en ndarray CPU détaché.
|
|
317
|
-
|
|
318
|
-
Returns
|
|
319
|
-
-------
|
|
320
|
-
list[np.ndarray]
|
|
321
|
-
Liste contenant chaque ligne des matrices de poids
|
|
322
|
-
(chaque élément est un vecteur numpy).
|
|
323
|
-
"""
|
|
324
|
-
|
|
325
|
-
list_weights = []
|
|
326
|
-
params = list(self.model.parameters())
|
|
327
|
-
|
|
328
|
-
# Indices pairs → matrices de poids (indices impairs = biais)
|
|
329
|
-
for i in rglen(params):
|
|
330
|
-
if i % 2 == 0:
|
|
331
|
-
weights = list(params[i]) # Chaque élément = ligne de la matrice W
|
|
332
|
-
for j in rglen(weights):
|
|
333
|
-
# On convertit ligne par ligne en numpy pour inspection externe
|
|
334
|
-
list_weights.append(weights[j].detach().cpu().numpy())
|
|
335
|
-
|
|
336
|
-
return list_weights
|
|
337
|
-
|
|
338
|
-
def nb_params(self):
|
|
339
|
-
"""
|
|
340
|
-
Calcule le nombre total de paramètres (poids) du MLP.
|
|
341
|
-
|
|
342
|
-
Cette méthode parcourt les paramètres du modèle et ne compte
|
|
343
|
-
que les **poids** des couches linéaires.
|
|
344
|
-
Dans un nn.Linear, `parameters()` renvoie dans l'ordre :
|
|
345
|
-
- les poids (indice pair),
|
|
346
|
-
- puis les biais (indice impair).
|
|
347
|
-
On ignore donc les biais dans ce comptage.
|
|
348
|
-
|
|
349
|
-
Returns
|
|
350
|
-
-------
|
|
351
|
-
int
|
|
352
|
-
Nombre total de paramètres pondérés (weights) dans le MLP.
|
|
353
|
-
"""
|
|
354
|
-
|
|
355
|
-
sum = 0
|
|
356
|
-
params = list(self.model.parameters())
|
|
357
|
-
|
|
358
|
-
# Les indices pairs correspondent aux matrices de poids
|
|
359
|
-
for i in rglen(params):
|
|
360
|
-
if i % 2 == 0:
|
|
361
|
-
weights = list(params[i])
|
|
362
|
-
# On additionne la longueur de chaque ligne de la matrice de poids
|
|
363
|
-
for j in rglen(weights):
|
|
364
|
-
sum += len(weights[j])
|
|
365
|
-
|
|
366
|
-
return sum
|
|
367
|
-
|
|
368
|
-
def neurons(self):
|
|
369
|
-
"""
|
|
370
|
-
Extrait l'ensemble des neurones (poids) du MLP couche par couche.
|
|
371
|
-
|
|
372
|
-
Cette méthode parcourt les paramètres du modèle et récupère
|
|
373
|
-
uniquement les poids associés aux biais des couches linéaires.
|
|
374
|
-
Dans un nn.Linear, `parameters()` renvoie successivement :
|
|
375
|
-
- les poids (weights),
|
|
376
|
-
- puis les biais (bias).
|
|
377
|
-
Les indices impairs correspondent donc aux biais.
|
|
378
|
-
|
|
379
|
-
Returns
|
|
380
|
-
-------
|
|
381
|
-
list of ndarray
|
|
382
|
-
Liste contenant chaque neurone (chaque valeur de biais),
|
|
383
|
-
converti en array NumPy sur CPU.
|
|
384
|
-
"""
|
|
385
|
-
|
|
386
|
-
list_neurons = []
|
|
387
|
-
params = list(self.model.parameters())
|
|
388
|
-
|
|
389
|
-
# Parcours des paramètres et sélection des biais (indices impairs)
|
|
390
|
-
for i in rglen(params):
|
|
391
|
-
if i % 2 == 1: # Les biais des nn.Linear
|
|
392
|
-
neurons = list(params[i])
|
|
393
|
-
# Extraction individuelle de chaque neurone
|
|
394
|
-
for j in rglen(neurons):
|
|
395
|
-
list_neurons.append(neurons[j].detach().cpu().numpy())
|
|
396
|
-
|
|
397
|
-
return list_neurons
|
|
398
|
-
|
|
399
|
-
def Create_MLP(self, layers):
|
|
400
|
-
"""
|
|
401
|
-
Construit un Multi-Layer Perceptron (MLP) standard composé :
|
|
402
|
-
- d'une succession de couches Linéaires,
|
|
403
|
-
- suivies d'une normalisation (self.norm) après chaque couche cachée,
|
|
404
|
-
- et d'une activation Sigmoid sur la couche de sortie.
|
|
405
|
-
|
|
406
|
-
Parameters
|
|
407
|
-
----------
|
|
408
|
-
layers : list[int]
|
|
409
|
-
Liste des dimensions successives du réseau.
|
|
410
|
-
Exemple : [in_features, hidden1, hidden2, ..., out_features]
|
|
411
|
-
|
|
412
|
-
Returns
|
|
413
|
-
-------
|
|
414
|
-
nn.Sequential
|
|
415
|
-
Le MLP complet sous forme de séquence PyTorch.
|
|
416
|
-
|
|
417
|
-
Notes
|
|
418
|
-
-----
|
|
419
|
-
- La couche finale applique systématiquement une Sigmoid, adaptée à des
|
|
420
|
-
sorties dans [0, 1].
|
|
421
|
-
"""
|
|
422
|
-
|
|
423
|
-
layer_list = []
|
|
424
|
-
|
|
425
|
-
# Ajout des couches cachées : Linear → Normalisation
|
|
426
|
-
# (pour chaque couple consecutive layers[k] → layers[k+1], sauf la dernière)
|
|
427
|
-
for k in range(len(layers) - 2):
|
|
428
|
-
layer_list.extend([
|
|
429
|
-
nn.Linear(layers[k], layers[k+1]),
|
|
430
|
-
self.norm
|
|
431
|
-
])
|
|
432
|
-
|
|
433
|
-
# Ajout de la couche finale : Linear → Sigmoid
|
|
434
|
-
layer_list.extend([
|
|
435
|
-
nn.Linear(layers[-2], layers[-1]),
|
|
436
|
-
nn.Sigmoid()
|
|
437
|
-
])
|
|
438
|
-
|
|
439
|
-
return nn.Sequential(*layer_list)
|
|
440
|
-
|
|
441
|
-
def plot(self, img_array, inputs):
|
|
442
|
-
"""
|
|
443
|
-
Affiche côte à côte :
|
|
444
|
-
- l’image originale,
|
|
445
|
-
- l’image prédite par le MLP,
|
|
446
|
-
- l’évolution de la fonction de perte (loss) au cours de l’entraînement.
|
|
447
|
-
|
|
448
|
-
Parameters
|
|
449
|
-
----------
|
|
450
|
-
img_array : np.ndarray
|
|
451
|
-
Image originale sous forme de tableau (H, W, 3) utilisée comme référence.
|
|
452
|
-
inputs : array-like or torch.Tensor
|
|
453
|
-
Tableau des coordonnées (ou features) servant d’entrée au réseau.
|
|
454
|
-
Doit correspondre à la grille permettant de reconstruire l’image.
|
|
455
|
-
|
|
456
|
-
Notes
|
|
457
|
-
-----
|
|
458
|
-
Cette méthode :
|
|
459
|
-
- tensorise les entrées puis les encode avant passage dans le MLP,
|
|
460
|
-
- reshape la sortie du modèle pour retrouver la forme (H, W, 3),
|
|
461
|
-
- trace également la courbe de pertes stockée dans `self.losses`.
|
|
462
|
-
"""
|
|
463
|
-
|
|
464
|
-
# Conversion des inputs en tenseur + récupération du nombre d'échantillons
|
|
465
|
-
inputs, n_samples = tensorise(inputs), inputs.size(0)
|
|
466
|
-
|
|
467
|
-
# Dimensions de l'image originale
|
|
468
|
-
h, w = img_array.shape[:2]
|
|
469
|
-
|
|
470
|
-
# Figure principale avec 3 panneaux : original / prédiction / loss
|
|
471
|
-
fig = plt.figure(figsize=(15, 5))
|
|
472
|
-
gs = GridSpec(1, 3, figure=fig)
|
|
473
|
-
|
|
474
|
-
# --- Image originale ---
|
|
475
|
-
ax_orig = fig.add_subplot(gs[0,0])
|
|
476
|
-
ax_orig.axis('off')
|
|
477
|
-
ax_orig.set_title("Original Image")
|
|
478
|
-
ax_orig.imshow(img_array)
|
|
479
|
-
|
|
480
|
-
# --- Image prédite ---
|
|
481
|
-
ax = fig.add_subplot(gs[0,1])
|
|
482
|
-
ax.axis('off')
|
|
483
|
-
ax.set_title("Predicted Image")
|
|
484
|
-
# Prédiction → CPU → numpy → reshape en (H, W, 3)
|
|
485
|
-
ax.imshow(
|
|
486
|
-
self.model(self.encoding(inputs))
|
|
487
|
-
.cpu()
|
|
488
|
-
.detach()
|
|
489
|
-
.numpy()
|
|
490
|
-
.reshape(h, w, 3)
|
|
491
|
-
)
|
|
492
|
-
|
|
493
|
-
# --- Courbe de loss ---
|
|
494
|
-
los = fig.add_subplot(gs[0,2])
|
|
495
|
-
los.set_title("Loss")
|
|
496
|
-
|
|
497
|
-
# Axe X = 1..N
|
|
498
|
-
los.plot(
|
|
499
|
-
np.linspace(1, len(self.losses), len(self.losses)),
|
|
500
|
-
[loss.item() for loss in self.losses]
|
|
501
|
-
)
|
|
502
|
-
if len(self.losses) ==1:
|
|
503
|
-
lenlosses = 2
|
|
504
|
-
else:
|
|
505
|
-
lenlosses = len(self.losses)
|
|
506
|
-
los.set_xlim(1, lenlosses)
|
|
507
|
-
|
|
508
|
-
# Évite un ylim min = 0 pile si les pertes sont trop faibles
|
|
509
|
-
maxarray = [0.00000001] + [loss.item() for loss in self.losses]
|
|
510
|
-
los.set_ylim(0, max(maxarray))
|
|
511
|
-
|
|
512
|
-
# Rafraîchissement non bloquant
|
|
513
|
-
fig.canvas.draw_idle()
|
|
514
|
-
plt.tight_layout()
|
|
515
|
-
plt.ion()
|
|
516
|
-
plt.show()
|
|
517
|
-
|
|
518
|
-
def train(self, inputs, outputs, num_epochs=1500, batch_size=1024):
|
|
519
|
-
"""
|
|
520
|
-
Entraîne le MLP sur des paires (inputs → outputs) en utilisant un
|
|
521
|
-
schéma de mini-batchs et l'AMP (Automatic Mixed Precision).
|
|
522
|
-
|
|
523
|
-
Parameters
|
|
524
|
-
----------
|
|
525
|
-
inputs : array-like or tensor
|
|
526
|
-
Données d'entrée du réseau, de shape (N, input_dim).
|
|
527
|
-
outputs : array-like or tensor
|
|
528
|
-
Cibles associées, de shape (N, output_dim).
|
|
529
|
-
num_epochs : int, optional
|
|
530
|
-
Nombre total d'époques d'entraînement (default: 1500).
|
|
531
|
-
batch_size : int, optional
|
|
532
|
-
Taille des mini-batchs utilisés à chaque itération (default: 1024).
|
|
533
|
-
|
|
534
|
-
Notes
|
|
535
|
-
-----
|
|
536
|
-
- Utilise torch.amp.autocast + GradScaler pour un entraînement accéléré en FP16.
|
|
537
|
-
- Les pertes par époque sont stockées dans `self.losses`.
|
|
538
|
-
- Le réseau doit posséder :
|
|
539
|
-
* self.model : module PyTorch (MLP)
|
|
540
|
-
* self.encoding() : encodage éventuel (Fourier features)
|
|
541
|
-
* self.crit : fonction de perte
|
|
542
|
-
* self.optim : optimiseur
|
|
543
|
-
"""
|
|
544
|
-
|
|
545
|
-
# --- Conversion en tensors et récupération du nombre d'échantillons ---
|
|
546
|
-
inputs, outputs, n_samples = tensorise(inputs).to(device), tensorise(outputs).to(device), inputs.size(0)
|
|
547
|
-
self.model = self.model.to(device)
|
|
548
|
-
|
|
549
|
-
# --- Initialisation du scaler pour l'entraînement en précision mixte ---
|
|
550
|
-
dev = str(device)
|
|
551
|
-
scaler = GradScaler(dev)
|
|
552
|
-
|
|
553
|
-
# --- Boucle principale sur les époques ---
|
|
554
|
-
for epoch in tqdm(range(num_epochs), desc="train epoch"):
|
|
555
|
-
# Génération d'un ordre aléatoire des indices
|
|
556
|
-
perm = torch.randperm(n_samples, device=device)
|
|
557
|
-
epoch_loss = 0.0
|
|
558
|
-
|
|
559
|
-
# --- Parcours des mini-batchs ---
|
|
560
|
-
for i in range(0, n_samples, batch_size):
|
|
561
|
-
idx = perm[i:i+batch_size]
|
|
562
|
-
|
|
563
|
-
# Fonction interne calculant la perte et les gradients
|
|
564
|
-
def closure():
|
|
565
|
-
self.optim.zero_grad(set_to_none=True)
|
|
566
|
-
with autocast(dev): # AMP
|
|
567
|
-
loss = self.crit(self.model(self.encoding(inputs[idx])),outputs[idx])
|
|
568
|
-
scaler.scale(loss).backward()
|
|
569
|
-
return loss
|
|
570
|
-
|
|
571
|
-
# Calcul de la perte et mise à jour des poids
|
|
572
|
-
loss = closure()
|
|
573
|
-
scaler.step(self.optim)
|
|
574
|
-
scaler.update()
|
|
575
|
-
|
|
576
|
-
# Accumulation de la perte pour l'époque
|
|
577
|
-
epoch_loss += loss
|
|
578
|
-
|
|
579
|
-
# --- Stockage de la perte de l'époque ---
|
|
580
|
-
self.losses.append(epoch_loss)
|
|
581
|
-
|
|
582
|
-
MLP.__init__.help = fPrintDoc(MLP.__init__)
|
|
583
|
-
MLP.__repr__.help = fPrintDoc(MLP.__repr__)
|
|
584
|
-
MLP.__call__.help = fPrintDoc(MLP.__call__)
|
|
585
|
-
MLP.help = fPrintDoc(MLP)
|
|
586
|
-
MLP.params.help = fPrintDoc(MLP.params)
|
|
587
|
-
MLP.nb_params.help = fPrintDoc(MLP.nb_params)
|
|
588
|
-
MLP.neurons.help = fPrintDoc(MLP.neurons)
|
|
589
|
-
MLP.Create_MLP.help = fPrintDoc(MLP.Create_MLP)
|
|
590
|
-
MLP.plot.help = fPrintDoc(MLP.plot)
|
|
591
|
-
MLP.train.help = fPrintDoc(MLP.train)
|