Il s'agit du code source et du modèle pré-entraîné pour la démo de webcam pix2pix que j'ai publiée récemment sur Twitter et Vimeo. Il utilise l'apprentissage en profondeur, ou pour ajouter quelques mots à la mode : autoencodeur de réseau contradictoire génératif conditionnel profond à convolution .
vidéo 1
vidéo 2
Le code de ce dépôt particulier n'a en réalité rien à voir avec pix2pix, les GAN ou même l'apprentissage en profondeur. Il charge simplement n'importe quel modèle Tensorflow pré-entraîné (à condition qu'il respecte quelques contraintes), lui transmet une entrée webcam traitée et affiche la sortie du modèle. Il se trouve que le modèle que j'ai formé et utilisé est pix2pix (détails ci-dessous).
C'est-à-dire que les étapes peuvent être résumées comme suit :
J'ai récupéré des collections d'art du monde entier grâce au Google Art Project sur wikimedia. La plupart des images sont des portraits classiques de riches hommes blancs, j'ai donc utilisé seulement environ 150 collections, en essayant de garder les données aussi diverses géographiquement et culturellement que possible (la liste complète que j'ai utilisée est ici). Mais les données restent très centrées sur l’euro, puisqu’il peut y avoir des centaines ou des milliers de scans provenant d’un seul musée européen, mais seulement 8 scans provenant d’un musée arabe.
J'ai téléchargé les versions 300px des images et exécuté un processus batch pour :
J'ai également exécuté un processus par lots pour effectuer plusieurs recadrages à partir des images (au lieu d'un redimensionnement non uniforme), mais je ne me suis pas encore formé à cela. Au lieu d'une détection astucieuse des bords, j'ai également commencé à étudier la bien meilleure «détection des bords holistiquement imbriquée» (alias HED) de Xie et Tu (telle qu'utilisée par l'article pix2pix original), mais je ne me suis pas encore entraîné à cela non plus.
Ceci est fait par le script preprocess.py (désolé, pas d'arguments de ligne de commande, modifiez le script pour modifier les chemins et les paramètres, cela devrait être assez explicite).
Un petit échantillon des données d'entraînement, y compris les prédictions du modèle entraîné, peut être consulté ici. La colonne la plus à droite est l'image originale, la colonne la plus à gauche est la version prétraitée. Ces deux images sont introduites dans le réseau pix2pix sous forme de « paire » sur lesquelles elles doivent être formées. La colonne du milieu est ce que le modèle apprend à produire étant donné uniquement la colonne la plus à gauche . (Les images montrent chaque itération d'entraînement - c'est-à-dire le nombre à gauche, qui va de 20 000 à 58 000, donc il s'améliore progressivement au fur et à mesure que l'on avance dans la page).
J'ai également formé un GAN inconditionnel (c'est-à-dire un DCGAN normal sur ces mêmes données de formation. Un exemple de sa sortie peut être vu ci-dessous. (Cela génère des images « complètement aléatoires » qui ressemblent aux données de formation).
La formation et l'architecture sont directement « Traduction d'image à image avec des réseaux contradictoires conditionnels » par Isola et al (alias pix2pix). Je me suis entraîné avec le port tensorflow de @affinelayer (Christopher Hesse), qui alimente également cette démo « sketch-to-cat » qui est devenue virale récemment. Il a également écrit un joli tutoriel sur le fonctionnement de pix2pix. Un merci infini aux auteurs (et à tous ceux sur lesquels ils ont construit) pour avoir rendu leur code open source !
Je n'ai apporté qu'une infime modification au code de formation tensorflow-pix2pix, à savoir ajouter tf.Identity aux entrées et sorties du générateur avec un nom lisible par l'homme, afin que je puisse alimenter et récupérer facilement les tenseurs. Donc, si vous souhaitez utiliser vos propres modèles avec cette application, vous devrez faire de même . (Ou notez les noms des tenseurs d'entrée/sortie et modifiez le json en conséquence, plus d'informations à ce sujet ci-dessous).
Vous pouvez télécharger mon modèle pré-entraîné à partir de l'onglet Releases.
Cette application particulière charge le modèle pré-entraîné, effectue un prétraitement en direct d'une entrée webcam et la transmet au modèle. Je fais le prétraitement avec la vision par ordinateur de base à l'ancienne, en utilisant opencv. C'est vraiment très minimal et basique. Vous pouvez voir l'interface graphique ci-dessous (l'interface graphique utilise pyqtgraph).
Différentes scènes nécessitent des paramètres différents.
Par exemple, pour « action en direct », j'ai trouvé astucieux de fournir de meilleurs résultats (à mon humble avis), et c'est ce que j'ai utilisé dans la première vidéo en haut. Les seuils (canny_t1, canny_t2) dépendent de la scène, de la quantité de détails et de l'apparence souhaitée.
Si vous avez beaucoup de bruit dans votre image, vous souhaiterez peut-être ajouter un tout petit peu de pre_blur ou pre_median . Ou jouez avec eux pour un « effet artistique ». Par exemple, dans la première vidéo, vers 1h05-1h40, j'ajoute une tonne de médiane (valeurs autour de 30-50).
Pour dessiner des scènes (par exemple, deuxième vidéo), j'ai trouvé que le seuil adaptatif donnait des résultats plus intéressants que Canny (c'est-à-dire désactiver Canny et activer le seuil adaptatif), bien que vous puissiez être en désaccord.
Pour une entrée complètement statique (c'est-à-dire si vous gelez la capture, désactivant la mise à jour de la caméra), la sortie est susceptible de scintiller très légèrement car le modèle fait des prédictions différentes pour la même entrée - bien que cela soit généralement assez subtil. Cependant, pour un flux de caméra en direct , le bruit dans l'entrée est susceptible de créer beaucoup de scintillement dans la sortie, notamment en raison de la forte susceptibilité du seuil astucieux ou adaptatif au bruit, donc un certain flou temporel peut aider.
accum_w1 et accum_w2 sont destinés au flou temporel de l'entrée, avant d'entrer dans le modèle : new_image = old_image * w1 + new_image * w2 (donc idéalement, ils devraient totaliser un - ou presque).
Prediction.pre_time_lerp et post_time_lerp effectuent également un lissage temporel : new_image = old_image * xxx_lerp + new_image * (1 - xxx_lerp) pre_time_lerp est avant d'entrer dans le modèle et post_time_lerp est après la sortie du modèle.
Zéro pour l'un des flous temporels les désactive. Les valeurs de ceux-ci dépendent de vos goûts. Pour les deux vidéos ci-dessus, tous les flous pre_model (c'est-à-dire accum_w1, accum_w2 et pre_time_lerp) étaient réglés sur zéro et j'ai joué avec différents paramètres post_time_lerp allant de 0,0 (très scintillant et clignotant) à 0,9 (très lent et fade et « rêveur »). ). Habituellement, environ 0,5 à 0,8 est ma plage préférée.
Si vous souhaitez utiliser un modèle différent, vous devez configurer un fichier JSON similaire à celui ci-dessous. La motivation ici est que j'ai en fait un tas de JSON dans mon dossier app/models que je peux analyser et recharger dynamiquement, et les données du modèle sont stockées ailleurs sur d'autres disques, et l'application peut charger et échanger entre les modèles au moment de l'exécution et à l'échelle. entrées/sorties etc automatiquement.
{
"name" : "gart_canny_256", # name of the model (for GUI)
"ckpt_path" : "./models/gart_canny_256", # path to saved model (meta + checkpoints). Loads latest if points to a folder, otherwise loads specific checkpoint
"input" : { # info for input tensor
"shape" : [256, 256, 3], # expected shape (height, width, channels) EXCLUDING batch (assumes additional axis==0 will contain batch)
"range" : [-1.0, 1.0], # expected range of values
"opname" : "generator/generator_inputs" # name of tensor (':0' is appended in code)
},
"output" : { # info for output tensor
"shape" : [256, 256, 3], # shape that is output (height, width, channels) EXCLUDING batch (assumes additional axis==0 will contain batch)
"range" : [-1.0, 1.0], # value range that is output
"opname" : "generator/generator_outputs" # name of tensor (':0' is appended in code)
}
}
Testé uniquement sur Ubuntu 16.04, mais devrait fonctionner sur d'autres plateformes.
J'utilise la distribution Anaconda python qui contient presque tout ce dont vous avez besoin, alors c'est (j'espère) aussi simple que :
Téléchargez et installez anaconda depuis https://www.continuum.io/downloads
Installez tensorflow https://www.tensorflow.org/install/ (Ce qui - si vous avez anaconda - est souvent assez simple puisque la plupart des dépendances sont incluses)
Installez opencv et pyqtgraph
conda install -c menpo opencv3 conda install pyqtgraph
Un merci infini encore une fois à