Video abstract for "An Adaptive Homeostatic Algorithm for the Unsupervised Learning of Visual Features"
This video shows the results of unsupervised learning with different type of kezrnel normalization. This is to illustrate the results obtained in this paper on the An Adaptive Homeostatic Algorithm for the Unsupervised Learning of Visual Features which is now in press.
In [1]:
%matplotlib inline
In [2]:
%load_ext autoreload
%autoreload 2
In [4]:
%%writefile /tmp/video_abstract.py
import os
import numpy as np
seed = 51
np.random.seed(seed)
from shl_scripts.shl_experiments import SHL
name = '2019-09-11_Perrinet19'
datapath = '/tmp/database'
opts = dict(datapath=datapath, verbose=True, cache_dir='/tmp/cache_dir', n_iter=2**5 + 1, seed=seed)
shl = SHL(**opts)
data = shl.get_data(matname=f'{name}_data')
homeo_methods = ['None', 'OLS', 'HEH', 'HAP']
N_step = 18
d_new, d_old = 1, 1
fibo = [d_old]
for i_step in range(N_step+1):
fibo.append(d_new)
d_new, d_old = d_new + d_old, d_new
print('Fibonacci=', fibo)
from shl_scripts import touch
#from shl_scripts.shl_experiments import SHL_set
for homeo_method in homeo_methods:
print(f'=> homeo_method={homeo_method}')
flockname = os.path.join(shl.cache_dir, f'{name}_{homeo_method}_lock')
if not os.path.isfile(flockname):
touch(flockname)
dictionary, P_cum = None, None
opts_ = opts.copy()
opts_.update(homeo_method=homeo_method, n_iter=1,)
shl = SHL(**opts_)
for i_step in range(N_step):
print(f'==> i_iter={i_step} / n_iter={fibo[i_step+1]}')
shl.n_iter = fibo[i_step]
dico = shl.learn_dico(data=data, dictionary=dictionary, P_cum=P_cum, matname=f'{name}_{homeo_method}_{i_step}')
dictionary = dico.dictionary
P_cum = dico.P_cum
if os.path.isfile(flockname): os.remove(flockname)
In [5]:
%run /tmp/video_abstract.py
In [6]:
phi = (np.sqrt(5) + 1. ) /2
fig_width = 15
dpi_export = 300
#dpi_export = 0
colors = ['black', 'orange', 'blue', 'red']
import matplotlib.pyplot as plt
def plot_dico(dico, color, dim_graph = (8, 8)):
subplotpars = dict(left=0.05, right=.95, bottom=0.05, top=.95, wspace=0.05, hspace=0.05,)
fig, axs = plt.subplots(1, 2, figsize=(fig_width, fig_width/phi), gridspec_kw=subplotpars)
for ax in axs:
ax.axis(c='b', lw=2, axisbg='w')
ax.set_facecolor('w')
from shl_scripts import show_dico
fig, axs[0] = show_dico(shl, dico, data=data, dim_graph=dim_graph, fig=fig, ax=axs[0], order=False, seed=51)
if False:
from shl_scripts import plot_P_cum
fig, axs[1] = plot_P_cum(dico.P_cum, ymin=0.6, ymax=1.001,
title=None, suptitle=None, ylabel='non-linear functions',
verbose=False, n_yticks=21, alpha=.02, c=color, fig=fig, ax=axs[1])
axs[1].plot([0], [0], lw=1, color=color, label=homeo_method, alpha=.6)
else:
from shl_scripts import plot_proba_histogram
coding = shl.code(data, dico)
fig, axs[1] = plot_proba_histogram(coding, fig=fig, ax=axs[1], lw=2., alpha=1., color='gray')
axs[1].plot([0], [0], lw=1, color=color, label=homeo_method, alpha=.6)
# ax.set_ylabel(homeo_method)
#ax.text(-8, 7*dim_graph[0], homeo_method, fontsize=12, color='k', rotation=90)#, backgroundcolor='white'
#axs[1].legend(loc='lower right')
# pos : [left, bottom, width, height] = The new position of the in `.Figure` coordinates.
axs[0].set_position([0.0, 0.0, .618, 1.0])
axs[1].set_position([0.618+0.05, 0.0+0.05, .382-0.07, 1.0-0.052])
return fig, axs
for homeo_method, color in zip(homeo_methods, colors):
print(f'=> homeo_method={homeo_method}')
flockname = os.path.join(shl.cache_dir, f'{name}_{homeo_method}_lock')
if not os.path.isfile(flockname):
for i_step in range(N_step):
dico = shl.learn_dico(data=data, matname=f'{name}_{homeo_method}_{i_step}', list_figures=[])
print(f'==> i_iter={i_step} / n_iter={fibo[i_step+1]}')
figname = f'/tmp/{name}_{homeo_method}_{i_step}.png'
if not os.path.isfile(figname):
fig, axs = plot_dico(dico, color)
axs[1].set_xlim(0., 1.9)
axs[1].text(0.1, 32, f'homeo_method={homeo_method}', fontsize=24, color=color, backgroundcolor='white')
axs[1].text(0.1, 92, f'n_iter={fibo[i_step+1]:4d}', fontsize=24, color='k', backgroundcolor='white')
plt.show()
if dpi_export > 0 : fig.savefig(figname, dpi=dpi_export, bbox_inches='tight')
Creating the movie using the (excellent) MoviePy library:
In [12]:
from moviepy.editor import VideoFileClip, ImageClip, TextClip, CompositeVideoClip
H = 500
W = 800
SIZE = (W, H)
# a list of sub clips that will be compsited at the end
clip = []
t = 0
texts = ["An Adaptive Homeostatic Algorithm\n for the Unsupervised Learning\n of Visual Features",
"as published Sep 2019\n in the journal Vision"
]
colors_intro = ['orange', 'white']
txt_opts = dict(fontsize=50, font="Amiri-Bold", stroke_color='gray', stroke_width=.5, size=(W,H))
duration = 2
for text, color in zip(texts, colors_intro):
txt_clip = TextClip(text, color=color, **txt_opts)
txt_clip = txt_clip.set_start(t).set_pos('center').set_duration(duration)#.resize(height=H, width=W)
t += duration
clip.append(txt_clip)
sub_opts = dict(fontsize=32, font="Amiri-Bold", stroke_color='gray', method='caption', align='South',
stroke_width=.5, size=(W,H))
for subtitle in ["This paper shows the role of... ", "... homeostasis mechanisms ...", "... in unsupervised learning algorithms."]:
sub_duration = 1.5
sub_clip = TextClip(subtitle, color='yellow', **sub_opts)
sub_clip = sub_clip.set_start(t).set_duration(sub_duration) #set_pos('bottom').
t += sub_duration
clip.append(sub_clip)
texts = ["Without homeostasis", "Olshausen (1997)", "Histogram Equalization", "Activation Probability"]
subtitles = {}
subtitles['None'] = [
'I show here the result of a simple algorithm of ...',
'... unsupervised learning based on sparse coding.',
'On the left, we show 64 randomly picked kernels...',
'... from the 661 receptive fields of the neurons and ...',
'... on the right the histogram of activation probability.',
'... Looking at results as learning iterates, ...',
'... edge-like filters appear after some iterations...',
'... but the histogram shows a desequilibrium in the ...',
'... activation probability, even though ...',
'... the norm of the kernels are normalized.',
]
subtitles['OLS'] = [
'The original algorithm developped ...',
'... by Olshausen and Field (1997) included a more ...',
'... elaborated adaptation of this norm based on ...',
"... coefficients' energy, yielding a better balance...",
'... and a better looking set of filters.',
'Still, this causes an under-optimisation of the ... ',
'... representation as some neurons are a priori ...',
'... more likely to be selected than others.',
' A proper homeostasis is necessary.'
]
subtitles['HEH'] = [
'Such an objective can be simply optimized...',
'... by introducing an adaptive non-linearity in our ...',
'... sparse coding algorithm. This non-linearity ...',
'... is based on well-known histogram equalization ...',
'... to make sure that all neurons are always picked up.',
'... with a priori the same probability ...',
'... We called it Histogram Equalization Homeostasis ...',
'... and it effectively works very well, as well ...',
'... qualitatively (left) ...', '... than quantitatively (right).',
]
subtitles['HAP'] = [
'A problem of Histogram Equalization Homeostasis ...',
'... is that it is computationally more expensive ...',
'... and less plausible to be implemented in real ...',
'... biological neurons. We thus explored another ...',
'... algorithm simply based on activation probability.',
'This Homeostasis on Activation Probability ... ',
'... performed qualitatively as well as HEH ...',
'... and also quantitatively similarly ...',
'Yet it comes at a very low cost and it is ...',
'... compatible with biomimetic algorithms.',
]
# http://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html?highlight=compositevideoclip#textclip
txt_opts = dict(fontsize=65, font="Amiri-Bold", stroke_color='gray', stroke_width=2.5, size=(W,H), bg_color='white')
sub_opts = dict(fontsize=32, font="Amiri-Bold", stroke_color='gray', method='caption', align='South',
stroke_width=.5, size=(W,H))
for homeo_method, text, color in zip(homeo_methods, texts, colors):
print(f'=> homeo_method={homeo_method}')
duration = 1
txt_clip = TextClip(text, color=color, **txt_opts)
txt_clip = txt_clip.set_start(t).set_pos('center').set_duration(duration)
t += duration
clip.append(txt_clip)
for i_step in range(N_step):
duration = 1
im_clip = ImageClip(f'/tmp/{name}_{homeo_method}_{i_step}.png')
im_clip = im_clip.set_start(t).set_duration(duration).set_pos('top').resize(height=int(H*.925), width=int(W*.925))
t += duration
clip.append(im_clip)
# please be kind, rewind
t_sub = t - duration * N_step
sub_duration = duration * N_step / len(subtitles[homeo_method])
for subtitle in subtitles[homeo_method]:
sub_clip = TextClip(subtitle, color='yellow', **sub_opts)
sub_clip = sub_clip.set_start(t_sub).set_duration(sub_duration) #set_pos('bottom').
t_sub += sub_duration
clip.append(sub_clip)
texts = ["... for more info,\n and open-sourced code\n visit ",
"https://laurentperrinet.github.io/publication/perrinet-19-hulk"]
colors_outro = ['orange', 'white']
txt_opts = dict(fontsize=30, font="Amiri-Bold", stroke_color='gray', stroke_width=.5, size=(W,H))
duration = 3
for text, color in zip(texts, colors_outro):
txt_clip = TextClip(text, color=color, **txt_opts)
txt_clip = txt_clip.set_start(t).set_pos('center').set_duration(duration)
t += duration
clip.append(txt_clip)
#sub_clip = TextClip("Thanks for your attention!", color='yellow', **sub_opts)
#sub_clip = sub_clip.set_start(t-.5).set_duration(.5) #set_pos('bottom').
#clip.append(sub_clip)
# Overlay the text clip on the first video clip
video = CompositeVideoClip(clip)
vext = 'mp4'
# Write the result to a file (many options available !)
video.write_videofile(f'../files/{name}.{vext}', fps=5)
some book keeping for the notebook¶
In [9]:
%load_ext version_information
%version_information numpy, scipy, matplotlib, MotionClouds
Out[9]: