Newer
Older
# ------------------------------------------------------------------
# _____ _ _ _
# | ___(_) __| | | ___
# | |_ | |/ _` | |/ _ \
# | _| | | (_| | | __/
# |_| |_|\__,_|_|\___| 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 matplotlib
import matplotlib.pyplot as plt
from IPython.display import display,Markdown,HTML
sys.path.append('..')
import fidle.pwk as pwk
class RegressionCooker():
pwk = None
version = '0.1'
def __init__(self, pwk):
self.pwk = pwk
pwk.subtitle('FIDLE 2020 - Regression Cooker')
print('Version :', self.version)
print('Run time : {}'.format(time.strftime("%A %d %B %Y, %H:%M:%S")))
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
@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], '.')
self.pwk.save_fig('01-dataset')
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)))
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
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
pwk.subtitle('Visualization :')
self.pwk.save_fig('02-basic_descent')
pwk.subtitle('Loss :')
self.pwk.save_fig('03-basic_descent_loss')
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
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)
pwk.subtitle('Visualization :')
self.pwk.save_fig('04-minibatch_descent')
pwk.subtitle('Loss :')
self.pwk.save_fig('05-minibatch_descent_loss')