Skip to content
Snippets Groups Projects
Commit d6748054 authored by Jean-Luc Parouty's avatar Jean-Luc Parouty
Browse files

Rewrite Linear Reg. as jupyter example

parent c92e65ec
No related branches found
No related tags found
No related merge requests found
source diff could not be displayed: it is too large. Options to address this: view the blob.
%% Cell type:markdown id: tags:
<img width="800px" src="../fidle/img/00-Fidle-header-01.svg"></img>
# <!-- TITLE --> [FIT1] - Complexity Syndrome
# <!-- TITLE --> [POLR1] - Complexity Syndrome
<!-- DESC --> Illustration of the problem of complexity with the polynomial regression
<!-- AUTHOR : Jean-Luc Parouty (CNRS/SIMaP) -->
## Objectives :
- Visualizing and understanding under and overfitting
## What we're going to do :
We are looking for a polynomial function to approximate the observed series :
$ y = a_n\cdot x^n + \dots + a_i\cdot x^i + \dots + a_1\cdot x + b $
## Step 1 - Import and init
%% Cell type:code id: tags:
``` python
import numpy as np
import math
import random
import matplotlib
import matplotlib.pyplot as plt
import sys
sys.path.append('..')
import fidle.pwk as ooo
ooo.init()
```
%% Output
FIDLE 2020 - Practical Work Module
Version : 0.2.9
Run time : Tuesday 18 February 2020, 17:23:05
TensorFlow version : 2.0.0
Keras version : 2.2.4-tf
%% Cell type:markdown id: tags:
## Step 2 - Preparation of learning data :
%% Cell type:code id: tags:
``` python
# ---- Parameters
n = 100
xob_min = -5
xob_max = 5
deg = 7
a_min = -2
a_max = 2
noise = 2000
# ---- Train data
# X,Y : data
# X_norm,Y_norm : normalized data
X = np.random.uniform(xob_min,xob_max,(n,1))
# N = np.random.uniform(-noise,noise,(n,1))
N = noise * np.random.normal(0,1,(n,1))
a = np.random.uniform(a_min,a_max, (deg,))
fy = np.poly1d( a )
Y = fy(X) + N
# ---- Data normalization
#
X_norm = (X - X.mean(axis=0)) / X.std(axis=0)
Y_norm = (Y - Y.mean(axis=0)) / Y.std(axis=0)
# ---- Data visualization
width = 12
height = 6
nb_viz = min(2000,n)
def vector_infos(name,V):
m=V.mean(axis=0).item()
s=V.std(axis=0).item()
print("{:8} : mean={:+12.4f} std={:+12.4f} min={:+12.4f} max={:+12.4f}".format(name,m,s,V.min(),V.max()))
print("Nombre de points : {} a={} deg={} bruit={}".format(n,a,deg,noise))
ooo.display_md('#### Before normalization :')
print("\nDonnées d'aprentissage brute :")
print("({} points visibles sur {})".format(nb_viz,n))
plt.figure(figsize=(width, height))
plt.plot(X[:nb_viz], Y[:nb_viz], '.')
plt.tick_params(axis='both', which='both', bottom=False, left=False, labelbottom=False, labelleft=False)
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.show()
vector_infos('X',X)
vector_infos('Y',Y)
ooo.display_md('#### After normalization :')
print("\nDonnées d'aprentissage normalisées :")
print("({} points visibles sur {})".format(nb_viz,n))
plt.figure(figsize=(width, height))
plt.plot(X_norm[:nb_viz], Y_norm[:nb_viz], '.')
plt.tick_params(axis='both', which='both', bottom=False, left=False, labelbottom=False, labelleft=False)
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.show()
vector_infos('X_norm',X_norm)
vector_infos('Y_norm',Y_norm)
```
%% Output
Nombre de points : 100 a=[-1.40023862 1.64009905 1.89987647 1.24972783 1.17765272 1.90935391
1.11259327] deg=7 bruit=2000
#### Before normalization :
Données d'aprentissage brute :
(100 points visibles sur 100)
X : mean= +0.2539 std= +2.9283 min= -4.9332 max= +4.9177
Y : mean= -2914.8537 std= +5532.3607 min= -23848.6013 max= +5139.0627
#### After normalization :
Données d'aprentissage normalisées :
(100 points visibles sur 100)
X_norm : mean= +0.0000 std= +1.0000 min= -1.7714 max= +1.5927
Y_norm : mean= -0.0000 std= +1.0000 min= -3.7839 max= +1.4558
%% Cell type:markdown id: tags:
## Step 3 - Polynomial regression with NumPy
### 3.1 - Underfitting
%% Cell type:code id: tags:
``` python
def draw_reg(X_norm, Y_norm, x_hat,fy_hat, size):
plt.figure(figsize=size)
plt.plot(X_norm, Y_norm, '.')
x_hat = np.linspace(X_norm.min(), X_norm.max(), 100)
plt.plot(x_hat, fy_hat(x_hat))
plt.tick_params(axis='both', which='both', bottom=False, left=False, labelbottom=False, labelleft=False)
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.show()
```
%% Cell type:code id: tags:
``` python
reg_deg=1
a_hat = np.polyfit(X_norm.reshape(-1,), Y_norm.reshape(-1,), reg_deg)
fy_hat = np.poly1d( a_hat )
print("Nombre de degrés : {} a_hat={}".format(reg_deg, a_hat))
draw_reg(X_norm[:nb_viz],Y_norm[:nb_viz], x_hat,fy_hat, (width,height))
```
%% Output
Nombre de degrés : 1 a_hat=[ 2.15635737e-01 -1.26046371e-16]
%% Cell type:markdown id: tags:
### 3.2 - Good fitting
%% Cell type:code id: tags:
``` python
reg_deg=5
a_hat = np.polyfit(X_norm.reshape(-1,), Y_norm.reshape(-1,), reg_deg)
fy_hat = np.poly1d( a_hat )
print("Nombre de degrés : {} a_hat={}".format(reg_deg, a_hat))
draw_reg(X_norm[:nb_viz],Y_norm[:nb_viz], x_hat,fy_hat, (width,height))
```
%% Output
Nombre de degrés : 5 a_hat=[ 0.09676506 -0.49102546 -0.19674074 0.41539174 -0.00888844 0.51187173]
%% Cell type:markdown id: tags:
### 3.3 - Overfitting
%% Cell type:code id: tags:
``` python
reg_deg=24
a_hat = np.polyfit(X_norm.reshape(-1,), Y_norm.reshape(-1,), reg_deg)
fy_hat = np.poly1d( a_hat )
print("Nombre de degrés : {} a_hat={}".format(reg_deg, a_hat))
draw_reg(X_norm[:nb_viz],Y_norm[:nb_viz], x_hat,fy_hat, (width,height))
```
%% Output
Nombre de degrés : 24 a_hat=[-3.39583761e-01 3.66524802e+00 1.35968152e+01 -5.33709389e+01
-1.54708597e+02 3.43661072e+02 8.76139324e+02 -1.29075459e+03
-2.93637308e+03 3.13537269e+03 6.25956959e+03 -5.14495063e+03
-8.72124478e+03 5.75688179e+03 7.93008239e+03 -4.30734159e+03
-4.57884398e+03 2.04404969e+03 1.58025869e+03 -5.55090657e+02
-2.89374022e+02 7.05282858e+01 2.12619645e+01 -2.67799255e+00
3.95718335e-01]
%% Cell type:markdown id: tags:
---
<img width="80px" src="../fidle/img/00-Fidle-logo-01.svg"></img>
......
# ------------------------------------------------------------------
# _____ _ _ _
# | ___(_) __| | | ___
# | |_ | |/ _` | |/ _ \
# | _| | | (_| | | __/
# |_| |_|\__,_|_|\___| Regression cooker
# ------------------------------------------------------------------
# Formation Introduction au Deep Learning (FIDLE)
# CNRS/SARI/DEVLOG 2020 - S. Arias, E. Maldonado, JL. Parouty
# ------------------------------------------------------------------
# Initial version by JL Parouty, feb 2020
import numpy as np
import math
import random
import datetime, time
import matplotlib
import matplotlib.pyplot as plt
from IPython.display import display,Markdown,HTML
class RegressionCooker():
__version__ = '0.1'
def __init__(self, mplstyle='../fidle/mplstyles/custom.mplstyle'):
print('\nFIDLE 2020 - Regression Cooker')
print('Version :', self.__version__)
print('Run time : {}'.format(time.strftime("%A %-d %B %Y, %H:%M:%S")))
if mplstyle is not None:
matplotlib.style.use(mplstyle)
@classmethod
def about(cls):
print('\nFIDLE 2020 - Regression Cooker)')
print('Version :', cls.version)
@classmethod
def vector_infos(cls,name,V):
"""
Show some nice infos about a vector
args:
name : vector name
V : vector
"""
m=V.mean(axis=0).item()
s=V.std(axis=0).item()
print("{:16} : mean={:8.3f} std={:8.3f} min={:8.3f} max={:8.3f}".format(name,m,s,V.min(),V.max()))
def get_dataset(self,n):
"""
Return a dataset of n observation
args:
n : dataset size
return:
X,Y : with X shapes = (n,1) Y shape = (n,)
"""
xob_min = 0 # x min and max
xob_max = 10
a_min = -30 # a min and max
a_max = 30
b_min = -10 # b min and max
b_max = 10
noise_min = 10 # noise min and max
noise_max = 50
a0 = random.randint(a_min,a_max)
b0 = random.randint(b_min,b_max)
noise = random.randint(noise_min,noise_max)
# ---- Construction du jeu d'apprentissage ---------------
# X,Y : données brutes
X = np.random.uniform(xob_min,xob_max,(n,1))
N = noise * np.random.normal(0,1,(n,1))
Y = a0*X + b0 + N
return X,Y
def plot_dataset(self,X,Y,title='Dataset :',width=12,height=6):
"""
Plot dataset X,Y
args:
X : Observations
Y : Values
"""
nb_viz = min(1000,len(X))
display(Markdown(f'### {title}'))
print(f"X shape : {X.shape} Y shape : {Y.shape} plot : {nb_viz} points")
plt.figure(figsize=(width, height))
plt.plot(X[:nb_viz], Y[:nb_viz], '.')
plt.show()
self.vector_infos('X',X)
self.vector_infos('Y',Y)
def __plot_theta(self, i, theta,x_min,x_max, loss,gradient,alpha):
Xd = np.array([[x_min], [x_max]])
Yd = Xd * theta.item(1) + theta.item(0)
plt.plot(Xd, Yd, color=(1.,0.4,0.3,alpha))
if i<0:
print( " #i Loss Gradient Theta")
else:
print(" {:3d} {:+7.3f} {:+7.3f} {:+7.3f} {:+7.3f} {:+7.3f}".format(i,loss,gradient.item(0),gradient.item(1),theta.item(0),theta.item(1)))
def __plot_XY(self, X,Y,width=12,height=6):
nb_viz = min(1000,len(X))
plt.figure(figsize=(width, height))
plt.plot(X[:nb_viz], Y[:nb_viz], '.')
plt.tick_params(axis='both', which='both', bottom=False, left=False, labelbottom=False, labelleft=False)
plt.xlabel('x axis')
plt.ylabel('y axis')
def __plot_loss(self,loss, width=8,height=4):
plt.figure(figsize=(width, height))
plt.tick_params(axis='both', which='both', bottom=False, left=False, labelbottom=False, labelleft=False)
plt.ylim(0, 20)
plt.plot(range(len(loss)), loss)
plt.xlabel('Iterations')
plt.ylabel('Loss')
def basic_descent(self, X, Y, epochs=200, eta=0.01,width=12,height=6):
"""
Performs a gradient descent where the gradient is updated at the end
of each iteration for all observations.
args:
X,Y : Observations
epochs : Number of epochs (200)
eta : learning rate
width,height : graphic size
return:
theta : theta
"""
display(Markdown(f'### Basic gradient descent :'))
display(Markdown(f'**With :** '))
print('with :')
print(f' epochs = {epochs}')
print(f' eta = {eta}')
display(Markdown(f'**epochs :** '))
x_min = X.min()
x_max = X.max()
y_min = Y.min()
y_max = Y.max()
n = len(X)
# ---- Initialization
theta = np.array([[y_min],[0]])
X_b = np.c_[np.ones((n, 1)), X]
# ---- Visualization
self.__plot_XY(X,Y,width,height)
self.__plot_theta( -1, theta,x_min,x_max, None,None,0.1)
# ---- Training
loss=[]
for i in range(epochs+1):
gradient = (2/n) * X_b.T @ ( X_b @ theta - Y)
mse = ((X_b @ theta - Y)**2).mean(axis=None)
theta = theta - eta * gradient
loss.append(mse)
if (i % (epochs/10))==0:
self.__plot_theta( i, theta,x_min,x_max, mse,gradient,i/epochs)
# ---- Visualization
display(Markdown(f'**Visualization :** '))
plt.show()
display(Markdown(f'**Loss :** '))
self.__plot_loss(loss)
plt.show()
return theta
def minibatch_descent(self, X, Y, epochs=200, batchs=5, batch_size=10, eta=0.01,width=12,height=6):
"""
Performs a gradient descent where the gradient is updated at the end
of each iteration for all observations.
args:
X,Y : Observations
epochs : Number of epochs (200)
eta : learning rate
width,height : graphic size
return:
theta : theta
"""
display(Markdown(f'### Mini batch gradient descent :'))
display(Markdown(f'**With :** '))
print('with :')
print(f' epochs = {epochs}')
print(f' batchs = {batchs}')
print(f' batch size = {batch_size}')
print(f' eta = {eta}')
display(Markdown(f'**epochs :** '))
x_min = X.min()
x_max = X.max()
y_min = Y.min()
y_max = Y.max()
n = len(X)
# ---- Initialization
theta = np.array([[y_min],[0]])
X_b = np.c_[np.ones((n, 1)), X]
# ---- Visualization
self.__plot_XY(X,Y,width,height)
self.__plot_theta( -1, theta,x_min,x_max, None,None,0.1)
# ---- Training
def learning_schedule(t):
return 1 / (t + 100)
loss=[]
for epoch in range(epochs):
for i in range(batchs):
random_index = np.random.randint(n-batch_size)
xi = X_b[random_index:random_index+batch_size]
yi = Y[random_index:random_index+batch_size]
mse = ((xi @ theta - yi)**2).mean(axis=None)
gradient = 2 * xi.T.dot(xi.dot(theta) - yi)
eta = learning_schedule(epoch*150)
theta = theta - eta * gradient
loss.append(mse)
self.__plot_theta( epoch, theta,x_min,x_max, mse,gradient,epoch/epochs)
# draw_theta(epoch,mse,gradients, theta,0.1+epoch/(n_epochs+1))
# draw_theta(epoch,mse,gradients,theta,1)
# ---- Visualization
display(Markdown(f'**Visualization :** '))
plt.show()
display(Markdown(f'**Loss :** '))
self.__plot_loss(loss)
plt.show()
return theta
\ No newline at end of file
......@@ -35,7 +35,7 @@ Useful information is also available in the [wiki](https://gricad-gitlab.univ-gr
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Direct determination of linear regression
[[GRAD1] - Linear regression with gradient descent](LinearReg/02-Gradient-descent.ipynb)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;An example of gradient descent in the simple case of a linear regression.
[[FIT1] - Complexity Syndrome](LinearReg/03-Polynomial-Regression.ipynb)
[[POLR1] - Complexity Syndrome](LinearReg/03-Polynomial-Regression.ipynb)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Illustration of the problem of complexity with the polynomial regression
[[LOGR1] - Logistic regression, in pure Tensorflow](LinearReg/04-Logistic-Regression.ipynb)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logistic Regression with Mini-Batch Gradient Descent using pure TensorFlow.
......
......@@ -31,7 +31,7 @@ import seaborn as sn #IDRIS : module en cours d'installation
from IPython.display import display,Markdown,HTML
VERSION='0.2.9'
VERSION='0.4.0'
# -------------------------------------------------------------
......@@ -390,7 +390,11 @@ def good_place( places={'SOMEWHERE':'/tmp'} ):
print('** Attention : No expected folder exists in this environment..')
assert False, 'No expected folder exists in this environment..'
def np_print(*args, format={'float': '{:6.3f}'.format}):
with np.printoptions(formatter=format):
for a in args:
print(a)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment