diff --git a/doc/LectureNotes/Results/FigureFiles/EoSfitting.png b/doc/LectureNotes/Results/FigureFiles/EoSfitting.png index dfbe67cd5..ad6242d0a 100644 Binary files a/doc/LectureNotes/Results/FigureFiles/EoSfitting.png and b/doc/LectureNotes/Results/FigureFiles/EoSfitting.png differ diff --git a/doc/LectureNotes/_build/.doctrees/chapter1.doctree b/doc/LectureNotes/_build/.doctrees/chapter1.doctree index 90c4c8184..2da43f30b 100644 Binary files a/doc/LectureNotes/_build/.doctrees/chapter1.doctree and b/doc/LectureNotes/_build/.doctrees/chapter1.doctree differ diff --git a/doc/LectureNotes/_build/.doctrees/chapter2.doctree b/doc/LectureNotes/_build/.doctrees/chapter2.doctree index 5622196e5..d7dad109b 100644 Binary files a/doc/LectureNotes/_build/.doctrees/chapter2.doctree and b/doc/LectureNotes/_build/.doctrees/chapter2.doctree differ diff --git a/doc/LectureNotes/_build/.doctrees/chapter3.doctree b/doc/LectureNotes/_build/.doctrees/chapter3.doctree index 677298c6a..29981a4cc 100644 Binary files a/doc/LectureNotes/_build/.doctrees/chapter3.doctree and b/doc/LectureNotes/_build/.doctrees/chapter3.doctree differ diff --git a/doc/LectureNotes/_build/.doctrees/chapter4.doctree b/doc/LectureNotes/_build/.doctrees/chapter4.doctree index 1bb3dd684..9e619ece3 100644 Binary files a/doc/LectureNotes/_build/.doctrees/chapter4.doctree and b/doc/LectureNotes/_build/.doctrees/chapter4.doctree differ diff --git a/doc/LectureNotes/_build/.doctrees/environment.pickle b/doc/LectureNotes/_build/.doctrees/environment.pickle index a1fb76610..2ef5fde0a 100644 Binary files a/doc/LectureNotes/_build/.doctrees/environment.pickle and b/doc/LectureNotes/_build/.doctrees/environment.pickle differ diff --git a/doc/LectureNotes/_build/html/Clustering.html b/doc/LectureNotes/_build/html/Clustering.html index 777167a84..eb64804f0 100644 --- a/doc/LectureNotes/_build/html/Clustering.html +++ b/doc/LectureNotes/_build/html/Clustering.html @@ -5,7 +5,7 @@
-In this chapter we will concern ourselves with the study of cluster analysis. In general terms cluster analysis, or clustering, is the task of grouping a data-set into different distinct categories based on some measure of equality of @@ -343,7 +343,7 @@ exists different categories of clustering algorithms. A few of the most common are: centroid-, distribution-, density- and hierarchical- clustering. We will concern ourselves primarily with the first one.
The simplest of all clustering algorithms is the aptly named k-means algorithm , sometimes also referred to as Lloyds algorithm. It is the simplest and also the most common. From its simplicity it obtains both strengths and weaknesses. @@ -436,7 +436,7 @@ no-where, don’t fret, the method does get a whole lot simpler once we start programming.
The k-means clustering algorithm goes as follows (note in my opinion this description is a bit complicated and is lifted directly out of ESL HASTIE for deeper understanding purposes)
@@ -460,12 +460,12 @@ understood but to help you along the way we summarize the algorithm as followsThat’s it, nothing magical happening.
In the following section we will work to develop a deeper understanding of the previously discussed mathematics through developing codes to do k-means cluster analysis.
Let us now program the most basic version of the algorithm using nothing but Python with numpy arrays. This code is kept intentionally simple to gradually progress our understanding. There is no vectorization of any kind, and even most @@ -718,7 +718,7 @@ two improvements.
def get_distances_to_clusters(data, centroids):
@@ -1000,8 +1000,8 @@ Runtime: 0.004456043243408203 seconds
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_11_0.png b/doc/LectureNotes/_build/html/_images/chapter1_11_0.png
index 8585b7491..65d331dc5 100644
Binary files a/doc/LectureNotes/_build/html/_images/chapter1_11_0.png and b/doc/LectureNotes/_build/html/_images/chapter1_11_0.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_136_0.png b/doc/LectureNotes/_build/html/_images/chapter1_136_0.png
new file mode 100644
index 000000000..29a1bd652
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter1_136_0.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_13_1.png b/doc/LectureNotes/_build/html/_images/chapter1_13_1.png
index b145ce82a..d70ab26ee 100644
Binary files a/doc/LectureNotes/_build/html/_images/chapter1_13_1.png and b/doc/LectureNotes/_build/html/_images/chapter1_13_1.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_183_1.png b/doc/LectureNotes/_build/html/_images/chapter1_183_1.png
new file mode 100644
index 000000000..0821feaf6
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter1_183_1.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_199_1.png b/doc/LectureNotes/_build/html/_images/chapter1_199_1.png
new file mode 100644
index 000000000..f19e88b16
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter1_199_1.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_201_1.png b/doc/LectureNotes/_build/html/_images/chapter1_201_1.png
new file mode 100644
index 000000000..13fd31349
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter1_201_1.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_203_0.png b/doc/LectureNotes/_build/html/_images/chapter1_203_0.png
new file mode 100644
index 000000000..dfe1e253c
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter1_203_0.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_210_0.png b/doc/LectureNotes/_build/html/_images/chapter1_210_0.png
new file mode 100644
index 000000000..a3eac788b
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter1_210_0.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_218_0.png b/doc/LectureNotes/_build/html/_images/chapter1_218_0.png
new file mode 100644
index 000000000..cbac4fd70
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter1_218_0.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_27_0.png b/doc/LectureNotes/_build/html/_images/chapter1_27_0.png
index bef273ce3..889056124 100644
Binary files a/doc/LectureNotes/_build/html/_images/chapter1_27_0.png and b/doc/LectureNotes/_build/html/_images/chapter1_27_0.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_3_0.png b/doc/LectureNotes/_build/html/_images/chapter1_3_0.png
index 0be2e475d..656724cd5 100644
Binary files a/doc/LectureNotes/_build/html/_images/chapter1_3_0.png and b/doc/LectureNotes/_build/html/_images/chapter1_3_0.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter1_61_10.png b/doc/LectureNotes/_build/html/_images/chapter1_61_10.png
index 16b5dca78..2c196f8b3 100644
Binary files a/doc/LectureNotes/_build/html/_images/chapter1_61_10.png and b/doc/LectureNotes/_build/html/_images/chapter1_61_10.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter2_245_1.png b/doc/LectureNotes/_build/html/_images/chapter2_245_1.png
new file mode 100644
index 000000000..dc3a3ce3e
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter2_245_1.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter2_316_1.png b/doc/LectureNotes/_build/html/_images/chapter2_316_1.png
new file mode 100644
index 000000000..07584f6bb
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter2_316_1.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter3_25_2.png b/doc/LectureNotes/_build/html/_images/chapter3_25_2.png
index b77a1febb..dada82b44 100644
Binary files a/doc/LectureNotes/_build/html/_images/chapter3_25_2.png and b/doc/LectureNotes/_build/html/_images/chapter3_25_2.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter4_114_1.png b/doc/LectureNotes/_build/html/_images/chapter4_114_1.png
new file mode 100644
index 000000000..6c642a6a1
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter4_114_1.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter4_116_0.png b/doc/LectureNotes/_build/html/_images/chapter4_116_0.png
new file mode 100644
index 000000000..dfd44cb86
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter4_116_0.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter4_122_1.png b/doc/LectureNotes/_build/html/_images/chapter4_122_1.png
new file mode 100644
index 000000000..59590fe49
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter4_122_1.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter4_57_2.png b/doc/LectureNotes/_build/html/_images/chapter4_57_2.png
new file mode 100644
index 000000000..fa199fba3
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter4_57_2.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter4_57_3.png b/doc/LectureNotes/_build/html/_images/chapter4_57_3.png
new file mode 100644
index 000000000..88bffd58a
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter4_57_3.png differ
diff --git a/doc/LectureNotes/_build/html/_images/chapter4_57_4.png b/doc/LectureNotes/_build/html/_images/chapter4_57_4.png
new file mode 100644
index 000000000..e242a4058
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/chapter4_57_4.png differ
diff --git a/doc/LectureNotes/_build/html/_sources/chapter1.ipynb b/doc/LectureNotes/_build/html/_sources/chapter1.ipynb
index c930e0a6b..9dab26cdc 100644
--- a/doc/LectureNotes/_build/html/_sources/chapter1.ipynb
+++ b/doc/LectureNotes/_build/html/_sources/chapter1.ipynb
@@ -13,38 +13,37 @@
"\n",
"\n",
"\n",
- "Our emphasis throughout this series of lectures \n",
- "is on understanding the mathematical aspects of\n",
- "different algorithms used in the fields of data analysis and machine learning. \n",
+ "Our emphasis throughout this series of lectures is on understanding\n",
+ "the mathematical aspects of different algorithms used in the fields of\n",
+ "data analysis and machine learning.\n",
"\n",
- "However, where possible we will emphasize the\n",
- "importance of using available software. We start thus with a hands-on\n",
- "and top-down approach to machine learning. The aim is thus to start with\n",
- "relevant data or data we have produced \n",
- "and use these to introduce statistical data analysis\n",
- "concepts and machine learning algorithms before we delve into the\n",
- "algorithms themselves. The examples we will use in the beginning, start with simple\n",
- "polynomials with random noise added. We will use the Python\n",
- "software package [Scikit-Learn](http://scikit-learn.org/stable/) and\n",
- "introduce various machine learning algorithms to make fits of\n",
- "the data and predictions. We move thereafter to more interesting\n",
- "cases such as data from say experiments (below we will look at experimental nuclear binding energies as an example).\n",
- "These are examples where we can easily set up the data and\n",
- "then use machine learning algorithms included in for example\n",
- "**Scikit-Learn**. \n",
+ "However, where possible we will emphasize the importance of using\n",
+ "available software. We start thus with a hands-on and top-down\n",
+ "approach to machine learning. The aim is thus to start with relevant\n",
+ "data or data we have produced and use these to introduce statistical\n",
+ "data analysis concepts and machine learning algorithms before we delve\n",
+ "into the algorithms themselves. The examples we will use in the\n",
+ "beginning, start with simple polynomials with random noise added. We\n",
+ "will use the Python software package\n",
+ "[Scikit-Learn](http://scikit-learn.org/stable/) and introduce various\n",
+ "machine learning algorithms to make fits of the data and\n",
+ "predictions. We move thereafter to more interesting cases such as data\n",
+ "from say experiments (below we will look at experimental nuclear\n",
+ "binding energies as an example). These are examples where we can\n",
+ "easily set up the data and then use machine learning algorithms\n",
+ "included in for example **Scikit-Learn**.\n",
"\n",
"These examples will serve us the purpose of getting\n",
"started. Furthermore, they allow us to catch more than two birds with\n",
"a stone. They will allow us to bring in some programming specific\n",
- "topics and tools as well as showing the power of various Python \n",
- "libraries for machine learning and statistical data analysis. \n",
+ "topics and tools as well as showing the power of various Python\n",
+ "libraries for machine learning and statistical data analysis.\n",
"\n",
- "Here, we will mainly focus on two\n",
- "specific Python packages for Machine Learning, Scikit-Learn and\n",
- "Tensorflow (see below for links etc). Moreover, the examples we\n",
- "introduce will serve as inputs to many of our discussions later, as\n",
- "well as allowing you to set up models and produce your own data and\n",
- "get started with programming.\n",
+ "Here, we will mainly focus on two specific Python packages for Machine\n",
+ "Learning, Scikit-Learn and Tensorflow (see below for links etc).\n",
+ "Moreover, the examples we introduce will serve as inputs to many of\n",
+ "our discussions later, as well as allowing you to set up models and\n",
+ "produce your own data and get started with programming.\n",
"\n",
"\n",
"\n",
@@ -286,7 +285,17 @@
"[gallery](https://matplotlib.org/gallery/index.html) of examples. In\n",
"this example we plot our original values of $x$ and $y$ as well as the\n",
"prediction **ypredict** ($\\tilde{y}$), which attempts at fitting our\n",
- "data with a straight line.\n",
+ "data with a straight line. Note also that **Scikit-Learn** requires a\n",
+ "matrix as input for the input values $x$ and $y$. In the above code we\n",
+ "have solved this by declaring $x$ and $y$ as arrays of dimension\n",
+ "$n\\times 1$.\n",
+ "\n",
+ "In the code here we have also made a new array for $x\\in [0,1]$. Our\n",
+ "prediction is computed for these values, meaning that they were not\n",
+ "included in the data set used to *train* (or fit) the model.\n",
+ "This is a recurrring theme in machine learning and data analysis. We would like to train a model on a specific given data set.\n",
+ "Thereafter we wish to apply it to data which were not included in the training. Below we will encounter this again in the so-called *train-validate-test* spliting. We will typically split our data into different sets, oen for training, one for validation and finally, our data from the untouched test vault!\n",
+ "\n",
"\n",
"The Python code follows here."
]
@@ -311,6 +320,7 @@
"y = 2*x+np.random.randn(100,1)\n",
"linreg = LinearRegression()\n",
"linreg.fit(x,y)\n",
+ "# This is our new x-array to which we test our model\n",
"xnew = np.array([[0],[1]])\n",
"ypredict = linreg.predict(xnew)\n",
"\n",
@@ -460,8 +470,7 @@
"Depending on the parameter in front of the normal distribution, we may\n",
"have a small or larger relative error. Try to play around with\n",
"different training data sets and study (graphically) the value of the\n",
- "relative error. Note also that **Scikit-Learn** requires a matrix as input for the input values $x$ and $y$. In the above code we have\n",
- "solved this by declaring $x$ and $y$ as arrays of dimension $n\\times 1$.\n",
+ "relative error.\n",
"\n",
"As mentioned above, **Scikit-Learn** has an impressive functionality.\n",
"We can for example extract the values of $\\alpha$ and $\\beta$ and\n",
@@ -1039,7 +1048,7 @@
"metadata": {},
"source": [
"The next step, and we will define this mathematically later, is to set up the so-called **design matrix**. We will throughout call this matrix $\\boldsymbol{X}$.\n",
- "It has dimensionality $p\\times n$, where $n$ is the number of data points and $p$ are the so-called predictors. In our case here they are given by the number of polynomials in $A$ we wish to include in the fit."
+ "It has dimensionality $n\\times p$, where $n$ is the number of data points and $p$ are the so-called predictors. In our case here they are given by the number of polynomials in $A$ we wish to include in the fit."
]
},
{
@@ -1064,9 +1073,12 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "Note well that we have made life simple here. We perform a fit in terms of the number of nucleons only. A more sophisticated fit can be done by including an explicit dependence on the number of protons and neutrons in the asymmetry and Coulomb terms.\n",
+ "Note well that we have made life simple here. We perform a fit in\n",
+ "terms of the number of nucleons only. A more sophisticated fit can be\n",
+ "done by including an explicit dependence on the number of protons and\n",
+ "neutrons in the asymmetry and Coulomb terms. We leave this as an exercise to you the reader.\n",
"\n",
- "With **scikitlearn** we are now ready to use linear regression and fit our data."
+ "With **Scikit-Learn** we are now ready to use linear regression and fit our data."
]
},
{
@@ -1124,7 +1136,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "As a teaser, let us now see how we can do this with decision trees using **scikit-learn**. Later we will switch to so-called **random forests**!"
+ "As a teaser, let us now see how we can do this with decision trees using **Scikit-Learn**. Later we will switch to so-called **random forests**!"
]
},
{
@@ -1172,6 +1184,17 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "With a deeper and deeper tree level, we can almost reproduce every\n",
+ "single data point by increasing the max depth of the tree.\n",
+ "We can actually decide to make a decision tree which fits every single point.\n",
+ "As we will\n",
+ "see later, this has the benefit that we can really train a model which\n",
+ "traverses every single data point. However, the price we pay is that\n",
+ "we will easily overfit. That is, if we apply our model to unseen data,\n",
+ "we will most likely fail miserably in our attempt at making\n",
+ "predictions. As an exercise, try to make the tree level larger by adjusting the maximum depth variable. When printing out the predicition, you will note that the binding energy of every nucleus is accurately reproduced.\n",
+ "\n",
+ "\n",
"The **seaborn** package allows us to visualize data in an efficient way. Note that we use **scikit-learn**'s multi-layer perceptron (or feed forward neural network) \n",
"functionality."
]
@@ -1977,6 +2000,47 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "We can then compute the second derivative of the cost function, which in our case is the second derivative\n",
+ "of the means squared error. This leads to"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\frac{\\partial^2 C(\\boldsymbol{\\beta})}{\\partial \\boldsymbol{\\beta}^T\\partial \\boldsymbol{\\beta}} =\\frac{2}{n}\\boldsymbol{X}^T\\boldsymbol{X}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This quantity defines was what is called the Hessian matrix (the second derivative of a function we want to optimize).\n",
+ "\n",
+ "The Hessian matrix plays an important role and is defined for the mean squared error as"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\boldsymbol{H}=\\boldsymbol{X}^T\\boldsymbol{X}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The Hessian matrix for ordinary least squares is also proportional to\n",
+ "the covariance matrix. As we will see in the chapter on Ridge and Lasso regression, This means that we can use the Singular Value Decomposition of a matrix to find\n",
+ "the eigenvalues of the covariance matrix and the Hessian matrix in\n",
+ "terms of the singular values.\n",
+ "\n",
+ "\n",
"The residuals $\\boldsymbol{\\epsilon}$ are in turn given by"
]
},
@@ -2529,9 +2593,7 @@
"**pandas** again, rather extensively in order to organize our data.\n",
"\n",
"The difference now is that we use **Scikit-Learn's** regression tools\n",
- "instead of our own matrix inversion implementation. Furthermore, we\n",
- "sneak in **Ridge** regression (to be discussed below) which includes a\n",
- "hyperparameter $\\lambda$, also to be explained below."
+ "instead of our own matrix inversion implementation."
]
},
{
@@ -2603,18 +2665,6 @@
"print('Mean absolute error: %.2f' % mean_absolute_error(Energies, ytilde))\n",
"print(clf.coef_, clf.intercept_)\n",
"\n",
- "# The Ridge regression with a hyperparameter lambda = 0.1\n",
- "_lambda = 0.1\n",
- "clf_ridge = skl.Ridge(alpha=_lambda).fit(X, Energies)\n",
- "yridge = clf_ridge.predict(X)\n",
- "EoS['Eridge'] = yridge\n",
- "# The mean squared error \n",
- "print(\"Mean squared error: %.2f\" % mean_squared_error(Energies, yridge))\n",
- "# Explained variance score: 1 is perfect prediction \n",
- "print('Variance score: %.2f' % r2_score(Energies, yridge))\n",
- "# Mean absolute error \n",
- "print('Mean absolute error: %.2f' % mean_absolute_error(Energies, yridge))\n",
- "print(clf_ridge.coef_, clf_ridge.intercept_)\n",
"\n",
"fig, ax = plt.subplots()\n",
"ax.set_xlabel(r'$\\rho[\\mathrm{fm}^{-3}]$')\n",
@@ -2623,8 +2673,6 @@
" label='Theoretical data')\n",
"ax.plot(EoS['Density'], EoS['Eols'], alpha=0.7, lw=2, c='m',\n",
" label='OLS')\n",
- "ax.plot(EoS['Density'], EoS['Eridge'], alpha=0.7, lw=2, c='g',\n",
- " label='Ridge $\\lambda = 0.1$')\n",
"ax.legend()\n",
"save_fig(\"EoSfitting\")\n",
"plt.show()"
@@ -2637,13 +2685,11 @@
"The above simple polynomial in density $\\rho$ gives an excellent fit\n",
"to the data. \n",
"\n",
- "We note also that there is a small deviation between the\n",
- "standard OLS and the Ridge regression at higher densities. We discuss this in more detail\n",
- "below.\n",
"\n",
"\n",
"## Splitting our Data in Training and Test data\n",
"\n",
+ "\n",
"It is normal in essentially all Machine Learning studies to split the\n",
"data in a training set and a test set (sometimes also an additional\n",
"validation set). **Scikit-Learn** has an own function for this. There\n",
@@ -2653,6 +2699,107 @@
"postpone a discussion of this splitting to the end of these notes and\n",
"our discussion of the so-called **bias-variance** tradeoff. Here we\n",
"limit ourselves to repeat the above equation of state fitting example\n",
+ "but now splitting the data into a training set and a test set.\n",
+ "\n",
+ "Let us study some examples. The first code here takes a simple\n",
+ "one-dimensional second-order polynomial and we fit it to a\n",
+ "second-order polynomial. Depending on the strength of the added noise,\n",
+ "the various measures like the $R2$ score or the mean-squared error,\n",
+ "the fit becomes better or worse."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import matplotlib.pyplot as plt\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "\n",
+ "\n",
+ "def R2(y_data, y_model):\n",
+ " return 1 - np.sum((y_data - y_model) ** 2) / np.sum((y_data - np.mean(y_data)) ** 2)\n",
+ "def MSE(y_data,y_model):\n",
+ " n = np.size(y_model)\n",
+ " return np.sum((y_data-y_model)**2)/n\n",
+ "\n",
+ "x = np.random.rand(100)\n",
+ "y = 2.0+5*x*x+0.1*np.random.randn(100)\n",
+ "\n",
+ "\n",
+ "# The design matrix now as function of a given polynomial\n",
+ "X = np.zeros((len(x),3))\n",
+ "X[:,0] = 1.0\n",
+ "X[:,1] = x\n",
+ "X[:,2] = x**2\n",
+ "# We split the data in test and training data\n",
+ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)\n",
+ "# matrix inversion to find beta\n",
+ "beta = np.linalg.inv(X_train.T @ X_train) @ X_train.T @ y_train\n",
+ "print(beta)\n",
+ "# and then make the prediction\n",
+ "ytilde = X_train @ beta\n",
+ "print(\"Training R2\")\n",
+ "print(R2(y_train,ytilde))\n",
+ "print(\"Training MSE\")\n",
+ "print(MSE(y_train,ytilde))\n",
+ "ypredict = X_test @ beta\n",
+ "print(\"Test R2\")\n",
+ "print(R2(y_test,ypredict))\n",
+ "print(\"Test MSE\")\n",
+ "print(MSE(y_test,ypredict))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Alternatively, you could write your own test-train splitting function as shown here."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# equivalently in numpy\n",
+ "def train_test_split_numpy(inputs, labels, train_size, test_size):\n",
+ " n_inputs = len(inputs)\n",
+ " inputs_shuffled = inputs.copy()\n",
+ " labels_shuffled = labels.copy()\n",
+ "\n",
+ " np.random.shuffle(inputs_shuffled)\n",
+ " np.random.shuffle(labels_shuffled)\n",
+ "\n",
+ " train_end = int(n_inputs*train_size)\n",
+ " X_train, X_test = inputs_shuffled[:train_end], inputs_shuffled[train_end:]\n",
+ " Y_train, Y_test = labels_shuffled[:train_end], labels_shuffled[train_end:]\n",
+ "\n",
+ " return X_train, X_test, Y_train, Y_test"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "But since **scikit-learn** has its own function for doing this and since\n",
+ "it interfaces easily with **tensorflow** and other libraries, we\n",
+ "normally recommend using the latter functionality.\n",
+ "\n",
+ "\n",
+ "As another example, we apply the training and testing split to \n",
+ "to the above equation of state fitting example\n",
"but now splitting the data into a training set and a test set."
]
},
@@ -3050,119 +3197,6 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Splitting our Data in Training and Test data\n",
- "\n",
- "\n",
- "It is normal in essentially all Machine Learning studies to split the\n",
- "data in a training set and a test set (sometimes also an additional\n",
- "validation set). **Scikit-Learn** has an own function for this. There\n",
- "is no explicit recipe for how much data should be included as training\n",
- "data and say test data. An accepted rule of thumb is to use\n",
- "approximately $2/3$ to $4/5$ of the data as training data. We will\n",
- "postpone a discussion of this splitting to the end of these notes and\n",
- "our discussion of the so-called **bias-variance** tradeoff. Here we\n",
- "limit ourselves to repeat the above equation of state fitting example\n",
- "but now splitting the data into a training set and a test set.\n",
- "\n",
- "Let us study some examples. The first code here takes a simple\n",
- "one-dimensional second-order polynomial and we fit it to a\n",
- "second-order polynomial. Depending on the strength of the added noise,\n",
- "the various measures like the $R2$ score or the mean-squared error,\n",
- "the fit becomes better or worse."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": false,
- "editable": true
- },
- "outputs": [],
- "source": [
- "import os\n",
- "import numpy as np\n",
- "import pandas as pd\n",
- "import matplotlib.pyplot as plt\n",
- "from sklearn.model_selection import train_test_split\n",
- "\n",
- "\n",
- "def R2(y_data, y_model):\n",
- " return 1 - np.sum((y_data - y_model) ** 2) / np.sum((y_data - np.mean(y_data)) ** 2)\n",
- "def MSE(y_data,y_model):\n",
- " n = np.size(y_model)\n",
- " return np.sum((y_data-y_model)**2)/n\n",
- "\n",
- "x = np.random.rand(100)\n",
- "y = 2.0+5*x*x+0.1*np.random.randn(100)\n",
- "\n",
- "\n",
- "# The design matrix now as function of a given polynomial\n",
- "X = np.zeros((len(x),3))\n",
- "X[:,0] = 1.0\n",
- "X[:,1] = x\n",
- "X[:,2] = x**2\n",
- "# We split the data in test and training data\n",
- "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)\n",
- "# matrix inversion to find beta\n",
- "beta = np.linalg.inv(X_train.T @ X_train) @ X_train.T @ y_train\n",
- "print(beta)\n",
- "# and then make the prediction\n",
- "ytilde = X_train @ beta\n",
- "print(\"Training R2\")\n",
- "print(R2(y_train,ytilde))\n",
- "print(\"Training MSE\")\n",
- "print(MSE(y_train,ytilde))\n",
- "ypredict = X_test @ beta\n",
- "print(\"Test R2\")\n",
- "print(R2(y_test,ypredict))\n",
- "print(\"Test MSE\")\n",
- "print(MSE(y_test,ypredict))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Alternatively, you could write your own test-train splitting function as shown here."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": false,
- "editable": true
- },
- "outputs": [],
- "source": [
- "# equivalently in numpy\n",
- "def train_test_split_numpy(inputs, labels, train_size, test_size):\n",
- " n_inputs = len(inputs)\n",
- " inputs_shuffled = inputs.copy()\n",
- " labels_shuffled = labels.copy()\n",
- "\n",
- " np.random.shuffle(inputs_shuffled)\n",
- " np.random.shuffle(labels_shuffled)\n",
- "\n",
- " train_end = int(n_inputs*train_size)\n",
- " X_train, X_test = inputs_shuffled[:train_end], inputs_shuffled[train_end:]\n",
- " Y_train, Y_test = labels_shuffled[:train_end], labels_shuffled[train_end:]\n",
- "\n",
- " return X_train, X_test, Y_train, Y_test"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "But since **scikit-learn** has its own function for doing this and since\n",
- "it interfaces easily with **tensorflow** and other libraries, we\n",
- "normally recommend using the latter functionality.\n",
- "\n",
- "\n",
- "\n",
- "\n",
"## Reducing the number of degrees of freedom, overarching view\n",
"\n",
"Many Machine Learning problems involve thousands or even millions of\n",
diff --git a/doc/LectureNotes/_build/html/_sources/chapter2.ipynb b/doc/LectureNotes/_build/html/_sources/chapter2.ipynb
index 651eadf4a..3049b1030 100644
--- a/doc/LectureNotes/_build/html/_sources/chapter2.ipynb
+++ b/doc/LectureNotes/_build/html/_sources/chapter2.ipynb
@@ -13,7 +13,7 @@
"What is presented here is a mathematical analysis of various regression algorithms (ordinary least squares, Ridge and Lasso Regression). The analysis is based on an important algorithm in linear algebra, the so-called Singular Value Decomposition (SVD). \n",
"\n",
"\n",
- "We have shown that in ordinary least squares the optimal parameters $\\beta$ are given by"
+ "We have shown that in ordinary least squares (OLS) the optimal parameters $\\beta$ are given by"
]
},
{
@@ -21,7 +21,7 @@
"metadata": {},
"source": [
"$$\n",
- "\\hat{\\boldsymbol{\\beta}} = \\left(\\boldsymbol{X}^T\\boldsymbol{X}\\right)^{-1}\\boldsymbol{X}^T\\boldsymbol{y}.\n",
+ "\\hat{\\boldsymbol{\\beta}}_{\\mathrm{OLS}} = \\left(\\boldsymbol{X}^T\\boldsymbol{X}\\right)^{-1}\\boldsymbol{X}^T\\boldsymbol{y}.\n",
"$$"
]
},
@@ -79,7 +79,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The matrix $\\boldsymbol{A}$ has the important property that $\\boldsymbol{A}^2=\\boldsymbol{A}$. This is the definition of a projection matrix.\n",
+ "The matrix $\\boldsymbol{A}$ has the important property that $\\boldsymbol{A}^2=\\boldsymbol{A}$. This is the definition of a [projection matrix](https://en.wikipedia.org/wiki/Projection_matrix).\n",
"We can then interpret our optimal model $\\tilde{\\boldsymbol{y}}$ as being represented by an orthogonal projection of $\\boldsymbol{y}$ onto a space defined by the column vectors of $\\boldsymbol{X}$. In our case here the matrix $\\boldsymbol{A}$ is a square matrix. If it is a general rectangular matrix we have an oblique projection matrix.\n",
"\n",
"\n",
@@ -545,7 +545,7 @@
"\n",
"## Code for SVD and Inversion of Matrices\n",
"\n",
- "How do we use the SVD to invert a matrix $\\boldsymbol{X}^\\boldsymbol{X}$ which is singular or near singular?\n",
+ "How do we use the SVD to invert a matrix $\\boldsymbol{X}^T\\boldsymbol{X}$ which is singular or near singular?\n",
"The simple answer is to use the linear algebra function for the pseudoinverse, that is"
]
},
@@ -3258,6 +3258,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "**More text will be added to this example.**\n",
+ "\n",
"## Linking the regression analysis with a statistical interpretation\n",
"\n",
"We will now couple the discussions of ordinary least squares, Ridge\n",
@@ -3624,7 +3626,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "It is a conditional probability (see below) and reads as the likelihood of a domain of events $\\boldsymbol{D}$ given a set of parameters $\\boldsymbol{\\beta}$.\n",
+ "It is a conditional probability (see below) and reads as the\n",
+ "likelihood of a domain of events $\\boldsymbol{D}$ given a set of parameters\n",
+ "$\\boldsymbol{\\beta}$.\n",
"\n",
"\n",
"In statistics, maximum likelihood estimation (MLE) is a method of\n",
@@ -3728,7 +3732,7 @@
"We define also the likelihood for $X$ and $Y$ as $p(X)$ and $p(Y)$ respectively.\n",
"The likelihood of a specific event $x_i$ (or $y_i$) is then written as $p(X=x_i)$ or just $p(x_i)=p_i$. \n",
"\n",
- "**Union of events is given by.**"
+ "The union of events is given by"
]
},
{
@@ -3744,7 +3748,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "**The product rule (aka joint probability) is given by.**"
+ "The product rule (aka joint probability) is given by"
]
},
{
@@ -3762,8 +3766,6 @@
"source": [
"where we read $p(X\\vert Y)$ as the likelihood of obtaining $X$ given $Y$.\n",
"\n",
- "\n",
- "\n",
"If we have independent events then $p(X,Y)=p(X)p(Y)$.\n",
"\n",
"\n",
@@ -3840,21 +3842,27 @@
"the parameter space represented by $X$. This function is not\n",
"necesseraly normalized and is normally called the likelihood function.\n",
"\n",
- "The function $p(X)$ on the right hand side is called the prior while the function on the left hand side is the called the posterior probability. The denominator on the right hand side serves as a normalization factor for the posterior distribution.\n",
+ "The function $p(X)$ on the right hand side is called the prior while\n",
+ "the function on the left hand side is the called the posterior\n",
+ "probability. The denominator on the right hand side serves as a\n",
+ "normalization factor for the posterior distribution.\n",
"\n",
"Let us try to illustrate Bayes' theorem through an example.\n",
"\n",
"\n",
- "Let us suppose that you are undergoing a series of mammography scans in\n",
- "order to rule out possible breast cancer cases. We define the\n",
+ "Let us suppose that you are undergoing a series of mammography scans\n",
+ "in order to rule out possible breast cancer cases. We define the\n",
"sensitivity for a positive event by the variable $X$. It takes binary\n",
"values with $X=1$ representing a positive event and $X=0$ being a\n",
"negative event. We reserve $Y$ as a classification parameter for\n",
- "either a negative or a positive breast cancer confirmation. (Short note on wordings: positive here means having breast cancer, although none of us would consider this being a positive thing).\n",
+ "either a negative or a positive breast cancer confirmation. (Short\n",
+ "note on wordings: positive here means having breast cancer, although\n",
+ "none of us would consider this being a positive thing).\n",
"\n",
"We let $Y=1$ represent the the case of having breast cancer and $Y=0$ as not.\n",
"\n",
- "Let us assume that if you have breast cancer, the test will be positive with a probability of $0.8$, that is we have"
+ "Let us assume that if you have breast cancer, the test will be positive with a probability of $0.8$ (the numbers here are all made up),\n",
+ "that is we have"
]
},
{
@@ -3870,12 +3878,32 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "This obviously sounds scary since many would conclude that if the test is positive, there is a likelihood of $80\\%$ for having cancer.\n",
- "It is however not correct, as the following Bayesian analysis shows.\n",
+ "This obviously sounds scary since many would conclude that if the test\n",
+ "is positive, there is a likelihood of $80\\%$ for having cancer. It is\n",
+ "however not correct, as the following Bayesian analysis shows. The correct question to pose is *what is the probability of having breast cancer in case of a positive test?*\n",
+ "We are thus interested in"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "p(Y=1\\vert X=1),\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "instead of $p(X=1\\vert Y=1)$.\n",
"\n",
"\n",
- "If we look at various national surveys on breast cancer, the general likelihood of developing breast cancer is a very small number.\n",
- "Let us assume that the prior probability in the population as a whole is"
+ "\n",
+ "If we look at various national surveys on breast cancer, the general\n",
+ "likelihood of developing breast cancer is a very small number. Let us\n",
+ "assume that the prior probability in the population as a whole is"
]
},
{
@@ -3891,7 +3919,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "We need also to account for the fact that the test may produce a false positive result (false alarm). Let us here assume that we have"
+ "We need also to account for the fact that the test may produce a false\n",
+ "positive result (false alarm). Let us here assume that we have"
]
},
{
@@ -3907,15 +3936,38 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "Using Bayes' theorem we can then find the posterior probability that the person has breast cancer in case of a positive test, that is we can compute"
+ "Using Bayes' theorem we can then find the posterior probability that\n",
+ "the person has breast cancer in case of a positive test, that is we\n",
+ "can compute"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
+ "\n",
+ "\n",
"$$\n",
- "p(Y=1\\vert X=1)=\\frac{p(X=1\\vert Y=1)p(Y=1)}{p(X=1\\vert Y=1)p(Y=1)+p(X=1\\vert Y=0)p(Y=0)}=\\frac{0.8\\times 0.004}{0.8\\times 0.004+0.1\\times 0.996}=0.031.\n",
+ "\\begin{equation}\n",
+ "p(Y=1\\vert X=1)=\\frac{p(X=1\\vert Y=1)p(Y=1)}{p(X=1\\vert Y=1)p(Y=1)+p(X=1\\vert Y=0)p(Y=0)}= \n",
+ "\\label{_auto2} \\tag{2}\n",
+ "\\end{equation}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "$$\n",
+ "\\begin{equation} \n",
+ " \\frac{0.8\\times 0.004}{0.8\\times 0.004+0.1\\times 0.996}=0.031.\n",
+ "\\label{_auto3} \\tag{3}\n",
+ "\\end{equation}\n",
"$$"
]
},
@@ -3941,9 +3993,12 @@
"parameters $\\boldsymbol{\\beta}$ using OLS, Ridge and Lasso regression. For\n",
"OLS, you will notice as function of the noise and polynomial degree,\n",
"that the parameters $\\beta$ will fluctuate from order to order in the\n",
- "polynomial fit and that for larger and larger polynomial degrees of freedom, the parameters will tend to increase in value for OLS.\n",
+ "polynomial fit and that for larger and larger polynomial degrees of\n",
+ "freedom, the parameters will tend to increase in value for OLS.\n",
"\n",
- "For Ridge and Lasso regression, the higher order parameters will typically be reduced, providing thereby less fluctuations from one order to another one."
+ "For Ridge and Lasso regression, the higher order parameters will\n",
+ "typically be reduced, providing thereby less fluctuations from one\n",
+ "order to another one."
]
},
{
@@ -4008,8 +4063,8 @@
" # Compute the MSE and print it\n",
" MSERidgePredict[i] = MSE(y_test,ypredictRidge)\n",
" MSELassoPredict[i] = MSE(y_test,ypredictLasso)\n",
- " print(lmb,RegRidge.coef_)\n",
- " print(lmb,RegLasso.coef_)\n",
+ "# print(lmb,RegRidge.coef_)\n",
+ "# print(lmb,RegLasso.coef_)\n",
"# Now plot the results\n",
"plt.figure()\n",
"plt.plot(np.log10(lambdas), MSERidgePredict, 'b', label = 'MSE Ridge Test')\n",
@@ -4024,10 +4079,13 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "How can we understand this? \n",
+ "How can we understand this? **More text to be added**.\n",
"\n",
"\n",
"\n",
+ "## Linking Bayes' Theorem with Ridge and Lasso Regression\n",
+ "\n",
+ "\n",
"Using Bayes' theorem we can gain a better intuition about Ridge and Lasso regression. \n",
"\n",
"For ordinary least squares we postulated that the maximum likelihood for the doamin of events $\\boldsymbol{D}$ (one-dimensional case)"
diff --git a/doc/LectureNotes/_build/html/_sources/chapter3.ipynb b/doc/LectureNotes/_build/html/_sources/chapter3.ipynb
index d7f8222d5..b2933e098 100644
--- a/doc/LectureNotes/_build/html/_sources/chapter3.ipynb
+++ b/doc/LectureNotes/_build/html/_sources/chapter3.ipynb
@@ -575,196 +575,6 @@
"plt.show()"
]
},
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Various steps in cross-validation\n",
- "\n",
- "When the repetitive splitting of the data set is done randomly,\n",
- "samples may accidently end up in a fast majority of the splits in\n",
- "either training or test set. Such samples may have an unbalanced\n",
- "influence on either model building or prediction evaluation. To avoid\n",
- "this $k$-fold cross-validation structures the data splitting. The\n",
- "samples are divided into $k$ more or less equally sized exhaustive and\n",
- "mutually exclusive subsets. In turn (at each split) one of these\n",
- "subsets plays the role of the test set while the union of the\n",
- "remaining subsets constitutes the training set. Such a splitting\n",
- "warrants a balanced representation of each sample in both training and\n",
- "test set over the splits. Still the division into the $k$ subsets\n",
- "involves a degree of randomness. This may be fully excluded when\n",
- "choosing $k=n$. This particular case is referred to as leave-one-out\n",
- "cross-validation (LOOCV). \n",
- "\n",
- "\n",
- "* Define a range of interest for the penalty parameter.\n",
- "\n",
- "* Divide the data set into training and test set comprising samples $\\{1, \\ldots, n\\} \\setminus i$ and $\\{ i \\}$, respectively.\n",
- "\n",
- "* Fit the linear regression model by means of ridge estimation for each $\\lambda$ in the grid using the training set, and the corresponding estimate of the error variance $\\boldsymbol{\\sigma}_{-i}^2(\\lambda)$, as"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "$$\n",
- "\\begin{align*}\n",
- "\\boldsymbol{\\beta}_{-i}(\\lambda) & = ( \\boldsymbol{X}_{-i, \\ast}^{T}\n",
- "\\boldsymbol{X}_{-i, \\ast} + \\lambda \\boldsymbol{I}_{pp})^{-1}\n",
- "\\boldsymbol{X}_{-i, \\ast}^{T} \\boldsymbol{y}_{-i}\n",
- "\\end{align*}\n",
- "$$"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "* Evaluate the prediction performance of these models on the test set by $\\log\\{L[y_i, \\boldsymbol{X}_{i, \\ast}; \\boldsymbol{\\beta}_{-i}(\\lambda), \\boldsymbol{\\sigma}_{-i}^2(\\lambda)]\\}$. Or, by the prediction error $|y_i - \\boldsymbol{X}_{i, \\ast} \\boldsymbol{\\beta}_{-i}(\\lambda)|$, the relative error, the error squared or the R2 score function.\n",
- "\n",
- "* Repeat the first three steps such that each sample plays the role of the test set once.\n",
- "\n",
- "* Average the prediction performances of the test sets at each grid point of the penalty bias/parameter. It is an estimate of the prediction performance of the model corresponding to this value of the penalty parameter on novel data. It is defined as"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "$$\n",
- "\\begin{align*}\n",
- "\\frac{1}{n} \\sum_{i = 1}^n \\log\\{L[y_i, \\mathbf{X}_{i, \\ast}; \\boldsymbol{\\beta}_{-i}(\\lambda), \\boldsymbol{\\sigma}_{-i}^2(\\lambda)]\\}.\n",
- "\\end{align*}\n",
- "$$"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For the various values of $k$\n",
- "\n",
- "1. shuffle the dataset randomly.\n",
- "\n",
- "2. Split the dataset into $k$ groups.\n",
- "\n",
- "3. For each unique group:\n",
- "\n",
- "a. Decide which group to use as set for test data\n",
- "\n",
- "b. Take the remaining groups as a training data set\n",
- "\n",
- "c. Fit a model on the training set and evaluate it on the test set\n",
- "\n",
- "d. Retain the evaluation score and discard the model\n",
- "\n",
- "\n",
- "5. Summarize the model using the sample of model evaluation scores\n",
- "\n",
- "The code here uses Ridge regression with cross-validation (CV) resampling and $k$-fold CV in order to fit a specific polynomial."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": false,
- "editable": true
- },
- "outputs": [],
- "source": [
- "import numpy as np\n",
- "import matplotlib.pyplot as plt\n",
- "from sklearn.model_selection import KFold\n",
- "from sklearn.linear_model import Ridge\n",
- "from sklearn.model_selection import cross_val_score\n",
- "from sklearn.preprocessing import PolynomialFeatures\n",
- "\n",
- "# A seed just to ensure that the random numbers are the same for every run.\n",
- "# Useful for eventual debugging.\n",
- "np.random.seed(3155)\n",
- "\n",
- "# Generate the data.\n",
- "nsamples = 100\n",
- "x = np.random.randn(nsamples)\n",
- "y = 3*x**2 + np.random.randn(nsamples)\n",
- "\n",
- "## Cross-validation on Ridge regression using KFold only\n",
- "\n",
- "# Decide degree on polynomial to fit\n",
- "poly = PolynomialFeatures(degree = 6)\n",
- "\n",
- "# Decide which values of lambda to use\n",
- "nlambdas = 500\n",
- "lambdas = np.logspace(-3, 5, nlambdas)\n",
- "\n",
- "# Initialize a KFold instance\n",
- "k = 5\n",
- "kfold = KFold(n_splits = k)\n",
- "\n",
- "# Perform the cross-validation to estimate MSE\n",
- "scores_KFold = np.zeros((nlambdas, k))\n",
- "\n",
- "i = 0\n",
- "for lmb in lambdas:\n",
- " ridge = Ridge(alpha = lmb)\n",
- " j = 0\n",
- " for train_inds, test_inds in kfold.split(x):\n",
- " xtrain = x[train_inds]\n",
- " ytrain = y[train_inds]\n",
- "\n",
- " xtest = x[test_inds]\n",
- " ytest = y[test_inds]\n",
- "\n",
- " Xtrain = poly.fit_transform(xtrain[:, np.newaxis])\n",
- " ridge.fit(Xtrain, ytrain[:, np.newaxis])\n",
- "\n",
- " Xtest = poly.fit_transform(xtest[:, np.newaxis])\n",
- " ypred = ridge.predict(Xtest)\n",
- "\n",
- " scores_KFold[i,j] = np.sum((ypred - ytest[:, np.newaxis])**2)/np.size(ypred)\n",
- "\n",
- " j += 1\n",
- " i += 1\n",
- "\n",
- "\n",
- "estimated_mse_KFold = np.mean(scores_KFold, axis = 1)\n",
- "\n",
- "## Cross-validation using cross_val_score from sklearn along with KFold\n",
- "\n",
- "# kfold is an instance initialized above as:\n",
- "# kfold = KFold(n_splits = k)\n",
- "\n",
- "estimated_mse_sklearn = np.zeros(nlambdas)\n",
- "i = 0\n",
- "for lmb in lambdas:\n",
- " ridge = Ridge(alpha = lmb)\n",
- "\n",
- " X = poly.fit_transform(x[:, np.newaxis])\n",
- " estimated_mse_folds = cross_val_score(ridge, X, y[:, np.newaxis], scoring='neg_mean_squared_error', cv=kfold)\n",
- "\n",
- " # cross_val_score return an array containing the estimated negative mse for every fold.\n",
- " # we have to the the mean of every array in order to get an estimate of the mse of the model\n",
- " estimated_mse_sklearn[i] = np.mean(-estimated_mse_folds)\n",
- "\n",
- " i += 1\n",
- "\n",
- "## Plot and compare the slightly different ways to perform cross-validation\n",
- "\n",
- "plt.figure()\n",
- "\n",
- "plt.plot(np.log10(lambdas), estimated_mse_sklearn, label = 'cross_val_score')\n",
- "plt.plot(np.log10(lambdas), estimated_mse_KFold, 'r--', label = 'KFold')\n",
- "\n",
- "plt.xlabel('log10(lambda)')\n",
- "plt.ylabel('mse')\n",
- "\n",
- "plt.legend()\n",
- "\n",
- "plt.show()"
- ]
- },
{
"cell_type": "markdown",
"metadata": {},
@@ -1221,6 +1031,203 @@
"plt.show()"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Cross-validation\n",
+ "\n",
+ "When the repetitive splitting of the data set is done randomly,\n",
+ "samples may accidently end up in a fast majority of the splits in\n",
+ "either training or test set. Such samples may have an unbalanced\n",
+ "influence on either model building or prediction evaluation. To avoid\n",
+ "this $k$-fold cross-validation structures the data splitting. The\n",
+ "samples are divided into $k$ more or less equally sized exhaustive and\n",
+ "mutually exclusive subsets. In turn (at each split) one of these\n",
+ "subsets plays the role of the test set while the union of the\n",
+ "remaining subsets constitutes the training set. Such a splitting\n",
+ "warrants a balanced representation of each sample in both training and\n",
+ "test set over the splits. Still the division into the $k$ subsets\n",
+ "involves a degree of randomness. This may be fully excluded when\n",
+ "choosing $k=n$. This particular case is referred to as leave-one-out\n",
+ "cross-validation (LOOCV). \n",
+ "\n",
+ "\n",
+ "* Define a range of interest for the penalty parameter.\n",
+ "\n",
+ "* Divide the data set into training and test set comprising samples $\\{1, \\ldots, n\\} \\setminus i$ and $\\{ i \\}$, respectively.\n",
+ "\n",
+ "* Fit the linear regression model by means of ridge estimation for each $\\lambda$ in the grid using the training set, and the corresponding estimate of the error variance $\\boldsymbol{\\sigma}_{-i}^2(\\lambda)$, as"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\begin{align*}\n",
+ "\\boldsymbol{\\beta}_{-i}(\\lambda) & = ( \\boldsymbol{X}_{-i, \\ast}^{T}\n",
+ "\\boldsymbol{X}_{-i, \\ast} + \\lambda \\boldsymbol{I}_{pp})^{-1}\n",
+ "\\boldsymbol{X}_{-i, \\ast}^{T} \\boldsymbol{y}_{-i}\n",
+ "\\end{align*}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "* Evaluate the prediction performance of these models on the test set by $\\log\\{L[y_i, \\boldsymbol{X}_{i, \\ast}; \\boldsymbol{\\beta}_{-i}(\\lambda), \\boldsymbol{\\sigma}_{-i}^2(\\lambda)]\\}$. Or, by the prediction error $|y_i - \\boldsymbol{X}_{i, \\ast} \\boldsymbol{\\beta}_{-i}(\\lambda)|$, the relative error, the error squared or the R2 score function.\n",
+ "\n",
+ "* Repeat the first three steps such that each sample plays the role of the test set once.\n",
+ "\n",
+ "* Average the prediction performances of the test sets at each grid point of the penalty bias/parameter. It is an estimate of the prediction performance of the model corresponding to this value of the penalty parameter on novel data. It is defined as"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\begin{align*}\n",
+ "\\frac{1}{n} \\sum_{i = 1}^n \\log\\{L[y_i, \\mathbf{X}_{i, \\ast}; \\boldsymbol{\\beta}_{-i}(\\lambda), \\boldsymbol{\\sigma}_{-i}^2(\\lambda)]\\}.\n",
+ "\\end{align*}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "For the various values of $k$\n",
+ "\n",
+ "1. shuffle the dataset randomly.\n",
+ "\n",
+ "2. Split the dataset into $k$ groups.\n",
+ "\n",
+ "3. For each unique group:\n",
+ "\n",
+ "a. Decide which group to use as set for test data\n",
+ "\n",
+ "b. Take the remaining groups as a training data set\n",
+ "\n",
+ "c. Fit a model on the training set and evaluate it on the test set\n",
+ "\n",
+ "d. Retain the evaluation score and discard the model\n",
+ "\n",
+ "\n",
+ "5. Summarize the model using the sample of model evaluation scores\n",
+ "\n",
+ "The code here uses Ridge regression with cross-validation (CV) resampling and $k$-fold CV in order to fit a specific polynomial."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "from sklearn.model_selection import KFold\n",
+ "from sklearn.linear_model import Ridge\n",
+ "from sklearn.model_selection import cross_val_score\n",
+ "from sklearn.preprocessing import PolynomialFeatures\n",
+ "\n",
+ "# A seed just to ensure that the random numbers are the same for every run.\n",
+ "# Useful for eventual debugging.\n",
+ "np.random.seed(3155)\n",
+ "\n",
+ "# Generate the data.\n",
+ "nsamples = 100\n",
+ "x = np.random.randn(nsamples)\n",
+ "y = 3*x**2 + np.random.randn(nsamples)\n",
+ "\n",
+ "## Cross-validation on Ridge regression using KFold only\n",
+ "\n",
+ "# Decide degree on polynomial to fit\n",
+ "poly = PolynomialFeatures(degree = 6)\n",
+ "\n",
+ "# Decide which values of lambda to use\n",
+ "nlambdas = 500\n",
+ "lambdas = np.logspace(-3, 5, nlambdas)\n",
+ "\n",
+ "# Initialize a KFold instance\n",
+ "k = 5\n",
+ "kfold = KFold(n_splits = k)\n",
+ "\n",
+ "# Perform the cross-validation to estimate MSE\n",
+ "scores_KFold = np.zeros((nlambdas, k))\n",
+ "\n",
+ "i = 0\n",
+ "for lmb in lambdas:\n",
+ " ridge = Ridge(alpha = lmb)\n",
+ " j = 0\n",
+ " for train_inds, test_inds in kfold.split(x):\n",
+ " xtrain = x[train_inds]\n",
+ " ytrain = y[train_inds]\n",
+ "\n",
+ " xtest = x[test_inds]\n",
+ " ytest = y[test_inds]\n",
+ "\n",
+ " Xtrain = poly.fit_transform(xtrain[:, np.newaxis])\n",
+ " ridge.fit(Xtrain, ytrain[:, np.newaxis])\n",
+ "\n",
+ " Xtest = poly.fit_transform(xtest[:, np.newaxis])\n",
+ " ypred = ridge.predict(Xtest)\n",
+ "\n",
+ " scores_KFold[i,j] = np.sum((ypred - ytest[:, np.newaxis])**2)/np.size(ypred)\n",
+ "\n",
+ " j += 1\n",
+ " i += 1\n",
+ "\n",
+ "\n",
+ "estimated_mse_KFold = np.mean(scores_KFold, axis = 1)\n",
+ "\n",
+ "## Cross-validation using cross_val_score from sklearn along with KFold\n",
+ "\n",
+ "# kfold is an instance initialized above as:\n",
+ "# kfold = KFold(n_splits = k)\n",
+ "\n",
+ "estimated_mse_sklearn = np.zeros(nlambdas)\n",
+ "i = 0\n",
+ "for lmb in lambdas:\n",
+ " ridge = Ridge(alpha = lmb)\n",
+ "\n",
+ " X = poly.fit_transform(x[:, np.newaxis])\n",
+ " estimated_mse_folds = cross_val_score(ridge, X, y[:, np.newaxis], scoring='neg_mean_squared_error', cv=kfold)\n",
+ "\n",
+ " # cross_val_score return an array containing the estimated negative mse for every fold.\n",
+ " # we have to the the mean of every array in order to get an estimate of the mse of the model\n",
+ " estimated_mse_sklearn[i] = np.mean(-estimated_mse_folds)\n",
+ "\n",
+ " i += 1\n",
+ "\n",
+ "## Plot and compare the slightly different ways to perform cross-validation\n",
+ "\n",
+ "plt.figure()\n",
+ "\n",
+ "plt.plot(np.log10(lambdas), estimated_mse_sklearn, label = 'cross_val_score')\n",
+ "plt.plot(np.log10(lambdas), estimated_mse_KFold, 'r--', label = 'KFold')\n",
+ "\n",
+ "plt.xlabel('log10(lambda)')\n",
+ "plt.ylabel('mse')\n",
+ "\n",
+ "plt.legend()\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "More examples of the application of cross-validation follow here."
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
diff --git a/doc/LectureNotes/_build/html/_sources/chapter4.ipynb b/doc/LectureNotes/_build/html/_sources/chapter4.ipynb
index 7cd60a191..81b9d76c8 100644
--- a/doc/LectureNotes/_build/html/_sources/chapter4.ipynb
+++ b/doc/LectureNotes/_build/html/_sources/chapter4.ipynb
@@ -7,8 +7,6 @@
"# Logistic Regression\n",
"\n",
"\n",
- "[Video of Lecture](https://www.uio.no/studier/emner/matnat/fys/FYS-STK3155/h20/forelesningsvideoer/LectureSeptember18.mp4?vrtx=view-as-webpage)\n",
- "\n",
"\n",
"## Logistic Regression\n",
"\n",
@@ -911,7 +909,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Optimization, the central part of any Machine Learning algortithm\n",
+ "# Optimization, the central part of any Machine Learning algortithm\n",
"\n",
"Almost every problem in machine learning and data science starts with\n",
"a dataset $X$, a model $g(\\beta)$, which is a function of the\n",
@@ -924,7 +922,6 @@
"\n",
"\n",
"\n",
- "## Revisiting our Logistic Regression case\n",
"\n",
"In our discussion on Logistic Regression we studied the \n",
"case of\n",
@@ -953,7 +950,6 @@
"where $\\boldsymbol{\\beta}$ are the weights we wish to extract from data, in our case $\\beta_0$ and $\\beta_1$. \n",
"\n",
"\n",
- "## The equations to solve\n",
"\n",
"Our compact equations used a definition of a vector $\\boldsymbol{y}$ with $n$\n",
"elements $y_i$, an $n\\times p$ matrix $\\boldsymbol{X}$ which contains the\n",
@@ -995,7 +991,6 @@
"This defines what is called the Hessian matrix.\n",
"\n",
"\n",
- "## Solving using Newton-Raphson's method\n",
"\n",
"If we can set up these equations, Newton-Raphson's iterative method is normally the method of choice. It requires however that we can compute in an efficient way the matrices that define the first and second derivatives. \n",
"\n",
@@ -1036,9 +1031,6 @@
"If we can compute these matrices, in particular the Hessian, the above is often the easiest method to implement. \n",
"\n",
"\n",
- "\n",
- "## Brief reminder on Newton-Raphson's method\n",
- "\n",
"Let us quickly remind ourselves how we derive the above method.\n",
"\n",
"Perhaps the most celebrated of all one-dimensional root-finding\n",
@@ -1050,7 +1042,6 @@
"normally discourage the use of this method.\n",
"\n",
"\n",
- "## The equations\n",
"\n",
"The Newton-Raphson formula consists geometrically of extending the\n",
"tangent line at a current point until it crosses zero, then setting\n",
@@ -1125,8 +1116,6 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Simple geometric interpretation\n",
- "\n",
"The above is Newton-Raphson's method. It has a simple geometric\n",
"interpretation, namely $x_{n+1}$ is the point where the tangent from\n",
"$(x_n,f(x_n))$ crosses the $x$-axis. Close to the solution,\n",
@@ -1141,7 +1130,6 @@
"\n",
"\n",
"\n",
- "## Extending to more than one variable\n",
"\n",
"Newton's method can be generalized to systems of several non-linear equations\n",
"and variables. Consider the case with two equations"
@@ -1278,8 +1266,6 @@
"we are always moving towards smaller function values, i.e a minimum.\n",
"\n",
"\n",
- "## More on Steepest descent\n",
- "\n",
"The previous observation is the basis of the method of steepest\n",
"descent, which is also referred to as just gradient descent (GD). One\n",
"starts with an initial guess $\\mathbf{x}_0$ for a minimum of $F$ and\n",
@@ -1303,8 +1289,6 @@
"the learning rate within the context of Machine Learning.\n",
"\n",
"\n",
- "## The ideal\n",
- "\n",
"Ideally the sequence $\\{\\mathbf{x}_k \\}_{k=0}$ converges to a global\n",
"minimum of the function $F$. In general we do not know if we are in a\n",
"global or local minimum. In the special case when $F$ is a convex\n",
@@ -1325,7 +1309,6 @@
"\n",
"\n",
"\n",
- "## The sensitiveness of the gradient descent\n",
"\n",
"The gradient descent method \n",
"is sensitive to the choice of learning rate $\\gamma_k$. This is due\n",
@@ -1356,13 +1339,10 @@
"regular polygons (triangles, rectangles, pentagons, etc...).\n",
"\n",
"\n",
- "## Convex function\n",
"\n",
"**Convex function**: Let $X \\subset \\mathbb{R}^n$ be a convex set. Assume that the function $f: X \\rightarrow \\mathbb{R}$ is continuous, then $f$ is said to be convex if $$f(tx_1 + (1-t)x_2) \\leq tf(x_1) + (1-t)f(x_2) $$ for all $x_1, x_2 \\in X$ and for all $t \\in [0,1]$. If $\\leq$ is replaced with a strict inequaltiy in the definition, we demand $x_1 \\neq x_2$ and $t\\in(0,1)$ then $f$ is said to be strictly convex. For a single variable function, convexity means that if you draw a straight line connecting $f(x_1)$ and $f(x_2)$, the value of the function on the interval $[x_1,x_2]$ is always below the line as illustrated below.\n",
"\n",
"\n",
- "## Conditions on convex functions\n",
- "\n",
"In the following we state first and second-order conditions which\n",
"ensures convexity of a function $f$. We write $D_f$ to denote the\n",
"domain of $f$, i.e the subset of $R^n$ where $f$ is defined. For more\n",
@@ -1395,7 +1375,6 @@
"This condition is particularly useful since it gives us an procedure for determining if the function under consideration is convex, apart from using the definition.\n",
"\n",
"\n",
- "## More on convex functions\n",
"\n",
"The next result is of great importance to us and the reason why we are\n",
"going on about convex functions. In machine learning we frequently\n",
@@ -1418,7 +1397,7 @@
"This result means that if we know that the cost/loss function is convex and we are able to find a minimum, we are guaranteed that it is a global minimum.\n",
"\n",
"\n",
- "## Some simple problems\n",
+ "### Some simple problems\n",
"\n",
"1. Show that $f(x)=x^2$ is convex for $x \\in \\mathbb{R}$ using the definition of convexity. Hint: If you re-write the definition, $f$ is convex if the following holds for all $x,y \\in D_f$ and any $\\lambda \\in [0,1]$ $\\lambda f(x)+(1-\\lambda)f(y)-f(\\lambda x + (1-\\lambda) y ) \\geq 0$.\n",
"\n",
@@ -1443,13 +1422,6 @@
"Using the definition of convexity, try to show that a function satisfying the properties above is convex (the third condition is not needed to show this).\n",
"\n",
"\n",
- "\n",
- "## Friday September 25\n",
- "\n",
- "[Video of Lecture](https://www.uio.no/studier/emner/matnat/fys/FYS-STK4155/h20/forelesningsvideoer/LectureSeptember25.mp4?vrtx=view-as-webpage) and [link to handwritten notes](https://github.com/CompPhysics/MachineLearning/blob/master/doc/HandWrittenNotes/NotesSeptember25.pdf).\n",
- "\n",
- "\n",
- "\n",
"## Standard steepest descent\n",
"\n",
"\n",
@@ -1498,7 +1470,6 @@
"When we have found the exact solution, $\\boldsymbol{r}=0$.\n",
"\n",
"\n",
- "## Gradient method\n",
"\n",
"The residual is zero when we reach the minimum of the quadratic equation"
]
@@ -1520,9 +1491,6 @@
"symmetric. This defines also the Hessian and we want it to be positive definite. \n",
"\n",
"\n",
- "\n",
- "## Steepest descent method\n",
- "\n",
"We denote the initial guess for $\\boldsymbol{x}$ as $\\boldsymbol{x}_0$. \n",
"We can assume without loss of generality that"
]
@@ -1559,8 +1527,6 @@
"instead.\n",
"\n",
"\n",
- "\n",
- "## Steepest descent method\n",
"One can show that the solution $\\boldsymbol{x}$ is also the unique minimizer of the quadratic form"
]
},
@@ -1599,9 +1565,6 @@
"$\\boldsymbol{x}_0=0$ it is equal $-\\boldsymbol{b}$.\n",
"\n",
"\n",
- "\n",
- "\n",
- "## Final expressions\n",
"We can compute the residual iteratively as"
]
},
@@ -1678,13 +1641,6 @@
"$$"
]
},
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Steepest descent example"
- ]
- },
{
"cell_type": "code",
"execution_count": null,
@@ -1848,10 +1804,6 @@
"Two vectors are conjugate if they are orthogonal with respect to \n",
"this inner product. Being conjugate is a symmetric relation: if $\\boldsymbol{s}$ is conjugate to $\\boldsymbol{t}$, then $\\boldsymbol{t}$ is conjugate to $\\boldsymbol{s}$.\n",
"\n",
- "\n",
- "\n",
- "\n",
- "## Conjugate gradient method\n",
"An example is given by the eigenvectors of the matrix"
]
},
@@ -1868,13 +1820,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "which is zero unless $i=j$.\n",
+ "which is zero unless $i=j$. \n",
"\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "## Conjugate gradient method\n",
"Assume now that we have a symmetric positive-definite matrix $\\boldsymbol{A}$ of size\n",
"$n\\times n$. At each iteration $i+1$ we obtain the conjugate direction of a vector"
]
@@ -1910,7 +1857,6 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Conjugate gradient method\n",
"The coefficients are given by"
]
},
@@ -1959,8 +1905,6 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Conjugate gradient method and iterations\n",
- "\n",
"If we choose the conjugate vectors $\\boldsymbol{p}_k$ carefully, \n",
"then we may not need all of them to obtain a good approximation to the solution \n",
"$\\boldsymbol{x}$. \n",
@@ -2003,11 +1947,6 @@
"source": [
"instead.\n",
"\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "## Conjugate gradient method\n",
"One can show that the solution $\\boldsymbol{x}$ is also the unique minimizer of the quadratic form"
]
},
@@ -2047,11 +1986,6 @@
"The other vectors in the basis will be conjugate to the gradient, \n",
"hence the name conjugate gradient method.\n",
"\n",
- "\n",
- "\n",
- "\n",
- "\n",
- "## Conjugate gradient method\n",
"Let $\\boldsymbol{r}_k$ be the residual at the $k$-th step:"
]
},
@@ -2090,7 +2024,6 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Conjugate gradient method\n",
"We can also compute the residual iteratively as"
]
},
@@ -2155,14 +2088,14 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Revisiting our first homework\n",
+ "## Revisiting our Linear Regression Solvers\n",
"\n",
"We will use linear regression as a case study for the gradient descent\n",
"methods. Linear regression is a great test case for the gradient\n",
"descent methods discussed in the lectures since it has several\n",
"desirable properties such as:\n",
"\n",
- "1. An analytical solution (recall homework set 1).\n",
+ "1. An analytical solution.\n",
"\n",
"2. The gradient can be computed analytically.\n",
"\n",
@@ -2221,8 +2154,6 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Gradient descent example\n",
- "\n",
"Let $\\mathbf{y} = (y_1,\\cdots,y_n)^T$, $\\mathbf{\\boldsymbol{y}} = (\\boldsymbol{y}_1,\\cdots,\\boldsymbol{y}_n)^T$ and $\\beta = (\\beta_0, \\beta_1)^T$\n",
"\n",
"It is convenient to write $\\mathbf{\\boldsymbol{y}} = X\\beta$ where $X \\in \\mathbb{R}^{100 \\times 2} $ is the design matrix given by (we keep the intercept here)"
@@ -2264,8 +2195,6 @@
"and we want to find $\\beta$ such that $C(\\beta)$ is minimized.\n",
"\n",
"\n",
- "## The derivative of the cost/loss function\n",
- "\n",
"Computing $\\partial C(\\beta) / \\partial \\beta_0$ and $\\partial C(\\beta) / \\partial \\beta_1$ we can show that the gradient can be written as"
]
},
@@ -2287,7 +2216,6 @@
"where $X$ is the design matrix defined above.\n",
"\n",
"\n",
- "## The Hessian matrix\n",
"The Hessian matrix of $C(\\beta)$ is given by"
]
},
@@ -2311,10 +2239,6 @@
"\n",
"\n",
"\n",
- "\n",
- "\n",
- "## Simple program\n",
- "\n",
"We can now write a program that minimizes $C(\\beta)$ using the gradient descent method with a constant learning rate $\\gamma$ according to"
]
},
@@ -2339,9 +2263,8 @@
"$\\beta= (X^TX)^{-1} X^T \\mathbf{y}$.\n",
"\n",
"\n",
- "## Gradient Descent Example\n",
"\n",
- "Here our simple example"
+ "Here is our simple example"
]
},
{
@@ -2405,7 +2328,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## And a corresponding example using **scikit-learn**"
+ "Alternatively, we can use **Scikit-Learn** as done here"
]
},
{
@@ -2439,8 +2362,6 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Gradient descent and Ridge\n",
- "\n",
"We have also discussed Ridge regression where the loss function contains a regularized term given by the $L_2$ norm of $\\beta$,"
]
},
@@ -2487,13 +2408,6 @@
"$$"
]
},
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Program example for gradient descent with Ridge Regression"
- ]
- },
{
"cell_type": "code",
"execution_count": null,
@@ -2590,8 +2504,6 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Computation of gradients\n",
- "\n",
"This in turn means that the gradient can be\n",
"computed as a sum over $i$-gradients"
]
@@ -2617,7 +2529,7 @@
"$k=1,\\cdots,n/M$.\n",
"\n",
"\n",
- "## SGD example\n",
+ "\n",
"As an example, suppose we have $10$ data points $(\\mathbf{x}_1,\\cdots, \\mathbf{x}_{10})$ \n",
"and we choose to have $M=5$ minibathces,\n",
"then each minibatch contains two data points. In particular we have\n",
@@ -2648,8 +2560,6 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## The gradient step\n",
- "\n",
"Thus a gradient descent step now looks like"
]
},
@@ -2671,10 +2581,7 @@
"probability from $[1,n/M]$. An iteration over the number of\n",
"minibathces (n/M) is commonly referred to as an epoch. Thus it is\n",
"typical to choose a number of epochs and for each epoch iterate over\n",
- "the number of minibatches, as exemplified in the code below.\n",
- "\n",
- "\n",
- "## Simple example code"
+ "the number of minibatches, as exemplified in the code below."
]
},
{
@@ -2715,7 +2622,6 @@
"all $n$ datapoints.\n",
"\n",
"\n",
- "## When do we stop?\n",
"\n",
"A natural question is when do we stop the search for a new minimum?\n",
"One possibility is to compute the full gradient after a given number\n",
@@ -2729,7 +2635,6 @@
"gave the lowest value.\n",
"\n",
"\n",
- "## Slightly different approach\n",
"\n",
"Another approach is to let the step length $\\gamma_j$ depend on the\n",
"number of epochs in such a way that it becomes very small after a\n",
@@ -2783,7 +2688,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Program for stochastic gradient"
+ "### Program for stochastic gradient"
]
},
{
@@ -2865,7 +2770,922 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "**Challenge**: try to write a similar code for a Logistic Regression case."
+ "## Momentum based GD\n",
+ "\n",
+ "The stochastic gradient descent (SGD) is almost always used with a\n",
+ "*momentum* or inertia term that serves as a memory of the direction we\n",
+ "are moving in parameter space. This is typically implemented as\n",
+ "follows"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\mathbf{v}_{t}=\\gamma \\mathbf{v}_{t-1}+\\eta_{t}\\nabla_\\theta E(\\boldsymbol{\\theta}_t) \\nonumber\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "$$\n",
+ "\\begin{equation} \n",
+ "\\boldsymbol{\\theta}_{t+1}= \\boldsymbol{\\theta}_t -\\mathbf{v}_{t},\n",
+ "\\label{_auto2} \\tag{3}\n",
+ "\\end{equation}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "where we have introduced a momentum parameter $\\gamma$, with\n",
+ "$0\\le\\gamma\\le 1$, and for brevity we dropped the explicit notation to\n",
+ "indicate the gradient is to be taken over a different mini-batch at\n",
+ "each step. We call this algorithm gradient descent with momentum\n",
+ "(GDM). From these equations, it is clear that $\\mathbf{v}_t$ is a\n",
+ "running average of recently encountered gradients and\n",
+ "$(1-\\gamma)^{-1}$ sets the characteristic time scale for the memory\n",
+ "used in the averaging procedure. Consistent with this, when\n",
+ "$\\gamma=0$, this just reduces down to ordinary SGD as discussed\n",
+ "earlier. An equivalent way of writing the updates is"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\Delta \\boldsymbol{\\theta}_{t+1} = \\gamma \\Delta \\boldsymbol{\\theta}_t -\\ \\eta_{t}\\nabla_\\theta E(\\boldsymbol{\\theta}_t),\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "where we have defined $\\Delta \\boldsymbol{\\theta}_{t}= \\boldsymbol{\\theta}_t-\\boldsymbol{\\theta}_{t-1}$.\n",
+ "\n",
+ "\n",
+ "\n",
+ "Let us try to get more intuition from these equations. It is helpful\n",
+ "to consider a simple physical analogy with a particle of mass $m$\n",
+ "moving in a viscous medium with drag coefficient $\\mu$ and potential\n",
+ "$E(\\mathbf{w})$. If we denote the particle's position by $\\mathbf{w}$,\n",
+ "then its motion is described by"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "m {d^2 \\mathbf{w} \\over dt^2} + \\mu {d \\mathbf{w} \\over dt }= -\\nabla_w E(\\mathbf{w}).\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can discretize this equation in the usual way to get"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "m { \\mathbf{w}_{t+\\Delta t}-2 \\mathbf{w}_{t} +\\mathbf{w}_{t-\\Delta t} \\over (\\Delta t)^2}+\\mu {\\mathbf{w}_{t+\\Delta t}- \\mathbf{w}_{t} \\over \\Delta t} = -\\nabla_w E(\\mathbf{w}).\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Rearranging this equation, we can rewrite this as"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\Delta \\mathbf{w}_{t +\\Delta t}= - { (\\Delta t)^2 \\over m +\\mu \\Delta t} \\nabla_w E(\\mathbf{w})+ {m \\over m +\\mu \\Delta t} \\Delta \\mathbf{w}_t.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Notice that this equation is identical to previous one if we identify\n",
+ "the position of the particle, $\\mathbf{w}$, with the parameters\n",
+ "$\\boldsymbol{\\theta}$. This allows us to identify the momentum\n",
+ "parameter and learning rate with the mass of the particle and the\n",
+ "viscous drag as:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\gamma= {m \\over m +\\mu \\Delta t }, \\qquad \\eta = {(\\Delta t)^2 \\over m +\\mu \\Delta t}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Thus, as the name suggests, the momentum parameter is proportional to\n",
+ "the mass of the particle and effectively provides inertia.\n",
+ "Furthermore, in the large viscosity/small learning rate limit, our\n",
+ "memory time scales as $(1-\\gamma)^{-1} \\approx m/(\\mu \\Delta t)$.\n",
+ "\n",
+ "Why is momentum useful? SGD momentum helps the gradient descent\n",
+ "algorithm gain speed in directions with persistent but small gradients\n",
+ "even in the presence of stochasticity, while suppressing oscillations\n",
+ "in high-curvature directions. This becomes especially important in\n",
+ "situations where the landscape is shallow and flat in some directions\n",
+ "and narrow and steep in others. It has been argued that first-order\n",
+ "methods (with appropriate initial conditions) can perform comparable\n",
+ "to more expensive second order methods, especially in the context of\n",
+ "complex deep learning models.\n",
+ "\n",
+ "These beneficial properties of momentum can sometimes become even more\n",
+ "pronounced by using a slight modification of the classical momentum\n",
+ "algorithm called Nesterov Accelerated Gradient (NAG).\n",
+ "\n",
+ "In the NAG algorithm, rather than calculating the gradient at the\n",
+ "current parameters, $\\nabla_\\theta E(\\boldsymbol{\\theta}_t)$, one\n",
+ "calculates the gradient at the expected value of the parameters given\n",
+ "our current momentum, $\\nabla_\\theta E(\\boldsymbol{\\theta}_t +\\gamma\n",
+ "\\mathbf{v}_{t-1})$. This yields the NAG update rule"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\mathbf{v}_{t}=\\gamma \\mathbf{v}_{t-1}+\\eta_{t}\\nabla_\\theta E(\\boldsymbol{\\theta}_t +\\gamma \\mathbf{v}_{t-1}) \\nonumber\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "$$\n",
+ "\\begin{equation} \n",
+ "\\boldsymbol{\\theta}_{t+1}= \\boldsymbol{\\theta}_t -\\mathbf{v}_{t}.\n",
+ "\\label{_auto3} \\tag{4}\n",
+ "\\end{equation}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "One of the major advantages of NAG is that it allows for the use of a larger learning rate than GDM for the same choice of $\\gamma$.\n",
+ "\n",
+ "\n",
+ "\n",
+ "In stochastic gradient descent, with and without momentum, we still\n",
+ "have to specify a schedule for tuning the learning rates $\\eta_t$\n",
+ "as a function of time. As discussed in the context of Newton's\n",
+ "method, this presents a number of dilemmas. The learning rate is\n",
+ "limited by the steepest direction which can change depending on the\n",
+ "current position in the landscape. To circumvent this problem, ideally\n",
+ "our algorithm would keep track of curvature and take large steps in\n",
+ "shallow, flat directions and small steps in steep, narrow directions.\n",
+ "Second-order methods accomplish this by calculating or approximating\n",
+ "the Hessian and normalizing the learning rate by the\n",
+ "curvature. However, this is very computationally expensive for\n",
+ "extremely large models. Ideally, we would like to be able to\n",
+ "adaptively change the step size to match the landscape without paying\n",
+ "the steep computational price of calculating or approximating\n",
+ "Hessians.\n",
+ "\n",
+ "Recently, a number of methods have been introduced that accomplish\n",
+ "this by tracking not only the gradient, but also the second moment of\n",
+ "the gradient. These methods include AdaGrad, AdaDelta, RMS-Prop, and\n",
+ "ADAM.\n",
+ "\n",
+ "\n",
+ "### RMS prop\n",
+ "\n",
+ "In RMS prop, in addition to keeping a running average of the first\n",
+ "moment of the gradient, we also keep track of the second moment\n",
+ "denoted by $\\mathbf{s}_t=\\mathbb{E}[\\mathbf{g}_t^2]$. The update rule\n",
+ "for RMS prop is given by"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "$$\n",
+ "\\begin{equation}\n",
+ "\\mathbf{g}_t = \\nabla_\\theta E(\\boldsymbol{\\theta}) \n",
+ "\\label{_auto4} \\tag{5}\n",
+ "\\end{equation}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\mathbf{s}_t =\\beta \\mathbf{s}_{t-1} +(1-\\beta)\\mathbf{g}_t^2 \\nonumber\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\boldsymbol{\\theta}_{t+1}=\\boldsymbol{\\theta}_t - \\eta_t { \\mathbf{g}_t \\over \\sqrt{\\mathbf{s}_t +\\epsilon}}, \\nonumber\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "where $\\beta$ controls the averaging time of the second moment and is\n",
+ "typically taken to be about $\\beta=0.9$, $\\eta_t$ is a learning rate\n",
+ "typically chosen to be $10^{-3}$, and $\\epsilon\\sim 10^{-8} $ is a\n",
+ "small regularization constant to prevent divergences. Multiplication\n",
+ "and division by vectors is understood as an element-wise operation. It\n",
+ "is clear from this formula that the learning rate is reduced in\n",
+ "directions where the norm of the gradient is consistently large. This\n",
+ "greatly speeds up the convergence by allowing us to use a larger\n",
+ "learning rate for flat directions.\n",
+ "\n",
+ "### ADAM optimizer\n",
+ "\n",
+ "A related algorithm is the ADAM optimizer. In ADAM, we keep a running\n",
+ "average of both the first and second moment of the gradient and use\n",
+ "this information to adaptively change the learning rate for different\n",
+ "parameters. In addition to keeping a running average of the first and\n",
+ "second moments of the gradient\n",
+ "(i.e. $\\mathbf{m}_t=\\mathbb{E}[\\mathbf{g}_t]$ and\n",
+ "$\\mathbf{s}_t=\\mathbb{E}[\\mathbf{g}^2_t]$, respectively), ADAM\n",
+ "performs an additional bias correction to account for the fact that we\n",
+ "are estimating the first two moments of the gradient using a running\n",
+ "average (denoted by the hats in the update rule below). The update\n",
+ "rule for ADAM is given by (where multiplication and division are once\n",
+ "again understood to be element-wise operations below)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "$$\n",
+ "\\begin{equation}\n",
+ "\\mathbf{g}_t = \\nabla_\\theta E(\\boldsymbol{\\theta}) \n",
+ "\\label{_auto5} \\tag{6}\n",
+ "\\end{equation}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\mathbf{m}_t = \\beta_1 \\mathbf{m}_{t-1} + (1-\\beta_1) \\mathbf{g}_t \\nonumber\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\mathbf{s}_t =\\beta_2 \\mathbf{s}_{t-1} +(1-\\beta_2)\\mathbf{g}_t^2 \\nonumber\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\boldsymbol{\\mathbf{m}}_t={\\mathbf{m}_t \\over 1-\\beta_1^t} \\nonumber\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\boldsymbol{\\mathbf{s}}_t ={\\mathbf{s}_t \\over1-\\beta_2^t} \\nonumber\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\boldsymbol{\\theta}_{t+1}=\\boldsymbol{\\theta}_t - \\eta_t { \\boldsymbol{\\mathbf{m}}_t \\over \\sqrt{\\boldsymbol{\\mathbf{s}}_t} +\\epsilon}, \\nonumber\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "$$\n",
+ "\\begin{equation} \n",
+ "\\label{_auto6} \\tag{7}\n",
+ "\\end{equation}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "where $\\beta_1$ and $\\beta_2$ set the memory lifetime of the first and\n",
+ "second moment and are typically taken to be $0.9$ and $0.99$\n",
+ "respectively, and $\\eta$ and $\\epsilon$ are identical to RMSprop.\n",
+ "\n",
+ "Like in RMSprop, the effective step size of a parameter depends on the\n",
+ "magnitude of its gradient squared. To understand this better, let us\n",
+ "rewrite this expression in terms of the variance\n",
+ "$\\boldsymbol{\\sigma}_t^2 = \\boldsymbol{\\mathbf{s}}_t -\n",
+ "(\\boldsymbol{\\mathbf{m}}_t)^2$. Consider a single parameter $\\theta_t$. The\n",
+ "update rule for this parameter is given by"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\Delta \\theta_{t+1}= -\\eta_t { \\boldsymbol{m}_t \\over \\sqrt{\\sigma_t^2 + m_t^2 }+\\epsilon}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Practical tips\n",
+ "\n",
+ "* **Randomize the data when making mini-batches**. It is always important to randomly shuffle the data when forming mini-batches. Otherwise, the gradient descent method can fit spurious correlations resulting from the order in which data is presented.\n",
+ "\n",
+ "* **Transform your inputs**. Learning becomes difficult when our landscape has a mixture of steep and flat directions. One simple trick for minimizing these situations is to standardize the data by subtracting the mean and normalizing the variance of input variables. Whenever possible, also decorrelate the inputs. To understand why this is helpful, consider the case of linear regression. It is easy to show that for the squared error cost function, the Hessian of the cost function is just the correlation matrix between the inputs. Thus, by standardizing the inputs, we are ensuring that the landscape looks homogeneous in all directions in parameter space. Since most deep networks can be viewed as linear transformations followed by a non-linearity at each layer, we expect this intuition to hold beyond the linear case.\n",
+ "\n",
+ "* **Monitor the out-of-sample performance.** Always monitor the performance of your model on a validation set (a small portion of the training data that is held out of the training process to serve as a proxy for the test set. If the validation error starts increasing, then the model is beginning to overfit. Terminate the learning process. This *early stopping* significantly improves performance in many settings.\n",
+ "\n",
+ "* **Adaptive optimization methods don't always have good generalization.** Recent studies have shown that adaptive methods such as ADAM, RMSPorp, and AdaGrad tend to have poor generalization compared to SGD or SGD with momentum, particularly in the high-dimensional limit (i.e. the number of parameters exceeds the number of data points). Although it is not clear at this stage why these methods perform so well in training deep neural networks, simpler procedures like properly-tuned SGD may work as well or better in these applications.\n",
+ "\n",
+ "## Automatic differentiation\n",
+ "\n",
+ "[Automatic differentiation (AD)](https://en.wikipedia.org/wiki/Automatic_differentiation), \n",
+ "also called algorithmic\n",
+ "differentiation or computational differentiation,is a set of\n",
+ "techniques to numerically evaluate the derivative of a function\n",
+ "specified by a computer program. AD exploits the fact that every\n",
+ "computer program, no matter how complicated, executes a sequence of\n",
+ "elementary arithmetic operations (addition, subtraction,\n",
+ "multiplication, division, etc.) and elementary functions (exp, log,\n",
+ "sin, cos, etc.). By applying the chain rule repeatedly to these\n",
+ "operations, derivatives of arbitrary order can be computed\n",
+ "automatically, accurately to working precision, and using at most a\n",
+ "small constant factor more arithmetic operations than the original\n",
+ "program.\n",
+ "\n",
+ "Automatic differentiation is neither:\n",
+ "\n",
+ "* Symbolic differentiation, nor\n",
+ "\n",
+ "* Numerical differentiation (the method of finite differences).\n",
+ "\n",
+ "Symbolic differentiation can lead to inefficient code and faces the\n",
+ "difficulty of converting a computer program into a single expression,\n",
+ "while numerical differentiation can introduce round-off errors in the\n",
+ "discretization process and cancellation\n",
+ "\n",
+ "\n",
+ "\n",
+ "Python has tools for so-called **automatic differentiation**.\n",
+ "Consider the following example"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "f(x) = \\sin\\left(2\\pi x + x^2\\right)\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "which has the following derivative"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "f'(x) = \\cos\\left(2\\pi x + x^2\\right)\\left(2\\pi + 2x\\right)\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Using **autograd** we have"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "\n",
+ "# To do elementwise differentiation:\n",
+ "from autograd import elementwise_grad as egrad \n",
+ "\n",
+ "# To plot:\n",
+ "import matplotlib.pyplot as plt \n",
+ "\n",
+ "\n",
+ "def f(x):\n",
+ " return np.sin(2*np.pi*x + x**2)\n",
+ "\n",
+ "def f_grad_analytic(x):\n",
+ " return np.cos(2*np.pi*x + x**2)*(2*np.pi + 2*x)\n",
+ "\n",
+ "# Do the comparison:\n",
+ "x = np.linspace(0,1,1000)\n",
+ "\n",
+ "f_grad = egrad(f)\n",
+ "\n",
+ "computed = f_grad(x)\n",
+ "analytic = f_grad_analytic(x)\n",
+ "\n",
+ "plt.title('Derivative computed from Autograd compared with the analytical derivative')\n",
+ "plt.plot(x,computed,label='autograd')\n",
+ "plt.plot(x,analytic,label='analytic')\n",
+ "\n",
+ "plt.xlabel('x')\n",
+ "plt.ylabel('y')\n",
+ "plt.legend()\n",
+ "\n",
+ "plt.show()\n",
+ "\n",
+ "print(\"The max absolute difference is: %g\"%(np.max(np.abs(computed - analytic))))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here we\n",
+ "experiment with what kind of functions Autograd is capable\n",
+ "of finding the gradient of. The following Python functions are just\n",
+ "meant to illustrate what Autograd can do, but please feel free to\n",
+ "experiment with other, possibly more complicated, functions as well."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "from autograd import grad\n",
+ "\n",
+ "def f1(x):\n",
+ " return x**3 + 1\n",
+ "\n",
+ "f1_grad = grad(f1)\n",
+ "\n",
+ "# Remember to send in float as argument to the computed gradient from Autograd!\n",
+ "a = 1.0\n",
+ "\n",
+ "# See the evaluated gradient at a using autograd:\n",
+ "print(\"The gradient of f1 evaluated at a = %g using autograd is: %g\"%(a,f1_grad(a)))\n",
+ "\n",
+ "# Compare with the analytical derivative, that is f1'(x) = 3*x**2 \n",
+ "grad_analytical = 3*a**2\n",
+ "print(\"The gradient of f1 evaluated at a = %g by finding the analytic expression is: %g\"%(a,grad_analytical))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To differentiate with respect to two (or more) arguments of a Python\n",
+ "function, Autograd need to know at which variable the function if\n",
+ "being differentiated with respect to."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "from autograd import grad\n",
+ "def f2(x1,x2):\n",
+ " return 3*x1**3 + x2*(x1 - 5) + 1\n",
+ "\n",
+ "# By sending the argument 0, Autograd will compute the derivative w.r.t the first variable, in this case x1\n",
+ "f2_grad_x1 = grad(f2,0)\n",
+ "\n",
+ "# ... and differentiate w.r.t x2 by sending 1 as an additional arugment to grad\n",
+ "f2_grad_x2 = grad(f2,1)\n",
+ "\n",
+ "x1 = 1.0\n",
+ "x2 = 3.0 \n",
+ "\n",
+ "print(\"Evaluating at x1 = %g, x2 = %g\"%(x1,x2))\n",
+ "print(\"-\"*30)\n",
+ "\n",
+ "# Compare with the analytical derivatives:\n",
+ "\n",
+ "# Derivative of f2 w.r.t x1 is: 9*x1**2 + x2:\n",
+ "f2_grad_x1_analytical = 9*x1**2 + x2\n",
+ "\n",
+ "# Derivative of f2 w.r.t x2 is: x1 - 5:\n",
+ "f2_grad_x2_analytical = x1 - 5\n",
+ "\n",
+ "# See the evaluated derivations:\n",
+ "print(\"The derivative of f2 w.r.t x1: %g\"%( f2_grad_x1(x1,x2) ))\n",
+ "print(\"The analytical derivative of f2 w.r.t x1: %g\"%( f2_grad_x1(x1,x2) ))\n",
+ "\n",
+ "print()\n",
+ "\n",
+ "print(\"The derivative of f2 w.r.t x2: %g\"%( f2_grad_x2(x1,x2) ))\n",
+ "print(\"The analytical derivative of f2 w.r.t x2: %g\"%( f2_grad_x2(x1,x2) ))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note that the grad function will not produce the true gradient of the function. The true gradient of a function with two or more variables will produce a vector, where each element is the function differentiated w.r.t a variable."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "from autograd import grad\n",
+ "def f3(x): # Assumes x is an array of length 5 or higher\n",
+ " return 2*x[0] + 3*x[1] + 5*x[2] + 7*x[3] + 11*x[4]**2\n",
+ "\n",
+ "f3_grad = grad(f3)\n",
+ "\n",
+ "x = np.linspace(0,4,5)\n",
+ "\n",
+ "# Print the computed gradient:\n",
+ "print(\"The computed gradient of f3 is: \", f3_grad(x))\n",
+ "\n",
+ "# The analytical gradient is: (2, 3, 5, 7, 22*x[4])\n",
+ "f3_grad_analytical = np.array([2, 3, 5, 7, 22*x[4]])\n",
+ "\n",
+ "# Print the analytical gradient:\n",
+ "print(\"The analytical gradient of f3 is: \", f3_grad_analytical)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note that in this case, when sending an array as input argument, the\n",
+ "output from Autograd is another array. This is the true gradient of\n",
+ "the function, as opposed to the function in the previous example. By\n",
+ "using arrays to represent the variables, the output from Autograd\n",
+ "might be easier to work with, as the output is closer to what one\n",
+ "could expect form a gradient-evaluting function."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "from autograd import grad\n",
+ "def f4(x):\n",
+ " return np.sqrt(1+x**2) + np.exp(x) + np.sin(2*np.pi*x)\n",
+ "\n",
+ "f4_grad = grad(f4)\n",
+ "\n",
+ "x = 2.7\n",
+ "\n",
+ "# Print the computed derivative:\n",
+ "print(\"The computed derivative of f4 at x = %g is: %g\"%(x,f4_grad(x)))\n",
+ "\n",
+ "# The analytical derivative is: x/sqrt(1 + x**2) + exp(x) + cos(2*pi*x)*2*pi\n",
+ "f4_grad_analytical = x/np.sqrt(1 + x**2) + np.exp(x) + np.cos(2*np.pi*x)*2*np.pi\n",
+ "\n",
+ "# Print the analytical gradient:\n",
+ "print(\"The analytical gradient of f4 at x = %g is: %g\"%(x,f4_grad_analytical))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "from autograd import grad\n",
+ "def f5(x):\n",
+ " if x >= 0:\n",
+ " return x**2\n",
+ " else:\n",
+ " return -3*x + 1\n",
+ "\n",
+ "f5_grad = grad(f5)\n",
+ "\n",
+ "x = 2.7\n",
+ "\n",
+ "# Print the computed derivative:\n",
+ "print(\"The computed derivative of f5 at x = %g is: %g\"%(x,f5_grad(x)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "2\n",
+ "6\n",
+ " \n",
+ "<\n",
+ "<\n",
+ "<\n",
+ "!\n",
+ "!\n",
+ "C\n",
+ "O\n",
+ "D\n",
+ "E\n",
+ "_\n",
+ "B\n",
+ "L\n",
+ "O\n",
+ "C\n",
+ "K\n",
+ " \n",
+ " \n",
+ "p\n",
+ "y\n",
+ "c\n",
+ "o\n",
+ "d"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "from autograd import grad\n",
+ "# Both of the functions are implementation of the sum: sum(x**i) for i = 0, ..., 9\n",
+ "# The analytical derivative is: sum(i*x**(i-1)) \n",
+ "f6_grad_analytical = 0\n",
+ "for i in range(10):\n",
+ " f6_grad_analytical += i*x**(i-1)\n",
+ "\n",
+ "print(\"The analytical derivative of f6 at x = %g is: %g\"%(x,f6_grad_analytical))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "from autograd import grad\n",
+ "\n",
+ "def f7(n): # Assume that n is an integer\n",
+ " if n == 1 or n == 0:\n",
+ " return 1\n",
+ " else:\n",
+ " return n*f7(n-1)\n",
+ "\n",
+ "f7_grad = grad(f7)\n",
+ "\n",
+ "n = 2.0\n",
+ "\n",
+ "print(\"The computed derivative of f7 at n = %d is: %g\"%(n,f7_grad(n)))\n",
+ "\n",
+ "# The function f7 is an implementation of the factorial of n.\n",
+ "# By using the product rule, one can find that the derivative is:\n",
+ "\n",
+ "f7_grad_analytical = 0\n",
+ "for i in range(int(n)-1):\n",
+ " tmp = 1\n",
+ " for k in range(int(n)-1):\n",
+ " if k != i:\n",
+ " tmp *= (n - k)\n",
+ " f7_grad_analytical += tmp\n",
+ "\n",
+ "print(\"The analytical derivative of f7 at n = %d is: %g\"%(n,f7_grad_analytical))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note that if n is equal to zero or one, Autograd will give an error message. This message appears when the output is independent on input.\n",
+ "\n",
+ "\n",
+ "Autograd supports many features. However, there are some functions that is not supported (yet) by Autograd.\n",
+ "\n",
+ "Assigning a value to the variable being differentiated with respect to"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "from autograd import grad\n",
+ "def f8(x): # Assume x is an array\n",
+ " x[2] = 3\n",
+ " return x*2\n",
+ "\n",
+ "f8_grad = grad(f8)\n",
+ "\n",
+ "x = 8.4\n",
+ "\n",
+ "print(\"The derivative of f8 is:\",f8_grad(x))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here, Autograd tells us that an 'ArrayBox' does not support item assignment. The item assignment is done when the program tries to assign x[2] to the value 3. However, Autograd has implemented the computation of the derivative such that this assignment is not possible."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "from autograd import grad\n",
+ "def f9(a): # Assume a is an array with 2 elements\n",
+ " b = np.array([1.0,2.0])\n",
+ " return a.dot(b)\n",
+ "\n",
+ "f9_grad = grad(f9)\n",
+ "\n",
+ "x = np.array([1.0,0.0])\n",
+ "\n",
+ "print(\"The derivative of f9 is:\",f9_grad(x))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here we are told that the 'dot' function does not belong to Autograd's\n",
+ "version of a Numpy array. To overcome this, an alternative syntax\n",
+ "which also computed the dot product can be used:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "import autograd.numpy as np\n",
+ "from autograd import grad\n",
+ "def f9_alternative(x): # Assume a is an array with 2 elements\n",
+ " b = np.array([1.0,2.0])\n",
+ " return np.dot(x,b) # The same as x_1*b_1 + x_2*b_2\n",
+ "\n",
+ "f9_alternative_grad = grad(f9_alternative)\n",
+ "\n",
+ "x = np.array([3.0,0.0])\n",
+ "\n",
+ "print(\"The gradient of f9 is:\",f9_alternative_grad(x))\n",
+ "\n",
+ "# The analytical gradient of the dot product of vectors x and b with two elements (x_1,x_2) and (b_1, b_2) respectively\n",
+ "# w.r.t x is (b_1, b_2)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The documentation recommends to avoid inplace operations such as"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "a += b\n",
+ "a -= b\n",
+ "a*= b\n",
+ "a /=b"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "More examples will be added, in particular how to compare autograd with own codes for the gradients."
]
}
],
diff --git a/doc/LectureNotes/_build/html/chapter1.html b/doc/LectureNotes/_build/html/chapter1.html
index 3e61ffcbd..2e7c0a670 100644
--- a/doc/LectureNotes/_build/html/chapter1.html
+++ b/doc/LectureNotes/_build/html/chapter1.html
@@ -159,7 +159,7 @@
Our emphasis throughout this series of lectures
-is on understanding the mathematical aspects of
-different algorithms used in the fields of data analysis and machine learning.
However, where possible we will emphasize the -importance of using available software. We start thus with a hands-on -and top-down approach to machine learning. The aim is thus to start with -relevant data or data we have produced -and use these to introduce statistical data analysis -concepts and machine learning algorithms before we delve into the -algorithms themselves. The examples we will use in the beginning, start with simple -polynomials with random noise added. We will use the Python -software package Scikit-Learn and -introduce various machine learning algorithms to make fits of -the data and predictions. We move thereafter to more interesting -cases such as data from say experiments (below we will look at experimental nuclear binding energies as an example). -These are examples where we can easily set up the data and -then use machine learning algorithms included in for example -Scikit-Learn.
+Our emphasis throughout this series of lectures is on understanding +the mathematical aspects of different algorithms used in the fields of +data analysis and machine learning.
+However, where possible we will emphasize the importance of using +available software. We start thus with a hands-on and top-down +approach to machine learning. The aim is thus to start with relevant +data or data we have produced and use these to introduce statistical +data analysis concepts and machine learning algorithms before we delve +into the algorithms themselves. The examples we will use in the +beginning, start with simple polynomials with random noise added. We +will use the Python software package +Scikit-Learn and introduce various +machine learning algorithms to make fits of the data and +predictions. We move thereafter to more interesting cases such as data +from say experiments (below we will look at experimental nuclear +binding energies as an example). These are examples where we can +easily set up the data and then use machine learning algorithms +included in for example Scikit-Learn.
These examples will serve us the purpose of getting started. Furthermore, they allow us to catch more than two birds with a stone. They will allow us to bring in some programming specific topics and tools as well as showing the power of various Python libraries for machine learning and statistical data analysis.
-Here, we will mainly focus on two -specific Python packages for Machine Learning, Scikit-Learn and -Tensorflow (see below for links etc). Moreover, the examples we -introduce will serve as inputs to many of our discussions later, as -well as allowing you to set up models and produce your own data and -get started with programming.
+Here, we will mainly focus on two specific Python packages for Machine +Learning, Scikit-Learn and Tensorflow (see below for links etc). +Moreover, the examples we introduce will serve as inputs to many of +our discussions later, as well as allowing you to set up models and +produce your own data and get started with programming.
In the code here we have also made a new array for \(x\in [0,1]\). Our +prediction is computed for these values, meaning that they were not +included in the data set used to train (or fit) the model. +This is a recurrring theme in machine learning and data analysis. We would like to train a model on a specific given data set. +Thereafter we wish to apply it to data which were not included in the training. Below we will encounter this again in the so-called train-validate-test spliting. We will typically split our data into different sets, oen for training, one for validation and finally, our data from the untouched test vault!
The Python code follows here.
Depending on the parameter in front of the normal distribution, we may have a small or larger relative error. Try to play around with different training data sets and study (graphically) the value of the -relative error. Note also that Scikit-Learn requires a matrix as input for the input values \(x\) and \(y\). In the above code we have -solved this by declaring \(x\) and \(y\) as arrays of dimension \(n\times 1\).
+relative error.As mentioned above, Scikit-Learn has an impressive functionality. We can for example extract the values of \(\alpha\) and \(\beta\) and their error estimates, or the variance and standard deviation and many @@ -787,13 +789,13 @@ example of the functionality of Scikit-Learn.
The intercept alpha:
- [1.84860939]
+ [1.89992521]
Coefficient beta :
- [[5.2571699]]
-Mean squared error: 0.25
-Variance score: 0.90
+ [[5.12908963]]
+Mean squared error: 0.20
+Variance score: 0.92
Mean squared log error: 0.01
-Mean absolute error: 0.40
+Mean absolute error: 0.36
@@ -893,7 +895,7 @@ a linear \(x\)-dependence we s
-0.0050000000000000044
+0.005000000000000007
The next step, and we will define this mathematically later, is to set up the so-called design matrix. We will throughout call this matrix \(\boldsymbol{X}\). -It has dimensionality \(p\times n\), where \(n\) is the number of data points and \(p\) are the so-called predictors. In our case here they are given by the number of polynomials in \(A\) we wish to include in the fit.
+It has dimensionality \(n\times p\), where \(n\) is the number of data points and \(p\) are the so-called predictors. In our case here they are given by the number of polynomials in \(A\) we wish to include in the fit.# Now we set up the design matrix X
@@ -1131,8 +1133,11 @@ It has dimensionality \(p\times n\)
Note well that we have made life simple here. We perform a fit in terms of the number of nucleons only. A more sophisticated fit can be done by including an explicit dependence on the number of protons and neutrons in the asymmetry and Coulomb terms.
-With scikitlearn we are now ready to use linear regression and fit our data.
+Note well that we have made life simple here. We perform a fit in +terms of the number of nucleons only. A more sophisticated fit can be +done by including an explicit dependence on the number of protons and +neutrons in the asymmetry and Coulomb terms. We leave this as an exercise to you the reader.
+With Scikit-Learn we are now ready to use linear regression and fit our data.
clf = skl.LinearRegression().fit(X, Energies)
@@ -1176,7 +1181,7 @@ Mean absolute error: 0.05
As a teaser, let us now see how we can do this with decision trees using scikit-learn. Later we will switch to so-called random forests!
+As a teaser, let us now see how we can do this with decision trees using Scikit-Learn. Later we will switch to so-called random forests!
#Decision Tree Regression
@@ -1228,11 +1233,20 @@ A
270 3344 160 110 270 Ds 7.253775 7.253775
[267 rows x 6 columns]
-0.009883615646716186
+0.009883615646716188
With a deeper and deeper tree level, we can almost reproduce every +single data point by increasing the max depth of the tree. +We can actually decide to make a decision tree which fits every single point. +As we will +see later, this has the benefit that we can really train a model which +traverses every single data point. However, the price we pay is that +we will easily overfit. That is, if we apply our model to unseen data, +we will most likely fail miserably in our attempt at making +predictions. As an exercise, try to make the tree level larger by adjusting the maximum depth variable. When printing out the predicition, you will note that the binding energy of every nucleus is accurately reproduced.
The seaborn package allows us to visualize data in an efficient way. Note that we use scikit-learn’s multi-layer perceptron (or feed forward neural network) functionality.
/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
- warnings.warn(
-/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
- warnings.warn(
-/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
- warnings.warn(
-/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
warnings.warn(
/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
@@ -1334,16 +1340,12 @@ functionality.
warnings.warn(
/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
warnings.warn(
+/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
+ warnings.warn(
/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
warnings.warn(
-/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
- warnings.warn(
-/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
- warnings.warn(
/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
warnings.warn(
+/Users/mhjensen/opt/anaconda3/lib/python3.8/site-packages/sklearn/neural_network/_multilayer_perceptron.py:582: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (100) reached and the optimization hasn't converged yet.
+ warnings.warn(
+
We can then compute the second derivative of the cost function, which in our case is the second derivative +of the means squared error. This leads to
+This quantity defines was what is called the Hessian matrix (the second derivative of a function we want to optimize).
+The Hessian matrix plays an important role and is defined for the mean squared error as
+The Hessian matrix for ordinary least squares is also proportional to +the covariance matrix. As we will see in the chapter on Ridge and Lasso regression, This means that we can use the Singular Value Decomposition of a matrix to find +the eigenvalues of the covariance matrix and the Hessian matrix in +terms of the singular values.
The residuals \(\boldsymbol{\epsilon}\) are in turn given by
+
We can easily test our fit by computing the \(R2\) score that we discussed in connection with the functionality of Scikit-Learn in the introductory slides. @@ -2138,9 +2160,7 @@ time the file is presented as a standard csv file.
before, with the same initializations and declarations. We use also pandas again, rather extensively in order to organize our data.The difference now is that we use Scikit-Learn’s regression tools -instead of our own matrix inversion implementation. Furthermore, we -sneak in Ridge regression (to be discussed below) which includes a -hyperparameter \(\lambda\), also to be explained below.
+instead of our own matrix inversion implementation.# Common imports
@@ -2203,18 +2223,6 @@ hyperparameter \(\lambda\), al
print('Mean absolute error: %.2f' % mean_absolute_error(Energies, ytilde))
print(clf.coef_, clf.intercept_)
-# The Ridge regression with a hyperparameter lambda = 0.1
-_lambda = 0.1
-clf_ridge = skl.Ridge(alpha=_lambda).fit(X, Energies)
-yridge = clf_ridge.predict(X)
-EoS['Eridge'] = yridge
-# The mean squared error
-print("Mean squared error: %.2f" % mean_squared_error(Energies, yridge))
-# Explained variance score: 1 is perfect prediction
-print('Variance score: %.2f' % r2_score(Energies, yridge))
-# Mean absolute error
-print('Mean absolute error: %.2f' % mean_absolute_error(Energies, yridge))
-print(clf_ridge.coef_, clf_ridge.intercept_)
fig, ax = plt.subplots()
ax.set_xlabel(r'$\rho[\mathrm{fm}^{-3}]$')
@@ -2223,8 +2231,6 @@ hyperparameter \(\lambda\), al
label='Theoretical data')
ax.plot(EoS['Density'], EoS['Eols'], alpha=0.7, lw=2, c='m',
label='OLS')
-ax.plot(EoS['Density'], EoS['Eridge'], alpha=0.7, lw=2, c='g',
- label='Ridge $\lambda = 0.1$')
ax.legend()
save_fig("EoSfitting")
plt.show()
@@ -2236,20 +2242,13 @@ hyperparameter \(\lambda\), al
Variance score: 1.00
Mean absolute error: 2.83
[ 0. 618.32047562 -861.13519106 1404.91549644] -11.057088709963637
-Mean squared error: 197.93
-Variance score: 1.00
-Mean absolute error: 11.69
-[ 0. 28.18220995 282.79902342 842.30879705] 12.946893955211749
+
The above simple polynomial in density \(\rho\) gives an excellent fit to the data.
-We note also that there is a small deviation between the -standard OLS and the Ridge regression at higher densities. We discuss this in more detail -below.
Let us study some examples. The first code here takes a simple +one-dimensional second-order polynomial and we fit it to a +second-order polynomial. Depending on the strength of the added noise, +the various measures like the \(R2\) score or the mean-squared error, +the fit becomes better or worse.
+import os
+import numpy as np
+import pandas as pd
+import matplotlib.pyplot as plt
+from sklearn.model_selection import train_test_split
+
+
+def R2(y_data, y_model):
+ return 1 - np.sum((y_data - y_model) ** 2) / np.sum((y_data - np.mean(y_data)) ** 2)
+def MSE(y_data,y_model):
+ n = np.size(y_model)
+ return np.sum((y_data-y_model)**2)/n
+
+x = np.random.rand(100)
+y = 2.0+5*x*x+0.1*np.random.randn(100)
+
+
+# The design matrix now as function of a given polynomial
+X = np.zeros((len(x),3))
+X[:,0] = 1.0
+X[:,1] = x
+X[:,2] = x**2
+# We split the data in test and training data
+X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
+# matrix inversion to find beta
+beta = np.linalg.inv(X_train.T @ X_train) @ X_train.T @ y_train
+print(beta)
+# and then make the prediction
+ytilde = X_train @ beta
+print("Training R2")
+print(R2(y_train,ytilde))
+print("Training MSE")
+print(MSE(y_train,ytilde))
+ypredict = X_test @ beta
+print("Test R2")
+print(R2(y_test,ypredict))
+print("Test MSE")
+print(MSE(y_test,ypredict))
+[ 2.00247083e+00 -3.54710530e-03 5.02096350e+00]
+Training R2
+0.99620088364924
+Training MSE
+0.008171076530362356
+Test R2
+0.9968966158779216
+Test MSE
+0.006530396683779109
+Alternatively, you could write your own test-train splitting function as shown here.
+# equivalently in numpy
+def train_test_split_numpy(inputs, labels, train_size, test_size):
+ n_inputs = len(inputs)
+ inputs_shuffled = inputs.copy()
+ labels_shuffled = labels.copy()
+
+ np.random.shuffle(inputs_shuffled)
+ np.random.shuffle(labels_shuffled)
+
+ train_end = int(n_inputs*train_size)
+ X_train, X_test = inputs_shuffled[:train_end], inputs_shuffled[train_end:]
+ Y_train, Y_test = labels_shuffled[:train_end], labels_shuffled[train_end:]
+
+ return X_train, X_test, Y_train, Y_test
+But since scikit-learn has its own function for doing this and since +it interfaces easily with tensorflow and other libraries, we +normally recommend using the latter functionality.
+As another example, we apply the training and testing split to +to the above equation of state fitting example +but now splitting the data into a training set and a test set.
import os
@@ -2335,13 +2423,13 @@ but now splitting the data into a training set and a test set.
Training R2
-0.9999869956119286
+0.9999850282256434
Training MSE
-5.745136489050356
+6.653725417896576
Test R2
-0.9999787681537219
+0.9999887274726137
Test MSE
-9.712199063818309
+5.071447584032141
+
It is now useful to look at the correlation matrix
@@ -2478,7 +2566,7 @@ dtype: int64<AxesSubplot:>
+
From the above coorelation plot we can see that MEDV is strongly correlated to LSTAT and RM. We see also that RAD and TAX are stronly correlated, but we don’t include this in our features together to avoid multi-colinearity
@@ -2501,7 +2589,7 @@ dtype: int64
+
Now we start training our model
@@ -2599,111 +2687,12 @@ R2 score is 0.6628996975186952
+
It is normal in essentially all Machine Learning studies to split the -data in a training set and a test set (sometimes also an additional -validation set). Scikit-Learn has an own function for this. There -is no explicit recipe for how much data should be included as training -data and say test data. An accepted rule of thumb is to use -approximately \(2/3\) to \(4/5\) of the data as training data. We will -postpone a discussion of this splitting to the end of these notes and -our discussion of the so-called bias-variance tradeoff. Here we -limit ourselves to repeat the above equation of state fitting example -but now splitting the data into a training set and a test set.
-Let us study some examples. The first code here takes a simple -one-dimensional second-order polynomial and we fit it to a -second-order polynomial. Depending on the strength of the added noise, -the various measures like the \(R2\) score or the mean-squared error, -the fit becomes better or worse.
-import os
-import numpy as np
-import pandas as pd
-import matplotlib.pyplot as plt
-from sklearn.model_selection import train_test_split
-
-
-def R2(y_data, y_model):
- return 1 - np.sum((y_data - y_model) ** 2) / np.sum((y_data - np.mean(y_data)) ** 2)
-def MSE(y_data,y_model):
- n = np.size(y_model)
- return np.sum((y_data-y_model)**2)/n
-
-x = np.random.rand(100)
-y = 2.0+5*x*x+0.1*np.random.randn(100)
-
-
-# The design matrix now as function of a given polynomial
-X = np.zeros((len(x),3))
-X[:,0] = 1.0
-X[:,1] = x
-X[:,2] = x**2
-# We split the data in test and training data
-X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
-# matrix inversion to find beta
-beta = np.linalg.inv(X_train.T @ X_train) @ X_train.T @ y_train
-print(beta)
-# and then make the prediction
-ytilde = X_train @ beta
-print("Training R2")
-print(R2(y_train,ytilde))
-print("Training MSE")
-print(MSE(y_train,ytilde))
-ypredict = X_test @ beta
-print("Test R2")
-print(R2(y_test,ypredict))
-print("Test MSE")
-print(MSE(y_test,ypredict))
-[ 2.05802766 -0.30626706 5.27262964]
-Training R2
-0.9967292151090247
-Training MSE
-0.007931713723267314
-Test R2
-0.9966744029509663
-Test MSE
-0.006968283076248407
-Alternatively, you could write your own test-train splitting function as shown here.
-# equivalently in numpy
-def train_test_split_numpy(inputs, labels, train_size, test_size):
- n_inputs = len(inputs)
- inputs_shuffled = inputs.copy()
- labels_shuffled = labels.copy()
-
- np.random.shuffle(inputs_shuffled)
- np.random.shuffle(labels_shuffled)
-
- train_end = int(n_inputs*train_size)
- X_train, X_test = inputs_shuffled[:train_end], inputs_shuffled[train_end:]
- Y_train, Y_test = labels_shuffled[:train_end], labels_shuffled[train_end:]
-
- return X_train, X_test, Y_train, Y_test
-But since scikit-learn has its own function for doing this and since -it interfaces easily with tensorflow and other libraries, we -normally recommend using the latter functionality.
-Many Machine Learning problems involve thousands or even millions of features for each training instance. Not only does this make training extremely slow, it can also make it much harder to find a good @@ -3156,7 +3145,7 @@ x_j^{(i)} \rightarrow (b-a)\frac{x_j^{(i)} - \min(x_j)}{\max(x_j) - \min(x_j)} -
where \(\min(x_j)\) and \(\max(x_j)\) return the minimum and maximum value of \(x_j\) over the data set, respectively.
Before we proceed with a more detailed analysis of the so-called Bias-Variance tradeoff, we present here an example of the relation between model complexity and the mean squared error for the triaining @@ -3208,14 +3197,14 @@ ourmodel (here in terms of the polynomial degree of the model).
+
The first exercise here is of a mere technical art. We want you to have
git as a version control software and to establish a user account on a provider like GitHub. Other providers like GitLab etc are equally fine. You can also use the University of Oslo GitHub facilities.
We recommend using Anaconda if you are not too familiar with setting paths in a terminal environment.
We will generate our own dataset for a function \(y(x)\) where \(x \in [0,1]\) and defined by random numbers computed with the uniform distribution. The function \(y\) is a quadratic polynomial in \(x\) with added stochastic noise according to the normal distribution \(\cal {N}(0,1)\). The following simple Python instructions define our \(x\) and \(y\) values (with 100 data points).
A much used approach before starting to train the data is to preprocess our data. Normally the data may need a rescaling and/or may be sensitive to extreme values. Scaling the data renders our inputs much more diff --git a/doc/LectureNotes/_build/html/chapter10.html b/doc/LectureNotes/_build/html/chapter10.html index f570beb9f..75098e166 100644 --- a/doc/LectureNotes/_build/html/chapter10.html +++ b/doc/LectureNotes/_build/html/chapter10.html @@ -5,7 +5,7 @@
-We are now gong to develop an example based on the MNIST data base. This is a classification problem and we need to use our cross-entropy function we discussed in connection with logistic @@ -472,7 +472,7 @@ P(y = 1 \mid \hat{x}, \hat{\theta}) = 1 - P(y = 0 \mid \hat{x}, \hat{\theta}) ,
where \(y \in \{0, 1\}\) and \(\hat{\theta}\) represents the weights and biases of our network.
Our cost function is given as (see the Logistic regression lectures)
See the logistic regression lectures for a full definition of the cost function.
The back propagation equations need now only a small change, namely the definition of a new cost function. We are thus ready to use the same equations as before!
As an example of the above, relevant for project 2 as well, let us consider a binary class. As discussed in our logistic regression lectures, we defined a cost function in terms of the parameters \(\beta\) as
In case we use another activation function than the logistic one, we need to evaluate other derivatives.
In case we employ the more general case given by the Softmax equation, we need to evaluate the derivative of the activation function with respect to the activation \(z_i^l\), that is we need
One can identify a set of key steps when using neural networks to solve supervised learning problems:
Collect and pre-process data
Adjust hyperparameters (if necessary, network architecture)
Here we will be using the MNIST dataset, which is readily available through the scikit-learn
package. You may also find it for example here.
The MNIST (Modified National Institute of Standards and Technology) database is a large database
@@ -679,7 +679,7 @@ X = (n_inputs, n_features) = (1797, 64)
Performing analysis before partitioning the dataset is a major error, that can lead to incorrect conclusions.
We will reserve \(80 \%\) of our dataset for training and \(20 \%\) for testing.
It is important that the train and test datasets are drawn randomly from our dataset, to ensure @@ -728,7 +728,7 @@ Number of test images: 360
Our simple feed-forward neural network will consist of an input layer, a single hidden layer and an output layer. The activation \(y\) of each neuron is a weighted sum of inputs, passed through an activation function. In case of the simple perceptron model we have
Denote \(F\) the number of features, \(H\) the number of hidden neurons and \(C\) the number of categories.
For each input image we calculate a weighted sum of input features (pixel values) to each neuron \(j\) in the hidden layer \(l\):
To measure how well our neural network is doing we need to introduce a cost function.
We will call the function that gives the error of a single sample output the loss function, and the function
that gives the total error of our network across all samples the cost function.
@@ -927,7 +927,7 @@ probability of the correct category \
you got the correct label. The probability of category \(c\) is given by the softmax function. The vector \(\hat{\theta}\) represents the parameters of our network, i.e. all the weights and biases.
The network is trained by finding the weights and biases that minimize the cost function. One of the most widely used classes of methods is gradient descent and its generalizations. The idea behind gradient descent
is simply to adjust the weights in the direction where the gradient of the cost function is large and negative. This ensures we flow toward a local minimum of the cost function.
Each parameter \(\theta\) is iteratively adjusted according to the rule
It is common to add an extra term to the cost function, proportional to the size of the weights. This is equivalent to constraining the size of the weights, so that they do not grow out of control. @@ -976,7 +976,7 @@ above. This is a clever use of the chain rule that allows us to calculate the gradient efficently.
To more efficently train our network these equations are implemented using matrix operations.
The error in the output layer is calculated simply as, with \(\hat{t}\) being our targets,
As we can see the network does not seem to be learning at all. It seems to be just guessing the label for each image.
In order to obtain a network that does something useful, we will have to do a bit more work.
The choice of hyperparameters such as learning rate and regularization parameter is hugely influential for the performance of the network. Typically a grid-search is performed, wherein we test different hyperparameters separated by orders of magnitude. For example we could test the learning rates \(\eta = 10^{-6}, 10^{-5},...,10^{-1}\) with different regularization parameters \(\lambda = 10^{-6},...,10^{-0}\).
@@ -1206,7 +1206,7 @@ being realizations of this object with different hyperparameters. An implementatTo measure the performance of our network we evaluate how well it does it data it has never seen before, i.e. the test data.
We measure the performance of the network using the accuracy score.
The accuracy is as you would expect just the number of images correctly labeled divided by the total number of images. A perfect classifier will have an accuracy score of \(1\).
We now perform a grid search to find the optimal hyperparameters for the network.
Note that we are only using 1 layer with 50 neurons, and human performance is estimated to be around \(98\%\) (\(2\%\) error rate).
# visual representation of grid search
@@ -1580,7 +1580,7 @@ Accuracy score on test set: 0.07777777777777778
# optional
@@ -1986,7 +1986,7 @@ Accuracy score on test set: 0.1527777777777778
Now we want to build on the experience gained from our neural network implementation in NumPy and scikit-learn and use it to construct a neural network in Tensorflow. Once we have constructed a neural network in NumPy and Tensorflow, building one in Keras is really quite trivial, though the performance may suffer.
@@ -2214,7 +2214,7 @@ If you have Anaconda installed you may run the following commandimport tensorflow as tf
@@ -2388,7 +2388,7 @@ If you have Anaconda installed you may run the following command
The flexibility of neural networks is also one of their main drawbacks: there are many hyperparameters to tweak. Not only can you use any imaginable network topology (how neurons/nodes are interconnected), @@ -2419,7 +2419,7 @@ of training data. However, you will rarely have to train such networks from scra common to reuse parts of a pretrained state-of-the-art network that performs a similar task.
The Back propagation algorithm we derived above works by going from the output layer to the input layer, propagating the error gradient on the way. Once the algorithm has computed the gradient of the cost @@ -2484,7 +2484,7 @@ it does not saturate for positive values (and also because it is quite fast to compute).
The ReLU activation function suffers from a problem known as the dying ReLUs: during training, some neurons effectively die, meaning they stop outputting anything other than 0.
@@ -2521,7 +2521,7 @@ bootstrap to evaluate other activation functions.Batch Normalization aims to address the vanishing/exploding gradients problems, and more generally the problem that the distribution of each layer’s inputs changes during training, as the parameters of the previous layers change.
@@ -2534,7 +2534,7 @@ standard deviation. It does so by evaluating the mean and standard deviation of mini-batch, from this the name batch normalization.It is a fairly simple algorithm: at every training step, every neuron (including the input neurons but excluding the output neurons) has a probability \(p\) of being temporarily dropped out, meaning it will be entirely ignored during this training step, but it may be active during the next step.
@@ -2543,7 +2543,7 @@ hyperparameter \(p\) is called It is viewed as one of the most popular regularization techniques.A popular technique to lessen the exploding gradients problem is to simply clip the gradients during backpropagation so that they never exceed some threshold (this is mostly useful for recurrent neural networks).
@@ -2552,7 +2552,7 @@ networks). Normalization is preferred.The first thing we would like to do is divide the data into two or three parts. A training set, a validation or dev (development) set, and a test set. The test set is the data on which we want to make @@ -2586,7 +2586,7 @@ can serve as another important diagnostic when using DNNs for supervised learning.
Like all statistical methods, supervised learning using neural networks has important limitations. This is especially important when one seeks to apply these methods, especially to physics problems. Like @@ -2630,7 +2630,7 @@ features).
diff --git a/doc/LectureNotes/_build/html/chapter2.html b/doc/LectureNotes/_build/html/chapter2.html index e41ee49d1..846cae837 100644 --- a/doc/LectureNotes/_build/html/chapter2.html +++ b/doc/LectureNotes/_build/html/chapter2.html @@ -159,7 +159,7 @@What is presented here is a mathematical analysis of various regression algorithms (ordinary least squares, Ridge and Lasso Regression). The analysis is based on an important algorithm in linear algebra, the so-called Singular Value Decomposition (SVD).
-We have shown that in ordinary least squares the optimal parameters \(\beta\) are given by
+We have shown that in ordinary least squares (OLS) the optimal parameters \(\beta\) are given by
The hat over \(\boldsymbol{\beta}\) means we have the optimal parameters after minimization of the cost function.
This means that our best model is defined as
@@ -386,7 +391,7 @@ \[ \tilde{\boldsymbol{y}}=\boldsymbol{X}\hat{\boldsymbol{\beta}} = \boldsymbol{A}\boldsymbol{y}. \]The matrix \(\boldsymbol{A}\) has the important property that \(\boldsymbol{A}^2=\boldsymbol{A}\). This is the definition of a projection matrix. +
The matrix \(\boldsymbol{A}\) has the important property that \(\boldsymbol{A}^2=\boldsymbol{A}\). This is the definition of a projection matrix. We can then interpret our optimal model \(\tilde{\boldsymbol{y}}\) as being represented by an orthogonal projection of \(\boldsymbol{y}\) onto a space defined by the column vectors of \(\boldsymbol{X}\). In our case here the matrix \(\boldsymbol{A}\) is a square matrix. If it is a general rectangular matrix we have an oblique projection matrix.
We have defined the residual error as
How do we use the SVD to invert a matrix \(\boldsymbol{X}^\boldsymbol{X}\) which is singular or near singular? +
How do we use the SVD to invert a matrix \(\boldsymbol{X}^T\boldsymbol{X}\) which is singular or near singular? The simple answer is to use the linear algebra function for the pseudoinverse, that is
0.059680303635344434
-4.260227742627244
-[[0.89704131 2.55795935]
- [2.55795935 8.24340751]]
+-0.1831277634928002
+3.3041320306136366
+[[1.03929932 3.07670437]
+ [3.07670437 9.7701384 ]]
0.08362077210702115
-1.8429949116841184
-[[1. 0.6996584]
- [0.6996584 1. ]]
+0.09456011349477329
+1.6600855222624895
+[[1. 0.70183798]
+ [0.70183798 1. ]]
[[-1.25981533 -3.84976606]
- [-0.52570079 -0.62262506]
- [ 0.51707172 3.46973015]
- [-0.47265243 -1.87030083]
- [ 0.73734906 2.46183815]
- [ 0.4918372 2.05531364]
- [ 0.3893239 0.47862383]
- [-0.41237437 -0.85058354]
- [ 0.77622336 0.54697204]
- [-0.24126232 -1.81920231]]
+[[ 0.54316925 0.40968888]
+ [-1.8393131 -5.8788431 ]
+ [ 0.24613822 0.9957744 ]
+ [ 1.38892672 3.93679587]
+ [ 0.06540809 -0.84008474]
+ [ 0.49841285 2.31081134]
+ [-0.49323032 -1.25263916]
+ [ 0.08380813 -0.7925146 ]
+ [ 0.64078247 2.92814088]
+ [-1.13410232 -1.81712976]]
0 1
-0 -1.259815 -3.849766
-1 -0.525701 -0.622625
-2 0.517072 3.469730
-3 -0.472652 -1.870301
-4 0.737349 2.461838
-5 0.491837 2.055314
-6 0.389324 0.478624
-7 -0.412374 -0.850584
-8 0.776223 0.546972
-9 -0.241262 -1.819202
+0 0.543169 0.409689
+1 -1.839313 -5.878843
+2 0.246138 0.995774
+3 1.388927 3.936796
+4 0.065408 -0.840085
+5 0.498413 2.310811
+6 -0.493230 -1.252639
+7 0.083808 -0.792515
+8 0.640782 2.928141
+9 -1.134102 -1.817130
0 1
-0 1.000000 0.881323
-1 0.881323 1.000000
+0 1.000000 0.942726
+1 0.942726 1.000000
0 1 2 3 4 5 6 7 \
0 0.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
-1 0.0 0.082272 0.078892 0.081102 0.080738 0.080182 0.072012 0.072246
-2 0.0 0.078892 0.076822 0.075975 0.076166 0.076251 0.066705 0.067202
-3 0.0 0.081102 0.075975 0.085259 0.084103 0.082616 0.078750 0.078649
-4 0.0 0.080738 0.076166 0.084103 0.083246 0.082091 0.077338 0.077407
-5 0.0 0.080182 0.076251 0.082616 0.082091 0.081309 0.075567 0.075818
-6 0.0 0.072012 0.066705 0.078750 0.077338 0.075567 0.074693 0.074434
-7 0.0 0.072246 0.067202 0.078649 0.077407 0.075818 0.074434 0.074285
-8 0.0 0.072468 0.067718 0.078474 0.077416 0.076026 0.074077 0.074044
-9 0.0 0.072661 0.068244 0.078197 0.077339 0.076169 0.073591 0.073681
-10 0.0 0.063190 0.058247 0.070949 0.069542 0.067794 0.068593 0.068293
-11 0.0 0.063523 0.058719 0.071156 0.069853 0.068213 0.068717 0.068491
-12 0.0 0.063880 0.059225 0.071359 0.070166 0.068640 0.068821 0.068673
-13 0.0 0.064257 0.059765 0.071549 0.070473 0.069071 0.068896 0.068828
-14 0.0 0.064647 0.060335 0.071714 0.070764 0.069496 0.068928 0.068945
+1 0.0 0.080633 0.085811 0.085748 0.084826 0.083221 0.080341 0.078342
+2 0.0 0.085811 0.092659 0.093248 0.092932 0.091659 0.088414 0.086561
+3 0.0 0.085748 0.093248 0.096639 0.096802 0.095941 0.093928 0.092288
+4 0.0 0.084826 0.092932 0.096802 0.097346 0.096763 0.094774 0.093328
+5 0.0 0.083221 0.091659 0.095941 0.096763 0.096406 0.094513 0.093236
+6 0.0 0.080341 0.088414 0.093928 0.094774 0.094513 0.093573 0.092375
+7 0.0 0.078342 0.086561 0.092288 0.093328 0.093236 0.092375 0.091318
+8 0.0 0.076213 0.084461 0.090355 0.091535 0.091578 0.090817 0.089881
+9 0.0 0.074037 0.082239 0.088258 0.089540 0.089693 0.089039 0.088209
+10 0.0 0.073546 0.081474 0.088137 0.089326 0.089437 0.089352 0.088484
+11 0.0 0.071453 0.079337 0.086052 0.087334 0.087544 0.087526 0.086757
+12 0.0 0.069371 0.077163 0.083905 0.085253 0.085544 0.085598 0.084916
+13 0.0 0.067326 0.074996 0.081744 0.083138 0.083495 0.083622 0.083015
+14 0.0 0.065334 0.072862 0.079597 0.081024 0.081435 0.081632 0.081092
8 9 10 11 12 13 14
0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
-1 0.072468 0.072661 0.063190 0.063523 0.063880 0.064257 0.064647
-2 0.067718 0.068244 0.058247 0.058719 0.059225 0.059765 0.060335
-3 0.078474 0.078197 0.070949 0.071156 0.071359 0.071549 0.071714
-4 0.077416 0.077339 0.069542 0.069853 0.070166 0.070473 0.070764
-5 0.076026 0.076169 0.067794 0.068213 0.068640 0.069071 0.069496
-6 0.074077 0.073591 0.068593 0.068717 0.068821 0.068896 0.068928
-7 0.074044 0.073681 0.068293 0.068491 0.068673 0.068828 0.068945
-8 0.073926 0.073695 0.067889 0.068165 0.068427 0.068667 0.068873
-9 0.073695 0.073607 0.067355 0.067711 0.068056 0.068385 0.068686
-10 0.067889 0.067355 0.063925 0.064013 0.064075 0.064101 0.064078
-11 0.068165 0.067711 0.064013 0.064156 0.064273 0.064357 0.064393
-12 0.068427 0.068056 0.064075 0.064273 0.064449 0.064591 0.064689
-13 0.068667 0.068385 0.064101 0.064357 0.064591 0.064795 0.064958
-14 0.068873 0.068686 0.064078 0.064393 0.064689 0.064958 0.065188
+1 0.076213 0.074037 0.073546 0.071453 0.069371 0.067326 0.065334
+2 0.084461 0.082239 0.081474 0.079337 0.077163 0.074996 0.072862
+3 0.090355 0.088258 0.088137 0.086052 0.083905 0.081744 0.079597
+4 0.091535 0.089540 0.089326 0.087334 0.085253 0.083138 0.081024
+5 0.091578 0.089693 0.089437 0.087544 0.085544 0.083495 0.081435
+6 0.090817 0.089039 0.089352 0.087526 0.085598 0.083622 0.081632
+7 0.089881 0.088209 0.088484 0.086757 0.084916 0.083015 0.081092
+8 0.088556 0.086985 0.087242 0.085610 0.083855 0.082032 0.080182
+9 0.086985 0.085510 0.085763 0.084221 0.082549 0.080806 0.079029
+10 0.087242 0.085763 0.086430 0.084864 0.083177 0.081425 0.079643
+11 0.085610 0.084221 0.084864 0.083384 0.081778 0.080101 0.078390
+12 0.083855 0.082549 0.083177 0.081778 0.080249 0.078646 0.077005
+13 0.082032 0.080806 0.081425 0.080101 0.078646 0.077115 0.075542
+14 0.080182 0.079029 0.079643 0.078390 0.077005 0.075542 0.074036
[2. 2.]
-Training MSE for OLS
+Training MSE for OLS
3.0
+
We see here that we reach a plateau for the Ridge results. Writing out the coefficients \(\boldsymbol{\beta}\), we that they are getting smaller and smaller and our error stabilizes since the predicted values of \(\tilde{\boldsymbol{y}}\) approach zero.
@@ -2438,6 +2441,7 @@ Optimal solution found.More text will be added to this example.
It is a conditional probability (see below) and reads as the likelihood of a domain of events \(\boldsymbol{D}\) given a set of parameters \(\boldsymbol{\beta}\).
+It is a conditional probability (see below) and reads as the +likelihood of a domain of events \(\boldsymbol{D}\) given a set of parameters +\(\boldsymbol{\beta}\).
In statistics, maximum likelihood estimation (MLE) is a method of estimating the parameters of an assumed probability distribution, given some observed data. This is achieved by maximizing a likelihood @@ -2663,12 +2669,12 @@ Bayes’ theorem is extremely simple to derive. But to do so we need some basic
Assume we have two domains of events \(X=[x_0,x_1,\dots,x_{n-1}]\) and \(Y=[y_0,y_1,\dots,y_{n-1}]\).
We define also the likelihood for \(X\) and \(Y\) as \(p(X)\) and \(p(Y)\) respectively. The likelihood of a specific event \(x_i\) (or \(y_i\)) is then written as \(p(X=x_i)\) or just \(p(x_i)=p_i\).
-Union of events is given by.
+The union of events is given by
The product rule (aka joint probability) is given by.
+The product rule (aka joint probability) is given by
The function \(p(X)\) on the right hand side is called the prior while the function on the left hand side is the called the posterior probability. The denominator on the right hand side serves as a normalization factor for the posterior distribution.
+The function \(p(X)\) on the right hand side is called the prior while +the function on the left hand side is the called the posterior +probability. The denominator on the right hand side serves as a +normalization factor for the posterior distribution.
Let us try to illustrate Bayes’ theorem through an example.
-Let us suppose that you are undergoing a series of mammography scans in -order to rule out possible breast cancer cases. We define the +
Let us suppose that you are undergoing a series of mammography scans +in order to rule out possible breast cancer cases. We define the sensitivity for a positive event by the variable \(X\). It takes binary values with \(X=1\) representing a positive event and \(X=0\) being a negative event. We reserve \(Y\) as a classification parameter for -either a negative or a positive breast cancer confirmation. (Short note on wordings: positive here means having breast cancer, although none of us would consider this being a positive thing).
+either a negative or a positive breast cancer confirmation. (Short +note on wordings: positive here means having breast cancer, although +none of us would consider this being a positive thing).We let \(Y=1\) represent the the case of having breast cancer and \(Y=0\) as not.
-Let us assume that if you have breast cancer, the test will be positive with a probability of \(0.8\), that is we have
+Let us assume that if you have breast cancer, the test will be positive with a probability of \(0.8\) (the numbers here are all made up), +that is we have
This obviously sounds scary since many would conclude that if the test is positive, there is a likelihood of \(80\%\) for having cancer. -It is however not correct, as the following Bayesian analysis shows.
-If we look at various national surveys on breast cancer, the general likelihood of developing breast cancer is a very small number. -Let us assume that the prior probability in the population as a whole is
+This obviously sounds scary since many would conclude that if the test +is positive, there is a likelihood of \(80\%\) for having cancer. It is +however not correct, as the following Bayesian analysis shows. The correct question to pose is what is the probability of having breast cancer in case of a positive test? +We are thus interested in
+instead of \(p(X=1\vert Y=1)\).
+If we look at various national surveys on breast cancer, the general +likelihood of developing breast cancer is a very small number. Let us +assume that the prior probability in the population as a whole is
We need also to account for the fact that the test may produce a false positive result (false alarm). Let us here assume that we have
+We need also to account for the fact that the test may produce a false +positive result (false alarm). Let us here assume that we have
Using Bayes’ theorem we can then find the posterior probability that the person has breast cancer in case of a positive test, that is we can compute
+Using Bayes’ theorem we can then find the posterior probability that +the person has breast cancer in case of a positive test, that is we +can compute
+ +That is, in case of a positive test, there is only a \(3\%\) chance of having breast cancer!
For Ridge and Lasso regression, the higher order parameters will typically be reduced, providing thereby less fluctuations from one order to another one.
+polynomial fit and that for larger and larger polynomial degrees of +freedom, the parameters will tend to increase in value for OLS. +For Ridge and Lasso regression, the higher order parameters will +typically be reduced, providing thereby less fluctuations from one +order to another one.
import numpy as np
@@ -2802,8 +2842,8 @@ polynomial fit and that for larger and larger polynomial degrees of freedom, the
# Compute the MSE and print it
MSERidgePredict[i] = MSE(y_test,ypredictRidge)
MSELassoPredict[i] = MSE(y_test,ypredictLasso)
- print(lmb,RegRidge.coef_)
- print(lmb,RegLasso.coef_)
+# print(lmb,RegRidge.coef_)
+# print(lmb,RegLasso.coef_)
# Now plot the results
plt.figure()
plt.plot(np.log10(lambdas), MSERidgePredict, 'b', label = 'MSE Ridge Test')
@@ -2819,22 +2859,15 @@ polynomial fit and that for larger and larger polynomial degrees of freedom, the
[ 1.0169643 0.27924636 -1.4087793 1.03308408 0. ]
Test MSE OLS
0.958228616652075
-0.001 [ 1.0170259 0.27852549 -1.40702 1.03193199 0. ]
-0.001 [ 1.034342 -0.18063928 -0. 0. 0. ]
-0.021544346900318832 [ 1.01825571 0.26412372 -1.37186301 1.00890601 0. ]
-0.021544346900318832 [ 0.92280994 -0. -0. -0. 0. ]
-0.46415888336127775 [ 1.0344707 0.07160764 -0.89928965 0.69843037 0. ]
-0.46415888336127775 [0.48019541 0. 0. 0. 0. ]
-10.0 [ 1.04529095 -0.18224665 -0.15751596 0.16831012 0. ]
-10.0 [0. 0. 0. 0. 0.]
-
-
-
+
How can we understand this?
+How can we understand this? More text to be added.
+Using Bayes’ theorem we can gain a better intuition about Ridge and Lasso regression.
For ordinary least squares we postulated that the maximum likelihood for the doamin of events \(\boldsymbol{D}\) (one-dimensional case)
Runtime: 0.136687 sec
+Runtime: 0.138472 sec
Jackknife Statistics :
original bias std. error
- 99.9196 99.9096 0.149076
+ 100.094 100.084 0.150306
Runtime: 1.78082 sec
+Runtime: 2.06834 sec
Bootstrap Statistics :
original bias std. error
- 99.9769 14.9969 99.9765 0.149832
+ 99.9933 15.0354 99.9941 0.149739
---------------------------------------------------------------------------
@@ -769,158 +769,8 @@ original bias std. error
When the repetitive splitting of the data set is done randomly, -samples may accidently end up in a fast majority of the splits in -either training or test set. Such samples may have an unbalanced -influence on either model building or prediction evaluation. To avoid -this \(k\)-fold cross-validation structures the data splitting. The -samples are divided into \(k\) more or less equally sized exhaustive and -mutually exclusive subsets. In turn (at each split) one of these -subsets plays the role of the test set while the union of the -remaining subsets constitutes the training set. Such a splitting -warrants a balanced representation of each sample in both training and -test set over the splits. Still the division into the \(k\) subsets -involves a degree of randomness. This may be fully excluded when -choosing \(k=n\). This particular case is referred to as leave-one-out -cross-validation (LOOCV).
-Define a range of interest for the penalty parameter.
Divide the data set into training and test set comprising samples \(\{1, \ldots, n\} \setminus i\) and \(\{ i \}\), respectively.
Fit the linear regression model by means of ridge estimation for each \(\lambda\) in the grid using the training set, and the corresponding estimate of the error variance \(\boldsymbol{\sigma}_{-i}^2(\lambda)\), as
Evaluate the prediction performance of these models on the test set by \(\log\{L[y_i, \boldsymbol{X}_{i, \ast}; \boldsymbol{\beta}_{-i}(\lambda), \boldsymbol{\sigma}_{-i}^2(\lambda)]\}\). Or, by the prediction error \(|y_i - \boldsymbol{X}_{i, \ast} \boldsymbol{\beta}_{-i}(\lambda)|\), the relative error, the error squared or the R2 score function.
Repeat the first three steps such that each sample plays the role of the test set once.
Average the prediction performances of the test sets at each grid point of the penalty bias/parameter. It is an estimate of the prediction performance of the model corresponding to this value of the penalty parameter on novel data. It is defined as
For the various values of \(k\)
-shuffle the dataset randomly.
Split the dataset into \(k\) groups.
For each unique group:
a. Decide which group to use as set for test data
-b. Take the remaining groups as a training data set
-c. Fit a model on the training set and evaluate it on the test set
-d. Retain the evaluation score and discard the model
-Summarize the model using the sample of model evaluation scores
The code here uses Ridge regression with cross-validation (CV) resampling and \(k\)-fold CV in order to fit a specific polynomial.
-import numpy as np
-import matplotlib.pyplot as plt
-from sklearn.model_selection import KFold
-from sklearn.linear_model import Ridge
-from sklearn.model_selection import cross_val_score
-from sklearn.preprocessing import PolynomialFeatures
-
-# A seed just to ensure that the random numbers are the same for every run.
-# Useful for eventual debugging.
-np.random.seed(3155)
-
-# Generate the data.
-nsamples = 100
-x = np.random.randn(nsamples)
-y = 3*x**2 + np.random.randn(nsamples)
-
-## Cross-validation on Ridge regression using KFold only
-
-# Decide degree on polynomial to fit
-poly = PolynomialFeatures(degree = 6)
-
-# Decide which values of lambda to use
-nlambdas = 500
-lambdas = np.logspace(-3, 5, nlambdas)
-
-# Initialize a KFold instance
-k = 5
-kfold = KFold(n_splits = k)
-
-# Perform the cross-validation to estimate MSE
-scores_KFold = np.zeros((nlambdas, k))
-
-i = 0
-for lmb in lambdas:
- ridge = Ridge(alpha = lmb)
- j = 0
- for train_inds, test_inds in kfold.split(x):
- xtrain = x[train_inds]
- ytrain = y[train_inds]
-
- xtest = x[test_inds]
- ytest = y[test_inds]
-
- Xtrain = poly.fit_transform(xtrain[:, np.newaxis])
- ridge.fit(Xtrain, ytrain[:, np.newaxis])
-
- Xtest = poly.fit_transform(xtest[:, np.newaxis])
- ypred = ridge.predict(Xtest)
-
- scores_KFold[i,j] = np.sum((ypred - ytest[:, np.newaxis])**2)/np.size(ypred)
-
- j += 1
- i += 1
-
-
-estimated_mse_KFold = np.mean(scores_KFold, axis = 1)
-
-## Cross-validation using cross_val_score from sklearn along with KFold
-
-# kfold is an instance initialized above as:
-# kfold = KFold(n_splits = k)
-
-estimated_mse_sklearn = np.zeros(nlambdas)
-i = 0
-for lmb in lambdas:
- ridge = Ridge(alpha = lmb)
-
- X = poly.fit_transform(x[:, np.newaxis])
- estimated_mse_folds = cross_val_score(ridge, X, y[:, np.newaxis], scoring='neg_mean_squared_error', cv=kfold)
-
- # cross_val_score return an array containing the estimated negative mse for every fold.
- # we have to the the mean of every array in order to get an estimate of the mse of the model
- estimated_mse_sklearn[i] = np.mean(-estimated_mse_folds)
-
- i += 1
-
-## Plot and compare the slightly different ways to perform cross-validation
-
-plt.figure()
-
-plt.plot(np.log10(lambdas), estimated_mse_sklearn, label = 'cross_val_score')
-plt.plot(np.log10(lambdas), estimated_mse_KFold, 'r--', label = 'KFold')
-
-plt.xlabel('log10(lambda)')
-plt.ylabel('mse')
-
-plt.legend()
-
-plt.show()
-We will discuss the bias-variance tradeoff in the context of continuous predictions such as regression. However, many of the intuitions and ideas discussed here also carry over to classification @@ -1265,6 +1115,157 @@ flexible statistical methods have higher variance.
When the repetitive splitting of the data set is done randomly, +samples may accidently end up in a fast majority of the splits in +either training or test set. Such samples may have an unbalanced +influence on either model building or prediction evaluation. To avoid +this \(k\)-fold cross-validation structures the data splitting. The +samples are divided into \(k\) more or less equally sized exhaustive and +mutually exclusive subsets. In turn (at each split) one of these +subsets plays the role of the test set while the union of the +remaining subsets constitutes the training set. Such a splitting +warrants a balanced representation of each sample in both training and +test set over the splits. Still the division into the \(k\) subsets +involves a degree of randomness. This may be fully excluded when +choosing \(k=n\). This particular case is referred to as leave-one-out +cross-validation (LOOCV).
+Define a range of interest for the penalty parameter.
Divide the data set into training and test set comprising samples \(\{1, \ldots, n\} \setminus i\) and \(\{ i \}\), respectively.
Fit the linear regression model by means of ridge estimation for each \(\lambda\) in the grid using the training set, and the corresponding estimate of the error variance \(\boldsymbol{\sigma}_{-i}^2(\lambda)\), as
Evaluate the prediction performance of these models on the test set by \(\log\{L[y_i, \boldsymbol{X}_{i, \ast}; \boldsymbol{\beta}_{-i}(\lambda), \boldsymbol{\sigma}_{-i}^2(\lambda)]\}\). Or, by the prediction error \(|y_i - \boldsymbol{X}_{i, \ast} \boldsymbol{\beta}_{-i}(\lambda)|\), the relative error, the error squared or the R2 score function.
Repeat the first three steps such that each sample plays the role of the test set once.
Average the prediction performances of the test sets at each grid point of the penalty bias/parameter. It is an estimate of the prediction performance of the model corresponding to this value of the penalty parameter on novel data. It is defined as
For the various values of \(k\)
+shuffle the dataset randomly.
Split the dataset into \(k\) groups.
For each unique group:
a. Decide which group to use as set for test data
+b. Take the remaining groups as a training data set
+c. Fit a model on the training set and evaluate it on the test set
+d. Retain the evaluation score and discard the model
+Summarize the model using the sample of model evaluation scores
The code here uses Ridge regression with cross-validation (CV) resampling and \(k\)-fold CV in order to fit a specific polynomial.
+import numpy as np
+import matplotlib.pyplot as plt
+from sklearn.model_selection import KFold
+from sklearn.linear_model import Ridge
+from sklearn.model_selection import cross_val_score
+from sklearn.preprocessing import PolynomialFeatures
+
+# A seed just to ensure that the random numbers are the same for every run.
+# Useful for eventual debugging.
+np.random.seed(3155)
+
+# Generate the data.
+nsamples = 100
+x = np.random.randn(nsamples)
+y = 3*x**2 + np.random.randn(nsamples)
+
+## Cross-validation on Ridge regression using KFold only
+
+# Decide degree on polynomial to fit
+poly = PolynomialFeatures(degree = 6)
+
+# Decide which values of lambda to use
+nlambdas = 500
+lambdas = np.logspace(-3, 5, nlambdas)
+
+# Initialize a KFold instance
+k = 5
+kfold = KFold(n_splits = k)
+
+# Perform the cross-validation to estimate MSE
+scores_KFold = np.zeros((nlambdas, k))
+
+i = 0
+for lmb in lambdas:
+ ridge = Ridge(alpha = lmb)
+ j = 0
+ for train_inds, test_inds in kfold.split(x):
+ xtrain = x[train_inds]
+ ytrain = y[train_inds]
+
+ xtest = x[test_inds]
+ ytest = y[test_inds]
+
+ Xtrain = poly.fit_transform(xtrain[:, np.newaxis])
+ ridge.fit(Xtrain, ytrain[:, np.newaxis])
+
+ Xtest = poly.fit_transform(xtest[:, np.newaxis])
+ ypred = ridge.predict(Xtest)
+
+ scores_KFold[i,j] = np.sum((ypred - ytest[:, np.newaxis])**2)/np.size(ypred)
+
+ j += 1
+ i += 1
+
+
+estimated_mse_KFold = np.mean(scores_KFold, axis = 1)
+
+## Cross-validation using cross_val_score from sklearn along with KFold
+
+# kfold is an instance initialized above as:
+# kfold = KFold(n_splits = k)
+
+estimated_mse_sklearn = np.zeros(nlambdas)
+i = 0
+for lmb in lambdas:
+ ridge = Ridge(alpha = lmb)
+
+ X = poly.fit_transform(x[:, np.newaxis])
+ estimated_mse_folds = cross_val_score(ridge, X, y[:, np.newaxis], scoring='neg_mean_squared_error', cv=kfold)
+
+ # cross_val_score return an array containing the estimated negative mse for every fold.
+ # we have to the the mean of every array in order to get an estimate of the mse of the model
+ estimated_mse_sklearn[i] = np.mean(-estimated_mse_folds)
+
+ i += 1
+
+## Plot and compare the slightly different ways to perform cross-validation
+
+plt.figure()
+
+plt.plot(np.log10(lambdas), estimated_mse_sklearn, label = 'cross_val_score')
+plt.plot(np.log10(lambdas), estimated_mse_KFold, 'r--', label = 'KFold')
+
+plt.xlabel('log10(lambda)')
+plt.ylabel('mse')
+
+plt.legend()
+
+plt.show()
+More examples of the application of cross-validation follow here.
# Common imports
diff --git a/doc/LectureNotes/_build/html/chapter4.html b/doc/LectureNotes/_build/html/chapter4.html
index ee803c07c..bb0ddc790 100644
--- a/doc/LectureNotes/_build/html/chapter4.html
+++ b/doc/LectureNotes/_build/html/chapter4.html
@@ -54,7 +54,7 @@
-
+
@@ -159,7 +159,7 @@
Almost every problem in machine learning and data science starts with a dataset \(X\), a model \(g(\beta)\), which is a function of the parameters \(\beta\) and a cost function \(C(X, g(\beta))\) that allows @@ -1307,9 +1135,6 @@ us to judge how well the model \(g(\b the cost function. Ideally we would be able to solve for \(\beta\) analytically, however this is not possible in general and we must use some approximative/numerical method to compute the minimum.
-In our discussion on Logistic Regression we studied the case of two classes, with \(y_i\) either @@ -1324,9 +1149,6 @@ p(y_i=0|x_i,\boldsymbol{\beta}) &= 1 - p(y_i=1|x_i,\boldsymbol{\beta}), \end{align*} \end{split}\]
where \(\boldsymbol{\beta}\) are the weights we wish to extract from data, in our case \(\beta_0\) and \(\beta_1\).
-Our compact equations used a definition of a vector \(\boldsymbol{y}\) with \(n\) elements \(y_i\), an \(n\times p\) matrix \(\boldsymbol{X}\) which contains the \(x_i\) values and a vector \(\boldsymbol{p}\) of fitted probabilities @@ -1343,9 +1165,6 @@ the first derivative of the cost function as
\frac{\partial^2 \mathcal{C}(\boldsymbol{\beta})}{\partial \boldsymbol{\beta}\partial \boldsymbol{\beta}^T} = \boldsymbol{X}^T\boldsymbol{W}\boldsymbol{X}. \]This defines what is called the Hessian matrix.
-If we can set up these equations, Newton-Raphson’s iterative method is normally the method of choice. It requires however that we can compute in an efficient way the matrices that define the first and second derivatives.
Our iterative scheme is then given by
The right-hand side is computed with the old values of \(\beta\).
If we can compute these matrices, in particular the Hessian, the above is often the easiest method to implement.
-Let us quickly remind ourselves how we derive the above method.
Perhaps the most celebrated of all one-dimensional root-finding routines is Newton’s method, also called the Newton-Raphson @@ -1370,9 +1186,6 @@ function \(f\) and its derivat If you can only calculate the derivative numerically and/or your function is not of the smooth type, we normally discourage the use of this method.
-The Newton-Raphson formula consists geometrically of extending the tangent line at a current point until it crosses zero, then setting the next guess to the abscissa of that zero-crossing. The mathematics @@ -1401,9 +1214,6 @@ s\approx x-\frac{f(x)}{f'(x)}. \[ x_{n+1}=x_n-\frac{f(x_n)}{f'(x_n)}. \]
The above is Newton-Raphson’s method. It has a simple geometric interpretation, namely \(x_{n+1}\) is the point where the tangent from \((x_n,f(x_n))\) crosses the \(x\)-axis. Close to the solution, @@ -1415,9 +1225,6 @@ from the true root as to let the search interval include a local maximum or minimum of the function. If an iteration places a trial guess near such a local extremum, so that the first derivative nearly vanishes, then Newton-Raphson may fail totally
-Newton’s method can be generalized to systems of several non-linear equations and variables. Consider the case with two equations
It is rather straightforward to extend the above scheme to systems of more than two non-linear equations. In our case, the Jacobian matrix is given by the Hessian that represents the second derivative of cost function.
-The basic idea of gradient descent is
that a function \(F(\mathbf{x})\),
\(\mathbf{x} \equiv (x_1,\cdots,x_n)\), decreases fastest if one goes from \(\bf {x}\) in the
@@ -1479,9 +1285,6 @@ direction of the negative gradient \(
For \(\gamma_k\) small enough, then \(F(\mathbf{x}_{k+1}) \leq
F(\mathbf{x}_k)\). This means that for a sufficiently small \(\gamma_k\)
we are always moving towards smaller function values, i.e a minimum.
The previous observation is the basis of the method of steepest descent, which is also referred to as just gradient descent (GD). One starts with an initial guess \(\mathbf{x}_0\) for a minimum of \(F\) and @@ -1492,9 +1295,6 @@ computes new approximations according to
\]The parameter \(\gamma_k\) is often referred to as the step length or the learning rate within the context of Machine Learning.
-Ideally the sequence \(\{\mathbf{x}_k \}_{k=0}\) converges to a global minimum of the function \(F\). In general we do not know if we are in a global or local minimum. In the special case when \(F\) is a convex @@ -1510,9 +1310,6 @@ have a very good intial guess. This also implies that the scheme is sensitive to the chosen initial condition.
Note that the gradient is a function of \(\mathbf{x} = (x_1,\cdots,x_n)\) which makes it expensive to compute numerically.
-The gradient descent method is sensitive to the choice of learning rate \(\gamma_k\). This is due to the fact that we are only guaranteed that \(F(\mathbf{x}_{k+1}) \leq @@ -1525,7 +1322,7 @@ randomness. One such method is that of Stochastic Gradient Descent (SGD), see below.
Ideally we want our cost/loss function to be convex(concave).
First we give the definition of a convex set: A set \(C\) in \(\mathbb{R}^n\) is said to be convex if, for all \(x\) and \(y\) in \(C\) and @@ -1535,13 +1332,7 @@ connecting \(x\) and The convex subsets of \(\mathbb{R}\) are the intervals of \(\mathbb{R}\). Examples of convex sets of \(\mathbb{R}^2\) are the regular polygons (triangles, rectangles, pentagons, etc…).
-Convex function: Let \(X \subset \mathbb{R}^n\) be a convex set. Assume that the function \(f: X \rightarrow \mathbb{R}\) is continuous, then \(f\) is said to be convex if $\(f(tx_1 + (1-t)x_2) \leq tf(x_1) + (1-t)f(x_2) \)\( for all \)x_1, x_2 \in X\( and for all \)t \in [0,1]\(. If \)\leq\( is replaced with a strict inequaltiy in the definition, we demand \)x_1 \neq x_2\( and \)t\in(0,1)\( then \)f\( is said to be strictly convex. For a single variable function, convexity means that if you draw a straight line connecting \)f(x_1)\( and \)f(x_2)\(, the value of the function on the interval \)[x_1,x_2]$ is always below the line as illustrated below.
-In the following we state first and second-order conditions which ensures convexity of a function \(f\). We write \(D_f\) to denote the domain of \(f\), i.e the subset of \(R^n\) where \(f\) is defined. For more @@ -1563,9 +1354,6 @@ Hessian is positive semi-definite for all \(f''(x) \geq 0\). Geometrically this means that \(f\) has nonnegative curvature everywhere.
This condition is particularly useful since it gives us an procedure for determining if the function under consideration is convex, apart from using the definition.
-The next result is of great importance to us and the reason why we are going on about convex functions. In machine learning we frequently have to minimize a loss/cost function in order to find the best @@ -1579,9 +1367,8 @@ is convex the following result provides invaluable information:
is minimal, where \(f\) is convex and differentiable. Then, any point \(x^*\) that satisfies \(\nabla f(x^*) = 0\) is a global minimum.This result means that if we know that the cost/loss function is convex and we are able to find a minimum, we are guaranteed that it is a global minimum.
-Show that \(f(x)=x^2\) is convex for \(x \in \mathbb{R}\) using the definition of convexity. Hint: If you re-write the definition, \(f\) is convex if the following holds for all \(x,y \in D_f\) and any \(\lambda \in [0,1]\) \(\lambda f(x)+(1-\lambda)f(y)-f(\lambda x + (1-\lambda) y ) \geq 0\).
Using the second order condition show that the following functions are convex on the specified domain.
Using the definition of convexity, try to show that a function satisfying the properties above is convex (the third condition is not needed to show this).
Before we proceed, we would like to discuss the approach called the standard Steepest descent (different from the above steepest descent discussion), which again leads to us having to be able to compute a matrix. It belongs to the class of Conjugate Gradient methods (CG).
@@ -1626,9 +1410,6 @@ algebra of the type \]where \(\boldsymbol{r}\) is the so-called residual or error in the iterative process.
When we have found the exact solution, \(\boldsymbol{r}=0\).
-The residual is zero when we reach the minimum of the quadratic equation
with the constraint that the matrix \(\boldsymbol{A}\) is positive definite and symmetric. This defines also the Hessian and we want it to be positive definite.
-We denote the initial guess for \(\boldsymbol{x}\) as \(\boldsymbol{x}_0\). We can assume without loss of generality that
instead.
-One can show that the solution \(\boldsymbol{x}\) is also the unique minimizer of the quadratic form
and \(\boldsymbol{x}_0=0\) it is equal \(-\boldsymbol{b}\).
-We can compute the residual iteratively as
import numpy as np
@@ -1724,6 +1493,12 @@ which equals
<mpl_toolkits.mplot3d.art3d.Poly3DCollection at 0x7febdb109490>
+
+And then as countor plot
+Find guesses
[ 1.33333333 -0.26666667]
+What happened?
[<matplotlib.lines.Line2D at 0x7febdb6780d0>]
+
+In the CG method we define so-called conjugate directions and two vectors \(\boldsymbol{s}\) and \(\boldsymbol{t}\) are said to be @@ -1788,18 +1577,12 @@ of our vectors \(\boldsymbol{x}_i\) \]
Two vectors are conjugate if they are orthogonal with respect to this inner product. Being conjugate is a symmetric relation: if \(\boldsymbol{s}\) is conjugate to \(\boldsymbol{t}\), then \(\boldsymbol{t}\) is conjugate to \(\boldsymbol{s}\).
- -An example is given by the eigenvectors of the matrix
which is zero unless \(i=j\).
-Assume now that we have a symmetric positive-definite matrix \(\boldsymbol{A}\) of size \(n\times n\). At each iteration \(i+1\) we obtain the conjugate direction of a vector
The coefficients are given by
If we choose the conjugate vectors \(\boldsymbol{p}_k\) carefully, then we may not need all of them to obtain a good approximation to the solution \(\boldsymbol{x}\). @@ -1852,9 +1629,6 @@ We can assume without loss of generality that
\boldsymbol{A}\boldsymbol{z} = \boldsymbol{b}-\boldsymbol{A}\boldsymbol{x}_0, \]instead.
-One can show that the solution \(\boldsymbol{x}\) is also the unique minimizer of the quadratic form
Let \(\boldsymbol{r}_k\) be the residual at the \(k\)-th step:
We can also compute the residual iteratively as
We will use linear regression as a case study for the gradient descent methods. Linear regression is a great test case for the gradient descent methods discussed in the lectures since it has several desirable properties such as:
An analytical solution (recall homework set 1).
An analytical solution.
The gradient can be computed analytically.
The cost function is convex which guarantees that gradient descent converges for small enough learning rates
---------------------------------------------------------------------------
+NameError Traceback (most recent call last)
+<ipython-input-14-be0d226abb41> in <module>
+----> 1 x = 2*np.random.rand(m,1)
+ 2 y = 4+3*x+np.random.randn(m,1)
+
+NameError: name 'm' is not defined
+with \(x_i \in [0,1] \) is chosen randomly using a uniform distribution. Additionally we have a stochastic noise chosen according to a normal distribution \(\cal {N}(0,1)\). The linear regression model is given by
@@ -1945,9 +1724,6 @@ h_\beta(x) = \boldsymbol{y} = \beta_0 + \beta_1 x, \[ \boldsymbol{y}_i = \beta_0 + \beta_1 x_i. \] - -Let \(\mathbf{y} = (y_1,\cdots,y_n)^T\), \(\mathbf{\boldsymbol{y}} = (\boldsymbol{y}_1,\cdots,\boldsymbol{y}_n)^T\) and \(\beta = (\beta_0, \beta_1)^T\)
It is convenient to write \(\mathbf{\boldsymbol{y}} = X\beta\) where \(X \in \mathbb{R}^{100 \times 2} \) is the design matrix given by (we keep the intercept here)
and we want to find \(\beta\) such that \(C(\beta)\) is minimized.
-Computing \(\partial C(\beta) / \partial \beta_0\) and \(\partial C(\beta) / \partial \beta_1\) we can show that the gradient can be written as
where \(X\) is the design matrix defined above.
-The Hessian matrix of \(C(\beta)\) is given by
This result implies that \(C(\beta)\) is a convex function since the matrix \(X^T X\) always is positive semi-definite.
-We can now write a program that minimizes \(C(\beta)\) using the gradient descent method with a constant learning rate \(\gamma\) according to
And finally we can compare our solution for \(\beta\) with the analytic result given by \(\beta= (X^TX)^{-1} X^T \mathbf{y}\).
-Here our simple example
+Here is our simple example
# Importing various packages
@@ -2055,9 +1819,7 @@ when \(||\nabla_\beta C(\beta_k) || \
Alternatively, we can use Scikit-Learn as done here
# Importing various packages
@@ -2080,9 +1842,6 @@ when \(||\nabla_\beta C(\beta_k) || \
We have also discussed Ridge regression where the loss function contains a regularized term given by the \(L_2\) norm of \(\beta\),
from random import random, seed
@@ -2154,7 +1910,7 @@ C_{\text{ridge}}(\beta) = \frac{1}{n}||X\beta -\mathbf{y}||^2 + \lambda ||\beta|
Gradient descent (GD) finds local minima of our function. Since the GD algorithm is deterministic, if it converges, it will converge to a local minimum of our cost/loss/risk function. Because in ML we are often dealing with extremely rugged landscapes with many local minima, this can lead to poor performance.
GD is sensitive to initial conditions. One consequence of the local nature of GD is that initial conditions matter. Depending on where one starts, one will end up at a different local minima. Therefore, it is very important to think about how one initializes the training process. This is true for GD as well as more complicated variants of GD.
Stochastic gradient descent (SGD) and variants thereof address some of the shortcomings of the Gradient descent method discussed above.
The underlying idea of SGD comes from the observation that the cost
@@ -2176,9 +1932,6 @@ sum over \(n\) data points
This in turn means that the gradient can be computed as a sum over \(i\)-gradients
As an example, suppose we have \(10\) data points \((\mathbf{x}_1,\cdots, \mathbf{x}_{10})\) and we choose to have \(M=5\) minibathces, then each minibatch contains two data points. In particular we have @@ -2212,9 +1962,6 @@ C(\mathbf{\beta}) = \sum_{i=1}^n \nabla_\beta c_i(\mathbf{x}_i, \mathbf{\beta}) \rightarrow \sum_{i \in B_k}^n \nabla_\beta c_i(\mathbf{x}_i, \mathbf{\beta}). \]
Thus a gradient descent step now looks like
import numpy as np
@@ -2256,9 +2000,6 @@ the size of the minibatches are small relative to the number of
datapoints (\(M < n\)), the computation of the gradient is much
cheaper since we sum over the datapoints in the \(k-th\) minibatch and not
all \(n\) datapoints.
-A natural question is when do we stop the search for a new minimum? One possibility is to compute the full gradient after a given number of epochs and check if the norm of the gradient is smaller than some @@ -2269,9 +2010,6 @@ evaluate the cost function at this point, store the result and continue the search. If the test kicks in at a later stage we can compare the values of the cost function and keep the \(\beta\) that gave the lowest value.
-Another approach is to let the step length \(\gamma_j\) depend on the number of epochs in such a way that it becomes very small after a reasonable time such that we do not move at all.
@@ -2311,9 +2049,8 @@ function.# Importing various packages
@@ -2384,7 +2121,594 @@ function.
Challenge: try to write a similar code for a Logistic Regression case.
+The stochastic gradient descent (SGD) is almost always used with a +momentum or inertia term that serves as a memory of the direction we +are moving in parameter space. This is typically implemented as +follows
+where we have introduced a momentum parameter \(\gamma\), with +\(0\le\gamma\le 1\), and for brevity we dropped the explicit notation to +indicate the gradient is to be taken over a different mini-batch at +each step. We call this algorithm gradient descent with momentum +(GDM). From these equations, it is clear that \(\mathbf{v}_t\) is a +running average of recently encountered gradients and +\((1-\gamma)^{-1}\) sets the characteristic time scale for the memory +used in the averaging procedure. Consistent with this, when +\(\gamma=0\), this just reduces down to ordinary SGD as discussed +earlier. An equivalent way of writing the updates is
+where we have defined \(\Delta \boldsymbol{\theta}_{t}= \boldsymbol{\theta}_t-\boldsymbol{\theta}_{t-1}\).
+Let us try to get more intuition from these equations. It is helpful +to consider a simple physical analogy with a particle of mass \(m\) +moving in a viscous medium with drag coefficient \(\mu\) and potential +\(E(\mathbf{w})\). If we denote the particle’s position by \(\mathbf{w}\), +then its motion is described by
+We can discretize this equation in the usual way to get
+Rearranging this equation, we can rewrite this as
+Notice that this equation is identical to previous one if we identify +the position of the particle, \(\mathbf{w}\), with the parameters +\(\boldsymbol{\theta}\). This allows us to identify the momentum +parameter and learning rate with the mass of the particle and the +viscous drag as:
+Thus, as the name suggests, the momentum parameter is proportional to +the mass of the particle and effectively provides inertia. +Furthermore, in the large viscosity/small learning rate limit, our +memory time scales as \((1-\gamma)^{-1} \approx m/(\mu \Delta t)\).
+Why is momentum useful? SGD momentum helps the gradient descent +algorithm gain speed in directions with persistent but small gradients +even in the presence of stochasticity, while suppressing oscillations +in high-curvature directions. This becomes especially important in +situations where the landscape is shallow and flat in some directions +and narrow and steep in others. It has been argued that first-order +methods (with appropriate initial conditions) can perform comparable +to more expensive second order methods, especially in the context of +complex deep learning models.
+These beneficial properties of momentum can sometimes become even more +pronounced by using a slight modification of the classical momentum +algorithm called Nesterov Accelerated Gradient (NAG).
+In the NAG algorithm, rather than calculating the gradient at the +current parameters, \(\nabla_\theta E(\boldsymbol{\theta}_t)\), one +calculates the gradient at the expected value of the parameters given +our current momentum, \(\nabla_\theta E(\boldsymbol{\theta}_t +\gamma +\mathbf{v}_{t-1})\). This yields the NAG update rule
+One of the major advantages of NAG is that it allows for the use of a larger learning rate than GDM for the same choice of \(\gamma\).
+In stochastic gradient descent, with and without momentum, we still +have to specify a schedule for tuning the learning rates \(\eta_t\) +as a function of time. As discussed in the context of Newton’s +method, this presents a number of dilemmas. The learning rate is +limited by the steepest direction which can change depending on the +current position in the landscape. To circumvent this problem, ideally +our algorithm would keep track of curvature and take large steps in +shallow, flat directions and small steps in steep, narrow directions. +Second-order methods accomplish this by calculating or approximating +the Hessian and normalizing the learning rate by the +curvature. However, this is very computationally expensive for +extremely large models. Ideally, we would like to be able to +adaptively change the step size to match the landscape without paying +the steep computational price of calculating or approximating +Hessians.
+Recently, a number of methods have been introduced that accomplish +this by tracking not only the gradient, but also the second moment of +the gradient. These methods include AdaGrad, AdaDelta, RMS-Prop, and +ADAM.
+In RMS prop, in addition to keeping a running average of the first +moment of the gradient, we also keep track of the second moment +denoted by \(\mathbf{s}_t=\mathbb{E}[\mathbf{g}_t^2]\). The update rule +for RMS prop is given by
+ + +where \(\beta\) controls the averaging time of the second moment and is +typically taken to be about \(\beta=0.9\), \(\eta_t\) is a learning rate +typically chosen to be \(10^{-3}\), and \(\epsilon\sim 10^{-8} \) is a +small regularization constant to prevent divergences. Multiplication +and division by vectors is understood as an element-wise operation. It +is clear from this formula that the learning rate is reduced in +directions where the norm of the gradient is consistently large. This +greatly speeds up the convergence by allowing us to use a larger +learning rate for flat directions.
+A related algorithm is the ADAM optimizer. In ADAM, we keep a running +average of both the first and second moment of the gradient and use +this information to adaptively change the learning rate for different +parameters. In addition to keeping a running average of the first and +second moments of the gradient +(i.e. \(\mathbf{m}_t=\mathbb{E}[\mathbf{g}_t]\) and +\(\mathbf{s}_t=\mathbb{E}[\mathbf{g}^2_t]\), respectively), ADAM +performs an additional bias correction to account for the fact that we +are estimating the first two moments of the gradient using a running +average (denoted by the hats in the update rule below). The update +rule for ADAM is given by (where multiplication and division are once +again understood to be element-wise operations below)
+ + +where \(\beta_1\) and \(\beta_2\) set the memory lifetime of the first and +second moment and are typically taken to be \(0.9\) and \(0.99\) +respectively, and \(\eta\) and \(\epsilon\) are identical to RMSprop.
+Like in RMSprop, the effective step size of a parameter depends on the +magnitude of its gradient squared. To understand this better, let us +rewrite this expression in terms of the variance +\(\boldsymbol{\sigma}_t^2 = \boldsymbol{\mathbf{s}}_t - +(\boldsymbol{\mathbf{m}}_t)^2\). Consider a single parameter \(\theta_t\). The +update rule for this parameter is given by
+Randomize the data when making mini-batches. It is always important to randomly shuffle the data when forming mini-batches. Otherwise, the gradient descent method can fit spurious correlations resulting from the order in which data is presented.
Transform your inputs. Learning becomes difficult when our landscape has a mixture of steep and flat directions. One simple trick for minimizing these situations is to standardize the data by subtracting the mean and normalizing the variance of input variables. Whenever possible, also decorrelate the inputs. To understand why this is helpful, consider the case of linear regression. It is easy to show that for the squared error cost function, the Hessian of the cost function is just the correlation matrix between the inputs. Thus, by standardizing the inputs, we are ensuring that the landscape looks homogeneous in all directions in parameter space. Since most deep networks can be viewed as linear transformations followed by a non-linearity at each layer, we expect this intuition to hold beyond the linear case.
Monitor the out-of-sample performance. Always monitor the performance of your model on a validation set (a small portion of the training data that is held out of the training process to serve as a proxy for the test set. If the validation error starts increasing, then the model is beginning to overfit. Terminate the learning process. This early stopping significantly improves performance in many settings.
Adaptive optimization methods don’t always have good generalization. Recent studies have shown that adaptive methods such as ADAM, RMSPorp, and AdaGrad tend to have poor generalization compared to SGD or SGD with momentum, particularly in the high-dimensional limit (i.e. the number of parameters exceeds the number of data points). Although it is not clear at this stage why these methods perform so well in training deep neural networks, simpler procedures like properly-tuned SGD may work as well or better in these applications.
Automatic differentiation (AD), +also called algorithmic +differentiation or computational differentiation,is a set of +techniques to numerically evaluate the derivative of a function +specified by a computer program. AD exploits the fact that every +computer program, no matter how complicated, executes a sequence of +elementary arithmetic operations (addition, subtraction, +multiplication, division, etc.) and elementary functions (exp, log, +sin, cos, etc.). By applying the chain rule repeatedly to these +operations, derivatives of arbitrary order can be computed +automatically, accurately to working precision, and using at most a +small constant factor more arithmetic operations than the original +program.
+Automatic differentiation is neither:
+Symbolic differentiation, nor
Numerical differentiation (the method of finite differences).
Symbolic differentiation can lead to inefficient code and faces the +difficulty of converting a computer program into a single expression, +while numerical differentiation can introduce round-off errors in the +discretization process and cancellation
+Python has tools for so-called automatic differentiation. +Consider the following example
+which has the following derivative
+Using autograd we have
+import autograd.numpy as np
+
+# To do elementwise differentiation:
+from autograd import elementwise_grad as egrad
+
+# To plot:
+import matplotlib.pyplot as plt
+
+
+def f(x):
+ return np.sin(2*np.pi*x + x**2)
+
+def f_grad_analytic(x):
+ return np.cos(2*np.pi*x + x**2)*(2*np.pi + 2*x)
+
+# Do the comparison:
+x = np.linspace(0,1,1000)
+
+f_grad = egrad(f)
+
+computed = f_grad(x)
+analytic = f_grad_analytic(x)
+
+plt.title('Derivative computed from Autograd compared with the analytical derivative')
+plt.plot(x,computed,label='autograd')
+plt.plot(x,analytic,label='analytic')
+
+plt.xlabel('x')
+plt.ylabel('y')
+plt.legend()
+
+plt.show()
+
+print("The max absolute difference is: %g"%(np.max(np.abs(computed - analytic))))
+Here we +experiment with what kind of functions Autograd is capable +of finding the gradient of. The following Python functions are just +meant to illustrate what Autograd can do, but please feel free to +experiment with other, possibly more complicated, functions as well.
+import autograd.numpy as np
+from autograd import grad
+
+def f1(x):
+ return x**3 + 1
+
+f1_grad = grad(f1)
+
+# Remember to send in float as argument to the computed gradient from Autograd!
+a = 1.0
+
+# See the evaluated gradient at a using autograd:
+print("The gradient of f1 evaluated at a = %g using autograd is: %g"%(a,f1_grad(a)))
+
+# Compare with the analytical derivative, that is f1'(x) = 3*x**2
+grad_analytical = 3*a**2
+print("The gradient of f1 evaluated at a = %g by finding the analytic expression is: %g"%(a,grad_analytical))
+To differentiate with respect to two (or more) arguments of a Python +function, Autograd need to know at which variable the function if +being differentiated with respect to.
+import autograd.numpy as np
+from autograd import grad
+def f2(x1,x2):
+ return 3*x1**3 + x2*(x1 - 5) + 1
+
+# By sending the argument 0, Autograd will compute the derivative w.r.t the first variable, in this case x1
+f2_grad_x1 = grad(f2,0)
+
+# ... and differentiate w.r.t x2 by sending 1 as an additional arugment to grad
+f2_grad_x2 = grad(f2,1)
+
+x1 = 1.0
+x2 = 3.0
+
+print("Evaluating at x1 = %g, x2 = %g"%(x1,x2))
+print("-"*30)
+
+# Compare with the analytical derivatives:
+
+# Derivative of f2 w.r.t x1 is: 9*x1**2 + x2:
+f2_grad_x1_analytical = 9*x1**2 + x2
+
+# Derivative of f2 w.r.t x2 is: x1 - 5:
+f2_grad_x2_analytical = x1 - 5
+
+# See the evaluated derivations:
+print("The derivative of f2 w.r.t x1: %g"%( f2_grad_x1(x1,x2) ))
+print("The analytical derivative of f2 w.r.t x1: %g"%( f2_grad_x1(x1,x2) ))
+
+print()
+
+print("The derivative of f2 w.r.t x2: %g"%( f2_grad_x2(x1,x2) ))
+print("The analytical derivative of f2 w.r.t x2: %g"%( f2_grad_x2(x1,x2) ))
+Note that the grad function will not produce the true gradient of the function. The true gradient of a function with two or more variables will produce a vector, where each element is the function differentiated w.r.t a variable.
+import autograd.numpy as np
+from autograd import grad
+def f3(x): # Assumes x is an array of length 5 or higher
+ return 2*x[0] + 3*x[1] + 5*x[2] + 7*x[3] + 11*x[4]**2
+
+f3_grad = grad(f3)
+
+x = np.linspace(0,4,5)
+
+# Print the computed gradient:
+print("The computed gradient of f3 is: ", f3_grad(x))
+
+# The analytical gradient is: (2, 3, 5, 7, 22*x[4])
+f3_grad_analytical = np.array([2, 3, 5, 7, 22*x[4]])
+
+# Print the analytical gradient:
+print("The analytical gradient of f3 is: ", f3_grad_analytical)
+Note that in this case, when sending an array as input argument, the +output from Autograd is another array. This is the true gradient of +the function, as opposed to the function in the previous example. By +using arrays to represent the variables, the output from Autograd +might be easier to work with, as the output is closer to what one +could expect form a gradient-evaluting function.
+import autograd.numpy as np
+from autograd import grad
+def f4(x):
+ return np.sqrt(1+x**2) + np.exp(x) + np.sin(2*np.pi*x)
+
+f4_grad = grad(f4)
+
+x = 2.7
+
+# Print the computed derivative:
+print("The computed derivative of f4 at x = %g is: %g"%(x,f4_grad(x)))
+
+# The analytical derivative is: x/sqrt(1 + x**2) + exp(x) + cos(2*pi*x)*2*pi
+f4_grad_analytical = x/np.sqrt(1 + x**2) + np.exp(x) + np.cos(2*np.pi*x)*2*np.pi
+
+# Print the analytical gradient:
+print("The analytical gradient of f4 at x = %g is: %g"%(x,f4_grad_analytical))
+import autograd.numpy as np
+from autograd import grad
+def f5(x):
+ if x >= 0:
+ return x**2
+ else:
+ return -3*x + 1
+
+f5_grad = grad(f5)
+
+x = 2.7
+
+# Print the computed derivative:
+print("The computed derivative of f5 at x = %g is: %g"%(x,f5_grad(x)))
+2 +6
+< +< +< +! +! +C +O +D +E +_ +B +L +O +C +K
+p +y +c +o +d
+import autograd.numpy as np
+from autograd import grad
+# Both of the functions are implementation of the sum: sum(x**i) for i = 0, ..., 9
+# The analytical derivative is: sum(i*x**(i-1))
+f6_grad_analytical = 0
+for i in range(10):
+ f6_grad_analytical += i*x**(i-1)
+
+print("The analytical derivative of f6 at x = %g is: %g"%(x,f6_grad_analytical))
+import autograd.numpy as np
+from autograd import grad
+
+def f7(n): # Assume that n is an integer
+ if n == 1 or n == 0:
+ return 1
+ else:
+ return n*f7(n-1)
+
+f7_grad = grad(f7)
+
+n = 2.0
+
+print("The computed derivative of f7 at n = %d is: %g"%(n,f7_grad(n)))
+
+# The function f7 is an implementation of the factorial of n.
+# By using the product rule, one can find that the derivative is:
+
+f7_grad_analytical = 0
+for i in range(int(n)-1):
+ tmp = 1
+ for k in range(int(n)-1):
+ if k != i:
+ tmp *= (n - k)
+ f7_grad_analytical += tmp
+
+print("The analytical derivative of f7 at n = %d is: %g"%(n,f7_grad_analytical))
+Note that if n is equal to zero or one, Autograd will give an error message. This message appears when the output is independent on input.
+Autograd supports many features. However, there are some functions that is not supported (yet) by Autograd.
+Assigning a value to the variable being differentiated with respect to
+import autograd.numpy as np
+from autograd import grad
+def f8(x): # Assume x is an array
+ x[2] = 3
+ return x*2
+
+f8_grad = grad(f8)
+
+x = 8.4
+
+print("The derivative of f8 is:",f8_grad(x))
+Here, Autograd tells us that an ‘ArrayBox’ does not support item assignment. The item assignment is done when the program tries to assign x[2] to the value 3. However, Autograd has implemented the computation of the derivative such that this assignment is not possible.
+import autograd.numpy as np
+from autograd import grad
+def f9(a): # Assume a is an array with 2 elements
+ b = np.array([1.0,2.0])
+ return a.dot(b)
+
+f9_grad = grad(f9)
+
+x = np.array([1.0,0.0])
+
+print("The derivative of f9 is:",f9_grad(x))
+Here we are told that the ‘dot’ function does not belong to Autograd’s +version of a Numpy array. To overcome this, an alternative syntax +which also computed the dot product can be used:
+import autograd.numpy as np
+from autograd import grad
+def f9_alternative(x): # Assume a is an array with 2 elements
+ b = np.array([1.0,2.0])
+ return np.dot(x,b) # The same as x_1*b_1 + x_2*b_2
+
+f9_alternative_grad = grad(f9_alternative)
+
+x = np.array([3.0,0.0])
+
+print("The gradient of f9 is:",f9_alternative_grad(x))
+
+# The analytical gradient of the dot product of vectors x and b with two elements (x_1,x_2) and (b_1, b_2) respectively
+# w.r.t x is (b_1, b_2).
+The documentation recommends to avoid inplace operations such as
+a += b
+a -= b
+a*= b
+a /=b
+More examples will be added, in particular how to compare autograd with own codes for the gradients.
A Support Vector Machine (SVM) is a very powerful and versatile Machine Learning method, capable of performing linear or nonlinear classification, regression, and even outlier detection. It is one of @@ -365,7 +365,7 @@ below. We distinguish also between linear and non-linear approaches. The latter are the most frequent ones since it is rather unlikely that we can separate classes easily by say straight lines.
The theory behind support vector machines (SVM hereafter) is based on the mathematical description of so-called hyperplanes. Let us start with a two-dimensional case. This will also allow us to introduce our @@ -509,7 +509,7 @@ y_i\left(b+w_1x_{i1}+w_2x_{i2}+\dots +w_px_{ip}\right) > 0. \]
When we try to separate hyperplanes, if it exists, we can use it to construct a natural classifier: a test observation is assigned a given class depending on which side of the hyperplane it is located.
Let us try to develop our intuition about SVMs by limiting ourselves to a two-dimensional
plane. To separate the two classes of data points, there are many
possible lines (hyperplanes if you prefer a more strict naming)
@@ -578,7 +578,7 @@ properly into two distinct classes, we may not experience a converge
at all.
A better approach is rather to try to define a large margin between the two classes (if they are well separated from the beginning).
Thus, we wish to find a margin \(M\) with \(\boldsymbol{w}\) normalized to @@ -611,7 +611,7 @@ about Lagrangian multipliers.
Consider a function of three independent variables \(f(x,y,z)\) . For the function \(f\) to be an extreme we have
Below we discuss how to find the optimal values of \(\lambda_i\). Before we proceed however, we discuss now the so-called soft classifier.
Till now, the margin is strictly defined by the support vectors. This defines what is called a hard classifier, that is the margins are well defined.
Suppose now that classes overlap in feature space, as shown in the figure here. One way to deal with this problem before we define the @@ -851,7 +851,7 @@ y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) -(1-\xi_) \geq 0 \hspace{0.1cm}\forall i \]
The cases we have studied till now, were all characterized by two classes with a close to linear separability. The classifiers we have described so far find linear boundaries in our input feature space. It is @@ -984,7 +984,7 @@ Given a kernel \(K\) and the t \(0\leq \lambda_i\) and \(\lambda_i \leq C\). These two inequalities define then the matrix \(\boldsymbol{G}\) and the vector \(\boldsymbol{h}\).
There are several popular kernels being used. These are
Linear: \(K(\boldsymbol{x},\boldsymbol{y})=\boldsymbol{x}^T\boldsymbol{y}\),
from __future__ import division, print_function, unicode_literals
@@ -1222,7 +1222,7 @@ Phi(-1.0, 1) = [0.30119421]
A mathematical (quadratic) optimization problem, or just optimization problem, has the form
We start here with the most basic algorithm, the so-called decision tree. With this basic algorithm we can in turn build more complex networks, spanning from homogeneous and heterogenous forests (bagging, @@ -415,7 +415,7 @@ to be the most informative ones. The process of finding the most informative feature is done until we accomplish a stopping criteria where we then finally end up in so called leaf nodes.
A decision tree is typically divided into a root node, the interior nodes, and the final leaf nodes or just leaves. These entities are then connected by so-called branches.
The leaf nodes @@ -426,7 +426,7 @@ given some assumptions, make predictions about the target feature value (class) of unseen query instances.
There are mainly two steps
We split the predictor space (the set of possible values \(x_1,x_2,\dots, x_p\)) into \(J\) distinct and non-non-overlapping regions, \(R_1,R_2,\dots,R_J\).
In order to implement the recursive binary splitting we start by selecting the predictor \(x_j\) and a cutpoint \(s\) that splits the predictor space into two regions \(R_1\) and \(R_2\)
Building a Regression Tree
Use recursive binary splitting to grow a large tree on the training data, stopping only when each terminal node has fewer than some minimum number of observations.
A classification tree is very similar to a regression tree, except that it is used to predict a qualitative response rather than a quantitative one. Recall that for a regression tree, the predicted @@ -737,7 +737,7 @@ g = \sum_{k=1}^K p_{mk}(1-p_{mk}). s = -\sum_{k=1}^K p_{mk}\log{p_{mk}}. \]
import os
@@ -823,7 +823,7 @@ s = -\sum_{k=1}^K p_{mk}\log{p_{mk}}.
Scikit-Learn has also another way to visualize the trees which is very useful, here with the Iris data.
Two algorithms stand out in the set up of decision trees:
The CART (Classification And Regression Tree) algorithm for both classification and regression
For classification, the CART algorithm splits the data set in two subsets using a single feature \(k\) and a threshold \(t_k\). This could be for example a threshold set by a number below a certain circumference of a malign tumor.
How do we find these two quantities? @@ -887,7 +887,7 @@ hyperparameters control additional stopping conditions such as the \(min\_samples\_leaf\), \(min\_weight\_fraction\_leaf\), and \(max\_leaf\_nodes\).
The CART algorithm for regression works is similar to the one for classification except that instead of trying to split the training set in a way that minimizes say the gini or entropy impurity, it now tries to split the training set in a way that minimizes our well-known mean-squared error (MSE). The cost function is now
The example we will look at is a classical one in many Machine Learning applications. Based on various meteorological features, we have several so-called attributes which decide whether we at the end @@ -944,7 +944,7 @@ humidity and weak and strong for wind.
# Common imports
@@ -1092,7 +1092,7 @@ algorithm ID3.
The ID3 algorithm learns decision trees by constructing them in a top down way, beginning with the question which attribute should be tested at the root of the tree?
The ID3 algorithm uses this information gain measure to select among the candidate attributes at each step while growing the tree.
import matplotlib.pyplot as plt
@@ -1163,7 +1163,7 @@ attributes at each step while growing the tree.
from __future__ import division, print_function, unicode_literals
@@ -1363,7 +1363,7 @@ attributes at each step while growing the tree.
White box, easy to interpret model. Some people believe that decision trees more closely mirror human decision-making than do the regression and classification approaches discussed earlier (think of support vector machines)
Trees are very easy to explain to people. In fact, they are even easier to explain than linear regression!
Trees can be displayed graphically, and are easily interpreted even by a non-expert (especially if they are small)
Unfortunately, trees generally do not have the same level of predictive accuracy as some of the other regression and classification approaches
If continuous features are used the tree may become quite large and hence less interpretable
As stated previously and seen in many of the examples discussed in the previous chapter about a single decision tree, we often end up overfitting our training data. This normally means that we have a high variance. Can we reduce @@ -395,11 +395,11 @@ try to explain here. These are
We discuss these methods here.
The plain decision trees suffer from high variance. This means that if we split the training data into two parts at random, and fit a decision tree to both halves, the results that we @@ -576,7 +576,7 @@ predictor, averaged over all \(B\)
from sklearn.ensemble import BaggingClassifier
@@ -645,7 +645,7 @@ predictor, averaged over all \(B\)
Let us bring up our good old boostrap example from the linear regression lectures. We change the linerar regression algorithm with a decision tree wth different depths and perform a bootstrap aggregate (in this case we perform as many bootstraps as data points \(n\)).
Random forests provide an improvement over bagged trees by way of a small tweak that decorrelates the trees.
As in bagging, we build a @@ -838,7 +838,7 @@ percentage of the total number of cases.
displays the diagnostic ability of a binary classifier system as its discrimination threshold is varied. It plots the true positive rate against the false positive rate.bag_clf = BaggingClassifier(
@@ -864,7 +864,7 @@ discrimination threshold is varied. It plots the true positive rate against the
The basic idea is to combine weak classifiers in order to create a good classifier. With a weak classifier we often intend a classifier which produces results which are only slightly better than we would get by @@ -909,7 +909,7 @@ simply invert a matrix and obtain the parameters \(\beta_m\) and \(\gamma_m\).
The way we proceed is as follows (here we specialize to the squared-error cost function)
Establish a cost function, here \(\cal{C}(\boldsymbol{y},\boldsymbol{f}) = \frac{1}{n} \sum_{i=0}^{n-1}(y_i-f_M(x_i))^2\) with \(f_M(x) = \sum_{i=1}^M \beta_m b(x;\gamma_m)\).
Let us consider a binary classification problem with two outcomes \(y_i \in \{-1,1\}\) and \(i=0,1,2,\dots,n-1\) as our set of observations. We define a classification function \(G(x)\) which produces a prediction taking one or the other of the two values \(\{-1,1\}\).
@@ -1036,7 +1036,7 @@ w_i^{m+1} = w_i^m \exp{(-y_i\beta_m G_m(x_i))} \]The algorithm here is rather straightforward. Assume that our weak classifier is a decision tree and we consider a binary set of outputs with \(y_i \in \{-1,1\}\) and \(i=0,1,2,\dots,n-1\) as our set of @@ -1108,7 +1108,7 @@ observations that are missed in the previous iterations.
Gradient boosting is again a similar technique to Adaptive boosting, it combines so-called weak classifiers or regressors into a strong method via a series of iterations.
@@ -1170,7 +1170,7 @@ C(\boldsymbol{y},\boldsymbol{f})=\sum_{i=0}^{n-1}(y_i-f(x_i))^2.import matplotlib.pyplot as plt
@@ -1225,7 +1225,7 @@ C(\boldsymbol{y},\boldsymbol{f})=\sum_{i=0}^{n-1}(y_i-f(x_i))^2.
import matplotlib.pyplot as plt
@@ -1274,7 +1274,7 @@ C(\boldsymbol{y},\boldsymbol{f})=\sum_{i=0}^{n-1}(y_i-f(x_i))^2.
XGBoost or Extreme Gradient Boosting, is an optimized distributed gradient boosting library designed to be highly efficient, flexible and portable. It implements @@ -1287,7 +1287,7 @@ sketch for efficient proposal calculation. It introduces a novel sparsity-aware
It is now the algorithm which wins essentially all ML competitions!!!
import matplotlib.pyplot as plt
@@ -1426,8 +1426,8 @@ sketch for efficient proposal calculation. It introduces a novel sparsity-aware
diff --git a/doc/LectureNotes/_build/html/chapter8.html b/doc/LectureNotes/_build/html/chapter8.html
index faf67b82a..02bf9f62e 100644
--- a/doc/LectureNotes/_build/html/chapter8.html
+++ b/doc/LectureNotes/_build/html/chapter8.html
@@ -5,7 +5,7 @@
- 10. Basic ideas of the Principal Component Analysis (PCA) — Applied Data Analysis and Machine Learning
+ 11. Basic ideas of the Principal Component Analysis (PCA) — Applied Data Analysis and Machine Learning
@@ -54,8 +54,8 @@
-
-
+
+
@@ -139,17 +139,17 @@
@@ -171,12 +171,12 @@
@@ -188,12 +188,12 @@
The principal component analysis deals with the problem of fitting a low-dimensional affine subspace \(S\) of dimension \(d\) much smaller than the total dimension \(D\) of the problem at hand (our data @@ -386,7 +386,7 @@ Historically, the PCA was first formulated in a statistical setting in order to
A good read is for example Vidal, Ma and Sastry.
Before we discuss the PCA theorem, we need to remind ourselves about the definition of the covariance and the correlation function. These are quantities
Suppose we have defined two vectors @@ -532,7 +532,7 @@ covariance matrix through the np.linalg.eig() function.
The previous example can be converted into the correlation matrix by simply scaling the matrix elements with the variances. We should also subtract the mean values for each column. This leads to the following @@ -752,7 +752,7 @@ x_{10}x_{00}+x_{11}x_{01} & x_{10}^2+x_{11}^2\\
It is easy to generalize this to a matrix \(\boldsymbol{X}\in {\mathbb{R}}^{n\times p}\).
We have that the covariance matrix (the correlation matrix involves a simple rescaling) is given as
Here’s how we would proceed in setting up the algorithm for the PCA, see also discussion below here.
Set up the datapoints for the design/feature matrix \(\boldsymbol{X}\) with \(\boldsymbol{X}\in {\mathbb{R}}^{n\times p}\), with the predictors/features \(p\) referring to the column numbers and the entries \(n\) being the row elements.
We will use a simple example first with two-dimensional data drawn from a multivariate normal distribution with the following mean and covariance matrix (we have fixed these quantities but will play around with them below):
Now we are ready to solve for the principal components! To do so we diagonalize the sample covariance matrix \(\Sigma\). We can use the function np.linalg.eig to do so. It will return the eigenvalues and @@ -1005,7 +1005,7 @@ Second eigenvector
We assume now that we have a design matrix \(\boldsymbol{X}\) which has been centered as discussed above. For the sake of simplicity we skip the overline symbol. The matrix is defined in terms of the various column @@ -1065,7 +1065,7 @@ chapter 12.4 and discussion therein.
For more details, see for example Vidal, Ma and Sastry, chapter 2.
For a detailed demonstration of the geometric interpretation, see Vidal, Ma and Sastry, section 2.1.2.
Principal Component Analysis (PCA) is by far the most popular dimensionality reduction algorithm. First it identifies the hyperplane that lies closest to the data, and then it projects the data onto it.
@@ -1250,7 +1250,7 @@ Selecting this hyperplane ensures that the projection will preserve as much variScikit-Learn’s PCA class implements PCA using SVD decomposition just like we did before. The following code applies PCA to reduce the dimensionality of the dataset down to two dimensions (note that it automatically takes care of centering the data):
@@ -1299,7 +1299,7 @@ available via the \(explained\_varian variance that lies along the axis of each principal component.We can now repeat the above but applied to real data, in this case our breast cancer data. Here we compute performance scores on the training data using logistic regression.
One problem with the preceding implementation of PCA is that it requires the whole training set to fit in memory in order for the SVD algorithm to run. Fortunately, Incremental PCA (IPCA) algorithms have been developed: you can split the training set into mini-batches and feed an IPCA algorithm one minibatch @@ -1390,14 +1390,14 @@ at a time. This is useful for large training sets, and also to apply PCA online instances arrive).
Scikit-Learn offers yet another option to perform PCA, called Randomized PCA. This is a stochastic algorithm that quickly finds an approximation of the first d principal components. Its computational complexity is \(O(m \times d^2)+O(d^3)\), instead of \(O(m \times n^2) + O(n^3)\), so it is dramatically faster than the previous algorithms when \(d\) is much smaller than \(n\).
The kernel trick is a mathematical technique that implicitly maps instances into a very high-dimensional space (called the feature space), enabling nonlinear classification and regression with Support Vector Machines. Recall that a linear decision boundary in the high-dimensional feature @@ -1419,7 +1419,7 @@ For example, the following code uses Scikit-Learn’s KernelPCA class to perform
There are many other dimensionality reduction techniques, several of which are available in Scikit-Learn.
Here are some of the most popular:
Artificial neural networks are computational systems that can learn to perform tasks by considering examples, generally without being programmed with any task-specific rules. It is supposed to mimic a @@ -444,7 +444,7 @@ can be viewed as natural, more powerful extensions of supervised learning methods such as linear and logistic regression and soft-max methods we discussed earlier.
The feed-forward neural network (FFNN) was the first and simplest type of ANNs that were devised. In this network, the information moves in only one direction: forward through the layers.
@@ -456,7 +456,7 @@ to all nodes in the subsequent layer, making this a so-called fully-connected FFNN.A different variant of FFNNs are convolutional neural networks (CNNs), which have a connectivity pattern inspired by the animal visual cortex. Individual neurons in the visual cortex only respond to @@ -476,7 +476,7 @@ produces the outputs. They have wide applications in image and video recognition.
So far we have only mentioned ANNs where information flows in one direction: forward. Recurrent neural networks on the other hand, have connections between nodes that form directed cycles. This @@ -489,7 +489,7 @@ example of such information is sentences, making recurrent NNs especially well-suited for handwriting and speech recognition.
There are many other kinds of ANNs that have been developed. One type that is specifically designed for interpolation in multidimensional space is the radial basis function (RBF) network. RBFs are typically @@ -502,7 +502,7 @@ fully-connected FFNN. They are however usually treated as a separate type of NN due the unusual activation functions.
One uses often so-called fully-connected feed-forward neural networks with three or more layers (an input layer, one or more hidden layers and an output layer) consisting of neurons that have non-linear @@ -672,7 +672,7 @@ the equation for the activations of hidden layer 2 (assuming three nodes for sim \end{equation} \end{split}\]
The activation of node \(i\) in layer 2 is
@@ -691,7 +691,7 @@ used as input to the activation functions. For each operation \(\mathrm{W}_l \hat{y}_{l-1}\) we move forward one layer.A property that characterizes a neural network, other than its connectivity, is the choice of activation function(s). As described in, the following restrictions are imposed on an activation function @@ -811,7 +811,7 @@ become the most popular for deep neural networks
The multilayer perceptron is a very popular, and easy to implement approach, to deep learning. It consists of
A neural network with one or more layers of nodes between the input and the output nodes.
A neural network with only one layer, what we called the simple perceptron, is best suited if we have a standard binary model with clear (linear) boundaries between the outcomes. As such it could @@ -857,7 +857,7 @@ the potential of being universal approximators.
As we have seen now in a feed forward network, we can express the final output of our network in terms of basic matrix-vector multiplications. The unknowwn quantities are our weights \(w_{ij}\) and we need to find an algorithm for changing them so that our errors are as small as possible. This leads us to the famous back propagation algorithm.
@@ -904,7 +904,7 @@ and their nodes. It means we have a_j^l = f(z_j^l) = \frac{1}{1+\exp{-(z_j^l)}}. \]From the definition of the activation \(z_j^l\) we have
We have thus
We have that (replacing \(L\) with a general layer \(l\))
We are now ready to set up the algorithm for back propagation and learning the weights and biases.
The four equations provide us with a way of computing the gradient of the cost function. Let us write this out in the form of an algorithm.
First, we set up the input data \(\hat{x}\) and the activations \(\hat{z}_1\) of the input layer and compute the activation function and @@ -1121,8 +1121,8 @@ Here it is convenient to use stochastic gradient descent (see the examples below
diff --git a/doc/LectureNotes/_build/html/genindex.html b/doc/LectureNotes/_build/html/genindex.html index 5097ffe24..aa55aab4e 100644 --- a/doc/LectureNotes/_build/html/genindex.html +++ b/doc/LectureNotes/_build/html/genindex.html @@ -157,7 +157,7 @@