web-dev-qa-db-fra.com

Keras utilise beaucoup trop de mémoire GPU pour appeler train_on_batch, fit, etc.

Je me suis moqué de Keras et je l'aime jusqu'à présent. Je rencontre un gros problème lorsque je travaille avec des réseaux assez profonds: lorsque vous appelez model.train_on_batch, ou model.fit, etc., Keras alloue nettement plus de mémoire GPU que ce dont le modèle aurait besoin. Ce n'est pas en essayant de s'entraîner sur de très grandes images, c'est le modèle de réseau lui-même qui semble nécessiter beaucoup de mémoire GPU. J'ai créé cet exemple de jouet pour montrer ce que je veux dire. Voici essentiellement ce qui se passe:

Je crée d’abord un réseau assez profond, puis utilise model.summary () pour obtenir le nombre total de paramètres nécessaires au réseau (dans ce cas, 206538153, ce qui correspond à environ 826 Mo). J'utilise ensuite nvidia-smi pour voir combien de mémoire GPU a été allouée par Keras, et je constate que cela est parfaitement logique (849 Mo).

Je compile ensuite le réseau et peux confirmer que cela n'augmente pas l'utilisation de la mémoire du processeur graphique. Et comme on peut le voir dans ce cas, il me reste presque 1 Go de VRAM disponible.

Ensuite, j'essaie de transmettre une image 16x16 simple et une vérité au sol 1x1 au réseau, puis tout explose, car Keras commence à allouer à nouveau beaucoup de mémoire, sans aucune raison qui m'est évidente. Quelque chose à propos de la formation du réseau semble nécessiter beaucoup plus de mémoire que celle d'avoir le modèle, ce qui n'a pas de sens pour moi. J'ai formé des réseaux beaucoup plus profonds sur ce GPU dans d'autres frameworks, ce qui me fait penser que j'utilise mal Keras (ou que quelque chose ne va pas dans ma configuration ou dans Keras, mais bien sûr, il est difficile de savoir avec certitude).

Voici le code:

from scipy import misc
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Activation, Convolution2D, MaxPooling2D, Reshape, Flatten, ZeroPadding2D, Dropout
import os

model = Sequential()

