Introduction

Le biais conduit à du sous-apprentissage (underfitting) et la variance amène du sur-apprentissage (overfitting) et donc à de hautes erreurs de tests.

Example pour un jeu de données composé de 8 points:

image

Polynomials of various degrees. d = 1 under-fits the data, while d = 6 over-fits the data.

On peut éviter cela en:

  • ajoutant de la régularisation à notre modèle
  • Si la data est under-fit le modèle est trop simple. On dit qu’il souffre de High-bias. Le modèle est biaisé et cela se traduit par le fait que les data sont poorly fit. On pourrait trouver un autre modèle plus complexe.
  • Attention au contraire à ne pas avoir un modèle trop complexe qui ferait que les données “over-fitterait” car il pourrait s’ajuster parfaitement aux données d’entrainement grâce à tous ses degrés de liberté.
  • Si le modèle over-fit on peut aussi ajouter des données au dataset…

image

Pour déterminer le bon algorithme à utiliser par rapport à notre jeu de données, il faut pouvoir identifier quantitativement le bias et la variance pour pouvoir optimiser les metaparamètres.

C’est faisable grâce au process de cross-validation.

Détecter l’overfitting grâce à la cross-validation

Pour quantifier les effets du biais et de la variance et construire le meilleur estimateur possible, on va découper notre dataset en 3 parties:

  • training set (60% du dataset)
  • cross-validation set (20%)
  • test set (20%)

L’idée générale est la suivante:

  1. Les paramètres du modèles (dans notre cas, les coefficients du polynôme) sont appris en utilisant le training set.
  2. L’erreur est évaluée sur le cross-validation set et les meta-paramètres (dans notre cas les degrés du polynôme) sont ajustés pour que l’erreur de cross-validation soit minimisée.
  3. Finalement les labels sont prédits pour le test set. Ces labels sont utilisés pour évaluer la performance de l’algorithme à labeliser des nouvelles données.

Pourquoi a-t-on besoin à la fois d’un cross-validation set et d’un test set ?

Certains data scientists utilisent les mêmes set de données pour le cross-validation set et le test set. Ce n’est pas la meilleure approche car les meta-paramètres peuvent “over-fittés“ le cross-validation set tout comme les paramètres peuvent “over-fittés“ le training set.

L’erreur de cross-validation de notre classifieur polynomial peut être visualisée en affichant l’erreur comme une fonction du polynôme de degré d. (Ici exemple avec 100 points)

image

De manière générale, plus on a données d’entraînement et plus on peut utiliser un modèle complexe. The learning curve

La courbe d’apprentissage

La courbe d’apprentissage est l’affichage des erreurs de training et de cross-validation en fonction du nombre de training points.

image

Learning Curves for a case of high bias (left, d = 2) and high variance (right, d = 20)

  • Sur la gauche, le polynôme de degré 1 est un estimateur hautement biaisé qui sous-apprend les données. C’est indiqué par le fait qu’à la fois les erreurs d’entrainement et les erreurs de cross-validation sont élevées.

  • Sur la droite, le polynôme est de degré 20. L’erreur d’entrainement est beaucoup plus faible que l’erreur de cross-validation. Plus on ajoute de données dans le training set et plus l’erreur d’entrainement augmente alors que l’erreur de cross-validation diminue.

Conclusion

Fort biais

Si notre algorithme montre un fort biais, il faut:

  • Ajouter plus de features
  • Utiliser un modèle plus sophistiqué
  • Diminuer le training set pour booster la durée d’entrainement. On arrivera à la même erreur plus rapidement; avec moins de données d’entrainement. Par contre, cela ne va pas améliorer la classification.
  • Diminuer la régularisation: la régularisation est une technique utilisée pour simplifier certains modèles de Machine Learning en ajoutant des termes de pénalité qui dépendent des caractéristiques des paramètres.

Forte variance

  • Utiliser moins de features
  • Augmenter le training set. Ajouter des données dans le training set peut réduire l’effet d’over-fitting et conduire à diminuer la variance de l’estimateur.
  • Augmenter la régularisation qui est faite justement pour éviter l’over-fitting.

Code des graphs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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
import pylab as pl
from matplotlib import ticker
from matplotlib.patches import FancyArrow

np.random.seed(42)

def test_func(x, err=0.5):
return np.random.normal(10 - 1. / (x + 0.1), err)


def compute_error(x, y, p):
yfit = np.polyval(p, x)
return np.sqrt(np.mean((y - yfit) ** 2))


#------------------------------------------------------------
# Plot linear regression example
np.random.seed(42)
x = np.random.random(20)
y = np.sin(2 * x)
p = np.polyfit(x, y, 1) # fit a 1st-degree polynomial to the data

