Dans cet article, je présenterai une collection de conseils pour accélérer l'apprentissage profond avec PyTorch annoncé par NVIDIA.
Cet article a été annoncé par Arun Mallya de NVIDIA, 「PyTorch Performance Tuning Guide - Szymon Migacz, NVIDIA」 J'expliquerai en ajoutant des explications et des programmes à.
Le but de cet article est exactement ce qu'Andrew Karpathy marmonne sur Twitter.
good quick tutorial on optimizing your PyTorch code ⏲️: https://t.co/7CIDWfrI0J
— Andrej Karpathy (@karpathy) August 30, 2020
quick summary: pic.twitter.com/6J1SJcWJsl
Je vais expliquer cela d'une manière facile à comprendre.
※Andrej Karpathy A obtenu un doctorat du Dr Fay Fay Lee qui a préparé ImageNet Actuellement directeur du département IA de Tesla La performance humaine avec ImageNet a un taux d'erreur de 5%, mais pour obtenir ce résultat, la personne qui a contesté ImageNet, ce qui a été fait par le représentant humain
Le contenu décrit dans cet article dépend de l'environnement GPU que vous utilisez.
Essayez de voir lequel fonctionne pour votre environnement.
Tous les programmes de cet article https://github.com/YutaroOgawa/Qiita/tree/master/pytorch_performance Il est ouvert au public au.
Il est au format Jupyter Notebook.
Dans cet article, vous pouvez facilement vérifier [Performance change] au moment de "MNIST training 1 epoch".
Le DataLoader de PyTorch a deux choses, les paramètres par défaut ne sont pas très bons. https://pytorch.org/docs/stable/data.html
1.1 num_workers
Tout d'abord, l'argument est par défaut num_workers = 0
.
En conséquence, la récupération du mini-lot est un processus unique.
En définissant num_workers = 2
etc., cela devient un chargement de données multi-processus et le traitement s'accélère.
Vous pouvez vérifier le nombre de cœurs de processeur ci-dessous.
#Vérifiez le nombre de cœurs de processeur
import os
os.cpu_count() #Nombres de coeurs
Quant au nombre de cœurs, 2 suffisent pour 1 GPU.
Créez un DataLoader comme suit.
#Pour Data Loader avec les paramètres par défaut
train_loader_default = torch.utils.data.DataLoader(dataset1,batch_size=mini_batch_size)
test_loader_default = torch.utils.data.DataLoader(dataset2,batch_size=mini_batch_size)
#Chargeur de données: 2
train_loader_nworker = torch.utils.data.DataLoader(
dataset1, batch_size=mini_batch_size, num_workers=2)
test_loader_nworker = torch.utils.data.DataLoader(
dataset2, batch_size=mini_batch_size, num_workers=2)
#Chargeur de données: plein
train_loader_nworker = torch.utils.data.DataLoader(
dataset1, batch_size=mini_batch_size, num_workers=os.cpu_count())
test_loader_nworker = torch.utils.data.DataLoader(
dataset2, batch_size=mini_batch_size, num_workers=os.cpu_count())
[Changement de performance] Vérifiez le changement de performance à l'époque de la formation MNIST 1.
#Vérifier le GPU
!nvidia-smi
Vous pouvez vérifier le GPU de l'environnement d'utilisation avec.
Cette fois, ● Cas 1: p3.2xlarge (NVIDIA® VOLTA V100 Tensor Core GPU) ● Cas 2: Google Colaboratory (Tesla Turing T4 Tensor Core GPU)
Ce sera. Veuillez noter que Google Colaboratory a un type de GPU différent à chaque fois.
[Par défaut] ● Cas 1: p3.2xlarge: 14,73 secondes ● Cas 2: Google Colaboratory: 10,01 secondes
[Dans le cas de num_workers = os.cpu_count ()] ● Cas 1: p3.2xlarge: 3,47 secondes ● Cas 2: Google Colaboratory: 9,43 secondes
Les deux sont plus rapides, mais le cas 1 est très rapide, jusqu'à environ 1/3.
Notez que p3.2xlarge a 8 cœurs de processeur et Goole Colaboratory a 2 cœurs de processeur.
Cependant, le nombre de cœurs est de 2 et num_workers = 2 donne une impression suffisante.
Même dans l'annonce originale, il semble qu'il n'y ait pas beaucoup de différence entre 2 et plus.
1.2 pin_memory
Le DataLoader de PyTorch utilise par défaut l'argument pin_memory = False
.
** L'épinglage automatique de la mémoire ** peut être utilisé en définissant pin_memory = True
.
La zone de mémoire du processeur ne sera pas paginée, ce qui devrait s'accélérer.
(référence) https://pytorch.org/docs/stable/data.html#memory-pinning https://zukaaax.com/archives/301 https://developer.nvidia.com/blog/how-optimize-data-transfers-cuda-cc/
(Explication de la pagination de la mémoire) https://wa3.i-3-i.info/word13352.html
La mise en œuvre est la suivante.
#Pour Data Loader avec les paramètres par défaut
train_loader_default = torch.utils.data.DataLoader(dataset1,batch_size=mini_batch_size)
test_loader_default = torch.utils.data.DataLoader(dataset2,batch_size=mini_batch_size)
#Mémoire des broches du chargeur de données
train_loader_pin_memory = torch.utils.data.DataLoader(
dataset1, batch_size=mini_batch_size, pin_memory=True)
test_loader_pin_memory = torch.utils.data.DataLoader(
dataset2, batch_size=mini_batch_size, pin_memory=True)
Comme précédemment, vérifiez le changement de performance à l'époque de la formation MNIST 1.
[Par défaut] ● Cas 1: p3.2xlarge: 14,73 secondes ● Cas 2: Google Colaboratory: 10,01 secondes
[Lorsque pin_memory = True] ● Cas 1: p3.2xlarge: 13,65 secondes ● Cas 2: Google Colaboratory: 9,82 secondes
[Dans le cas de num_workers = os.cpu_count ()] ● Cas 1: p3.2xlarge: 3,47 secondes ● Cas 2: Google Colaboratory: 9,43 secondes
[Lorsque num_workers = os.cpu_count () & pin_memory = True] ● Cas 1: p3.2xlarge: 3,50 secondes ● Cas 2: Google Colaboratory: 9,35 secondes
Par rapport aux paramètres par défaut, vous pouvez voir que c'est plus rapide.
Si num_workers est défini, l'échelle de ce MNIST est trop petite ou l'effet de pin_memory ne peut pas être vu.
[1] Lors de la création d'un DataLoader avec PyTorch, modifiez les arguments num_workers et pin_memory et implémentez comme suit.
#Configuration par défaut
train_loader_default = torch.utils.data.DataLoader(dataset1,batch_size=mini_batch_size)
test_loader_default = torch.utils.data.DataLoader(dataset2,batch_size=mini_batch_size)
#Chargeur de données recommandé
train_loader_pin_memory = torch.utils.data.DataLoader(
dataset1, batch_size=mini_batch_size, num_workers=os.cpu_count(), pin_memory=True)
test_loader_pin_memory = torch.utils.data.DataLoader(
dataset2, batch_size=mini_batch_size, num_workers=os.cpu_count(), pin_memory=True)
#Ou chargeur de données num_workers=2
train_loader_pin_memory = torch.utils.data.DataLoader(
dataset1, batch_size=mini_batch_size, num_workers=2, pin_memory=True)
test_loader_pin_memory = torch.utils.data.DataLoader(
dataset2, batch_size=mini_batch_size, num_workers=2, pin_memory=True)
Assurez-vous d'exécuter torch.backends.cudnn.benchmark = True
lors de la formation.
Cela optimise et accélère les calculs de réseau côté GPU lorsque la forme du réseau est fixe.
Définissez sur True si la taille d'entrée des données ne change pas au début ou au milieu comme un CNN normal.
Cependant, veuillez noter que la reproductibilité du calcul sera perdue.
(À propos de la reproductibilité des calculs de PyTorch) https://pytorch.org/docs/stable/notes/randomness.html
La mise en œuvre est la suivante, par exemple.
def MNIST_train_cudnn_benchmark_True(optimizer, model, device, train_loader, test_loader):
#Formation par défaut
epochs = 1
#ajouter à
torch.backends.cudnn.benchmark = True
#En traitement
for epoch in range(1, epochs+1):
train(model, device, train_loader, optimizer, epoch)
test(model, device, test_loader)
Ici, la fonction train () a la forme suivante.
def train(model, device, train_loader, optimizer, epoch):
model.train() #En mode entraînement
for batch_idx, (data, target) in enumerate(train_loader):
#Récupération de données
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
#propagation
output = model(data)
#Calcul des pertes et rétro-propagation
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
Comparez les vitesses. Laissez le chargeur de données sur le paramètre par défaut.
[Par défaut] ● Cas 1: p3.2xlarge: 14,73 secondes ● Cas 2: Google Colaboratory: 10,01 secondes
[Lorsque torch.backends.cudnn.benchmark = True] ● Cas 1: p3.2xlarge: 14,47 secondes ● Cas 2: Google Colaboratory: 9,66 secondes
Cette fois, je résous uniquement MNIST, donc le réseau est petit, donc cet effet est faible, mais c'est un peu plus rapide.
** Entrez torch.backends.cudnn.benchmark = True
lors de l'exécution du programme **
Plus la taille du mini-lot est grande, plus l'apprentissage est stable. Par conséquent, augmentons la taille du mini lot.
Avec la fonction ** AMP (Automatic Mixed Precision) ** de PyTorch, il existe des cas où une taille de mini-lot plus grande que le calcul attendu est réellement possible.
AMP (Automatic Mixed Precision) signifie la précision du mélange.
Normalement, il est calculé avec FP32 (virgule flottante 32 bits), mais la moitié de FP16 (virgule flottante 16 bits) est une fonction qui économise l'utilisation de la mémoire et améliore la vitesse de calcul sans compromettre la précision.
De plus, si le GPU a un cœur Tensor, il sera 8 à 16 fois plus rapide que deux fois. (Jusqu'à 12 fois pour l'entraînement, jusqu'à 6 fois pour le raisonnement)
(référence) https://www.nvidia.com/ja-jp/data-center/tensor-cores/
Le V100 Volta est équipé du noyau TENSOR 1ère génération. La série T est équipée du noyau TURING TENSOR 2ème génération. On dit que la 2ème génération de noyau TURING TENSOR est environ deux fois plus rapide que la 1ère génération.
Cliquez ici pour des explications sur son utilisation.
(référence) https://pytorch.org/blog/accelerating-training-on-nvidia-gpus-with-pytorch-automatic-mixed-precision/ https://pytorch.org/docs/stable/notes/amp_examples.html
Mettre en œuvre selon les exemples ci-dessus.
Réécrivez le test de fonction précédent ().
def train_PyTorchAMP(model, device, train_loader, optimizer, epoch):
model.train() #En mode entraînement
scaler = torch.cuda.amp.GradScaler()
for batch_idx, (data, target) in enumerate(train_loader):
#Récupération de données
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
#propagation
# Runs the forward pass with autocasting.
with torch.cuda.amp.autocast():
output = model(data)
loss = F.nll_loss(output, target)
# Scales loss. Calls backward() on scaled loss to create scaled gradients.
scaler.scale(loss).backward()
# scaler.step() first unscales the gradients of the optimizer's assigned params.
scaler.step(optimizer)
# Updates the scale for next iteration.
scaler.update()
Créez un scaler avec scaler = torch.cuda.amp.GradScaler ()
et encapsulez les mises à jour avant, perte, rétropropagation et paramètres avec scaler.
Définissez DataLoader comme paramètre par défaut et utilisez AMP pour comparer les vitesses.
[Par défaut] ● Cas 1: p3.2xlarge: 14,73 secondes ● Cas 2: Google Colaboratory: 10,01 secondes
[Pour AMP] ● Cas 1: p3.2xlarge: 14,21 secondes ● Cas 2: Google Colaboratory: 11,97 secondes
Dans ce MNIST, le montant d'un calcul est petit, donc je n'ai pas ressenti beaucoup d'effet.
En utilisant cet AMP, il est possible d'augmenter la taille du mini-lot plus que prévu, mais Veuillez tenir compte des points suivants à noter lors de l'augmentation de la taille du mini-lot.
[1] Ajustement de la valeur du taux d'apprentissage [2] Ajustement de la décroissance du poids: L'ampleur des pénalités de l'optimiseur [3] Incorporer l'échauffement dans l'apprentissage: Dans les premiers stades de l'apprentissage, le taux d'apprentissage est progressivement augmenté linéairement de 0 à un certain niveau. [4] Incorporer la dégradation du taux d'apprentissage dans l'apprentissage: réduire progressivement le taux d'apprentissage à la fin de l'apprentissage
De plus, pour les gros mini-lots, envisagez d'utiliser LARS, LAMB, LAMB NVLAMB de NVIDIA, etc. pour l'optimiseur.
Pour les grands mini-lots
** Sur le même laps de temps, le nombre total d'époques sera inférieur à celui lorsque la taille du mini-lot est petite. Si vous augmentez simplement le taux d'apprentissage pour le compenser, cette fois le taux d'apprentissage sera trop élevé et il sera difficile de stabiliser l'entraînement **
Arrivera.
Par conséquent, LARS (Layerwise Adaptive Rate Scaling) est une méthode de multiplication du taux d'apprentissage par un coefficient appelé «rapport de confiance» en fonction du gradient.
De plus, LAMB (Layer -wise Adaptive Moments optimizer for Batch training) est une méthode d'optimisation qui prend en compte le taux de changement de chaque paramètre de poids pour chaque époque dans LARS.
En utilisant LAMB, l'apprentissage BERT, qui prend normalement 81 heures, peut être accéléré à 76 minutes, ce qui est environ 100 fois plus rapide.
Large Batch Optimization for Deep Learning: Training BERT in 76 minutes https://arxiv.org/abs/1904.00962
(Tiré du guide NVIDIA sur l'implémentation de l'optimiseur pour BERT à grande échelle)
(référence) https://medium.com/nvidia-ai/a-guide-to-optimizer-implementation-for-bert-at-scale-8338cc7f45fd https://developer.nvidia.com/blog/pretraining-bert-with-layer-wise-adaptive-learning-rates/ https://postd.cc/optimizing-gradient-descent/ https://towardsdatascience.com/an-intuitive-understanding-of-the-lamb-optimizer-46f8c0ae4866
Tout d'abord, installez apex en vous référant à la page NVIDIA APEX (A PyTorch Extension).
https://github.com/NVIDIA/apex https://nvidia.github.io/apex/
$ git clone https://github.com/NVIDIA/apex
$ cd apex
$ pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" ./
La mise en œuvre est la suivante. Tout d'abord, réécrivez train ().
from apex import amp
def trainAMP(model, device, train_loader, optimizer, epoch):
model.train() #En mode entraînement
for batch_idx, (data, target) in enumerate(train_loader):
#Récupération de données
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
#propagation
output = model(data)
#Calcul des pertes et rétro-propagation
loss = F.nll_loss(output, target)
# AMP Train your model
with amp.scale_loss(loss, optimizer) as scaled_loss:
scaled_loss.backward()
optimizer.step()
Ensuite, écrivez une fonction d'apprentissage en utilisant trainAMP ().
def MNIST_trainAMP(optimizer, model, device, train_loader, test_loader):
epochs = 1
start = time.time()
torch.backends.cudnn.benchmark = True
#En traitement
for epoch in range(1, epochs+1):
trainAMP(model, device, train_loader, optimizer, epoch)
test(model, device, test_loader)
#Temps pris
print("=======Temps pris========")
print(time.time() - start)
Définissez l'optimiseur sur apex.optimizers.FusedLAMB. Le LAMBA de NVIDIA s'appelle NVLAMB.
import apex
#Définir le modèle, le taux d'apprentissage et l'optimiseur
model = Net().to(device)
lr_rate = 0.1
optimizer = apex.optimizers.FusedLAMB(model.parameters(), lr=lr_rate)
# Initialization
opt_level = 'O1'
model, optimizer = amp.initialize(model, optimizer, opt_level=opt_level)
Initialisez le modèle et l'optimiseur avec AMP.
Enfin, nous effectuerons des formations.
MNIST_trainAMP(optimizer, model, device,
train_loader_pin_memory, test_loader_pin_memory)
Voilà comment utiliser l'optimiseur LAMB de NVIDIA pour les gros mini-lots.
Lors de l'entraînement avec Multi-GPU
Pas le torch.nn.DataParallel
de DATAPARALLEL
DISTRIBUTEDDATAPARALLEL torch.nn.parallel.DistributedDataParallel
Utilisez le.
C'est comme la diapositive de la conférence ci-dessous En effet, DATA PARALLEL n'utilise qu'un seul cœur du processeur. S'il s'agit de DISTRIBUTEDDATAPARALLEL, 1 cœur de processeur est alloué à 1 GPU.
En outre, APEX ʻapex.parallel.DistributedDataParallel de NVIDIA peut être utilisé de la même manière que
torch.nn.parallel.DistributedDataParallel`, mais avec ses avantages.
Autrement dit, ʻapex.parallel.DistributedDataParallel` de NVIDIA est maintenant ** Normalisation de lots synchronisés **.
Dans le cas du multi-GPU, la couche de normalisation par lots de PyTorch effectue une normalisation par lots dans un mini-lot attribué à chaque GPU, calcule la moyenne et l'écart type pour chaque GPU, et les moyenne pour faire la moyenne de la normalisation du lot. Apprenons l'écart type.
Cela s'appelle ** Normalisation de lots asynchronisée ** car elle effectue une normalisation par lots pour chaque GPU.
La normalisation par lots et les résultats des calculs pour toutes les données distribuées sur le multi-GPU changeront.
Dans le cas de PyToch, il existe une stratégie pour utiliser torch.nn.SyncBatchNorm
, mais c'est assez compliqué à mettre en œuvre.
Utilisation de l'APEX de NVIDIA ʻapex.parallel.DistributedDataParallel`
sync_bn_model = apex.parallel.convert_syncbn_model(model)
Convertissez simplement le modèle avec pour obtenir la * normalisation synchronisée des lots **.
(référence) https://nvidia.github.io/apex/parallel.html https://github.com/NVIDIA/apex/tree/master/apex/parallel https://github.com/NVIDIA/apex/tree/master/examples/simple/distributed
Attachez le [email protected] à la fonction de l'opération individuelle au tenseur et faites-le PyToch JIT (format d'exécution C ++) Accélérez.
JIT (Just-In-Time Compiler) est un compilateur qui compile le code lorsque le logiciel est exécuté pour améliorer la vitesse d'exécution.
Tensorflow et Keras sont définis et exécutés, compilés puis exécutés (le code était difficile à écrire)
PyTorch est défini par exécution, qui construit des calculs tout en faisant circuler les données. Cependant, il est préférable de compiler d'abord les fonctions de calcul fixes, utilisez donc JIT pour en faire un format d'exécution C ++ (fonctionne à partir de Python).
Par exemple, lorsque vous souhaitez définir la fonction d'activation gelu, la définition normale et la définition dans JIT sont les suivantes.
def gelu(x):
return x * 0.5 * (1.0 + torch.erf(x / 1.41421))
@torch.jit.script
def fused_gelu(x):
return x * 0.5 * (1.0 + torch.erf(x / 1.41421))
Pour créer PyTorch JIT, attachez le décorateur @ torch.jit.script
à la fonction.
En comparant la vitesse d'exécution de ceci,
import time
x = torch.randn(2000, 3000)
start = time.time()
for i in range(200):
gelu(x)
#Temps pris
print("=======Temps pris========")
print(time.time() - start)
Quand
import time
x = torch.randn(2000, 3000)
start = time.time()
for i in range(200):
fused_gelu(x)
#Temps pris
print("=======Temps pris========")
print(time.time() - start)
Puis
● Cas 1: p3.2xlarge (NVIDIA® VOLTA V100 Tensor Core GPU)
Donc, 9,8 secondes → 6,6 secondes
● Cas 2: Google Colaboratory (Tesla Turing T4 Tensor Core GPU)
Puis 13,94 secondes → 13,91 secondes
était.
Il n'y a pratiquement aucun changement dans Google Colaboratory, mais dans AWS p3.2xlarge, le temps est réduit à environ 60%.
Lors de l'utilisation d'un modèle ne nécessitant pas de rétropropagation pour une partie de l'ensemble, comme pour le calcul du GAN,
model.zero_grad()
ne pas,
for param in model.parameters():
param.grad = None
Définissez le calcul du dégradé sur Aucun avec. En effet, model.zero_grad () consomme en fait une zone mémoire.
Si vous standardisez avec la normalisation par lots et que vous la moyennez à 0, alors s'il y a un paramètre de biais dans la couche précédente, la normalisation par lots apprendra également un terme constant pour l'annuler.
Puisqu'il s'agit d'une perte de temps de calcul et de quantité de calcul, le paramètre de biais doit être défini sur Faux pour la couche avant la normalisation du lot, et le terme de biais ne doit pas être utilisé.
Le DataLoader de PyTorch utilise par défaut l'argument pin_memory = False
, mais vous pouvez utiliser ** l'épinglage de mémoire automatique ** en définissant pin_memory = True
.
La zone de mémoire du processeur ne sera pas paginée, ce qui devrait s'accélérer.
La mise en œuvre à ce moment était la suivante.
#Chargeur de données recommandé
train_loader_pin_memory = torch.utils.data.DataLoader(
dataset1, batch_size=mini_batch_size, num_workers=os.cpu_count(), pin_memory=True)
test_loader_pin_memory = torch.utils.data.DataLoader(
dataset2, batch_size=mini_batch_size, num_workers=os.cpu_count(), pin_memory=True)
Désormais, pour des vitesses encore plus rapides, activez les copies GPU asynchrones.
Parce que, comme c'est ** Le CPU ne peut pas fonctionner pendant le transfert de données de la mémoire épinglée du CPU vers le GPU **.
Utilisez donc le paramètre non_blocking = True
.
Ensuite, le processeur peut fonctionner même lors du transfert de la mémoire épinglée vers le GPU, et une accélération est attendue.
La mise en œuvre est simple, réécrivant la partie qui envoie les données à cuda.
for batch_idx, (data, target) in enumerate(train_loader):
#Récupération de données
data, target = data.to(device), target.to(device)
À
# non_blocking=True
for batch_idx, (data, target) in enumerate(train_loader):
#Récupération de données
data, target = data.to(device, non_blocking=True), target.to(device, non_blocking=True)
Et donnez l'argument non_blocking = True
dans à ().
référence https://stackoverflow.com/questions/55563376/pytorch-how-does-pin-memory-works-in-dataloader https://pytorch.org/docs/stable/notes/cuda.html#use-pinned-memory-buffers https://discuss.pytorch.org/t/should-we-set-non-blocking-to-true/38234 https://developer.nvidia.com/blog/how-optimize-data-transfers-cuda-cc/
Comparez quand non_blocking = True et quand ce n'est pas le cas (pin_memory = True uniquement).
● Cas 1: p3.2xlarge (NVIDIA® VOLTA V100 Tensor Core GPU)
Donc, 13,126 secondes → 13,125 secondes
● Cas 2: Google Colaboratory (Tesla P100-PCIE Tensor Core GPU) Cela a changé. C'est la même Tesla.
Donc, 8,370 secondes → 8,298 secondes
C'est devenu un peu plus rapide.
Ce qui précède a été exécuté avec num_workers = 0 de DataLoader, donc s'il est exécuté avec num_workers = 2,
● Cas 1: p3.2xlarge Donc, 6,843 secondes → 6,77 6 secondes
● Cas 2: Google Colaboratory Puis 8,059 secondes → 7,935 secondes
C'est aussi un peu plus rapide.
Étant donné que l'échelle est petite avec MNIST, il est difficile de voir les avantages, mais cela peut être significativement efficace pour le traitement compliqué et les données volumineuses qui sont lourdes pour le processeur.
Jusqu'à présent, nous avons présenté les conseils pour accélérer l'apprentissage et le raisonnement avec PyTorch.
Certaines techniques, dans le cas de Google Colaboratory, J'ai eu le sentiment: "Est-ce que quelque chose se passe dans les coulisses, est-ce que cela ne fonctionne pas ou est-ce que cela fonctionne automatiquement?"
D'un autre côté, je pense que cet article peut être utilisé de nombreuses manières lorsque vous configurez normalement une instance GPU dans le cloud et effectuez un apprentissage en profondeur avec PyTorch.
J'espère que vous en profiterez ♪
** [Auteur] ** Dentsu International Information Service (ISID) AI Transformation Center Development Gr Yutaro Ogawa (Livre principal "Apprendre en créant! Apprentissage en profondeur par PyTorch", etc. /github.com/YutaroOgawa/about_me))
【Twitter】 En me concentrant sur l'IT / IA et le business / management, j'envoie des articles que je trouve intéressants et des impressions de nouveaux livres que j'ai récemment lus. Si vous souhaitez collecter des informations sur ces champs, veuillez nous suivre ♪ (Il y a beaucoup d'informations à l'étranger)
** [Autre] ** L '«équipe de développement AI Transformation Center» que je dirige recherche des membres. Si vous êtes intéressé, veuillez visiter cette page pour postuler.
** [Sokumen-kun] ** Si vous souhaitez postuler soudainement, nous aurons un entretien informel avec "Sokumen-kun". Veuillez également l'utiliser ♪ https://sokumenkun.com/2020/08/17/yutaro-ogawa/
[Clause de non-responsabilité] Le contenu de cet article lui-même est l'opinion / la transmission de l'auteur, et non l'opinion officielle de la société à laquelle l'auteur appartient.
Recommended Posts