model.add(Convolution2D(256, 3, 3, border_mode='same', input_shape=(16,16,1)))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Convolution2D(512, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Convolution2D(256, 3, 3, border_mode='same'))
model.add(Convolution2D(32, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(4))
model.add(Dense(1))

model.summary()

os.system("nvidia-smi")
raw_input("Press Enter to continue...")    

model.compile(optimizer='sgd',
              loss='mse', 
              metrics=['accuracy'])

os.system("nvidia-smi")              
raw_input("Compiled model. Press Enter to continue...")

n_batches = 1
batch_size = 1
for ibatch in range(n_batches):
    x = np.random.Rand(batch_size, 16,16,1)
    y = np.random.Rand(batch_size, 1)

    os.system("nvidia-smi")
    raw_input("About to train one iteration. Press Enter to continue...")

    model.train_on_batch(x, y)         
    print("Trained one iteration")

Ce qui me donne la sortie suivante:

Using Theano backend.
Using gpu device 0: GeForce GTX 960 (CNMeM is disabled, cuDNN 5103)
/usr/local/lib/python2.7/dist-packages/theano/sandbox/cuda/__init__.py:600: UserWarning: Your cuDNN version is more recent than the one Theano officially supports. If you see any problems, try updating Theano or downgrading cuDNN to version 5.
  warnings.warn(warn)
____________________________________________________________________________________________________
Layer (type)                     Output Shape          Param #     Connected to                     
====================================================================================================
convolution2d_1 (Convolution2D)  (None, 16, 16, 256)   2560        convolution2d_input_1[0][0]      
____________________________________________________________________________________________________
maxpooling2d_1 (MaxPooling2D)    (None, 8, 8, 256)     0           convolution2d_1[0][0]            
____________________________________________________________________________________________________
convolution2d_2 (Convolution2D)  (None, 8, 8, 512)     1180160     maxpooling2d_1[0][0]             
____________________________________________________________________________________________________
maxpooling2d_2 (MaxPooling2D)    (None, 4, 4, 512)     0           convolution2d_2[0][0]            
____________________________________________________________________________________________________
convolution2d_3 (Convolution2D)  (None, 4, 4, 1024)    4719616     maxpooling2d_2[0][0]             
____________________________________________________________________________________________________
convolution2d_4 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_3[0][0]            
____________________________________________________________________________________________________
convolution2d_5 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_4[0][0]            
____________________________________________________________________________________________________
convolution2d_6 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_5[0][0]            
____________________________________________________________________________________________________
convolution2d_7 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_6[0][0]            
____________________________________________________________________________________________________
convolution2d_8 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_7[0][0]            
____________________________________________________________________________________________________
convolution2d_9 (Convolution2D)  (None, 4, 4, 1024)    9438208     convolution2d_8[0][0]            
____________________________________________________________________________________________________
convolution2d_10 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_9[0][0]            
____________________________________________________________________________________________________
convolution2d_11 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_10[0][0]           
____________________________________________________________________________________________________
convolution2d_12 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_11[0][0]           
____________________________________________________________________________________________________
convolution2d_13 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_12[0][0]           
____________________________________________________________________________________________________
convolution2d_14 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_13[0][0]           
____________________________________________________________________________________________________
convolution2d_15 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_14[0][0]           
____________________________________________________________________________________________________
convolution2d_16 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_15[0][0]           
____________________________________________________________________________________________________
convolution2d_17 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_16[0][0]           
____________________________________________________________________________________________________
convolution2d_18 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_17[0][0]           
____________________________________________________________________________________________________
convolution2d_19 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_18[0][0]           
____________________________________________________________________________________________________
convolution2d_20 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_19[0][0]           
____________________________________________________________________________________________________
convolution2d_21 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_20[0][0]           
____________________________________________________________________________________________________
convolution2d_22 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_21[0][0]           
____________________________________________________________________________________________________
convolution2d_23 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_22[0][0]           
____________________________________________________________________________________________________
convolution2d_24 (Convolution2D) (None, 4, 4, 1024)    9438208     convolution2d_23[0][0]           
____________________________________________________________________________________________________
maxpooling2d_3 (MaxPooling2D)    (None, 2, 2, 1024)    0           convolution2d_24[0][0]           
____________________________________________________________________________________________________
convolution2d_25 (Convolution2D) (None, 2, 2, 256)     2359552     maxpooling2d_3[0][0]             
____________________________________________________________________________________________________
convolution2d_26 (Convolution2D) (None, 2, 2, 32)      73760       convolution2d_25[0][0]           
____________________________________________________________________________________________________
maxpooling2d_4 (MaxPooling2D)    (None, 1, 1, 32)      0           convolution2d_26[0][0]           
____________________________________________________________________________________________________
flatten_1 (Flatten)              (None, 32)            0           maxpooling2d_4[0][0]             
____________________________________________________________________________________________________
dense_1 (Dense)                  (None, 4)             132         flatten_1[0][0]                  
____________________________________________________________________________________________________
dense_2 (Dense)                  (None, 1)             5           dense_1[0][0]                    
====================================================================================================
Total params: 206538153
____________________________________________________________________________________________________
None
Thu Oct  6 09:05:42 2016       
+------------------------------------------------------+                       
| NVIDIA-SMI 352.63     Driver Version: 352.63         |                       
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 960     Off  | 0000:01:00.0      On |                  N/A |
| 30%   37C    P2    28W / 120W |   1082MiB /  2044MiB |      9%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0      1796    G   /usr/bin/X                                     155MiB |
|    0      2597    G   compiz                                          65MiB |
|    0      5966    C   python                                         849MiB |
+-----------------------------------------------------------------------------+
Press Enter to continue...
Thu Oct  6 09:05:44 2016       
+------------------------------------------------------+                       
| NVIDIA-SMI 352.63     Driver Version: 352.63         |                       
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 960     Off  | 0000:01:00.0      On |                  N/A |
| 30%   38C    P2    28W / 120W |   1082MiB /  2044MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0      1796    G   /usr/bin/X                                     155MiB |
|    0      2597    G   compiz                                          65MiB |
|    0      5966    C   python                                         849MiB |
+-----------------------------------------------------------------------------+
Compiled model. Press Enter to continue...
Thu Oct  6 09:05:44 2016       
+------------------------------------------------------+                       
| NVIDIA-SMI 352.63     Driver Version: 352.63         |                       
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 960     Off  | 0000:01:00.0      On |                  N/A |
| 30%   38C    P2    28W / 120W |   1082MiB /  2044MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0      1796    G   /usr/bin/X                                     155MiB |
|    0      2597    G   compiz                                          65MiB |
|    0      5966    C   python                                         849MiB |
+-----------------------------------------------------------------------------+
About to train one iteration. Press Enter to continue...
Error allocating 37748736 bytes of device memory (out of memory). Driver report 34205696 bytes free and 2144010240 bytes total 
Traceback (most recent call last):
  File "memtest.py", line 65, in <module>
    model.train_on_batch(x, y)         
  File "/usr/local/lib/python2.7/dist-packages/keras/models.py", line 712, in train_on_batch
    class_weight=class_weight)
  File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 1221, in train_on_batch
    outputs = self.train_function(ins)
  File "/usr/local/lib/python2.7/dist-packages/keras/backend/theano_backend.py", line 717, in __call__
    return self.function(*inputs)
  File "/usr/local/lib/python2.7/dist-packages/theano/compile/function_module.py", line 871, in __call__
    storage_map=getattr(self.fn, 'storage_map', None))
  File "/usr/local/lib/python2.7/dist-packages/theano/gof/link.py", line 314, in raise_with_op
    reraise(exc_type, exc_value, exc_trace)
  File "/usr/local/lib/python2.7/dist-packages/theano/compile/function_module.py", line 859, in __call__
    outputs = self.fn()