xfit = np.linspace(-0.2, 1.2, 10)
yfit = np.polyval(p, xfit)

pl.scatter(x, y, c='k')
pl.plot(xfit, yfit)
pl.xlabel('x')
pl.ylabel('y')
pl.title('Linear Regression Example')

#------------------------------------------------------------
# Plot example of over-fitting and under-fitting

N = 8
np.random.seed(42)
x = 10 ** np.linspace(-2, 0, N)
y = test_func(x)

xfit = np.linspace(-0.2, 1.2, 1000)

titles = ['d = 1 (under-fit)', 'd = 2', 'd = 6 (over-fit)']
degrees = [1, 2, 6]

pl.figure(figsize = (9, 3.5))
for i, d in enumerate(degrees):
pl.subplot(131 + i, xticks=[], yticks=[])
pl.scatter(x, y, marker='x', c='k', s=50)

p = np.polyfit(x, y, d)
yfit = np.polyval(p, xfit)
pl.plot(xfit, yfit, '-b')

pl.xlim(-0.2, 1.2)
pl.ylim(0, 12)
pl.xlabel('house size')
if i == 0:
pl.ylabel('price')

pl.title(titles[i])

pl.subplots_adjust(left = 0.06, right=0.98,
bottom=0.15, top=0.85,
wspace=0.05)

#------------------------------------------------------------
# Plot training error and cross-val error
# as a function of polynomial degree

Ntrain = 100
Ncrossval = 100
error = 1.0

np.random.seed(0)
x = np.random.random(Ntrain + Ncrossval)
y = test_func(x, error)

xtrain = x[:Ntrain]
ytrain = y[:Ntrain]

xcrossval = x[Ntrain:]
ycrossval = y[Ntrain:]

degrees = np.arange(1, 21)
train_err = np.zeros(len(degrees))
crossval_err = np.zeros(len(degrees))

for i, d in enumerate(degrees):
p = np.polyfit(xtrain, ytrain, d)

train_err[i] = compute_error(xtrain, ytrain, p)
crossval_err[i] = compute_error(xcrossval, ycrossval, p)

pl.figure()
pl.title('Error for 100 Training Points')
pl.plot(degrees, crossval_err, lw=2, label = 'cross-validation error')
pl.plot(degrees, train_err, lw=2, label = 'training error')
pl.plot([0, 20], [error, error], '--k', label='intrinsic error')
pl.legend()
pl.xlabel('degree of fit')
pl.ylabel('rms error')

pl.gca().add_patch(FancyArrow(5, 1.35, -3, 0, width = 0.01,
head_width=0.04, head_length=1.0,
length_includes_head=True))
pl.text(5.3, 1.35, "High Bias", fontsize=18, va='center')

pl.gca().add_patch(FancyArrow(19, 1.22, 0, -0.1, width = 0.25,
head_width=1.0, head_length=0.05,
length_includes_head=True))
pl.text(19.8, 1.23, "High Variance", ha='right', fontsize=18)

#------------------------------------------------------------
# Plot training error and cross-val error
# as a function of training set size

Ntrain = 100
Ncrossval = 100
error = 1.0

np.random.seed(0)
x = np.random.random(Ntrain + Ncrossval)
y = test_func(x, error)

xtrain = x[:Ntrain]
ytrain = y[:Ntrain]

xcrossval = x[Ntrain:]
ycrossval = y[Ntrain:]

sizes = np.linspace(2, Ntrain, 50).astype(int)
train_err = np.zeros(sizes.shape)
crossval_err = np.zeros(sizes.shape)

pl.figure(figsize=(10, 5))

for j,d in enumerate((1, 20)):
for i, size in enumerate(sizes):
p = np.polyfit(xtrain[:size], ytrain[:size], d)
crossval_err[i] = compute_error(xcrossval, ycrossval, p)
train_err[i] = compute_error(xtrain[:size], ytrain[:size], p)

ax = pl.subplot(121 + j)
pl.plot(sizes, crossval_err, lw=2, label='cross-val error')
pl.plot(sizes, train_err, lw=2, label='training error')
pl.plot([0, Ntrain], [error, error], '--k', label='intrinsic error')

pl.xlabel('traning set size')
if j == 0:
pl.ylabel('rms error')
else:
ax.yaxis.set_major_formatter(ticker.NullFormatter())

pl.legend(loc = 4)

pl.ylim(0.0, 2.5)
pl.xlim(0, 99)

pl.text(98, 2.45, 'd = %i' % d, ha='right', va='top', fontsize='large')

pl.subplots_adjust(wspace = 0.02, left=0.07, right=0.95)
pl.suptitle('Learning Curves', fontsize=18)


pl.show()