Rêver plus loin avec Deep Dream

La semaine dernière, lorsque j’ai présenté Google Deep Dream, il a fallu que je prenne une décision éditoriale afin de garder le billet dans une taille raisonnable. Configurer Docker et mettre en place le nécessaire pour « rêver » sur sa première image était déjà une bouchée raisonnable à mastiquer, à mon avis.

Alors, une fois que vous avez Deep Dream, que pouvez-vous faire de plus? DE LA SCIENCE!

Le code source

La plateforme utilisée par Deep Dream pour exécuter le code source permettant de faire fonctionner la machine à rêver est IPython. IPython permet, notamment, d’exécuter de façon interactive du code source Python à même votre navigateur web.

En particulier, avec l’exemple de Deep Dream, des explications sont fournies pour chaque extrait de code source que vous serez invité à exécuter. Parlant de code source, j’ai extrait le code de la page interactive de Deep Dream afin que vous puissiez voir une idée de ce que cela représente.


# imports and basic notebook setup
from cStringIO import StringIO
import numpy as np
import scipy.ndimage as nd
import PIL.Image
from IPython.display import clear_output, Image, display
from google.protobuf import text_format
import caffe
def showarray(a, fmt='jpeg'):
a = np.uint8(np.clip(a, 0, 255))
f = StringIO()
PIL.Image.fromarray(a).save(f, fmt)
display(Image(data=f.getvalue()))
model_path = '/src/bvlc_googlenet/' # substitute your path here
net_fn = model_path + 'deploy.prototxt'
param_fn = model_path + 'bvlc_googlenet.caffemodel'
# Patching model to be able to compute gradients.
# Note that you can also manually add "force_backward: true" line to "deploy.prototxt".
model = caffe.io.caffe_pb2.NetParameter()
text_format.Merge(open(net_fn).read(), model)
model.force_backward = True
open('tmp.prototxt', 'w').write(str(model))
net = caffe.Classifier('tmp.prototxt', param_fn,
mean = np.float32([104.0, 116.0, 122.0]), # ImageNet mean, training set dependent
channel_swap = (2,1,0)) # the reference model has channels in BGR order instead of RGB
# a couple of utility functions for converting to and from Caffe's input image layout
def preprocess(net, img):
return np.float32(np.rollaxis(img, 2)[::-1]) – net.transformer.mean['data']
def deprocess(net, img):
return np.dstack((img + net.transformer.mean['data'])[::-1])
def make_step(net, step_size=1.5, end='inception_5b/5x5_reduce', jitter=32, clip=True):
'''Basic gradient ascent step.'''
src = net.blobs['data'] # input image is stored in Net's 'data' blob
dst = net.blobs[end]
ox, oy = np.random.randint(-jitter, jitter+1, 2)
src.data[0] = np.roll(np.roll(src.data[0], ox, -1), oy, -2) # apply jitter shift
net.forward(end=end)
dst.diff[:] = dst.data # specify the optimization objective
net.backward(start=end)
g = src.diff[0]
# apply normalized ascent step to the input image
src.data[:] += step_size/np.abs(g).mean() * g
src.data[0] = np.roll(np.roll(src.data[0], -ox, -1), -oy, -2) # unshift image
if clip:
bias = net.transformer.mean['data']
src.data[:] = np.clip(src.data, -bias, 255-bias)
def deepdream(net, base_img, iter_n=10, octave_n=4, octave_scale=1.4, end='inception_5b/5x5_reduce', clip=True, **step_params):
# prepare base images for all octaves
octaves = [preprocess(net, base_img)]
for i in xrange(octave_n-1):
octaves.append(nd.zoom(octaves[-1], (1, 1.0/octave_scale,1.0/octave_scale), order=1))
src = net.blobs['data']
detail = np.zeros_like(octaves[-1]) # allocate image for network-produced details
for octave, octave_base in enumerate(octaves[::-1]):
h, w = octave_base.shape[-2:]
if octave > 0:
# upscale details from the previous octave
h1, w1 = detail.shape[-2:]
detail = nd.zoom(detail, (1, 1.0*h/h1,1.0*w/w1), order=1)
src.reshape(1,3,h,w) # resize the network's input image size
src.data[0] = octave_base+detail
for i in xrange(iter_n):
make_step(net, end=end, clip=clip, **step_params)
# visualization
vis = deprocess(net, src.data[0])
if not clip: # adjust image contrast if clipping is disabled
vis = vis*(255.0/np.percentile(vis, 99.98))
showarray(vis)
print octave, i, end, vis.shape
clear_output(wait=True)
# extract details produced on the current octave
detail = src.data[0]-octave_base
# returning the resulting image
return deprocess(net, src.data[0])
# Show and assign the image
img = np.float32(PIL.Image.open('/src/<img>.jpg'))
showarray(img)
# Dream
_=deepdream(net, img)
# Dream with layer
_=deepdream(net, img, end='inception_3a/output')
# Display keys
net.blobs.keys()
# loop dream
!mkdir frames
frame = img
frame_i = 0
h, w = frame.shape[:2]
s = 0.05 # scale coefficient
for i in xrange(100):
frame = deepdream(net, frame, end='inception_4e/5×5')
PIL.Image.fromarray(np.uint8(frame)).save("frames/%04d.jpg"%frame_i)
frame = nd.affine_transform(frame, [1-s,1-s,1], [h*s/2,w*s/2,0], order=1)
frame_i += 1

view raw

dd.py

hosted with ❤ by GitHub

Je ne crois pas que vous devez être vraiment familier avec Python pour comprendre le fonctionnement sommaire de ce code. La principale chose à savoir avec Python est que l’indentation va servir à identifier un bloc d’exécution. Alors, pas d’accolades comme en C# avec Python.

Des jeux de données supplémentaires

Lorsque vous exécutez Deep Dream dans la machine virtuelle Docker de mon billet précédent, un jeu de données nommé bvlc_googlenet est utilisé. Ce jeu de modèle, mis en place par Google, est reconnu pour sa capacité à reconnaître et classer des images.

Si vous êtes du genre à pousser l’expérience un peu plus loin, vous pouvez télécharger ces modèles de données et les exécuter sur votre instance Deep Dream. Par exemple, bvlc_googlenet et bvlc_alexnet servent des buts différents et donnent des résultants qui sont, en conséquent, différents.

Voici les étapes pour y arriver:

  1. Cloner le repository git https://github.com/BVLC/caffe.git
  2. Copier le contenu du dossier /Models/ dans /deepdream (le répertoire où vous avez mappé le répertoire /src dans la commande de démarrage du conteneur Docker dans les instructions du précédent billet)
  3. Pour chaque jeu de données, se référer aux instructions pour télécharger le fichier à l’extension .caffemodel et le déposer à la racine du dossier du jeu de données que vous désirez utiliser.