MemoryError: Error allocating 37748736 bytes of device memory (out of memory).
Apply node that caused the error: GpuContiguous(GpuDimShuffle{3,2,0,1}.0)
Toposort index: 338
Inputs types: [CudaNdarrayType(float32, 4D)]
Inputs shapes: [(1024, 1024, 3, 3)]
Inputs strides: [(1, 1024, 3145728, 1048576)]
Inputs values: ['not shown']
Outputs clients: [[GpuDnnConv{algo='small', inplace=True}(GpuContiguous.0, GpuContiguous.0, GpuAllocEmpty.0, GpuDnnConvDesc{border_mode='half', subsample=(1, 1), conv_mode='conv', precision='float32'}.0, Constant{1.0}, Constant{0.0}), GpuDnnConvGradI{algo='none', inplace=True}(GpuContiguous.0, GpuContiguous.0, GpuAllocEmpty.0, GpuDnnConvDesc{border_mode='half', subsample=(1, 1), conv_mode='conv', precision='float32'}.0, Constant{1.0}, Constant{0.0})]]

HINT: Re-running with most Theano optimization disabled could give you a back-trace of when this node was created. This can be done with by setting the Theano flag 'optimizer=fast_compile'. If that does not work, Theano optimizations can be disabled with 'optimizer=None'.
HINT: Use the Theano flag 'exception_verbosity=high' for a debugprint and storage map footprint of this apply node.

