#!/usr/bin/env python3
# -*- coding: utf-8 -*-
__author__ = "Ponzoni, Nelson"
__copyright__ = "Copyright 2015"
__credits__ = ["Ponzoni Nelson"]
__maintainer__ = "Ponzoni Nelson"
__contact__ = "npcuadra@gmail.com"
__email__ = "npcuadra@gmail.com"
__license__ = "GPL"
__version__ = "1.0.0"
__status__ = "Production"
"""
modulo de graficos,
filtros, visualizaciones varias
"""
""" This file contains different utility functions that are not connected
in anyway to the networks presented in the tutorials, but rather help in
processing the outputs into a more understandable way.
For example ``tile_raster_images`` helps in generating a easy to grasp
image from a set of samples or weights.
"""
import os, itertools, numpy
from numpy import arange as npArange
from numpy import linspace as npLinspace
import math
from theano.tensor import dvector as Tdvector
from theano.tensor import cast as Tcast
from theano import function as Tfunction
from theano import config as Tconfig
theanoFloat = Tconfig.floatX
import theano.printing
try:
import PIL.Image as Image
except ImportError:
import Image
havedisplay = "DISPLAY" in os.environ
if not havedisplay:
exitval = os.system('python3 -c "import matplotlib.pyplot as plt; plt.figure()"')
havedisplay = (exitval == 0)
if havedisplay:
#import matplotlib.pyplot as plt
import matplotlib.pylab as plt
else:
#import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('Agg')
import matplotlib.pylab as plt
[documentos]def display_avalible():
"""
si se ejecuta en un servidor, retorna falso... (si no hay pantalla... )
util para el show del ploteo
"""
return ('DISPLAY' in os.environ)
[documentos]def scale_to_unit_interval(ndar, eps=1e-8):
""" Scales all values in the ndarray ndar to be between 0 and 1 """
ndar = ndar.copy()
ndar -= ndar.min()
ndar *= 1.0 / (ndar.max() + eps)
return ndar
[documentos]def imagenTiles(X, img_shape, tile_shape, tile_spacing=(0, 0),
scale_rows_to_unit_interval=True,
output_pixel_vals=True):
"""
Transform an array with one flattened image per row, into an array in
which images are reshaped and layed out like tiles on a floor.
This function is useful for visualizing datasets whose rows are images,
and also columns of matrices for transforming those rows
(such as the first layer of a neural net).
:type X: a 2-D ndarray or a tuple of 4 channels, elements of which can
be 2-D ndarrays or None;
:param X: a 2-D array in which every row is a flattened image.
:type img_shape: tuple; (height, width)
:param img_shape: the original shape of each image
:type tile_shape: tuple; (rows, cols)
:param tile_shape: the number of images to tile (rows, cols)
:param output_pixel_vals: if output should be pixel values (i.e. int8
values) or floats
:param scale_rows_to_unit_interval: if the values need to be scaled before
being plotted to [0,1] or not
:returns: array suitable for viewing as an image.
(See:`Image.fromarray`.)
:rtype: a 2-d array with same dtype as X.
"""
assert len(img_shape) == 2
assert len(tile_shape) == 2
assert len(tile_spacing) == 2
# The expression below can be re-written in a more C style as
# follows :
#
# out_shape = [0,0]
# out_shape[0] = (img_shape[0]+tile_spacing[0])*tile_shape[0] -
# tile_spacing[0]
# out_shape[1] = (img_shape[1]+tile_spacing[1])*tile_shape[1] -
# tile_spacing[1]
out_shape = [
(ishp + tsp) * tshp - tsp
for ishp, tshp, tsp in zip(img_shape, tile_shape, tile_spacing)
]
if isinstance(X, tuple):
assert len(X) == 4
# Create an output numpy ndarray to store the image
if output_pixel_vals:
out_array = numpy.zeros((out_shape[0], out_shape[1], 4),
dtype='uint8')
else:
out_array = numpy.zeros((out_shape[0], out_shape[1], 4),
dtype=X.dtype)
#colors default to 0, alpha defaults to 1 (opaque)
if output_pixel_vals:
channel_defaults = [0, 0, 0, 255]
else:
channel_defaults = [0., 0., 0., 1.]
for i in range(4):
if X[i] is None:
# if channel is None, fill it with zeros of the correct
# dtype
dt = out_array.dtype
if output_pixel_vals:
dt = 'uint8'
out_array[:, :, i] = numpy.zeros(
out_shape,
dtype=dt
) + channel_defaults[i]
else:
# use a recurrent call to compute the channel and store it
# in the output
out_array[:, :, i] = tile_raster_images(
X[i], img_shape, tile_shape, tile_spacing,
scale_rows_to_unit_interval, output_pixel_vals)
return out_array
else:
# if we are dealing with only one channel
H, W = img_shape
Hs, Ws = tile_spacing
# generate a matrix to store the output
dt = X.dtype
if output_pixel_vals:
dt = 'uint8'
out_array = numpy.zeros(out_shape, dtype=dt)
for tile_row in range(tile_shape[0]):
for tile_col in range(tile_shape[1]):
if tile_row * tile_shape[1] + tile_col < X.shape[0]:
this_x = X[tile_row * tile_shape[1] + tile_col]
if scale_rows_to_unit_interval:
# if we should scale values to be between 0 and 1
# do this by calling the `scale_to_unit_interval`
# function
this_img = scale_to_unit_interval(
this_x.reshape(img_shape))
else:
this_img = this_x.reshape(img_shape)
# add the slice to the corresponding position in the
# output array
c = 1
if output_pixel_vals:
c = 255
out_array[
tile_row * (H + Hs): tile_row * (H + Hs) + H,
tile_col * (W + Ws): tile_col * (W + Ws) + W
] = this_img * c
return out_array
[documentos]def dibujarFiltros(w, nombreArchivo=None, automatico=None, formaFiltro = None, binary=False, mostrar=None):
# dibujar lso filtros por orden de norma l2, de forma automatica. http://www.ehu.eus/izaballa/Ana_Matr/Transparencias/presen02-1x2.pdf
assert isinstance(formaFiltro, tuple), "Forma filtro debe ser una tupla (X,Y)"
# corrige si lo indico... sino es porque quiero asi, en modo auto es cuadrado
if automatico:
cantPesos = w.shape[0]
# ancho/alto tile es la cantidad dividido su raiz y tomando el floor
# a entero
anchoTile= int(cantPesos // math.sqrt(cantPesos))
cantPesosCorregido = anchoTile ** 2
if cantPesos != cantPesosCorregido:
cantPesos = cantPesosCorregido
formaImagen = (anchoTile, anchoTile)
image = Image.fromarray(
imagenTiles(
# se mandan las imagenes desde 0 a hasta donde cuadre
X=w.T[:,0:cantPesos],
img_shape=formaImagen,
tile_shape=formaFiltro,
tile_spacing=(1, 1)
)
)
if binary:
gray = image.convert('L')
# Let numpy do the heavy lifting for converting pixels to pure black or white
bw = numpy.asarray(gray).copy()
# Pixel range is 0...255, 256/2 = 128
bw[bw < 128] = 0 # Black
bw[bw >= 128] = 255 # White
# Now we put it back in Pillow/PIL land
image = Image.fromarray(bw)
# si le pase un nombre es porque lo quiero guardar
if nombreArchivo is not None:
image.save(nombreArchivo)
else:
nombreArchivo=''
if mostrar:
image.show(title=nombreArchivo)
return 0
[documentos]def dibujarCadenaMuestras(data, labels=None, chains=20, samples=10, gibbsSteps=1000, patchesDim=(28,28), binary=False):
data = theano.shared(numpy.asarray(a=data, dtype=theanoFloat), name='DataSample')
n_samples = data.get_value(borrow=True).shape[0]
# seleeciona de forma aleatoria donde comienza a extraer los ejemplos
# devuelve un solo indice.. desde [0,..., n - chains]
test_idx = self.numpy_rng.randint(n_samples - chains)
# inicializacion de todas las cadenas... el estado persiste a traves
# del muestreo
cadenaFija = theano.shared(
numpy.asarray(data.get_value(borrow=True)
[test_idx:test_idx + chains],
dtype=theanoFloat
)
)
# tengo leyenda sobre la imagen?
if labels is not None:
lista = range(test_idx, test_idx + chains)
print("labels: ", str(labels[lista]))
([_, _, _, _, probabilidad_V1, muestra_V1],
updates) = self.pasoGibbsVHV(self.x, gibbsSteps)
# cambiar el valor de la cadenaFija al de la reconstruccion de las visibles
updates.update({cadenaFija: muestra_V1})
# funcion princial
muestreo = theano.function(inputs=[],
outputs=[probabilidad_V1, muestra_V1],
updates=updates,
givens={self.x: cadenaFija},
name='muestreo'
)
# dimensiones de los patches, para el mnist es (28,28)
#ancho=28
#alto=28
alto, ancho = patchesDim
imageResults = numpy.zeros(((alto+1) * samples + 1, (ancho+1) * chains - 1),
dtype='uint8')
for idx in range(samples):
#genero muestras y visualizo cada gibssSteps, ya que las muestras intermedias
# estan muy correlacionadas, se visializa la probabilidad de activacion de
# las unidades ocultas (NO la muestra binomial)
probabilidad_V1, visiblerecons = muestreo()
print(' ... plotting sample {}'.format(idx))
imageResults[(alto+1) * idx:(ancho+1) * idx + ancho, :] \
= imagenTiles(X=probabilidad_V1,
img_shape=(alto, ancho),
tile_shape=(1, chains),
tile_spacing=(1, 1)
)
# construct image
image = Image.fromarray(imageResults)
nombreArchivo = self.ruta + "samples_" + str(labels[lista])
nombreArchivo = nombreArchivo.replace(" ", "_")
# poner las etiquetas sobre la imagen
watermark = False
if watermark:
from PIL import ImageDraw, ImageFont
# get the ImageDraw item for this image
draw = ImageDraw.Draw(image)
fontsize = 15
font = ImageFont.truetype("arial.ttf", fontsize)
#fill = (255,255,255) # blanco
fill = (255,255,0) # amarillo
fill = 255
draw.text((0, 0),text=str(labels[lista]),fill=fill,font=font)
if binary:
gray = image.convert('L')
# Let numpy do the heavy lifting for converting pixels to pure black or white
bw = numpy.asarray(gray).copy()
# Pixel range is 0...255, 256/2 = 128
bw[bw < 128] = 0 # Black
bw[bw >= 128] = 255 # White
# Now we put it back in Pillow/PIL land
image2 = Image.fromarray(bw)
image2.save(nombreArchivo + '_binary.pdf')
image.save(nombreArchivo + '.pdf')
return 0
[documentos]def filtrosConstructor(images, titulo, formaFiltro, nombreArchivo=None, mostrar=False, forzar=False):
assert False, "no usar"
# la forma de la imagen es inferida, debe ser cuadrada
# para el mnist es de 28,28 en la primer capa..
# si no es cuadra (cantidad de unidades no tiene raiz cuadrada exacta..)
# debe fallar, solo a que fuerce el plot
# TODO hace lo de formaImagen adaptativo... en caso de que no sea cuadrada perfecto agarrar lo que corresponda
entrada = images.shape[1] # 784 mnist
# cuadrado perfecto?
check = int(numpy.floor(numpy.mod(entrada,numpy.floor(numpy.power(entrada,1/2))**2)))
assert not (check!=0 and forzar), "Forma de la imagen no corresponde"
#tmp = int(numpy.floor(numpy.mod(entrada,numpy.floor(numpy.power(entrada,1/2))**2)))
#formaImagen = (tmp, tmp)
formaImagen = (int(numpy.power(entrada,1/2)) ,int(numpy.power(entrada,1/2)))
n_col, n_row = formaFiltro
#plt.figure(figsize=(2. * n_col, 2. * n_row))
plt.cla() # Clear axis
plt.clf() # Clear figure
plt.close("all") # Close a figure window
plt.figure(figsize=(12,12))
plt.title(titulo, size=16)
fig = plt.gcf()
DPI = fig.get_dpi()
fig.set_size_inches(1024.0/float(DPI),1024.0/float(DPI))
for i, comp in enumerate(images):
plt.subplot(n_row, n_col, i + 1)
plt.gca().set_aspect('equal', adjustable='box')
vmax = max(comp.max(), -comp.min())
plt.imshow(comp.reshape(formaImagen), cmap=plt.cm.gray,
vmin=-vmax, vmax=vmax)
plt.xticks(())
plt.yticks(())
#matplotlib.pyplot.tight_layout()
#plt.subplots_adjust(hspace = .001, wspace=.001, left=0.001)
#plt.subplots_adjust(wspace=.01, hspace=.01)
plt.subplots_adjust(0,0,1,1,0,0)
if nombreArchivo is not None:
#print("guardando los filtros en: " + nombreArchivo)
plt.savefig(nombreArchivo, bbox_inches='tight')
if mostrar:
plt.show()
return plt
[documentos]def pesosConstructor(pesos, nombreArchivo='pesos.png', mostrar=False):
"""
Grafica la matriz de pesos de (n_visible x n_ocultas) unidades
:param weight: matriz de pesos asociada a una RBM, cualquiera
"""
if not type(pesos) == numpy.array:
pesos = numpy.asarray(pesos)
from PIL import Image
image = Image.fromarray(pesos * 256).show()
assert False
fig, ax = plt.subplots()
cax = ax.imshow(weight, interpolation='nearest', cmap=matplotlib.cm.binary)
plt.xlabel('# Hidden Neurons')
plt.ylabel('# Visible Neurons')
# Add colorbar, make sure to specify tick locations to match desired ticklabels
cbar = fig.colorbar(cax)
cbar.ax.set_yticklabels(['0', '','','','','','','','1']) # el color bar tiene 10 posiciones para los ticks
plt.title('Weight Matrix')
if save is not None and path is None: # corrigo la direccion en caso de no proporcionarla y si guardar
path = ''
if save == 'png' or save is True:
plt.savefig(path + "weightMatrix" + ".png", format='png')
elif save == 'eps':
plt.savefig(path + 'weightMatrix' + '.eps', format='eps', dpi=1000)
elif save == 'svg':
plt.savefig(path + 'weightMatrix' + '.svg', format='svg', dpi=1000)
else:
pass
plt.show()
return 1
[documentos]def dibujarFnActivacionTheano(self, axe=None, axis=[-10.0, 10.0],
axline=[0.0, 0.0], mostrar=True):
if axe is None:
axe = plt.gca()
Xaxis = npArange(axis[0], axis[1], 0.01)
Yaxis = self(Xaxis)
x = Tdvector('x')
s = Tcast(self(x), dtype=theanoFloat)
dibujador=Tfunction(inputs=[x], outputs=s)
axe.plot(Xaxis, dibujador(Xaxis), color='red', linewidth=2.0)
# lineas horizontales y verticales
axe.axhline(axline[0], linestyle='-.', color='blue', linewidth=1.5)
axe.axvline(axline[1], linestyle='-.', color='blue', linewidth=1.5)
plt.title(self.__str__())
plt.grid(True)
plt.show() if mostrar else None
return axe
[documentos]def dibujarFnActivacionNumpy(self, axe=None, axis=[-10.0, 10.0],
axline=[0.0, 0.0], mostrar=True):
if axe is None:
axe = plt.gca()
Xaxis = npArange(axis[0], axis[1], 0.01)
Yaxis = self(Xaxis)
axe.plot(Xaxis, Yaxis, color='red', linewidth=2.0)
# lineas horizontales y verticales
axe.axhline(axline[0], linestyle='-.', color='blue', linewidth=1.5)
axe.axvline(axline[1], linestyle='-.', color='blue', linewidth=1.5)
plt.title(self.__str__())
plt.grid(True)
plt.show() if mostrar else None
return axe
# colores para los grafos, puedo cambiar lo que quiera del diccionario y pasarlo
default_colorCodes = {'GpuFromHost':'red',
'HostFromGpu':'red',
'Scan': 'yellow',
'Shape': 'brown',
'IfElse': 'magenta',
'Elemwise': '#FFAABB', # dark pink
'Subtensor': '#FFAAFF', # purple
'Alloc': '#FFAA22', # orange
'Output': 'lightblue'}
[documentos]def dibujarGrafoTheano(graph, nombreArchivo=None):
"""
dibuja el grafo de theano (funciones, scans, nodes, etc)
"""
if nombreArchivo is None:
nombreArchivo = "grafo_simbolico_theano.pdf"
theano.printing.pydotprint( fct=graph,
outfile=nombreArchivo,
format='pdf',
compact=True, # no imprime variables sin nombre
with_ids=True, # numero de nodos
high_contrast=True,
scan_graphs=True, # imprime los scans
cond_highlight=True,
var_with_name_simple=True, #si la variable tiene nombre, solo imprime eso
colorCodes=default_colorCodes) # codigo de colores
return 1
[documentos]def dibujarCostos(**kwargs):
"""
kwargs['axe']=axe de matplotlib
kwargs['mostrar']= plot el dibujo
kwargs['costoTRN']= arra con el costo del entrenamiento
kwargs['costoVAL']= array con el costo de validacion
kwargs['costoTST']= array con el costo de testing
kwargs['']=
kwargs['']=
"""
# configuraciones
if 'axe' in kwargs:
axe = kwargs['axe']
else:
plt.cla()
axe = plt.gca()
if 'mostrar' in kwargs.keys():
mostrar = kwargs['mostrar']
else:
mostrar = False
if 'costoTRN' in kwargs.keys():
axe.plot(kwargs['costoTRN'], color='black', linewidth=2.0, label='Costo Entrenamiento')
if 'costoVAL' in kwargs.keys():
axe.plot(kwargs['costoVAL'], color='blue', linewidth=2.0, label='Costo Validacion')
if 'costoTST' in kwargs.keys():
# para el mlp rapido, no estan todos los valores
linea = '' if numpy.isinf(kwargs['costoTST']).any() else '-'
marcador = '*' if numpy.isinf(kwargs['costoTST']).any() else ''
axe.plot(kwargs['costoTST'], color='red', linewidth=2.0, label='Costo Testeo', marker=marcador, linestyle=linea)
if 'diffEnergiaTRN' in kwargs.keys():
axe.plot(kwargs['diffEnergiaTRN'], color='black', linewidth=2.0, label='Dif. energias libre')
if 'errorReconsTRN' in kwargs.keys():
axe.plot(kwargs['errorReconsTRN'], color='blue', linewidth=2.0, label='Error reconstruccion')
if 'mseTRN' in kwargs.keys():
axe.plot(kwargs['mseTRN'], color='red', linewidth=2.0, label='error cuadratico medio')
limitesX = axe.get_xlim()
plt.xlim(1, limitesX[1]) # se corrige a la epoca 1...max
plt.title("COSTOS vs. EPOCAS")
plt.xlabel('epocas')
plt.legend()
plt.show() if mostrar else None
if 'guardar' in kwargs:
plt.savefig(kwargs['guardar']+'.png', dpi=None, facecolor='w', edgecolor='w', orientation='portrait', papertype=None, format='png', transparent=True, bbox_inches=None, pad_inches=0.1, frameon=None)
plt.savefig(kwargs['guardar']+'.pdf', dpi=None, facecolor='w', edgecolor='w', orientation='portrait', papertype=None, format='pdf', transparent=True, bbox_inches=None, pad_inches=0.1, frameon=None)
plt.gcf().clear()
return axe
[documentos]def dibujarMatrizConfusion(cm, clases, normalizar=False, titulo='Matriz de Confusion', cmap=plt.cm.Blues, axe=None, mostrar=False, guardar=None):
"""
This function prints and plots the confusion matrix.
Normalization can be applied by setting `normalize=True`.
"""
if axe is None:
plt.cla() # Clear axis
plt.clf() # Clear figure
axe = plt.gca()
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(titulo)
plt.colorbar()
tick_marks = numpy.arange(len(clases))
plt.xticks(tick_marks, clases, rotation=45)
plt.yticks(tick_marks, clases)
if normalizar:
cm = cm.astype('float') / cm.sum(axis=1)[:, numpy.newaxis]
cm = numpy.around(cm, decimals=2) #redondeo de los flotantes
print("Matriz de Confusion Normalizada")
else:
print('Matriz de Confusion')
print(cm)
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, cm[i, j],
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
plt.tight_layout()
plt.ylabel('Etiqueta Real')
plt.xlabel('Etiqueta Prediccion')
if guardar is not None:
plt.savefig(guardar+'.png', dpi=None, facecolor='w', edgecolor='w', orientation='portrait', papertype=None, format='png', transparent=True, bbox_inches=None, pad_inches=0.1, frameon=None)
plt.savefig(guardar+'.pdf', dpi=None, facecolor='w', edgecolor='w', orientation='portrait', papertype=None, format='pdf', transparent=True, bbox_inches=None, pad_inches=0.1, frameon=None)
plt.show() if mostrar else None
plt.gcf().clear()
return axe