Pour modifier le code précédemment cité, afin de faire fonctionner des jeux de données différents, vous devez ajuster les bouts de code suivants:

  • La variable model_path: afin d’y spécifier le répertoire de votre jeu de données (portez attention à l’emplacement débutant par /src
  • La variable param_fn: spécifiez-y le nom de votre fichier .caffemodel
  • La fonction make_step: modifiez le contenu du paramètre end pour un des layers de votre jeu de données. Pour trouver le nom d’un layer, consultez le fichier deploy.prototxt de votre jeu de données. Il s’agit d’un fichier JSON qui contient la définition des layers à votre disposition
  • La fonction deepdream: idem au point précédent.
  • La variable img: spécifiez le nom de l’image que vous désirez utiliser.

Faites de beaux rêves!

S’éclater avec Google Deep Dream

Connaissez-vous Google Deep Dream? Il s’agit du nom donné à une technologie fascinante qui a donné lieu à des avancées remarquées dernièrement. En particulier pour l’identification d’images et de reconnaissance de la voix.

Ce qui est particulier avec Deep Dream est l’algorithme utilisé pour alimenter l’engin. Question de citer Wikipédia : un réseau de neurones artificiels est un modèle de calcul dont la conception est très schématiquement inspirée du fonctionnement des neurones biologiques.

Vous l’avez lu. Deep Dream est basé sur une technologie inspirée du fonctionnement humain. Pour faire simple, il s’agit d’un algorithme qui apprend et classifie selon les différents intrants qui sont mis à sa disposition grâce à des calculs statistiques. C’est par là que s’en va le futur!

Deep Dream, grâce à ses images psychédéliques, a donné un peu de popularité au concept de réseau de neurones artificiel. Cependant, il ne s’agit pas d’un concept nouveau. Ces algorithmes sont déjà utilisés dans divers champs d’application comme à la bourse ou même en météorologie.

L’autre facteur qui a donné de la visibilité à Deep Dream est la possibilité d’exécuter le code sur sa propre machine. La plateforme est basée sur un framework de Deep Learning nommée Caffe. Vous vous doutez surement que je n’ai pas résisté à la tentation de l’exécuter sur ma propre machine, n’est-ce pas?

Installation de Deep Dream

Le plus simple pour exécuter Deep Dream à partir de votre propre ordinateur est d’avoir recours à une machine virtuelle Linux qui exécutera Docker pour héberger le nécessaire.

Dans le cas où vous ne connaissez pas Docker, il s’agit d’une plateforme de virtualisation d’applications qui fonctionne sous le concept de conteneurs partageant les ressources du système hôte. Vous trouverez plus d’informations au sujet de Docker ici.

Le principal avantage que j’ai trouvé à avoir recours à Docker est d’avoir accès à des conteneurs préparés par la communauté que vous pouvez utiliser pour vos besoins.

Alors donc, dans l’ordre, pour exécuter Deep Dream sur votre machine vous devez:

À partir de cet instant, vous avez Docker sur votre machine virtuelle Linux. Cependant, ce n’est qu’un début, car vous devez maintenant mettre en place un conteneur Docker avec tout ce qu’il faut pour Deep Dream.

Pour configurer un conteneur Docker pour Deep Dream, j’ai eu recours aux instructions de Ryan Kennedy:

  • S’assurer que Docker est en fonction : sudo service docker start
  • Exécuter la commande docker pull ryankennedyio/deepdream
  • Attendre
  • Attendre
  • Attendre
  • Démarrer le conteneur avec la commande: docker run -d -p 443:8888 -e « PASSWORD=password  » -v /docker:/src ryankennedyio/deepdream

Voilà! Vous avez maintenant accès à Deep Dream à partir de votre machine virtuelle Linux. C’est bien beau Docker mais comment y accéder? Il y a quelques détails que vous devez savoir à partir de cet instant.

Notes sur la commande docker run

Afin de vous sauver quelques recherches sur la signification des arguments envoyés à la commande docker run, voici un résumé de ce que vous devez savoir.

  • L’argument -p 443:8888 redirige les requêtes faites au port 443 (HTTPS) vers le port 8888
  • Le mot de passe pour accéder à votre conteneur est « password »
  • À partir de votre conteneur, le dossier « /src » sera mappé au dossier « /docker » de l’hôte. Ceci veut dire que c’est dans ce dernier que vous devrez déposer vos propres images.

Récupérer l’adresse IP locale de votre conteur Docker

Lorsque vous démarrer un conteneur Docker, un identifiant unique lui est associé. Prenez-le en note et exécuter la commande sudo docker inspect <CID> | grep IPAddress | cut -d ‘ »‘ -f 4 où <CID> est l’identifiant unique.

Dans le cas où vous n’avez pas noté cet identifiant, vous pouvez le récupérer avec la commande sudo docker ps vous aurez maintenant dans la colonne « NAMES » l’identifiant unique en question.

 

deepdream

Une fois que vous aurez trouvé votre adresse IP accédez-y en tapant l’URL suivante: https://IP:8888/tree. Félicitations! Vous pouvez maintenant exécuter Deep Dream en cliquant sur dream.ipynb.

Quelques rêves

J’ai fait quelques Deep Dream depuis que j’ai procédé à ma propre installation de docker. Je vous laisse contempler le résultat. Pour vous donner une idée, ces images sont toutes basées sur mon image de profil Twitter.

Faites de beaux rêves!