Quelques points à noter: 

  • J'ai essayé les deux backends Theano et TensorFlow. Tous deux ont les mêmes problèmes et manquent de mémoire sur la même ligne. Dans TensorFlow, il semble que Keras préalloue beaucoup de mémoire (environ 1,5 Go), de sorte que nvidia-smi ne nous aide pas à suivre ce qui se passe là-bas, mais les mêmes exceptions de mémoire insuffisante me sont appliquées. Encore une fois, ceci pointe vers une erreur dans (mon utilisation de) Keras (bien qu'il soit difficile d'être certain de telles choses, cela pourrait être quelque chose avec ma configuration).
  • J'ai essayé d'utiliser CNMEM dans Theano, qui se comporte comme TensorFlow: il préalloue une grande quantité de mémoire (environ 1,5 Go) mais se bloque au même endroit.
  • Il y a quelques avertissements concernant la version CudNN. J'ai essayé d'exécuter le backend Theano avec CUDA mais pas CudNN et j'ai eu les mêmes erreurs, donc ce n'est pas la source du problème.
  • Si vous souhaitez tester cela sur votre propre GPU, vous pouvez rendre le réseau plus profond/moins profond en fonction de la quantité de mémoire GPU nécessaire pour le tester.
  • Ma configuration est la suivante: Ubuntu 14.04, GeForce GTX 960, CUDA 7.5.18, CudNN 5.1.3, Python 2.7, Keras 1.1.0 (installé via pip).
  • J'ai essayé de changer la compilation du modèle pour utiliser différents optimiseurs et pertes, mais cela ne semble rien changer.
  • J'ai essayé de changer la fonction train_on_batch pour qu'elle utilise plutôt fit, mais le problème est le même.
  • J'ai vu une question similaire ici sur StackOverflow - Pourquoi ce modèle Keras requiert-il plus de 6 Go de mémoire? - mais pour autant que je sache, je n’ai pas ces problèmes dans ma configuration. Je n'ai jamais eu plusieurs versions de CUDA installées et j'ai vérifié deux fois plus mes variables PATH, LD_LIBRARY_PATH et CUDA_ROOT que je ne peux en compter.
  • Julius a suggéré que les paramètres d'activation utilisent eux-mêmes la mémoire GPU. Si cela est vrai, quelqu'un peut-il l'expliquer un peu plus clairement? J'ai essayé de remplacer la fonction d'activation de mes couches de convolution par des fonctions clairement codées en dur, sans aucun paramètre pouvant être appris, pour autant que je sache, et cela ne change rien. En outre, il semble peu probable que ces paramètres utilisent presque autant de mémoire que le reste du réseau.
  • Après des tests approfondis, le plus grand réseau que je peux former représente environ 453 Mo de paramètres, sur environ 2 Go de mémoire vive du GPU. Est-ce normal? 
  • Après avoir testé les keras sur des CNN plus petits qui tiennent dans mon GPU, je constate qu'il y a des pointes très soudaines dans l'utilisation du GPU RAM. Si je gère un réseau avec environ 100 Mo de paramètres, 99% du temps utilisé pendant l’entraînement consomme moins de 200 Mo de RAM GPU. Mais de temps en temps, l'utilisation de la mémoire atteint environ 1,3 Go. Il semble prudent de supposer que ce sont ces pics qui causent mes problèmes. Je n'ai jamais vu ces pics dans d'autres cadres, mais ils pourraient être là pour une bonne raison? Si quelqu'un sait ce qui les cause, et s'il y a un moyen de les éviter, merci de le signaler!
31
Martin

C'est une erreur très courante d'oublier que les activations et les gradients prennent également vram, pas seulement les paramètres, ce qui augmente considérablement l'utilisation de la mémoire. Les calculs de backprob font en sorte que la phase d’entraînement utilise presque le double de la VRAM de l’utilisation directe/inférence du réseau neuronal.

Ainsi, au début de la création du réseau, seuls les paramètres sont attribués. Cependant, lorsque la formation commence, les activations (temps de chaque minibatch) sont allouées, ainsi que les calculs de backprop, ce qui augmente l'utilisation de la mémoire.

15
Jules G.M.

Theano et Tensorflow augmentent le graphe symbolique créé, mais les deux différemment. 

Pour analyser la consommation de mémoire, commencez avec un modèle plus petit et augmentez-le pour afficher la croissance correspondante en mémoire. De même, vous pouvez agrandir le batch_size pour voir la croissance correspondante en mémoire.

Voici un extrait de code pour augmenter batch_size en fonction de votre code initial:

from scipy import misc
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Activation, Convolution2D, MaxPooling2D, Reshape, Flatten, ZeroPadding2D, Dropout
import os
import matplotlib.pyplot as plt


def gpu_memory():
    out = os.popen("nvidia-smi").read()
    ret = '0MiB'
    for item in out.split("\n"):
        if str(os.getpid()) in item and 'python' in item:
            ret = item.strip().split(' ')[-2]
    return float(ret[:-3])

