Bonjour à tous,

j'essaie de développer un Conditionnal GAN sous Python afin de générer des volumes 3D de taille (32,32,32) voir (64,64,64) si possible car la taille peut limiter mon pc pour l'apprentissage en terme de mémoire.

J'ai donc besoin d'entrainer simultanément un Generator "G" et Disciminateur "D" afin que ce premier puisse tromper ce dernier, incapable de reconnaître une image réelle et une générée par G.
Mon soucis concerne l'entrainement car,

- la fonction de perte de D converge très très vite vers 0 au bout de quelques epoques,
- la fonction de perte du GAN fait un peu n'importe quoi. Elle est cappable de tendre vers 0 puis de sauter vers une valeur quelconque et de ne plus bouger.

De ce que je comprends, le discriminateur apprend très bien la distinction entre volumes réels et ceux générer, ce qui me vient à dire que le G est trop faible et D trop fort en termes de performances. J'ai sincèrement l'impression que mon code est correct mais je ne comprends pas comment cettfonction de perte peut tendre direct vers 0, et donc créer un entrainement inutil de la part du GAN. voici G et D ainsi que GAN :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def define_generator(latent_dim, n_classes=2):
 
    # label input
    in_label = Input(shape=(1,))
 
    # embedding for categorical input
    li = Embedding(n_classes, 2)(in_label)
 
    # linear multiplication
    # n_nodes = int(size/8) * int(size/8) * int(size/8)
    n_nodes = 1
    li = Dense(n_nodes)(li)
 
    # reshape to additional channel
    # li = Reshape((int(size/8), int(size/8), int(size/8), 1))(li)
 
    # image generator input
    in_lat = Input(shape=(latent_dim,))
 
    # foundation for 4x4 image
    n_nodes = int(size/8) * int(size/8) * int(size/8)
    gen = Dense(n_nodes)(in_lat)
    gen = LeakyReLU(alpha=0.2)(gen)
    gen = Reshape((int(size/8), int(size/8), int(size/8), 1))(gen)
 
    # merge image gen and label input
    merge = Concatenate()([gen, li])
 
    # upsample to 8x8
    gen = Conv3DTranspose(8, (4, 4, 4), strides=(2, 2, 2), padding='same')(merge)
    fe = BatchNormalization(3)(gen)
    gen = LeakyReLU(alpha=0.2)(fe)
 
    # upsample to 16x16
    gen = Conv3DTranspose(16, (4, 4, 4), strides=(2, 2, 2), padding='same')(gen)
    fe = BatchNormalization(3)(gen)
    gen = LeakyReLU(alpha=0.2)(fe)
 
    # upsample to 32x32
    gen = Conv3DTranspose(32, (4, 4, 4), strides=(2, 2, 2), padding='same')(gen)
    fe = BatchNormalization(3)(gen)
    gen = LeakyReLU(alpha=0.2)(fe)
 
    # output
    out_layer = Conv3D(1, (2, 2, 2), activation='softmax', padding='same')(gen)
    # out_layer = Conv3DTranspose(1, (3, 3, 3), strides=(2, 2, 2), padding='same')(gen)
 
    # define model
    model = Model([in_lat, in_label], out_layer)
 
 
    return model
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
def define_discriminator(in_shape=(size, size, size, 1), n_classes=2):
 
    # label input
    in_label = Input(shape=(1,))
 
    # embedding for categorical input
    li = Embedding(n_classes, 2)(in_label)
 
    # scale up to image dimensions with linear activation
    # n_nodes = in_shape[0] * in_shape[1] * in_shape[2]
    n_nodes = 1
    li = Dense(n_nodes)(li)
 
    # reshape to additional channel
    # li = Reshape((in_shape[0], in_shape[1], in_shape[2], 1))(li)
 
    # image input
    in_image = Input(shape=in_shape)
 
    # concat label as a channel
    merge = Concatenate()([in_image, li])
 
    # downsample
    fe = Conv3D(32, (4, 4, 4), strides=(2, 2, 2), padding='same')(merge)
    fe = BatchNormalization(3)(fe)
    fe = LeakyReLU(alpha=0.2)(fe)
 
    # downsample
    fe = Conv3D(16, (4, 4, 4), strides=(2, 2, 2), padding='same')(fe)
    fe = BatchNormalization(3)(fe)
    fe = LeakyReLU(alpha=0.2)(fe)
 
    # downsample
    fe = Conv3D(8, (4, 4, 4), strides=(2, 2, 2), padding='same')(fe)
    fe = BatchNormalization(3)(fe)
    fe = LeakyReLU(alpha=0.2)(fe)
 
    # flatten feature maps
    fe = Flatten()(fe)
 
    # dropout
    fe = Dropout(0.1)(fe)
 
    # output
    out_layer = Dense(1, activation='sigmoid')(fe)
 
    # define model
    model = Model([in_image, in_label], out_layer)
 
    # compile model
    opt = Adam()
    model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])
 
 
    return model

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def define_gan(g_model, d_model):
 
    # make weights in the discriminator not trainable
    d_model.trainable = False
 
    # get noise and label inputs from generator model
    gen_noise, gen_label = g_model.input
 
    # get image output from the generator model
    gen_output = g_model.output
 
    # connect image output and label input from generator as inputs to discriminator
    gan_output = d_model([gen_output, gen_label])
 
    # define gan model as taking noise and label and outputting a classification
    model = Model([gen_noise, gen_label], gan_output)
 
    # compile model
    opt = Adam()
    model.compile(loss='binary_crossentropy', optimizer=opt)
 
    return model

J'ai deux classes de volumes, c'est pourquoi n_classes admet la valeur 2.

Aussi, mes volumes ne possedent que la valeur 0, 1 ou 2. c'est à dire qu'il semble possible de faire un One-Hot-encoding mais je ne vois pas bien comment l'integrer. En effet après entrainement, mes volumes possedent des valeurs reelles entre 0 et 1 mais pas 0 1 ou 2.

Si quelqu'un peut m'aider !

Merci de votre aide