gpu_mem = []
gpu_mem.append(gpu_memory())

model = Sequential()
model.add(Convolution2D(100, 3, 3, border_mode='same', input_shape=(16,16,1)))
model.add(Convolution2D(256, 3, 3, border_mode='same'))
model.add(Convolution2D(32, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(4))
model.add(Dense(1))

model.summary()
gpu_mem.append(gpu_memory())

model.compile(optimizer='sgd',
              loss='mse', 
              metrics=['accuracy'])
gpu_mem.append(gpu_memory())


batches = []
n_batches = 20
batch_size = 1
for ibatch in range(n_batches):
    batch_size = (ibatch+1)*10
    batches.append(batch_size)
    x = np.random.Rand(batch_size, 16,16,1)
    y = np.random.Rand(batch_size, 1)
    print y.shape

    model.train_on_batch(x, y)         
    print("Trained one iteration")

    gpu_mem.append(gpu_memory())

fig = plt.figure()
plt.plot([-100, -50, 0]+batches, gpu_mem)
plt.show()

De plus, pour la vitesse, Tensorflow exploite toute la mémoire GPU disponible. Pour arrêter cela, vous devez ajouter config.gpu_options.allow_growth = True dans get_session()

# keras/backend/tensorflow_backend.py
def get_session():
    global _SESSION
    if tf.get_default_session() is not None:
        session = tf.get_default_session()
    else:
        if _SESSION is None:
            if not os.environ.get('OMP_NUM_THREADS'):
                config = tf.ConfigProto(allow_soft_placement=True,
                    )
            else:
                nb_thread = int(os.environ.get('OMP_NUM_THREADS'))
                config = tf.ConfigProto(intra_op_parallelism_threads=nb_thread,
                                        allow_soft_placement=True)
            config.gpu_options.allow_growth = True
            _SESSION = tf.Session(config=config)
        session = _SESSION
    if not _MANUAL_VAR_INIT:
        _initialize_variables()
    return session

Maintenant, si vous exécutez l'extrait précédent, vous obtenez des tracés tels que:

Theano:  Theano Tensorflow:  Tenserflow

Theano: Après model.compile() quelle que soit la mémoire utilisée, au début de l’entraînement, le nombre de doublons est presque atteint. Cela est dû au fait que Theano augmente le graphe symbolique pour effectuer une propagation en arrière et que chaque tenseur a besoin d'un tenseur correspondant pour obtenir le flux en arrière des gradients. Les besoins en mémoire ne semblent pas croître avec batch_size et ceci est inattendu pour moi car la taille de l'espace réservé devrait augmenter pour prendre en charge le flux de données provenant de CPU-> GPU.

Tensorflow: aucune mémoire GPU n'est allouée même après model.compile() car Keras n'appelle pas get_session() jusqu'à cette heure qui appelle réellement _initialize_variables(). Tensorflow semble encombrer la mémoire par morceaux pour la vitesse et la mémoire ne croît donc pas linéairement avec batch_size.

Cela dit, Tensorflow semble avoir faim de mémoire, mais pour les grands graphiques, il est très rapide. Par contre, Theano est très efficace en mémoire mais prend beaucoup de temps à initialiser le graphique au début de la formation. Après c'est aussi assez rapide. 

12
indraforyou

200M params pour 2 Gb GPU est trop. De plus, votre architecture n'est pas efficace, l'utilisation des goulets d'étranglement locaux sera plus efficace .Vous devriez également passer du petit modèle au grand, et non pas en arrière, vous avez maintenant une entrée 16x16, avec cette architecture qui signifie qu'au bout du compte le réseau sera "rempli à zéro" et non basé sur les entités en entrée . Vos couches de modèle dépendent de votre entrée, vous ne pouvez donc pas définir un nombre arbitraire de couches et de tailles, vous devez compter le nombre de données transmises à chacune d'elles. , avec la compréhension pourquoi le faisons ... Je vous recommande de regarder ce cours gratuit http://cs231n.github.io

0
Andrey Nikishaev