From b8a8574aa86e278582988f85f5cda9b63571df6d Mon Sep 17 00:00:00 2001 From: Morten Hjorth-Jensen Date: Sat, 27 Sep 2025 10:05:22 +0200 Subject: [PATCH] update week 40 --- doc/pub/week40/html/._week40-bs000.html | 219 +- doc/pub/week40/html/._week40-bs001.html | 220 +- doc/pub/week40/html/._week40-bs002.html | 219 +- doc/pub/week40/html/._week40-bs003.html | 225 +- doc/pub/week40/html/._week40-bs004.html | 310 ++- doc/pub/week40/html/._week40-bs005.html | 265 +- doc/pub/week40/html/._week40-bs006.html | 283 +-- doc/pub/week40/html/._week40-bs007.html | 256 +- doc/pub/week40/html/._week40-bs008.html | 263 +- doc/pub/week40/html/._week40-bs009.html | 251 +- doc/pub/week40/html/._week40-bs010.html | 294 +-- doc/pub/week40/html/._week40-bs011.html | 276 +- doc/pub/week40/html/._week40-bs012.html | 291 +-- doc/pub/week40/html/._week40-bs013.html | 294 +-- doc/pub/week40/html/._week40-bs014.html | 322 ++- doc/pub/week40/html/._week40-bs015.html | 306 +-- doc/pub/week40/html/._week40-bs016.html | 270 +- doc/pub/week40/html/._week40-bs017.html | 294 +-- doc/pub/week40/html/._week40-bs018.html | 299 +-- doc/pub/week40/html/._week40-bs019.html | 402 +-- doc/pub/week40/html/._week40-bs020.html | 305 +-- doc/pub/week40/html/._week40-bs021.html | 267 +- doc/pub/week40/html/._week40-bs022.html | 252 +- doc/pub/week40/html/._week40-bs023.html | 239 +- doc/pub/week40/html/._week40-bs024.html | 271 +- doc/pub/week40/html/._week40-bs025.html | 239 +- doc/pub/week40/html/._week40-bs026.html | 242 +- doc/pub/week40/html/._week40-bs027.html | 262 +- doc/pub/week40/html/._week40-bs028.html | 242 +- doc/pub/week40/html/._week40-bs029.html | 222 +- doc/pub/week40/html/._week40-bs030.html | 305 +-- doc/pub/week40/html/._week40-bs031.html | 274 +- doc/pub/week40/html/._week40-bs032.html | 253 +- doc/pub/week40/html/._week40-bs033.html | 262 +- doc/pub/week40/html/._week40-bs034.html | 278 +- doc/pub/week40/html/._week40-bs035.html | 261 +- doc/pub/week40/html/._week40-bs036.html | 298 +-- doc/pub/week40/html/._week40-bs037.html | 278 +- doc/pub/week40/html/._week40-bs038.html | 316 +-- doc/pub/week40/html/._week40-bs039.html | 300 +-- doc/pub/week40/html/._week40-bs040.html | 322 +-- doc/pub/week40/html/._week40-bs041.html | 316 +-- doc/pub/week40/html/._week40-bs042.html | 332 +-- doc/pub/week40/html/week40-bs.html | 219 +- doc/pub/week40/html/week40-reveal.html | 925 +------ doc/pub/week40/html/week40-solarized.html | 948 +------ doc/pub/week40/html/week40.html | 948 +------ doc/pub/week40/ipynb/ipynb-week40-src.tar.gz | Bin 526744 -> 34323 bytes doc/pub/week40/ipynb/week40.ipynb | 1987 ++++----------- doc/src/week40/Previousversions/week40.do.txt | 2259 +++++++++++++++++ doc/src/week40/week40.do.txt | 716 ------ 51 files changed, 6530 insertions(+), 13367 deletions(-) create mode 100644 doc/src/week40/Previousversions/week40.do.txt diff --git a/doc/pub/week40/html/._week40-bs000.html b/doc/pub/week40/html/._week40-bs000.html index e77b3a43b..9a3894e65 100644 --- a/doc/pub/week40/html/._week40-bs000.html +++ b/doc/pub/week40/html/._week40-bs000.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -369,18 +259,15 @@ MathJax.Hub.Config({
    -Morten Hjorth-Jensen [1, 2] +Morten Hjorth-Jensen
    - +
    -[1] Department of Physics, University of Oslo, Norway -
    -
    -[2] Department of Physics and Astronomy and Facility for Rare Ion Beams, Michigan State University, USA +Department of Physics, University of Oslo, Norway

    -

    September 30-October 4, 2024

    +

    September 29-October 3, 2025


    @@ -405,7 +292,7 @@ MathJax.Hub.Config({
  • 9
  • 10
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • @@ -419,7 +306,7 @@ MathJax.Hub.Config({ -->
    - © 1999-2024, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license + © 1999-2025, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license
    diff --git a/doc/pub/week40/html/._week40-bs001.html b/doc/pub/week40/html/._week40-bs001.html index c135404f4..89fa72667 100644 --- a/doc/pub/week40/html/._week40-bs001.html +++ b/doc/pub/week40/html/._week40-bs001.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,7 +252,19 @@ MathJax.Hub.Config({

     

     

     

    -

    Plans for week 40

    +

    Lecture Monday September 30, 2024

    +
    +
    + +
      +
    1. Stochastic Gradient descent with examples and automatic differentiation
    2. +
    3. If we get time, we start with the basics of Neural Networks, setting up the basic steps, from the simple perceptron model to the multi-layer perceptron model
    4. +
    5. Video of lecture
    6. +
    7. Whiteboard notes at https://github.com/CompPhysics/MachineLearning/blob/master/doc/HandWrittenNotes/2024/NotesSeptember30.pdf
    8. +
    +
    +
    +

    @@ -380,7 +282,7 @@ MathJax.Hub.Config({

  • 10
  • 11
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs002.html b/doc/pub/week40/html/._week40-bs002.html index ea218983a..c23ffe247 100644 --- a/doc/pub/week40/html/._week40-bs002.html +++ b/doc/pub/week40/html/._week40-bs002.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,15 +252,18 @@ MathJax.Hub.Config({

     

     

     

    -

    Lecture Monday September 30, 2024

    +

    Suggested readings and videos

      -
    1. Stochastic Gradient descent with examples and automatic differentiation
    2. -
    3. If we get time, we start with the basics of Neural Networks, setting up the basic steps, from the simple perceptron model to the multi-layer perceptron model
    4. -
    5. Video of lecture
    6. -
    7. Whiteboard notes at https://github.com/CompPhysics/MachineLearning/blob/master/doc/HandWrittenNotes/2024/NotesSeptember30.pdf
    8. +
    9. The lecture notes for week 40 (these notes)
    10. +
    11. For a good discussion on gradient methods, we would like to recommend Goodfellow et al section 4.3-4.5 and sections 8.3-8.6. We will come back to the latter chapter in our discussion of Neural networks as well.
    12. +
    13. For neural networks we recommend Goodfellow et al chapter 6 and Raschka et al chapter 2 (contains also material about gradient descent) and chapter 11 (we will use this next week)
    14. +
    15. Video on gradient descent at https://www.youtube.com/watch?v=sDv4f4s2SB8
    16. +
    17. Video on stochastic gradient descent at https://www.youtube.com/watch?v=vMh0zPT0tLI
    18. +
    19. Neural Networks demystified at https://www.youtube.com/watch?v=bxe2T-V8XRs&list=PLiaHhY2iBX9hdHaRr6b7XevZtgZRa1PoU&ab_channel=WelchLabs
    20. +
    21. Building Neural Networks from scratch at URL:https://www.youtube.com/watch?v=Wo5dMEP_BbI&list=PLQVvvaa0QuDcjD5BAw2DxE6OF2tius3V3&ab_channel=sentdex"
    @@ -393,7 +286,7 @@ MathJax.Hub.Config({
  • 11
  • 12
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs003.html b/doc/pub/week40/html/._week40-bs003.html index c93b19017..76419a7bc 100644 --- a/doc/pub/week40/html/._week40-bs003.html +++ b/doc/pub/week40/html/._week40-bs003.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,22 +252,19 @@ MathJax.Hub.Config({

     

     

     

    -

    Suggested readings and videos

    +

    Lab sessions Tuesday and Wednesday

    -
      -
    1. The lecture notes for week 40 (these notes)
    2. -
    3. For a good discussion on gradient methods, we would like to recommend Goodfellow et al section 4.3-4.5 and sections 8.3-8.6. We will come back to the latter chapter in our discussion of Neural networks as well.
    4. -
    5. For neural networks we recommend Goodfellow et al chapter 6 and Raschka et al chapter 2 (contains also material about gradient descent) and chapter 11 (we will use this next week)
    6. -
    7. Video on gradient descent at https://www.youtube.com/watch?v=sDv4f4s2SB8
    8. -
    9. Video on stochastic gradient descent at https://www.youtube.com/watch?v=vMh0zPT0tLI
    10. -
    11. Neural Networks demystified at https://www.youtube.com/watch?v=bxe2T-V8XRs&list=PLiaHhY2iBX9hdHaRr6b7XevZtgZRa1PoU&ab_channel=WelchLabs
    12. -
    13. Building Neural Networks from scratch at URL:https://www.youtube.com/watch?v=Wo5dMEP_BbI&list=PLQVvvaa0QuDcjD5BAw2DxE6OF2tius3V3&ab_channel=sentdex"
    14. -
    +
    - +

    @@ -397,7 +284,7 @@ MathJax.Hub.Config({

  • 12
  • 13
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs004.html b/doc/pub/week40/html/._week40-bs004.html index 2c637fbc2..394b532fe 100644 --- a/doc/pub/week40/html/._week40-bs004.html +++ b/doc/pub/week40/html/._week40-bs004.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,19 +252,105 @@ MathJax.Hub.Config({

     

     

     

    -

    Lab sessions Tuesday and Wednesday

    -
    -
    - +

    Automatic differentiation

    + +

    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 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 +

    +$$ +f(x) = \sin\left(2\pi x + x^2\right) +$$ + +

    which has the following derivative

    +$$ +f'(x) = \cos\left(2\pi x + x^2\right)\left(2\pi + 2x\right) +$$ + +

    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))))
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    - +

    @@ -395,7 +371,7 @@ MathJax.Hub.Config({

  • 13
  • 14
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs005.html b/doc/pub/week40/html/._week40-bs005.html index a2408701c..cf8e76e1a 100644 --- a/doc/pub/week40/html/._week40-bs005.html +++ b/doc/pub/week40/html/._week40-bs005.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -361,17 +251,56 @@ MathJax.Hub.Config({

     

     

     

    - -

    Summary from last week, using gradient descent methods, limitations

    + +

    Using autograd

    + +

    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))
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + -
      -
    • 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.
    • -
    • Gradients are computationally expensive to calculate for large datasets. In many cases in statistics and ML, the cost/loss/risk function is a sum of terms, with one term for each data point. For example, in linear regression, \( E \propto \sum_{i=1}^n (y_i - \mathbf{w}^T\cdot\mathbf{x}_i)^2 \); for logistic regression, the square error is replaced by the cross entropy. To calculate the gradient we have to sum over all \( n \) data points. Doing this at every GD step becomes extremely computationally expensive. An ingenious solution to this, is to calculate the gradients using small subsets of the data called "mini batches". This has the added benefit of introducing stochasticity into our algorithm.
    • -
    • GD is very sensitive to choices of learning rates. GD is extremely sensitive to the choice of learning rates. If the learning rate is very small, the training process take an extremely long time. For larger learning rates, GD can diverge and give poor results. Furthermore, depending on what the local landscape looks like, we have to modify the learning rates to ensure convergence. Ideally, we would adaptively choose the learning rates to match the landscape.
    • -
    • GD treats all directions in parameter space uniformly. Another major drawback of GD is that unlike Newton's method, the learning rate for GD is the same in all directions in parameter space. For this reason, the maximum learning rate is set by the behavior of the steepest direction and this can significantly slow down training. Ideally, we would like to take large steps in flat directions and small steps in steep directions. Since we are exploring rugged landscapes where curvatures change, this requires us to keep track of not only the gradient but second derivatives. The ideal scenario would be to calculate the Hessian but this proves to be too computationally expensive.
    • -
    • GD can take exponential time to escape saddle points, even with random initialization. As we mentioned, GD is extremely sensitive to initial condition since it determines the particular local minimum GD would eventually reach. However, even with a good initialization scheme, through the introduction of randomness, GD can still take exponential time to escape saddle points.
    • -

      @@ -392,7 +321,7 @@ MathJax.Hub.Config({
    • 14
    • 15
    • ...
    • -
    • 69
    • +
    • 43
    • »
    diff --git a/doc/pub/week40/html/._week40-bs006.html b/doc/pub/week40/html/._week40-bs006.html index 7379dc348..498e75324 100644 --- a/doc/pub/week40/html/._week40-bs006.html +++ b/doc/pub/week40/html/._week40-bs006.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,61 +252,53 @@ MathJax.Hub.Config({

     

     

     

    -

    Simple implementation of GD for OLS, Ridge and Lasso

    +

    Autograd with more complicated functions

    -

    Last week we studied both several gradient methods. With and without an update of the learning. -We summarize some of these here for the methods we hvae studied in project one, without the inclusion of momentum. +

    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.

    +
    -
    from random import random, seed
    -import numpy as np
    +  
    import autograd.numpy as np
    +from autograd import grad
    +def f2(x1,x2):
    +    return 3*x1**3 + x2*(x1 - 5) + 1
     
    -# the number of datapoints with a 2nd-order polynomial
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+5*x*x
    -# Design matrix including the intercept
    -# No scaling of data of and all data used for training 
    -X = np.c_[np.ones((n,1)), x, x*x]
    -# Learning rate and number of iterations
    -eta = 0.05
    -Niterations = 100
    +# 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)
     
    -# OLS part
    -beta_OLS = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradient = (2.0/n)*X.T @ (X @ beta_OLS-y)
    -    beta_OLS -= eta*gradient
    -print('Parameters for OLS using gradient descent')    
    -print(beta_OLS)
    +# ... and differentiate w.r.t x2 by sending 1 as an additional arugment to grad
    +f2_grad_x2 = grad(f2,1)
     
    -#Ridge and Lasso parameter Lambda
    -Lambda  = 0.01
    -Id = n*Lambda* np.eye((X.T @ X).shape[0])
    -# Gradient descent with  Ridge
    -beta_Ridge = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ (X @ beta_Ridge-y)+2*Lambda*beta_Ridge
    -    beta_Ridge -= eta*gradients
    -print('Parameters for Ridge using gradient descent')    
    -print(beta_Ridge)
    +x1 = 1.0
    +x2 = 3.0 
     
    -# Gradient descent with Lasso
    -beta_Lasso = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ (X @ beta_Lasso-y)+Lambda*np.sign(beta_Lasso)
    -    beta_Lasso -= eta*gradients
    -print('Parameters for Lasso using gradient descent')    
    -print(beta_Lasso)
    +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) ))
     
    @@ -432,6 +314,7 @@ gradient = np.<
    +

    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.

    @@ -454,7 +337,7 @@ gradient = np.<

  • 15
  • 16
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs007.html b/doc/pub/week40/html/._week40-bs007.html index 191de7c21..b20c1c5c8 100644 --- a/doc/pub/week40/html/._week40-bs007.html +++ b/doc/pub/week40/html/._week40-bs007.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,9 +252,8 @@ MathJax.Hub.Config({

     

     

     

    -

    But none of these can compete with Newton's method

    +

    More complicated functions using the elements of their arguments directly

    -

    Note that we here have introduced automatic differentiation

    @@ -372,39 +261,23 @@ MathJax.Hub.Config({
    -
    # Using Newton's method
    -from random import random, seed
    -import numpy as np
    -import autograd.numpy as np
    +  
    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
     
    -def CostOLS(beta):
    -    return (1.0/n)*np.sum((y-X @ beta)**2)
    +f3_grad = grad(f3)
     
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+5*x*x
    +x = np.linspace(0,4,5)
     
    -X = np.c_[np.ones((n,1)), x, x*x]
    -XT_X = X.T @ X
    -beta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    -print("Own inversion")
    -print(beta_linreg)
    -# Hessian matrix
    -H = (2.0/n)* XT_X
    -# Note that here the Hessian does not depend on the parameters beta
    -invH = np.linalg.pinv(H)
    -beta = np.random.randn(3,1)
    -Niterations = 5
    -# define the gradient
    -training_gradient = grad(CostOLS)
    +# Print the computed gradient:
    +print("The computed gradient of f3 is: ", f3_grad(x))
     
    -for iter in range(Niterations):
    -    gradients = training_gradient(beta)
    -    beta -= invH @ gradients
    -    print(iter,gradients[0],gradients[1])
    -print("beta from own Newton code")
    -print(beta)
    +# 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)
     
    @@ -420,6 +293,13 @@ training_gradient = grad(CostOLS)
    +

    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. +

    @@ -443,7 +323,7 @@ training_gradient = grad(CostOLS)

  • 16
  • 17
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs008.html b/doc/pub/week40/html/._week40-bs008.html index 05c8af889..17f5df4f9 100644 --- a/doc/pub/week40/html/._week40-bs008.html +++ b/doc/pub/week40/html/._week40-bs008.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -361,13 +251,8 @@ MathJax.Hub.Config({

     

     

     

    - -

    Gradient descent and Logistic regression

    - -

    Finally, we complete these examples by adding a simple code for -Logistic regression. Note the more general approach with a class for -the method. Here we use a so-called AND gate for our data set. -

    + +

    Functions using mathematical functions from Numpy

    @@ -376,37 +261,23 @@ the method. Here we use a so-called AND gate for our data set.
    -
    import numpy as np
    -class LogisticRegression:
    -    def __init__(self, learning_rate=0.01, num_iterations=1000):
    -        self.learning_rate = learning_rate
    -        self.num_iterations = num_iterations
    -        self.beta_logreg = None
    -    def sigmoid(self, z):
    -        return 1 / (1 + np.exp(-z))
    -    def GDfit(self, X, y):
    -        n_data, num_features = X.shape
    -        self.beta_logreg = np.zeros(num_features)
    -        for _ in range(self.num_iterations):
    -            linear_model = X @ self.beta_logreg
    -            y_predicted = self.sigmoid(linear_model)
    -            # Gradient calculation
    -            gradient = (X.T @ (y_predicted - y))/n_data
    -            # Update beta_logreg
    -            self.beta_logreg -= self.learning_rate*gradient
    -    def predict(self, X):
    -        linear_model = X @ self.beta_logreg
    -        y_predicted = self.sigmoid(linear_model)
    -        return [1 if i >= 0.5 else 0 for i in y_predicted]
    -# Example usage
    -if __name__ == "__main__":
    -    # Sample data
    -    X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
    -    y = np.array([0, 0, 0, 1])  # This is an AND gate
    -    model = LogisticRegression(learning_rate=0.01, num_iterations=1000)
    -    model.GDfit(X, y)
    -    predictions = model.predict(X)
    -    print("Predictions:", predictions)
    +  
    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))
     
    @@ -446,7 +317,7 @@ the method. Here we use a so-called AND gate for our data set.
  • 17
  • 18
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs009.html b/doc/pub/week40/html/._week40-bs009.html index 09e3cf44d..b628f5424 100644 --- a/doc/pub/week40/html/._week40-bs009.html +++ b/doc/pub/week40/html/._week40-bs009.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,16 +252,45 @@ MathJax.Hub.Config({

     

     

     

    -

    Overview video on Stochastic Gradient Descent

    +

    More autograd

    + + + +
    +
    +
    +
    +
    +
    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)))
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    -What is Stochastic Gradient Descent -

    There are several reasons for using stochastic gradient descent. Some of these are:

    -
      -
    1. Efficiency: Updates weights more frequently using a single or a small batch of samples, which speeds up convergence.
    2. -
    3. Hopefully avoid Local Minima
    4. -
    5. Memory Usage: Requires less memory compared to computing gradients for the entire dataset.
    6. -

      @@ -396,7 +315,7 @@ MathJax.Hub.Config({
    • 18
    • 19
    • ...
    • -
    • 69
    • +
    • 43
    • »
    diff --git a/doc/pub/week40/html/._week40-bs010.html b/doc/pub/week40/html/._week40-bs010.html index 447208763..1fd914383 100644 --- a/doc/pub/week40/html/._week40-bs010.html +++ b/doc/pub/week40/html/._week40-bs010.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,19 +252,85 @@ MathJax.Hub.Config({

     

     

     

    -

    Batches and mini-batches

    +

    And with loops

    -

    In gradient descent we compute the cost function and its gradient for all data points we have.

    -

    In large-scale applications such as the ILSVRC challenge, the -training data can have on order of millions of examples. Hence, it -seems wasteful to compute the full cost function over the entire -training set in order to perform only a single parameter update. A -very common approach to addressing this challenge is to compute the -gradient over batches of the training data. For example, a typical batch could contain some thousand examples from -an entire training set of several millions. This batch is then used to -perform a parameter update. -

    + +
    +
    +
    +
    +
    +
    import autograd.numpy as np
    +from autograd import grad
    +def f6_for(x):
    +    val = 0
    +    for i in range(10):
    +        val = val + x**i
    +    return val
    +
    +def f6_while(x):
    +    val = 0
    +    i = 0
    +    while i < 10:
    +        val = val + x**i
    +        i = i + 1
    +    return val
    +
    +f6_for_grad = grad(f6_for)
    +f6_while_grad = grad(f6_while)
    +
    +x = 0.5
    +
    +# Print the computed derivaties of f6_for and f6_while
    +print("The computed derivative of f6_for at x = %g is: %g"%(x,f6_for_grad(x)))
    +print("The computed derivative of f6_while at x = %g is: %g"%(x,f6_while_grad(x)))
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    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))
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @@ -401,7 +357,7 @@ perform a parameter update.

  • 19
  • 20
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs011.html b/doc/pub/week40/html/._week40-bs011.html index 71aee4fdb..0e9cecec8 100644 --- a/doc/pub/week40/html/._week40-bs011.html +++ b/doc/pub/week40/html/._week40-bs011.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,31 +252,57 @@ MathJax.Hub.Config({

     

     

     

    -

    Stochastic Gradient Descent (SGD)

    +

    Using recursion

    -

    In stochastic gradient descent, the extreme case is the case where we -have only one batch, that is we include the whole data set. -

    + +
    +
    +
    +
    +
    +
    import autograd.numpy as np
    +from autograd import grad
     
    -

    This process is called Stochastic Gradient -Descent (SGD) (or also sometimes on-line gradient descent). This is -relatively less common to see because in practice due to vectorized -code optimizations it can be computationally much more efficient to -evaluate the gradient for 100 examples, than the gradient for one -example 100 times. Even though SGD technically refers to using a -single example at a time to evaluate the gradient, you will hear -people use the term SGD even when referring to mini-batch gradient -descent (i.e. mentions of MGD for “Minibatch Gradient Descent”, or BGD -for “Batch gradient descent” are rare to see), where it is usually -assumed that mini-batches are used. The size of the mini-batch is a -hyperparameter but it is not very common to cross-validate or bootstrap it. It is -usually based on memory constraints (if any), or set to some value, -e.g. 32, 64 or 128. We use powers of 2 in practice because many -vectorized operation implementations work faster when their inputs are -sized in powers of 2. -

    +def f7(n): # Assume that n is an integer + if n == 1 or n == 0: + return 1 + else: + return n*f7(n-1) -

    In our notes with SGD we mean stochastic gradient descent with mini-batches.

    +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.

    @@ -413,7 +329,7 @@ sized in powers of 2.

  • 20
  • 21
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs012.html b/doc/pub/week40/html/._week40-bs012.html index a9f7f40ba..ead624155 100644 --- a/doc/pub/week40/html/._week40-bs012.html +++ b/doc/pub/week40/html/._week40-bs012.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,20 +252,83 @@ MathJax.Hub.Config({

     

     

     

    -

    Stochastic Gradient Descent

    +

    Using Autograd with OLS

    -

    Stochastic gradient descent (SGD) and variants thereof address some of -the shortcomings of the Gradient descent method discussed above. +

    We conclude the part on optmization by showing how we can make codes +for linear regression and logistic regression using autograd. The +first example shows results with ordinary leats squares.

    -

    The underlying idea of SGD comes from the observation that the cost -function, which we want to minimize, can almost always be written as a -sum over \( n \) data points \( \{\mathbf{x}_i\}_{i=1}^n \), -

    -$$ -C(\mathbf{\beta}) = \sum_{i=1}^n c_i(\mathbf{x}_i, -\mathbf{\beta}). -$$ + + +
    +
    +
    +
    +
    +
    # Using Autograd to calculate gradients for OLS
    +from random import random, seed
    +import numpy as np
    +import autograd.numpy as np
    +import matplotlib.pyplot as plt
    +from autograd import grad
    +
    +def CostOLS(beta):
    +    return (1.0/n)*np.sum((y-X @ beta)**2)
    +
    +n = 100
    +x = 2*np.random.rand(n,1)
    +y = 4+3*x+np.random.randn(n,1)
    +
    +X = np.c_[np.ones((n,1)), x]
    +XT_X = X.T @ X
    +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    +print("Own inversion")
    +print(theta_linreg)
    +# Hessian matrix
    +H = (2.0/n)* XT_X
    +EigValues, EigVectors = np.linalg.eig(H)
    +print(f"Eigenvalues of Hessian Matrix:{EigValues}")
    +
    +theta = np.random.randn(2,1)
    +eta = 1.0/np.max(EigValues)
    +Niterations = 1000
    +# define the gradient
    +training_gradient = grad(CostOLS)
    +
    +for iter in range(Niterations):
    +    gradients = training_gradient(theta)
    +    theta -= eta*gradients
    +print("theta from own gd")
    +print(theta)
    +
    +xnew = np.array([[0],[2]])
    +Xnew = np.c_[np.ones((2,1)), xnew]
    +ypredict = Xnew.dot(theta)
    +ypredict2 = Xnew.dot(theta_linreg)
    +
    +plt.plot(xnew, ypredict, "r-")
    +plt.plot(xnew, ypredict2, "b-")
    +plt.plot(x, y ,'ro')
    +plt.axis([0,2.0,0, 15.0])
    +plt.xlabel(r'$x$')
    +plt.ylabel(r'$y$')
    +plt.title(r'Random numbers ')
    +plt.show()
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @@ -403,7 +356,7 @@ $$

  • 21
  • 22
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs013.html b/doc/pub/week40/html/._week40-bs013.html index 98b9d5ccf..14ff6d61c 100644 --- a/doc/pub/week40/html/._week40-bs013.html +++ b/doc/pub/week40/html/._week40-bs013.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,22 +252,82 @@ MathJax.Hub.Config({

     

     

     

    -

    Computation of gradients

    +

    Same code but now with momentum gradient descent

    -

    This in turn means that the gradient can be -computed as a sum over \( i \)-gradients -

    -$$ -\nabla_\beta C(\mathbf{\beta}) = \sum_i^n \nabla_\beta c_i(\mathbf{x}_i, -\mathbf{\beta}). -$$ + +
    +
    +
    +
    +
    +
    # Using Autograd to calculate gradients for OLS
    +from random import random, seed
    +import numpy as np
    +import autograd.numpy as np
    +import matplotlib.pyplot as plt
    +from autograd import grad
    +
    +def CostOLS(beta):
    +    return (1.0/n)*np.sum((y-X @ beta)**2)
    +
    +n = 100
    +x = 2*np.random.rand(n,1)
    +y = 4+3*x#+np.random.randn(n,1)
    +
    +X = np.c_[np.ones((n,1)), x]
    +XT_X = X.T @ X
    +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    +print("Own inversion")
    +print(theta_linreg)
    +# Hessian matrix
    +H = (2.0/n)* XT_X
    +EigValues, EigVectors = np.linalg.eig(H)
    +print(f"Eigenvalues of Hessian Matrix:{EigValues}")
    +
    +theta = np.random.randn(2,1)
    +eta = 1.0/np.max(EigValues)
    +Niterations = 30
    +
    +# define the gradient
    +training_gradient = grad(CostOLS)
    +
    +for iter in range(Niterations):
    +    gradients = training_gradient(theta)
    +    theta -= eta*gradients
    +    print(iter,gradients[0],gradients[1])
    +print("theta from own gd")
    +print(theta)
    +
    +# Now improve with momentum gradient descent
    +change = 0.0
    +delta_momentum = 0.3
    +for iter in range(Niterations):
    +    # calculate gradient
    +    gradients = training_gradient(theta)
    +    # calculate update
    +    new_change = eta*gradients+delta_momentum*change
    +    # take a step
    +    theta -= new_change
    +    # save the change
    +    change = new_change
    +    print(iter,gradients[0],gradients[1])
    +print("theta from own gd wth momentum")
    +print(theta)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    -

    Stochasticity/randomness is introduced by only taking the -gradient on a subset of the data called minibatches. If there are \( n \) -data points and the size of each minibatch is \( M \), there will be \( n/M \) -minibatches. We denote these minibatches by \( B_k \) where -\( k=1,\cdots,n/M \). -

    @@ -404,7 +354,7 @@ minibatches. We denote these minibatches by \( B_k \) where

  • 22
  • 23
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs014.html b/doc/pub/week40/html/._week40-bs014.html index a59e64516..a32f28575 100644 --- a/doc/pub/week40/html/._week40-bs014.html +++ b/doc/pub/week40/html/._week40-bs014.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,27 +252,103 @@ MathJax.Hub.Config({

     

     

     

    -

    SGD example

    -

    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 -\( B_1 = (\mathbf{x}_1,\mathbf{x}_2), \cdots, B_5 = -(\mathbf{x}_9,\mathbf{x}_{10}) \). Note that if you choose \( M=1 \) you -have only a single batch with all data points and on the other extreme, -you may choose \( M=n \) resulting in a minibatch for each datapoint, i.e -\( B_k = \mathbf{x}_k \). -

    +

    Including Stochastic Gradient Descent with Autograd

    +

    In this code we include the stochastic gradient descent approach discussed above. Note here that we specify which argument we are taking the derivative with respect to when using autograd.

    -

    The idea is now to approximate the gradient by replacing the sum over -all data points with a sum over the data points in one the minibatches -picked at random in each gradient descent step -

    -$$ -\nabla_{\beta} -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}). -$$ + + +
    +
    +
    +
    +
    +
    # Using Autograd to calculate gradients using SGD
    +# OLS example
    +from random import random, seed
    +import numpy as np
    +import autograd.numpy as np
    +import matplotlib.pyplot as plt
    +from autograd import grad
    +
    +# Note change from previous example
    +def CostOLS(y,X,theta):
    +    return np.sum((y-X @ theta)**2)
    +
    +n = 100
    +x = 2*np.random.rand(n,1)
    +y = 4+3*x+np.random.randn(n,1)
    +
    +X = np.c_[np.ones((n,1)), x]
    +XT_X = X.T @ X
    +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    +print("Own inversion")
    +print(theta_linreg)
    +# Hessian matrix
    +H = (2.0/n)* XT_X
    +EigValues, EigVectors = np.linalg.eig(H)
    +print(f"Eigenvalues of Hessian Matrix:{EigValues}")
    +
    +theta = np.random.randn(2,1)
    +eta = 1.0/np.max(EigValues)
    +Niterations = 1000
    +
    +# Note that we request the derivative wrt third argument (theta, 2 here)
    +training_gradient = grad(CostOLS,2)
    +
    +for iter in range(Niterations):
    +    gradients = (1.0/n)*training_gradient(y, X, theta)
    +    theta -= eta*gradients
    +print("theta from own gd")
    +print(theta)
    +
    +xnew = np.array([[0],[2]])
    +Xnew = np.c_[np.ones((2,1)), xnew]
    +ypredict = Xnew.dot(theta)
    +ypredict2 = Xnew.dot(theta_linreg)
    +
    +plt.plot(xnew, ypredict, "r-")
    +plt.plot(xnew, ypredict2, "b-")
    +plt.plot(x, y ,'ro')
    +plt.axis([0,2.0,0, 15.0])
    +plt.xlabel(r'$x$')
    +plt.ylabel(r'$y$')
    +plt.title(r'Random numbers ')
    +plt.show()
    +
    +n_epochs = 50
    +M = 5   #size of each minibatch
    +m = int(n/M) #number of minibatches
    +t0, t1 = 5, 50
    +def learning_schedule(t):
    +    return t0/(t+t1)
    +
    +theta = np.random.randn(2,1)
    +
    +for epoch in range(n_epochs):
    +# Can you figure out a better way of setting up the contributions to each batch?
    +    for i in range(m):
    +        random_index = M*np.random.randint(m)
    +        xi = X[random_index:random_index+M]
    +        yi = y[random_index:random_index+M]
    +        gradients = (1.0/M)*training_gradient(yi, xi, theta)
    +        eta = learning_schedule(epoch*m+i)
    +        theta = theta - eta*gradients
    +print("theta from own sdg")
    +print(theta)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @@ -410,7 +376,7 @@ $$

  • 23
  • 24
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs015.html b/doc/pub/week40/html/._week40-bs015.html index 807703ac2..bb6680274 100644 --- a/doc/pub/week40/html/._week40-bs015.html +++ b/doc/pub/week40/html/._week40-bs015.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,20 +252,96 @@ MathJax.Hub.Config({

     

     

     

    -

    The gradient step

    +

    Same code but now with momentum gradient descent

    -

    Thus a gradient descent step now looks like

    -$$ -\beta_{j+1} = \beta_j - \gamma_j \sum_{i \in B_k}^n \nabla_\beta c_i(\mathbf{x}_i, -\mathbf{\beta}) -$$ + +
    +
    +
    +
    +
    +
    # Using Autograd to calculate gradients using SGD
    +# OLS example
    +from random import random, seed
    +import numpy as np
    +import autograd.numpy as np
    +import matplotlib.pyplot as plt
    +from autograd import grad
    +
    +# Note change from previous example
    +def CostOLS(y,X,theta):
    +    return np.sum((y-X @ theta)**2)
    +
    +n = 100
    +x = 2*np.random.rand(n,1)
    +y = 4+3*x+np.random.randn(n,1)
    +
    +X = np.c_[np.ones((n,1)), x]
    +XT_X = X.T @ X
    +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    +print("Own inversion")
    +print(theta_linreg)
    +# Hessian matrix
    +H = (2.0/n)* XT_X
    +EigValues, EigVectors = np.linalg.eig(H)
    +print(f"Eigenvalues of Hessian Matrix:{EigValues}")
    +
    +theta = np.random.randn(2,1)
    +eta = 1.0/np.max(EigValues)
    +Niterations = 100
    +
    +# Note that we request the derivative wrt third argument (theta, 2 here)
    +training_gradient = grad(CostOLS,2)
    +
    +for iter in range(Niterations):
    +    gradients = (1.0/n)*training_gradient(y, X, theta)
    +    theta -= eta*gradients
    +print("theta from own gd")
    +print(theta)
    +
    +
    +n_epochs = 50
    +M = 5   #size of each minibatch
    +m = int(n/M) #number of minibatches
    +t0, t1 = 5, 50
    +def learning_schedule(t):
    +    return t0/(t+t1)
    +
    +theta = np.random.randn(2,1)
    +
    +change = 0.0
    +delta_momentum = 0.3
    +
    +for epoch in range(n_epochs):
    +    for i in range(m):
    +        random_index = M*np.random.randint(m)
    +        xi = X[random_index:random_index+M]
    +        yi = y[random_index:random_index+M]
    +        gradients = (1.0/M)*training_gradient(yi, xi, theta)
    +        eta = learning_schedule(epoch*m+i)
    +        # calculate update
    +        new_change = eta*gradients+delta_momentum*change
    +        # take a step
    +        theta -= new_change
    +        # save the change
    +        change = new_change
    +print("theta from own sdg with momentum")
    +print(theta)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    -

    where \( k \) is picked at random with equal -probability from \( [1,n/M] \). An iteration over the number of -minibathces (n/M) is commonly referred to as an epoch. Thus it is -typical to choose a number of epochs and for each epoch iterate over -the number of minibatches, as exemplified in the code below. -

    @@ -402,7 +368,7 @@ the number of minibatches, as exemplified in the code below.

  • 24
  • 25
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs016.html b/doc/pub/week40/html/._week40-bs016.html index aa516eb92..77fc52023 100644 --- a/doc/pub/week40/html/._week40-bs016.html +++ b/doc/pub/week40/html/._week40-bs016.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,8 +252,7 @@ MathJax.Hub.Config({

     

     

     

    -

    Simple example code

    - +

    Similar (second order function now) problem but now with AdaGrad

    @@ -371,20 +260,54 @@ MathJax.Hub.Config({
    -
    import numpy as np 
    +  
    # Using Autograd to calculate gradients using AdaGrad and Stochastic Gradient descent
    +# OLS example
    +from random import random, seed
    +import numpy as np
    +import autograd.numpy as np
    +import matplotlib.pyplot as plt
    +from autograd import grad
     
    -n = 100 #100 datapoints 
    +# Note change from previous example
    +def CostOLS(y,X,theta):
    +    return np.sum((y-X @ theta)**2)
    +
    +n = 1000
    +x = np.random.rand(n,1)
    +y = 2.0+3*x +4*x*x
    +
    +X = np.c_[np.ones((n,1)), x, x*x]
    +XT_X = X.T @ X
    +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    +print("Own inversion")
    +print(theta_linreg)
    +
    +
    +# Note that we request the derivative wrt third argument (theta, 2 here)
    +training_gradient = grad(CostOLS,2)
    +# Define parameters for Stochastic Gradient Descent
    +n_epochs = 50
     M = 5   #size of each minibatch
     m = int(n/M) #number of minibatches
    -n_epochs = 10 #number of epochs
    +# Guess for unknown parameters theta
    +theta = np.random.randn(3,1)
     
    -j = 0
    -for epoch in range(1,n_epochs+1):
    +# Value for learning rate
    +eta = 0.01
    +# Including AdaGrad parameter to avoid possible division by zero
    +delta  = 1e-8
    +for epoch in range(n_epochs):
    +    Giter = 0.0
         for i in range(m):
    -        k = np.random.randint(m) #Pick the k-th minibatch at random
    -        #Compute the gradient using the data in minibatch Bk
    -        #Compute new suggestion for 
    -        j += 1
    +        random_index = M*np.random.randint(m)
    +        xi = X[random_index:random_index+M]
    +        yi = y[random_index:random_index+M]
    +        gradients = (1.0/M)*training_gradient(yi, xi, theta)
    +        Giter += gradients*gradients
    +        update = gradients*eta/(delta+np.sqrt(Giter))
    +        theta -= update
    +print("theta from own AdaGrad")
    +print(theta)
     
    @@ -400,14 +323,7 @@ j = 0
    -

    Taking the gradient only on a subset of the data has two important -benefits. First, it introduces randomness which decreases the chance -that our opmization scheme gets stuck in a local minima. Second, if -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. -

    +

    Running this code we note an almost perfect agreement with the results from matrix inversion.

    @@ -434,7 +350,7 @@ all \( n \) datapoints.

  • 25
  • 26
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs017.html b/doc/pub/week40/html/._week40-bs017.html index c9734f413..bc8073132 100644 --- a/doc/pub/week40/html/._week40-bs017.html +++ b/doc/pub/week40/html/._week40-bs017.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,19 +252,83 @@ MathJax.Hub.Config({

     

     

     

    -

    When do we stop?

    +

    RMSprop for adaptive learning rate with Stochastic Gradient Descent

    + + +
    +
    +
    +
    +
    +
    # Using Autograd to calculate gradients using RMSprop  and Stochastic Gradient descent
    +# OLS example
    +from random import random, seed
    +import numpy as np
    +import autograd.numpy as np
    +import matplotlib.pyplot as plt
    +from autograd import grad
    +
    +# Note change from previous example
    +def CostOLS(y,X,theta):
    +    return np.sum((y-X @ theta)**2)
    +
    +n = 1000
    +x = np.random.rand(n,1)
    +y = 2.0+3*x +4*x*x# +np.random.randn(n,1)
    +
    +X = np.c_[np.ones((n,1)), x, x*x]
    +XT_X = X.T @ X
    +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    +print("Own inversion")
    +print(theta_linreg)
    +
    +
    +# Note that we request the derivative wrt third argument (theta, 2 here)
    +training_gradient = grad(CostOLS,2)
    +# Define parameters for Stochastic Gradient Descent
    +n_epochs = 50
    +M = 5   #size of each minibatch
    +m = int(n/M) #number of minibatches
    +# Guess for unknown parameters theta
    +theta = np.random.randn(3,1)
    +
    +# Value for learning rate
    +eta = 0.01
    +# Value for parameter rho
    +rho = 0.99
    +# Including AdaGrad parameter to avoid possible division by zero
    +delta  = 1e-8
    +for epoch in range(n_epochs):
    +    Giter = 0.0
    +    for i in range(m):
    +        random_index = M*np.random.randint(m)
    +        xi = X[random_index:random_index+M]
    +        yi = y[random_index:random_index+M]
    +        gradients = (1.0/M)*training_gradient(yi, xi, theta)
    +	# Accumulated gradient
    +	# Scaling with rho the new and the previous results
    +        Giter = (rho*Giter+(1-rho)*gradients*gradients)
    +	# Taking the diagonal only and inverting
    +        update = gradients*eta/(delta+np.sqrt(Giter))
    +	# Hadamard product
    +        theta -= update
    +print("theta from own RMSprop")
    +print(theta)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    -

    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 -threshold and stop if true. However, the condition that the gradient -is zero is valid also for local minima, so this would only tell us -that we are close to a local/global minimum. However, we could also -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. -

    @@ -401,7 +355,7 @@ gave the lowest value.

  • 26
  • 27
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs018.html b/doc/pub/week40/html/._week40-bs018.html index a6e7c620e..fcd18c1a7 100644 --- a/doc/pub/week40/html/._week40-bs018.html +++ b/doc/pub/week40/html/._week40-bs018.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,18 +252,89 @@ MathJax.Hub.Config({

     

     

     

    -

    Slightly different approach

    +

    And finally ADAM

    + + + +
    +
    +
    +
    +
    +
    # Using Autograd to calculate gradients using RMSprop  and Stochastic Gradient descent
    +# OLS example
    +from random import random, seed
    +import numpy as np
    +import autograd.numpy as np
    +import matplotlib.pyplot as plt
    +from autograd import grad
    +
    +# Note change from previous example
    +def CostOLS(y,X,theta):
    +    return np.sum((y-X @ theta)**2)
    +
    +n = 1000
    +x = np.random.rand(n,1)
    +y = 2.0+3*x +4*x*x# +np.random.randn(n,1)
    +
    +X = np.c_[np.ones((n,1)), x, x*x]
    +XT_X = X.T @ X
    +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    +print("Own inversion")
    +print(theta_linreg)
    +
    +
    +# Note that we request the derivative wrt third argument (theta, 2 here)
    +training_gradient = grad(CostOLS,2)
    +# Define parameters for Stochastic Gradient Descent
    +n_epochs = 50
    +M = 5   #size of each minibatch
    +m = int(n/M) #number of minibatches
    +# Guess for unknown parameters theta
    +theta = np.random.randn(3,1)
    +
    +# Value for learning rate
    +eta = 0.01
    +# Value for parameters beta1 and beta2, see https://arxiv.org/abs/1412.6980
    +beta1 = 0.9
    +beta2 = 0.999
    +# Including AdaGrad parameter to avoid possible division by zero
    +delta  = 1e-7
    +iter = 0
    +for epoch in range(n_epochs):
    +    first_moment = 0.0
    +    second_moment = 0.0
    +    iter += 1
    +    for i in range(m):
    +        random_index = M*np.random.randint(m)
    +        xi = X[random_index:random_index+M]
    +        yi = y[random_index:random_index+M]
    +        gradients = (1.0/M)*training_gradient(yi, xi, theta)
    +        # Computing moments first
    +        first_moment = beta1*first_moment + (1-beta1)*gradients
    +        second_moment = beta2*second_moment+(1-beta2)*gradients*gradients
    +        first_term = first_moment/(1.0-beta1**iter)
    +        second_term = second_moment/(1.0-beta2**iter)
    +	# Scaling with rho the new and the previous results
    +        update = eta*first_term/(np.sqrt(second_term)+delta)
    +        theta -= update
    +print("theta from own ADAM")
    +print(theta)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    -

    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. Such approaches are -also called scaling. There are many such ways to scale the learning -rate -and discussions here. See -also -https://towardsdatascience.com/learning-rate-schedules-and-adaptive-learning-rate-methods-for-deep-learning-2c8f433990d1 -for a discussion of different scaling functions for the learning rate. -

    @@ -400,7 +361,7 @@ for a discussion of different scaling functions for the learning rate.

  • 27
  • 28
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs019.html b/doc/pub/week40/html/._week40-bs019.html index 28b7fd295..94a21dda4 100644 --- a/doc/pub/week40/html/._week40-bs019.html +++ b/doc/pub/week40/html/._week40-bs019.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,16 +252,7 @@ MathJax.Hub.Config({

     

     

     

    -

    Time decay rate

    - -

    As an example, let \( e = 0,1,2,3,\cdots \) denote the current epoch and let \( t_0, t_1 > 0 \) be two fixed numbers. Furthermore, let \( t = e \cdot m + i \) where \( m \) is the number of minibatches and \( i=0,\cdots,m-1 \). Then the function $$\gamma_j(t; t_0, t_1) = \frac{t_0}{t+t_1} $$ goes to zero as the number of epochs gets large. I.e. we start with a step length \( \gamma_j (0; t_0, t_1) = t_0/t_1 \) which decays in time \( t \).

    - -

    In this way we can fix the number of epochs, compute \( \beta \) and -evaluate the cost function at the end. Repeating the computation will -give a different result since the scheme is random by design. Then we -pick the final \( \beta \) that gives the lowest value of the cost -function. -

    +

    And Logistic Regression

    @@ -380,30 +261,175 @@ function.
    -
    import numpy as np 
    +  
    import autograd.numpy as np
    +from autograd import grad
     
    -def step_length(t,t0,t1):
    -    return t0/(t+t1)
    +def sigmoid(x):
    +    return 0.5 * (np.tanh(x / 2.) + 1)
     
    -n = 100 #100 datapoints 
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -n_epochs = 500 #number of epochs
    -t0 = 1.0
    -t1 = 10
    +def logistic_predictions(weights, inputs):
    +    # Outputs probability of a label being true according to logistic model.
    +    return sigmoid(np.dot(inputs, weights))
     
    -gamma_j = t0/t1
    -j = 0
    -for epoch in range(1,n_epochs+1):
    -    for i in range(m):
    -        k = np.random.randint(m) #Pick the k-th minibatch at random
    -        #Compute the gradient using the data in minibatch Bk
    -        #Compute new suggestion for beta
    -        t = epoch*m+i
    -        gamma_j = step_length(t,t0,t1)
    -        j += 1
    +def training_loss(weights):
    +    # Training loss is the negative log-likelihood of the training labels.
    +    preds = logistic_predictions(weights, inputs)
    +    label_probabilities = preds * targets + (1 - preds) * (1 - targets)
    +    return -np.sum(np.log(label_probabilities))
     
    -print("gamma_j after %d epochs: %g" % (n_epochs,gamma_j))
    +# Build a toy dataset.
    +inputs = np.array([[0.52, 1.12,  0.77],
    +                   [0.88, -1.08, 0.15],
    +                   [0.52, 0.06, -1.30],
    +                   [0.74, -2.49, 1.39]])
    +targets = np.array([True, True, False, True])
    +
    +# Define a function that returns gradients of training loss using Autograd.
    +training_gradient_fun = grad(training_loss)
    +
    +# Optimize weights using gradient descent.
    +weights = np.array([0.0, 0.0, 0.0])
    +print("Initial loss:", training_loss(weights))
    +for i in range(100):
    +    weights -= training_gradient_fun(weights) * 0.01
    +
    +print("Trained loss:", training_loss(weights))
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    Introducing JAX

    + +

    Presently, instead of using autograd, we recommend using JAX

    + +

    JAX is Autograd and XLA (Accelerated Linear Algebra)), +brought together for high-performance numerical computing and machine learning research. +It provides composable transformations of Python+NumPy programs: differentiate, vectorize, parallelize, Just-In-Time compile to GPU/TPU, and more. +

    +

    Getting started with Jax, note the way we import numpy

    + + +
    +
    +
    +
    +
    +
    import jax
    +import jax.numpy as jnp
    +import numpy as np
    +import matplotlib.pyplot as plt
    +
    +from jax import grad as jax_grad
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    A warm-up example

    + + + +
    +
    +
    +
    +
    +
    def function(x):
    +    return x**2
    +
    +def analytical_gradient(x):
    +    return 2*x
    +
    +def gradient_descent(starting_point, learning_rate, num_iterations, solver="analytical"):
    +    x = starting_point
    +    trajectory_x = [x]
    +    trajectory_y = [function(x)]
    +
    +    if solver == "analytical":
    +        grad = analytical_gradient    
    +    elif solver == "jax":
    +        grad = jax_grad(function)
    +        x = jnp.float64(x)
    +        learning_rate = jnp.float64(learning_rate)
    +
    +    for _ in range(num_iterations):
    +        
    +        x = x - learning_rate * grad(x)
    +        trajectory_x.append(x)
    +        trajectory_y.append(function(x))
    +
    +    return trajectory_x, trajectory_y
    +
    +x = np.linspace(-5, 5, 100)
    +plt.plot(x, function(x), label="f(x)")
    +
    +descent_x, descent_y = gradient_descent(5, 0.1, 10, solver="analytical")
    +jax_descend_x, jax_descend_y = gradient_descent(5, 0.1, 10, solver="jax")
    +
    +plt.plot(descent_x, descent_y, label="Gradient descent", marker="o")
    +plt.plot(jax_descend_x, jax_descend_y, label="JAX", marker="x")
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    A more advanced example

    + + + +
    +
    +
    +
    +
    +
    backend = np
    +
    +def function(x):
    +    return x*backend.sin(x**2 + 1)
    +
    +def analytical_gradient(x):
    +    return backend.sin(x**2 + 1) + 2*x**2*backend.cos(x**2 + 1)
    +
    +
    +x = np.linspace(-5, 5, 100)
    +plt.plot(x, function(x), label="f(x)")
    +
    +descent_x, descent_y = gradient_descent(1, 0.01, 300, solver="analytical")
    +
    +# Change the backend to JAX
    +backend = jnp
    +jax_descend_x, jax_descend_y = gradient_descent(1, 0.01, 300, solver="jax")
    +
    +plt.scatter(descent_x, descent_y, label="Gradient descent", marker="v", s=10, color="red") 
    +plt.scatter(jax_descend_x, jax_descend_y, label="JAX", marker="x", s=5, color="black")
     
    @@ -445,7 +471,7 @@ j = 0
  • 28
  • 29
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs020.html b/doc/pub/week40/html/._week40-bs020.html index 1bdbd33a9..2a0b67cb6 100644 --- a/doc/pub/week40/html/._week40-bs020.html +++ b/doc/pub/week40/html/._week40-bs020.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,97 +252,16 @@ MathJax.Hub.Config({

     

     

     

    -

    Code with a Number of Minibatches which varies

    - -

    In the code here we vary the number of mini-batches.

    - - -
    -
    -
    -
    -
    -
    # Importing various packages
    -from math import exp, sqrt
    -from random import random, seed
    -import numpy as np
    -import matplotlib.pyplot as plt
    -
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+np.random.randn(n,1)
    -
    -X = np.c_[np.ones((n,1)), x]
    -XT_X = X.T @ X
    -theta_linreg = np.linalg.inv(X.T @ X) @ (X.T @ y)
    -print("Own inversion")
    -print(theta_linreg)
    -# Hessian matrix
    -H = (2.0/n)* XT_X
    -EigValues, EigVectors = np.linalg.eig(H)
    -print(f"Eigenvalues of Hessian Matrix:{EigValues}")
    -
    -theta = np.random.randn(2,1)
    -eta = 1.0/np.max(EigValues)
    -Niterations = 1000
    -
    -
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ ((X @ theta)-y)
    -    theta -= eta*gradients
    -print("theta from own gd")
    -print(theta)
    -
    -xnew = np.array([[0],[2]])
    -Xnew = np.c_[np.ones((2,1)), xnew]
    -ypredict = Xnew.dot(theta)
    -ypredict2 = Xnew.dot(theta_linreg)
    -
    -n_epochs = 50
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -t0, t1 = 5, 50
    -
    -def learning_schedule(t):
    -    return t0/(t+t1)
    -
    -theta = np.random.randn(2,1)
    -
    -for epoch in range(n_epochs):
    -# Can you figure out a better way of setting up the contributions to each batch?
    -    for i in range(m):
    -        random_index = M*np.random.randint(m)
    -        xi = X[random_index:random_index+M]
    -        yi = y[random_index:random_index+M]
    -        gradients = (2.0/M)* xi.T @ ((xi @ theta)-yi)
    -        eta = learning_schedule(epoch*m+i)
    -        theta = theta - eta*gradients
    -print("theta from own sdg")
    -print(theta)
    -
    -plt.plot(xnew, ypredict, "r-")
    -plt.plot(xnew, ypredict2, "b-")
    -plt.plot(x, y ,'ro')
    -plt.axis([0,2.0,0, 15.0])
    -plt.xlabel(r'$x$')
    -plt.ylabel(r'$y$')
    -plt.title(r'Random numbers ')
    -plt.show()
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    +

    Introduction to Neural networks

    +

    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 +biological system, wherein neurons interact by sending signals in the +form of mathematical functions between layers. All layers can contain +an arbitrary number of neurons, and each connection is represented by +a weight variable. +

    @@ -479,7 +288,7 @@ plt.show()

  • 29
  • 30
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs021.html b/doc/pub/week40/html/._week40-bs021.html index 3a9312816..6640e3c99 100644 --- a/doc/pub/week40/html/._week40-bs021.html +++ b/doc/pub/week40/html/._week40-bs021.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,12 +252,63 @@ MathJax.Hub.Config({

     

     

     

    -

    Replace or not

    +

    Artificial neurons

    -

    In the above code, we have use replacement in setting up the -mini-batches. The discussion -here may be -useful. +

    The field of artificial neural networks has a long history of +development, and is closely connected with the advancement of computer +science and computers in general. A model of artificial neurons was +first developed by McCulloch and Pitts in 1943 to study signal +processing in the brain and has later been refined by others. The +general idea is to mimic neural networks in the human brain, which is +composed of billions of neurons that communicate with each other by +sending electrical signals. Each neuron accumulates its incoming +signals, which must exceed an activation threshold to yield an +output. If the threshold is not overcome, the neuron remains inactive, +i.e. has zero output. +

    + +

    This behaviour has inspired a simple mathematical model for an artificial neuron.

    + +$$ +\begin{equation} + y = f\left(\sum_{i=1}^n w_ix_i\right) = f(u) +\tag{1} +\end{equation} +$$ + +

    Here, the output \( y \) of the neuron is the value of its activation function, which have as input +a weighted sum of signals \( x_i, \dots ,x_n \) received by \( n \) other neurons. +

    + +

    Conceptually, it is helpful to divide neural networks into four +categories: +

    +
      +
    1. general purpose neural networks for supervised learning,
    2. +
    3. neural networks designed specifically for image processing, the most prominent example of this class being Convolutional Neural Networks (CNNs),
    4. +
    5. neural networks for sequential data such as Recurrent Neural Networks (RNNs), and
    6. +
    7. neural networks for unsupervised learning such as Deep Boltzmann Machines.
    8. +
    +

    In natural science, DNNs and CNNs have already found numerous +applications. In statistical physics, they have been applied to detect +phase transitions in 2D Ising and Potts models, lattice gauge +theories, and different phases of polymers, or solving the +Navier-Stokes equation in weather forecasting. Deep learning has also +found interesting applications in quantum physics. Various quantum +phase transitions can be detected and studied using DNNs and CNNs, +topological phases, and even non-equilibrium many-body +localization. Representing quantum states as DNNs quantum state +tomography are among some of the impressive achievements to reveal the +potential of DNNs to facilitate the study of quantum systems. +

    + +

    In quantum information theory, it has been shown that one can perform +gate decompositions with the help of neural. +

    + +

    The applications are not limited to the natural sciences. There is a +plethora of applications in essentially all disciplines, from the +humanities to life science and medicine.

    @@ -395,7 +336,7 @@ useful.

  • 30
  • 31
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs022.html b/doc/pub/week40/html/._week40-bs022.html index c1f9f4e2d..948b34f3c 100644 --- a/doc/pub/week40/html/._week40-bs022.html +++ b/doc/pub/week40/html/._week40-bs022.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,39 +252,29 @@ MathJax.Hub.Config({

     

     

     

    -

    Momentum based GD

    +

    Neural network types

    -

    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 +

    An artificial neural network (ANN), is a computational model that +consists of layers of connected neurons, or nodes or units. We will +refer to these interchangeably as units or nodes, and sometimes as +neurons.

    -$$ -\begin{align} -\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t) \nonumber \\ -\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}, -\tag{1} -\end{align} -$$ - -

    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 +

    It is supposed to mimic a biological nervous system by letting each +neuron interact with other neurons by sending signals in the form of +mathematical functions between layers. A wide variety of different +ANNs have been developed, but most of them consist of an input layer, +an output layer and eventual layers in-between, called hidden +layers. All layers can contain an arbitrary number of nodes, and each +connection between two nodes is associated with a weight variable.

    -$$ -\Delta \boldsymbol{\theta}_{t+1} = \gamma \Delta \boldsymbol{\theta}_t -\ \eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t), -$$ - -

    where we have defined \( \Delta \boldsymbol{\theta}_{t}= \boldsymbol{\theta}_t-\boldsymbol{\theta}_{t-1} \).

    +

    Neural networks (also called neural nets) are neural-inspired +nonlinear models for supervised learning. As we will see, neural nets +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. +

    @@ -421,7 +301,7 @@ $$

  • 31
  • 32
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs023.html b/doc/pub/week40/html/._week40-bs023.html index a66ee74bf..ae8cd3c00 100644 --- a/doc/pub/week40/html/._week40-bs023.html +++ b/doc/pub/week40/html/._week40-bs023.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,31 +252,20 @@ MathJax.Hub.Config({

     

     

     

    -

    More on momentum based approaches

    +

    Feed-forward neural networks

    -

    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 +

    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.

    -$$ -m {d^2 \mathbf{w} \over dt^2} + \mu {d \mathbf{w} \over dt }= -\nabla_w E(\mathbf{w}). -$$ - -

    We can discretize this equation in the usual way to get

    - -$$ -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}). -$$ - -

    Rearranging this equation, we can rewrite this as

    - -$$ -\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. -$$ - +

    Nodes are represented by circles, while the arrows display the +connections between the nodes, including the direction of information +flow. Additionally, each arrow corresponds to a weight variable +(figure to come). We observe that each node in a layer is connected +to all nodes in the subsequent layer, making this a so-called +fully-connected FFNN. +

    @@ -413,7 +292,7 @@ $$

  • 32
  • 33
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs024.html b/doc/pub/week40/html/._week40-bs024.html index 20b5a5065..6fed5b8d9 100644 --- a/doc/pub/week40/html/._week40-bs024.html +++ b/doc/pub/week40/html/._week40-bs024.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,58 +252,29 @@ MathJax.Hub.Config({

     

     

     

    -

    Momentum parameter

    +

    Convolutional Neural Network

    -

    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: +

    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 +stimuli from small sub-regions of the visual field, called a receptive +field. This makes the neurons well-suited to exploit the strong +spatially local correlation present in natural images. The response of +each neuron can be approximated mathematically as a convolution +operation. (figure to come)

    -$$ -\gamma= {m \over m +\mu \Delta t }, \qquad \eta = {(\Delta t)^2 \over m +\mu \Delta t}. -$$ - -

    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) \). +

    Convolutional neural networks emulate the behaviour of neurons in the +visual cortex by enforcing a local connectivity pattern between +nodes of adjacent layers: Each node in a convolutional layer is +connected only to a subset of the nodes in the previous layer, in +contrast to the fully-connected FFNN. Often, CNNs consist of several +convolutional layers that learn local features of the input, with a +fully-connected layer at the end, which gathers all the local data and +produces the outputs. They have wide applications in image and video +recognition.

    -

    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 -

    - -$$ -\begin{align} -\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t +\gamma \mathbf{v}_{t-1}) \nonumber \\ -\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}. -\tag{2} -\end{align} -$$ - -

    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 \).

    -

    diff --git a/doc/pub/week40/html/._week40-bs025.html b/doc/pub/week40/html/._week40-bs025.html index 90f79cf87..236ae8d35 100644 --- a/doc/pub/week40/html/._week40-bs025.html +++ b/doc/pub/week40/html/._week40-bs025.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,29 +252,18 @@ MathJax.Hub.Config({

     

     

     

    -

    Second moment of the gradient

    +

    Recurrent neural networks

    -

    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. -

    - -

    During the last decade 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, Root Mean Squared Propagation (RMS-Prop), and -ADAM. +

    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 +creates a form of internal memory which are able to capture +information on what has been calculated before; the output is +dependent on the previous computations. Recurrent NNs make use of +sequential information by performing the same task for every element +in a sequence, where each element depends on previous elements. An +example of such information is sentences, making recurrent NNs +especially well-suited for handwriting and speech recognition.

    @@ -412,7 +291,7 @@ the gradient. These methods include AdaGrad, AdaDelta, Root Mean Squared Propaga

  • 34
  • 35
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs026.html b/doc/pub/week40/html/._week40-bs026.html index 243cb4354..c2aab247d 100644 --- a/doc/pub/week40/html/._week40-bs026.html +++ b/doc/pub/week40/html/._week40-bs026.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,32 +252,18 @@ MathJax.Hub.Config({

     

     

     

    -

    RMS prop

    +

    Other types of networks

    -

    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 -

    - -$$ -\begin{align} -\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) -\tag{3}\\ -\mathbf{s}_t &=\beta \mathbf{s}_{t-1} +(1-\beta)\mathbf{g}_t^2 \nonumber \\ -\boldsymbol{\theta}_{t+1}&=&\boldsymbol{\theta}_t - \eta_t { \mathbf{g}_t \over \sqrt{\mathbf{s}_t +\epsilon}}, \nonumber -\end{align} -$$ - -

    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. +

    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 +made up of three layers: an input layer, a hidden layer with +non-linear radial symmetric activation functions and a linear output +layer (''linear'' here means that each node in the output layer has a +linear activation function). The layers are normally fully-connected +and there are no cycles, thus RBFs can be viewed as a type of +fully-connected FFNN. They are however usually treated as a separate +type of NN due the unusual activation functions.

    @@ -415,7 +291,7 @@ learning rate for flat directions.

  • 35
  • 36
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs027.html b/doc/pub/week40/html/._week40-bs027.html index 022e3ec3b..9ac9a8399 100644 --- a/doc/pub/week40/html/._week40-bs027.html +++ b/doc/pub/week40/html/._week40-bs027.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,59 +252,15 @@ MathJax.Hub.Config({

     

     

     

    -

    ADAM optimizer

    +

    Multilayer perceptrons

    -

    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. The method isefficient when working with large -problems involving lots data and/or parameters. It is a combination of the -gradient descent with momentum algorithm and the RMSprop algorithm -discussed above. +

    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 +activation functions.

    -

    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) -

    - -$$ -\begin{align} -\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) -\tag{4}\\ -\mathbf{m}_t &= \beta_1 \mathbf{m}_{t-1} + (1-\beta_1) \mathbf{g}_t \nonumber \\ -\mathbf{s}_t &=\beta_2 \mathbf{s}_{t-1} +(1-\beta_2)\mathbf{g}_t^2 \nonumber \\ -\boldsymbol{\mathbf{m}}_t&={\mathbf{m}_t \over 1-\beta_1^t} \nonumber \\ -\boldsymbol{\mathbf{s}}_t &={\mathbf{s}_t \over1-\beta_2^t} \nonumber \\ -\boldsymbol{\theta}_{t+1}&=\boldsymbol{\theta}_t - \eta_t { \boldsymbol{\mathbf{m}}_t \over \sqrt{\boldsymbol{\mathbf{s}}_t} +\epsilon}, \nonumber \\ -\tag{5} -\end{align} -$$ - -

    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 -

    - -$$ -\Delta \theta_{t+1}= -\eta_t { \boldsymbol{m}_t \over \sqrt{\sigma_t^2 + m_t^2 }+\epsilon}. -$$ - +

    Such networks are often called multilayer perceptrons (MLPs).

    @@ -441,7 +287,7 @@ $$

  • 36
  • 37
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs028.html b/doc/pub/week40/html/._week40-bs028.html index f5f7681a1..90db2d333 100644 --- a/doc/pub/week40/html/._week40-bs028.html +++ b/doc/pub/week40/html/._week40-bs028.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,32 +252,20 @@ MathJax.Hub.Config({

     

     

     

    -

    Algorithms and codes for Adagrad, RMSprop and Adam

    +

    Why multilayer perceptrons?

    -

    The algorithms we have implemented are well described in the text by Goodfellow, Bengio and Courville, chapter 8.

    +

    According to the Universal approximation theorem, a feed-forward +neural network with just a single hidden layer containing a finite +number of neurons can approximate a continuous multidimensional +function to arbitrary accuracy, assuming the activation function for +the hidden layer is a non-constant, bounded and +monotonically-increasing continuous function. +

    -

    The codes which implement these algorithms are discussed after our presentation of automatic differentiation.

    -

    AdaGrad algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    -

    RMSProp algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    -

    ADAM algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    +

    Note that the requirements on the activation function only applies to +the hidden layer, the output nodes are always assumed to be linear, so +as to not restrict the range of output values. +

    @@ -414,7 +292,7 @@ MathJax.Hub.Config({

  • 37
  • 38
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs029.html b/doc/pub/week40/html/._week40-bs029.html index 8b7943fa3..ae885f332 100644 --- a/doc/pub/week40/html/._week40-bs029.html +++ b/doc/pub/week40/html/._week40-bs029.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,15 +252,15 @@ MathJax.Hub.Config({

     

     

     

    -

    Practical tips

    +

    Illustration of a single perceptron model and a multi-perceptron model

    -
      -
    • 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.
    • -
    -

    Geron's text, see chapter 11, has several interesting discussions.

    +
    +
    +
    +

    Figure 1: In a) we show a single perceptron model while in b) we dispay a network with two hidden layers, an input layer and an output layer.

    +
    +

    +

    @@ -397,7 +287,7 @@ MathJax.Hub.Config({

  • 38
  • 39
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs030.html b/doc/pub/week40/html/._week40-bs030.html index 52fd05644..9bc999189 100644 --- a/doc/pub/week40/html/._week40-bs030.html +++ b/doc/pub/week40/html/._week40-bs030.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,49 +252,15 @@ MathJax.Hub.Config({

     

     

     

    -

    Automatic differentiation

    +

    Examples of XOR, OR and AND gates

    -

    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. +

    Let us first try to fit various gates using standard linear +regression. The gates we are thinking of are the classical XOR, OR and +AND gates, well-known elements in computer science. The tables here +show how we can set up the inputs \( x_1 \) and \( x_2 \) in order to yield a +specific target \( y_i \).

    -

    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 -

    -$$ -f(x) = \sin\left(2\pi x + x^2\right) -$$ - -

    which has the following derivative

    -$$ -f'(x) = \cos\left(2\pi x + x^2\right)\left(2\pi + 2x\right) -$$ - -

    Using autograd we have

    -
    @@ -412,40 +268,36 @@ $$
    -
    import autograd.numpy as np
    +  
    """
    +Simple code that tests XOR, OR and AND gates with linear regression
    +"""
     
    -# To do elementwise differentiation:
    -from autograd import elementwise_grad as egrad 
    +import numpy as np
    +# Design matrix
    +X = np.array([ [1, 0, 0], [1, 0, 1], [1, 1, 0],[1, 1, 1]],dtype=np.float64)
    +print(f"The X.TX  matrix:{X.T @ X}")
    +Xinv = np.linalg.pinv(X.T @ X)
    +print(f"The invers of X.TX  matrix:{Xinv}")
     
    -# To plot:
    -import matplotlib.pyplot as plt 
    +# The XOR gate 
    +yXOR = np.array( [ 0, 1 ,1, 0])
    +ThetaXOR  = Xinv @ X.T @ yXOR
    +print(f"The values of theta for the XOR gate:{ThetaXOR}")
    +print(f"The linear regression prediction  for the XOR gate:{X @ ThetaXOR}")
     
     
    -def f(x):
    -    return np.sin(2*np.pi*x + x**2)
    +# The OR gate 
    +yOR = np.array( [ 0, 1 ,1, 1])
    +ThetaOR  = Xinv @ X.T @ yOR
    +print(f"The values of theta for the OR gate:{ThetaOR}")
    +print(f"The linear regression prediction  for the OR gate:{X @ ThetaOR}")
     
    -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))))
    +# The OR gate 
    +yAND = np.array( [ 0, 0 ,0, 1])
    +ThetaAND  = Xinv @ X.T @ yAND
    +print(f"The values of theta for the AND gate:{ThetaAND}")
    +print(f"The linear regression prediction  for the AND gate:{X @ ThetaAND}")
     
    @@ -461,6 +313,7 @@ plt.show()
    +

    What is happening here?

    @@ -487,7 +340,7 @@ plt.show()

  • 39
  • 40
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs031.html b/doc/pub/week40/html/._week40-bs031.html index 7f289ab36..1d1b77149 100644 --- a/doc/pub/week40/html/._week40-bs031.html +++ b/doc/pub/week40/html/._week40-bs031.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -361,15 +251,8 @@ MathJax.Hub.Config({

     

     

     

    - -

    Using autograd

    - -

    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. -

    + +

    Does Logistic Regression do a better Job?

    @@ -378,23 +261,55 @@ experiment with other, possibly more complicated, functions as well.
    -
    import autograd.numpy as np
    -from autograd import grad
    +  
    """
    +Simple code that tests XOR and OR gates with linear regression
    +and logistic regression
    +"""
     
    -def f1(x):
    -    return x**3 + 1
    +import matplotlib.pyplot as plt
    +from sklearn.linear_model import LogisticRegression
    +import numpy as np
     
    -f1_grad = grad(f1)
    +# Design matrix
    +X = np.array([ [1, 0, 0], [1, 0, 1], [1, 1, 0],[1, 1, 1]],dtype=np.float64)
    +print(f"The X.TX  matrix:{X.T @ X}")
    +Xinv = np.linalg.pinv(X.T @ X)
    +print(f"The invers of X.TX  matrix:{Xinv}")
     
    -# Remember to send in float as argument to the computed gradient from Autograd!
    -a = 1.0
    +# The XOR gate 
    +yXOR = np.array( [ 0, 1 ,1, 0])
    +ThetaXOR  = Xinv @ X.T @ yXOR
    +print(f"The values of theta for the XOR gate:{ThetaXOR}")
    +print(f"The linear regression prediction  for the XOR gate:{X @ ThetaXOR}")
     
    -# 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))
    +# The OR gate 
    +yOR = np.array( [ 0, 1 ,1, 1])
    +ThetaOR  = Xinv @ X.T @ yOR
    +print(f"The values of theta for the OR gate:{ThetaOR}")
    +print(f"The linear regression prediction  for the OR gate:{X @ ThetaOR}")
    +
    +
    +# The OR gate 
    +yAND = np.array( [ 0, 0 ,0, 1])
    +ThetaAND  = Xinv @ X.T @ yAND
    +print(f"The values of theta for the AND gate:{ThetaAND}")
    +print(f"The linear regression prediction  for the AND gate:{X @ ThetaAND}")
    +
    +# Now we change to logistic regression
    +
    +
    +# Logistic Regression
    +logreg = LogisticRegression()
    +logreg.fit(X, yOR)
    +print("Test set accuracy with Logistic Regression for OR gate: {:.2f}".format(logreg.score(X,yOR)))
    +
    +logreg.fit(X, yXOR)
    +print("Test set accuracy with Logistic Regression for XOR gate: {:.2f}".format(logreg.score(X,yXOR)))
    +
    +
    +logreg.fit(X, yAND)
    +print("Test set accuracy with Logistic Regression for AND gate: {:.2f}".format(logreg.score(X,yAND)))
     
    @@ -410,6 +325,7 @@ grad_analytical = = 40
  • 41
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs032.html b/doc/pub/week40/html/._week40-bs032.html index d37d20e9e..76d4ee949 100644 --- a/doc/pub/week40/html/._week40-bs032.html +++ b/doc/pub/week40/html/._week40-bs032.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,12 +252,7 @@ MathJax.Hub.Config({

     

     

     

    -

    Autograd with more complicated functions

    - -

    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. -

    +

    Adding Neural Networks

    @@ -376,39 +261,14 @@ 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
    +  
    # and now neural networks with Scikit-Learn and the XOR
     
    -# 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) ))
    +from sklearn.neural_network import MLPClassifier
    +from sklearn.datasets import make_classification
    +X, yXOR = make_classification(n_samples=100, random_state=1)
    +FFNN = MLPClassifier(random_state=1, max_iter=300).fit(X, yXOR)
    +FFNN.predict_proba(X)
    +print(f"Test set accuracy with Feed Forward Neural Network  for XOR gate:{FFNN.score(X, yXOR)}")
     
    @@ -424,7 +284,6 @@ f2_grad_x2_analytical = x1 = x1 41
  • 42
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs033.html b/doc/pub/week40/html/._week40-bs033.html index 075b2d381..bd7f38f17 100644 --- a/doc/pub/week40/html/._week40-bs033.html +++ b/doc/pub/week40/html/._week40-bs033.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,53 +252,19 @@ MathJax.Hub.Config({

     

     

     

    -

    More complicated functions using the elements of their arguments directly

    +

    Mathematical model

    +

    The output \( y \) is produced via the activation function \( f \)

    +$$ + y = f\left(\sum_{i=1}^n w_ix_i + b_i\right) = f(z), +$$ - -
    -
    -
    -
    -
    -
    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. +

    This function receives \( x_i \) as inputs. +Here the activation \( z=(\sum_{i=1}^n w_ix_i+b_i) \). +In an FFNN of such neurons, the inputs \( x_i \) are the outputs of +the neurons in the preceding layer. Furthermore, an MLP is +fully-connected, which means that each neuron receives a weighted sum +of the outputs of all neurons in the previous layer.

    @@ -435,8 +291,6 @@ could expect form a gradient-evaluting function.

  • 41
  • 42
  • 43
  • -
  • ...
  • -
  • 69
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs034.html b/doc/pub/week40/html/._week40-bs034.html index 22faf3bf4..d030bc08b 100644 --- a/doc/pub/week40/html/._week40-bs034.html +++ b/doc/pub/week40/html/._week40-bs034.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -361,48 +251,49 @@ MathJax.Hub.Config({

     

     

     

    - -

    Functions using mathematical functions from Numpy

    + +

    Mathematical model

    +

    First, for each node \( i \) in the first hidden layer, we calculate a weighted sum \( z_i^1 \) of the input coordinates \( x_j \),

    - -
    -
    -
    -
    -
    -
    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)
    +$$
    +\begin{equation} z_i^1 = \sum_{j=1}^{M} w_{ij}^1 x_j + b_i^1
    +\tag{2}
    +\end{equation}
    +$$
     
    -f4_grad = grad(f4)
    +

    Here \( b_i \) is the so-called bias which is normally needed in +case of zero activation weights or inputs. How to fix the biases and +the weights will be discussed below. The value of \( z_i^1 \) is the +argument to the activation function \( f_i \) of each node \( i \), The +variable \( M \) stands for all possible inputs to a given node \( i \) in the +first layer. We define the output \( y_i^1 \) of all neurons in layer 1 as +

    -x = 2.7 +$$ +\begin{equation} + y_i^1 = f(z_i^1) = f\left(\sum_{j=1}^M w_{ij}^1 x_j + b_i^1\right) +\tag{3} +\end{equation} +$$ -# Print the computed derivative: -print("The computed derivative of f4 at x = %g is: %g"%(x,f4_grad(x))) +

    where we assume that all nodes in the same layer have identical +activation functions, hence the notation \( f \). In general, we could assume in the more general case that different layers have different activation functions. +In this case we would identify these functions with a superscript \( l \) for the \( l \)-th layer, +

    -# 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)) -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    +$$ +\begin{equation} + y_i^l = f^l(u_i^l) = f^l\left(\sum_{j=1}^{N_{l-1}} w_{ij}^l y_j^{l-1} + b_i^l\right) +\tag{4} +\end{equation} +$$ +

    where \( N_l \) is the number of nodes in layer \( l \). When the output of +all the nodes in the first hidden layer are computed, the values of +the subsequent layer can be calculated and so forth until the output +is obtained. +

    @@ -427,9 +318,6 @@ f4_grad_analytical = x41

  • 42
  • 43
  • -
  • 44
  • -
  • ...
  • -
  • 69
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs035.html b/doc/pub/week40/html/._week40-bs035.html index bd8007acb..b9975ff9e 100644 --- a/doc/pub/week40/html/._week40-bs035.html +++ b/doc/pub/week40/html/._week40-bs035.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,43 +252,30 @@ MathJax.Hub.Config({

     

     

     

    -

    More autograd

    +

    Mathematical model

    +

    The output of neuron \( i \) in layer 2 is thus,

    - -
    -
    -
    -
    -
    -
    import autograd.numpy as np
    -from autograd import grad
    -def f5(x):
    -    if x >= 0:
    -        return x**2
    -    else:
    -        return -3*x + 1
    +$$
    +\begin{align}
    + y_i^2 &= f^2\left(\sum_{j=1}^N w_{ij}^2 y_j^1 + b_i^2\right) 
    +\tag{5}\\
    + &= f^2\left[\sum_{j=1}^N w_{ij}^2f^1\left(\sum_{k=1}^M w_{jk}^1 x_k + b_j^1\right) + b_i^2\right]
    +\tag{6}
    +\end{align}
    +$$
     
    -f5_grad = grad(f5)
    +

    where we have substituted \( y_k^1 \) with the inputs \( x_k \). Finally, the ANN output reads

    -x = 2.7 - -# Print the computed derivative: -print("The computed derivative of f5 at x = %g is: %g"%(x,f5_grad(x))) -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    +$$ +\begin{align} + y_i^3 &= f^3\left(\sum_{j=1}^N w_{ij}^3 y_j^2 + b_i^3\right) +\tag{7}\\ + &= f_3\left[\sum_{j} w_{ij}^3 f^2\left(\sum_{k} w_{jk}^2 f^1\left(\sum_{m} w_{km}^1 x_m + b_k^1\right) + b_j^2\right) + + b_1^3\right] +\tag{8} +\end{align} +$$

    @@ -423,10 +300,6 @@ x = 2.7

  • 41
  • 42
  • 43
  • -
  • 44
  • -
  • 45
  • -
  • ...
  • -
  • 69
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs036.html b/doc/pub/week40/html/._week40-bs036.html index 426306ba0..218212cd1 100644 --- a/doc/pub/week40/html/._week40-bs036.html +++ b/doc/pub/week40/html/._week40-bs036.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,85 +252,22 @@ MathJax.Hub.Config({

     

     

     

    -

    And with loops

    +

    Mathematical model

    +

    We can generalize this expression to an MLP with \( l \) hidden +layers. The complete functional form is, +

    - -
    -
    -
    -
    -
    -
    import autograd.numpy as np
    -from autograd import grad
    -def f6_for(x):
    -    val = 0
    -    for i in range(10):
    -        val = val + x**i
    -    return val
    -
    -def f6_while(x):
    -    val = 0
    -    i = 0
    -    while i < 10:
    -        val = val + x**i
    -        i = i + 1
    -    return val
    -
    -f6_for_grad = grad(f6_for)
    -f6_while_grad = grad(f6_while)
    -
    -x = 0.5
    -
    -# Print the computed derivaties of f6_for and f6_while
    -print("The computed derivative of f6_for at x = %g is: %g"%(x,f6_for_grad(x)))
    -print("The computed derivative of f6_while at x = %g is: %g"%(x,f6_while_grad(x)))
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - - -
    -
    -
    -
    -
    -
    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))
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    +$$ +\begin{align} +&y^{l+1}_i = f^{l+1}\left[\!\sum_{j=1}^{N_l} w_{ij}^3 f^l\left(\sum_{k=1}^{N_{l-1}}w_{jk}^{l-1}\left(\dots f^1\left(\sum_{n=1}^{N_0} w_{mn}^1 x_n+ b_m^1\right)\dots\right)+b_k^2\right)+b_1^3\right] && +\tag{9} +\end{align} +$$ +

    which illustrates a basic property of MLPs: The only independent +variables are the input values \( x_n \). +

    @@ -463,11 +290,6 @@ f6_grad_analytical = 41

  • 42
  • 43
  • -
  • 44
  • -
  • 45
  • -
  • 46
  • -
  • ...
  • -
  • 69
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs037.html b/doc/pub/week40/html/._week40-bs037.html index 009ec6f0b..80280ecef 100644 --- a/doc/pub/week40/html/._week40-bs037.html +++ b/doc/pub/week40/html/._week40-bs037.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,57 +252,31 @@ MathJax.Hub.Config({

     

     

     

    -

    Using recursion

    +

    Mathematical model

    - -
    -
    -
    -
    -
    -
    import autograd.numpy as np
    -from autograd import grad
    +

    This confirms that an MLP, despite its quite convoluted mathematical +form, is nothing more than an analytic function, specifically a +mapping of real-valued vectors \( \hat{x} \in \mathbb{R}^n \rightarrow +\hat{y} \in \mathbb{R}^m \). +

    -def f7(n): # Assume that n is an integer - if n == 1 or n == 0: - return 1 - else: - return n*f7(n-1) +

    Furthermore, the flexibility and universality of an MLP can be +illustrated by realizing that the expression is essentially a nested +sum of scaled activation functions of the form +

    -f7_grad = grad(f7) +$$ +\begin{equation} + f(x) = c_1 f(c_2 x + c_3) + c_4 +\tag{10} +\end{equation} +$$ -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.

    +

    where the parameters \( c_i \) are weights and biases. By adjusting these +parameters, the activation functions can be shifted up and down or +left and right, change slope or be rescaled which is the key to the +flexibility of a neural network. +

    @@ -434,12 +298,6 @@ f7_grad_analytical = 41

  • 42
  • 43
  • -
  • 44
  • -
  • 45
  • -
  • 46
  • -
  • 47
  • -
  • ...
  • -
  • 69
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs038.html b/doc/pub/week40/html/._week40-bs038.html index 2ba6e5e1f..1414a08d9 100644 --- a/doc/pub/week40/html/._week40-bs038.html +++ b/doc/pub/week40/html/._week40-bs038.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,83 +252,40 @@ MathJax.Hub.Config({

     

     

     

    -

    Using Autograd with OLS

    +

    Matrix-vector notation

    -

    We conclude the part on optmization by showing how we can make codes -for linear regression and logistic regression using autograd. The -first example shows results with ordinary leats squares. +

    We can introduce a more convenient notation for the activations in an A NN.

    + +

    Additionally, we can represent the biases and activations +as layer-wise column vectors \( \hat{b}_l \) and \( \hat{y}_l \), so that the \( i \)-th element of each vector +is the bias \( b_i^l \) and activation \( y_i^l \) of node \( i \) in layer \( l \) respectively.

    - - -
    -
    -
    -
    -
    -
    # Using Autograd to calculate gradients for OLS
    -from random import random, seed
    -import numpy as np
    -import autograd.numpy as np
    -import matplotlib.pyplot as plt
    -from autograd import grad
    -
    -def CostOLS(beta):
    -    return (1.0/n)*np.sum((y-X @ beta)**2)
    -
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+np.random.randn(n,1)
    -
    -X = np.c_[np.ones((n,1)), x]
    -XT_X = X.T @ X
    -theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    -print("Own inversion")
    -print(theta_linreg)
    -# Hessian matrix
    -H = (2.0/n)* XT_X
    -EigValues, EigVectors = np.linalg.eig(H)
    -print(f"Eigenvalues of Hessian Matrix:{EigValues}")
    -
    -theta = np.random.randn(2,1)
    -eta = 1.0/np.max(EigValues)
    -Niterations = 1000
    -# define the gradient
    -training_gradient = grad(CostOLS)
    -
    -for iter in range(Niterations):
    -    gradients = training_gradient(theta)
    -    theta -= eta*gradients
    -print("theta from own gd")
    -print(theta)
    -
    -xnew = np.array([[0],[2]])
    -Xnew = np.c_[np.ones((2,1)), xnew]
    -ypredict = Xnew.dot(theta)
    -ypredict2 = Xnew.dot(theta_linreg)
    -
    -plt.plot(xnew, ypredict, "r-")
    -plt.plot(xnew, ypredict2, "b-")
    -plt.plot(x, y ,'ro')
    -plt.axis([0,2.0,0, 15.0])
    -plt.xlabel(r'$x$')
    -plt.ylabel(r'$y$')
    -plt.title(r'Random numbers ')
    -plt.show()
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    +

    We have that \( \mathrm{W}_l \) is an \( N_{l-1} \times N_l \) matrix, while \( \hat{b}_l \) and \( \hat{y}_l \) are \( N_l \times 1 \) column vectors. +With this notation, the sum becomes a matrix-vector multiplication, and we can write +the equation for the activations of hidden layer 2 (assuming three nodes for simplicity) as +

    +$$ +\begin{equation} + \hat{y}_2 = f_2(\mathrm{W}_2 \hat{y}_{1} + \hat{b}_{2}) = + f_2\left(\left[\begin{array}{ccc} + w^2_{11} &w^2_{12} &w^2_{13} \\ + w^2_{21} &w^2_{22} &w^2_{23} \\ + w^2_{31} &w^2_{32} &w^2_{33} \\ + \end{array} \right] \cdot + \left[\begin{array}{c} + y^1_1 \\ + y^1_2 \\ + y^1_3 \\ + \end{array}\right] + + \left[\begin{array}{c} + b^2_1 \\ + b^2_2 \\ + b^2_3 \\ + \end{array}\right]\right). +\tag{11} +\end{equation} +$$

    @@ -460,13 +307,6 @@ plt.show()

  • 41
  • 42
  • 43
  • -
  • 44
  • -
  • 45
  • -
  • 46
  • -
  • 47
  • -
  • 48
  • -
  • ...
  • -
  • 69
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs039.html b/doc/pub/week40/html/._week40-bs039.html index 1d5e056c2..b65b3084d 100644 --- a/doc/pub/week40/html/._week40-bs039.html +++ b/doc/pub/week40/html/._week40-bs039.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,82 +252,24 @@ MathJax.Hub.Config({

     

     

     

    -

    Same code but now with momentum gradient descent

    +

    Matrix-vector notation and activation

    - -
    -
    -
    -
    -
    -
    # Using Autograd to calculate gradients for OLS
    -from random import random, seed
    -import numpy as np
    -import autograd.numpy as np
    -import matplotlib.pyplot as plt
    -from autograd import grad
    +

    The activation of node \( i \) in layer 2 is

    -def CostOLS(beta): - return (1.0/n)*np.sum((y-X @ beta)**2) - -n = 100 -x = 2*np.random.rand(n,1) -y = 4+3*x#+np.random.randn(n,1) - -X = np.c_[np.ones((n,1)), x] -XT_X = X.T @ X -theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) -print("Own inversion") -print(theta_linreg) -# Hessian matrix -H = (2.0/n)* XT_X -EigValues, EigVectors = np.linalg.eig(H) -print(f"Eigenvalues of Hessian Matrix:{EigValues}") - -theta = np.random.randn(2,1) -eta = 1.0/np.max(EigValues) -Niterations = 30 - -# define the gradient -training_gradient = grad(CostOLS) - -for iter in range(Niterations): - gradients = training_gradient(theta) - theta -= eta*gradients - print(iter,gradients[0],gradients[1]) -print("theta from own gd") -print(theta) - -# Now improve with momentum gradient descent -change = 0.0 -delta_momentum = 0.3 -for iter in range(Niterations): - # calculate gradient - gradients = training_gradient(theta) - # calculate update - new_change = eta*gradients+delta_momentum*change - # take a step - theta -= new_change - # save the change - change = new_change - print(iter,gradients[0],gradients[1]) -print("theta from own gd wth momentum") -print(theta) -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    +$$ +\begin{equation} + y^2_i = f_2\Bigr(w^2_{i1}y^1_1 + w^2_{i2}y^1_2 + w^2_{i3}y^1_3 + b^2_i\Bigr) = + f_2\left(\sum_{j=1}^3 w^2_{ij} y_j^1 + b^2_i\right). +\tag{12} +\end{equation} +$$ +

    This is not just a convenient and compact notation, but also a useful +and intuitive way to think about MLPs: The output is calculated by a +series of matrix-vector multiplications and vector additions that are +used as input to the activation functions. For each operation +\( \mathrm{W}_l \hat{y}_{l-1} \) we move forward one layer. +

    @@ -457,14 +289,6 @@ delta_momentum = 41

  • 42
  • 43
  • -
  • 44
  • -
  • 45
  • -
  • 46
  • -
  • 47
  • -
  • 48
  • -
  • 49
  • -
  • ...
  • -
  • 69
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs040.html b/doc/pub/week40/html/._week40-bs040.html index 9366e6fcd..b1038052f 100644 --- a/doc/pub/week40/html/._week40-bs040.html +++ b/doc/pub/week40/html/._week40-bs040.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,105 +252,20 @@ MathJax.Hub.Config({

     

     

     

    -

    Including Stochastic Gradient Descent with Autograd

    -

    In this code we include the stochastic gradient descent approach discussed above. Note here that we specify which argument we are taking the derivative with respect to when using autograd.

    - - - -
    -
    -
    -
    -
    -
    # Using Autograd to calculate gradients using SGD
    -# OLS example
    -from random import random, seed
    -import numpy as np
    -import autograd.numpy as np
    -import matplotlib.pyplot as plt
    -from autograd import grad
    -
    -# Note change from previous example
    -def CostOLS(y,X,theta):
    -    return np.sum((y-X @ theta)**2)
    -
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+np.random.randn(n,1)
    -
    -X = np.c_[np.ones((n,1)), x]
    -XT_X = X.T @ X
    -theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    -print("Own inversion")
    -print(theta_linreg)
    -# Hessian matrix
    -H = (2.0/n)* XT_X
    -EigValues, EigVectors = np.linalg.eig(H)
    -print(f"Eigenvalues of Hessian Matrix:{EigValues}")
    -
    -theta = np.random.randn(2,1)
    -eta = 1.0/np.max(EigValues)
    -Niterations = 1000
    -
    -# Note that we request the derivative wrt third argument (theta, 2 here)
    -training_gradient = grad(CostOLS,2)
    -
    -for iter in range(Niterations):
    -    gradients = (1.0/n)*training_gradient(y, X, theta)
    -    theta -= eta*gradients
    -print("theta from own gd")
    -print(theta)
    -
    -xnew = np.array([[0],[2]])
    -Xnew = np.c_[np.ones((2,1)), xnew]
    -ypredict = Xnew.dot(theta)
    -ypredict2 = Xnew.dot(theta_linreg)
    -
    -plt.plot(xnew, ypredict, "r-")
    -plt.plot(xnew, ypredict2, "b-")
    -plt.plot(x, y ,'ro')
    -plt.axis([0,2.0,0, 15.0])
    -plt.xlabel(r'$x$')
    -plt.ylabel(r'$y$')
    -plt.title(r'Random numbers ')
    -plt.show()
    -
    -n_epochs = 50
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -t0, t1 = 5, 50
    -def learning_schedule(t):
    -    return t0/(t+t1)
    -
    -theta = np.random.randn(2,1)
    -
    -for epoch in range(n_epochs):
    -# Can you figure out a better way of setting up the contributions to each batch?
    -    for i in range(m):
    -        random_index = M*np.random.randint(m)
    -        xi = X[random_index:random_index+M]
    -        yi = y[random_index:random_index+M]
    -        gradients = (1.0/M)*training_gradient(yi, xi, theta)
    -        eta = learning_schedule(epoch*m+i)
    -        theta = theta - eta*gradients
    -print("theta from own sdg")
    -print(theta)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    +

    Activation functions

    +

    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 +for a FFNN to fulfill the universal approximation theorem +

    +
      +
    • Non-constant
    • +
    • Bounded
    • +
    • Monotonically-increasing
    • +
    • Continuous
    • +

    diff --git a/doc/pub/week40/html/._week40-bs041.html b/doc/pub/week40/html/._week40-bs041.html index 7ad2afa6c..201a3ff20 100644 --- a/doc/pub/week40/html/._week40-bs041.html +++ b/doc/pub/week40/html/._week40-bs041.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,95 +252,27 @@ MathJax.Hub.Config({

     

     

     

    -

    Same code but now with momentum gradient descent

    +

    Activation functions, Logistic and Hyperbolic ones

    - -
    -
    -
    -
    -
    -
    # Using Autograd to calculate gradients using SGD
    -# OLS example
    -from random import random, seed
    -import numpy as np
    -import autograd.numpy as np
    -import matplotlib.pyplot as plt
    -from autograd import grad
    +

    The second requirement excludes all linear functions. Furthermore, in +a MLP with only linear activation functions, each layer simply +performs a linear transformation of its inputs. +

    -# Note change from previous example -def CostOLS(y,X,theta): - return np.sum((y-X @ theta)**2) +

    Regardless of the number of layers, the output of the NN will be +nothing but a linear function of the inputs. Thus we need to introduce +some kind of non-linearity to the NN to be able to fit non-linear +functions Typical examples are the logistic Sigmoid +

    -n = 100 -x = 2*np.random.rand(n,1) -y = 4+3*x+np.random.randn(n,1) +$$ + f(x) = \frac{1}{1 + e^{-x}}, +$$ -X = np.c_[np.ones((n,1)), x] -XT_X = X.T @ X -theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) -print("Own inversion") -print(theta_linreg) -# Hessian matrix -H = (2.0/n)* XT_X -EigValues, EigVectors = np.linalg.eig(H) -print(f"Eigenvalues of Hessian Matrix:{EigValues}") - -theta = np.random.randn(2,1) -eta = 1.0/np.max(EigValues) -Niterations = 100 - -# Note that we request the derivative wrt third argument (theta, 2 here) -training_gradient = grad(CostOLS,2) - -for iter in range(Niterations): - gradients = (1.0/n)*training_gradient(y, X, theta) - theta -= eta*gradients -print("theta from own gd") -print(theta) - - -n_epochs = 50 -M = 5 #size of each minibatch -m = int(n/M) #number of minibatches -t0, t1 = 5, 50 -def learning_schedule(t): - return t0/(t+t1) - -theta = np.random.randn(2,1) - -change = 0.0 -delta_momentum = 0.3 - -for epoch in range(n_epochs): - for i in range(m): - random_index = M*np.random.randint(m) - xi = X[random_index:random_index+M] - yi = y[random_index:random_index+M] - gradients = (1.0/M)*training_gradient(yi, xi, theta) - eta = learning_schedule(epoch*m+i) - # calculate update - new_change = eta*gradients+delta_momentum*change - # take a step - theta -= new_change - # save the change - change = new_change -print("theta from own sdg with momentum") -print(theta) -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    +

    and the hyperbolic tangent function

    +$$ + f(x) = \tanh(x) +$$

    @@ -469,16 +291,6 @@ delta_momentum = 41

  • 42
  • 43
  • -
  • 44
  • -
  • 45
  • -
  • 46
  • -
  • 47
  • -
  • 48
  • -
  • 49
  • -
  • 50
  • -
  • 51
  • -
  • ...
  • -
  • 69
  • »
  • diff --git a/doc/pub/week40/html/._week40-bs042.html b/doc/pub/week40/html/._week40-bs042.html index 9c83fc42a..b0eac9817 100644 --- a/doc/pub/week40/html/._week40-bs042.html +++ b/doc/pub/week40/html/._week40-bs042.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -362,7 +252,15 @@ MathJax.Hub.Config({

     

     

     

    -

    Similar (second order function now) problem but now with AdaGrad

    +

    Relevance

    + +

    The sigmoid function are more biologically plausible because the +output of inactive neurons are zero. Such activation function are +called one-sided. However, it has been shown that the hyperbolic +tangent performs better than the sigmoid for training MLPs. has +become the most popular for deep neural networks +

    +
    @@ -370,54 +268,77 @@ MathJax.Hub.Config({
    -
    # Using Autograd to calculate gradients using AdaGrad and Stochastic Gradient descent
    -# OLS example
    -from random import random, seed
    -import numpy as np
    -import autograd.numpy as np
    +  
    """The sigmoid function (or the logistic curve) is a 
    +function that takes any real number, z, and outputs a number (0,1).
    +It is useful in neural networks for assigning weights on a relative scale.
    +The value z is the weighted sum of parameters involved in the learning algorithm."""
    +
    +import numpy
     import matplotlib.pyplot as plt
    -from autograd import grad
    +import math as mt
     
    -# Note change from previous example
    -def CostOLS(y,X,theta):
    -    return np.sum((y-X @ theta)**2)
    +z = numpy.arange(-5, 5, .1)
    +sigma_fn = numpy.vectorize(lambda z: 1/(1+numpy.exp(-z)))
    +sigma = sigma_fn(z)
     
    -n = 1000
    -x = np.random.rand(n,1)
    -y = 2.0+3*x +4*x*x
    +fig = plt.figure()
    +ax = fig.add_subplot(111)
    +ax.plot(z, sigma)
    +ax.set_ylim([-0.1, 1.1])
    +ax.set_xlim([-5,5])
    +ax.grid(True)
    +ax.set_xlabel('z')
    +ax.set_title('sigmoid function')
     
    -X = np.c_[np.ones((n,1)), x, x*x]
    -XT_X = X.T @ X
    -theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    -print("Own inversion")
    -print(theta_linreg)
    +plt.show()
     
    +"""Step Function"""
    +z = numpy.arange(-5, 5, .02)
    +step_fn = numpy.vectorize(lambda z: 1.0 if z >= 0.0 else 0.0)
    +step = step_fn(z)
     
    -# Note that we request the derivative wrt third argument (theta, 2 here)
    -training_gradient = grad(CostOLS,2)
    -# Define parameters for Stochastic Gradient Descent
    -n_epochs = 50
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -# Guess for unknown parameters theta
    -theta = np.random.randn(3,1)
    +fig = plt.figure()
    +ax = fig.add_subplot(111)
    +ax.plot(z, step)
    +ax.set_ylim([-0.5, 1.5])
    +ax.set_xlim([-5,5])
    +ax.grid(True)
    +ax.set_xlabel('z')
    +ax.set_title('step function')
     
    -# Value for learning rate
    -eta = 0.01
    -# Including AdaGrad parameter to avoid possible division by zero
    -delta  = 1e-8
    -for epoch in range(n_epochs):
    -    Giter = 0.0
    -    for i in range(m):
    -        random_index = M*np.random.randint(m)
    -        xi = X[random_index:random_index+M]
    -        yi = y[random_index:random_index+M]
    -        gradients = (1.0/M)*training_gradient(yi, xi, theta)
    -        Giter += gradients*gradients
    -        update = gradients*eta/(delta+np.sqrt(Giter))
    -        theta -= update
    -print("theta from own AdaGrad")
    -print(theta)
    +plt.show()
    +
    +"""Sine Function"""
    +z = numpy.arange(-2*mt.pi, 2*mt.pi, 0.1)
    +t = numpy.sin(z)
    +
    +fig = plt.figure()
    +ax = fig.add_subplot(111)
    +ax.plot(z, t)
    +ax.set_ylim([-1.0, 1.0])
    +ax.set_xlim([-2*mt.pi,2*mt.pi])
    +ax.grid(True)
    +ax.set_xlabel('z')
    +ax.set_title('sine function')
    +
    +plt.show()
    +
    +"""Plots a graph of the squashing function used by a rectified linear
    +unit"""
    +z = numpy.arange(-2, 2, .1)
    +zero = numpy.zeros(len(z))
    +y = numpy.max([zero, z], axis=0)
    +
    +fig = plt.figure()
    +ax = fig.add_subplot(111)
    +ax.plot(z, y)
    +ax.set_ylim([-2.0, 2.0])
    +ax.set_xlim([-2.0, 2.0])
    +ax.grid(True)
    +ax.set_xlabel('z')
    +ax.set_title('Rectified linear unit')
    +
    +plt.show()
     
    @@ -433,7 +354,6 @@ delta = 1e-8
    -

    Running this code we note an almost perfect agreement with the results from matrix inversion.

    @@ -450,18 +370,6 @@ delta = 1e-841

  • 42
  • 43
  • -
  • 44
  • -
  • 45
  • -
  • 46
  • -
  • 47
  • -
  • 48
  • -
  • 49
  • -
  • 50
  • -
  • 51
  • -
  • 52
  • -
  • ...
  • -
  • 69
  • -
  • »
  • diff --git a/doc/pub/week40/html/week40-bs.html b/doc/pub/week40/html/week40-bs.html index e77b3a43b..9a3894e65 100644 --- a/doc/pub/week40/html/week40-bs.html +++ b/doc/pub/week40/html/week40-bs.html @@ -36,8 +36,7 @@ doconce format html week40.do.txt --html_style=bootstrap --pygments_html_style=d
  • Plans for week 40
  • -
  • Lecture Monday September 30, 2024
  • -
  • Suggested readings and videos
  • -
  • Lab sessions Tuesday and Wednesday
  • -
  • Summary from last week, using gradient descent methods, limitations
  • -
  • Simple implementation of GD for OLS, Ridge and Lasso
  • -
  • But none of these can compete with Newton's method
  • -
  • Gradient descent and Logistic regression
  • -
  • Overview video on Stochastic Gradient Descent
  • -
  • Batches and mini-batches
  • -
  • Stochastic Gradient Descent (SGD)
  • -
  • Stochastic Gradient Descent
  • -
  • Computation of gradients
  • -
  • SGD example
  • -
  • The gradient step
  • -
  • Simple example code
  • -
  • When do we stop?
  • -
  • Slightly different approach
  • -
  • Time decay rate
  • -
  • Code with a Number of Minibatches which varies
  • -
  • Replace or not
  • -
  • Momentum based GD
  • -
  • More on momentum based approaches
  • -
  • Momentum parameter
  • -
  • Second moment of the gradient
  • -
  • RMS prop
  • -
  • "ADAM optimizer":"https://arxiv.org/abs/1412.6980"
  • -
  • Algorithms and codes for Adagrad, RMSprop and Adam
  • -
  • AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html"
  • -
  • Practical tips
  • -
  • Automatic differentiation
  • -
  • Using autograd
  • -
  • Autograd with more complicated functions
  • -
  • More complicated functions using the elements of their arguments directly
  • -
  • Functions using mathematical functions from Numpy
  • -
  • More autograd
  • -
  • And with loops
  • -
  • Using recursion
  • -
  • Using Autograd with OLS
  • -
  • Same code but now with momentum gradient descent
  • -
  • Including Stochastic Gradient Descent with Autograd
  • -
  • Same code but now with momentum gradient descent
  • -
  • Similar (second order function now) problem but now with AdaGrad
  • -
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • -
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • -
  • And Logistic Regression
  • -
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • -
  •    Getting started with Jax, note the way we import numpy
  • -
  •    A warm-up example
  • -
  •    A more advanced example
  • -
  • Introduction to Neural networks
  • -
  • Artificial neurons
  • -
  • Neural network types
  • -
  • Feed-forward neural networks
  • -
  • Convolutional Neural Network
  • -
  • Recurrent neural networks
  • -
  • Other types of networks
  • -
  • Multilayer perceptrons
  • -
  • Why multilayer perceptrons?
  • -
  • Illustration of a single perceptron model and a multi-perceptron model
  • -
  • Examples of XOR, OR and AND gates
  • -
  • Does Logistic Regression do a better Job?
  • -
  • Adding Neural Networks
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  • Mathematical model
  • -
  •    Matrix-vector notation
  • -
  •    Matrix-vector notation and activation
  • -
  •    Activation functions
  • -
  •    Activation functions, Logistic and Hyperbolic ones
  • -
  •    Relevance
  • +
  • Lecture Monday September 30, 2024
  • +
  • Suggested readings and videos
  • +
  • Lab sessions Tuesday and Wednesday
  • +
  • Automatic differentiation
  • +
  • Using autograd
  • +
  • Autograd with more complicated functions
  • +
  • More complicated functions using the elements of their arguments directly
  • +
  • Functions using mathematical functions from Numpy
  • +
  • More autograd
  • +
  • And with loops
  • +
  • Using recursion
  • +
  • Using Autograd with OLS
  • +
  • Same code but now with momentum gradient descent
  • +
  • Including Stochastic Gradient Descent with Autograd
  • +
  • Same code but now with momentum gradient descent
  • +
  • Similar (second order function now) problem but now with AdaGrad
  • +
  • RMSprop for adaptive learning rate with Stochastic Gradient Descent
  • +
  • And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf"
  • +
  • And Logistic Regression
  • +
  • Introducing "JAX":"https://jax.readthedocs.io/en/latest/"
  • +
  •    Getting started with Jax, note the way we import numpy
  • +
  •    A warm-up example
  • +
  •    A more advanced example
  • +
  • Introduction to Neural networks
  • +
  • Artificial neurons
  • +
  • Neural network types
  • +
  • Feed-forward neural networks
  • +
  • Convolutional Neural Network
  • +
  • Recurrent neural networks
  • +
  • Other types of networks
  • +
  • Multilayer perceptrons
  • +
  • Why multilayer perceptrons?
  • +
  • Illustration of a single perceptron model and a multi-perceptron model
  • +
  • Examples of XOR, OR and AND gates
  • +
  • Does Logistic Regression do a better Job?
  • +
  • Adding Neural Networks
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  • Mathematical model
  • +
  •    Matrix-vector notation
  • +
  •    Matrix-vector notation and activation
  • +
  •    Activation functions
  • +
  •    Activation functions, Logistic and Hyperbolic ones
  • +
  •    Relevance
  • @@ -369,18 +259,15 @@ MathJax.Hub.Config({
    -Morten Hjorth-Jensen [1, 2] +Morten Hjorth-Jensen
    - +
    -[1] Department of Physics, University of Oslo, Norway -
    -
    -[2] Department of Physics and Astronomy and Facility for Rare Ion Beams, Michigan State University, USA +Department of Physics, University of Oslo, Norway

    -

    September 30-October 4, 2024

    +

    September 29-October 3, 2025


    @@ -405,7 +292,7 @@ MathJax.Hub.Config({
  • 9
  • 10
  • ...
  • -
  • 69
  • +
  • 43
  • »
  • @@ -419,7 +306,7 @@ MathJax.Hub.Config({ -->
    - © 1999-2024, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license + © 1999-2025, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license
    diff --git a/doc/pub/week40/html/week40-reveal.html b/doc/pub/week40/html/week40-reveal.html index 1f6ba7f5d..acc77e203 100644 --- a/doc/pub/week40/html/week40-reveal.html +++ b/doc/pub/week40/html/week40-reveal.html @@ -173,31 +173,24 @@ MathJax.Hub.Config({
    -Morten Hjorth-Jensen [1, 2] +Morten Hjorth-Jensen
    - +
    -[1] Department of Physics, University of Oslo, Norway -
    -
    -[2] Department of Physics and Astronomy and Facility for Rare Ion Beams, Michigan State University, USA +Department of Physics, University of Oslo, Norway

    -

    September 30-October 4, 2024

    +

    September 29-October 3, 2025


    - © 1999-2024, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license + © 1999-2025, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license
    -
    -

    Plans for week 40

    -
    -

    Lecture Monday September 30, 2024

    @@ -254,890 +247,6 @@ MathJax.Hub.Config({
    -
    -

    Summary from last week, using gradient descent methods, limitations

    - -
      -

    • 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.
    • -

    • Gradients are computationally expensive to calculate for large datasets. In many cases in statistics and ML, the cost/loss/risk function is a sum of terms, with one term for each data point. For example, in linear regression, \( E \propto \sum_{i=1}^n (y_i - \mathbf{w}^T\cdot\mathbf{x}_i)^2 \); for logistic regression, the square error is replaced by the cross entropy. To calculate the gradient we have to sum over all \( n \) data points. Doing this at every GD step becomes extremely computationally expensive. An ingenious solution to this, is to calculate the gradients using small subsets of the data called "mini batches". This has the added benefit of introducing stochasticity into our algorithm.
    • -

    • GD is very sensitive to choices of learning rates. GD is extremely sensitive to the choice of learning rates. If the learning rate is very small, the training process take an extremely long time. For larger learning rates, GD can diverge and give poor results. Furthermore, depending on what the local landscape looks like, we have to modify the learning rates to ensure convergence. Ideally, we would adaptively choose the learning rates to match the landscape.
    • -

    • GD treats all directions in parameter space uniformly. Another major drawback of GD is that unlike Newton's method, the learning rate for GD is the same in all directions in parameter space. For this reason, the maximum learning rate is set by the behavior of the steepest direction and this can significantly slow down training. Ideally, we would like to take large steps in flat directions and small steps in steep directions. Since we are exploring rugged landscapes where curvatures change, this requires us to keep track of not only the gradient but second derivatives. The ideal scenario would be to calculate the Hessian but this proves to be too computationally expensive.
    • -

    • GD can take exponential time to escape saddle points, even with random initialization. As we mentioned, GD is extremely sensitive to initial condition since it determines the particular local minimum GD would eventually reach. However, even with a good initialization scheme, through the introduction of randomness, GD can still take exponential time to escape saddle points.
    • -
    -
    - -
    -

    Simple implementation of GD for OLS, Ridge and Lasso

    - -

    Last week we studied both several gradient methods. With and without an update of the learning. -We summarize some of these here for the methods we hvae studied in project one, without the inclusion of momentum. -

    - - -
    -
    -
    -
    -
    -
    from random import random, seed
    -import numpy as np
    -
    -# the number of datapoints with a 2nd-order polynomial
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+5*x*x
    -# Design matrix including the intercept
    -# No scaling of data of and all data used for training 
    -X = np.c_[np.ones((n,1)), x, x*x]
    -# Learning rate and number of iterations
    -eta = 0.05
    -Niterations = 100
    -
    -# OLS part
    -beta_OLS = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradient = (2.0/n)*X.T @ (X @ beta_OLS-y)
    -    beta_OLS -= eta*gradient
    -print('Parameters for OLS using gradient descent')    
    -print(beta_OLS)
    -
    -#Ridge and Lasso parameter Lambda
    -Lambda  = 0.01
    -Id = n*Lambda* np.eye((X.T @ X).shape[0])
    -# Gradient descent with  Ridge
    -beta_Ridge = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ (X @ beta_Ridge-y)+2*Lambda*beta_Ridge
    -    beta_Ridge -= eta*gradients
    -print('Parameters for Ridge using gradient descent')    
    -print(beta_Ridge)
    -
    -# Gradient descent with Lasso
    -beta_Lasso = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ (X @ beta_Lasso-y)+Lambda*np.sign(beta_Lasso)
    -    beta_Lasso -= eta*gradients
    -print('Parameters for Lasso using gradient descent')    
    -print(beta_Lasso)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -

    But none of these can compete with Newton's method

    - -

    Note that we here have introduced automatic differentiation

    - - -
    -
    -
    -
    -
    -
    # Using Newton's method
    -from random import random, seed
    -import numpy as np
    -import autograd.numpy as np
    -from autograd import grad
    -
    -def CostOLS(beta):
    -    return (1.0/n)*np.sum((y-X @ beta)**2)
    -
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+5*x*x
    -
    -X = np.c_[np.ones((n,1)), x, x*x]
    -XT_X = X.T @ X
    -beta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    -print("Own inversion")
    -print(beta_linreg)
    -# Hessian matrix
    -H = (2.0/n)* XT_X
    -# Note that here the Hessian does not depend on the parameters beta
    -invH = np.linalg.pinv(H)
    -beta = np.random.randn(3,1)
    -Niterations = 5
    -# define the gradient
    -training_gradient = grad(CostOLS)
    -
    -for iter in range(Niterations):
    -    gradients = training_gradient(beta)
    -    beta -= invH @ gradients
    -    print(iter,gradients[0],gradients[1])
    -print("beta from own Newton code")
    -print(beta)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -

    Gradient descent and Logistic regression

    - -

    Finally, we complete these examples by adding a simple code for -Logistic regression. Note the more general approach with a class for -the method. Here we use a so-called AND gate for our data set. -

    - - - -
    -
    -
    -
    -
    -
    import numpy as np
    -class LogisticRegression:
    -    def __init__(self, learning_rate=0.01, num_iterations=1000):
    -        self.learning_rate = learning_rate
    -        self.num_iterations = num_iterations
    -        self.beta_logreg = None
    -    def sigmoid(self, z):
    -        return 1 / (1 + np.exp(-z))
    -    def GDfit(self, X, y):
    -        n_data, num_features = X.shape
    -        self.beta_logreg = np.zeros(num_features)
    -        for _ in range(self.num_iterations):
    -            linear_model = X @ self.beta_logreg
    -            y_predicted = self.sigmoid(linear_model)
    -            # Gradient calculation
    -            gradient = (X.T @ (y_predicted - y))/n_data
    -            # Update beta_logreg
    -            self.beta_logreg -= self.learning_rate*gradient
    -    def predict(self, X):
    -        linear_model = X @ self.beta_logreg
    -        y_predicted = self.sigmoid(linear_model)
    -        return [1 if i >= 0.5 else 0 for i in y_predicted]
    -# Example usage
    -if __name__ == "__main__":
    -    # Sample data
    -    X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
    -    y = np.array([0, 0, 0, 1])  # This is an AND gate
    -    model = LogisticRegression(learning_rate=0.01, num_iterations=1000)
    -    model.GDfit(X, y)
    -    predictions = model.predict(X)
    -    print("Predictions:", predictions)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -

    Overview video on Stochastic Gradient Descent

    - -What is Stochastic Gradient Descent -

    There are several reasons for using stochastic gradient descent. Some of these are:

    - -
      -

    1. Efficiency: Updates weights more frequently using a single or a small batch of samples, which speeds up convergence.
    2. -

    3. Hopefully avoid Local Minima
    4. -

    5. Memory Usage: Requires less memory compared to computing gradients for the entire dataset.
    6. -
    -
    - -
    -

    Batches and mini-batches

    - -

    In gradient descent we compute the cost function and its gradient for all data points we have.

    - -

    In large-scale applications such as the ILSVRC challenge, the -training data can have on order of millions of examples. Hence, it -seems wasteful to compute the full cost function over the entire -training set in order to perform only a single parameter update. A -very common approach to addressing this challenge is to compute the -gradient over batches of the training data. For example, a typical batch could contain some thousand examples from -an entire training set of several millions. This batch is then used to -perform a parameter update. -

    -
    - -
    -

    Stochastic Gradient Descent (SGD)

    - -

    In stochastic gradient descent, the extreme case is the case where we -have only one batch, that is we include the whole data set. -

    - -

    This process is called Stochastic Gradient -Descent (SGD) (or also sometimes on-line gradient descent). This is -relatively less common to see because in practice due to vectorized -code optimizations it can be computationally much more efficient to -evaluate the gradient for 100 examples, than the gradient for one -example 100 times. Even though SGD technically refers to using a -single example at a time to evaluate the gradient, you will hear -people use the term SGD even when referring to mini-batch gradient -descent (i.e. mentions of MGD for “Minibatch Gradient Descent”, or BGD -for “Batch gradient descent” are rare to see), where it is usually -assumed that mini-batches are used. The size of the mini-batch is a -hyperparameter but it is not very common to cross-validate or bootstrap it. It is -usually based on memory constraints (if any), or set to some value, -e.g. 32, 64 or 128. We use powers of 2 in practice because many -vectorized operation implementations work faster when their inputs are -sized in powers of 2. -

    - -

    In our notes with SGD we mean stochastic gradient descent with mini-batches.

    -
    - -
    -

    Stochastic Gradient Descent

    - -

    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 -function, which we want to minimize, can almost always be written as a -sum over \( n \) data points \( \{\mathbf{x}_i\}_{i=1}^n \), -

    -

     
    -$$ -C(\mathbf{\beta}) = \sum_{i=1}^n c_i(\mathbf{x}_i, -\mathbf{\beta}). -$$ -

     
    -

    - -
    -

    Computation of gradients

    - -

    This in turn means that the gradient can be -computed as a sum over \( i \)-gradients -

    -

     
    -$$ -\nabla_\beta C(\mathbf{\beta}) = \sum_i^n \nabla_\beta c_i(\mathbf{x}_i, -\mathbf{\beta}). -$$ -

     
    - -

    Stochasticity/randomness is introduced by only taking the -gradient on a subset of the data called minibatches. If there are \( n \) -data points and the size of each minibatch is \( M \), there will be \( n/M \) -minibatches. We denote these minibatches by \( B_k \) where -\( k=1,\cdots,n/M \). -

    -
    - -
    -

    SGD example

    -

    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 -\( B_1 = (\mathbf{x}_1,\mathbf{x}_2), \cdots, B_5 = -(\mathbf{x}_9,\mathbf{x}_{10}) \). Note that if you choose \( M=1 \) you -have only a single batch with all data points and on the other extreme, -you may choose \( M=n \) resulting in a minibatch for each datapoint, i.e -\( B_k = \mathbf{x}_k \). -

    - -

    The idea is now to approximate the gradient by replacing the sum over -all data points with a sum over the data points in one the minibatches -picked at random in each gradient descent step -

    -

     
    -$$ -\nabla_{\beta} -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}). -$$ -

     
    -

    - -
    -

    The gradient step

    - -

    Thus a gradient descent step now looks like

    -

     
    -$$ -\beta_{j+1} = \beta_j - \gamma_j \sum_{i \in B_k}^n \nabla_\beta c_i(\mathbf{x}_i, -\mathbf{\beta}) -$$ -

     
    - -

    where \( k \) is picked at random with equal -probability from \( [1,n/M] \). An iteration over the number of -minibathces (n/M) is commonly referred to as an epoch. Thus it is -typical to choose a number of epochs and for each epoch iterate over -the number of minibatches, as exemplified in the code below. -

    -
    - -
    -

    Simple example code

    - - - -
    -
    -
    -
    -
    -
    import numpy as np 
    -
    -n = 100 #100 datapoints 
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -n_epochs = 10 #number of epochs
    -
    -j = 0
    -for epoch in range(1,n_epochs+1):
    -    for i in range(m):
    -        k = np.random.randint(m) #Pick the k-th minibatch at random
    -        #Compute the gradient using the data in minibatch Bk
    -        #Compute new suggestion for 
    -        j += 1
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -

    Taking the gradient only on a subset of the data has two important -benefits. First, it introduces randomness which decreases the chance -that our opmization scheme gets stuck in a local minima. Second, if -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. -

    -
    - -
    -

    When do we stop?

    - -

    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 -threshold and stop if true. However, the condition that the gradient -is zero is valid also for local minima, so this would only tell us -that we are close to a local/global minimum. However, we could also -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. -

    -
    - -
    -

    Slightly different approach

    - -

    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. Such approaches are -also called scaling. There are many such ways to scale the learning -rate -and discussions here. See -also -https://towardsdatascience.com/learning-rate-schedules-and-adaptive-learning-rate-methods-for-deep-learning-2c8f433990d1 -for a discussion of different scaling functions for the learning rate. -

    -
    - -
    -

    Time decay rate

    - -

    As an example, let \( e = 0,1,2,3,\cdots \) denote the current epoch and let \( t_0, t_1 > 0 \) be two fixed numbers. Furthermore, let \( t = e \cdot m + i \) where \( m \) is the number of minibatches and \( i=0,\cdots,m-1 \). Then the function

     
    -$$\gamma_j(t; t_0, t_1) = \frac{t_0}{t+t_1} $$ -

     
    goes to zero as the number of epochs gets large. I.e. we start with a step length \( \gamma_j (0; t_0, t_1) = t_0/t_1 \) which decays in time \( t \).

    - -

    In this way we can fix the number of epochs, compute \( \beta \) and -evaluate the cost function at the end. Repeating the computation will -give a different result since the scheme is random by design. Then we -pick the final \( \beta \) that gives the lowest value of the cost -function. -

    - - - -
    -
    -
    -
    -
    -
    import numpy as np 
    -
    -def step_length(t,t0,t1):
    -    return t0/(t+t1)
    -
    -n = 100 #100 datapoints 
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -n_epochs = 500 #number of epochs
    -t0 = 1.0
    -t1 = 10
    -
    -gamma_j = t0/t1
    -j = 0
    -for epoch in range(1,n_epochs+1):
    -    for i in range(m):
    -        k = np.random.randint(m) #Pick the k-th minibatch at random
    -        #Compute the gradient using the data in minibatch Bk
    -        #Compute new suggestion for beta
    -        t = epoch*m+i
    -        gamma_j = step_length(t,t0,t1)
    -        j += 1
    -
    -print("gamma_j after %d epochs: %g" % (n_epochs,gamma_j))
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -

    Code with a Number of Minibatches which varies

    - -

    In the code here we vary the number of mini-batches.

    - - -
    -
    -
    -
    -
    -
    # Importing various packages
    -from math import exp, sqrt
    -from random import random, seed
    -import numpy as np
    -import matplotlib.pyplot as plt
    -
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+np.random.randn(n,1)
    -
    -X = np.c_[np.ones((n,1)), x]
    -XT_X = X.T @ X
    -theta_linreg = np.linalg.inv(X.T @ X) @ (X.T @ y)
    -print("Own inversion")
    -print(theta_linreg)
    -# Hessian matrix
    -H = (2.0/n)* XT_X
    -EigValues, EigVectors = np.linalg.eig(H)
    -print(f"Eigenvalues of Hessian Matrix:{EigValues}")
    -
    -theta = np.random.randn(2,1)
    -eta = 1.0/np.max(EigValues)
    -Niterations = 1000
    -
    -
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ ((X @ theta)-y)
    -    theta -= eta*gradients
    -print("theta from own gd")
    -print(theta)
    -
    -xnew = np.array([[0],[2]])
    -Xnew = np.c_[np.ones((2,1)), xnew]
    -ypredict = Xnew.dot(theta)
    -ypredict2 = Xnew.dot(theta_linreg)
    -
    -n_epochs = 50
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -t0, t1 = 5, 50
    -
    -def learning_schedule(t):
    -    return t0/(t+t1)
    -
    -theta = np.random.randn(2,1)
    -
    -for epoch in range(n_epochs):
    -# Can you figure out a better way of setting up the contributions to each batch?
    -    for i in range(m):
    -        random_index = M*np.random.randint(m)
    -        xi = X[random_index:random_index+M]
    -        yi = y[random_index:random_index+M]
    -        gradients = (2.0/M)* xi.T @ ((xi @ theta)-yi)
    -        eta = learning_schedule(epoch*m+i)
    -        theta = theta - eta*gradients
    -print("theta from own sdg")
    -print(theta)
    -
    -plt.plot(xnew, ypredict, "r-")
    -plt.plot(xnew, ypredict2, "b-")
    -plt.plot(x, y ,'ro')
    -plt.axis([0,2.0,0, 15.0])
    -plt.xlabel(r'$x$')
    -plt.ylabel(r'$y$')
    -plt.title(r'Random numbers ')
    -plt.show()
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -

    Replace or not

    - -

    In the above code, we have use replacement in setting up the -mini-batches. The discussion -here may be -useful. -

    -
    - -
    -

    Momentum based GD

    - -

    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 -

    - -

     
    -$$ -\begin{align} -\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t) \nonumber \\ -\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}, -\tag{1} -\end{align} -$$ -

     
    - -

    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 -

    - -

     
    -$$ -\Delta \boldsymbol{\theta}_{t+1} = \gamma \Delta \boldsymbol{\theta}_t -\ \eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t), -$$ -

     
    - -

    where we have defined \( \Delta \boldsymbol{\theta}_{t}= \boldsymbol{\theta}_t-\boldsymbol{\theta}_{t-1} \).

    -
    - -
    -

    More on momentum based approaches

    - -

    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 -

    - -

     
    -$$ -m {d^2 \mathbf{w} \over dt^2} + \mu {d \mathbf{w} \over dt }= -\nabla_w E(\mathbf{w}). -$$ -

     
    - -

    We can discretize this equation in the usual way to get

    - -

     
    -$$ -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}). -$$ -

     
    - -

    Rearranging this equation, we can rewrite this as

    - -

     
    -$$ -\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. -$$ -

     
    -

    - -
    -

    Momentum parameter

    - -

    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: -

    - -

     
    -$$ -\gamma= {m \over m +\mu \Delta t }, \qquad \eta = {(\Delta t)^2 \over m +\mu \Delta t}. -$$ -

     
    - -

    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 -

    - -

     
    -$$ -\begin{align} -\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t +\gamma \mathbf{v}_{t-1}) \nonumber \\ -\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}. -\tag{2} -\end{align} -$$ -

     
    - -

    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 \).

    -
    - -
    -

    Second moment of the gradient

    - -

    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. -

    - -

    During the last decade 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, Root Mean Squared Propagation (RMS-Prop), and -ADAM. -

    -
    - -
    -

    RMS prop

    - -

    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 -

    - -

     
    -$$ -\begin{align} -\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) -\tag{3}\\ -\mathbf{s}_t &=\beta \mathbf{s}_{t-1} +(1-\beta)\mathbf{g}_t^2 \nonumber \\ -\boldsymbol{\theta}_{t+1}&=&\boldsymbol{\theta}_t - \eta_t { \mathbf{g}_t \over \sqrt{\mathbf{s}_t +\epsilon}}, \nonumber -\end{align} -$$ -

     
    - -

    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. -

    -
    - -
    -

    ADAM optimizer

    - -

    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. The method isefficient when working with large -problems involving lots data and/or parameters. It is a combination of the -gradient descent with momentum algorithm and the RMSprop algorithm -discussed above. -

    - -

    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) -

    - -

     
    -$$ -\begin{align} -\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) -\tag{4}\\ -\mathbf{m}_t &= \beta_1 \mathbf{m}_{t-1} + (1-\beta_1) \mathbf{g}_t \nonumber \\ -\mathbf{s}_t &=\beta_2 \mathbf{s}_{t-1} +(1-\beta_2)\mathbf{g}_t^2 \nonumber \\ -\boldsymbol{\mathbf{m}}_t&={\mathbf{m}_t \over 1-\beta_1^t} \nonumber \\ -\boldsymbol{\mathbf{s}}_t &={\mathbf{s}_t \over1-\beta_2^t} \nonumber \\ -\boldsymbol{\theta}_{t+1}&=\boldsymbol{\theta}_t - \eta_t { \boldsymbol{\mathbf{m}}_t \over \sqrt{\boldsymbol{\mathbf{s}}_t} +\epsilon}, \nonumber \\ -\tag{5} -\end{align} -$$ -

     
    - -

    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 -

    - -

     
    -$$ -\Delta \theta_{t+1}= -\eta_t { \boldsymbol{m}_t \over \sqrt{\sigma_t^2 + m_t^2 }+\epsilon}. -$$ -

     
    -

    - -
    -

    Algorithms and codes for Adagrad, RMSprop and Adam

    - -

    The algorithms we have implemented are well described in the text by Goodfellow, Bengio and Courville, chapter 8.

    - -

    The codes which implement these algorithms are discussed after our presentation of automatic differentiation.

    -

    AdaGrad algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    -

    RMSProp algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    -

    ADAM algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    -
    - -
    -

    Practical tips

    - -
      -

    • 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.
    • -
    -

    -

    Geron's text, see chapter 11, has several interesting discussions.

    -
    -

    Automatic differentiation

    @@ -2448,7 +1557,7 @@ i.e. has zero output. $$ \begin{equation} y = f\left(\sum_{i=1}^n w_ix_i\right) = f(u) -\tag{6} +\tag{1} \end{equation} $$

     
    @@ -2834,7 +1943,7 @@ of the outputs of all neurons in the previous layer.

     
    $$ \begin{equation} z_i^1 = \sum_{j=1}^{M} w_{ij}^1 x_j + b_i^1 -\tag{7} +\tag{2} \end{equation} $$

     
    @@ -2851,7 +1960,7 @@ first layer. We define the output \( y_i^1 \) of all neurons in layer 1 as $$ \begin{equation} y_i^1 = f(z_i^1) = f\left(\sum_{j=1}^M w_{ij}^1 x_j + b_i^1\right) -\tag{8} +\tag{3} \end{equation} $$

     
    @@ -2865,7 +1974,7 @@ In this case we would identify these functions with a superscript \( l \) for th $$ \begin{equation} y_i^l = f^l(u_i^l) = f^l\left(\sum_{j=1}^{N_{l-1}} w_{ij}^l y_j^{l-1} + b_i^l\right) -\tag{9} +\tag{4} \end{equation} $$

     
    @@ -2886,9 +1995,9 @@ is obtained. $$ \begin{align} y_i^2 &= f^2\left(\sum_{j=1}^N w_{ij}^2 y_j^1 + b_i^2\right) -\tag{10}\\ +\tag{5}\\ &= f^2\left[\sum_{j=1}^N w_{ij}^2f^1\left(\sum_{k=1}^M w_{jk}^1 x_k + b_j^1\right) + b_i^2\right] -\tag{11} +\tag{6} \end{align} $$

     
    @@ -2899,10 +2008,10 @@ $$ $$ \begin{align} y_i^3 &= f^3\left(\sum_{j=1}^N w_{ij}^3 y_j^2 + b_i^3\right) -\tag{12}\\ +\tag{7}\\ &= f_3\left[\sum_{j} w_{ij}^3 f^2\left(\sum_{k} w_{jk}^2 f^1\left(\sum_{m} w_{km}^1 x_m + b_k^1\right) + b_j^2\right) + b_1^3\right] -\tag{13} +\tag{8} \end{align} $$

     
    @@ -2919,7 +2028,7 @@ layers. The complete functional form is, $$ \begin{align} &y^{l+1}_i = f^{l+1}\left[\!\sum_{j=1}^{N_l} w_{ij}^3 f^l\left(\sum_{k=1}^{N_{l-1}}w_{jk}^{l-1}\left(\dots f^1\left(\sum_{n=1}^{N_0} w_{mn}^1 x_n+ b_m^1\right)\dots\right)+b_k^2\right)+b_1^3\right] && -\tag{14} +\tag{9} \end{align} $$

     
    @@ -2947,7 +2056,7 @@ sum of scaled activation functions of the form $$ \begin{equation} f(x) = c_1 f(c_2 x + c_3) + c_4 -\tag{15} +\tag{10} \end{equation} $$

     
    @@ -2992,7 +2101,7 @@ $$ b^2_2 \\ b^2_3 \\ \end{array}\right]\right). -\tag{16} +\tag{11} \end{equation} $$

     
    @@ -3008,7 +2117,7 @@ $$ \begin{equation} y^2_i = f_2\Bigr(w^2_{i1}y^1_1 + w^2_{i2}y^1_2 + w^2_{i3}y^1_3 + b^2_i\Bigr) = f_2\left(\sum_{j=1}^3 w^2_{ij} y_j^1 + b^2_i\right). -\tag{17} +\tag{12} \end{equation} $$

     
    diff --git a/doc/pub/week40/html/week40-solarized.html b/doc/pub/week40/html/week40-solarized.html index b62619a15..bee8bc88f 100644 --- a/doc/pub/week40/html/week40-solarized.html +++ b/doc/pub/week40/html/week40-solarized.html @@ -63,8 +63,7 @@ div.toc p,a {

    -Morten Hjorth-Jensen [1, 2] +Morten Hjorth-Jensen
    - +
    -[1] Department of Physics, University of Oslo, Norway -
    -
    -[2] Department of Physics and Astronomy and Facility for Rare Ion Beams, Michigan State University, USA +Department of Physics, University of Oslo, Norway

    -

    September 30-October 4, 2024

    +

    September 29-October 3, 2025


    -









    -

    Plans for week 40

    -









    Lecture Monday September 30, 2024

    @@ -358,841 +271,6 @@ MathJax.Hub.Config({
    -









    -

    Summary from last week, using gradient descent methods, limitations

    - -
      -
    • 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.
    • -
    • Gradients are computationally expensive to calculate for large datasets. In many cases in statistics and ML, the cost/loss/risk function is a sum of terms, with one term for each data point. For example, in linear regression, \( E \propto \sum_{i=1}^n (y_i - \mathbf{w}^T\cdot\mathbf{x}_i)^2 \); for logistic regression, the square error is replaced by the cross entropy. To calculate the gradient we have to sum over all \( n \) data points. Doing this at every GD step becomes extremely computationally expensive. An ingenious solution to this, is to calculate the gradients using small subsets of the data called "mini batches". This has the added benefit of introducing stochasticity into our algorithm.
    • -
    • GD is very sensitive to choices of learning rates. GD is extremely sensitive to the choice of learning rates. If the learning rate is very small, the training process take an extremely long time. For larger learning rates, GD can diverge and give poor results. Furthermore, depending on what the local landscape looks like, we have to modify the learning rates to ensure convergence. Ideally, we would adaptively choose the learning rates to match the landscape.
    • -
    • GD treats all directions in parameter space uniformly. Another major drawback of GD is that unlike Newton's method, the learning rate for GD is the same in all directions in parameter space. For this reason, the maximum learning rate is set by the behavior of the steepest direction and this can significantly slow down training. Ideally, we would like to take large steps in flat directions and small steps in steep directions. Since we are exploring rugged landscapes where curvatures change, this requires us to keep track of not only the gradient but second derivatives. The ideal scenario would be to calculate the Hessian but this proves to be too computationally expensive.
    • -
    • GD can take exponential time to escape saddle points, even with random initialization. As we mentioned, GD is extremely sensitive to initial condition since it determines the particular local minimum GD would eventually reach. However, even with a good initialization scheme, through the introduction of randomness, GD can still take exponential time to escape saddle points.
    • -
    -









    -

    Simple implementation of GD for OLS, Ridge and Lasso

    - -

    Last week we studied both several gradient methods. With and without an update of the learning. -We summarize some of these here for the methods we hvae studied in project one, without the inclusion of momentum. -

    - - -
    -
    -
    -
    -
    -
    from random import random, seed
    -import numpy as np
    -
    -# the number of datapoints with a 2nd-order polynomial
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+5*x*x
    -# Design matrix including the intercept
    -# No scaling of data of and all data used for training 
    -X = np.c_[np.ones((n,1)), x, x*x]
    -# Learning rate and number of iterations
    -eta = 0.05
    -Niterations = 100
    -
    -# OLS part
    -beta_OLS = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradient = (2.0/n)*X.T @ (X @ beta_OLS-y)
    -    beta_OLS -= eta*gradient
    -print('Parameters for OLS using gradient descent')    
    -print(beta_OLS)
    -
    -#Ridge and Lasso parameter Lambda
    -Lambda  = 0.01
    -Id = n*Lambda* np.eye((X.T @ X).shape[0])
    -# Gradient descent with  Ridge
    -beta_Ridge = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ (X @ beta_Ridge-y)+2*Lambda*beta_Ridge
    -    beta_Ridge -= eta*gradients
    -print('Parameters for Ridge using gradient descent')    
    -print(beta_Ridge)
    -
    -# Gradient descent with Lasso
    -beta_Lasso = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ (X @ beta_Lasso-y)+Lambda*np.sign(beta_Lasso)
    -    beta_Lasso -= eta*gradients
    -print('Parameters for Lasso using gradient descent')    
    -print(beta_Lasso)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -









    -

    But none of these can compete with Newton's method

    - -

    Note that we here have introduced automatic differentiation

    - - -
    -
    -
    -
    -
    -
    # Using Newton's method
    -from random import random, seed
    -import numpy as np
    -import autograd.numpy as np
    -from autograd import grad
    -
    -def CostOLS(beta):
    -    return (1.0/n)*np.sum((y-X @ beta)**2)
    -
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+5*x*x
    -
    -X = np.c_[np.ones((n,1)), x, x*x]
    -XT_X = X.T @ X
    -beta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    -print("Own inversion")
    -print(beta_linreg)
    -# Hessian matrix
    -H = (2.0/n)* XT_X
    -# Note that here the Hessian does not depend on the parameters beta
    -invH = np.linalg.pinv(H)
    -beta = np.random.randn(3,1)
    -Niterations = 5
    -# define the gradient
    -training_gradient = grad(CostOLS)
    -
    -for iter in range(Niterations):
    -    gradients = training_gradient(beta)
    -    beta -= invH @ gradients
    -    print(iter,gradients[0],gradients[1])
    -print("beta from own Newton code")
    -print(beta)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -









    -

    Gradient descent and Logistic regression

    - -

    Finally, we complete these examples by adding a simple code for -Logistic regression. Note the more general approach with a class for -the method. Here we use a so-called AND gate for our data set. -

    - - - -
    -
    -
    -
    -
    -
    import numpy as np
    -class LogisticRegression:
    -    def __init__(self, learning_rate=0.01, num_iterations=1000):
    -        self.learning_rate = learning_rate
    -        self.num_iterations = num_iterations
    -        self.beta_logreg = None
    -    def sigmoid(self, z):
    -        return 1 / (1 + np.exp(-z))
    -    def GDfit(self, X, y):
    -        n_data, num_features = X.shape
    -        self.beta_logreg = np.zeros(num_features)
    -        for _ in range(self.num_iterations):
    -            linear_model = X @ self.beta_logreg
    -            y_predicted = self.sigmoid(linear_model)
    -            # Gradient calculation
    -            gradient = (X.T @ (y_predicted - y))/n_data
    -            # Update beta_logreg
    -            self.beta_logreg -= self.learning_rate*gradient
    -    def predict(self, X):
    -        linear_model = X @ self.beta_logreg
    -        y_predicted = self.sigmoid(linear_model)
    -        return [1 if i >= 0.5 else 0 for i in y_predicted]
    -# Example usage
    -if __name__ == "__main__":
    -    # Sample data
    -    X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
    -    y = np.array([0, 0, 0, 1])  # This is an AND gate
    -    model = LogisticRegression(learning_rate=0.01, num_iterations=1000)
    -    model.GDfit(X, y)
    -    predictions = model.predict(X)
    -    print("Predictions:", predictions)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -









    -

    Overview video on Stochastic Gradient Descent

    - -What is Stochastic Gradient Descent -

    There are several reasons for using stochastic gradient descent. Some of these are:

    - -
      -
    1. Efficiency: Updates weights more frequently using a single or a small batch of samples, which speeds up convergence.
    2. -
    3. Hopefully avoid Local Minima
    4. -
    5. Memory Usage: Requires less memory compared to computing gradients for the entire dataset.
    6. -
    -









    -

    Batches and mini-batches

    - -

    In gradient descent we compute the cost function and its gradient for all data points we have.

    - -

    In large-scale applications such as the ILSVRC challenge, the -training data can have on order of millions of examples. Hence, it -seems wasteful to compute the full cost function over the entire -training set in order to perform only a single parameter update. A -very common approach to addressing this challenge is to compute the -gradient over batches of the training data. For example, a typical batch could contain some thousand examples from -an entire training set of several millions. This batch is then used to -perform a parameter update. -

    - -









    -

    Stochastic Gradient Descent (SGD)

    - -

    In stochastic gradient descent, the extreme case is the case where we -have only one batch, that is we include the whole data set. -

    - -

    This process is called Stochastic Gradient -Descent (SGD) (or also sometimes on-line gradient descent). This is -relatively less common to see because in practice due to vectorized -code optimizations it can be computationally much more efficient to -evaluate the gradient for 100 examples, than the gradient for one -example 100 times. Even though SGD technically refers to using a -single example at a time to evaluate the gradient, you will hear -people use the term SGD even when referring to mini-batch gradient -descent (i.e. mentions of MGD for “Minibatch Gradient Descent”, or BGD -for “Batch gradient descent” are rare to see), where it is usually -assumed that mini-batches are used. The size of the mini-batch is a -hyperparameter but it is not very common to cross-validate or bootstrap it. It is -usually based on memory constraints (if any), or set to some value, -e.g. 32, 64 or 128. We use powers of 2 in practice because many -vectorized operation implementations work faster when their inputs are -sized in powers of 2. -

    - -

    In our notes with SGD we mean stochastic gradient descent with mini-batches.

    - -









    -

    Stochastic Gradient Descent

    - -

    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 -function, which we want to minimize, can almost always be written as a -sum over \( n \) data points \( \{\mathbf{x}_i\}_{i=1}^n \), -

    -$$ -C(\mathbf{\beta}) = \sum_{i=1}^n c_i(\mathbf{x}_i, -\mathbf{\beta}). -$$ - - -









    -

    Computation of gradients

    - -

    This in turn means that the gradient can be -computed as a sum over \( i \)-gradients -

    -$$ -\nabla_\beta C(\mathbf{\beta}) = \sum_i^n \nabla_\beta c_i(\mathbf{x}_i, -\mathbf{\beta}). -$$ - -

    Stochasticity/randomness is introduced by only taking the -gradient on a subset of the data called minibatches. If there are \( n \) -data points and the size of each minibatch is \( M \), there will be \( n/M \) -minibatches. We denote these minibatches by \( B_k \) where -\( k=1,\cdots,n/M \). -

    - -









    -

    SGD example

    -

    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 -\( B_1 = (\mathbf{x}_1,\mathbf{x}_2), \cdots, B_5 = -(\mathbf{x}_9,\mathbf{x}_{10}) \). Note that if you choose \( M=1 \) you -have only a single batch with all data points and on the other extreme, -you may choose \( M=n \) resulting in a minibatch for each datapoint, i.e -\( B_k = \mathbf{x}_k \). -

    - -

    The idea is now to approximate the gradient by replacing the sum over -all data points with a sum over the data points in one the minibatches -picked at random in each gradient descent step -

    -$$ -\nabla_{\beta} -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}). -$$ - - -









    -

    The gradient step

    - -

    Thus a gradient descent step now looks like

    -$$ -\beta_{j+1} = \beta_j - \gamma_j \sum_{i \in B_k}^n \nabla_\beta c_i(\mathbf{x}_i, -\mathbf{\beta}) -$$ - -

    where \( k \) is picked at random with equal -probability from \( [1,n/M] \). An iteration over the number of -minibathces (n/M) is commonly referred to as an epoch. Thus it is -typical to choose a number of epochs and for each epoch iterate over -the number of minibatches, as exemplified in the code below. -

    - -









    -

    Simple example code

    - - - -
    -
    -
    -
    -
    -
    import numpy as np 
    -
    -n = 100 #100 datapoints 
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -n_epochs = 10 #number of epochs
    -
    -j = 0
    -for epoch in range(1,n_epochs+1):
    -    for i in range(m):
    -        k = np.random.randint(m) #Pick the k-th minibatch at random
    -        #Compute the gradient using the data in minibatch Bk
    -        #Compute new suggestion for 
    -        j += 1
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -

    Taking the gradient only on a subset of the data has two important -benefits. First, it introduces randomness which decreases the chance -that our opmization scheme gets stuck in a local minima. Second, if -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. -

    - -









    -

    When do we stop?

    - -

    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 -threshold and stop if true. However, the condition that the gradient -is zero is valid also for local minima, so this would only tell us -that we are close to a local/global minimum. However, we could also -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. -

    - -









    -

    Slightly different approach

    - -

    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. Such approaches are -also called scaling. There are many such ways to scale the learning -rate -and discussions here. See -also -https://towardsdatascience.com/learning-rate-schedules-and-adaptive-learning-rate-methods-for-deep-learning-2c8f433990d1 -for a discussion of different scaling functions for the learning rate. -

    - -









    -

    Time decay rate

    - -

    As an example, let \( e = 0,1,2,3,\cdots \) denote the current epoch and let \( t_0, t_1 > 0 \) be two fixed numbers. Furthermore, let \( t = e \cdot m + i \) where \( m \) is the number of minibatches and \( i=0,\cdots,m-1 \). Then the function $$\gamma_j(t; t_0, t_1) = \frac{t_0}{t+t_1} $$ goes to zero as the number of epochs gets large. I.e. we start with a step length \( \gamma_j (0; t_0, t_1) = t_0/t_1 \) which decays in time \( t \).

    - -

    In this way we can fix the number of epochs, compute \( \beta \) and -evaluate the cost function at the end. Repeating the computation will -give a different result since the scheme is random by design. Then we -pick the final \( \beta \) that gives the lowest value of the cost -function. -

    - - - -
    -
    -
    -
    -
    -
    import numpy as np 
    -
    -def step_length(t,t0,t1):
    -    return t0/(t+t1)
    -
    -n = 100 #100 datapoints 
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -n_epochs = 500 #number of epochs
    -t0 = 1.0
    -t1 = 10
    -
    -gamma_j = t0/t1
    -j = 0
    -for epoch in range(1,n_epochs+1):
    -    for i in range(m):
    -        k = np.random.randint(m) #Pick the k-th minibatch at random
    -        #Compute the gradient using the data in minibatch Bk
    -        #Compute new suggestion for beta
    -        t = epoch*m+i
    -        gamma_j = step_length(t,t0,t1)
    -        j += 1
    -
    -print("gamma_j after %d epochs: %g" % (n_epochs,gamma_j))
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -









    -

    Code with a Number of Minibatches which varies

    - -

    In the code here we vary the number of mini-batches.

    - - -
    -
    -
    -
    -
    -
    # Importing various packages
    -from math import exp, sqrt
    -from random import random, seed
    -import numpy as np
    -import matplotlib.pyplot as plt
    -
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+np.random.randn(n,1)
    -
    -X = np.c_[np.ones((n,1)), x]
    -XT_X = X.T @ X
    -theta_linreg = np.linalg.inv(X.T @ X) @ (X.T @ y)
    -print("Own inversion")
    -print(theta_linreg)
    -# Hessian matrix
    -H = (2.0/n)* XT_X
    -EigValues, EigVectors = np.linalg.eig(H)
    -print(f"Eigenvalues of Hessian Matrix:{EigValues}")
    -
    -theta = np.random.randn(2,1)
    -eta = 1.0/np.max(EigValues)
    -Niterations = 1000
    -
    -
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ ((X @ theta)-y)
    -    theta -= eta*gradients
    -print("theta from own gd")
    -print(theta)
    -
    -xnew = np.array([[0],[2]])
    -Xnew = np.c_[np.ones((2,1)), xnew]
    -ypredict = Xnew.dot(theta)
    -ypredict2 = Xnew.dot(theta_linreg)
    -
    -n_epochs = 50
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -t0, t1 = 5, 50
    -
    -def learning_schedule(t):
    -    return t0/(t+t1)
    -
    -theta = np.random.randn(2,1)
    -
    -for epoch in range(n_epochs):
    -# Can you figure out a better way of setting up the contributions to each batch?
    -    for i in range(m):
    -        random_index = M*np.random.randint(m)
    -        xi = X[random_index:random_index+M]
    -        yi = y[random_index:random_index+M]
    -        gradients = (2.0/M)* xi.T @ ((xi @ theta)-yi)
    -        eta = learning_schedule(epoch*m+i)
    -        theta = theta - eta*gradients
    -print("theta from own sdg")
    -print(theta)
    -
    -plt.plot(xnew, ypredict, "r-")
    -plt.plot(xnew, ypredict2, "b-")
    -plt.plot(x, y ,'ro')
    -plt.axis([0,2.0,0, 15.0])
    -plt.xlabel(r'$x$')
    -plt.ylabel(r'$y$')
    -plt.title(r'Random numbers ')
    -plt.show()
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -









    -

    Replace or not

    - -

    In the above code, we have use replacement in setting up the -mini-batches. The discussion -here may be -useful. -

    - -









    -

    Momentum based GD

    - -

    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 -

    - -$$ -\begin{align} -\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t) \nonumber \\ -\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}, -\label{_auto1} -\end{align} -$$ - -

    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 -

    - -$$ -\Delta \boldsymbol{\theta}_{t+1} = \gamma \Delta \boldsymbol{\theta}_t -\ \eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t), -$$ - -

    where we have defined \( \Delta \boldsymbol{\theta}_{t}= \boldsymbol{\theta}_t-\boldsymbol{\theta}_{t-1} \).

    - -









    -

    More on momentum based approaches

    - -

    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 -

    - -$$ -m {d^2 \mathbf{w} \over dt^2} + \mu {d \mathbf{w} \over dt }= -\nabla_w E(\mathbf{w}). -$$ - -

    We can discretize this equation in the usual way to get

    - -$$ -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}). -$$ - -

    Rearranging this equation, we can rewrite this as

    - -$$ -\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. -$$ - - -









    -

    Momentum parameter

    - -

    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: -

    - -$$ -\gamma= {m \over m +\mu \Delta t }, \qquad \eta = {(\Delta t)^2 \over m +\mu \Delta t}. -$$ - -

    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 -

    - -$$ -\begin{align} -\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t +\gamma \mathbf{v}_{t-1}) \nonumber \\ -\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}. -\label{_auto2} -\end{align} -$$ - -

    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 \).

    - -









    -

    Second moment of the gradient

    - -

    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. -

    - -

    During the last decade 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, Root Mean Squared Propagation (RMS-Prop), and -ADAM. -

    - -









    -

    RMS prop

    - -

    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 -

    - -$$ -\begin{align} -\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) -\label{_auto3}\\ -\mathbf{s}_t &=\beta \mathbf{s}_{t-1} +(1-\beta)\mathbf{g}_t^2 \nonumber \\ -\boldsymbol{\theta}_{t+1}&=&\boldsymbol{\theta}_t - \eta_t { \mathbf{g}_t \over \sqrt{\mathbf{s}_t +\epsilon}}, \nonumber -\end{align} -$$ - -

    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. -

    - -









    -

    ADAM optimizer

    - -

    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. The method isefficient when working with large -problems involving lots data and/or parameters. It is a combination of the -gradient descent with momentum algorithm and the RMSprop algorithm -discussed above. -

    - -

    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) -

    - -$$ -\begin{align} -\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) -\label{_auto4}\\ -\mathbf{m}_t &= \beta_1 \mathbf{m}_{t-1} + (1-\beta_1) \mathbf{g}_t \nonumber \\ -\mathbf{s}_t &=\beta_2 \mathbf{s}_{t-1} +(1-\beta_2)\mathbf{g}_t^2 \nonumber \\ -\boldsymbol{\mathbf{m}}_t&={\mathbf{m}_t \over 1-\beta_1^t} \nonumber \\ -\boldsymbol{\mathbf{s}}_t &={\mathbf{s}_t \over1-\beta_2^t} \nonumber \\ -\boldsymbol{\theta}_{t+1}&=\boldsymbol{\theta}_t - \eta_t { \boldsymbol{\mathbf{m}}_t \over \sqrt{\boldsymbol{\mathbf{s}}_t} +\epsilon}, \nonumber \\ -\label{_auto5} -\end{align} -$$ - -

    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 -

    - -$$ -\Delta \theta_{t+1}= -\eta_t { \boldsymbol{m}_t \over \sqrt{\sigma_t^2 + m_t^2 }+\epsilon}. -$$ - - -









    -

    Algorithms and codes for Adagrad, RMSprop and Adam

    - -

    The algorithms we have implemented are well described in the text by Goodfellow, Bengio and Courville, chapter 8.

    - -

    The codes which implement these algorithms are discussed after our presentation of automatic differentiation.

    -

    AdaGrad algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    -

    RMSProp algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    -

    ADAM algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    - -









    -

    Practical tips

    - -
      -
    • 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.
    • -
    -

    Geron's text, see chapter 11, has several interesting discussions.

    -









    Automatic differentiation

    @@ -2861,7 +1939,7 @@ of the outputs of all neurons in the previous layer. $$ \begin{equation} z_i^1 = \sum_{j=1}^{M} w_{ij}^1 x_j + b_i^1 -\label{_auto6} +\label{_auto1} \end{equation} $$ @@ -2906,7 +1984,7 @@ is obtained. $$ \begin{align} y_i^2 &= f^2\left(\sum_{j=1}^N w_{ij}^2 y_j^1 + b_i^2\right) -\label{_auto7}\\ +\label{_auto2}\\ &= f^2\left[\sum_{j=1}^N w_{ij}^2f^1\left(\sum_{k=1}^M w_{jk}^1 x_k + b_j^1\right) + b_i^2\right] \label{outputLayer2} \end{align} @@ -2917,10 +1995,10 @@ $$ $$ \begin{align} y_i^3 &= f^3\left(\sum_{j=1}^N w_{ij}^3 y_j^2 + b_i^3\right) -\label{_auto8}\\ +\label{_auto3}\\ &= f_3\left[\sum_{j} w_{ij}^3 f^2\left(\sum_{k} w_{jk}^2 f^1\left(\sum_{m} w_{km}^1 x_m + b_k^1\right) + b_j^2\right) + b_1^3\right] -\label{_auto9} +\label{_auto4} \end{align} $$ @@ -2960,7 +2038,7 @@ sum of scaled activation functions of the form $$ \begin{equation} f(x) = c_1 f(c_2 x + c_3) + c_4 -\label{_auto10} +\label{_auto5} \end{equation} $$ @@ -3002,7 +2080,7 @@ $$ b^2_2 \\ b^2_3 \\ \end{array}\right]\right). -\label{_auto11} +\label{_auto6} \end{equation} $$ @@ -3016,7 +2094,7 @@ $$ \begin{equation} y^2_i = f_2\Bigr(w^2_{i1}y^1_1 + w^2_{i2}y^1_2 + w^2_{i3}y^1_3 + b^2_i\Bigr) = f_2\left(\sum_{j=1}^3 w^2_{ij} y_j^1 + b^2_i\right). -\label{_auto12} +\label{_auto7} \end{equation} $$ @@ -3172,7 +2250,7 @@ plt.show()
    - © 1999-2024, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license + © 1999-2025, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license
    diff --git a/doc/pub/week40/html/week40.html b/doc/pub/week40/html/week40.html index 6b1494bfb..bf39f9635 100644 --- a/doc/pub/week40/html/week40.html +++ b/doc/pub/week40/html/week40.html @@ -140,8 +140,7 @@ div.toc p,a {
    -Morten Hjorth-Jensen [1, 2] +Morten Hjorth-Jensen
    - +
    -[1] Department of Physics, University of Oslo, Norway -
    -
    -[2] Department of Physics and Astronomy and Facility for Rare Ion Beams, Michigan State University, USA +Department of Physics, University of Oslo, Norway

    -

    September 30-October 4, 2024

    +

    September 29-October 3, 2025


    -









    -

    Plans for week 40

    -









    Lecture Monday September 30, 2024

    @@ -435,841 +348,6 @@ MathJax.Hub.Config({
    -









    -

    Summary from last week, using gradient descent methods, limitations

    - -
      -
    • 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.
    • -
    • Gradients are computationally expensive to calculate for large datasets. In many cases in statistics and ML, the cost/loss/risk function is a sum of terms, with one term for each data point. For example, in linear regression, \( E \propto \sum_{i=1}^n (y_i - \mathbf{w}^T\cdot\mathbf{x}_i)^2 \); for logistic regression, the square error is replaced by the cross entropy. To calculate the gradient we have to sum over all \( n \) data points. Doing this at every GD step becomes extremely computationally expensive. An ingenious solution to this, is to calculate the gradients using small subsets of the data called "mini batches". This has the added benefit of introducing stochasticity into our algorithm.
    • -
    • GD is very sensitive to choices of learning rates. GD is extremely sensitive to the choice of learning rates. If the learning rate is very small, the training process take an extremely long time. For larger learning rates, GD can diverge and give poor results. Furthermore, depending on what the local landscape looks like, we have to modify the learning rates to ensure convergence. Ideally, we would adaptively choose the learning rates to match the landscape.
    • -
    • GD treats all directions in parameter space uniformly. Another major drawback of GD is that unlike Newton's method, the learning rate for GD is the same in all directions in parameter space. For this reason, the maximum learning rate is set by the behavior of the steepest direction and this can significantly slow down training. Ideally, we would like to take large steps in flat directions and small steps in steep directions. Since we are exploring rugged landscapes where curvatures change, this requires us to keep track of not only the gradient but second derivatives. The ideal scenario would be to calculate the Hessian but this proves to be too computationally expensive.
    • -
    • GD can take exponential time to escape saddle points, even with random initialization. As we mentioned, GD is extremely sensitive to initial condition since it determines the particular local minimum GD would eventually reach. However, even with a good initialization scheme, through the introduction of randomness, GD can still take exponential time to escape saddle points.
    • -
    -









    -

    Simple implementation of GD for OLS, Ridge and Lasso

    - -

    Last week we studied both several gradient methods. With and without an update of the learning. -We summarize some of these here for the methods we hvae studied in project one, without the inclusion of momentum. -

    - - -
    -
    -
    -
    -
    -
    from random import random, seed
    -import numpy as np
    -
    -# the number of datapoints with a 2nd-order polynomial
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+5*x*x
    -# Design matrix including the intercept
    -# No scaling of data of and all data used for training 
    -X = np.c_[np.ones((n,1)), x, x*x]
    -# Learning rate and number of iterations
    -eta = 0.05
    -Niterations = 100
    -
    -# OLS part
    -beta_OLS = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradient = (2.0/n)*X.T @ (X @ beta_OLS-y)
    -    beta_OLS -= eta*gradient
    -print('Parameters for OLS using gradient descent')    
    -print(beta_OLS)
    -
    -#Ridge and Lasso parameter Lambda
    -Lambda  = 0.01
    -Id = n*Lambda* np.eye((X.T @ X).shape[0])
    -# Gradient descent with  Ridge
    -beta_Ridge = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ (X @ beta_Ridge-y)+2*Lambda*beta_Ridge
    -    beta_Ridge -= eta*gradients
    -print('Parameters for Ridge using gradient descent')    
    -print(beta_Ridge)
    -
    -# Gradient descent with Lasso
    -beta_Lasso = np.random.randn(3,1)
    -gradient = np.zeros(3)
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ (X @ beta_Lasso-y)+Lambda*np.sign(beta_Lasso)
    -    beta_Lasso -= eta*gradients
    -print('Parameters for Lasso using gradient descent')    
    -print(beta_Lasso)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -









    -

    But none of these can compete with Newton's method

    - -

    Note that we here have introduced automatic differentiation

    - - -
    -
    -
    -
    -
    -
    # Using Newton's method
    -from random import random, seed
    -import numpy as np
    -import autograd.numpy as np
    -from autograd import grad
    -
    -def CostOLS(beta):
    -    return (1.0/n)*np.sum((y-X @ beta)**2)
    -
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+5*x*x
    -
    -X = np.c_[np.ones((n,1)), x, x*x]
    -XT_X = X.T @ X
    -beta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)
    -print("Own inversion")
    -print(beta_linreg)
    -# Hessian matrix
    -H = (2.0/n)* XT_X
    -# Note that here the Hessian does not depend on the parameters beta
    -invH = np.linalg.pinv(H)
    -beta = np.random.randn(3,1)
    -Niterations = 5
    -# define the gradient
    -training_gradient = grad(CostOLS)
    -
    -for iter in range(Niterations):
    -    gradients = training_gradient(beta)
    -    beta -= invH @ gradients
    -    print(iter,gradients[0],gradients[1])
    -print("beta from own Newton code")
    -print(beta)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -









    -

    Gradient descent and Logistic regression

    - -

    Finally, we complete these examples by adding a simple code for -Logistic regression. Note the more general approach with a class for -the method. Here we use a so-called AND gate for our data set. -

    - - - -
    -
    -
    -
    -
    -
    import numpy as np
    -class LogisticRegression:
    -    def __init__(self, learning_rate=0.01, num_iterations=1000):
    -        self.learning_rate = learning_rate
    -        self.num_iterations = num_iterations
    -        self.beta_logreg = None
    -    def sigmoid(self, z):
    -        return 1 / (1 + np.exp(-z))
    -    def GDfit(self, X, y):
    -        n_data, num_features = X.shape
    -        self.beta_logreg = np.zeros(num_features)
    -        for _ in range(self.num_iterations):
    -            linear_model = X @ self.beta_logreg
    -            y_predicted = self.sigmoid(linear_model)
    -            # Gradient calculation
    -            gradient = (X.T @ (y_predicted - y))/n_data
    -            # Update beta_logreg
    -            self.beta_logreg -= self.learning_rate*gradient
    -    def predict(self, X):
    -        linear_model = X @ self.beta_logreg
    -        y_predicted = self.sigmoid(linear_model)
    -        return [1 if i >= 0.5 else 0 for i in y_predicted]
    -# Example usage
    -if __name__ == "__main__":
    -    # Sample data
    -    X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
    -    y = np.array([0, 0, 0, 1])  # This is an AND gate
    -    model = LogisticRegression(learning_rate=0.01, num_iterations=1000)
    -    model.GDfit(X, y)
    -    predictions = model.predict(X)
    -    print("Predictions:", predictions)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -









    -

    Overview video on Stochastic Gradient Descent

    - -What is Stochastic Gradient Descent -

    There are several reasons for using stochastic gradient descent. Some of these are:

    - -
      -
    1. Efficiency: Updates weights more frequently using a single or a small batch of samples, which speeds up convergence.
    2. -
    3. Hopefully avoid Local Minima
    4. -
    5. Memory Usage: Requires less memory compared to computing gradients for the entire dataset.
    6. -
    -









    -

    Batches and mini-batches

    - -

    In gradient descent we compute the cost function and its gradient for all data points we have.

    - -

    In large-scale applications such as the ILSVRC challenge, the -training data can have on order of millions of examples. Hence, it -seems wasteful to compute the full cost function over the entire -training set in order to perform only a single parameter update. A -very common approach to addressing this challenge is to compute the -gradient over batches of the training data. For example, a typical batch could contain some thousand examples from -an entire training set of several millions. This batch is then used to -perform a parameter update. -

    - -









    -

    Stochastic Gradient Descent (SGD)

    - -

    In stochastic gradient descent, the extreme case is the case where we -have only one batch, that is we include the whole data set. -

    - -

    This process is called Stochastic Gradient -Descent (SGD) (or also sometimes on-line gradient descent). This is -relatively less common to see because in practice due to vectorized -code optimizations it can be computationally much more efficient to -evaluate the gradient for 100 examples, than the gradient for one -example 100 times. Even though SGD technically refers to using a -single example at a time to evaluate the gradient, you will hear -people use the term SGD even when referring to mini-batch gradient -descent (i.e. mentions of MGD for “Minibatch Gradient Descent”, or BGD -for “Batch gradient descent” are rare to see), where it is usually -assumed that mini-batches are used. The size of the mini-batch is a -hyperparameter but it is not very common to cross-validate or bootstrap it. It is -usually based on memory constraints (if any), or set to some value, -e.g. 32, 64 or 128. We use powers of 2 in practice because many -vectorized operation implementations work faster when their inputs are -sized in powers of 2. -

    - -

    In our notes with SGD we mean stochastic gradient descent with mini-batches.

    - -









    -

    Stochastic Gradient Descent

    - -

    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 -function, which we want to minimize, can almost always be written as a -sum over \( n \) data points \( \{\mathbf{x}_i\}_{i=1}^n \), -

    -$$ -C(\mathbf{\beta}) = \sum_{i=1}^n c_i(\mathbf{x}_i, -\mathbf{\beta}). -$$ - - -









    -

    Computation of gradients

    - -

    This in turn means that the gradient can be -computed as a sum over \( i \)-gradients -

    -$$ -\nabla_\beta C(\mathbf{\beta}) = \sum_i^n \nabla_\beta c_i(\mathbf{x}_i, -\mathbf{\beta}). -$$ - -

    Stochasticity/randomness is introduced by only taking the -gradient on a subset of the data called minibatches. If there are \( n \) -data points and the size of each minibatch is \( M \), there will be \( n/M \) -minibatches. We denote these minibatches by \( B_k \) where -\( k=1,\cdots,n/M \). -

    - -









    -

    SGD example

    -

    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 -\( B_1 = (\mathbf{x}_1,\mathbf{x}_2), \cdots, B_5 = -(\mathbf{x}_9,\mathbf{x}_{10}) \). Note that if you choose \( M=1 \) you -have only a single batch with all data points and on the other extreme, -you may choose \( M=n \) resulting in a minibatch for each datapoint, i.e -\( B_k = \mathbf{x}_k \). -

    - -

    The idea is now to approximate the gradient by replacing the sum over -all data points with a sum over the data points in one the minibatches -picked at random in each gradient descent step -

    -$$ -\nabla_{\beta} -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}). -$$ - - -









    -

    The gradient step

    - -

    Thus a gradient descent step now looks like

    -$$ -\beta_{j+1} = \beta_j - \gamma_j \sum_{i \in B_k}^n \nabla_\beta c_i(\mathbf{x}_i, -\mathbf{\beta}) -$$ - -

    where \( k \) is picked at random with equal -probability from \( [1,n/M] \). An iteration over the number of -minibathces (n/M) is commonly referred to as an epoch. Thus it is -typical to choose a number of epochs and for each epoch iterate over -the number of minibatches, as exemplified in the code below. -

    - -









    -

    Simple example code

    - - - -
    -
    -
    -
    -
    -
    import numpy as np 
    -
    -n = 100 #100 datapoints 
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -n_epochs = 10 #number of epochs
    -
    -j = 0
    -for epoch in range(1,n_epochs+1):
    -    for i in range(m):
    -        k = np.random.randint(m) #Pick the k-th minibatch at random
    -        #Compute the gradient using the data in minibatch Bk
    -        #Compute new suggestion for 
    -        j += 1
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -

    Taking the gradient only on a subset of the data has two important -benefits. First, it introduces randomness which decreases the chance -that our opmization scheme gets stuck in a local minima. Second, if -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. -

    - -









    -

    When do we stop?

    - -

    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 -threshold and stop if true. However, the condition that the gradient -is zero is valid also for local minima, so this would only tell us -that we are close to a local/global minimum. However, we could also -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. -

    - -









    -

    Slightly different approach

    - -

    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. Such approaches are -also called scaling. There are many such ways to scale the learning -rate -and discussions here. See -also -https://towardsdatascience.com/learning-rate-schedules-and-adaptive-learning-rate-methods-for-deep-learning-2c8f433990d1 -for a discussion of different scaling functions for the learning rate. -

    - -









    -

    Time decay rate

    - -

    As an example, let \( e = 0,1,2,3,\cdots \) denote the current epoch and let \( t_0, t_1 > 0 \) be two fixed numbers. Furthermore, let \( t = e \cdot m + i \) where \( m \) is the number of minibatches and \( i=0,\cdots,m-1 \). Then the function $$\gamma_j(t; t_0, t_1) = \frac{t_0}{t+t_1} $$ goes to zero as the number of epochs gets large. I.e. we start with a step length \( \gamma_j (0; t_0, t_1) = t_0/t_1 \) which decays in time \( t \).

    - -

    In this way we can fix the number of epochs, compute \( \beta \) and -evaluate the cost function at the end. Repeating the computation will -give a different result since the scheme is random by design. Then we -pick the final \( \beta \) that gives the lowest value of the cost -function. -

    - - - -
    -
    -
    -
    -
    -
    import numpy as np 
    -
    -def step_length(t,t0,t1):
    -    return t0/(t+t1)
    -
    -n = 100 #100 datapoints 
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -n_epochs = 500 #number of epochs
    -t0 = 1.0
    -t1 = 10
    -
    -gamma_j = t0/t1
    -j = 0
    -for epoch in range(1,n_epochs+1):
    -    for i in range(m):
    -        k = np.random.randint(m) #Pick the k-th minibatch at random
    -        #Compute the gradient using the data in minibatch Bk
    -        #Compute new suggestion for beta
    -        t = epoch*m+i
    -        gamma_j = step_length(t,t0,t1)
    -        j += 1
    -
    -print("gamma_j after %d epochs: %g" % (n_epochs,gamma_j))
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -









    -

    Code with a Number of Minibatches which varies

    - -

    In the code here we vary the number of mini-batches.

    - - -
    -
    -
    -
    -
    -
    # Importing various packages
    -from math import exp, sqrt
    -from random import random, seed
    -import numpy as np
    -import matplotlib.pyplot as plt
    -
    -n = 100
    -x = 2*np.random.rand(n,1)
    -y = 4+3*x+np.random.randn(n,1)
    -
    -X = np.c_[np.ones((n,1)), x]
    -XT_X = X.T @ X
    -theta_linreg = np.linalg.inv(X.T @ X) @ (X.T @ y)
    -print("Own inversion")
    -print(theta_linreg)
    -# Hessian matrix
    -H = (2.0/n)* XT_X
    -EigValues, EigVectors = np.linalg.eig(H)
    -print(f"Eigenvalues of Hessian Matrix:{EigValues}")
    -
    -theta = np.random.randn(2,1)
    -eta = 1.0/np.max(EigValues)
    -Niterations = 1000
    -
    -
    -for iter in range(Niterations):
    -    gradients = 2.0/n*X.T @ ((X @ theta)-y)
    -    theta -= eta*gradients
    -print("theta from own gd")
    -print(theta)
    -
    -xnew = np.array([[0],[2]])
    -Xnew = np.c_[np.ones((2,1)), xnew]
    -ypredict = Xnew.dot(theta)
    -ypredict2 = Xnew.dot(theta_linreg)
    -
    -n_epochs = 50
    -M = 5   #size of each minibatch
    -m = int(n/M) #number of minibatches
    -t0, t1 = 5, 50
    -
    -def learning_schedule(t):
    -    return t0/(t+t1)
    -
    -theta = np.random.randn(2,1)
    -
    -for epoch in range(n_epochs):
    -# Can you figure out a better way of setting up the contributions to each batch?
    -    for i in range(m):
    -        random_index = M*np.random.randint(m)
    -        xi = X[random_index:random_index+M]
    -        yi = y[random_index:random_index+M]
    -        gradients = (2.0/M)* xi.T @ ((xi @ theta)-yi)
    -        eta = learning_schedule(epoch*m+i)
    -        theta = theta - eta*gradients
    -print("theta from own sdg")
    -print(theta)
    -
    -plt.plot(xnew, ypredict, "r-")
    -plt.plot(xnew, ypredict2, "b-")
    -plt.plot(x, y ,'ro')
    -plt.axis([0,2.0,0, 15.0])
    -plt.xlabel(r'$x$')
    -plt.ylabel(r'$y$')
    -plt.title(r'Random numbers ')
    -plt.show()
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -









    -

    Replace or not

    - -

    In the above code, we have use replacement in setting up the -mini-batches. The discussion -here may be -useful. -

    - -









    -

    Momentum based GD

    - -

    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 -

    - -$$ -\begin{align} -\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t) \nonumber \\ -\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}, -\label{_auto1} -\end{align} -$$ - -

    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 -

    - -$$ -\Delta \boldsymbol{\theta}_{t+1} = \gamma \Delta \boldsymbol{\theta}_t -\ \eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t), -$$ - -

    where we have defined \( \Delta \boldsymbol{\theta}_{t}= \boldsymbol{\theta}_t-\boldsymbol{\theta}_{t-1} \).

    - -









    -

    More on momentum based approaches

    - -

    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 -

    - -$$ -m {d^2 \mathbf{w} \over dt^2} + \mu {d \mathbf{w} \over dt }= -\nabla_w E(\mathbf{w}). -$$ - -

    We can discretize this equation in the usual way to get

    - -$$ -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}). -$$ - -

    Rearranging this equation, we can rewrite this as

    - -$$ -\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. -$$ - - -









    -

    Momentum parameter

    - -

    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: -

    - -$$ -\gamma= {m \over m +\mu \Delta t }, \qquad \eta = {(\Delta t)^2 \over m +\mu \Delta t}. -$$ - -

    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 -

    - -$$ -\begin{align} -\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t +\gamma \mathbf{v}_{t-1}) \nonumber \\ -\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}. -\label{_auto2} -\end{align} -$$ - -

    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 \).

    - -









    -

    Second moment of the gradient

    - -

    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. -

    - -

    During the last decade 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, Root Mean Squared Propagation (RMS-Prop), and -ADAM. -

    - -









    -

    RMS prop

    - -

    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 -

    - -$$ -\begin{align} -\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) -\label{_auto3}\\ -\mathbf{s}_t &=\beta \mathbf{s}_{t-1} +(1-\beta)\mathbf{g}_t^2 \nonumber \\ -\boldsymbol{\theta}_{t+1}&=&\boldsymbol{\theta}_t - \eta_t { \mathbf{g}_t \over \sqrt{\mathbf{s}_t +\epsilon}}, \nonumber -\end{align} -$$ - -

    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. -

    - -









    -

    ADAM optimizer

    - -

    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. The method isefficient when working with large -problems involving lots data and/or parameters. It is a combination of the -gradient descent with momentum algorithm and the RMSprop algorithm -discussed above. -

    - -

    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) -

    - -$$ -\begin{align} -\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) -\label{_auto4}\\ -\mathbf{m}_t &= \beta_1 \mathbf{m}_{t-1} + (1-\beta_1) \mathbf{g}_t \nonumber \\ -\mathbf{s}_t &=\beta_2 \mathbf{s}_{t-1} +(1-\beta_2)\mathbf{g}_t^2 \nonumber \\ -\boldsymbol{\mathbf{m}}_t&={\mathbf{m}_t \over 1-\beta_1^t} \nonumber \\ -\boldsymbol{\mathbf{s}}_t &={\mathbf{s}_t \over1-\beta_2^t} \nonumber \\ -\boldsymbol{\theta}_{t+1}&=\boldsymbol{\theta}_t - \eta_t { \boldsymbol{\mathbf{m}}_t \over \sqrt{\boldsymbol{\mathbf{s}}_t} +\epsilon}, \nonumber \\ -\label{_auto5} -\end{align} -$$ - -

    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 -

    - -$$ -\Delta \theta_{t+1}= -\eta_t { \boldsymbol{m}_t \over \sqrt{\sigma_t^2 + m_t^2 }+\epsilon}. -$$ - - -









    -

    Algorithms and codes for Adagrad, RMSprop and Adam

    - -

    The algorithms we have implemented are well described in the text by Goodfellow, Bengio and Courville, chapter 8.

    - -

    The codes which implement these algorithms are discussed after our presentation of automatic differentiation.

    -

    AdaGrad algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    -

    RMSProp algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    -

    ADAM algorithm, taken from Goodfellow et al

    - -

    -
    -

    -
    -

    - -









    -

    Practical tips

    - -
      -
    • 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.
    • -
    -

    Geron's text, see chapter 11, has several interesting discussions.

    -









    Automatic differentiation

    @@ -2938,7 +2016,7 @@ of the outputs of all neurons in the previous layer. $$ \begin{equation} z_i^1 = \sum_{j=1}^{M} w_{ij}^1 x_j + b_i^1 -\label{_auto6} +\label{_auto1} \end{equation} $$ @@ -2983,7 +2061,7 @@ is obtained. $$ \begin{align} y_i^2 &= f^2\left(\sum_{j=1}^N w_{ij}^2 y_j^1 + b_i^2\right) -\label{_auto7}\\ +\label{_auto2}\\ &= f^2\left[\sum_{j=1}^N w_{ij}^2f^1\left(\sum_{k=1}^M w_{jk}^1 x_k + b_j^1\right) + b_i^2\right] \label{outputLayer2} \end{align} @@ -2994,10 +2072,10 @@ $$ $$ \begin{align} y_i^3 &= f^3\left(\sum_{j=1}^N w_{ij}^3 y_j^2 + b_i^3\right) -\label{_auto8}\\ +\label{_auto3}\\ &= f_3\left[\sum_{j} w_{ij}^3 f^2\left(\sum_{k} w_{jk}^2 f^1\left(\sum_{m} w_{km}^1 x_m + b_k^1\right) + b_j^2\right) + b_1^3\right] -\label{_auto9} +\label{_auto4} \end{align} $$ @@ -3037,7 +2115,7 @@ sum of scaled activation functions of the form $$ \begin{equation} f(x) = c_1 f(c_2 x + c_3) + c_4 -\label{_auto10} +\label{_auto5} \end{equation} $$ @@ -3079,7 +2157,7 @@ $$ b^2_2 \\ b^2_3 \\ \end{array}\right]\right). -\label{_auto11} +\label{_auto6} \end{equation} $$ @@ -3093,7 +2171,7 @@ $$ \begin{equation} y^2_i = f_2\Bigr(w^2_{i1}y^1_1 + w^2_{i2}y^1_2 + w^2_{i3}y^1_3 + b^2_i\Bigr) = f_2\left(\sum_{j=1}^3 w^2_{ij} y_j^1 + b^2_i\right). -\label{_auto12} +\label{_auto7} \end{equation} $$ @@ -3249,7 +2327,7 @@ plt.show()
    - © 1999-2024, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license + © 1999-2025, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license
    diff --git a/doc/pub/week40/ipynb/ipynb-week40-src.tar.gz b/doc/pub/week40/ipynb/ipynb-week40-src.tar.gz index 116180ff4ff6f5ec2b1a4c5aee2b97bb73e0db47..67627a2f7c80c1cdd34c4aae2461db4815f9136a 100644 GIT binary patch literal 34323 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 XhEXsIM!_f;1=Iil|FrXY0G0p%s{W8* literal 526744 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

    D!w{O- z6P<&zgBdO3w5mM&b8a{{+*7M$((}OcTzkd%iF?s-{Y2Hzydl3u$I)}`yRYG!=!7jN z;w@NkHd-3&$Fu_4omciZ5!a3A*fS)a>DfvCB9K!Z^TINTb1x)7zj7=HwzCA4 zwqslWcr6u~o$~rJH$3O|7%YT{D0sw@j4#@X!;JPAf-N_k@-T)-8Puoz|T7ym=7HXC%zD9hVGpn%%TU^TJ?!3#39?SDhtUZn%}sGN0) zmTZuj2f^MEi;LAVBrjo=3xI>H=O4OMaF@kYFWykJzd&U_addlkf=t{YCA`IM8;@?& zk*PTrC*LnU4&SzU=f!ztr)ajotXXhN z(g4pLL(}l_m=;6$^qhlh0r2!?=oAYdj9P%vz<%0}2FiLh;uy+$XcWSedZtiJ<{QU% zxMA_h1%q*38)#zvGPPSpsf$638sPJ{%P(G3>UYq|BnzNyP`6HTyd-5gAMk7#-&@k~ zA>|VGZC|RWZYM48Pthdsv(AsHlZg~VR7adF!NH5HRGQ{I?=?k&wo1>MXxk4JC7|Zv zTETt=HI8ZMQp8tePdlh?TL-J1Yx}7`cVg4TVqwFhdeoU8ew+WvpMCu`hY?ry>O1I* zQL(F$@UMX1`+ZL0CJJ>KVzr5nDJ@;aTrAEhONzJ1o|!}ty%P+!Stf)S9xEBqqT=bm zpCncW=a3V3>Xm=}j;?Q4(scev{qD+jwC(wv%tXuVRpDQKm4rn;9@jR$sDgS92IJ#)~gv`UAm z&$==Mxw!2^GsZtFXi+`G=dQnN^H7O4*}EhlS(K^+cagSad2Ts?0!+pYSYI5-&25=a zw<|rXx#9Td;sq}C;<~Frhg766pQ!S8gV`yf;DVpR56Q+QoR)|hstnsHQ{C)_g^j7E zEGG_XduS~QeQADq^?-1-B`!=X^et@kY|O%=3{djXFVO3Vhr+W&bZOOdgFEH#s8;D@Qt+ zJ)c@D9mAPO$HTVA{-$+y(<$9&G_w5$ne(mk$&Vaq3MTTomS68Xw-k_bd*4ewdHB7G zKh)c0Pt0rSCs4}-LlMDRB&5oaJa7q zn{B)ytXMn>r(;R08JRzyGS}zr%MW2FZABf5@wb$1;>ezL7?YVz?-E4lK`pmVtFzMR zNDPcckKDTmRU81x^!RxCLA&C*b-RUU?+@*ff93K{)Lz$Fbdgc!>}RO>6v>CXj|9=_ zyUre2N9Vcnb3n^5FJ{Y4TgXt1?KE$R{{hgTx$8U~&Ut?s;TzPJgdBO}%?2wI?1t33 z5!M)Pv@yuXEh(Y*u+tzZa2u?sE+oJ^wPOrbGE za>b4p)P+<4m|C3sM_&K$Tj5tloPXD&{ZBWeyMI`fCh=i)xkpcc~7C3+Vp zcxC9>?VDX!EWxF|S-+s*{G&561*ofZq`Tm+(YwB?*S2Xxx7?z|UTu<8;B^nd`o{RE ze}UxBo^_srd0#r~o`?mla8N*|-)}TNtO9(vo#E%Zij14Wi3|=wlr}28-rweuQnCJ% zNAIDcUP^?P5kiN4I7N!IQQA1|9rO}VZ@LeXNI!1`DIrY1Y)cIoe^M;Y z8YWh2wejk6jp<|k_DYPB3#~Cz5-=5_uwp2rLj4-)b88n3<#}cIz9rcGhQ-d?*A`h> z&jBZ0)h&EyD|7c63rzV#SOqSAB3~0(o_?gaTYe{#T3`Z2nvu-($MCEO>|*LCCW~iO zQ}-iJ>{?MCete{W{|OpR)l2i$ioLz;?X$da(e)59^VMY{nHDNo=_pqOU4}>bPpMhn zKECrvne!u>m1v9&3L)$L>^L4obomJ_Wx1Wds#Gwi@wk&JZRq<2wD*By@^tN{lL|d6 z=i}Iq+4bJL7t`NJ_N(H;OdLS#ngzSW^d0$O7#XaF@1@`+&yEYnJ{bEl$HiOqzadl} zVJos^+JYMy*fnKi@yU{%Cz1Lz{lVJ-m#0Fyns~4US|`#v3Vg@nD0}hcJzM9CB9X5| z{#$#QPSCAAZX(y-g|ifljSq6+*zn}G&Krzer6l*MX_w+QB z1(QSAu#EZeU?P2MWW;Lz7?Zgn-<@3_Ca>edp8e|4i&YPhp-!#-I;-npVj##IRZh9U zBjzGF%Bn2J5YwQpe8GS}+;Ehx_qPzz;CmtBvu+6sFe#v_S@d!T$<$;; z3h>wu#k&XV6yq@C8LuIErv()nCZik#SHVMx~hcB&n0zfC3kOkfVSIDQ*!$ zim@(xWeqqd6ruB43*I3(o>gfbdFg%aD0&Yy7nF(bQN@EXNPZ!@HStqg z%}LNU+pArPC;~K1I_maI6paMGhmOCC20FOI!xqg;npTxyaR<1eiAS7b3G%<~AYm^z zaw;v`A_@dA*tU4AQfeV){k=lF-~I(Y-b1}J2z!cAxJ7YFqp@F*DB(*%2tRt0lh)T3 zUyJ{w%JY0Wuj3BTy-Mbnd_u{7R&D+B5yk`;B&t;W3(qM&YOSQc`;7R*gKw`$^MV&U zB%ppeg(Px3ieidkPu8);cJK%7Ab?=Vx$H{mR&I)!@%_34H|nkLc=^@*g5W^I?obI6 z9rNfk5?9mL)a@(tB;sq~96xk>ls+YBIc;%uT1SbwsFBj8scV4Qq}_b;bch{96VG2m z4BkO2Z1Q&oJ>m0oN_23y0hS&#K|uT~khD*(op&XSjb~xZ2%G=(SM^2@*+Am7+5go7 zaMoN8yshtR%Q0CWD>)h*8I`FsyK~%kyc11d@xYw`8saC)`x#T#u$?_XzzM@V@<|&1 zf);SmZhMH|;AvL)Vto5rq7-DK5KWbiX$2oW_zwjm}Rma%k zo@-$tO~tbBolC%jg4J;IXKDy>%+?*94^Z=TOa+l;U zRTJv3LFO$t=jQfQG;f^Rs(wubtBk5w#zOs8o%XvNyR@^Ix_;y5RNVU!~#ltkr&P{V9q|obrlr@%E--5Jx zo1a97j@ar-W?uegqaVI~R2sJdS31ctB?ihv3w= z;TRWV;dIRVh#n*V<$C;{vZHQNtr-q|KGdO%q-XkJqSLj%Jtj{A*sb(@c`B z7Wjg@D05>6n8!3qaE2=M744rPQ>!W^GrJg4IOeg)P*B4KefHo3Qj1@>M!WHgQNJY9s~!6ytMjzuYkHo$GfXAO_{X?CD0V%c zr(B{m*7u$wIH=JD5r5{Om2p(32zkY686U_a!#}dW`kXbAnev<>Q`IME5HD!J;RG^Bcp3TNuT7WIj3r#n;dtW9P2f5l z=aBU#{2j(m$>aW$L5^95U94YLYq!<2R_6R?( zjkZf0ut4(kD#zu(rGc1SW*@Gu><6YJmkI8Du1#kX<~i))FDzwp{L#fmGi8D$d1@7` z*FL=KBdy8z!ml|s_+m6rQ&_j2Y}r{2m0Ao55Lmas|Ia1 zreQ*Zd$B$DQ9%(=EhfJB95*KEzvQ;~Mg>Y5kNdz+PXKMHm!$1Wq+hYaEi*MwMn9fE zYdqrwg>5=JWC$g{YT3x}Zf4+exBiz!OX&NJvRyG(6dJ3W`9wJCDzu9Kjk?L1Fonsn zO8dA<5N=UjUdK{8CLaw6TKa@f3^N4<<>(2D^QIbUV2l!gs#~ zkC;>{KN(!lAIs{z!e*fq(Y(^~7{2Bc4&@U!>3+I=G0fJJwL;AY!SS653vmJ&nGA9I}(pQLz21o+5GM*y?PRALiG&wbX-wRhS9}G@J1zli#RQwmiepYHe!8VQ9^uF zOnvk9$#TL*EaVH1h5X#lxMqxC?B{Xtt4Grrc-uH2f_g-yAQ-RLJ*jjSg^hBC30@gZ zRq+}M${&oN+ScFASoA1Z?(j&VpDg!SYf2E${pd#7b>d{X=5IXw=v&;JsYuC_|&g>M|^(6DlNHTXe zh9Uf+p%`u}WH7UI=Ld3Dxrk50K?g@Y#LTFJ^6m!M!J1L zas7`hhGc?v_|wgySuW@CS>P0-OMe_rWc;rdUm;2s(K`IJoH*|HB0+O>-hP;$Qf4Cn zS3s!0-M#pP#;Z1uY|*YCGK8N4?4;QPdyN|P1qfo=#{sV(N~HxW-RAqea&CccozD8v z;$T}~r!kFU4#;Z}SV_NH6y&xRcQ6*wTT&=JN`Ui%qXM*B-Z(Co?8GD7@ReYs4Xvmk z=;?7dJIkMOcL2ICrYIB}wB$H8@)}p0Q@|cr9Zi&9gKey}J6!FVn$S&}|NM0R>*6NS z8g!UWxodq-0tzS60nOu>JVlX#x+{`dWrcH?@jLejDnT3cK9=2F|Qs_)CzT;HcW6dPPGlt02obeX)&}ieGAj!|Mpuz zSXshhrt+{+Rf*UF>0EqnSp6dPejX^W?gP3&j>cHPt+ikXIV`##H2Ftsy1@LcfUau? z1E&Ac1@b*HQS`#(deu#Tsnr)Cqu)}e$YSIa)Xw0ThV*_akA1VNs zkdrg}h%tG4-P-?Bo%}Bk`4EM={o1d<-|S!S?SC%JG#JFV0yOA)z5o9F z{^zoZjWh%JLlw~P|M<4QF1nJy>`6Xq|DyN*9>p(mz(TN#!9V`v+y3jZL{aF9T|^N; zUv&JxNAXnp~a34$Pan9Y9gb zf44^+$+xWSzW1hPGcy!R>k1+a4BG|G>nK#G7C7pBzpUrEJ=-u}MGA89&H*B&yJ#n~ zKpj8=-5?jO2ZsfI#Oya`GI3 z144iz<3pSR@xR+O0W~xGQy9_$7Uve+5B7dpY)O!ezQy&02-aMfE2QPMRDoFV{ zAcul#@(eJMedK^JFRUs@B=k@@#-!N@FUnO6G5D@`D}aVidjJbvUoYM*tUqh`nsKvh zJWm<;YAe=Uwpf>3K7$xzZXacomF{T|;E9tIJeDal}+0g zIP}Hd>~R9(6E_AjUW4>@DyMsIb>R)D6a|d2Nq}q_P`y4E;h6Curb?gV$<1}7v z7erVy&x~UWB1);H`|JQtedujRW6CnXqXGgGSs%IhdB=|aXsCNP1F#*@K{evOc&+U` zz|vETw1ou#Y*MPme*A^U$%6JEyfyZf;v7H}wb&xJX+_z;Iq<&w8uNj-8PJcm`sNSb zKJ4*W+RDq=cM*^$2dvQdG~(p0ZrF23%WW&?Xr}LV|L@gjMzz#i{SBwZZg$3L)>1>mvP$WEqhd7V4$;cv&SV8>-c4*Ee=>eD zb06#+Yf~yC3=a{z?nPKZpgKgUYDco zPQ|z7#K(Vn|7PL|=iD!z-O`Sky~!MeVg z$BU9N3%CG*U;UP%eIhr-Dp^lTXE*q8;eHK{8Kup<<78E%k*zXTtd!Q}Exct>A3?Pu z)?%Nz7DrcZ+{k-#I=1tGml=-q`x=thNJHl?nc4nIC;5=XbJBK1xpCcj2Pn(9t`#$2a~zljo|4~Pyxjq0K5yRe`JQgc z#M#GPjmfByc_aQ0V`mu_)!*%X1tg?H8iqznQa~6&N*V>}Zjc7)5*WH0q!bD1?vm~r zy1SX7yPg^U_qngmvGm#2-$i1!o@@n4b@`g8 zeel<04Jc2cq97|#HGS`k;>X;OW80-KzAh_3gh{9Ux)m9)*Qz*P_DT)T=`Q3Fn@183 zL9oDw{by$`y|%%eZkj5YD%6i7w`3L)ZdKPkKjAhqHo}0bd8;zQ4gOpFNRcaeJUT2n zzADJi{2o}b{oSgzdD?M%*-ERfc?oj(fX0{}(?XU+)`PgYaFj!yL>I^v<9NbwUisBM z{sl?WGEnw%(H1sx)T^%ECeASe0$~!BE12K63^gW35rF93#!TOJY{O8?w0#ScUddvB z%^gjtYs1Q4uPd~EcKBlZuchaRL+mP1zd4bnU~yO97mRH4s#;BcpY~Y+O;^ck{{?r} zjr_x(p$~%#NTd6|>yEV1aH}Vf?n0$NaHXcXJQ#8;V9WB{E~-)L4`7{m00K)TjszkM zuXac4P~FeX2$8>k?i1X@p2aof;zy#QLGtu4xC}x};*u(L2-VznrigU5)}=7L3-)!~S+EuoT?=5m3kv2qCj00(K6j(OQJ# zONPNIk9iT`ps)vG0t8l6IqmI2qA$paL3$hGO^(5ds872eL`Yo%&%e*;-FtE~X=?IG zf@VrYR0jvL>JoDkJ!IwwB?#9wi{Jh$IoPH2bC3i5y2+rixfyfwEL@`HZTB`B5Z~Ch zIjn)##wpl;ZXATOjx#X7J)UJfea13LR8>QJj6fX?9tt`3vPOQ8;$iRQ#*HGxUP*e7 zzm~8Ccbeh2T2q>iZ2`yECnW0Y*o4L_MaJ$c`vTNBbDo=Uho2t)$R6(3r=Ur<%fDvf zDmaCGfhp9&yeo~-!b~ouMUS&xh3=f23+wJ?)K_ow>yM+c%cSOodix(^+9t1X3}Qni zt!~5KA1xQgG%GWz_D_Mo-R^!nq6rT-W*R!l1$+rZWfXDVSIVe7-4T7E;_^6@FI&C@ z)7I3!QXqBzLGr)3K}`6cG4iB65iJTXOK?t<`7%#f6Kv@UX694EYs@fEFnf-gla%;% z1$=DVim3ne&;At^@J=Ma)C02=!=Nve!>U1lV1XcZZ5t&D3R~Td1-F^*ANk-}#od5< zD;G7^;O99PZR?7_GyIg}*UlPdb+$DkO?H%iH8XmGlS& z4kK^ogGFyl9!W70(!@GC4Nx+n6=dRUSt|M_(f-AZQP7b`2+ zm7k&i$hCAoZbw;ysUo~ZcdmEj{P1ja`!@a&9ff@Hu0rl6x+Xrf@>TQG z_PN>0VC?8z>kNo|@U4I)7$S~(@2G*t5^l!9rjP7Fr%gUdQ+#bV3UznTCP5`o)30dZ zMj+>Q$3NPODpK@~q%ab@S6G#*ZUcK2ZfX3(RGCjrr^uQ-kAhZY=n^&x!eh>HZDW7! zS|J?qgxrQ-LOC;j3Jayo(Ct!Tgu|iOR?p@yAbsa4RZYrXG1~je!8e2JAIJvfb0*93 zm#&{#6)afzreYBKY0x$oMjpdG51I`Q{AQ^Zo>iTWyR2puInb#&1+}CZy_Ey;{hn<0 z!?zFHD>%evNc$Ef(UQWKORg(p?2+n`#{wyrRmCPdk(QttCft7>|B5mqY)tdK)SQZc zk;-FVBA(|eW~PMUXND6~GCV0`JwJn6_KItb@auleg7e~Z`_kgHxB*N6ji9ETNQ0_c zzRP5J>G$~G-(0mlErF2;&`mleqNa*Ce{E>tubJktN-?VciU-?<+K=$WUN$b+HYJ)7 zPcW@#+VMhciY2ko>4iG!8Uf6L_ns+W8%s_kspoz^aYZfLS=IgNJt4QF1t+ykORzs!?J$y#DEZGX-vwm)7vRY!b@|`K zsjBO~^&zh6 z-~{^mb)VWfGxUX>E}@$%-qA%^LJWoLzIu2kJ-t_Y4?pwasvF&O9h=3;&V5kZ-*;dO zUKIax<$4RIi=cT~KDQl^zKSe8UwE&gD99wuBa;0N_Mf<{Ky~?FOzs#W2#c~+D;p0%c77uK)d#J)WM0*l1WF)t?dc{omQm~* z54gXn&f&XdUcVD>-YAKy0haWYrkB#gs({z8+eH3bM4O=BVU`KAqn|!dY+b@)We1%{ z+UAJWs;TY$`;;iVD~(XzqHRc0Q!l{Rt2hpfTgDsN;a1VNDIaY9^sV{R3g_EIQk4Ar z*{X3#1J+xJ-uS+AdM`1tp{<(wt)(rkqFjbgMlBS(|LbG<3XVK}-Y1WC%jWM=C%gko z!6Nr-20_?AhIwRltRQuN6ORiV;yMX_{0jJ!EI6ZqA_UHyKcb2kB!9Si-UWe8!a?f; z#LgU$HOp2zf1jj@(ykZy&9vON1C5bicpB$V%%ax4VMu#Y>5STdbPc=L8u|!;U`rW4 z3#h#dLaV@7E7^h#rxM=G`t}g_=-0>9w>KoEC=_2~?t1uI$1ml54B`nFs3BLzvvwd32iNck<8ChIP?qX5$7WQ_yx;(|l%GRqBC>-OFqwiET+)Gci@ zC}kePpU>gc&Ct2b>XU(%&hV9h} z!XujvDn5#zSHnqO?PnuxSft#{*d8|;|Fkd8II;` z_5})d1KdtK2yl-7>b;JiWsfnWB(RrLP9>>pWaK%mY2I))D$@2#=|}U!TBAT12g#yw zw9tI!9-w6!0QT94>b6aMA}bXj{ck_?w_>2Iee1GDpGK&Ab*j6 z?N8Gz?@NaX1-=ZQO^wAxg8 zS*!`nr5q7FY90X~Z^0?kV|uT(=U?JCMSE@1{v5V2s$#9s+hDfxP1k(iFjgnsG-ucL zFdw4aafX5()F|Jm@ip!iP6q~Yp>VfefIbLa<#Bf)h<|ZV!(U^KVy_+(i{f!tA^kaO z;^6XlvxEJx56e~4t+WM37-#)x(Pa#n#Ila}lzaueX2J;Zohg|R`x*DL^^JgkvL|7w z_dXPs7mp#gXSF@uwLLjGjSAICq&9;UEkq(dT-$~nEBt7!i1C5Dg{#3LmvTnRO)qg3 zQ#sxc{9J-(qo>^NxfpO$`ys_vCHy^D8;UpLiGsG+uF_sWuQD7?&LK>N8DX_WMtBwY z`n5IeD5H?cB_HMAz_{uJJaTv;c0YeOhDBYXee2~pyv9;Fp?n+HiA?(CN)~V76-g3( z2YM(R{s;Yrh=n>p?}bPr^2zlhFT6O3!u#3E^NN$=jWxk;x0LeT_-k7E!>67Vto=hc z43D?2+Uam6AeHdmQ^i9QK=nX@?s{IMvv<^o|B{JSltYS&Jp#8n!{b(>^@4BFKEPP- z9B$`)JvYW!(gbZ3nD4l&*saqfMpkx$T%LyZm-)#=@BBHV%T z{Gjsdach=@8{dP#MUcxuO+wX)&>o##gs-t7RGr7w;$=Po?nra&S7qOVLAVJ`{K;Rz zY2RMH;?yp=?Sq)#V~klnk3A4)srF2Xj{VHTMz~!&#e= zzi{xHKE8z7Nz)<4v8PWE^i8-Kb^NCwn>%~5HdMKabClrwxaXw<) zU{i`PJ2Dl_P^@F*T&LPS6kBJ_SSxteqV3kmJZ^&YEawnq_(u>`v zrJP?b8SIX3KeM&T_&wM1G`<}N@Obb4A$(=l;Ub(>Q=mPI_mkv)ieSM;t?Xh2S=;f% zG@pUhW%Y!j)y;FKT>uhG8$Y4vu#e{{YXY~a{~a7(za^7|gGDT}vLQ2PLQ$%M{Eoq{KKu*8F= zUCTw>Ui+dS<0k~@YJ}h|xg~8*2Jdc7wm_Wg^;$4v=g=VgO1Mv7ID6~tDazGW-itG| zbB6$eec6{Nt>IvXf`H6LOLwk{5@8R7riJK>h80 zQ5}cwDv?&D*O)N0^$r^K`?OWXC-!G2+s1Q>vctgFG_Uq`CZe=wSWbikD+w@&>+PT8t z{M5brdS;uAn;~eYm7C|oi&AwD0xPnSmUBYJn?OrEMvkQF_pel;ra(phb8$(ZKh#Oh!VHPg zvt|F(@){)I5UcZcP)Cv&h~DQ2_#n@z+T?RtMsylbjc&@JgA5MeWO{{rf(e_pIy+1b z`x&z^My_`qQsOZTsJZQFAC&<#Ww?{4q|9unW)6(%$VE(kDF$&RorEGxH00LQb#FtN zpehpl@q{4^3R_vxn1p)F@gAyS;9T(q&0!I$&*)U$8DC7T>xBcB#;igc| z>WlNW;-ez?vOez?BeP!&6A~z+$!fYq!LDI2s4-8;ul%Ik(Uo*{&ZK9|zC}li<-mw& zSN0B^-MpnFjkPFB)#uc(o#?4@5nTC`vg(;E>829HCB}6NudenZ-BEq+QkPgtoKJ@0 zqPWR`V1vi-cm9w}U-8|&#`jO7b>j1-n-f+V7v$<0&zh4|cEy!f(Do^uzkLm}$M&P! z8!p;e&tzG_a5#D^DY(z*o^(~sCJn&7RU&k3zVzBgu2Tk}lEns!F5^nc<~*!RNegz2 z8)LKveAhY6<5zwkXg-N=$<8|2h2WRBA>YuB?Y_AnrQ;vaTKSrA#$DQEi9H7_GbhVG zd6$6mX2o_fH)J#+%Qnkd9CYx)4czDYTb?*grnTXA>5Hk}?QLd7N)Ae#d2!$i-MxdH z$2j3zUH1{yI&tt&z540%pLusL`tetQ4&p04Zjy5G5Y1riuSzYy9>u2*csn~@-R!V4 zG`-~v<!1NVp`&zhk0VJaWVg7e1k}0M^oCd+C$-?!M4FPB^0We!r-1`2s*-0P4#h zokY0&j&arW{QMy5uHvw+z<0>%e37F}KN-ZwITFu7Y~E#x1@$O?Pu53fCG<Pt`$v zXI`!i>WXV(qcfU%gS=bIel?kzz!Mp7YX|ln6E@9cv-}~yxezJ1?@g}{2p`y{XU4GEp3%-8L?a5yz*XR{{?&RJUuJog- z=&$D9K=6yD?b!Q6^1B}pFQ4kxkHX%{#T1-U$m~JGX2`iV60f06YE!3CO&AU8PgGq? z*tE1E!dzYtrCv*pZM1lCaBiPP(?K7Jqg!!Dfcpm8a9R=da73^mUKeliBflU1bu3k`h(7$c+LTigOrQgIG?E zgw-1~%LK=KBGc1F&eizq*JWG<;vYA%oV`qBY@FU)yw(tVuqG z_sKGlb_EFTONV`BJQUa}ariLth8~<8hDRx>5!_ByL9UD&Y67$^O%`N;oOaQonNv?n)CwNajng4TYov9>8zo8^q?tj z;~c=7sx`>~Y>|%9B2VVO=+M+#p|^DgB+ztpQ=mIGVmW2a=y%&7)ww?eO-BWrjKmx6 z)zuKbncadP;vLf~qFC=D0*{hyxtBMM4|5={Bn|W1_3P1jx6Ww6x5}T1l>5Js=DXSU zlJi^$(X)Ap*C0I4@yh&MB63}(qPCo%F)gejQLh-S#?_amZFzO8XXTL$VF2%qYF|$q zF0}kzbiYFWNaL-Yd@J4M(+)Wk{^tH7uZEoNkft&Wat1qLi_gQ3e{TJvJ=)ZgvJjIF z*KQ!hT&BwF%FqdCSk6)M{no97iyH+HvS?Q#!7Z(!q{AvL{v3`I%_6Vfd>k=Qr=U(mhThfEZi{LumG?4c{t&tkTiiLT~Y{y1E1@c}g3jS-vA#6ib_H zQcOF1b&9@BQq-1LQ~q#qN3;Gr?fT$)+_cX&lg1BcY(-i=yi4q(%;hD@L6S}xqhWDjnPu!%e-XlXBpqvr^%+g+Y8&!W1m$5 z{5AKNbp9W#xzN*9lu@1pY%j=*VFJH+Q=O;Q6ezJUlIE0iTw(tA)ma270__LTuhij7 z?VAnSF!yJ*m-{w$T>KjYCgp`)o8*sY$npY18i=Vf)zbH$lB&BG;=5aPs8x9iJ|!i6 zqUkV>d|v*?hsosCHu*V{4t6<`;NmN^*--6<>_7r^(_frH{LC!L{1FVk@pir`I90g_h~Yp7Q|d=DX*Rey;I(r>?Y)0!4Q#C&d`8iXVY*w!|Kc<6;y0QJ&C&hlk6Z$p42Jh)izSxv<~r9-EQ3r``kf#Y4=3Lqj& zQCS@izaZd#x5=UfxAys*X*iY#is%4R3`1yW^pc`8l65X?7-9ALicQ5Mv|ow)t69Z{PZZlYvr1mx5Ie7@+B^1n$&ZYcpe1R z5c^w%f)6@p^8r!skCJ{Yak_*^&Nz3JEM#sR7v4u5sEk9Y9~4-=$L}6}hHb(-e*p=8 z%l>$`8T0YfcPDOA(F^qVhWm9zG4To!XLLs%B$(+s%yfR7=G|LioI z5nU3glPc7n&?^`EQP>^A!(fj59yNDBAAe01wU>C%O|X@B@Uv-l$zAwl_D_b9LJ-l; zr#f7Y(RjCZ?2^ZXG4nBz@|aJPL|-DuCx3zktTTEG8H9LJ3tS28rE?}lN?GF!_58Y< z`IRPz3%%16?K19cL+rhIU%0>4+Kj92x`?x@kRg4p>w3!5F~>x8@%u|t_*>pV!rH>1 zv=PaR{Khgi(lmUUJZriYNp$mD!6|l{=G{N)AsRA_GugU^Db?e)Dos4W1uLauio7so zL)yh3Aspv8L`$&I-8%{8Lo1WL?Y5b+QhD%TmvEclx1?#d$js&hZ_oXn@K}5U-Cx!3 zg~0Cr9Y}B9=F5rVVUHE1I7j)vGzyxZ!v~NGzXuglhLAc|7z=)h0;5mraRp}6F1xUh zb{hGrIICfQ4KpXe>U(?=kc6J5c>wA2X#u0UKLGzc`*byf0sBO~nnHD*bekpqy+UgY zBXSl~Xy`Z%L`VS?pc(s_zC*>ZeD>S42r1Z_JsA<0D?bim$5XJ543w&8a6aRa3ImS{ zw!BuGOxmzNpFSoC)y{7&!dY`i4^vjNSTK^~%uUUoDCI1IX-|&L)|uO1ZRnnmnq;K3 z=6%U(L+Xy2mYr<2>x!0Z8q6w_Z8DGFp~uV*-uDk-2Mwii)fCk~!ynIG5w%+@EaK|P z*z}i(dKtca)lm(#hkSs}W%#-Cfk$US6b=H*ZWW^U{i-{hqYUNsiAB)lw+$#2m{2fE zm-_O1$L$PHnl(OWND!)dUA&@eV#dqa)fu15IrFT%N)BkpxXqhr)R~R7!fmHnil2j2 zlAHUD%L<;*JPsaQy=w8O@{6B;j1@piNG%=ruA-d?-bsz!2ULE(dc zO>JwM2L>*{ADz$YG6j!~i%QTby0z;_aFbLJI5_TjvGbuD_XjfabqsceD;(>f6A*gw^9J)|>xoG22 zcwHn1!q3w?9=`xCmnuDK6#u^MHMFU)SdXC4b(U0Oc=v}#X&-OxFlZHrH4<=RnvBpD z3Vl*(68|djm9hvXfS|PAF>8p}KpdAonTLTUaGki>xk@8-ho=05r6PnNWCDXa`$0aH zi{8bk?I~Q81UD)vx2N(;MnwNyf+e=@Oq1p45m(<%F9P{6^r_u8q#}W zDaJqArAT2^4S-Dp_qTiS0kFF$^1X-zLTCrS{V zXhBmKCdI!uxgw~r-V1s;Ki(3?FfzOJQT^+RssyWyKD%jlFS0|r1?z#mCh_%jUF+03 zhbgXZ^xb<TDQ?Uq z_*bj54zp@inaDR0^WP1cA>be)v0s6x3f&H=9nv{`A+<&i~+^y>15h*F?o*5 z%&I0wrqmQ)sATF}R`bLdy|;%yjf4F&Rn>9cPu)*Hczg=;DoO>%flS=vF)xXlCj7zi!K4QhJ_-I6J{iw@-Ers8%0tz2*S!?ur~-;~Xw!G9j*T;! zS(#sNYv}wMDX#)hSH4atRB`=aH5q?#Mi5bAv_>-TG@lceVEDz;{jhCeWeI2PoGp&G z)HKgjIt|KxqGFCjs@GI;N|)o;j(4p(Aa7W-!DaOKl6sy(d=d)=z~`qJ9}7E8;t$ zz_(`-bjN)00XXHbK!-cR-!xFKl+}{!TE)@!qqJwkw?A3;Z)G5{5^97T4RCp&kWtt) zLvZ1~#uHkEvn!eCkBGRzLH)8wx-Hb6fyQCp$cR}npYruO9|Nn=6@1==?hdOesuow6 zDk+t#nfwxhF@lPjivSAUOcHJsT%Xr{PP&PzxCR%tJ_Zxpd`FFj$Prlv?8{W(tdTP( zR4VXIOYkE~6ttxjlm z^~TntB$fPCB=}7%)3bc0018xCVW>M}q8wmSK29lBAE!K!fo`o^9ud|!2PI2^9Oz6T z2Iv@BBkA0_f0)-d*!K7)@+~f<6-BR&*v|VIW9km-A?l65YQiglXi38`&(g+4o{<=0 z(-oFJ#1_w-LNtB~-zm6S>6qqqFEYRb*xwJZlzmoM2RW$+qRt>;Y%DP2)kS~yEj;kx zgEYtr81cb^m{oK5NF~*hN3m+P{Y;J}!8%2rPt(hHb6xz=URK;`5i8KPCm%{zX-eD? z>dh3r31#|+dGEwKSc1Yuqtmx{JvQdEO6R~Cwd$!R34aq`d-9<$t1Q5mqD}#C?L0vB zG=hXwXgS;Gr7HsAKe0?62_DNv2CAT|7v8eJLj4I52>d@ZCEqodJUP&>iHggMl6#+z z&lO!Kn01&K&^ef4;q!f$?$DngU7Now-*lc0IhJE@ss1HTJegm;g@+S_NIyRCAzmQK zEpCvmHLBKwTyJVc3>5H=&WxhrY($V7c#6#G95S94dJGh7bD%7EQr@Y5iTj51$fD4K z#EOO-ERoNbnX_9xAfz2Yea?T5)vi{7C4R~ZRZ%BN4{J+s@y-ps<$au zL$>6LYsWg7c)hy%cVc-ZK`N!nZ*+`p7!QTcfKyjp8Uzp9o-`*pSYh~W0z&7pszh2{ zzVYe`zX{obWYXd6*`yDrq<3ou^6lTOB5FYR`tMR$Rj)kgM+))ePEu%0NlkkxT&)MS z2O>A+@ZXAo2CtANRJ35>Fs8L)59dDIAPQlTME_Oj^m0kzi8g`Wa+7VSeao1dB=vKM zae=F8_@ldJ#_Q3yoM~K<2w3F2%x;b)Tv*eBM#qRU#Nnj}zvMx7r0rO zvj0*r)<)@!=&Q=3D!h=~$NdvNs3b8_x1exQj{d!R3-46ffxE5jCyCZ0uOf-tK-doE zNBJe|-d!)}0hcc}brRR5O;Bc;!P0d7gbop>;}x>)Q4bW#3%#B*F8$DlS-ZdGT|Hz7 zPj~xRh9jH5a>`U|3&-27L~ez1WoYo_u$0Bt{RAFW0O`bB$a(4H(VnPgxX8C!aJ9ek+o>ke-Shwwgi2D&K0OXbF_i+q5Do4jKWQY5Ppf#vF6Wq;F* zY2HcL(gEUJ`M5pk0|@hi+(4aLyE>%$mN zrZv^`sKu4JXf5^ea@|KG^!VSY>Uu`Eq|>XGqHm4_bEe6<{+c8=!!@$EHFwNc3Ks_+ z5n>`Z;jCtRI}aT)_-kJ5gM6E%|GjsPjt!;bFYYH5XNI#P|Z=mJnhR(2%Ck z#xKit+1*Al)lHh;aSJhnCi)oFkR5vdN<^}9MBw1-^`O(Jp_+ho!w2I+>2o?{5mPN? zctqIT5@gq_4tR?u#-H;m#6T=uUulSV^$Tu?Dwu9&l1lN;YF!V1txG$R<3}bMF2Z;M z-=7Js4GWOjWIIYIavqCgXJaLfDj4 zGGB>DQN`g@zP2-OAK|DbNx^zXwc3xzeP;Cb*MvU>gvKu-p)n{=C3g4L2X4`Qm*@j5 z9khvJz878419x`4r9a1vBizSm!VQzKqTXoz{e~zo{whj<+VagrbIW=d3s>E>OsW)3 zrkg{3$XLKPzb>Ts$tz?wAsPL!*Q0~UK%!!_fER(l(7W4fL6C?pp9*>e9`D9W8E$o+ z`j{qYBMWfGCUoa^LC*IDgF7C60&6{N)IjzYO_DT%?@v(!Y1&j*&~Dh>K5G)kmcOlF z-Vk=rFSFiAK5ihi+_&=WbSrZWk4e_x{1M7?VD~Egn|p`hj6chKvik<{{ec~sGy7DM z!;FgP7{k!SF-0#?fP!3A98>07~2ZFvCA(AN412?~+AjIUm+ z@+eG}Yyf-nBvUrJZbBb;0^=Dv+F2go^ziStA_j&63$%QX_4A7rMIO$JbvRX3=+cX5 zoxhzZuukUp$20au$G2^~c-CP$QyBU;2giQ_H!7yGW~b&oEQDpT2#{2E+tr5o($Yx)^^P&Jws&pHto9Dza6kG>5fdYBW0es=P};k5rGPui9|F_ z-to->UOnB06+A;eh_SeTzsWfs_tjBBp)XWFnD&a*;#}Lv5mZkS@m^{ZZ7Z*CI4sFw zz`GgDPUkcLQ51ws1_iviniUG*X%A)DA`jP#cz#FVPSus1fNK~EF_yO8|1mu&j;_W2 zg#eTApgwX!?=tN+_brm;RYB;x`aUC_efzgISCo($0;y{B7W{0BPd^pits=SYqh+*U zNwaXYS3Z^;WomQ21U}`t^C}~aw<@sz@WaD69j7}p4Vm$TR`npwxDAcVU=Fign$4$_ z0$1{K`S}|;-0tt^@)YL;!37JHhH7(bIKiLJwSDo?MC`5*x4XV-&C2T2-FkNL2~0g& z2!a(==6^Z>-jnQg7iM3(qnxmrwyUDzD{#$i~>e6wmqvg@m%t zmlEnSqNdqtfAMpayma|5761~0T=L9!tI|2YU>pWe=N<4=xwbEUaSf5eF&w+&s$YX1DdLD2g_SFFHiFje-~Ud_m)`lF(CR1zql>s+C z22;r*EpXXRl)+*o&s15w`I1`dMkq(p4n_Ep7A%0vg96l--I<1>Unqfzqdz!%6iox} zCz)7E5~N6#y?^Eea3!BRPBqn<9A?(3XmpIJ3+3lT7jk2P*Jl6yiee0BEqgpi@S6Eb zva5Xh<&@#c&-Y}iR-e0EzA(u%L|6+=2M|yw?)zLVxsGN~;W6NI2vH?*xb@H_-uG3d zl&`(%IZ7#^4GVz)X8!EUtaq101SX#KRn)RD@SGeZhaP{Dm} z#}-Nb_MB@l>-c6NsNEocCA((swYe_T+B+bE5bt?Mtf~itQk)bavytJapaApgcP|}A z6Vci%GR1S&cvXoUE!57~va|5{4BoH!xlnBhI`2=8sUN4;7RyMSh~GugGjuq}!4%}q zo!Gs_uf0m6Pi&I&yDykKe)?wXGe%A-NYm?LtC;wtw+ghiCjtF49tmY186g#jEw26Z$f&s|C7@e%j|`R3Ia8_((qOCSFq-;y5@pZ$t55s4TgDZu>T1iPg2y0E zgo}61+W~5dKU!5>s=06Z+aq|6lf(1}65ruGG`i4UHMaTRXSZ~%AUVi+(z4z%&7+wX z_A;(VvE1Y;c0o*wZ*3CfcF$Dya+|LiatTa5D0aFbm^#D@xNp#>&dpc5`RMiTae#Ym z(jsny9i`11vbX)(h2E+q3ksJ99?Ku*KmKWev&?U0*f02!^6bHDFL4zq%tu~dd>5uT zyvfsZnKNZ0j7C!0?&aD68%`C7I1hwXymY3SiXJ;Ud1J?iEGr&od#i9O)uRgP20*F{ zEzWof+)bzKhcf=Z-N-aS4IV%HWH6R;8?HX&OwCbm9G6V`OlDSx`h+-V3vFH*gNOKI z9&)vp8&%IK>I}aQLw^eSsyHK}w+uF-kMxH*qfrB~We564E^7AK8?$dY4+BC0S`1AX zpGh$K&L&lPR7r}vkNWH0;0yP0RYarkT@SN-VBmJ%TJ}7`1o7ucMBqAb9>0&5w7SV( zH*n7AM>71zcIg_vFUA~Un_2NkRDcP6V9l@$QrAtW{ndbc2XiQ}K71qhvD=j3i2*3F z@FIGt&u(38GltAPvr&xFlG+#N*5QG$4Tq=lMZ&SOu;m0-%*1!Rb-q?`Ppp8gvsP0} zK4df2==>EI3EN8mp6b4SIy=YD=pUu|Ig0MdHBRe!ZKA|pXP$CpxxG2+4Au^}ueC$u znTkG>x+BZvF_Pn9*(6A2Ch(~Go)U`FW9oE|RL;JgK3czP=8_E8VbGpeDyGgHu*xv! zbkEtyW@n;#Tz5+W#+u&>Jsz**SU4sIVu$EH$b%JyvZHc&0O8=y9Ko`o*Wm;OZ-U>; zEEcdp-jogdsSHH>NIl7?jg2Z_ZED|&p32N|;pUPnL-!a>j4(cp)~PR^Kol%dzR;vM zO1EWw_$|7c+b6|@IL|RFY9?yGc>&4cJ|d$xbatXI>r!gImucB*SajN=fV$~TQ&tB7 z9yNY%MBqf)giRhWJQzcQ9WXDlyar~=qqYt7Zr`dY12$MT=7EOobW^T)$d+48r3;~0 z`7@WrorN9%D~}%cEk0v63F(6bGWR6cZN!Zkpf!p1``EK7YsOXjRPlsR}%td&k$Ki~W+@iS0>`PU( zvNY(-+;bU^bs$kH)DnR)L#g#)l_k7l2r*SZcOLQn8>`M9$7buxM`ho_`ov1`N+vPO zjc!gt_pElS(|YD3mtAteCZluW=>WG)!m07-KQ)HfsPZ)Ut@spI>nNrpWj%sQ8vJFs zyZ3)a|4kuy-1x-ubbVFZy`;T-O1L9ZY`dLmUb-dXa;W|@gE2jWkrH0)K7Z*^J7?zf zNSi4{+u9581>WhpY%tDHA13Sj%nfsNV%V+)61hw$iFj`h<9~v-qX33{dimtoYCfmk zT|boHUm|(+?Z7MIw=+GVF*AlT+RPL%sTOp1XfASaZ_wjzQ#gcnb3C8(vs79CCKBGN z<1bax*BCO12pkz7zPL zg}eULQG&v4@=s^jI2}^{G(Ai>$c-`)bi?v;po9n7pb4 zx|}Vue*~RgFCF>pz*}nw9G}xU&3M=F;SzS7bs6&Y%iR7PZQRN9>}YZt6`FAuqgp%@ zYT8QDPS>YGyJ$|U&8E#cqN23)%>=$&ae9SrG7odaRLcqDj@Q`lC0(jj=bnT+h=!4Jaj6E0+<=c?7=LsZl6$+iN0g#rAQS z8P9k3?{#-vgcpu`N4w6_9&bAR=|0MKI2#cxGnRj|!B{rDcTL!QmT~kI&U2`D)Zb|W zs@(u;e43ISD7_iCc3njUwsp?gy{gR99eQ}LNz6Hkasavd0ML1n{?!0R)Ctnfad@$9 zUaA@M@CcRtso;1zV|eFvd@VupdrO+&q336=+hGy?uyu7~J*4+G)j&~Xa1ngeSFk_4 z_}A>j@dhV_L*n{(l3E$;=k@~F=3lOCVx*J=?sr$D*^!dJL+yS0ex21$lA$jk6b5}` z=%99ffEInB9GQH!_${6ngu& zEYOPv?yOHP!d(;B6HNmCeLy2c{G8`(OyJUGbqV(a`M8E64=!{V&=AQx|GT1`?Z+2X z3mUIGNS*64P~mO#_7@%6)nSKvL~J0(;Q+C7WS@iX$E0`v5GW+Rac1(hPgJOYcHk|^ zW&;Op75-rZGms)kfw0{}$#8`?UzqfB|GgLx?(t<)MjZ-3UdJFVpJ`kGK|sF0g8%#W zGNGl)du{$#xMLF6QG(EvRGEU^rSwQ~B#!W^A+A9r1f+@A{{;!!z<=)h!FWn zZ@X1BZdl#LweEL%^UUAoi}mL;48rHt$8c9LPJsyj^uuwm2)Q)^Ywb^QgQtfpZ1Z?H z^1a>VXpDXg&*WcrPgDf`>kguHksrLE?i+c&6)&gyU}AW4h|U%fizadH=GZsBM{>n7-)BU-@rzr08=5v4qFdvCA)bgd&fQyu4<<{GBh*en& zFRKS^hr;ZM)gwi?E|% z3vN9Fmi?JUl_by=)B#b(h`=95G0QeF!Ooj7P zQ>E(Z>_*=0eB~bIiND8~shQDRsF>>iHyQAEz#p5sCBmVfUJxsNCksnHYB+;~c9CZ8 zzW^MYUCS5W{!FRs>o$tE&VMONRT!h>pj0h``(m_Vv#%R({yc)2Fv<3x<&A(aqwm`y zxcUu|TpjMjbP$A8$1~B%gF5Pfq_Cl(hFu#`$Nz>6Ar?a7ZwhRK_tQJavt#;u|39$d zYzvf+Y|{S$+X0`PwfBEQj@OvbVl z@z~3Sb21K(Z{X1x-tii8gMiMuTD$CVP-}kqOBeyRgHrC!vYrkfFYDSG;9e=e3s`{L zux*0yUOis5wfTJ8HrAmMrQp9m?iA1Xp$B}rKl>R4@5cd!HXTtCxmU}>Ce{DX%}&-) zX~XvS;+Ap11QFn09Er|2dAVTfF;}E0p-T-{c*CZnNH167rzNkmVcW->og)DsvV*Uf z8SejcxR|M7Gf$r~Pf=10mWAe}*?#fWI4+v{@~YVeIt6DW!`mBha0Yn6`*WqC>jZY0 z*v;s=ViLoF1h#O8Q`Lw-k>mJ11a=;7WV)?~MtwVKIueFMKU{!2?d(1$=&r}@C{3DX zsojv4t7Ti*nIP9#75ppwkI>cPMv{(We-uVDoQzT(46JC34UQ1vLpsI11}C>}!dpCG zp}>1uEV?Y%%$#`5Qff2-YVj=J2&v@BJM5%8MQML2$X$GnLOyo&;Gd#7UoN(s^pL^*MB(r@FN;k1>0rWveBleGx=t*?de~_;qVS!kpRIn?-{$D*7>1p{2}piO0W5IbKoE>#JT z_7d@fV;y+}Cc@z#w^cusMdumaoy!&9Csy2Fq9E<2(J-sUr7raBth>b>a>1)xriiDI zt9+4%0ytu!>bD1d$3c{HWeCK~1n2rd|A~~)3XX%cjwr+*b#vZIRCfuc^!Tl9mTG#= z(!}@QR*l6o*cf>toxsj#^aTTIR0*n=Jsmo|V(4rHL&4Glib5BY$|c8u`&AS}?K=wB z#kIn?E^EITlk*@lTVg^ax@8}|6|XY|K1lV%-@AvmSna(u2|0(QnyhD5d>iP`L!#l1 zZj-_gR6w-z229F-Jt(Qm42Uu54GX0nvqOTnZ)<}4_$0UqC9YwcXgkwmzaS^bgZXHq zVk!Uh9d1^J_vM`JAY0u~5-f<5X#5yy} zElDm($lwiy(1f5Zg&-smI54$9+X3Dpth#%nW_@c)wA7~~ru!)Lc#%I@&tq?B2}StW zPsjDr$ct*##@~Dk5_;SrA6eJ9rXUPzhAp72z?<6SAW;=mc+l4LJdbRg z_w>I1g#`HxT$mG3AhW6d#KE^7daOmtXdP)T$Dtj=`GQ+|?U`~dJ*_+GT65P3~C@GaVJ@U~T*{d&L)K$}xF79cV@S z8Yp!PosoYoX7rELbe*SaC5&z*(o*7*$)(A&ES*mK83o(^&?+AOcly>CBAlJ|EYppG zkVXfra`DnZ7;4wxd_mk2jsd4%!9BRoVO$`|5P< znMn>ymu$;gF28ts_mG(LkL+^(k1xlB@9R$XYf4F)d)O$t!X34pyn0-Q5^jjE+Wm=D zkQkV8p`*z5@E!nvmP3v?OZ@SfPb+9T06y1-b%&LMK^gK=Af?~TeATIMX}m1L&0gcx z{tJIq$j0{Ql^G?@U4w{Kx${Gw4c-JYT?AV~q|)=htC2TwnS(xN#QsYfWY_j^39X(` z9IWJ$rn%or*2g+&h1l2)u9rD+f64ol>3ykr73JF83HQ`HSI+U(vHBZ~5(pl!lr=j- zrx)|^j_0k)-VHRb@Xn*ifZAZmI20a1Ju?RezHvWqz3yf=`+w}cbyU>f_b#p?0wOV> zpfp1aC?g>Pl7e)HG?G#x-7PT0(A^Azgn*<&m(tzR-8ppEotNw0b-(Y=``+)m|Nhqc z{l!|!nmL@a&)(18XFvPtYxBk4Ef+9_t8;&TmTp-wF?}?wP>dL@ysdT76Xstd%s!x#M3;nL=GLlk zn+oAsm!&X#qAx;>p@f1Ido4aO75vwPRDW4Zj(j3(&Eu9n+ z6Ljq0fZUcyq8%{6F-^!)&|cz zw-mRl%f&{npX-w*Xfz8dozgkA_Mq#7Uw}>7nx;9%*P;PZ6K&;Hzr;^{^_EYMd8YKi+LSJ zeb3e>>M)Mz<}D^VHvcMMw%kn5tNv8XcS#;->%_liJVto=zOY(XFSmJ0tv&3R?(04I zbpO-B8_zceQr`Wqx`?$=*w_57IfVyS2-j6xKoQf7T&G-7Xn-(FP`GUfYsdr`Tg7(~ zr*SrF^W~?9sU+4hYW-V;)zCGrLIOUwCWY00IL#v1joe)>k)Z z2W#UocXlH+iG3NXBHxL>NpgzB#r}oHUX?b#2^)tV{0gb*iW9uc5w{QWoBk@W`f?)o(QVJ%xf|b`Zg1>DG*W< zN{aj%RJKzwwJBkFI^Q`Bj+dZvrS~9RT08mYtj@0w?jiVJZGi3y(OS87{A{e7M_X-u zPngqR*@czP@%VIp<0Skc_OSx}6qA3K+-7Fhr47i}f=BC(s=_*?TN8g=n5uKWf}H6G&br>!sqySk9_ z=q46`DqO(UVoM=JF*miIl645Co}qQASdtYHGWwa8Zh;lso$@i0jr*(${2x&*0_qA* zNFZ?_arxpCn_abkUrQodK#IJnseaCNV6ifNyMli(y7evzf@Xa$#cdw`Jsx8Bsu3nL zHI7ES+Fk`VE-0ylc)dqm(}Z5qnAWu-zwj=QVrn6tTAX)!o={u~Nafa-U-?SL zGyV?ULN9#uAmoFk@!P3!lN3vi)7S*a?NrkeR@FvH7b*`!E_lQzXY%LVCgp`dXFD2x z&mGVUcN6PCFKB*K_8hhlJ3tleOsfVS0R0XF{oCm91XZXAaOU@3&j>8jH{&L<_UNU! zK3&Z(D3Y#``%_+LlgH3 zDGC8oBLm9*%vAzouxukgT%X+cidU1e_c#uzurzQF8_^L`o?TX$TtlPw@q>@)JYRRs7k{oW? zq6z}NT;_8%68VZb^lpuy3}fi0Y!_o7;U*xpi2=_!OiY#(VS$qmEtU^xEvw+R#39x> zO1+N;CCX!L6jF&uVrCN``zwx`N5BKa@4OKFqWB~_1?ehx)UzhTT0i3J5$zy68-#tL z%g4v>J90AV>~lqODyzjz+H_1d1}$z)_V*_z;Y6;xi3tR^TKJpXNWC&=C29ghd|wI4 z<{OpuSfrH45o}0D#k8p8T1nQ>e8(if4y_6=`%b&t8B??t`9}Yq?Sp_td_ydbFO7-Y z0Rx22XM+n-jFYuUrK05bUtGp^t5};g4m4LL9o*yhI#^qHJ>RqFYI8RGwFYX`1?Z69 zUE0ZRmv6ET5{FCh?UCIS=BeaXfK;nwaE#?NKlL1Lk{uI?sEz5N{A0u5CI=Z?*z`Y+ z_&m6g18UjfHpe+4M_X^pN`FaDjiQuAd9I0YRo!Us3fW#vg7<{-2^RqI4Q)W1PSS7e zQMe!W9G{%sPnt-g3#z;^!u4p#g^FuYvF>FVG|_5OKs2u99a+7ayLRH0K1gC(Q7zVh z#rT*;w?jWee9VvBs)`oB?8Lgkz~fefWdz1zo;wYvyFm@^w&1$5Xs8sgV?3jl(@GTU+U_CwBgR>&C)9PEvK()m^N@-AJMp;k}b2VRYjR`Mn19_e~G)Tjf-NtGH4Y80g z3b_$JGFPG(DVv8dHkAuWYEfD}x7rbG7}Hu86RkoFynEc<1k+MDNz{mgJLz%0fwBE@ zm938JtgIYMBrjxnFR76S58?(5i|d*ds!+1Q{9rMaB^fj7)u$$oWo*}XWhr&9;t#e3 zY%M61Yah|D(TCajo4rkJ>3UT(D=Mk&k%`mJ$GFCv(IELW^2qhxewLId67TT7viMjC zzn$`xdLDVzan6S_WabV@%skO7cf)>I&xhd8EtJM|=d03FL8LPD{IrQS>Rbk+EhKz0 z7tC@MrZXhi32wa#EQ=_+$s6%L>395CM2#7YwK(ICpq zm+atY_!-)?N_%%tlO>w)RZtA5TCFa$eu)@z_DS$d1A- z)(u%tKL(v^x#2lW*Z%TO>sb8CZA4k@!Qy3L$vWLiVe$5t=!*>J064j|cp*#8vil?g z^^?9Xr}$`p_Prtpo-x5Qy6hnp@tZZ!x^eQd@kZ(CKe794PKnO|-#zxc4-BI9g~`Hp zKlXE*BRe0Ux+L!v6hM_%Cvs5O6w8S$gH#ulJd`g;$XZtTsj*}EhV^^Rnq&71MP_%+c|)vF{uqntIrASacv`nJ*dNPagZ(cY zH4Zem)ApNUvVMNPD?Mhq->jN~nV&*p|4(g%y<0kTPKNP1LmkY|=)6d8zKHz1$1f|& zb3S0+{zyvNP)>G`Lb`fIb7EQX@`ZhOymLo-?AMjT^035T2Jzr{m&_ROeI#|^GnVA{ z7oKVEmY-l!%2XKGI#n}SU)6t|R3GzMfav9|z{Xzb89DbS^fwv1RY{E+R0YSMrzeBU_fN%!knvQut;sFM z^m?g+h1H34KdqRy>wdJvf!CafUHr{BbmK8+qUO=BHe-YtR2ZK$L@WhC zqbJMQEo!mLEex|5CRXKCc+LJ);YO;Ku_+{oY})QuG7<+rmnB-5XhE*rl*EYM+suaq zM=Lv0=Cj`zOsa0BE>z=JJezT3?gS}uoS6C0PSKB|)`cAW#JDPCz3ZM7=wwlixFR_; z`qb{vT(U6nLY9w{)a|>Jj;*Qk2M!ZOG;&}y^8{Z%o$dx|x51K6XY3PkTG%05cN-70 z&Qaei~^PnVu)8(=^OS#B;w+k~2f+BMR~)fDu3BVl1aY zi5HJ|hMCxA5_-x~BzfB&HzUi;Tu>nA{Y}}t!(BXiqqe-0BTctc&qKU5gtZ}&l1s+B z#V2J+6Pd*D8)h-#i?e!+bg$+P+uPUCX0iS+?=DRD^GhrIq@jJ`I0(_-sf!fIR?{FKEkl>H+(Mu-S)-o_9#x)ri4P^RroYB$8Ww2paEd73q zbKNOk-#Bl$eyNWlT_Oot;b#wYTNW%dc=rjK{)2OK|dW$wRL=@1|$Q%d)6!z-+T z7a&0rEjK^LrU@c~g^breNmatZ9GdaMf@2)aDHNY>9jAjE0TptnfH7C25jfpHB;T9x zdwp;po%WH@V4#+dwREk*B^di>$UEVhg=6W&rv-!x(Sb-3No@`(Xf)JfoZn8xOa zAMf#t@Z8N^bZVXj?X{yRJ0m@0HimKT;O|&|2+;p6&xNgf-OKt4GpG5x1$WI$(Ciks zw9R7v@P|0;H9lHL#(sXpO+|YM*Y%nB2LGRWg$b-($9C-*&PU%aH7@nK>LjauJzB2) z&z1&0{8NV6XOo;9E%|il4zhaV4`BG=?-?q;t{o3JD_4c4M%I0_-`9SQPT*SWfeE_y?HdAE> zA#IV2Rn8)#j*c>YlpP)I^{bdh3zno;AL~RUrJhR-9nQ_EY#|ZXD9?bkH~mKq7M_B; z?tS)sg6?NK=apl+m!<7g79qZ)S5uy+GgGszUNBLY9=XkDu*ix8nL3&ZHtoC57&FW7 zJ8DLrY7H0WkD9W=ZII-(ar?K42Zxc2g=%f)JK$o@CP#p#*CUM_#S^s46;EIGknk)B*Vpo3d=c| ziG*{WXwyJmKl?2J!>H&khnkSkD08_vroIM+bLpur?1@;OU|uN`8&J+Y1vM-LkguM9 zS=D)B9*qs*mupLy*e@n(6b3E4GU+k%pG2rGlGm7*30gpvoPr&|Su$g)ePrw6Zes68 z_nqrN3lukbhsiavmqgO&Ym?k}B$bER1GbBD*{EQ4lKlA8*()%FkNr@^u}ioy$c8c; zwVS1Y;C1}OQa$k#gMh!J@TL?)a%wMufRCZc$Ov=)l~bVzjC(?2gU3Mxwp9ws={8hW zQ%ga8GqnAFA-j7M?WD=-qT z{_^mtNDUeD?UEI31)ae!F;(_Erwa<=IV@TwxC|YM|3Q>K(EByWMlv~{k*bMjYff&| z6kjx!_nqgaD9=}gtNAX2%0&Yj8N&%!qyHGfq8`L|knuA);($+Fn@`e$3*Td^2&iV1P7@OKb( z67knmhB;;lADlYbWI;&=ZXuHiPeJ$w0C6ZnGw~11jx}hH@scU5GTd3I5iZ5ftq2zz`cIA;c{~5-DKBfag9OCbl`a&yX8d#IY;URs0|Xg7A)-J( zn_AR`Md!f3W+ZH#<1Wd}=vw5{AgGJ~ek@`k11s zhG&h26AN^=@rFeZ9o#xV3&w!djW(+r-2Cwy$QO=GG2*Uznx>TPZ_4{cA~5@s;&U8gz)RmO|OGq%*9XoJ%Msm=HzfzxRfDr0p^->j~? zN@g%&u2{qyMNkn?UVDZ6#rzJ^OeLl;_Li1i zxwVMLinCPHfeBKv_F4^if+KlCTbA7uMX(r-d?I(xH5U?I#fmoZ-=~p2L|8?DGWn3U zBo31Lw@+)F;t_48F(WCx0?yBELe80ZSOwfziH<(CsVeRoCFVKm5~;U+UlJ#9H%brr zWJD9hDdQ*@U!D!HcjD983wssmc(Yf!XuWD=TRJr0)MJX5Kfeop;;8xY=$ip_|4u@z zndMfd*b_^l``$(&&v_qt^62)2zBl_MJ?XfEb!uOCg3R)Jah-?l$V}hVT=o>@VPH!? zY8{kbQ`d5Fe|peaI+dm*_`)Hraar>RYAM$#a87LHEeWQrdMwG6rO1)UOM~d}OwKJX zi8b}72|(XwJILF4%CfQthtc|svO;Fk%1KFxBB0sY5<#ct>^3MN#eeiPfb+2dX}oin zn6!hYT$p1r;0>7Ei!OB!;)D*Gmm9HRj(0;{NQj-FIN^52w$uOAKmPg*5Z)q^z>kUb z$^Q%aMf3&(hO!I>MWg*1Tl9*=7;y%iMzkQtfdj(&A#)jxX6p;;(ll$!+Kd*kLWWd_ zOyOrKXWwvwg~$jP@5<8CCW;U-vcWI7+MY)~~@eHZigEFt-azwPkHhYPJi zqDk``SF@(+o*czAqf9b{(O@$B4$`1&MJo60(h57)r$P1m0|Jc&v3Te5F@pL}>1ts2 zA)h-&6~7Z`g%CL>QU~LR7Bj-W2bR{*&23&S@--2Gphw_n&1sSk?n>$VDk*YbWP=TG z<;%uh_FG9K;H$tBsoD+m96Ko0EJWEiry-Ua`;VfAMr2hGUs0-kWb~e*u;v-OdMr8f zOk4E9<_URa-a$(d6{WhS+0cStl2fw)V}kO*_RoHkou3}W+K--;sZ2`>jCqL|TJ*F+ zk8$iJuW}w)WK5g+DyHaU?96{KlNW0!*4oYU^$SBu1%rAR!BGL#J?X5 z)jG+H0EZ`ILq1=GYPcFeLe)M?hH>xx?9<4F3kI|CMcFK*9>wf38iBBZTk}ET7PK%EaUKP%i3Q40(-9Y_^aH& z%>cfl6K&GqP+S!Z*Q_PN8A*x_BR$XV9hKCzW1td24l^#QU5%oua_bY^0^!McT;pG% z;fn}6Db0|bwgE@KG7;U(47oQMJ&Ra#2ap@vIF9F@cq>%gr5w`rIeJ6OIiuq3LL?P5 zj^+h<?ErT7|2L=MR@yHRr$ye#*66;ZO$e}szAJyuc<*ZfQ@g4idwB=n?o;Xp(m zh)g@wanRfx7WZjLG;HNW5DD?t2jJ@JQ=j;yT?ouJ7zwA`ykRLob{N#s^#5HL^T zanG`q9sT3ogaGh{cZ}tDJN4t>c%tHG?f2!f9%?dkajL+wVC||MIE872b6f753x-XH zPc?}@1sxX3?jai&1gwxHJKS7VYkX|Y{Jx32iRk=h>b@}kXj9{3sjTJ%OO&ydYedQV zTM8t#>MpxbG*Qs2j^{~7pM+>5CGBOkSyuE0?U6<0CQPtL_c4s+ZfHu9Vh`op{oM!k z9}|-;T<$q1CE-hoSM0S7h3iF98G?N zCV`d9KL@#c`g_Ryk=cyY&uav^w-P0c$Cde-4MA7KO_}jTx?(7j^BWm-^WI@N@)yi< ztEM;a4Q!4L9IGb-Z?H*Z^*wYXjuB6&wB%DuN z8IkGncC}mMK{OvfU%;7??)uvDuQ@h>t5KfpA^LIuIp-k>e=mmv?J)vW3fY_kQG(K0 zfLE-SP+TKFR(s~myKj;5A>aPd>K^<{N3@5aMwXH1o^HX2tKFEu`Era^*y~XnfSmL# zXuff*&CcuII{&kk*}VX69tDqTbQEcXQZ%m2qJP`fx4D;l&ckw7d_NFkmImo9L)LA` zS=)89{0vQTo^>Uc>N@NfN;g<9?@fjLnFboY`Ek_Nxm~xNIjev&yZsturq6oU*}nI+ z`hv5g9uar(hpoDk+`~zvrt3k=7x&f|x`V56V;}9k*xOuvf7Kslvs${7UM|2NtV!K* zzTBxaHC_h@WZ@74x5b{nYPwNkB%QZsGg*YDO{d!DGm9ats9!c4*$Gx0LE+c;Fcf&J z-FNG`Uyvi-ZjKjc61c0T!y6&}cAwFCq~_`5SVINV^Fim?7U@yMxqsY`KG(87Xvwd8 zN|kwm4q-_3`3)%{37xuC)75F>^giNJP1l^l32ThsQ!jv^+GvceG?(ihEd_>tQ zJ5H@@D|^hr2@%;hR5orHvf}t1&ehFY@y0t|WVFE#vhcF;>c9$By=EnY?>PYUfc+r& zKJ?PnaQNK6>_^x!AIqmTd+m8lA*PghCp2y{-YJCS1A>p5d#z^m2e`C-G5c0&j-#DJ z>W~xUg6`#vtEJ6pCTV>~{bAZ}Xa)QT>u9UkW97w`%N%j#vMK8Y6Q$;)RHMx*Kl`?t zw&jtn>&pL{1yKH@VdJ#EX4jcoOk0X~qj@7nE}!WT)6??@m&MzP^yj6=E9fO@95NGT}q4%l46B@d)+H#0mbk2W9^~D}@aK z^ttk{6=hpa)3G^jzUMY-3uQ^85Qop$;C~Il!5a9hbGh1+^bDu(ZVH7B1J<3khW|MW z_y4LR>jH2__9H{$18~BAZBP81IhnHFMb)3qJ_=M-(`4Y|IXo`*uGcop@SpZ05KOG+ zyWIZy>K=szI{mLr;j&EDHiR=UayrGk{CA8OIG|ZfOqULgTcYsszFMM29dxrg1DD6i zbKVEbZYU+I5#?BHZ|%}dPC4k{!Aplao7E)K8pp8@&W3jl^Irew;(QQ5ZL*&h zC3nZ7usptYG5AF$0=T8lx#?bRM;{;r>Uy4z&cJ9T&zehAZEeyk(+Yv5c7ULG+Cr=l z>e}bGF`Qd#KAa;qH_;3a`2}#TPNwY@0L|H&Fs{jt9kjau2;+#VFOS$(PUpNEr_jrp z+4a742ef9Z)0`&Fzm#rR4yd8rLW<9=uw!Z201|YX$Cmb-9p84zyMy}r|I@A#16cKb zIqg}1)M9pm?q*RfiuZK=TSP_ccPX$(U+NoFn6-yd%I($LS69xBmotfLW}bkEJu1JT z$WB4%+F{C_u4!t%g!)!^e%vU+k>y8F$&`L^{YiAX(+=G|^fp)Xt)0wT0_dqL7w)0)%9v%vgb4~p zEN`>xK6iOw9eCZ=HB+)SFn)GDk0oRSFpg^X+sFad8uzG=fE1Xm=lBS{cYRKn8y&+4 zfZuWvHS@2(2c03jM%%J8-h#fs*;wPv3fj036_T7%^f%}I-cB;C^+!*4tUf#IqW!St z!X`DluU97F!mew-`!p_V-F#8wjT;_(210n&so=H9HRCXR1*PXP9?!bP_E^BxvuUTW zm!)E>mD9c6R9|Z};s#pfwXN%qr!h%&=DEi8{Ssp`JWN)sn0{unDJRNZpwZVV!t-Qe z{n-m3CL-0=k1d#0Cnbqgj{hn6KK{iAtD@B~{fn9g8UIY539N;=XooB0VpF~}-o_$LH zH|JCWFcr|}=0hc+ARFb&5fz1M;HCo*7Es-`+o(8#OT&O^rAcxt&UH(a0EhE+Y2p!~ z51?9xsypl>mjc%XmL!hh(ftDVqJb;|+L0{o;%O6DjUWT*3JLAt{>wqFKSES4-b?m*z2Cj4FQE*5Hbd#$9t`aJt@yhstKWO1tx}{`H1^sm^ zxz$|%a%p{NtW;;eeZZRTj(XFc9#7hM);d8O|5uk>==NOUI)CRzjMXg)05+3|R<9B$ zMG`vsn9^+z+C!%&(`bOKS0u68)rZPzI=yZ zr_7&JmuJ{bO@7L%_766sFM|IdsP=T$eFhDe)=6}1gil8+8(#m^)WIyS=x{j0uxG<% zDS1m$;c}OD_*41x)nPwtMA-|T`pcPJrz~=FUu;N!y2n9h55-#-nolG_*W^#{QGngM zp_M$Fr&<<;uXFf0pRsq{Jvj&HkKAY{`Fg`q-7C$u?HP(V{Y(@kK`eTP&I(8+QY1a8 zF8TAwjmKgX&+-;g_f=8j&Se z_nmx}jWCOPM}PbiZMPhBmT!1UB>{2Fk60CO^3OW}3qCe|LiH*lsz6MXC+0VxVjljk zERo`q0TG_hDWFLXkYq1Zy}Z$Gtp-R)&aFLvqH4BkLRcF#gg({o#$w<0T6- z_cs*0 zCjn@HLYt>eF2e1TQ^^aSJ$GOLOhIvjo0{I-SsVAK-RRRu=D&=blSvE8o3~xcLci7l zHR*~-tb-2!5&cUUXn8DuA3i~< zpr>2B#4_H~{dR){pq2aQX{-;B)S)UHuPvQum{(%#!gK(w$cf0hxGiBU%4KwjQ&?FT znEi4{;CJz&4aK74a=iAIh_AcYr3J+*K7#nH&V-QFg50!q{5UtLlT(&NL z5y89p{Soc~{Kk*}9tH_diWc^Uy63$z`Tcv^lXtsV_y3gbHe8xGstA2U1bF`R(mQTo ziRdUm;~f)QH-K*7-^E?OA*ZR`V$jGNL1SXBP*k(|TwDe7}rYz0ULb0>RX7FpIr8hg)|m zTuINkg6p6T3f~zU_dn{UXnVOdS%$yoZ8g27f>MQ}I3Hhr>4q_%MPA!V- zow{TCjjlGAe?L*zi8A^*VUkiF&a)Wwh*ZeO+La?`MXHbgv%=Yma2@()_NH5SD4%-S zrF)alx-@-X=?v=;I_M)#C3 zs$O||ig1XiN#ih`Dex+WV%;CNZKu?Rq&X;CqKY33fGyS@R?;1$iyMfLP0W;*{PtE+p$BWYCx#j$I#XJT=W^v(n9cBD>5 z2PLRyGDExUyAtEAhP861H*9v%7&%_ArE3v0{x40)Vyfc%@CbyN5AjH$LPpt(-qP;4 z)=CSD+QVj*d*_O4>htiyM{6o7)US5pR9Jn)XV6<*eIQ{9IZzq_)#7*05?khMJPB=#ES1fgCFwYT7k$jXGW1Tw9;axcCXJuIPZF}i0C!NpCs z*(dXX7UQK}3qQh@uZml{cqmLrT-=%Fjq8e&L=-&stAEA?ZzP`k+3@Op3L2CG|9(rV zV#1kCHihfXPK7lSK{Cr8S)3*8VL1HfnB-^A9Sgng=CK>Eo5OT#p9qrT!Sn>-=>toq zNH^VPb~-_S(H6^4?9-`D?Pa`=^|6-IB5Lo7_DG{=MxMbTb8oqFmUD%!%~A0jE3b#` zbM*sm7ZWPsY4zVw3jjGl#=r4vy4tUt=Qi+M@dp_eB1vJOVBNj1SMaxcXOwuBmUxzT zSKvoW@g9$Ft3~o@Bh6SewkzknEO+05DV%HgEp%wqkNHrVSwV2_sDaFINu4@zmy}ms z93PYF2uRIqq%6|xAW;W=ly-~ZWn|i4mXbyo_Hr5m?oq`)Az@&!)Tvkdd_sQke(epe zu1LdDQ66T3?pQA4-T|NJ!GY+^n9CqmpmA@?H1+~&-T8UMRbK!LKGNBMO1MP&O5<(3 zKTk2<3<=hxvVc`&MON>iw^!t;Tj|hlAK8*DtA42&Waz!XliN+5XU&oVgtApbRDn&4 z#a8|0mte3?rOyE#?t@qhXy|W4+>0Xx#(yOtZ0rEU3-OS!&|oyM!+TxV>MqG>OE(sq z!!n1>?yHTx5z9tPdfW7ZxH)mXv)m&F{NoHERbCZi5hLmns_*|^9zIIKAZYg4nNCFH zl`Ctsecu~MvoP_(Wc}H@)PY~c&$(wDRKi(X3_%&qO|a#=El$!j`Yn{|2QS2n4h3K} zjC2G1@=_X3b>?ZY!}0SB`vYV>3lhl#aL~e}z@*nAM17Hpj`3WaxSY8x*&m#C^VA22 zna-f>)m>lAjGJr{ZVs&1H|CFMgz}s--mY$m`8|C@G8J}LINT+M!j)H&AjCG~t17EG z9(-@0kg;wYsv<^{c`W~MQ%+X0U>SGpY2QqasuAM3b1cD!@BvXdoDe)B(*qn1ZpO$| z-%=e~4I>e%Ao4EV;h~U=5l-C^>)&52Bwe_|aBlu|(m6d?KeJ8$L|)G2r6lw_v*xTb z+%I;3Ac)T?vo$NmjqEVD>s7tG)S`cYoAmgb+$G3d)+AMz?+CkXNW5#*fN6+!k%!($ zKgqfA?!R&?edOPRxx$rVNHS}!n9V$g?yhvf*coMi8E2|<-d&w~3<@9BlvdHI_$kOe{X^wjslc*4{7ACT zI^)E?#hUeMTe}NxKC-7+q+T}u@#t+pFnN(!h{oVsX{rE|Smk3-j07*086tov8QB5rv%Pg!h{gmHE8QUY0 zm=GAd=9!$Pkjip;{i}bWgF&D!`tneIY9kg-^3i}Pqw}t9$n~t^c*Tp|Bu-MPU~CC{ z9)_Dcb<^HBSYZ|5jVGX@^6v~U^DythsVBcIsudX%8=P}FwR#ntHG_qtDrl2U(c#Ix zCna89CMqZW<|)(|C&fbA@4dJEa+JjC+}o-aSuZniT`&prc2>1$Bg6~2M zwq-+qBW47W`YA{%+z^r^j7FF(cA$j;IGn^?mY25aIDRL8+0|@Kpn_7D zctN!bw6X9-uoI(*UFCT)w&~#4U^DFjb`D~pE^H~va7GjjaR>|pk3o*POsQ6?HG<87 zS9x+p%$C_LcZ)PIh6Lwie6X&i!A(}A?0bGr#n~SjFvV0~G_?+E)%-miF1J6)2lLd@ zmFCbF&Xe@``*MG-*>rh@j8-jdis3e04$|u~oF)b-u@^;~hm2b)#d~BAz^PtfhHdbm zD-3TdRzLb(ZP?y4uucjN(QU!D zESTRiT&m%<_JV=@|I|VFFHYp@FPX>nhn#B1eHrU5K(6EvCzDagru)8{g^fY9$knfS zv!s?Fo1kg%Ge)qE!aT!FWE6nW7Sb6Xo)wWB64|{dSM-^y^DAjsO|}Tu-;t!#!Pllw zjqQwMQ|w8_R?{)MAI8|key%KrFL*Z3 zED8&RRp=|925%%;-6#K%94qf1A+VpA!)Y+~2fMw;A3yhbDMj?lQs`w(YFr%FZz%sB z)T!ztM6{|RN!HCMFg6YpO(ap2jLk|XoKLuraeb4RL|K1`VfUk>s65;v4(&SD?e?0f zZ%VpMrMPL|Q1CgtIxqDeM4RBERBl{ZCo258H_K!HD(95ZGCPPRw{4MD#4k1P1P-|@ zsZn6~P!hv6eN%0r0`H96;_FAEE=pAXmUdBcyBuJCehfc5 zJdC|fq6HR*pmd#rPr1S^Te~H!l+qAU9xTpJ-bP$ne6&pfnH_C$^h#(W8y@2Xh0l#& z#UqQ+nGV#lGU1)FE936O!eADx%6ZFM5`QerLI}PG6l|@ICa3@IP%deEe)3DO@8ly4 zODWl`!d#svQ9r(k!cHF+!)0MVjk2{jut0+Lt37pLu@z;TFN5<%s|2q!n!eY>JlBa_ zaewCS7*gzM{jXPzZ@?rwyp=dcY-8Ux;bgZLyXXus-oMSqXHmQe{c)X=8s}+cx8&l^ zBk;ZP7N^aTJOd8*3vv}YGt9uISIEqAbArxvzTLW44!ZfEK3a3LV)G&07z0)Obb3Y3 z8+t08#-nW3Ft`jv^b8I`jIZtjv!~khKJ*oQDhb5uQZ{+VOh;dSsY|%9a5oSr4B`?q zjHse8t(&a0fMUqBcax9era0%DRIowFm31_BI=hj$OuEolf_sdG^x+v-Hh3{uw}=E*Ic9X9@xbHs-h-p0L5EHuXmwc zEi6v{G=%49YiDcQ5xm@vu>h5|R_BNEg2LlHf=ESmgfQ)DLYI9Xk4}c8Pjx+!Dc&50 z`=-|*5PVUhSW&JX1-$E9Cbn`0F|d>re#*RKsJ+$-%wl5XO(R@@vEJk$KXs#heiV9} z%pQo4y^|D~wn*8J#gknu(fEV=JD_O3*)c-kWc_)fRp$aD+~z=+H4zrL-X>Yi3*Y4` zG+qgJD>@Y4easY`JFApAT-=x^T^1fK?ozz>oUSRGqGeJf%ys56-*to@Bv0XZo>!yt zoypQz6umtmSJL${`~%1Sm$A(3I|`xL5j&EG2E0d&n=bGM$W{D>^}pZ5iE;1JHIesN zTME*q+So?MlE|jRtd^bAIw!spFRZ0G&pxG~p%&5pMaJhzaQ+B2*;nJGw?Z`x){kg& ziZYX{Pdup*bO1pY6-%yVc_{jrfhtW!cH={H!pW=%5E8v57hf75yXq!j6A*YUT_(nY zqAya=TN7K&){pSI*pQ|V57*8`Cm(kfDGdu{sa)oLNNOP>mC2Etx#B!Ip&}Ww=7!W@ z%@_}sJ8B?&tL#4i<8M>Q__$h`m(^K?Ub>EdRI>;1NX1lkTvekTV}tf|7yNN3H>j&O zKfM0f0Z4At@8(bk8Gru6{|OzK4djQkoxbF?quAPZePG+KnKFjnVhr*Zr%0 zFsM4`?6udLbDz29f;y`j0vsDmm4oFrir5asxUj#nXTmcy_5lvb0T|OFMVT6_g@~Bm zfBg^=+{x>F3^mhxG&a!5F~TtBAGi_nr3vqD{E?X_%Cm1ZtE~=8>!X?`#awZCOF;~F zyU7&s?3lW}9K`}3V;%D>MSfw%@x(%)cXCfy(!iwt?Sbwt-kqNNer~RCDAS`b*1DPD zm&Q=cwipHI$%K|>4ZpM0D}At=eF5<{&CI~bXH2v@O z$bL?GkoVX7QWtUQW{f3%oCj*J3eWD(CWL{fS5Y{2db7IrH^B`*8F+nU|DBj@K(l;+ z8=7=B%^2JI7rDKfLR34gIg@Qj6m~>MT3dy|GLp51Nujcf)!qp7UB@N zhVd&CRF^I~O%b!}N&0?U^nw(1QSnfgD#58(3G*=d@*A(uw`*%%pwWz% ztNe%p)WMysJEsRUt$Hk|Eo-ylFs9Z(LnPAx-@{&ZqhLd3WC7)3o=4F!)~jQxsMfWJ zvLT)}^0wBg04-$>tBWv?$m@CaQq4Cy7qiGOZMICBjG1GHb(S|r3q1Q)x9%`UVGLzv z9{E1M_lvs~m;n1W2g{r~84rGQ5L`2xAVx>Y7{x)SdKtp;byw*K1u0Zb-K4gV(XQL6 z`M7TQIj3zeO>B|)7Gt}npU&edZDyJ^qNu%=gEtYQ{OhZ%mQZs^CHQe>gTsr&JB+vN zs35aF6zMo-)h@u};`6q^PB8z!^Of^|s?Kh%z(*Cpk3yspfKV@!m?=)DJo}B)xZvwk z9TNGA5XNPcU{Z|Xj&OSKNR?2>r7m_J)I<0s5&(zzc0=)L+K3jx1>Fz zM-rK%p;oI=@T6h0id|^u9AOaF8jG|HsI2*@<`%iouct z1>l*O8xXd}@Fsh{nWJFS0F(E8PVnA<>x=187HG)Zka0EJ3ey_MnZbP!MdPM&p*iVh zxJOfxC&>cp#ixJp79S@+XYUNC6Wm7)64Q3g_4BDu`)H}PS{$jW=VUSTRDdcNo~_gJ@wnbbW_>5cCjIA9U9iqe z0a#L5p4z*Hh7M`ivWPg}dbo?>MH$b~Dk|o0LnyJWET3bd6NH?iLN2_uu-qSBZSiyK z{9BkY5f`cCLz}YzyB?@JXkPSsk~QQ;ZxeT7+X4iBog;cB-~2i)I^tsZlKr1ZYtSY0 zOwf|^k`!vf_TxJ}1p4Le$U7*)B+Yb8a}OG^SJu`fW(eti%vrIv^k!-OYEkR{0|}FOD{U9Q5ytkriy$@% zw?e#9vQX(?vqy90zh%Mgz|tQS{DyrImP(Z0d^%CE*y{fJy{pkp{H_$(kOeP)S3^#h zX}MY719q26`VNd?qeA|=MHwzc0U;prjbPSB5upJ7bNGDds|@7ec$kq^-^v{Ep{$p5 zj}fHYMe89B5VKRrgLDcxFHVnMqcU>`LmdWI5W(Zh;e%MB+~3^Is76d3Ng#Ze!EufG zG~03^jhxgUKL2%0;I8L3KZGA>_5n5L)Z|^j?xF zRKKX%hWNpFZic7By!3;+udSvuk-A24cPcgmqM@J08|R(_8~)63#|DJ$+W;QL4Ugqd zoVa66wHJW#85IeI07$i#AsV z-Up~p`Osu|+TTcFXXg&K3gLZ6QBREBG&v7`FJN_BFg=Q z8^^T?o55~kTrtz)Ag_^h%RO}K zn0d5-2__I`7TyOD&I_%jQi*V7?18^9NXVhoJ~R93Zd7UCmvV$ECYjAfEkilg26hyi zGk6MCa!%+3fuXVAGD!=&jWigu&;n2B`U_WBu@DYe;l7u&{Uz1>qpvk-rFj_78=9|8 zZfK5Ra2;Zbkt`nkwhz}-WZBG+Ord*s-DWX>-pa2>N6$ke!;x!cBlmeDoekfDR2236 zteL01cn5RwNt%5cXK8aS9ABmK*D{I~XS>afqWS$+!IN7M(>a{Eslek;vFaL z&3r12&p)Er`^V}ro?$n8HiuIrgx$f!qx6H5`YF?wI6!;M`c8(=%g~GasOzqD%}6T^ zUMkH*wMY42;<~tou3azAiv2LtE_A-d&?TuFE-nYiQ_oN`~c_kNZUTJWS1T+q7KZ9Z@@P57Z5QjD?V^ z-Rv6!?E%?!;Db~;WAjm!=n6pD*^E-^wy3x)x!2{xkY}l^`Gg(VRY~G$qs-%CkYTf>zdvYy?`>DsZPC=%TY_g0zU7fhYEERTg6|0WRvHH6ZGee=IqmuL8ywO zL@=~9oIhLk@0_v>lPXb4qR-99zscA7@Sp;^@~4^^d{_e5WW->;YhG+ZVF~PY-jjyx z%Q{n{a~H*Q&kJydW3|cX5H69rYeCce-`e<3%8M54rl9h<36if^jN1Q`MD#s`Jn6zv zIT#>D5W+$jyvw3F4fKs}G$FgyxsLb!b{ePg`Yfaf$WAvO8xNw}WX!s0%_lJ|sjI*y zwEmj_C^7@bdPzl)%K#A-7 zWwJ#X!GS0-LTGuQ)qhq%RzNSSVhhyUjj@O22O+4_R*l;Ufo&xfUGM*y8j+cDw!JHG z+c+f(oD>MQBo)_(SzlUvsat{sx-DSyRCD-`u{hNBa>VjILR1z~)OR%F#Ts)o z-hIffeWe8~ZCL*2ivWp0a0AlMm4x~8h>mV_!6VjdB}dy$$nH)u=bP(XuNr0^{`^~I ztrW7;qq-?2HPYP==v>wV@pz_qJ#LO7o@V#m4z<<}5_H|o>mfO;84_iGpibitwf~*^ z?Y}Jaflv#5yB+lzXq;6b3Pl+bnpF1U5?P8dI{r_KSq8P-Ww<*s{C}!ZQT+5JAvdQ# zP9C1|{}!YQsXOhYDM5I_?anQE-MDt7}2_N3;AK z)TSQl=ISz|B-vaPH3-YBXo)nS*SK-+ph2&mTa1grS3yj zf_^=nuxazq4Ow})ru^@RPyhPx68ZadIqve0!Uk%vx?q}d3{A5VBCF>4Y0LF(*G!y- zeJGs9L-7(%>CUH1hc4jVDu!RXs}aAA>p@)B#!l?bXZl+lJTsj8{9s$A$4_SY$>;!e@a5cCr5^VAJ>p0$Rm zPY;UA$Chg~OLIKj&Y^lisG;P0W<%?#6=WM&uQ<&);psTWrdX6U_T3qy1JGa@TcFj#>c`VS?rly4&QrmcAAD!&0asgDA{ZgQ`yuT6$jj>OTAjp*Qw>KgbQ+ zprM+F)Cq$-F_!*O!mb?Z{xS!R^PaX$ws2j~s8n;6HyspNL#K{Fen0&2<+eSevGfaQ zGb-TIBw{;s;=ns1OAORu5_yz=?CyDoaBenT=JkU!zg+DKzPjB;+IV(DCn}skAf`n) z(T*=!zlu}tXyr32+z;q6J8H#$qjUJ*iGmb%obNJ%_kIh!g6@45Ae;RVN|Qc7G3XZ$ zN#P4Zlr0c~W^5O56mV5czhqf0XGQU`9r7Qt_1g(rCduo|DYCL~B%Wu&w?UjOovla4 zEDq6vFRs)nSI=Sx&`||Y8Bv}3^@J#TquWjr4RShWArYk^QyoBPG@k#%>^ea*rOTnzd z%apaJzSdK()8RUX8$n#$EXbc6{ojBGq3Tp<2h~ERDI@{7(5%jL{_DkgT}T>P@keH!SCqPL)jwe}A%%Kz{~^3|`T}yW1>AIYzAe4e2L>yV z@;_z~!R5&&ZA9@L(AHm$@tP*jt=#=7wwcqi;dg-={U7W8POnITA=-e{bX}4wt+j_) zM*bOdY|-B;&^!FlNd6Rc%&d1mq}Df&-Hkf~*()b#0(ajfyZvnOVYK8<8h6vlWe3kB z_R)RrM4g*}YA^URPmthnv2h#LVtcgcCUOX0s2~$E^*-;#+cgfp=zeoeBX}?ETrpbF z;}CQHo2hvx*`lh6`Z}WNox~~RP7nxcCAuWE%;$7mM&+&MNZ9mw_jAA(&YJDj9#A*c z#LpH9|JYv(#6EmUk?<0KwB#f4ysFN49?AUE51W9v$%yvb0L5fV5Dq%6iTf!0i=f{Q zO>j5RjROd6r3vhKc|6S+os{~VT%M>o57{ii@8BvIA`7w6I!Y+hu+~B3aFnh>pk!G- zxNq8ay|U*!%MRmCDV9~zbZ-)|HO(>uvrZt%l>4>|nT2ZY67x$EEz(RZ)H>XH&Ffa~ zMECm%+^<}@{D0=GKwZDnz5`mc?gUwlO2+2*A-TuUS)uuAll0ZqV14sgGAV)!_N8Zk z7D3<)CMss^1*++*ZM#f6t?_=C&ZzSgwz&^ryKrg4wsfOlemp(~N4gF@l0HM<5cDgb z?HnMLyh!$md<^iNb2d|YQPXwXp3MvuH(b8D=!7a#ah)R0TKU@(=I}par_v~9 z84uVjeB5--5}3E`M$N|8@w)y)i5^PoTeJGK!)dyIxur1-ekp~nhMW7dkkQt(8B(G; z;vO*Q1n(Kncp1j-ZasL{$*H)s?gtR?n?$CGz$NJl9Y(=+AEW&GVk5;DLwOJ7VuOY)cpuL{_|6D_=Ewd>*3~>0rhv$oA1XZUENDUj2E-XZE#O ze=iFlf%VqsV&V0HJc0KxP<6ECnP~hk=viK`%@(xl;c!^*#eTL-hWjeGqR#uSn{?*| zD7obQc&xPwlD^@8uI3z`cE6gGbl?={oYV91A{jT$@Z#9Nf@(8QqV8{8KlF`XWu{m+ znIA&Ro*8@S9gSN-`PCA(oMjEy2KUKlJx$$VUWSPmjF^PEuVHxu7HT`F;1BMUUD=8_ z0w8tcjYD)sb76I)1nAJE+4^6OQ*kufk8;c&r2}!bAwO)SYp0%G2WW_aXIqoKOF6!7vjtJs_x~fULuR?P#G| zOP9C4^kXz9g*FT5F^!I?9P_8#nd3^X4(C28EVMUe*rLH0ES`q`9PStRf#Qu@)}=pC zLC|<&{q|ES?yL`{P@&Ke@#VVyhoo|kl>XZ6IaEw+^D%(U<`>KDxkOm7doo2#=)E#}s0@;FPQgTA>_7_79)~Ar z;OqL5M}@&nX|rRRbD2%Z@<{p){$lTu0J%gNg7vK1?sweMV>rFTRl%#j9=5Hp>jL$@ zF<;3?=>xi=1s?WfyNf^gl5oX@zP%q5>82fK@wp#v@r0gMxhbowgX?G5$AYSTddCbT&^1Eb0cDS>r#~Ac=l~-`iQLd3uI{UQDl;@(U2~>mOPIwW*{-D zht1pL=XQy-a5CV1{GRJ#fb!DrLvnmKE!)`TPR|d?aw3XlQh`Ln>C?2TTI?UB>`}g) z+;Q82hCeCv$w^^xDP~hf2Zm9$aoLDSq{Ab;jM8^T6ZYmxr{#H>ZUflV#l=#z*(X)j zq;xh8MrU$UBexu!Kkr}Jp}Xk-Xf=yrM@ ztm67K2+c#P%E^WxMCShXh%;Gt0~SJYp_IhmO2Mv2`5>)N3le%%i#Z*v*y|`A2)WW( zc*qiIh_?uTwygTj`$^ZnvCk_@-J>ETTSXlOle2Cix@zUP5s=!5HJI%Q)tGlu;qB}t zueKF+CraI>-Eg{Za2>chg>|y#cwB4^x)BMb`C%OAqwqX==Q$;IyF=~r?S0>w3yNW{ z)ApjIxIXr|wbH6+hxfKZp3{=YShx3CCxYSXQng(~2L$E)-1bSzLIu?c9#V<=v(bCe zdn%3O3_%#p%`z%4tZ1iY*qxG-CzUsZ4G(6zShXAT1-)YQZ%WVOFe1a|pi@WCiwIWZ`SVF~=|BiK2zz{$4ZcM;zaD(ioNu|r5+8FK=58~pAvWdas!VzQ4?GaqW zs7q~QOVJkrwxFIF^VkSeid4ty;Yhv?I60i7349vCCi1R1ZHG~cf&T60Nm8b$VavjV zf)$rFejCt%B|kQAp9Dy)n|pgG6o z%X$diF29_OWz{g6|7sI>yP1Ya3jQ010EHSswV3PFLh$919yRz>CRxw%)A{B`br7UJ zG`PzOONc?)#UP67RKN@KDH1DifFyy8j99?QRb4JSmke8VmxUaba~9@TazqCM zM3fIOI(_}vm}QTT6s1Le{(@+*r+Mv}q(9r0g0hHEB)C^_Z_fjLEsr@Vp4RS*K6jCN zT}>_~tw8R?D*NM>y?M!oFWUrg?&6} zw)sZN3BkT!kmhbWxtnPLY_l?>sN8274@SUxtVcsI$=%l_#EcM=R|%JzyS1l`3Kz4OFO=Ostr%77wI+osRr89zH)LRgCIOuHoUkic z>szYr@~3rAL}SWJ=oG1J5-Z1I6Q1!LfY0-Vhb(r5Dks*eKxS^iZC?=uU4Z zsK)N^f@=cgY3vs_+$g(qJ0Ic(mToEOIwyqPzwek%Xs zXx|nP|LgIz-6vwMM=8W?rxNJa&$}9XpE;Uk`MiwXACY zT$rYNr!~yutnDSziY3(bLxCJyPmr0PStR z;0v%>*ZY2Zj5A^koh_ASD@|~QwHZ<>^-dCWoHcgqPa4p@_C&2#?*j;{T<_$&?%%>J zr>tH9c8MHsC!@V*N+FET%6dC^?PdGr^z~(&AHsk&K8Ex|n9e@rrx|zAoo(AT?b={$ z@7x}b>v_w`PgkE$T$){44|Pr`N$*3TZWO)6d)E;D*XS|su?lXzBwSDOQ3`%_+e44D zg-(Y_6FeKgp9ZI`0e-cf(@>e3zZsuvyQvk|opGPDdijHd!srbF45s(UtA9tJ-g5Td zXFIgTFC7TGp_sb}`p{v4F3?=Nk|PaXp4GBRdrmkzX}#6ubl8#IwOTMWHi7UCm*Voa zrc1c+OJ0H=jio=N16wVTRg9iP$?=Wj-Z$0Or>(cv4qD%s&n@~Q2s9eE(s?9a%Af-S z!Ezktmol$sZ-W`NbyjKf|Hj2ddmR~$E!~dmJ_a)FsvWNM;^`gHp2lO_dM+)kCj2oS z%F{dg;`Zle*+zPpHK!zia{~cY;DL;`Jh(p7fBJUe^a%DAim0nAZ#oB*ij*{XNC^P;(%cML)}W0lm)AloqGX5E5G z%99Hxr{f`13-!-vJsvoY;E(oFL}N8>-u}t8TF}D)D81YZd24>ZMI*Qm;b&!h@1cHB z-+X+|!}Yj^5Uig&hVM&V$IzSXUF6m#PVWMKSKEu;3qSeG260=puT?GJZb7^ET5jGm zsxLX*SDtktH`A%)4Jb%9J!MYc+jxmSUL}otN(c^}6kj>L8G=BHyDpQZc3sOpp3_YQ5Yy4SmuZ*`S-H^v-S|Q*cc=#B05IvV=FL*zw z@Xzv;lwffjqZ~7NQC!1dm+kyjm%^y z;=lI2K7Pxx|?*eNK{ClVUwYah^gDuhGOlBiQCP# z1m2Z1_wY!Z<9wG}!mKaw9yXVPyI@xWqKu2>rC^&B(KD1x?aqDjc-{tt4S0kOZO}_d zBchd{&j@CcLp0HO=w||bIKIim^2K|Rq_s!1=GtyF-WpGGYkmlOsa4ry&~t8p@qQ4N z9Y$xZ!m(M~-!1lS>$Y)=quA$M+vghOFW&uF(qXf)A38BxV?M3f=D&U76}%=w8K`0_ zZZWIyqB)gc2lwDVwcZG=$TAHj*1r8=X? z=R`U_N~rS;Y4^vr#B-03Ft%GlSACaPS_6wy4G4~A(kSsrySd3_(D=M3q; z?9G1Oi6^1KqXN(HI8zZsiO^o={o-#zp7bp-hkg%h;Adp5i90Dym6wY@M>c)2M1jbPv4ko56agwwRlU;ZjI*bzPHxzO2$qx^obhM}IOZ zcZ%^HA%p}$u`Ln%F|dfwhdP6QGO3=D&rqBG_`CrYSdM80O$ zRT*+-l=2%T#|(oY{>S;E784;Z5~pYR%C|-v`qv^5wKXfAuwfCe9bn@Vwt-dhn z&3nuqBVQY`S+c)kWRC3TxC!vfz(PvF7J$o=5QhXPe<+tRid6$~I2V9KZe!539^5i* z9X1V&i&@RB ztXyBamvq43p5wFnbO7u-d0=cEV!P29{xGH7-8b?h1O32p&>fZK1wBB7XETUH?w8K; zrvi)?M@@B%m|bmNjf#lg;3{Elbu%IMBuPToF%N)hW+5iPyJa)Fw3+SP|LbHAy<6EK zl~cL&Bpj=ilzLxIDOoy?o;sEP6U>sWvM|9Fp@r3C4_{|*Q!uXLs)E~DyXkvCx;P(zy;z0EjlF4;_e%T_oE#tZ+dW)&!0 zle^};V@b68+2-Gr7wE0oO!=xjRbHu8k3X^V>1M(yx$@I?{7qyX5tc~47MMmZlAzT@ zE4=bO)o(PJ5RAxAhR%q3a%9R0xu^`ooQsu;?}*!af*YiX^V5G!`8vw1z*7Q=L>|e< zc~wLFuKE-%QrU2@A2IMfj zTRs`eBK5}Gy7iW*E9nP2?6G0x7xYI5%C2DkVEUfuK_478?f0w!Gc#0ae;sqbla(T2 zgrbRo?<521E~0H5yT@IUTQCG0fB5wJ5QZdH(6d-S)x9QypOUN{?}CJ7zHDvjEGsRj zICB?ctg~w;|9-oa$Qt{zhSl#-!adfV+RgjuHJ;g$d!!ki)VZ#28ROdBFtM4&dBwt zmmEW<-Dof%MfYx`YamHzr+>@)F`+F)WlmVUy9;D zg{Q@QzZw+VG06Ly# zTYC5NK4u&RE_za8NP7&4yGUNUey7l~-Em!nOG>|)G-h(E7=;^ z!0eOokmC{jgk&N5MLPrn<`)$KWjD?}dw_YF{c%k@W;;B3W8P3<`uD0B0jq8<5b_Q%@`nDt?_`F8!066hn49VK3NK1|KB zCmPmAAilqyHvh{s*yPKeLe4W%sO?JLgwKHd=mg6EFP$ES7;v&#An+)<(c*$2r=};o zx4)=Mp8Gz^nRhlJ4A!q<^SwkBKJgf}E2)b0?=@UO5pfV}Tf{Wg$F7ZNI~1Rbl-u}B zw%AJPN&Nf~bdNQDSofD+F4}n85^7`dovO;0RBjg>%;q&(FPu=$Z17LshtT=NBpYK( zotn35U10XJW?3Un3|^&Su@JAPerxw~ah4k3P8ia2Y0fVmdMl5;Z++l~$?&N~;&8wQ z-dwz%X8_jk1{`YIW3|cFlh@wpd2KjqmJJ4L9-RuNuwk-Q0!#tK8IKQuE$fm`2_nVi zD2d8&qEZsoB6#oLa_EqUvFG1^10(hX^a%jmDWZ7^o4)c*?j^8KHhw_bN@_6n{YHf% zw*RKb>qiF@D#3{|C|_5cQEPq1&1IOW{)2esnGVZEIcvw?T!3NcyVAgT*5BBvjd|ag zKF=1SNp($V?z6eZxUARyXq;Kc-ldqdR@oM5o7=7$f(-$v(Y|Kx3FEr=8&|Q11i#DwWdY02R4&#EqPcDAo1uq`;U*#ogAVJ6J+BiHm?$2kYo49lX2J_E=|52#J4KXZlKPa$C| z*dhE+N2yG8d2 znizOK2sqvin`9Dz?B~+y2=07<*bbBU)`xY(SYoX8s&M~?+(qm*(^TejQ@#?H*$a|= zPE0iEoLxmaaMEj(&Z7_c_1>KF4*u1=))cdYD0}^OlJ+^nXP2LCMsU9dy=Xc#@;bIh;%v+L-6`oD#xyBqQ}PV5wAmZ35nQ*811=~7PSrm; zt}5-OU?lwpze9|j5sRykLO8i&&`f>5BwD#5ttX1VWg~^sJC$|#Bh2+S7^E78{Spjk zJZVrh+eU*P4glsz+h#K7iD9pQR|I|b_T@b3v2iBp$tj88jO}-43rSG=;r~Whbb-0Tz}9JbU)IeT{oAG|!PY3WiGT zV}|--%YDv?s6UP*G@Ckw=FF$mICef9b#YXM0(~@i$@Cq5w)|a`Ycm%_z-eRFs`*7X zdF-eH^2b>Jo5=QA(vy|am&htz3>TG}MOiZ}j%1R)-%Hk`Voj{!2t+CHohaEc)-_md z$2rb~yiSy}W^_YB4_fO>kBWK<@adKAU|3~s&WkyWZX`+WU9fLrex{DpPld|! z^5G;Bi_XwJm-yy*Wf8_)whR$rlXUVq*2zml$Ozb5qAaE(Xk+(1+2 zvOOOxWHscP@q8Nc`WhQ-{s}uNEfLQlM&OYHuVADzWFhl1fZ2C3=9t z@R(8iC<QiQXZD|xSl$OkOLbMmR2#u{IO!B^2eM&F0XQ6_ztbF(+miJFLq3@5fr7*`&=AhGtMYp7JC zntbyG5^Fdp_D8d*@0#Sn0xRfdsRp-l(FDVbFvJLh$Ym>ADK`#^>*0}FQ*nd{7z(X> zs|U(-a-GlPMm$S@E^9tcs-FYn~}u6gr93!%ihx(Fn&c0i8Igp6_xC1y^8j&1ru1^53*AJ%!&Vx#xwRRsGbF1L2{f zJqUyFl5F=8Fm-da{TrE8jPvwt$A9|=m=dtZk~XETt9^M4w=u?uodzmfMcKOKbYUhM97yN>y^Y{ue2@XRp8(6qyO4Y2E;tJ`i(~H{>nBgwBoIDoIJ|SQXIVO?K05pI+5^jZS)zzf z^y7A_Kd-E5CG^bF)0Ac)ZvP3me88a+HZ@g3)1rP3i z+7IK4J6lKNd9)SQLg_3qA=ZnH)0pFb+1M$cVc5Bg+PBgLx&??e1eFyySttqpUXhvwM(FXDHH zDzir|Mt}AK_ct(f30O5U8l5v>4|-~&ha73}A|T5w6E_r49rmq5l%mDVcS43DwPr8W zS=OP{(tuG*FNZu^zvMy9iZ z`o`QDDZTS?m{%%EE$z#8|m#~PAU6Vru`StuP zMgbJpB$-M7lJhl3cUqu|$m*t2G2i&BR@3PCO14PM`27oEh)=8;Me3k!>;M%^d%kRv z@>b2L{0}avInp0fC5&YkX|qA(%r)qlAAX(#F7Z+MeKesv$x27lJ zB)Ni5C(0)6e(f5o@e734)(0?~8lTUd^6uMQ-4eD_q~sWj-H}0q=Jz4{v5Jnl{fPPu z8tD87{aQ_X!21kum0MKc@%NR436~Go!#r}TCrHsZ+J=Oy*zGa+e+=!G)%IQNL?1=n zMfM>P(-OlICXp-8a7_9vGM(iDL`p~$KKv%ne?7yP!PQbf$VPS^w^FJ4({hWq8SR~) zElu1^cb;K)gIZsgc=JgL8s~OKqVbockFs7gx3O;C? zM=QRYcF3_cjTb#Rz*qxJGYsgRJ$P|D~ z5!$!wvMBY&tr#+X?(bP$Lc(Bg_pDiVOnEKxW06Ubl)lWpwly&>tJIzhi$9$o8V*kl zmI4oD$HG|)ALN%tWtoyg^fZ_1N0_!Xr;>RrM4n3BQKhHmnNy3rbC>sfRW|hc;c(y( zZVISZw1Ju3vzC~ps8Ym?al+W~$?Oc_#W?{wygbjqtk!}E&b0n2xkPxxm7RSq`|-}A zl`k4Tqz~mwH}rV{6IZ`n)ke{~W}byD`M4lBXG8g_nFtHt2VSsj1!FznW3y9$U)gko z-l5dAVPBRrS%jL(ecm%Mgd}?K-T%gMPej;jz@hWqyP9bk>cp{97Wy8Ams-0j-Yr_ z$R~3y44sRZ;v+>$YtQZtHJnLrd`w;V$_MKa_Ag!|K|9DbR)vaA4E#6X9Q$)GTC)!W z9%Us#{dGdorWC22(S1Us-^g8m%0+Y^*BTRsZ`jn&>2B$zaS>pyYEfu|=Ph67x}4>7 ztW{`~EuiWa0-?%>QJ7SU#j7tXgAI3?<RA73j4N=qUR`S#eO$+<;Cs|( z+RO|COP$>gh0x*|q9Gn9U6!NJ6kTm@8DG|I1vEoRV2~>!a4ZVPuABTE5jlg8fyYOo zU!!eTlRYTc2D5%-P_*%GBODxV<0q%K0ninAXHyKY+{$u&dg|X#ZBaa8sqm7+((MIKfi^ z3Hyf~(Fv`A5cM|Qwb!IWq(ag+_gKMo-a6u8s<%^;b$~duA+v>b9?e6LO_w{xdTxj< zuJ}a5jI!xj;peXi=7i!)uL=uTGj8}=N0X<#qlSQw;zn@ysP`pHjah7^m()&rvunX? z`#?z?3hg6_FDw2t^w?8$Cyjka7HIz>*pQ09X2A%FVFaKv*wHaSm`2RCyf30Dy?+r# znq}^vVn1-UKrNn3Mw*zv-z)eaD{B!N^gGI-{`SgPyskJY!`x%e-4j>fboQ$x0p{3p z^;lF1{rq09CoW0R5dZD+w1HB>Tf_zaoPKL}gxdJ&c?}dST;ya%&%MgV7KWxQ;YFsM z#aAAL?Ss>!HW$R0cG?leG5r30zN`@?(%gu_&&C1)@Jb^-6`Q}@R|?OpWHU2WUJtw_ zR}O2It7B-mI(e^DCiW641{EHZyd7|3Lj(p?aPtU6!Q;Sf<$HNOY7}VVI=Vx>7eLA% z!=DVX6&@`U_4CD8|1iSi9|~8ftx5Stu*W2+CECg>p@LnQI!_6N=!-I!wSv1~K!Qv0 zF(us}W)448hXW`f^UcN5KemtB8C@W45%E;@rFSCiOk0H`%c2g9jj?H%8caZ1tA=OgAS+&UW|sz8YyidY0?nte z+h=Asc)*tvuTAaLHUn=LGqXDL7|lYo_%Tts|7h-LYUxTPX2B;;l%Lge@GIk*-Y0~@ znoyItZDG2x@6cOKLCr>54Ka#pgUD6I!wpCJU;OH772IS)0iQzK5p!t4xJ*v(GMf0% z!VvRUV&ENzq{Dic88+p%Dj9#6saO$eHA<$0HC(6#MkJgX%vHSzJmoQClKddRAx2@; zH=l}U?{lU@X-bvWF4l$={F?T-Iql~E6F7b~ojH1d)eW12#bThL2Ji39>90_}OCX>> z{bI2JyZt*$K%&2O+M`Q0mUvO2w1iA7<)nE4odECP)Zq52v=W$3g5JCHDSo`FjS*LO z@{<*X_|gf}!#g&tWk-UUogX>nlczvTTx?vbk z!ByoewW8K~lJG;^?b)L6W6gRS_m0-dSM+BnFo66Vp}9#M4%^NjBge3~D3CBOTkRe% zNaadPie_rmKrYq{6^;K6r9BBT*x3F~A!+Zp7-gc?ta)^PL@snjiSAccAt7a#=qG&g zq_A1!7c>2;eDun2tGT(8#tZ>3_ZdCox?!K~emKbS6$>z0@=vr&q(8nRV0AAjOk;(4BVi&INSWxmi(wbqa~~Q z(evrWHeh}CQ-rw9gU1fhM-Jks$KpQXGCyuIllz(~**~YfI@m9)^+F3lE#fInD*ubH zw~mYIfA+@(>5y0{DOtKxIs}#y1V!m?knZm84y6G@rvM2E~y| z1&v_TaO4+_PmmFF@D!27jf&0xu;b+?U>J14M5_98Q6JtPPj_InR@G1~_4naE7V`;x zw)C5A;iBb2Bz!QNQS2f^yb*}_}q2**oB*G(rxshnyq0V@t#b5D#(?RRSl2f^<<=c_Enlyyyq z3RC*y!q}O_rj3&7l&2zKsq))jYpU-ab~AOpsYpHTR*T3(erx*P)RbWcRhmW?e<=`& zfJBONSn|CpE*^oD==*$FfH=;%ez<|iseclINYY#2jkj-~2FK~^T_%Z};L^N3nJrh` zu`xTSyr|z;aNKWx@b@&!Zr(5&@HL$*(x^1eC&LM@E|718X^`q-Ihg!hR4W79 z;6m?+aS9!VAgwGf4M*OIQUqSw=SVfpxzA+b2!~au8LZt#IBmPhqzfK5?cDNz??Wf# zEYW)W(r6y4DlFCP_;q| z$@*;JNkqZIO(zc5^1?0Mt*PDR87gw_sGVKWq$1a7lvz)&NUVRdKEm_smtdG(M{n0F z!RhQ+k;-?Ttq6w{Pc_?iSKSIQ4Sc3jbHTwxDVd|Pnm@mp?qW0=jIN2%!Bf=Op_`7U zU)>gy(VA%NnJVnMAx>SC6kQ2@p)E*;I96nIfgG+ zWxv4Li<+WPt+TRA%f(SxIuId(#1@A|n$O;dmRnl%jVsTq)}4WV;htM>SBi=Uu>V|! z4(5Y_XyBQthQ=~a?4()7*ZUn~+~dP@y&8(xy-+8Y{W%Ree6Q3_KDRe9s9$9-YSe4| zPUqS0>N@!GiHo7>Oz@R}@UfevP)fpHX_DdArJFj6lNeXwOD}$(Y}uh6{_>_4j^TVP zdoxUnwW9awxl^%D-%9yaxw_!4zZ)u!6YoQ!Mmjo!ow`%FbM4pc7h5;j`e2hTk|KTM zu!FInmT=;(D{{ALjigOAjU`K6waZ^$`q`L1qDy8@Y~l1B8C^Rcr73x+cV$)>JqajR z9{iGaQ8&L1eS0wdx;3HSl6WziXN^=EL+TwZV!8Ne*jrOOMY~ML9RaxQV#{6JXZs2n z;@Z;~gpc~eBT$G#XS%Itj8=-l_(JdD4ob&HmZuGDx}pF5vU}ce0;DTr|C?P93erRd zN1r}Hze=hYVo7Qw|40S=r1PQ^0cVGZxr0O42u~r+M#4%!_f~}PjA-oOTw6759G#3o zg&cD0R--CFSu1>g=!_9iM+*^e?yI&)JxVb*|JE;tu@W>uezC-pJWD${RPPdn{PMl( zdd)yL@}uK{%&Sx=$B>*mtIn{n30qk6AwVZtO30dRzwG&gwotB@$=W%9H}6$;CE*gTBr?#i ze`38bSQy_8{%kb7DtwCgwb)24D3J8-8wSpxH?2Z#aFMn~-vREmT>nEER-uCl*|v*D z(pXp|_xKBEO&5lrD~ca8I`g_ooP-<&KV1Vh-?F)OmRPCm{A_t9Cuk_TK8RdtX27ET zfFQ5}>rJ&K_4*4!E^44Hk7Vg=WA}x8J7n;pkNQb% zo0jaN`Yx(^ndzw$_?y~UA&y>;v&b!^&RK*GJ1@iRSU#+4H&voEEFWRBDP3rV6PX<3 zM;uldpdAq_^T`oV;z!|iNHk--%9qk@*#a({qEC^}Yq>Wr&cm^u&6$2s9ut+;0(Md634%CVi;pvV+uE9loE;XeF)#%h_$dqf3 z$zw2sbKr2HFU(zKJpP2f2U|N&t-Zit1P|7PqNNc8a))L;SWY;$`B`U0y2(9F@H`v&mdhkOTt>tvB5`!-T z#P}yCWrs-HKfI{SH7xdx1TaMpQ7_rmB})sOB`f@TUz=L2oJNxsC!ve#s*+u3cJq)N zJA6816cP@WqxEGlAeOmAQPp3Jq^7vzW|Qdh(#WNvREugW{GO_<7y9t_plZJ19xd}w zwmU&ESS_b4m%L(NZWd?JOFMdvG~b1A>%;M!OVgL3PUL=dv8e7UZ^BV+l))p^viwYL z>6Cf5UK`FuUgEM%^gVl5tq#8(>8kRMD1Oy`*}Ck8+uiQn^#a~mGYGeQe|gd9 zwUSI>l$1Jl$F!zS@Y;tavm13vS6gh*K?zAX2#U$-lz=;XN6ipX+1bsVNJ z>u(K>+O}!fqCK-69G~8de>^Fs7oY9CS)2j>7OSyHCbR9tfsGfGF2aUYb?Bm(Hm9nTQvDs*NX}iA zgK#{tCx*K_vQWaIkNi>c5?%YI->h&)eeLDdNzzdv$3sr$&SY=7Gz>b9NB>Sqy9^mg z^YscLTwYnend3IFFJbu=eB@eRyi#IEgN0$6CYd~%@bgFCkIEw9L*cKn97&E?O~dhp z)Wle4sg+*8@+S6l#I{SdD2{~8s->|UhHSRRj05}vP=lq}GB2Nep-`(Kjy1TQDJD;^ zkx%+eQQKF5z4WOHGbp3N=!W4jx=Cj_$4VrWQ|Y&YPUET57ZO^oK>etLAqM9=2b$lq zPiZby^FAX8W#77KUNTTL3ebtEBpNM@5%t@!Y=6s;Nnd19c%xLldyh4#&{i1qd}EA4 zbi-5VgXBA%X*V)NLNjMJCb;*{ayBpF$iaTNK(LB+0b8-nBJS=RTsP4Xnfev)-(%t= zlfT?Fgf9FVvI@+B0i_yhEifN2aZE6o9Qbg zoWiHcuEt63ghn`#IQ2*9qFSyjZ)5Z#S{pof zz$J}0cDdW#SBLCzo8sx>lifeISWc`>%l<~UYvf0xLCE(^clY0y)?Mk^p3!OC2r$tY zVNRdeA(dNOVH3XY?~Et{v`Q?AVy;39pDDSF_(Wgo)RRVnP?dx&O1ehWMf~(hkL`Wv zvR`L9*Pyn;;#t2nHOJ;jiMgDOet2KH!ns>uRlLKC7mQ+QWSRvR({1U#1N zqe2(xJm@K_A1F_L=Mf0yh!o=;q$Jo+f<<_ot&*GLvN zB+h!P$t9f}TV?&}!5EY1Dq<(Mt1-$agZ0=qS#n6~?rnj}Ne3~X+C@2Q$9x?p#SlYr zzY%k5KZ>QbamTSuk8Gq^Wt+g;c>~-m3@9H0p6qNti#1Md?#sP5*~GQn`)mmS(m;@FV=sb~bRZ#6q zK|+zo)CxTv3Pi;rG*A>if(dPZ``Q3M?q_dRSGFSBqNlAH`1GRCk_;yf$uB_fXJU-V zxw=-9Tlqk?*rJ#cnwZ9oy7C+KiWo-oP)hKpE|M}r>IFs$QAf`;bSEYu24ggXPlR?k zMnF@NYWN}P{2Z6aZ|>XLVHyzVA_+#40+ zJ_@YYI`y|m2Y0Bs(c@-Jmxd0I%5-Si&Pbpj0PMzcWdx>JD~^h zqK-eS^iAnA>?Ak|S=GxvPiQ~B^1IA+oU`xNP~IiFt&WK~<{N#vFOL}+T=eMS8D_UO zKjX8=+%dzTz3K9=D!ft5Jpvho?Iu(xovE}IXr^PQ%*Eh zCUKEk4&j*A=esjt=dtP>l;+3Y7`l;ODlc%Bg-)Wk#tO7F|1e$a6-Lpy>#yrt&^x{D z%SEd-F5=mzRmAi--)}tl{X?bj!xhsB?d68sNY5>jXy;s3{e$uP+pon=jBuIA&&x_^ zNI#w~K?2krXy*2qCAWg zgy$Ss5r+s*wKUF25P%0@eM=x!M9P5*XPRkZ?Y7H(|Msuvp&?Ll)S$tn_=Tj)tl}a6 zy5zrrD=WjPA^4+rRMknoo4Mu{Qlvyt`^;KGOujjRn*W33%ZS7K+90RhOap=#=Zd)p zw6b?uEuUi6s+^K~A1F_GY|v!!L~Y(EZAayzWsgr3!UYiD;@yKI5o?C7T(AE9+~-L7 z7>LS2O39y81%mx>iE)s?p+@p%Xha%c&}66<##!}Rn)vhMS0?#=6iY-9w@RRmK;9J* zwiRXRc{ZUoOP@nbjx;Jl;BviH(7#RR-GJO;T=68q|xBg6gCA` zXkLF1t4`c38$vLJe_OJeuEiF<4C(k)KXn*M4rNC3uK*SHjbWU(oOC>lbKPwk_xt10 z#M=4I$(`i#h`I#{qgCY1W@;6H={%tab0?WKNk zk4BAEr)xK@wbhZxR&JtGc}yTw57hB6BElt;S?~&5{VM)!g^B!{i5ppInaiH0=l#`2 zu=HwLQ#k!D`=&C}4jdDaPW`aIlSAQ~kZ^6%a6 zy&T&%c(}i-F(1iUHqQoDtAjs4VqXmDRyJuMoo{xpc9BgT#qW`H3}7cM-sdxBQu_`1 zZjX{V!Yh)XUid2c5nT8PK_f)EZU(FUqwGm*9B&2wv5-U(grbk&&ng|I#7l}Q&4y}T zr}M6fZe{*^MR;ER84`P7DQaBwx!GG*@0xFPjSX{N|7b?|N-O5@<(K^V@6>;`u237j z!T#)uw_pcn^(6k4C~m=n(>Jk?ju9f!EGLV$SQf^+(**U(lQxJ2bm9ck1Ru_4ZKHKC z)Pq*)Lj5;7BZ+WAp05cm0ruhrSNnqTAJYA!+<(1j4{IxJz5jrULs7L7E9OJoo6f`2 z{BVC$<8$XRTWzUUpui#ww$n{;$oBy3Lz+Nc5)28!!=aW;+JcpOKgj zfDTue*!;ecen84aquk!cv;Tjd^q((YLXhgl4?BtUcw%y98eL280QBr+Ghh=;0%D84 z;qx+sb`;O;?*$k;2gsO&(+RZl5!BXskFtr+_;%mF!V}$nL38~-zsUdlLjOG&UYIVQ zYW%Ms`HvSN^LW|`R4SsYOKm5*<0#f z;F@JRrxa_~kMdgoHXbWbvL)BU`|Hhkq<{dKFUy$mpYIKe|2dn|tL-@J-^G~U8^#3Vg+qg7vyYD&=OwIps*?$skccFPUg0-Y3VP%$6CDk$%?j4h*dbT^0#iU2C#r`Vr zDJBRJ!MUS&|6l?#F2CI$KUSTFaR3mF7QHVrLF}y=zqvT5m5L;sv2DFGRnu`!1|Zf5 zcIkV6)m_qZ{lRlBSRhvYv|s5Z+zBy2>= zYgGn>y;jTbVt1$S0L^RQ?GFkaRCQDO-p29YobOe-pRCW!)jRG1w5dwKah(ibn*Hw! ziUKZZVAe9mKMN{>wmaWA1yVL}f}sJPs8LsxblzfvvnAgC^-gK6My09A3cxDJYuryv zwJJ@cMXoo$&Tx1zBK_q7pVa_AI3N({g#4qiPTaby_4K{1f^4>@6AVQ+TRs3RE#KM| z!F_L!WYR^wJ;V~#H2-3R9G!TVM2{XlJj8PK=stS%@)7t0_}xs@Di*1Unwx@H%S=8{{$21qE!xwdPW@m;vNbT z*vP1)aq&!5)v~U(18g-Euz&ud@~&rlCOPl_>PHT^Y0sg;s05h+tN2`iHs^IRuyi`6 zgfk>^q3x%=61(C&sX&|Hgj6%<&~JBp)Ll^S zIsR5AIprK+D#1D~Gqf453+@J4?(68JR%POTt63j@e1A1I58QhRY@HNw(nV?;1T1(9 zPYWByUnPqGB>N%Dm<38E`3GPD=wPq4I)KK&d1tL4U`v7|R}ws*gXW76AZRv~w1cfO z*_saF*S6$f+|WWI)NvZI1F$U=?DoA|HKrIGTn;yyF-gS+asV0r%RhmSSFQn|e3D47 z^aLD$hdE}yl)M%YBK1*Rir2^ zs))!`W%#Rj)S!4s+4!KnFd_nh%y=3A)pxumu*;Jnv1}HF;wEqis`d?}dzo-&M$5K& z;`!TYTBPZs_}8S>1}nY@-gjqH?NQu=X^P;iP=mZ=)$0Q(*V9pX_FxUO%on%EsjXOG zGc&j2Uix+*!%H{(Gics=ckWnzf|IK2v1NC&S4+<)HwU5ltJOF71M6$^`I|6s)tuBn z`{8zDDOBv%;FX?q5Cox6*((g3e2xP)cW8GSdp+e+-=1YxQooJ?h~FA^NWnwnQ+5=} z3cYRpBYM;U`QB>3?vF}=7Rgf4}!|s;EuQS&`IcfFV9wQEa*RR0gktQ(EUZ$41_j|#D2|ULPBl3pNFZfx3pf@W7$uv zf;6PkRt*zht45^F<}z(PmHDd-B#2OW|M18Q;DtvFpt4D-1@DXb_J`Y{hcGl-@`ijy zUC+Jh!>o%Y`c4Smy<2$&rJSzdTQz+19L32;8{){b+E-Z*8-2@ovB7$XX*l0STaJR%yWJ ze*e&utMRVqNeQ>>kwg>GmMp4UjxYc??E%_5ZAF&KUt9=$1hRbEU(3)Ly}M-xW1j9B zEQ4e3mH-ES#U{}9xzBsAxOM?UUp3heoQ&1(+H#WV!74}vuNS+$S$v>)%XuJ)v8jXB{O}^T@^V(MOLBXA(s`{OVof1+o zmX5o!+VFPlVL(J`mQ2qZd@%p2B2+*{d!KnfTiDdErPu+CnNF;TEM31obV!94diw`e z%)G!+GK{(hRW_2;rtS*`>he}%_N}qHWpOne>{l&zfV1EFaDP~+cgG}rG3U6214SA& zJ{jOsQuPLwPOlwob?Eg>5_dT?6?=WD;%lc=I~=*gXRHkcia-Xa3a?I`?C8cfPCdWjm#^ zZXCRFP|#A{WyYj^L+s(|5u<7_n%S7J(^{-gCnXJKOGUHa9i9wXyj`tZ#?5f3Xp)yG zWLD-*2c3|1FH)ST9-md>7d7D?N2ZP ze6W?MPC1V*>I>}sp(y(8aaR9Lvq}x#_%jJlu0gOjsBgm(apqPjIFox+I&ChHZ(2Vv zg#SKN<3lz;BrGHqd|5rcmc!}uJ;gTa`6>|BzZYaZqf^Wvrf^@4FB_J?G)c@|TsWQ^ zU6US{`)m4948=t!?(LlZ+XIj%5GMHnJ?Cqg&B` zUqZJw+CdSj`8DE8q@cw$BhsXK=at7{m|5|{zXqnVy#O+8Sy)`7*-ZBPlLtT(C#(5M z;s?h{+q#`zJ_wiZh~{Q#gtL)uyI<99DrHB*%o`}s7jtFiqS(*mB1!2TDl}p)Uz4=# znGf-kC{qfpnpnT|jh?Km=0`~E({Y|qky%w+Lt1HbD#E|^**Yoke(l;NK_hBOq-`hu z;qmX;;~0okbsavOzL?ULYjEe|?c&cY&wUMcNEDP&D-uF;<`_clO^@GPO&u#-;lql* zggs+V8QwCsGqqy;l2!5P#BztOH9$s6vtwbldjLl&Er>?)y!$lK%CbuFF*&vSAJ+*vhW^2G(jy}{MQt;B@_IH4p$ z*%w8a&qyk3-NUAIEv|n|x=h&owc1QlGmMQLNBHoi^}XyT4V@gRy4H*yVx>WeV^9A} zde&V1s#Q&c3V1?s16va?9U=U z=ae{hDE#Z1!!{}IbUyRd20HNwn{*8%+lU(LE3K*na6E@1((#ikEyA~xr+@OE5x#O}B>W&0m8N0p*x27bpuk$HAPlJWGoHDes z6h<|)BzmqrW1=M+?*T8)H*P65$AnxL&<|hC+KM&4$Jwe(p@f*w#Vu0^rDM^sU2yqE z8|js-8PM=UFx}y~0j~$06VYmgN6z4w>uM%N+U!T)PenTNfEx$%vV1vd%TKYqK#O8%O>=w)^t3>v*smUe99nL)h1x3#+_np`w&3gOIha}AxN1W5bm&vsG>1IWTl zIG>eBO`&cHKa?q-!*t`F+1-c{l~jwP1j~6C{C@0C6OBfHTND3+4(vt5bI&M2CGze(i%h zCY6vm%>ae7im0~bv!5|R#O#eMo~xfAMcPCL(ptt3Z?IAnKCVDCu$)3K9)cX?rRw%c z+wRn6SA7U(Ib9*!J*In`(;tI!S8mFl=+Z5ah)q$jsc8!19AT9cc>=3P_f8RGFA^-j z?YoY%ZOuW)NrypOo6yPh*t-9in{bb)(afoZPq9KXZi136FR1qOe0J?KuUFBXD^Cfp z(F2-zg!Nc#D(|D%c&}j3=&W;w&YG-92S|KFH=}*yo*vC;VM_J^EyhkT@5Viu=KE(U^Z>`IH7`1QtxW;Az8AAJJC18r6Kz8_n zZb1rx#_@DQ6pFsuv=!AKZ5rT77O5xwL?S{{Sb~o97)f4{l6}Y-B@xdD|M|7@VE>P$ z4Ep}QQ=0gLlYy|qqVyyyvEx^6sibu^JrE_gfX7!G;kBB!yk8PhTW0EA!Vim*UzEfi zcNBGfH<}ygV1IR|-MBK>qu3Ybv%GV470B{d3&v&E>seG288q=|GBlFzSd$j+?I{d! z04b@0lha}wyrs#Z;VEqb0|J|~%HdLl!@fNr6Qf?HaOj~DeYIa+FT>byVFux3lp*~X zGqZEg2O*PQHM(QR`=6vAp!%=DoDni0x`FI(Y>c}4ih?uz6)t=sVfrSj+GI0DDSoZ2 z^wZTa9kwwI;iN`yf{n_ZUZPS8TB!t`DJxZ^tmxR77N)1fuSESiRz`d@((RaFuPirc z(=Yh+sHvRkoSxf}kK<2r=3~=kRzJCwdAG}|EHrlN>7xmoyP!CiK8*V`?+p5EFD_D( z4qK(3vjnuE2G~)ATfkF3B6q_QiXtB$TL0Js){pjD|#=1gf~LK?rn()C(n&%vN4h}k0TPk(zUhe0qV@5e2* zNAG3x8UBh5OjOUIP526dB)u#f&uKqtaI8EKNvuw4*;;>#qTlhj2d0mlGP?F_DPSukhMg!(7O3- z2skaB`p#B`Ey{&2(pF*{A}&P}oWqT_MDTn7_By+TM`gX~+(TV2f+sVhlB)-Ei$~@Y z#rM*Pb&rBrl0Y^@M=*@ z?IS7Plg{rXWS|_*&7WC>UDY= z;*Z=Nq6la@crR1K>EV%HHfCdH1~mbj(gvd8ih{FMyHK?@Bb?R;Vb3H9W%;9o~u6{6j5J0Qj;Egw&k z2Jx5NN&QU6+_?zm?QF&CRqoRs9o}~wRqpf}=&AW;@FD1XR7(bVW-lbI@UaHRRaHc4 zyQYLvsk(77rOJydvk@z|XH*8+EO5!BLp5tU`%x^{ljVZ=08 z*STne!0(25|MlET#O?k@-k8Auk}v@wN~HsZ=APVj?k#=%bFRak*%;y(7=;S2b8ggb zzNh;>r7+$?UxMfHMXn;AySy;FPrKmuXbCObJ{!X#W``K5k_4{D6lGFiI(~^+9y!zt z;O4gG?+!|*ZWh=ob_ciHY?ZbNt~}4ZKSLtzdS2UN59CLx7^j8Vg-OK{bzjzrZh!mw zEKJ9X;pV(BKyreAAk2voabQ#1v$3cLVSExIW&J0dHh{uBT;ADP z7`tn!k5lZj>)W&B>RqaE7H^u8vT+N{#*`r$LW?k_ouM0$yt5s=eCZwtikEPhaW zQ{*fvMR70&ux|n>KCf11$-Rwq(CoBPpmrjQzmkwixI?5CENIbrO6M$^gta7DYLNx1 z%UXg%rL&cO*_kcu?ht(wcTlK~%KcN-vi;;YJw-63aoC?3J@km64sdKZi*Zm0)L@~>-?+Po@qJ>wc-^VZX zuchkgvg7>fFEVB&XG8T8x;sv7t&+z!;0w3YJNS|A@dScrW1LSPe}prj*V^I5Jys*n zT0I_Sc!W9dLJ11)H(+~%$10TZgNpj`)^}Zv(qD>-Ykv3ThHKKaCiqkoxGB~{rbDpq4-JfzT{DvF^0^4Yt>LEC7jZBe63r(z45%ds7N@{ zO$n`%#EkpMm_yLmJ7Y|DVbPVKUoD&7?dcWmJ{?|+)|2+&!}D2NTh%j^RA}Hn^&Bq^ z%cu9|nlo&$LsHKQcQaM1oWATu*F|sA-^i4gQt+;%$&dvH5@zc;FEY2@E?W1{72?)CU-W(O5Tu50kq#i~ZLapynDTWl z+V*6N0AWC$zZDIibSQn+oCAA=vv0r2{5o%s=Q#G74?B55S@kcG`#RJw?C{=TJ~3fZ z)3R6)J?PBzW42n)lQ5jtBFa1~3$dv(7oMF>;ozfW>s9oiH}QIEEQ+iY`#75MV0YfE z6yYD&n$otXwGK!1I&`?x9cQA0(P%OoTmerKdi#1$DtE&f?T!gMG%_m^@w&-fwRvA% zM=v@uCzhE%7Ka*riIS@6WOtl0aHg}FL3%k^YnM{Qm)A_1YPzaFIiSex$}~Q+jZ|W? ze8XhX*M+h#z@o#v$hYgSB(l)rW4yb!tA!&O+T6#rp(S!HZZOi%yQ8Fsx-YQL}y{!`yJ~uJ8*4! za(rR59sJ-P{@2ZY7JxuhhGEUvdR0nn6MuhOB}du6N+o>Rk6(-1g4>$X-4PD4ynH^? z7lr=rq3La#n@|FjrT!=yDU`+MYAtog z-s`tqBHhH08IINCCMeecWN8zTD#Pr{lcNn*9xCL1G&kFs$TcQ5l?uf8uvXW0eQ=bq z^!Eo8_DGq!y_(s{QWG4ozA&UtYX3zOCff1oWTmLmT%%i4cx130N%+>C5rlH_P^#i$ z!IN(@QYamI1Y^45Dmg~Vtk*r4$$XykF-%}72=aA&`o@wlG%lQF=Ri%@J+F2A$lhh_jZ^N!OfKC;*6w<4 z2xo~&h>jIO(8Tvy!i)Bp*i)jvti*%VOV}mxCc3(^hjO@47y^q-IYx&R3KEvDl#daW zLK8FgErO9q7>;!j*%7H#kdU!SR_q5}&7k*3sx#6GZ+J^Y>>B;f3{{_hwSTuf@2jpU z!SW6)hd|lcv!XaB&7>-0xdV8sPJ1^mA)G$T&9E=jGENoOOE>CUMO9Mx1Uuw0ZWXTj zX0P)h1N5>I#((q^n~Q|mBTUHYh=#wznxJ1HOlb^49wU6*GhT8r=cwd>^H?=s3}%(} zQvXvrPNXGO5OgmnrtaNOiIjW&DQ{W5$BVnG7+Y2qewUY%`3K@Zz=7?(N+KKI#fWc& z1wvN4_fRArx}-u&Q#)&YOzg|C^1PcoF(c(=MXaQdI+*Oe^~&r1ywY3nIvJ2@OQrQ? zef?Hew^(64ih*Mzs8%2Kv8<1(SK141BQfTM3%&-fEd>8p>1F;oXHwT#iA1WDi&M|v z1M8_k=3BdLs!5VkIhf7<~m=w zzos(Ac({03QpU2rMt40SX6`gRNC?J*U{!6EORBbm991~lNBHPH6xvr*BtjMM>NP4y zA3gjS`hwl&T$`J6G=;N65XQ3V$cy7+M0*FomDZ_;EIHM1+4urL2OP!{C<2}a6v_(Y z-3Lo-qhK+!`Pcf^d(;-diL~xvE=pNpq?+OnU zJ5{Omzc-CD(kV_cWAW0pxik#<1GuL*&dBKmBIu&(a478B5S*14Pit}I?ddu`p+od) zIDh2P=I-uBAXiGGxbl7*NH3#eg*^rFJoUh+Qh)RTYVb+cD1NdtjX zK3sO=hPUIQe?Iib@%o%6j6&;B)%IlMnhz#F1Rg>J2NUV?|KeYXs^6BvoZ$cuqXZ#T z_$*ZTedw5WVXHdVo)?Xandu9P(uFIy=oP2j_$^eLGx;m#?vy#zHlH)V8Qd%tJy3%m z-}5Vst%Ktk6x~Nn!NZAncY*_ztWvM=rBcbMG}lAS%gIx;9eUr}M&9pM4uzPTkeQ}i z*NiKfWjaqf3AbZ$t0%q1`N?a8Pnt8~y-jM*MGqTod|z6Z@En#PrtN(;!Khm$jAM^1 zk;Y*lVbP$0~BJN$sosSNx-^glwv%&wJ0P0Uh{Elu!P^hC<?itLHEsLO>lb!L8DDQu#V&t3QN|=H>Db)wDUeP5yuM0EQPmv!sYjV;S?V!I2-*z#ZU`-+n`L{uNP5rABKRJliNe8i$dJ1750Yg2GV2A+O94KAP5X%3 z!K|h|y70#t5rVd9nfT%W-y+#_IF;CIaGncTaz$%7tvdHX-6QyG?4y<>9Ff!E+#are z7RVu~O^}hQ5O13BZdp4#UWVf1H3Dg|#JxmFtgFGv447Hf^CLu3$M8e{c;uTW4(*h- zitg6T+BhF;Gqc>!29}|i1+*b)fAj;(0Y~YIi;UYS8`1A@@iW~19_LoD0ZpzHcd9IA zQI)NwXz|WJJps#T_}9~nJn{p%_E{09bUm#vf8zMyQutghy~j-?waN%T*mec9(YwJl zH7NFQdkyPxnYB(0)Ar($zX!f^?k?c-;Yb@;NPB9n*AqM%JVU}KL0~-&g5@;A|mw(k3QQmFJj3L3n3AJEUzfi?nWBZGWCG^_>P#67!O>+jy?uArl*F}zz zE&w*a3M@VJ`*4~4a7%wxon;V00$1Q3;Q6fiiuJFHC819Y-YKe>E;IOV{`%hwxVQkC z&McW1_J5Y%f+dhqpf0;q69@nQKKTZ8y5uj)u>a#T|6U$xAd=x270Q|YryJAL(E0%7q1N(gPd z%l*&lUCz)p@T{A|q%R5J5U4?kN}>W22Y>@%X5XI{bZhIVPysSO!>ilOiG&0BBLTQ$ zYj=OO5&Av<(+^IGV7<7E#j8PA!M?8&oDrjDNFdWJTmNJk0-D>L+e)-S{aT8pM&Oj5 zuLw9id#SveLO!u5`(|!Kb5IifzsUO%NZt=?GI{=C_8j@RbxR?nZ~(Ch!D1S`Gq}Y2 zpiVS(CkeDDMkL~!ezr!d%gb&tijs!y9~=O=OPxG8>ZZiO-2e;7;D8`gxUNGY7g&jO zuQ9+w;%U!=X3~~2fRU{GMgs;-3czbc`pL3yXGwI&q)x$=hU5#Ig7{o;c>5;6@k(o}xB z&8O|>P_J*Fl>0FJQ}Eo*Ce+5JeJ__n$0Fj83DrOI#BOB!ih5nPQ$AsDy>+;}o@%A= zx!cj>>nNT05dNt7PXHzyz%hubrbS-J&NZhtT87(lxB*y3#IP?#O{ng{#jjA!lSsrY>GJI*? zIlFcafWzgk?6wxyE(n4py%z2BpyAH+UyC52c>!L9S&-rIiXTW|6K;x_n8Xg-9xu%~ z4!vf357tVp(*2a`14}JSnomdN^N?;Z*_&`dhB)Wtr2Jn>qX6AkNlWhCf4VOQ2ogW) zyRA&@mpH>xdP=={5~-yD5ldqg=zb!4kZ}>)W$Z-`Dr;Iv2Q-h<|g zg|f@#$k4soMbWd7ACMRIAGdP0ukFBPDLHd6J;s)?f2TwX|n~tRU_o~L=U=icK@w7NwT`Mt6xh{~2fX*8L zP5AXrX|~sVD}VvPg#E!Jr-z6>l@^#qc{6Vuc#!3_b|BzDXC+=XZR_fZ1j@~S%Co;} z%*XU+S(enp6Xe-Qz}Vh)q@GIdI>$){z-D-ENYQ=`SegyS2l+)|0Prjg&et12W-gbq z4sFN$GK&0Xg&q3aWDO>@Bd!Aos&YAC>jT+u*eRL&^}L}ReszD*s#hCl;Ccq4 zp780gB*J0@i0^`u`hf19fWy@gAY@{>Y7XSKRxLbD6auWhzaUrvc>Ej-7Yjukp8*>6I;9}kA&+U;W zwNAP^oGZ{Et0&0Pn8BNo-P?CkVBy;z^b0gWJ@lKNG?DTf(Ro(oXkMUs{O^uUk(};*i^+mUrOG)8urg)?Tfr ztI^?m3zm5TkrvUICJ1uDr<$=eTmP|2!iBfLaN9YIjYW>C!tOB_5XlR0BNexg4}2el zCW3cv?e~QiuN05fbgHo^ajd4l9rQ7mDop;X1`!}60kNZ#N3Z$jlUVAS?H?bwG#z-K zq%RgFZA_@?Wk!*QfyXJK1gh#^lpA!Vxu%{*@a89%-iVAe>o`=+bq zi|UC4_^19OPgOBF7@dGX7emY!cLp9`E!`k^%+ke1(f_vZA~7Qy*gh??+GjOA8;l^F z`eH7X!Qb~)#~s9z=`>$0 zm{(D>&HYI2rL9+cq0DM%d=q6MwB&y>G27}5Cm z4daqnUiMV*A5>@9_px`5O(0MyXq~Xb`i-2$jaCW(^U&?sQ%aXXQY6Ebd_b-E>}0*# zsm3K>%nwcrH~Lf9qIP1FL*NbXPDKV$7Qclx{c0UHKTydh#KQSO$#$4wl`-v!YK>2`#co- zmC}wL+J*^G#gqp4z9qf{@y#i~MRKVe-$Z4E@-ehS>%7?sIs&{5yGQH}eAjfqV({>PUhbY6LjidI};du-io@ zS}g{90LX@jk^6mPdgBi0JmlWmCHuvinXMH23LGiDI<2Li=jOgZ)4CnEVhf^&{Hz?y zZGS|TwE*$n>?*dLGw}-MXBF9NE`Dt;7NGSR|J35K`Hp?JDg2y>qCANn~4GP z#T+v1(t7$w!JGrHl^AO>ejS@-3WB7qM<5ie0hWW~#=i##8_*40&p79YEU=d(`=l6G zeY;=m;3+?TwL_@vJl1_G%kn3aZGlbOf8rjEb*4tnF%5~8b{YF7@|Z|NieDV|-98H$%Q8(Vu1C_79D6po{SyTE0AlZNY(1xR6=HFUPk5enf z5t@;dUiwSS$vh{;{=FktlAM9f3k(8p>A8nrq58NQX0G8gNvm@*2epW5btlyKLtmRB%6pprJHmO}Eds_s#RyYpOn-FGy;i4Y~aQo(NTL2CY+2YMa)k&_l@a6TOM+2Ul zOU|NPAzSlPckPFp$zAInOcg?XN9B~v+mX12=n<|m2rHxVKJPlf2v5AhE5;zEIY z>mfs0$g}jQd7oXJUV#=cz2LHC6KbYe_V}O$;lA2Wk#5BtkY4{Ii|9AfPHiELiXNmv z;2m$+smf@UviRG#>#9CHWw`}`tdIa}v5K)xly;)I-BdTrCHJ!+?YkDK?dcMbm(skd ztvaZTt>QAfI>1ml(4Y8vd@*gMOi^a4l4@!%#7Q@d0!A0$TDglokOE3=+ zzQA!(Md-kex6+%Is}`F$?zW!V+$or76A-2=A#29i>1}-_l(NUzboe0<(Uo{W9E!L!`g&U6FrpW+9n| z3)1pcJT=7@2{)@fY;Za4(kJ(&H~DkJ8Je>5}F5r?Z$(?7N-VonfXDb97$x?bT`+Px)tl3$tLZgY0t`-1)q= zW4vW0&F@Y~r7-~*yQlE8PlGNs%a(4T#m4PTz=XxnLK}3XP|oqN%F@%2I5c*h(|@v$ z@(vh5gr1w>e9~aEPAj4W(lbdf84ABJDX5za4+=q{jIaL7t7j0T!O^Aqg&c$B)0SQv zp4hq%sRF$97=ftZctf(ET?h`V?xBkh5<*J#6w*b;UbU;kUY2~WXarhLu^TKK;A0GN z6Kd%6K8r*}5uU>uW`%3#K$g8NURc0=oo{YI1Ul{a8%dUG(WyQgqM6eh{__y>U2t8} zAuj^c8tzEV+xvW5aM~QdHR4|-lU3SXTu7{&ovKVq+Xs7wIu(kZocIh?@hMd-(12ZS zq6X%A*VgCvzfI$!Mr&_uv@SFkxWf>9Me1_}_k!cVi!O0`49u&@HW0kT*S!&>+Az&!`xe*ERGkbMs zUEBe;poRfMUvCxx;XPG7ib7du=D9R-=q-G1JI2FGp;&pox`d%)jiBmjlb zc>9*UdpOVnZ!$FqngmtTNHv9kzZJEQHJ<;?OEZxjY+FNx^`lesLRmxHXF!zt7dr#Pkm6 z5rtZaPxTjmtNkb7t9L3k-88Kbb@Ld}G;M0K76g4JOke-(2*7zHbSCUyVt2+E!+af5 z1>jEnRcttScHL^}$Pt35(7LVkT8#**#lWOr!mf02Dd~w3R3iImdeEI4?uOtrnBN8k z9RyiDuw_cE5DX@h@00L-7rz?0k8%52hA)nS0DBwF*bD1n8ny1HR$KvizRS^{KcE3- zCjPQs`?k+l{dD|$Z;1zfnrdWETd~}(u0<(e#%a4d<<7QZ2`967?CFEihbh_GVx9te z#U9%2E1s&PQ3YYa<@dFcvW3{p<)X<$Xvb7Ez)9jVAha1q`t>tEh^6NBcSN9S7X&~FTPMl4sjLQ=$L;K*sK!?^%I=|$Sd0Q{p1wFA-cpE1a$61F9Qg^8 z0P^0{Eke!rFhKK(D=)0>c0Mj2!j5C3po0Ni7*X5^VMZXMoteU1oRS|&PmL&VVa_%sABKHOh!^KK1>_~@qwSvPt) zE2XQ4*cKI~8J~XNBpPH}3uG)r9eyg6#2X@a(a!45eoj-kS23wYVR81BL$NynP{D>! z9MlIF*!yhq3_eOtnY%<#tYNl!+tHA&P#5k)c>&qiE)f!VCO1s$2{s5~oo)2#Y*mm_ z!Ncn^8&KJ%l-}xSOoP(VL$KYlb2!{w`9q%(FKZq;D~s{fPUIaed1GN(Q>IhgO5dOy zu-28Wbpr(W40Effy*vC2b9)dP_D8{s#|BWn0h(vxtei%tu(f&9o!>bh%(c!e!gG)h zt3S)XQCi4qs+F2M;;2tL)>@Feg7~x8w;*72$_>RKQ{CiolEW_La{cKKZ_L~r#=tni z!FU}e@(38%nzg@U((>=|@gwZ-sBsu{NbZE%d+#eC1q3}``!^(@vR|m!Ra-ApV~DkD zqGG6tS4zbAH?I-zy#H(Ep9t2lI_6L;)e#xjSrWfR;k#ulQzqt$6MxHIwUQx&9LIrW zZ-O`q6>mrMOjieBhLx3dW2b*bpwFC%9I`!~ZOgvN?8}dRt_fjI%>D0-GC{}(P7d2x%|N?Llt{wcdoEs&(7ER_JjB-+*c`^W2Z+%%Pm^M7@{%H&E*Mui03W#SP_rijt`kSD7+VJLWoeEOU-4nPn>g8g5t&P{YMMl@U6F>S)g?1%pbVU*W09RGl$G`nIQQ|s;oAt(P zT}1E(>LX7|$*aveYx_uShHF=SrVxiC+nJ(LJlPss_`u~;+pkTNOTL+z`z@opY0Fl= z4_tNACGS0y*7S||Mn^;cv&S8O3*l)P2 z+Dem!Z|b-EzKsr)vGXzJ^t4%uPak|GVY;NB+||8V`U=~`Xc6RmIYzZ|%(Q;}h4vyj zU+=mPKHjrAZMk|Wt9_%W3VL&BN-Dc=crs&JM6)PFsqm`KJ z-bh##-RgJ{ca*AgxD1gJJ@B*^E&lT2L91)3?sR}(s_nAyL*k$2=J}}YCIV4Mo>dJ_ zQ}c@ja?|ORm+* zADQ@@ZmW=Cn(RF-9ov03lmBkuXgQi@=G5Pc+m~_>ki?7lna!&T-4BUjjXwxDVMJ^f zS@-$Lq>9TH&fE=${TydkgYk&3dfQZtL-MqZ^fHLOgf2Xvx!-#uS23l2H==BZ$za<) zm4)?ZUHzzhp;Iu3l;aEgY0{tSMo6Y+td}wa7V`Sa;UWy`>-F%*$lF_VQ%>2lzCL(yGU=4d z4Ik=_i?2%DC|y3J%5@S*)i+i-l8M?wP4s6 zw8Nw@(g`t3PyOxU4fbPkq}T(kyH4j%jZKR4C*~V*BVEobQHB0*y?%7&4xG^RQMJ?; zURX=aQBo#%WAsLawKJhvT99+SMd`m=@ilV@evY2E&p<9%;vr-NW6etFL6;<>G?sdc zE4V)QDJ5H^#jgtn{>sTAv~{+2~Fzwzi8 z>G(7C0$gG`^W7(Bj|C5%k3#z?bSfqZ?m)tpRo!>yeGn#gI&JcR)v4+VZK4J{H1<|wSX%xK;QQ* zC&??1+Z2U%PaRjmFi!Ba?E1!`fHLo!FyU7|j_J^=%@EC1RVCVN)8Se@?tLJ8jrK{d z9L7oh+I;{Ec4a>`Kd(Yf9j*cN+JJfGg&#!hY`{gKn=$DUxwlbiMToVr^qV^lgw`;; zT3Dvub<}&)BlU%4cRkd z1i$y57s{H^h3c|u!TNR*_J0{+OIf4 z>qYgew$>A50aHU)0*)B&-AV?Io#O{j%m^1~#5pPFx>!#3xj~^%W89D z_)~OBpnbl|5k7zDbSAW1%s*$boxv*IT=6CC@dbthV$4&A6y&u<4}02IPT4nPj9pcE za8T{iEOW#iC)A4li+Sqr{H_sA#WH7CHx{*%qeNODG&qf88-~i-TQxhWGQT|A8A_26 z)YhdCB#TNo^rE>j_fS7rR^||UtBrxgL8aV{Zeq!Lw8G$VA1A8b)AY)oZRIQK?E@1EqDPlYQ7f0)sGQcjU*u$(qaogIj{)nhh# zp(l$ytMhrvEpFXC$7}3wr=8G)Xp8HQz1u^Q9Po3^@>+WuK+kdFG?p3$1u;q0Qud0? z%pWjMj5n$lM_&Iuk&whfytWKKw@wAW&XPXJklgrKGM;q2e<|DHevd1! z7IPk?+Zek^mf80-etc4TqO@BzDCx!VPjne$w=Tc49QRw;V4=SVI2GE;RDXsw&{k2Q zs${y6t8x>gu)k&=MN}Zr316!K&8oUN#g*}?cX3Wr-?~zNSh!7VufoP>YBS%k=v`4p zqqyjIu2-5=n_Im$RjMNvY4r;?Vq#=Exd*0aK=F}=m-7xq8g&ja5Cct3-m*x4_w(S0 zN$eiqvZ8MbE|7_-?^pe)DHAz0f}gx@1$tOd6ts}U;E@gy6S=JS&a{008h`iw?tj!E zG7tAU3fb4@<}EB;D+{EpcI;AXP7G7)@qAT8xwdL&;60dcATz^}2T_2Xj%d*Czg#wp zRF$X;>!BR6`si=<@biPqJB<~->@C(>5r}FMS8L#UZv)mVH~*U#)w!-$PLy>!l8O>F zrLc>mR;;2D78z*l_ma$gkphN{b72L1vQG($z!##RQm;mg|%y$ zb8*KqrB@4YMpejL;A>%)85|Cr(=ucuF`&)<8;dz-!uryW)_YL9k`9uQ_n z`IuP<=8rHwEG;d|u-%AOwcYk-zu3Yl2t5DEkn~Y)AwSsDtgWX)x|H$da9H;z*0oj` zncGa4qKDvNe85-Rj&%|P6P`9&^P~dUuB2+LpX!ge*8VX@KON*p za&c?dKhc!;@6;3XA3za3EhzZo)GRG=RZm%zgV>1OuGZOFltT7>$L;3?U3pHqq0XJr zewk#$^_`l(qC7Gr%9hzyb89~|&uMSAVPZ^0HRAXo*Fglb z5E6yM16NDCpHr#0CNeNS>9K+$y?oiV+07nh4!;va=@8Ay3nsvyL)lDmSV(u%FcFHUPI(cjw4Z@(to&_QT z=v1xt@UsaeJEL{HHGZhk3y<6l-Q!UHgKEBmGwpw|lqul4XYax!SM#F%PnWXYXfOu| zxE&Ptnlj11*=vt2&SiWqH0N4VN4o46gSv>|BE&nfMgd#1MqF+%BVoSck%OEoEa$Ge zJws6yI(6Y`i`spL--ckZ%-ZejB!(=Cm*9y72f=L$G~iU`*$9@Pe2xI+TG)#BwodP1t*@2HgI?dVrrDS5tgIrX8zL535@N~Z@7 zb@{?85HvV~#jy%vp_Z-iyx5a`D7zE*0w5S{Ue4&3W;35wH_=8siD0?e-A5u zxBvqiWU(2MIAG2DtSEdjEopv`kWF!9zgo^U)=F+HEiev1eAfHTi9KKZ?LD&Kh3ZRh zZUSaX5=IhB!T?#MB2(Pm^$#~6xtU{48Xm0b7Ts^hL-}@o5ka)Gi7jMKtok-OEfrwO z@b4}CtzYvBAgp0FK|)@24G3nSjj14{)S<}}V8wRCLb7F=(qjx-4zE)&3(a<%6qo?> z%ot~g#yGEo=kU9#*@NELwvbK~qpdMhW9b)xJ(Lc?{Z{#3aTf~TI8LCrrkc{sy;0Ss zZi{nlZ1;B`^$tnDrT?5Q_j_5f0H-C7_`bO$)bCec?I74`E#ln1$F$S_ctx<+YSAD{ zex|3RYaGHH)cgGOfJd&8!R1TzdV)hgAA|GWn0XEM8`-j=1?rleK{P%$! zH_8|{E*72cf6@i!Hn-J#aX!^-AnZC~$rH{2O^W=O!w zRGIgA6TK8{TSrxH6;ZWm$MDMkS z*x|-orqyy?WfvDLJX_lH<=iYI%r0c$risoZ!MIWret5{B7L^Tu!dCAMi^Ut(vQp+m zf>Uapi~8R<75k*()A(R6-kw^2Xi;! z)V?8U9J0#+7G+jJjfV}l5avR%K?Mz6<001LJW9C-N@Y6x#d1ej^^A#Zc@>)TMpgVb$!Jf~o~IaMY|tt-0#hh^gwNj#H9-98@QdBk%xa!!OZ($2RQI zsCNK?se@>bu~a_R@tvi_mZ@Bm$dDmCm6%Mcky6$%H7gt@;8MHHog2d!Y&f@9MwlPS zG!|vpD($--1?wNyDnobL=Lh1d@aD@^+o6~jZ2Cs(#SYGf; z<=-J#U|xFMis(vZ8tZ~muToXQEWnb?r1zz~Lbe`sTrT+ak_3Jgz7vPB_}e5gZkz|* z7qk*WRmTCc^Vf{(*@>EXv%#oU>sM<@MxM`9V>Jnv;-8HdF}v6Qm7@0E1!Tw*e9)lytlao?fkeXud?y%-G7 z#hKZNY>Tt(z?};#gGV~bVQdC?@R-N-4fZ+=4W@h>;C-==A}N8_<%0MR{Ht@)+?~~x z1Xld1cAU;}EG?6D;n`cM%Zu8~EKypmO!i^FOHaIF1nUNaee?2kJ5*}^b1JY!i`Y1| z0UNJ3V=79gjMCiHM*RDcoaonm3b&q4aI;a8;R!*(5QhaPBe)NVUS*d;MwnEC1oShZ z0zs5f!V!fo>vaDd3!Al$b$8WX1}8to#|@!okEM5k_yG?5-emo#@)~UM4XTa1uEjPl z8ke+;87)B}VW%AI;K1p--jP?Dt$d^@O|fW?nOcjzR^815M&JL80f~Mt4!AH;} zn;F{oz9p))(*|CMZlX5Uy@IQXkxsnsl1DMZ^(|)wKC}s1UhB;ah*9t-PNw{+y{e2u zNo6T;BQKuxN4S(btFKhPX{bG_FFFmk!zcnvL*q^bK2#f}ggk8nKipeGfo{mZ=4hzX zb}1q@pOf{(&J?ivaVX;)_Q-`!YaI$xlKpA zH6wG6oGvbN|6shy#6QW@ZeGHKsT;)!j+0CND-;PP;^DL&fG#Z`zE zj}uq|=uDs4q9K0YhlsMDb$uX@1su3>0Sjy6u)z#^t^QS(kSS@MhK&(R=t{@C-5}M{ zO18DsYBX+0TB`P-)x2^#o5F(dapHXbuP(iSJ3&w=rV87p>JJgrD}47mB0SZA2v*iV z4Hl9=Z2H@}n88@el+YDA>MQ9BUT@3YuI`Yr8z8c#J|jEGmLLAMX*4CB>nz*^uyH4~l5h zTx$64b;fI@{9>$`%p$`)JzCwp|ltX2EVzDlP zMOAbL!E8E|EDCqxPn^zd{#2!*{$T3ytw!dTetH9ifb*1D@4StUk61zz5Iu|CEOfa+&U8#%&p7NdbRU3hw^q8Nq|OCAIK|L=vNwdTg@s z$-A{U!PS$U*!g&VQ?BOhhI@#A*21cj=}s`dawLnw^dKT0Ef?&+;)^J}^&~UK@G1khuNn4-KM?DZO^MnbjcuUXdw` zx~A$g3a)l2XPCC`P|=ZtK9s`E^^$E5{El49OM7XHT?)`I*BAyTIRvX&4b$-JPG6x7 zIvx1gH*%9WDwxn#yO&+f7yq~%yv$E3GpxDV4HLRC)?{6f$n}>$Q*ql{uy1;dGIm;O ziszMrHmKOx!+hIU;^<9sBTrWlT41r2V&~K0;v-n=Bz%HY}nkNJWex+-7?91>;CDiVQq9v5YQ^Z zw%@IF^>T}wlO-6kn&F9lJ^ra=C>W{y8yFT0@53iKqqdwRV-L6fJrcjUiE@kTd z7$az(6o0HF)GLN3miJVubTJOv8BUR+f^uDY{pbV|9^EZP)K(22rd>+O38T{|50UFk zAG-0HYzFJoV{J(2dpGF7WADY2)Kyh*@IaMovMy`uK?}-SPEaEKSY_^Vnb#fi7it#{ z!<~2y52{lAlc7vEYF zo8M8Vfo1Aoy!)c!GQvZVQ@qm~nK0%Zkm>FZBABb9fs2q2G6)PluT0>ciz{2DsilA8 z^lnM5vFvIt$eDQ|?NrNUe|&ev=G3pcVw1>?B+hc_laf_^`)QUjM}$BE+q#pfhg`PN zp{y^zE}@f!vs3T4P=4IS`?@e&N<*uUK0`Sqv_fuhCvJ7JWTU6Ci(v0>OPw%=)s~zJ znXwON;E?iswUhIu_~YSR#~{~}rRin^x5~y6hO*HBFhn|Wpx<_#(8!wEV6K8Oco+dP z7hK?({xR!fv))aA-O6{f|C{6SAKfLq(RsP$dz^lL zIY8~sM0Yo`O+XQYM-uu~38B#{>&6g1D6&y3); zSU;?i;toBq4KbshC9iJ<=t_6|gX-1Kf)Vbv<`eu~6KNRaDLOT`d+R!~ffi_Z_G?3% z6c4JLkn`11FO^=|b!kFImG7!pZXaBZ+iiSt>)F7SK>G<8!_`Ga$Te9MQgPCZ^jn@^ zKP06cN71|V>Z(;V1s5gdf^l?Q)YezSaFi3(k!pJX#@KHx>0VO(GTq!oRk$PQ!N00u zexI8u_lbG$T6?i23*<|qh+x|J{(LBcnr7i#wh0`=V$X{pbh)P|%=|`4TZ&}J$Hu|3 z2R?I$34N^v@$zJ+8u<)PQD3HyXL>AAw*{0xtGd80lq{_KaPotvOjVA2#&e3a}Oepbnl@mhJr;j4&hGy)tR$VeXPP|Sw1b(^^P zV#{_T;7Q$grrj*I?dOEPAI3`Z&1`_ zsFMQt#&O<7I|q|51z5%2y|3|p6!rWfVklUrFLn!l5^ElqD4(+^`a=o1u7VZMCLf9Z zB^7bLHV(%!)o63y2h`iq;26Ty)WY~5 zyP|9sko;D3VKQ)Q?53(Nxx27n_h0PAC6#+Lok>-F8Pvx88xw{nTix#hk}?fcQX%5-J&=M3=Olxec_(B z|Ad11HqlBUJ8Zx9u)#;>gsDX}h9|#8{MjLTu+m(H^uI)OB7lglJcetZ0tvx(spyZ(AmhTyoF-Q_#e+Ow#WoXZ_S?0|MCXcaXl)yqu0m zh|=#xWP*nc$R!XR!l-oV-e{dg`#bcJIO}CRWzf|Q?>S4h`9u%FO2R~-PQAQ`X=fV$ zfnI)*TKr|h#%)@=Y2{BNMmvI#YNKRp$@&9t0T~XWsb6ycSq9#Kzq^Pf#r7mVve`El ztsy@sp}qF^?PBa$*;y$p0%aPElJ{JZ7$b6&$j(0R77Twnfw!(4xb-G(xO8zFFY8C# zrcQkJkU7h$d6cP=pUmdl{V;Fncym8hK7K3fdskW61np<@|3fZfsbS)nzyW;^Z|Jn+ zCd+poJiGoPc;VJK39H?13w+f2{RL8e-Ejx;HXSSj)T6}xB9n9IOKWMr}(ebA%ANb*Kd@wrN35Jp_fGvl=bztyUS zLod&ZJOsA~pRGe9?aJE7o|IFQ+!quM?PQa+M#stHk$T)6Kgqk`o;8cQ zk>j_p1ms%Lu|l(REV_=8kqSFIbP)mEOr&u_7v$}$2!7l$rELQd)gq1@9_uqC5Gh$ zqtxv>t95eZ_t;I(M`^Y01j!GRHFF+T2E;~)kg8qZE`5KZNXZ?-DNrKahjU1YB)gJ- zg-d7ljt9fbr|Q!B18Ks?W7tS;UZENgLgWk~Ws;`IZvtzQFT2o>UB~N({;uL#zmfTF zHeF3y+AwT3I%YN_awR`I4F_Bb>A!Rr`8Pqak<$g~5|DR%rq*8Wr>3avNI117Zvu%F zGZ7^wdAQFCgp@U`CEW7Y{!r78;v>abcd3{>#f8ObaU^cfdis87+%8N|Bv z&BfPtwI=uq6|8B-SFsw(PkYktk97M^ zk6s`Xd!ouIQ`w>XBa5gGHBz{_ilgo)lTI{B~+$7Z;h%^ z2<#V7xQM9?pDGT`Jg$20R5~bhJBAieCvY-?(ZVbJ<|4h=CCw*1N)D4qvVI76WY*uY z>qyI@4Q<&ctAXyipz!vv(Zk}r*sJQT;qMRHDlYpKrht;rB2h%Zgi(I0RW(jH`w)|V z?_&{TQj1O4&x2}>t(cf?)1rC^-E4wu>??6jsvLRe)d=N3H~43yo>!m9 zwA{|eftgU)@0`?{!}Yv(!2K|aXADG*Uc+JDj>00IU`0}&D!O_-R=uUPmnCUH%I2;3 zh=q8v1imJhxNslEhcB=#L;bdM5n+&~B@H}7_Sexemd9Ih#k@_1PWf|Sj5wi(_j2yr zll`I4qa6Y?IJTyLmhcWXU9_m}9}uN3X*zKzw&vt3LsI6Ct)l46Tr1AhaiX?AqXs$y zMgdv5-~X4Z!u~3YFrxc=^3^}y9E{1>1v+B3a2&&A>yBsrKt=>MS|7HX4_#d~0iB!Z zoC;grq1&OU|7<@vxXRcwbtcEy%&x3Xx1X`*H=6Yuv4eV}@?G)8>$y!K{AvY`?BNO} z3i)ILbZb^$NECOQ(cEYlAaeGjOLe4d!v#@%aDRF*2v`RIu?A^3=f#by?YOUW+i{gK zhEwE-ssMfb6U-Zmzhm5300GV^$o&1Ew)aztT&>o3J10$O{D~K*+Vjv~ILON^wR@2R zo1hX!R?5*fr~sSG$A9BI?A-Nj$| zI^sF0{QNI|X-8Bf)(%PKzm1)R3Y+IK#_$Wpo;Nk&s7V$z+x{<$k$tb)-t!&cvaL9u z<&k0vT`k!Pu_$9%JGuMct3^F!i4BNE{GRC1#Z5@)T&W~k+JKVLpQY4Bwo{E1T{-_( z!X7yp-f}*fie3PX%_zo+4AZ8^MOm89=m&o0JH%>3{Ve}xyy;gE)X{brCmlVp7}3J8 zg0&Pgd6Ckt`;1!f8;*Ri-E1z+Pcr{N0{^}t1P}oP+*ajL<^LIvV57zMzi$>hJ51T( zfc8X#kePe$t>a*`A(n2t>dSj&gJhp9zXg?^jmXj|lZby8=;Sy7B+UL-tME2i*81q! zQz>wL2BySZF*}e!@yB`SLi_$CPHYbKji!;;YV~R;x@mriq=jqB-+_$(e4TP2lnFAV zsPT8pQXyM)Tb++9(=l4)|0!F6d#|$c?zYC(KmEs~#h_Ze`AuLJd*jHoz`08`wm

    zU%)1zyVELyKVmsIq8#`CHln}=$|Pz5Iq84xYn~t%U!@>kl%jmloj2HaNJMv1(?Q<) zqd3#eFvXCGBukK1K=@Ld6m1bLqMR~w0@g~dlL=$ji^QUBBO0^>1g z*%v1IKR@!{wir=BgYOx zu(9nSD!#-gJNIA;s{!6k7+{ql@Njp!efVcH6&=Xn`2jX7?WWbwugnd_HV$nn8x$hO zL;#ALc*o;*{3oj`^@nbj)wc(=Nk%^iVz99XVssR#|Hl{E!a*#bTjVoi{BJF2bpIs7 z{4SZ&3-SRhE&efk!a-VuA2_rU8YQ!*1Hp_!W{7uBHLwfACfG$S<}gHj9Qac|mfM!t z@~{+`)LM&fM(l@XGHdN#X)&T#!!GMK1x-fm5k=2L;c?c>|Me7>5D(#?iJ;eyv9MYX zaP-(wf}#3h#|66~7x%bs{q$=A{7!&u9%mm3*yPWl=C@)?+7CC%lyy0B2`}wu&8q;r z32MMhy^5;b`xMa-Z~zmECO7m1XsqhUF%V~^xgMSLzf7d~fx`@MS_Dq)Z1qBCnfmxy zBV&n3jH3bjY6ZWMps?zTTq*NYVF``~L4G@Qf~QJ;&$ zE(>FFSMDYo@81CWlNW(=9uM&43^3fd^^flLPnU(_^60bwyYT1;02(cl@{>%NsFqZh zgXxc>fa%V=aM=!gBx3XOPk`-$VwRLQD&Rib3Ixn8IIe~OP9|ZjM@qAv;*U&^XyPVXEBG&llw4rXQjctDnwp9G$2=6ybatQ|!2-)nXOShJXFuEP@e zFI2`vUSlUNF+i`^dC?yf~Bi z9}rJfy2lJbcK*qIO3@P>P`#`pdy>C5E2*Q zln)SeRCjmM>!Z|SK04WOQBiz4z#pdaM=@R+|NmIp&jA08C*vgZ${U5X2hRcLw^6A9 zBcaoTVj$B6z4`eTfS(^Gnx~|6xB`x<7Tx*#*gHwKsXmKeO&yxHDz-vUXLNs$lJD@6 zSx*RBV!Nc3DzNO+`T3!iIzzO=4DxTXDqW;$BV}}mI5!!Glm6LK}PeZ zHIt(k^A3yU&CHqm!JGqA^}(IiA68RPjh-9>CN?HE?x+1cSZ5`FHWKqp!gRuLm|7^> zfSv9K?C}?e6Y`uNk^j9nJwE{+HosaHXImal(;i?>n<+d%$`&S&DGYeJ;ebq%XcTX< z;_{9Z=^f{Dgp2L(a$F+Z2o-@K`Eozx{DJWfaYTBxm4gUG6TdObr`KrD57gdcu zSnfyO^sNBWtDm%Gy*y4Db);m%zVa9VFZHf(Vur3`FXE8h3`Q? za+(jJVf@d1GnMxP9ACKU64`V`XRlxD3L&LnFBdi3eC;Vuk*}ykltU{-aU6@;dG?Ri z(eDybT;0@%zc1=>U!B2;OYOZYzMXt;LuG$Voj0R0&uu1j=adHcZjEy4ZD++{at;c7V_^XNbeekN zH+%Jhm}50;)+F~%x<#m3nuFx$fI*q>6rG4){aBpE;a2kq(aJx#k*p+M8r&$=A_X)I z@a<;W*CObKbEVo(?Wyu0?~#ACU7dJf+shStC?+{EVdS-I-Fw6w&1|?Q`tiKmgXA=G8JuHCGPQ)@u6&|;`n=viQ z>d&`8bWAJ6Urn4pmYuubYq&kooUePn_>(ThRxw_{$%c|vp0KCYV~bAcIDieH+&x}G zpQy3d0mIL$R`7ke)zxU){VTIz!0+uvtT7O$*z(U9sgV@%Kl4uwvWq{oha3oJwE)LC zu8o35^)3}YL=|!y19bx7Mn5!eVnUz?SZ1ZYl3&lPAu+GI0rBNcb+Nll*VkA67{vmJ zQq$s%B}9Oy?Rp$dCoUJkX5zMf0xLZ&N|+-->} zEqnbT@-lELHO7o)7jYgV(J?UO{|Ff*Yg%zyA~08u2>h^XdF^ABG_DDtX#%C^Cm&rFRD zl;()ZbDO9b=PU`u>>G_VJQ>|^G5+{jKTug7pdjjjrix(#bYusw1LhGM>A-X7q;vEz z?SgZ4o4xbkk(ARFPAw)L{r;DM^vi(PuwRzfKco{xH#o!t{6A)K`Cz<%)0f2OQ*H=~)Nhq>;ErGfhkRDVRhc0Uc5?5Hr|PvRB4nsGUIYHVTJ;Kn zx1T@o(qzZ+{cO4XP%8;;iC_BRjrkmy=Dp@W9@mB23eRwFga+oC8{RIOedaJTOMGADw~G1} zDfBzl67WY;7Zv#v<~Vx)@8M&l3GZxSZ7JdW3F5YydWIgN;qq3W&zJ6R4-Zj2qkN7l ztLh8>AJ*P7D$cIi7EN%1HUtQ60YY$sySoGkE@lE5C|Hn#7=CsGn-xp z-PROf?rSKD@`T;YS&jYtn3XpyBWQDU}i?S(4b z)>hAwYElx>HVJNihj&_gv-GK}(w73LyQe&;`)JiIXax9MZg2wy!`P&h(R{`^oFl|% zgC*EpxKEcNVXchJ89Djhl*vv#5K1%Z_ZH|_qq09@%Sb74YFnh90b3ocQ3eKj-X{&( zoF*X6GpBqg@bE$XyLYp|q%?|JtJGJ}{lk0KGHiARCxWA(u5cebo=YR_F=j6K; zB=KcxT`V*8u9jaPX}SeV`1@#zvAf?hAt;8{TkrrWBMs(t7uu75v@Dcc?0wr9Pu8_d z3m)*M4+=SC=~=)XpxT*}Lua?Y7QE1B`}`Ff|7JP+(?}4^Y8egf_JNqJQ`1EH??BkL% zD}fl-V>G|EsV#@1XTZUoXr~Y%Rpe*VWy3zXi@fIruH}xpyV~zdn(=0ibp3RZcD{dD zE+rnt9!&E(24$5e=-@N5ael{;zLx$4a6lk|J>Hoh(6ZB;WD+Vr_yayWA$N1&`IaQS zp}lJlvuOPGp3*1`X&nJp*}w6L3Ym%lZ))~bM9YGRVqa38-*rBqP?Otj3m(9-?63cx z`c#!F^A%+th3^cir5tcuqh4zJ{hX3qvt}S|mH-=@xpBGW+mkUHV>+E3gf!H`#Fp)c zqpyGYyazCVloHH^<*q5xK=I#U{hkD`fjPxt4m34=AotMPdNJM_>|9IW+W>U=V8j6L z(`LFC(c@BYP-1w;O!={bOi)-SOp;-gMWV=p!M!;MC6Q@7Eu-yWaW`)Z`9^F;uH_1$ zR%091-oCA-a2o2#$q2r12;he$z6-ILMl4H284yGeK$F<{I@8ao{8OA!W=S%gJ#Zlz z!z^wX78mT3^^^F-<%;9~_u_|tR3wdCO)y8iJ;;YRHks>rXX6d9WGjMShLzzy!5jdEY>4NB={P58*DE~V>IkA99c5{>3rHtMAs-BhwamphtOS#g5-pqR+DIhvyThs4@}d^j&%d-)nxvjv&HE z$iQ3vux#0C7`USEzQ*~G_q?s!n7S-Gw>gTr{{X}=S&S}ILOGd|I2Xx zm;Ee=5)n#ZAEv*ppA!>71;Zkbf!=fYjR}!o>TCl`{tEocis!qRzM@y2jF~@A^C(RB zNX|4=jqjjSpzY!U3BJP4q936fXINo7G*vE`uMh$8baIp#chDN+2Ln)^)bn~u`jhHwf5z`S z;fqFN-BsNT6P>=dFwNEwb;*cYY|-?~Fb5ggNQmF#iFv{A7G=&2=nrmQS(-b}?t5x- zEX>(z8&ur7s$@xcYxe~5FyPjlEGM}?h0A7-M$-J8y42{(nd2xTxdgh2*6e;PMsCRz zon7Mjl_#U+Q*+aVUXssRmK_-$jo#YkMNw>AduM1SyV2&Rtq|+dJb;D33#VPS+pDes zbfKvlscv0^r)VPTE^`y;f`+Z_u$K(C^Juz!-o8E;gTj zrsrW(qZxazwVZ!1^>)~IT*$VT6`ticoH0Xk_Mb8^sVGo5imvMs%JLc?p{OoMredD< zlu7&i7d)1!(K%=^6EQu3h(L2Xlg=&vixiN7ndloKAlqsu$r8H=mtd6aEh>>KkuYv2 zRRF~oclBQ8VzOCVTnP`WkUWc(R{i4-BGO#bKjx%auFM*CSL? zhwQW~k0iU%C|9Hb+w=wIl^=YIZE;U%i;FJZK5=Nz+iu$se7FodcQN{8&mFWCLjSQ+ zH+IW2-YUD8->X9O7ftMc_W~ea+24Ugt<)cvcMuW_-C<8$L+UFTN5Pa2q)T2oR@*@< z2Hq!0l0QP)j4i9Ks}xZ;gidlpCi1tN!fwUEq>Zi49Ln_*AKexbI+Q!DT~~J09~WHq zWfB|B0F~q%$Cdo2e_nvAK%;$Ix1Jo~py>g*}Iud>n}OVi?J z_)Q=Ak^I|9Xd+~ykT1kD$Z~^y(-?oAKmQ$Pl9K6+3g7Fc71I>Ua2&gcnK$I8 zQS1Tidj}*2lqgPm_UBj~7?(iL>gpH0NfE|)82fP6lmv>aTBIss zLkeZ-u7HuzR|2wE`cg!9;%|l^7TO&$p`7$_DP;Awc%f};@Sc8`*`@eYMn+V5QNN6* z;AhA+DtO7eKP<}{K5Ipb%I9ivua=;39C$yrG6O)S?<|>g1mp?g%7(jfKo*{wsJ%cM z0yZ;MTDO4^8ZI^4wb?`!gVa>oNiP%BE`i2&p}KEoVFh7dYIdk;3x?m*beD%Y6KklM z38H6~hdBs}!|6rhA90+eQckn)r7!GjQDxp%DcC$}UHjh6>?QRr_4A*6wI!b5Hmuot zx$FGvt9gCw+zPg;s!sYp!RhO&sab5ohpO zx^VwDR)swj@SqEo^O45#GH>~(8PNoKiz`k=0-ANu3PQ?SF&AUGO&}B$FK9I)TZ`~D zQ>>Sv!Y`X!FeEMck|6;=x~ZI4w-HjU#)A#$1jp&+D^$~Q)pQvsp$=vlEGunl#LemM zHksB2O?z?jhg>x9!-Hlw31npH=0ehIP7UdQ7E4bxl>{z&K|U8*-w}JI9u!sPEuZ_* z!}^M1ZkN~wND}@Kasgs^F%(urq#PU!;ug0x8^xdQUS)@CBx7tY28rpI8B0(%Z*r4v~9f%`C)BDqN{U@M%&X zmmA@tQ;{N-V$TzCZv|o~wHmk9(~KlbzsPdOZ_X-zV**@TVYC{_;<>VF3D576ku4qv zyiANF3pYJHH5FAX@+N#5sscRl1v1Am+^%1XcU0bDPL%4VW|iYy{&YM@5~_?j7tA}J zDp%m*YA;?`nrqhAc zi_IAU3r={XKQh|12|s$vjbB&~a_IAs(e{O8x#pN#_2NKMlj(8Ycr87)6@Vq4y%Onr z@>QONwuknU8>ztR=cax^?S(Q@miC>6)7#0XYiqs&#&v;Rr0A*x>rUj9;>g~@$d`JB zfGDnJV_Q#p`qp_p^Ufw?p3P6)J_A@ z#;Pv2;TP%a*1j`S0EEO1`L*I7E3yyn^~6IZLfd7?M|itqI1pD%TJeH~kRN~R6(aq_ zIZE5Lbj>XY4rMYVcrJ9sxa}c7+=l$V)(e`&<3QB;X)e2o>MKG6>iU>yx-0R8Z$fIB z%g7I$IZm(ev7jral*&%2P+6rGjzW%anPEJlgxLD7a8VW1^Q6`nP@BbOxm@nIa{J{f zsgXMGVdGCc(e}b%yiwts&D9)eIxMPRwEIdm}!Kk(7^~F_KZ0g zL1ye900x?MEsPlL9YK11{mw1ehF7EQS%c0W3Vl1T#`zZ_=9SuPJxcct@GXw>)d>CS z;paKf4$P^3R65IFuAGg|2XRC{fhF!?9c=dtkF@20nrW7Ymo|QjTyJW@G4+bT0?D7Q zaOi9~hJDLm<&!a8cdr~A$V1zBLuoA;(s(;IWaH(w@yN7uHX0X_1(IZ~th0>+dj>o1 zCTY4w%kq42&)kJli17~Jz63A9kL(J>5R#D6cZ=3be;B}6YQoRU$jHuN_w3#~I?Ts! zU3sV3_NzC+uhtl+>R{M=v}LOTLAyD0#O zg^RU5WH{|j&@j}bv~k%_3ZQS1+iFJA-&qh~>1tKf6#sZ=Ko&f9+3!m+w+cD)`C^(1 zX~t7M0{5jioq4h_>h8D%)3RCAJ^&! zXDYvnIRaj${~MA(9|80sP|T_JQ)CX)YD(jzt)dtRhr2<=jIdi20Tg?Om2CRim?>3jTn51eT#*jn~7rwP@It1pr>Wc`G6%2^m^s z3hv7l&0Pz2vezgbj%x8V=-GU}#0sn6vu`8?smmKKQ-+N+!dwTwkBy5e!|% z>3Hr#F64$KN!n%I4HxXUA&y`(P7jtOd#X&eGU!ra=h#}NGCc@$&B;af}Kw)fy7OhnR)31)bE^_x9^?gBC~0>|F*+`z7IM;e@zX}S0=;zh zMJn>E*Y7&+`sx!c%ODHPRE{3Ga#m2&|611qg<;RESY=W`(_L@G^zZZC#40`jl9&)O z(5Us^>Z|(NM}U&&1v--#!!2=@IIy77CVZ@{=M5(_KGZ5HHi_(56E)*AZT<8I+2TTM z66lz~<8?o0&bnisrMxM-GZ>*ROivPc=gh+#*_dTS{r@=d@xs);+)F{p`sY72EO*g1Mqbf2>j|OQ&MQc z2ROzmYM|l6f#rA-qghXG_Yx&wfh6oYO5vJo>=ma|M2-0f_GMG{ ziqf&SA4O+KoT>?~L@ZO~faE^sT?gf;ovr}m6n(d$b(Jc{QkZJyx3dU4#!}7eXGlsl zo;XPE)qZffWsklNS(EvGC`P31Z^`&&T1}^~;pZ+Z9#v46rZbJE+A$tT)=Kb;h>G+z z7O{Jl?KRiBK&J68_@|lReyW5|?MP6cy6ytq@#gYW#i3?_OO=i5%j*7DtA&fxSStH4 zDaUK|5=*MK4K8I|sTC!EDdLLIuESO?5Wc-F0c}Qo(fah?xNP?6dJF+1j88vSGtt#P znf-Z33sB;->6A%Jj<#jZD7pDu<*FEsx0~h{=%vIfaJT9#IsV`UI+@~Hv6)HvYh)zO zAFe8zRmcA@9Omux?`1;AcA)Y>e^aW2lO)qKZ&w8eDa6G9p$|sVqFT7?G{O{Yj9g;p ztuzG$pOkWN@rfqPaD8e1FfCb7&%ukKmdnVKs#0ZHB$C3xuHRjE>ll5p|3t{nX?(>D zQEkL_lQeFq9N}<<`CT&zzz$El?Pgxr{B(*>nWh0^$5~&gdtMEsc06)389WjYo7(c9 zQ`cPD%wIz3mO)iNPGT_7E9ZDi32{sb*}&88!=mY?mzNn}r_AY1Nq=iZ04&b%G4XGd znYNuWliCrBXyY+^;D`gpEng>63x1Olv{aU z*?G`d5Vv@n^wO>-4LVEVENqpDJ;hb7t+En zb+MU#N=qe7GHcUG>gs)i;G%pyV6mu%8XxX8Mf8IfD5=c#<@X z&|azjJ^K20xyvV5>Fv8Hf;baNZADvi-1)pvGM$|^6GdiL?V(S;ubK;%2Rv~xY5&IJ zq@U&oZA}W$V7^4i4E130Gom3!-+ZxNEtcHgPM1coE}lXH+a=x4+}%d>SGnp+JsJ5g zxAeW2$^QARt|gd5HW)F`r52^sT#;2vn9)uo%qq2zCMl7%Kxh}>TBdKm9Xe?yCPQMO zS!{fjovzm1MLwvwzOIQg6+UxLTcwh0mvth3OP0EeFKu@w&b&^5(8 zDUw+_U+XGkaO^IU30-EtN{q|4KFSWA|Oo~KzIfhYtowA3X?oMf_b*vAK0}d^OnBjaGhs%$i|5M z=%B@-q~_&lBN|&D_&MJ`)njSMsE7CQxXzlUB)ZlPZU0LK`1j{s7fO>EMeeN07x+q9bn`-~EPQyX4_8-K12zq1p#%6?wC!b;|AO{VMHjK5q@ zOO9#AIt{TaQhdYRBwT>;tsK&z?`R0D5y@%{&%(&rpv@i@ogo`!I)(1Ns<5Z`ddF;H zT2>E~>#Q}en*)&2tR6`H?jhRgb4(IMo&f`PVT|0nL%CkifrZy6@fF_d#MgoH;&qXgT z^|8eX4zg#1T~kT+cdTNTFTd7X3iJk9OzGaor(+vlz-3nIwomAih%%&Kml2P?HRO|) zy{QdGWRwc8(7h(-Wm)g!ke1qv$NM@lEf$7#; zIam0Nm+AR0Z>ed2^Jx?F9ZQFqIfS_Wf% zO;eH45_@iYiC+oP$TQe8u@NJu{_RZxnDL=~A&Zo2Jm0Nyg9quN1o>~E?|Sz!g;C=! z_ldL&ze%=AJk;9kWZf>D{;YNd9g{s#)MQ{k3~N4_Gpc@jsr<;C$gK62b}cGWl_u)r z--AbRO-(BS=a?nYQ{%r`(#&fpOB$$8r0guC#ZcE)V`3o2Ou&%&@N5D%?wc(lCMvQy z5Yi>+NAX++42K71afTcAh{2;@y;FyieFaF7wh&3R)VZ9N^Reh&W?JOJxF!1=#;I?- zvEm)Z)r+%y+uk19JB%Af(hz60=8RPu_RW_pyvuv;3s6h(xwunJkyA!G>wSq`*DFQ+ ztZT=xQrDiYACiGwX6s@>#SMex6O`Xd?Iq0=(kUE}@i?XjsnOVv5e6fFJY7D2kk!Da zTTY%I4KS8$GDNO1!CI`K>JE=Q*@<=WydjJaKz!3MQFU>^`J9bvUDba3ag=T&DZM?9 zd4(tKsr=T7)JeQEoW0Eh8PN26yJBt{T&!Qk_)`7h3k~C7^#}8r3Zu_{odmi!Wf!1{ z8y)USGs|548lA3K7VKs0?T3Lztgd1HXx*w7TwpMtuZCM?8NXtZYx;h%L$O`*E=y%= zI_5IfsKlwFT6yH3DJxks1 zNy};-f6hFLLYAUDX|a}^Q50si%J+SerOV=&Exc&YcAeM0Xq~Mgzxg4_xa_NdOK<08 zmRBlk)K)V5I!e@4K#d!7lywReEA)^mO0dbf&Q)VX`5N(^L-F5{6`JCM^YZ^-$b*w|w9C>QwOa(r*Ak84N%NeCGgxEd7uzoZh6Y&~i{ z1a%BGtG_b%KGOgh!0|n>9@Fy%-X|h0-f{IEOm(B|M&PAyM>Jt#jfEI(Ly-~3_$Xpg zp=saJ>4o<7t1SKY(#!*~LjtOQ#j<|^RMt|Y&s~(nrise1`l@>s{VBGQC=ebr{`_>x zp+{L2L;@!0q?|5uHG$>EVq8I~hJ6-A*Ic69S^1AHS|pCI-$OtDi$%F7;@q7<=4 z0v0`*LxJ80^W|jEy|j{&4?w-a4&1|YIflx_If6?joq*SRHm#q5YHMMrDNf02Z$)LY zwTi{OQoQyva+zV`qf=Sfouc?8ChZJ2i`ygMVJ~(ErMm1}>e-Z(wjG+%y1c(+^<&oj zUA1BFU_y$E%uF@CIJVLY&iAmMMn%gUEXKZM+T#dQj?f_^I~qcap}n8sApqVDSY;xE|VW%52K0a{OYg^Tayq z76@gF}eeo-|Z3!uTWBw&K8+f?uEK2OHN+Xtl*gr8~^Cic)0 z>!uP)+NAd{_c;Fte}MtxFLK>85SWR>hXsNRrV5Pc!A~arllf<63qw%OiQg+Ba?P;k z9+h;Pq2KI-lfJwiSl;9RWoKaBr7}pA8*bwM2mY+w0ux1&v0}|mY{JwW0-6r1#ML~W8G-{5hx{e`@15`AIJX;sldZ20e^_odlHdC z-y}z!3q(j`q(&{~Kv83KHog-a)W&4fOeGKtssw7D zcDeDLWWH(rwsZa)7OFTb@aS{nHXpdIEhuLA4)_aMjPiKxdHJt3lcR!?`$R^KiA303 z@xd(y?!6M^*q$7$b6PS>=?lW=ZF4NcdBxSKc0*>o|GVHv%+mIz%5g|lb@!X*rCnBa zOkj@zQ|MML2KlGgUiX$DI{)AQL=D2Is~3$UB{8fOY4;?*96e4+lSl7Ul0eb^#iYG! zPZIph1m97`D?%alzM8Z$nxjAe!?6NXq<)2;t1y!)XTadOHi8@UqnsyI`4n;Z>)O;v z!jz@t*6v59q&8cQKxq8O)#5NER}(Q!1J7L#hdot!COnuigtbKPcPG$u5Pkp4vHtP2 zH549`hobGeh=ufI)bsG4*ZmaPj1|X3g%xiEm!B@&=V9zPjFmFRjD2C&pUC*vHu?zL zMpi=}E&t3K_4k7)Sk6t6r_YG)I*!}A=e{cUi_8LT5<|a{cT7nKvs0*2o~IaI+2`fYeh*9+@#W%&KM*F%YZSw~_b#p8Q|!McNe;zlhngG}2F4blCawo2 z*pO7a=jr(G1zLvLrnk%w=GmUKJ}`x3sOL3mIxH)9a(EN(|LJ*_Q=UX&+riL$j zdoWu7JCi+e(qz1{GtbUGqPkpu)`3Gu)RuENliVY%0vXEg(4XfSJw}WS&#(Ah=!l00OUHcQc0ju&#e3&c>Ooi1= z@Qyr2L?6Mx0}|{2GnOr`k0*@-lFl4PjZnf2%dcO+=!d!ywKuQpf8DJ*Pn@?bv@`#s z%Xr$nKYl5lbADp)&;PhKG6t*Bf|XrVPs=d`bIxlOFsvGMLmk<#FQVU@4`GGC=l9z` zLSgyr285r^Iv!6U-{CP+KQ3MSz&6rb=}nk~C`_+(Yc;3&{mDC9BDs>Ns)N4+vc-HU z5Q%%9x&CxZGga?p%aXn>_}+{+g?DA;AfmtTCjUMxbjILrK-oV7-=AZ1VPYXzR{MUo zH*?#|O%)a_1(xUOyr(Asne3qVIoW|x$VA>1rs{W zx*od>Uzd`k@ng7_Eeb&9&o72-xZPNlR|Y%%#P(5gj8T6MsKLut%{~+;=WJq$9ZZU2Wu32*|JQMfK$+Bpp}%I? zp!YfM>z>XVif;bd86P}(cAL?s9vsueP{NQ*q>;`@OIw$6&};cSpHJ-3oavW0vY>}) zcd8v-iVvoUxThI*F6RFNv&j*F*de2RSf1x-DjW4<_C0ej3d`+|JuT^LZGq#DEVlAc zA2*&?astZ{)zkt0Jl1pU!($^A^K%h`?q&D(6jA|ke!Hsiq(W2 z01JUox32NQuBBQJ6R{z|eow*wmFyMr>+hrgUzXc#Sf;r7^UcDU)dUcQMd8%+ZeJ2L z<4{lP!*G)@xiEq$UfER$cU#_30ZgN8HqQ1YDJ|~ABFnw~NMGNNFqI!*fVw8bgMBg= zV^c#KUhhHG@{g09yU|xf0*n{x*N5@fKG*X*zF5P-IkD1&?Op{Xc@3?CJJ754;Ix@0`60CdQF(h+hi(48w?9bQW$D_ z(FLJMqeY)-+hltMBvMd>qM8RKe_0`V^0HNv&;RHfOd9~+^5Opp?gb*rm7te*V&wa!#{IkX%UXYk>OOMDm7-v6c-8RihrvGf2#K)k=~NvcJgG4eB^ z-(U^uf*6dc53`em9&56^Pn&&tC=2h>C(C<=GjE9C7AF&JD#RM@HX z+c3E~A`D~m>?W$U9HQThyco@kVlp$J84q`wbW?#X={_JYIwr4=bZt2{Do%0p?RKS$ z5zbbQD#&@qC8C_UqGy+kUOsO8?chMY=Y6@~HWBpwofj&%2EK@2D^B$UtZb6*VcHI} zZd-jKCv)S3<3DXOnHS~-7(}PEIv|u`=T;fEZAp0Gsg89>4@nG!>y3n+51mdN?fBF- zNAX!6&qd=x+Nrn#PiJ29EO!N=fYEMxT&aAp--m7!*isFnO^=)>~O-i!dB3ygJ z&$k`|eAS<0D7paF;@T?`ykDw$Vv*KaKhHH?d)+RX6NFUQT|dPA@F|?E>~ug7`OX$t z$r6ikdzNYvb5PB1-0~)U!^#cL*%=n+5Q|HXHvEtT4Y)l>ycKZgoGQ4&Y-1B9>>#Vsk8RWh`7S0V{=;Y4)Zk&$OGNAVQH!|{2yv?Mz{7q8=@pZMsgzbcheB~Z1B#1#D^ znT{l;;`I7qzOjRI!jfTP@nyoU5KMrqBm2aGIh&2lPMBU;@a7q&tU8V?eBX7iIQ6aI zL`NFx>YK-5h1M07xyo*Y!U$X&K37_|Hh)jl(cXP8x|iod$fskhVit?|Q|L_=|? ziM~(vJwQUF5(x_PR=XXke40G&a5Hcr&$(P;e$~X~2q+5%jn4RH!Ie|MeF+bMSi!{; z6mcAhB&ujYDTGwoPLVNtxP$lad|ZfU(agc`E%FWQoklzkGh5;jU)_~oH?dsAh z7a1Gvn)g4~7=_Ot{ex>FrnfC$ya3hOFdbYMw*s%6nZKr0{hM`mKLGLy-KmhdUFdr$y77G=+ z1bS_c;bYMl{vl8sH)~{`eC|crU1N{HcEnDCklLiZRY6ac+0$v! zrk^e@f-2roYG4ag!?!9cSa@60z5>Ql1VDWD)xt$qj6zANlu|`x5G$=|WZueiSY;&V z{C(QjH!E^nb6wC6R&g}UX_;Y&OzpwOjGy7rmT@2?M>vM#+o_bNn?Zo-i6aLFImVKC zxg3_3V7}GRpCB3RRr&=z<=$E3fA0r`Fw4<09YYm;Y$rNy8>-T{Z|pLtx|h0=Zn>2O zE+pC|qT(11ZPuHL$9l|5dPsH;N^+PR#Q8DRP1(a7_S90-b{^{j6*o$~ZhL;t;qARu z3lPuMw{9UlYCP!%W}KoF`)Alt`NaOIcxE2h^;?wiSa}+w(Ch!1yrl46K?pO2O+tk4 zHwFA2C^3>tR?D_wt|j~CN}PkN2L`P=pgc2J@OH6)6{W`V9dpa?{PQ027gm%mg0;9} zn2a^7n*nORHlBny+rnR1fUOtba`Pkn^F7^iswff_WSsvj$`6R}#_8SXSXqNurd1M_54_B;6W>iY5HykZKKT4kUSnzy4?3Jp@*j%ve7u zmZsYdm|=&B$VEC@^O-te7gD3ut_jN^<6OCIM{^^wHb394^uUNS&?dtF%yYuK8wyiP zx?J_`TTj3gZq2nmaopYdet&j*pzLyS_x9!S3=5_)8q@+Q^WW(ku54T<>PeEd_t*?T zJ}y5$Q1)**;ue+=XBu={L7lkig8Iy}^SLTN&Or%QY;dg3#hkUlReJSS1OpN!Y7Z2; zmyZ)S$KMj$HBlxDHXY?Ga$`aXyS*k!Ehi63-io?Z6P@jTj=x{Z3InK#N)PIK({xvd zetjHF-v6h(6=uFfN0kvMNliTE=T^?~<^e3H8F7(9Z`5;=_c zkNSEQSmra&(4J#NM+^p-)+oOIdg!-Y9IvE}jV>1NPV=WY!!E*X^~T{l`K&MHc#9Zz zou+8mFv$E?Iy)ztYx%>x;}IzO5r$Z5p7&ND-cHby@_YL?frYMwGw&cM2sNA_|KlhW zapPty_aW0|I*8f8OXBim`aK-Lo2$@L*JKrq{k^I3Cw(jnfLDaW#<+F39HI+_a!ki= zo>wK;8})ST0WrQ^na<;ck50pDW>ioxWyP}-E4~#8b!5~P)!lD!Ns|QP^x2G7Y#Yb) z!lKV9R;KDU+E)j~tVsrbk`FsVcgjo-q;=!juIbNS#x_rAOG%Qt-+y@|vKz1WJ;kyY#C%dNV*rjdy|qa*S##g;g+O<- zYi47|jg|UJ{CU9B(|2C<=hrbx!LdTbu*`FZlcrgA7yz@o4Nw4Zo|kInZ9{0 zvNXbU9imC;<$ZPa>JTpVvvO~uL8k7{99!@b?K#t8Gg>O^g2wTm>}CQdA>)o;aA-g8 zMD#ZE>~7>dRWwKT{sztC?Tu{aZM@z<@E?^-C79G0r1Gx#F$zf|X1&YT&$KK~s})!z zJ`7-_k~)5;MxFTDZwPH0$~&`Hya?~JxdOP9X0X;*KOq+?`$C!LR_fRBM-(RwxukI6L5{%obf{_8>guUX2=GKv4@D)f4*eDXzWNW#7p@ z=#$JtkNaSHn04!#NU#x=SpZl8>}`&UTd3`2xvvk3PDxF5s$hDuqj!Aon3@0T!9Q(Y zWan@9{M$F-Ns(ADq}aKz3LC<_9sb>?Hw`KBORdL5nHz5RFyrmlk#6xvz3rseUy+%J zo^sVoiB#GK^w%R=I4;xtF+$5-0;dG&rmiyZK7h;eOKC7%_spX?=Lb2+3q_+Q*l+`x z7%74L^O$7{Z}_Kq6~EI?^n;2e`7WEhhV3n7Oqz7<+g*_#;|@a}sUDj)^G=VGs#S;T zFe?018(VyJH#GIl;F6Hyp7E*Lse?LFl^h5H8=U(I&0TmH$NH%w5u43Y5ofnCc=n3; z?d5B+?V9bDFye+!ThFqO@T0#Tx5rCw^|3TLG#qT^F1DnPv;T~8U3n;3PcUd0kn-`t zZLi2TE=XrB9f9(1>wV|}J{}Zd^MfZMa77vG6ri7G)adloqzt+WjF_laDI-Fhbq7B= zW53&I_CwoA;M03w+cXvYX=DE9U=-me^*l7U`0MI1g`T|mjSNsy)2 zbqmzMr+8ZKtiklKeC6v2n72c}E5z2e^kA}bB6edUP*QF2gJ+doMT0_a(GqAgo2L^e z`!5v1HQo|3`KTv|zHnTi2H}OeJ|L*Dz zWRt4jCOJef(d*wzN9s>$5&z+0m=3ZuGLX*%DrXgUZa;lWotA3mGs9fZu09J z%M6I9M}5zer2&*NZT{9*T$-BKqEAP|<#y&^I4-QVth+ONcExoqvgl9{Vq+@4dU5d^ z;LfDuv!}zF)l|_q%!J(^>gJDMWcq32<6pMjJx94sZx!FoT5JCfcMZI^73{@uF8{*w zMeiz__z(BDEYBJ zvNswMJ0V#s@TeJWQZB#MN8pYo2$BP#r=Ao7Uq@jId15)1U5E%Bni_1^kP-&X2^e9+ zY10#t=tnboTn-p6#uuzwZ_5+iC(P}liY90vspl7w^{6zWC#o7fW>r}9zfOsdJQQ*r z(V*kAeo>u4c~~_dhsoAqv|nRM?{)^}E!B7Fv2%$^yaLv;?R;kH>nx>jmh zpdv{(BZf#;6=p^XeLJv z91#b|qsG^F(HY(0>gxtC2 z3tPC;d~;^Y_A(Lx^e6v}p}RL`C?f3KB@bA??DQRBhWC{ze}vQyJxzC)I!D2_fNHo} z9|iQAw0b}zjiKY$`3VknO|8wM%DOAFW#q%$;s8W5Md5||XE4A8+=zR%RGwkntQJ_v=BUl)BaYUr@qlLjFIS}x1yf= zs%D##wXdxv?&E!%wVvYJnGQCnQXDl8Pw=GmO^PXbE8pHtU3ik9?$bkRo44zT;{MJ@ zl#~j3V3g9;)3@xGx7azdwjH3Hn?$aZBKjaVVCaa|wBMiOgQec@U&9h~X-#I62Jf-A zmVX}Lb$Z5^pt2MTJ0Tlev{-rQjc6pR2g$F^{7EK_2nC0>>_*&5#IdTVH@ak+1tNvC z?CQ{Jl>fM%$HS+2*JdFg2_$>p;)+baR$m=aelSSgZR>Lz+bBS_+R_lo3H*^Predxv zZA!;y<~EDc6EAI+z`t7N*0fg>h0+*QMkO|5rORpo!a))ua-YgqH+ZL!5ykgwOEOyv z!-ZDY^W71J-b|d*;#D_k|EH|`sbme=2d3DRGCnQ5;*Q1yxxSwp*6W6P+m>4&i>YfL z-me5?piK9qnj)n7)L;)cj>4_G;PfkEyV{~8Saz7u8Yza6dRsnz=km{HbyMN?Ix&li zCD{Ao+b^NZmhXQeo&LUi>VDzcq3A0U4!<4!k!IhjjAp7?C@U_35rEqjskTri@pq3c z*^sz*z9+pdFd$RaX$c3ywO-aVTluV%o?f7JqCTcP1rp#_I&n9Wyi#=uZku=cEQRe| zD#EkOMk8U9#_C4Rh>^lzT2A9W*9o>g)EF)PU5=_*KR8DkK`S}T>miY$zvg5cgt8z> z$wtFYS$P|fiXLS-MBUA#BF`u59+xX?f0ZZ=EZ?YKQwn!*9lAGSUHmYdaWRzM~ zJ5$R4E{R}CZq4=E9U~mfaUB>B-~y61ru(%YHqC?e+v=RTQS9XNXI=(R`82DH}=6Nmc~M8G2l-4iQ2Q6Gf}pEokXO|1^lm{Ls1&!J?z^#WUL-8bu9|iHE||+oKd&;^w}RnXP2JZo zt2$Mn#8z~wn;OEFro2}7`_)nw(ovJcah_yF(&b_6 z3!2)RqnR{{QF0t|liG>S>K*{X#d6(j24^J2BPrpbt_QRom{1&7nM|d%eMqrtUiMk) zGY*S}u3=$1K1h;w>Nph%d!n zGda%UUagj&ruzWiW}UKS1fhGGnKf~&S@p6Z3WZLoFUJ}HSl7_6aa8*j>-RDC>_eR> z#|p1%3xy^JIaQ`h4dTgMvE+!>RlMKAtiJ-kG1YX$T34W(PtxKa8m(QXH{dxpMI^xb zyw5!IhcAw=62r&%Hw;^FB}XcmI&w9s+LZk5coS;Dz_z3dZs=Z#IB3!v(FQvX^>HZD z>Ebn9%v-M@Bv{#CllN+n#);F`y3_`y)6oMkwKZtdzk)1QlTi~SU9sZSXb)qowUH~0 z3|0Fc=!wvmMO~H(LmX_)Wfskh`8A3D@WrQpp};Z=ECr02WCgfrYk8g>-;RO9&iP1b zE$e{HyNNhtP7X#Ph^ezQpWh0D%x;F`=OqgfBbB+@%7&^i>OfK+Wl0I#7IkLy$iGc3 ztxRfq`{!octqw~PGHcHXXBTCOcE5+rP;_slWxcmt${*^-U(6SFHLnUPF8V+|%WLCq zrHB4BV_z^>CG3tMh4-4KVlhsGM&Ve^SoL`5Vufj z6UVS>swv4ADrZ}DM}VEK^IQH9Wd1{ixa#PQExjGP*nOu>M@6nW;w~IW zy}Ow)UVv&H;BX>DGnBQL+_Z3OfdgRI@Y7Ol|>&$^oy_;u) zIeX_M*1r6t*7Tf}v-@PVuJlg@P4`R|lBby=LC1$rZm;*lX}UAE(86FT?@(B0%S?^6 zt>Vjti<&SDVGluZIINH5)u(SPsdR6**bGHiYE|06o8}H%YaEW{&01=~JvphKRh4)B zv(2#y%M9?Q-LZ+q{PdW$J}Uh8X{q!opN7QrGM;b9&)KQkhC8w|7zG{H^sCPOAX;!q zM`_ zaSE22aWT;vc|W;WNYLj+f8OKfbCf+jK5L?vPbT6q#mbN;PB84p1f2l3S>Il?!Up8j zfX5#zisoHrwu?hu{B*;&hDByM?qTchh1;;6LV_9Q$v)PN%lJnOjD^9v`#}GDR{^`mw4m~O zzbAyW7300-OUk%Q;=Mr6$VVK!YI0FDJ&!m&N6f+c#fU&Q)GetG@lQ;HaG|0E@gor2 zvs-RzV?<-N$=3A{2GESr7OIN}sn4gLnJu!O2&fFk>WZxX*>h{!p!Ix~!QPX-yo}=S z&UVe10njQk~R* zeU{*J(a<|%6o}~%a}^aoX5-T4!@Qv%7NRk|KRB||J*H~@b11T{5+1TIPo%c}2&eHK z&zQjZPBG7s*4Kfze&k&`Vg5^DjsoXOw#E=t>dvPo3ADSqnn5R>#|Xc<^!#P!T_&Yq zXcG0;oVy%Bk00ZFoNJv)u=pa+o@iW< ziXoZe2J=sZMXM%>Y{7mpEjbF{G3?UQjGLBP@spi8Uw|1xTGl|RFQ-i3>*%#COKW}U zUP_u(Rp5Wg??7S!o*+wH=lz!bHw)ku#(AqP#o7S zc@A<|)9A0H&u=*Xg$+=hx(Ve-K|>;qE_7QwWm6?;h*FFRv_L@`=4o!Bl>n|t(7Hu#y*GZwzgl6p+E3jAxdVIRI>$43Y1086X5Cq!Q#=jfl0XwbmcBkHt2Ie=nk7C=Xat0?PyqpM9SCVADl-{6t^OBRL#vo6Lv%yuU)t=$ zZ3|^K=v7>@dJFUxtUtcSEnS80!|8t_&`$tCi^9bd#daK8d;XlYf=&OeIiaSL3&VX& znXgXx$q;iB<5b9~tSk#jCFq+DO107DjK&y7)qc`U$eLt2C~1Z!O6D-f!XGlDJP8R6 zm><%=sw#MA#Yux^j7uCK#k1I0WTX;5s}_Tb^=7Z-V+eV1i(^eNu;nvn(}&l(8x6O6 z#o1TX8Z-Ct0~*eUmIkD?fu*zVai2c3TxQ%%>0t}(=SE}}mXmzGA?Fm8eGZgq73W1_ z92UAe5TwOp3RFASwi-lTc$~A>1Ot`E%o8%@mEQnT{P;lu;{;sq*ff(f@uUQ6nhcY} zSXfF3TXrPv2+RZOv{G>?$v&uznZKA2$o{>fK7J)B zONURbZ~P#iah?L+5j=KLoMTv|NpF&qXa{eb)GJ*4TBR+FU!x*{#@1Q5ybxa?nrkf0 z#v8qPSt|EF3hxDrKY$17|Dq~vN3*$X%P=mU3n4T(_~bOwOW>$r=+$6@sE#69S9@8N zKw(Jn2ye(?ehOLF_Rs1Bvl_jF#R}yND;a6fcoyXV!)@24+0)1|)jP3K_m9kk@3iKcmC(-HnLFsC{CJ=8 zGer%IqtUM9?T4hzv6krra^r&XloH2EnvNP5+h8QcPH7`*kxx=HjmfW>z{-^ypzJ52avtzihR|Jm$jqH5q@W zHi0g!&H=jFOo%W;dot)#z)(&GzCJZ&^+_;otrM`;Wc;LrA=$Ky?dIJ@0Qh|%uJ*N< ztrYNsWz2%bn`}o_nwDv=&JO0Ra041XjD+dapl>`d7 z8`Vq@-wyTnl-~Epg-VV#rbC|ApsiYb&Q6kXHsPuO8h+xB*0VHumFL1&<-Jt7K_}nT zLa?A)1`nW*I>t9_%|$Ce77~weH^=2bct!o6y*>%I*OxFu`{Lzij)LgJZF|SSy2J)^ zc)h86YBgjUXHG!p999)y zT2GNcVI~@!X5%;1Pk%+UBqxNyg+dkn_4y&-`u2xLRKMd{wx27CGCgJp2X>jHpSolD zoWszV3~gFYdDTA83n&P;r-R;Qa+azw1T9bi-))T?yIHNWoBgNxvrmrf!^QGrUtT~H z391|g1l9HBE!OgONBw~PR`@ligz{D?Z#oCqAvq=U3RQdUZ}x4bkCTG@SRhQOrPsK- z;F9_=_B*w2!D&bT2D)~oK#d`NMHmw$CX=aljIKrkfAFjP{mCiZWFy7Bb z<{Yvaw|Yttn$?s@s+MvP$qv2@C!Bn8)OuScWg4az+7ns&i$Foo)ZOxCL!uG|6W@f8s+8lq9~yS`svH41i*_~G-f^{ z+cd6|Liw)?&vhBBQ4YO7LuJY~qQ1dgfcj5CglO-}6W1M%9S*&*G8iL-PUQwr{J3KuBlg zRWGFb_;SRDN59C_jcL6seGSBg0(5W+Q$D6RO72t6@k#IivgK91)X!TuSb+COfoNux z66fu4HiZ$Ih~!?N`z2F|I_wNY6bL{T9M9smdq=4UELWD)9xmB34g=BZ4rM}`@;a`B zYb+geV45W?FZd+yCWWgZjBh?Xnv}Lvx{%{m4kJbe^8Wlsb=7h?-TUfaTPaS+2&dxn zw}E+f?CWV|IcS8DUHiUf#heY;48V>JsDKg+Ik*DNi^1pt}t9+`Vr`d;3CY+ zy58RHNDD9478laBdZvrN5u=~cn?87pjjg)H&wJAT)a`WkCs%nm9;8Xn`XJI_U+B~r zdoY&>0rI;_a|#|L`6M-t*n|fOXc}kYcQ1wkB2QQ&4ot4a@OevLT=UVqDbeB~7*+Wr z6b9+=pdcrLpS0U%IZ7sN3s^-a!|L+cJ3di>rnxtG3W8O3gd>qv-H+S7&o$&?>G6AOC>YUM)H^@L`D6nHDJn6#UF+gX|< zc)Q#vb|*>-skspM&&Ln|dFsUrZBc}1HBNy?z(dS=?12iBzk;PHJvcmO=4>Dt(W^Au z)mM;WW0G$*nw}-*&?3rL%^@sLn*S9U;QFvu`r$Wj^kxe*ymk~G9!M42`B;n^LRX&s z6d#C5EJ?5r@^in=8wHx2jt9RVV0uA<070vi=TVHUm=RFJv*8*Bb9C;{FR8nA<)p+N zWxZG^Z`>=w0i9dL|#AbAsm1rklYd-JVW4~Va*$HpFay|~QKe|%PbiwB*v|qkQ z5iN4w4oZ9VgINpcs~=70L*#x-5c^d>^Gd!xx*z}!`fMdEloXAA2r zXi@MUO5N_%-dVS39xEQt58tHE4@YP#df_@8cv^_F&h&C?fHAUHogLkkq)gSmrKMMj zX%ETKYGonR-5aIUd>|6fBo9t%*=6L*V|-mWctRYDwk<%x#8Ni>D>i31w9VjEYDFnc zx9>0@#T7|-!GW!h%tm}|Q_9On8-lxp5nk$NR&T;--OMvS;|Q@A+1}IJHOa#mlAfRk=Uim$9(l^)ImuvXXb-= zVX|JgYA&Ah;Jf@U;kb_>lj5{RyIb0`S}~|;HEW-O+q0Sh>9#st)ZK0J;xpjVno5>x zoK(;wM}$jfW?!Dq-K*h~u}?Jn6j&S#MVDQ(1`Jj|tBB&|OHT7?G6_2%=S*?qh*bxYmv2%r;P(Qc9C#!(9Z4#vWBp z1l3nd6a^_qXH?5_3OkyrGMqAJlfZ|}Tr|)uW@KyMQ4v#96>xGdf1sHBfNfqPCbLi& zLSaF%pBz3Zu;@c?w3#IIVIOakx5`*f}M)+0#H0jOyRw<)Ktdd zbPe?eeNGxeUG$R+_8P^O$M-G(ON8+ESfN^mtDCciGxah!x<|E)yT7#zr@`MCfC}`R zel`=0Q+HYCx+-FQ(Sm>*)rUGgR_49CAy%aqR3R=CM0{9&^|3)pZSKD%jk~AY^vFs{ zF!DW1pZoTX)Po5tQLDF-q?BK!o(%Q&cNc~tOkczN4~8&sMET%HZ4JIj^wCRTBUYWU zsjYn9Lo(OiCqAKx$~k?vLwrbxgQpSURbhh3=YjStyC;|PU;}l2rNh*yX3mzb@#j!= z)9*?sQ^)JqS>vBgnhwE3D-&i3QG11-Jc;oX$fjAsxz#^Uawu7Ys4=c*-9sBKi_1>Z z03;1tOu7J)$znmG=;ruvV`9rHx({UP=wAT>j-EPiJF`HvEM%OO*+iR6Vwzs@&5VmZ z3!fl8sd7`#RtmGQ(e*6D@XA;p zR@EH7#}BKFwO?-K5@xhBp77XoMX{AP?PU-uOjJ9FMAdx`1%rE1s;C9Y`e6>c4+UFNB9L=T ztlmVMsJjpG`z-#4^JY=jnD4R8-8gnXgAXfq*LFozmB03QdTIZ@R04AxPE*P=Xfz#a z@r%)9x_m~x>(;6f>G{F!Ke8^dk~3yO3@x)jU}9nN6R7s14VBcnjy2$$XOtE8^U!%D zuv}TVl}QH3?$zv@*kRvBfR(4%%r&PL+7w8r)^Ao0>abeXUz8~KDFmbT61KR%=o%*M z7SNoEKX1XJkA3&^L&i)u$e2?@n&dL_5i2WT*`el?(R`2J?Jc=vz46LuBYE$SCcn>+ zc(11Mh?ZG>e<7Ab<1>)K0_y_wsZ0q*h&FZ@v6|&v<5-i~k`W}daSNTZ#KAqau06~8 zye!Oae!U!!pP{&){I*lZvMBZkl#O|UFExKxgO(Yqc$XLb=g@l1R*YrRh>q+96dW;I zoYyj{&iRE?P?DsOQDD7y77xVyoibLzJmbJwUY-|FkNaIR`e;4(5mHeiEXx%gpVeU4 zNF~8%9y8R>OsbgXb{NSKDS58ZIeBW69zaK9N)!m-F^o&_B8Z=Ckj2Nd-o|nPvaM=b ze2sP3WRj>=*JzhNAFWLg4@iR0t$G`rj6fFpUxhG(Ia;W)9N&`bT%VO@RpbyU5l%KF z^!~7CUt;5?vs_KFZu%g8TY4r~G>-HBS_Cg!rt&-qR;~fUcPrPe+;twA5ev(Z3nr7$ zA>b+Uu9FIwXi4_ZZA+Adi7$dAQkn|>I8T34_lb%ZJ^cvGnLzrs^F>9+ie z6W?hiE}GFWZAN|_BxTI>$O7~*nV{K~=sX{?V$Z_M19Y-Hwcx-dDu`xTHVseV!r81Q zsa$*V9)o#Jp0A&hyqH|+yZ)nXhFR8|!+Bd-p6(tb+)h6}OGU-JlA(S_oxEwvp0pYx z+6caIQ=}MS8j|j$e8+FX>s2xDZ0Al+`mTGjo;<}zvt&|4`Ho8kUYe#{m8N&!zgl}f z*~2AB(3a@0TF1znep`pyg^QEJ?MTd&@H&F$)e!BfT~rcgF;H=3kcJX)@As%sOA+iv zMZ#hRi+KmzMyRJ#@zo8KHXgvXOgyDQ|`P%&YMxw>%3=)hN0fWIC8;({cb& z6V7&52igh_8LCYcdEh=+t-SiO>>%#D&po7B@=kQ1LxCBXq6AVTRe7@uhSI+c%CgPt zv~Qv^Fe8&o$qzwU{GIo+eV*|CGV+x9q4llLG!9TCUCN9C999?FTlXCsRuWzEppzNq zBoTsFnjX5YCUP=DR$jSAO48KjM3hv8(HNR`pPunwP}NOX8>=WjKJ&Ble=Fn`JVetN z%!`ik1vk~O=vTEyuTG;IM(2yA&?VnzmsB>GHdA`n`Va)%A69MNhM&(+KCWfTj1sYxkE#Yt)7CVqQe%N80x#H6zvW~DRi{F4##GS| z_Z#g?Ijrw=2-7*ebgAQrja83{x~iUj+U}XQ>*aIlu~`Mo2U#f8*{uL zJ%+hh7yq7+Z`51p?o(lA)W6YCRYe!)PEv#izd5i8F4YDVOiP+)`+q(Og zq2%i5*z#w{IX+*v`R6zm8C=#{=*KT18QeXq93v(P;}HQ$@26k{_V zN+&wu5ciAZ5*m$r&xRgW0OtkrRlS3TVjOZ8Z)e>29GAIr#|Fz>%_SRgzi-ppkXAUN zD))N};)wG-Ct>4j(nnHRwHTkj`M{2qvK(QyYHz^N@Z;cYQmb#}wI4Iegk+2rAKv6N zn02QjEn$RTlbvX$wEBwt`bM?~WaaPy)0*P>ep%WEa~o@gM5x~W0MRG6|oH8At>>mi`|Sm-q=(PEUT$JJpR z-SH*lh6lH}KwgO~xq0u4#CytFbC0x0v(zi2SP4R!N`%8nN<==c=>p2BBB`v7tWMDe^P*b6I6-jT{O8bT zKN$D~b*$LPKg3Sn?QJKRr<*DJUZw128+I}Yw{RXkRA`4NOvdlX8b zMyInbKcI6Tjk3r!Ipph$rFaa;K*c98M8o;X+KOk%r?fG_5IQ}~U*z9dnp1lF^CNL) z?ufI7)A(s~2pX->mM-HfORwmF;!sCPlfdZ6IGR25&@(P_$?KekGS=fMyDuaZ8v*vC zy!qBjwadHA+Z?SI+^e6+jh05qlFt;n*0_QGp2CiuT_c%54SfN|$<5p-u0||?v5;l3 z?XaCnyyRf4EfemeV~$Mg6NR_s6!T`We)JqzlmCC1PItJgEe%VE<=E=xu_9itxY^X- ztcUukT~OsQ`IaR2EPd=F-yAPG@xgJYVg%2Beo9UCG?fY>T5J&I+lIqcOpk6Gpw%%5pT0-D>Zf|gShw^Q zT3hY`r1B)D3k+p$q=UE8fj@dN{Mc^4m1M>ou7E->$`Ob7lbT!#GkaS6Oa+7~@q6+a zDzPE*UJ#jWe7(hWKIRiY-2C@AhEJG7>dbXewHiiQmEGYxp`Qgu`*?jHWfDRSwJd9( zS@CNz&qAUG_+s|^VXAcM+K+H{c$MRPNRcx)Zb^t}z~H8iuD<`C|BXPK4*q>T9J?|U z9^gt7N`t_d?tV5vm1gQZq_e^XO?k!AEvxCT^R_;rCneFTbqe0cX|{ph>z3koPUu;Z z+fjotIdy85dx3DB*5PBI(8Uj_)*pLB`RN!* z5~veZ7*(P4{hOdQ%*li)P^i>ayAc*iyJ-rL;ENcAKNU7xAsI*gkDG*L0q6$hZ|AVk zuTkWzl`YJn_g4^`$fJH*Am;Yp}7#-n#CC3!%Jk`#JiQ)RgZ30MjeWWP(te_&>;|e`qUn4aZr*#>y2!&d3UcJ{e~Mk zi+vg_XxX{_mRKM2h4$P-P6^Htw)(ppx}VE-Hy{`<>HB}BQVfF(#4whatbE(VsoKH! z!oZ`DuoQOF0EsUqx}h(SNc?zvby#yAg6x5vWl!BxVlF3C!pZQAPBe1k~mW0Pc{TJY?P}3;iK2klg#7m}XUZF!Y zmsd6nB^6@#SEflO@jGRsZARzFj+4{HDS0=fTWRuk#4TG!Y)i20OO=vgA|s>___>6%IC3bTg$fT*Rs#!RLro z$WG&H0ecxT-c}>n8U`MYVH%(=qzRRT3cpD~7I_Q)*X+;0mTd>Eww%^N{8{jm2!qz;Y( z*hhJ?_mh6pNsGt@A@d?JS;STvkM;baPKe^!zH(PWf(;$l_id*#AMQC_c>B7$=xf#p z6DkG&NRvvJEQnb9b7*3r54#eNDj?$%-dln?I`0c7SqQjB zMUQ_PX4ea*F+fHq#(PV;+|Nh2&BwnzE`W!5B)&0iSb52R1I|yU#Fq5wc2b4X0|cg^ z+?rL{i0t+o%|YzsgM;TgXki#|dWo!z3!gMGY_Y3vSj|TA!7vuLJ-vWznzUAlQ}3&{ z#&^HP3p2$zWvWics_44Ju$CeCliN`E7l!dHHEBQB*35AznYJ#L)7_4EMIpTB0+Kcr z#-XLM3~T=38VtB#^BkSd)awf`+EiO#$GvM#Jf+Ex*p(q%UZ}OF+U(j+TYoSU2!dYT z2S)r$PAPH|zE@VYA>M+h-|VQ(Tsf#m2|0Y$odci}H_q`X`HiATJgLzGZ?E#;OkBn< z!+`$X?Ng<=1+$FhLo3t%up=zgGNp8~wd=?0HsQ>c{7!;Xr`Ged)3s`S>=o4@2*L*S7-LM(J z9%YTo#*u=E565mR=M)|SI^9+jhTPK@W#uBzZZJ9@4tdBULKO3L zl7Mi4)y0UM{HMcsU!HMWwqXmLw6}g`it!sIu`HQLSfvpt1ut5>$AMMNA^){a+ku-1 zjzM1&X#(2ndkbOrhs!x>udkXWbNmxT8MrHIUQ~G|jjT^zPoQU<$W=a_gYRo9>SBw% zf95iSpjgpzwP+dmJYRYpe$G*Sx^RS>D@td%?&8Ybe@+inYg4`>Od5-!=6ukfiHD)IMkVQm7dIjryeYUSCu3-I^~Izt z>VZ$gzpxI(Xa$F699hTp8xh`I7{2nKIr?yGT;Gq)6m#U_DXazo!tph9-&>f?$@IZn zEhZkxb1!pP?B#gE8%3I>$0i8Ka2Jz3ia+4l}i~`f^q$p;5+w z&*1wjHbJ999*h+V{HmFz_iy>aHC`~fAjrM7928tEy;?Iq7Tj+q^m?DDi2q6 zZ6jDZHO<)r*l6|(NiRO>InEFT<{`YGbXDks_Y9>XaXiIGePzcQ9r~Kp3aLV)tpkPB zAKt2UR=qT%OChjt`+u-&#>rrriaRhjaPvPgHPnbhjMZ{Af{a_TS@D3qlMx$Fdx11rB#UMfidNfC%4`CRK_Dm(7Twj%z5SWiAc|y{RJ7?w3nboKt6oC+yOVd zJ0XJ3wpoS;=+?E<#!9GlN0MbQU3^eHQ^)7Kfo%u!>q?u9yO!6ia!7EFQ#*42{O0+K z)&!%xu8pt%1JVFPK)k(wJ z3LMnQYqFZ2PnOu&^e;H_C-l`{yq2`KJO6>>@n?5s(hH8s_cB$>AP6$ruez2);3+vE zAeNbLI#j%a>gfI3)27u2W(w9cWNq8?Y|4iMS<=UUBUDt@7AgONTpGuOFQ#91;QIeu zOhP>e<#tal-v`SBn|wr3tlbuPyW!W70&E_7znb2WLM3Y8!i1NOwKq8L2BzXDkEgs6 zjeea33X_=*C*rkUmfGZ&+j||u0#@%=j5tNMluMcMzrbJra||NlaKI4mcZ#t8d|MLj z56%Z(q}{^--y62mn}&Ab4HS8X34aYJdOpY5+yAPxAsr*ZLqk2Q=d?`3z%>N#-^>aN z1BYBh$WJ&wAiIIkDtJy%Nr`inlNGzfb3j%z_GITYqT$T+Vj`AOq!TYWp)UE!7J2g%Ki-@{!C4u|@`L^g9tRP{)yCysD z${LWs`;AJ5?@Lp-ylLJRJbqTU;%X_t8twP`E-o+FcCw=*DF>?(Nhna~2=-@2|4xJM z2HTXV-{4KolcwOigNQ`JvSXy0=2HY|z?nXUaQa#e*97*&e6tCQH~f*%<|D`QeI{?j zIUp`HO@X$gemw*V_cN7Q9Ukxp%3H2i_z$YbgrNPeBN;!)pKid643EIW#ng{Ncf!6+ zo4=sJZdhQ){Y{9`_CKhJR(R%qXsBVZ$#BEFuHq3|eG~q*8H13reZA`CrD^`-TQ32N zV*P)k&RF26GyR{34gU{y=JPJ(391fr^)MUM|Am4%Mh4s zznqcRk+6V$Z6J{@@}HxoA@qT%6G1qlh-STq#na9i-ccN`KpTS3=Kq31+kta!-JT4k z@%`s=ljF6Q{rWn@L`dPh=40E9C++_LTS>moH5btTCaC$mhok@AGYcp-{^#(z#Mb(R zAMNT7s)jnDfs_J;B5lg8@lWLe;TL^`~zg#-D==JP@pZ@c3~O8d?Y%YQ`Q;Iy+Q=n?WZ5=^C$md z4pic>wZ#nCb+NyJ1_q*1I8zBc-fTdFY17f*U^M50%Dzsfx~1pAZM(rC+lzQRQfp^J zEI6dr^+s^kQ5U?GJgktlTBAM={S#O(2kxA5Lh~QGnZWa(q3~|G{z0CwRQ3&K>ODK{ zz1Gk;eA?l_xvM4nG21D5?r-qDatCd{A73jnAJxfq*Bu`lX z@AV~m4!@wE?I?$Db)ZsW!sMO?oDtax$WM!ZI|Z9FdK&=22i{{0-a%NaAI_`l$``sU zJh-M?5m{-wsx8Ozy6K|qTyZ-lkKo%YP?pQfANZ%0M1{qIy+~3-Bpm(*uS#FEoL&j| zeO9rlkbi*XPZro(Qp6-jyhYxya==pn4vcGd^AHQE;8WSlRtN zybp@N_Yc9!0lzv&jQPOS%(c@h%8)orSTy|Vxq%522DoxCf*T81y58KRE$Dcu>o6f{ z1Y6V*F@K~$OiENOvoy!7w39PxYdB*Mz7clbJUhITf8{hn*}M4@3DsfUqDAq}RRsSL8vF(Zlh;xIKLyAc zoc(xKLD`U)hDKTXigzo~IBWT!umDd;`@?m7GQ7d4(PJ7SWDaknW}tug zkD7))@bHrR_#Cc(D)x$s1KJ)h%inv_b~c4Vck?r_?MHddG?upvClvBu;1C{y(tht} z{JuB))2Lk^7U z1pzqYcHF`pFlrQPB|Ndic_KR24R7zy657JLnYz~p8Oq64 zZfENPp5h3wK9A>`)Uj#dw4JB=at^x`Daz-yS3nS87u+Slja%R!)FP||Ltz>M8#lGw zxrd=s+p-iN4p*(%$qF^?5H*F#J_D=-eOJJm;lP4v3KNBHe@7@>ZFEJ;GAA`KHMv|Z zn03Ladna%saDTro90|^_i|jq7FD`k09u*+D2n(wD6PSPM6)^YI|23%5d$IN#X2BwE zmK^8w?4k@8OcKKDZFx3f{?;dkxnq{Yi;Sx94G*?$6D(_k8h-Y{TgDP-oBwz=wl9>q z#N4nMEw(MoSSbOQDTtSQzb%i2+H>g6gdzxC6P+X3-9kPiN*LJl$@RO?U>df^Xh^E5 zIgdPhkN1*y7(o&VziZbgtKZE`3=<7SK^cnl)KG*qGm$lP(dOZ{Wv{L=-^~={Wa#P`H#x9S-K-7q!7k_*r@(7LPO#Xvk{= zvD@fH=Gq|#*C7lT?u`HN!D2&!cQaSBdAiq2v1RvxSUC^@>}6|(&vvB$0*zG7(@*ejR+*kz|%m z95Gkhv=PDo`C-A^%fhS7V{uZ5F6dHu3O{9=@Ay5x!wxQJx6FQ#NX?A$gGAt{MYd(` z8LYhJQkcQHAEX-5>UAj)}f*G$Wehy~ajHjkjUW5U15 z<^$Q3o0#<)kzPxMp;qh>o{qnZ-S%1F&z5K8j zA9TF&1No1y36$EkMWqP8SF?8-n`KjFBKBC{scY!rLypRC9yT%j8AJ|m_m>*%8F7mq zUvhvT_yslWzS&*##GO9ADI|dywne4BiRcpheWSDCi~D|Q&&V$GJr0HsZ4Ho%wntJ3 zEiF~mB!G@q$cfbIMUu4=^1}R9#!$W32a%sC;9ActBbBws||Q?dq zv1udc-!4?m?*&6*>3r@ge|2OF9m?$$tN`cORvUWwMl~y|=lzJ;P5nh(omy&QQ_^ZF z7Z!;Rp?+~A+^Yg4F^g~vm60JNuO~Rd&@2(vH3)j0ANYpdY!nkxP)c_By%*67i7pXH@sPpG&GBmhFppi&S&lKkE-JM(4kRz zKSBIoFL4YaRLx(@$QsHo^xP1afszcg}hbqJ-m0*3#-=O2pC98?lu_vj#oYgpb|^*wwTUv&o^HS z!R%0H)#pSehDLH@@I9agFd<>i>hH?R#tfV??5~Z>b>&d~JRmoW0^^)3HS$VUTREx^k!{NtZS`Dc%BD_m8Gj&paOTpRA08;Cq+luPG@U$dy zSYo_5UR|9}oitKUVAdP{eLwd5CdD|z?fM94wU}5jiqaV_FZ~?id4JkRO6niJ2ggS5 z*e?d=XLv5o6JJ8}YV1anIftw&dk7}V0ATA4aU8)f@O$RAGq67$kw1c^3s6AiAKD%t zX*cIpPi*Dk06r-Z7guIR$*7jiN^`>k%-q@UsT-LclBSfsT{Ja_1}xUuP?k2mUueGQ z-NL}x2PTuV8@78FjL>Gdf1cI0WXisq$Qupbn-U765ahGU2Xf(B_ePMDT3%hw83gv# zt-cJJX~JLjBPmZ~vgV*^b3f@oHC=X`3oin}tdgT-73jw{5wRcAz(%W{@+ zDIR3-<)|CwZ{@|6kP27-cr%yRu+8%!Y$S%<(R9ix5&x4Wwf5Nc5BU@>DW40I1U;@< zMgyv)Eh8@Yt@x6bG)^*|u{xMIyzhZ)kxCj*s-?UIR#2~tw zVhF%*-kSD*r#4d6`wfRuV`9TW*}bE~*!%dy8QeDMb_hoNkd;)sUSc?FI~aLpDnf$} zx6ET}G|duL>si_Dw}xw&v-naJmtb~{Ny^7Fu8+cP*x_i2chS1d&QQC~n!I%TF7s|_ zOE?mFvU;)U{F8|Ow%lK@KqZ6`w0sUBgk0B(I<<@Q$GhXXUvKWGaY0hfCBnHlr;+*7 z_97O^GnQ%6Lwe>Y|E^hoO%V@V_ddP@zPvWn}s3^j6jQUi0XWQEGHEX!$%KXNBS zHyIv1a_>4?awdhG(IVd)b^40{KHP8Iu;8kH#P@1*@1u_;={YQ3+H`%t4byHfheD4d zMKd1U&fpyw!j)ZyWcA?TyF>JmRO0_g9j5*eG;L!>uZMkuaF2IiI2=gBIFs@96QXUT z>TfSqv&md{er&-eR6Yci6CXj-Si~NY`ZOU2l?)}A*%cu9ELCqRAPo01b%<8X)-Z#z z{n8Pe%LYs=;B0FO*=(4ns#^foEf2%2F=3v#@?H$Q?~UAX*1{ouvX9sK2zOw09i-OM z>^^BT3AKt8eFSZ;GL}N}I?W(fL5lr0Ze=T&HvNP)2xC%|pIxIcv=L?wLmEs_sSt0TvoZWr&d@Js=qmjyadw{$W2Mi?go+o8HX;Z3fvqDy1VaXscBRSgXEieC~_N zwMJS7K}DMoN+v!!LT=enW9hAF=Uo1|p`1>jD8} zdr`vgbs$5g{t{>+nNTD&f9_O|v`F_6&N&Gmp^;Q|ieoX8-w)R~Pj}FBXyFG$TpfIW z=$nE5g@B&xo8-KH$H^B!0j%;&xG@o=%gFL@OwzL(1#`ZDNeX0f@C!*C~@~pyaXV;Un z^`21sWB@@aMhyt&kIb43jLsFLf%r(H8VcNfCOiLT0q{Wm3rZ=8F0U(H^0K)|x(bxD z??-qu6onryDq2Ql(y9;RH1vZna})SsaxeEoE1{#lZ5O%I5+48Ka1y&J4is^mWMjqcIBk)p_zZTu@Q5Fld0N+=c0RV3%MJG1(+)xw zUNEr~@UYYRVI>qj^Uhc;{cdv@bP4rcR?X6a08aA@b^`#Lpbl|aPpcwIb@q)@`AUa9bfax%-oWo zbh4)T{%iJ6=K9W%4vcB6g#*(S#z-4uA(7 zM;_IQIn0$h;9Dsi=4Ww&XzuLy(Pv?HO5bs~hN{u`B-tb*wX`GRh8_CBXIG$2rGozHRj4-_8Ru?krJ)yVN#oBqghR3EMvd@JjeZ6 z6MlVOe$VS=r|`6QR`EL4yiOyPFc&qwdMJCXXnSF zxiNV66Clf$pM0^g)i{Jvx1P0G@$#+`X6Oj3EvL7-Unp|aEqx8G#NiK<*D=-xTM+{{ zp8oe4^%nX03>U4u*|IYTHgR9%mzg#*MRAp@ovd7!k(KWp=$&gYvHr3~BCtScz=5Y) z614f|yWTAa95cVM6z=lg>H$kzy5v{?eLbSZe()A?4yM{gK|m@pXx}2?hFCWN6Y~NV z)@Hm~c*Xxahf%s=EmHgEtJ1CJ^HFwGa)TU?V4>sD9f(ghZ3%qOzIdXrhfiMdK*QhvANI0|hKn{v{R8p;ID$xKGE91COwDZS{vX3cK>7;%jqUGB{~vpA z0Txx;t_{;5h+xnPD2jwIdGk2!euuf^;d}h;)~Lv~;(0#}G3xd~5kU z&l?>2?!DiC@Bcr(3DCK?7WaD;*c=c`%A%#R{l?xDsDza-r0%$> z2H=yXz!A`Vt)Q+hWpp#tR`qsVqaSYko9p-EfU2-jzQ-sB=J?9DO~9byUELuV3BzX zI^*fEKWQfq4rJMQ7%jsYK5njM1y$}|DFEH6N^NbYT2k!aDpGh!z_w#9}r}q z)l9dhS)z$}2qnoa9p7)xo8z(3dhU!l+GdGPUCl&7)@9S~>sg^hl^6i)yhL;J(eBsl zed5@zaN@lob^VYv=V>>y{cm((Y@(+#cjB-M&Lt{2%)ire+RX}=Ywax>hY6ShvYLz2 zWot6a_RMFujmGEgP@-eMlqmoN6sZI+N&y>SCWRmoBm#&j=ZWq|$csS?)Q3k_VAAt-A*GsPawx$-IJcrdBT)Tg&7pB*s2&qnRhG(8^1K(Se`-4u5P zfG4^umy_1jG%tvGE+epE$MYoo2LLhYwXT>8C|Z&ZNx8u&m;UJdbiZ$8@{&K#sj3fv zqPhSEM1Cdh6ULnTL&tBo17kRQ9~IAuthr(BFZc3zY?i89AFjWbpr*hO2OjDl9-EBlx;W*^ z*`LgupUo^S#oPAqx}=vXQN}7ofyOLLO$3m)RVocgctG~b<8w<$}mH5o`P*L~OY!gXfhX_X+;+sv~$k7;Y>3ad>0s=25L zui}ktIMxy?a0+lQ6f=@|DbEx69E(0s4J`1jyO(l$;$68_wQfX&UpC{7)abZT4^uwN zt521a}ym&=6oc2pY8~xSwgj#kKUy`|I#&jC1$3#za%3^2G*~gAMXJ z3!*#&od`0xMjZ#_n$stwvLDBFbT;7mSLfc_sZ@k_TAx`@f=t=`oxIS#NDX| zX+4lp`v{5c5p8UT)SvdxluG#wKiC#H9Bl@48Sm1^0|u+SBJn(VW_PKKe!Gg4*_@3| zUC8qPC`~@=e&M{3-J32%rQ_BF$Tx~*cdHZ+G!>V3tjZt8NkfetDLf}g{#$HO1>!CKLG98St5V9Ui2hoIBRw!sOLe@mxpuWTO1DwN7t+XwyBJyhz4Ev;l3kQ0MI?aSl`|4nC~idwROxD_;B% z9_C$3yZz>V((6NyjiNR%WZ3n5^>ti;xjLCpaS#i7pSn5#q9TA+j*%EOsH_kRrWPrp z65+HFLafjg&j&HLu1y6c{8)?zbEEP4iuriJgqX<-$z-X40>v3MnQGJ0W5ztTYrDU` zxy~7w)FqG~pzpc+O3{l~CLNHt=X7WFQb)=0gj+rJX1z&E1=U;jxrXsoHF@>`i04tx zkbQ#~z!k6qHJ_1_jTq6h58^El_t+)icAQt=rMRH6*zreiW`1BI`OL|K>7jrF#g=vq zfHvG1&ejuxn!!r)w1HW;QZuz(@0D#lZ8#oV%!_=q_l?f&D7#yn zpP8?U)n)Rz1gt7+#H$XuRW0lzk&voAK1dh4@VPkAVce=7e4gr%tOR>F|C+AJc$rE+ zJ5*Ix2;mdnGu4CBYawXXlW_AsvS~TNxkY94<}9z*YQ>?5&e9gplpevu_#3gCV;4E0 zD^|=^n{!p2{6!Fyg37~ft8%#uG=5B48qxQ;wPfV9oJZjXA|Oq}S0p;BOZ_<3O|gyu zK!GAoHi~t5jkq*1-8?gs3_O)eig(RYt1u&T^+)QX zUYYt^nbx$f2lZ2r8boVzySstL6lD49es%T`e)U1U3~lSR5C56iC5oO5QCD!20Nr zy}{fS!S7yKW7%=oS`pDEYu*Dg@DC&E#qGL%XX&=Q-?Wbm)%v`$lR+P@C4fx_#aTSE zI0Dlf*{Es5O0#tLngPXTd@wIkYu%fe+|R;5a}F*AFWr#eS}0@|2(TX3b zO5?Ei5V~T`g~^j&p;_GylgqFj^ z{=@9T=s44mH|`fu?zKx?NihO+`EMG+giz!?pJn4=R+u?O6t=((p|7YrF>7ZnY3XJS|k_PmJX?jgi#A%#7A?-EoPU+MIHl`X6a_G&KUxiiHpv&SKvrifX5{? zPA>id)Yf`U&?)x0H=y*>4lVY7&=b)-yETI|X#`tu9=Y}ONOz{rE7jq9ts!P}BLLe- zMqk)!*!qn$`d_-90<}2GT36^C(eq%b3ghx~1MrovmjN+otD;E57wW|}yG`mfY;Ejv zD_GZZ$yKX}i1#G{q=s#+5CB%breou{@^fdKh;rXH;o^XSATNgNn}vs%xL0JY)cX05 zN|U4PQxC~lv_81qJkzz?JWVIeG22p(CxpIIc7%WkqjWW8`lyJ}*xq_WMq)p7AuU3_ zV=VJ~ZE|@trFC8!#T=B!b>$tDYBDk0`~1{HJ{iV$y}U9jy^cK`YE`e0Ea-ML;v`Ew zA&AvoO+7CuQ5yzPx_CVvKaN0}0 z_L57|hI6>FBv`6X`7}F*3i;(f30J)I;46IgLT1^-Oas?>seGMDt8S->z&F|EF|4p= zuVWUtncj{M9{9Z+hT=NByBr6Iz|CNJ%y=0d(icPAa)4S7ut%Tp7$( z<~scOQ2*{zd|VeBcj6Cf0fbbfrHT`e(FaQeEwz@(-NL3gJsvm)T@{)C{&9 zedf%Oneu8!Dl^^WeR#cm15mda>2J?w2+I}ZP=~{dPnhlz+nD(U+Uyl`p6@4xQ)lqq zXCWCx0nl!5Yr)p@aLmjYSzWi$sn1y$L0whpjM}SOFW9eM;=BMB=tuytAPLd=WXRl* z>GO@5%;8JL*gQ(;V3S}XynC-e0RS(gY@hXch;IClWX5Nz8k^_Kkej$_PHL{js9ygH zV-BTp8aoV|D1-AXdLAN&MrAZTi%Wznd>;5L8Eer_ma;?_78KE}4CHO*rOcLXk-3~N z68P(T!G{#9^N=7G4IO7_P-Dkb_X>S6vKAlg z*$q4CW_WR?uo{od+$U2RF2|u1ErK*Zh+Q^`)>VUK>M;857@7LynVMA3;Z0uqXKDk3h-XzHpgCD-V(y@|wh&%s zv~xzJJ$xNEk071(IfTM#p_^=W`0}&TPBL;i{$8UsF73gPPfuw*<6&iQ#+L~EqdV1C z1tv9u-HH-~9QgEUCu>!D;fbX0l!&LXm51aB=0TNgTbU{>~kc@`1V(F0&QAZ7ajb z!gQNhFJf$VYckU48&7U~p53|chZzZ&AWxLXKxNUBf9C9xWVFOdTm4y9k*uQUqxAq> z;OM2}WiB;t3yp;hK<{GaSY(TaBTsy%@?MBnBJ!nZbrudWJEha#tCq-#XduHo^5{zo zj+9+*;QJ$s+pMnPL0X)YnaG7IK5QRf5oL6o6gI%4c0zXV$SB$2pYp;*r<2^eV z*#B~T1MdJ&us-3D+pUxBeBsW+`AdaI`pO6U+?858Tg zC5(DrvOV7tJeARvZaRC?CQHEfA$KMYrwRV}5w^~xYh=eAO~lbQjZHGIgQ>l;)bKhT zv0l)61}=J!R3`xDzRaGG@zXuZr^8+W*BuyeKffGz-&xSleatCuMTzG^^k|aTG9b%a zeebNIOp7VgQIyncqM0U4@Mv}5zJnybHzLVq2DJEeNH&5pXlx)XS4?0IiJkPYjT0qN zliC;0Pmgz7J};I?dAyE=W+)B9x2E`)k4v+^*QV~?KupQ5YeNunNiv_#)$i5s{y6MK zh`$M4uP+%Y9Z@=0NV%{ip%N&}nHX@^Mx8E=WmC0EZ@kYGFUK=ASYqCHXIpbD*3EQl zvQjY~L}Q~LmcZ@5tP^%zTgJyJ z=1jpXqZ7L@A6ahG^&%KU_Ilm;l65!iS9{2RC z?QJHki@V<}ea`_Hdy;af`MiZBM9$2p2cS(U<7V7nR-?N>qDZanBMPw4*deZB zR6T0FzH79|ICZniY@@lm>%1+5il^t>H^?hg&uAds+{{%UnzQM3+bb8>-lVZ|=#qLh zAEI}wm6n?-^5$|EKV`f&IDK}5zq%62Ssqc$SnaaC6>y8CbI4ZC%->2FCAe24vTB|H zt)Pgr&@515wFmE` zinZ!aIzX0@Sh!!_xae8^!82Y4!eR9Fb@-8Pmgte(i}5ZT7q9#JYRnQyv`$!$=CtR2 zH}8@=J5234B*uB9jRnr}?BY@a9Pb@vx_f~M`O|)(Sujz2O0V>))T9uibYr62RuMT& zZ;;qE!T0Rjy98r^jR5^UC+z`^Oe;nUVJ=d|pRXI$Yx6 zQlZruQI+Rgj$6V}NUEbw;B#PsAMvc4q#C!reN(FHk*?IibVzlLck^h}I4o~zknY0z zof5cychHnhsO_cT-O`q=<_{*U1{BH-Oa_P!m8IW@A7#QRZv6xC{4# zfP{6{^uFbiHE%G@B+CuFBmLIsZA5glIy$|X%7$ow5yl*pL}IWIA+-2GnWNH+nGA1) z06Q{T&`pRe?y8M40X9_b>4paWk4lFJOD3^JiBzs)C!eQAOS@b`PS@uT-@|x=_PDEU z)4o;51ad5rOUNM|S#4r_C60oumZJ!FY12Pp%$X&*nYyB!VhOhj!jRSLH%q(XNKj1# zkil=dGtYLBL(2fKs}L=|01~pU0c}>bzwJbcPtRxoker#Jl{`MDwHpK&k4}C>U>_CA z39CX@_WcMgAgs*l^`(UV%rQBEm^PF6tyN_8tLY(&51P zY-?AemPWRR2Xk~rs%?bV{Ln!(>IZz_@^0Qdf0akal5MZ0-m-hG#*n~QiwB%`k#TKf z=59@w?x*p2qE43QW{m6e4_TJWC6#cEn5pg%Z<+Q+8$m1h3!90A9+@U{Gfyr(2`e4o zu0U>8>+%$(qkNVDojk%-M#p?{)kYow4XM@7Rx!PITgaMyx|p4w$OYR|BYn}Z@d+ZI zHB>#_;T+R*GaiusqMMD#htcX7%VsRU8v@Af2k2?|@TykTdib{0S;wc%aSP1|VOK^^ zlFeBJPKRP?eS+ial_>-y$dn;F8l+NlLdN(^oj<25(0+%q$f~Bg8yryQ z5Pc%o@WpA5?QVqxK)vxT?*o=sc^{bD7Z_T=B_+(o zYYNCj=`yoh7v!fQ2)FZm+C#TY^XUD&TW$(-e$youmch2JJ4YdFs_8L@S&w5%Ba-h3 z`}XDui&i3r@^oB60nMHkqR;t$s?O%*cp)s4o5f;Ej7;~&EuI<7D?(wFtu7O=a+AAbBgq{Wo3$Q!JO6>}M%UOy_Eix^RR z)TWxuXrO~y4!y-66_Ik+>;8aE+L=Hld|2B!${zNO3^MFOJK2ph;sypim=h>K*4z+6 z3FP$dDIm|^^k*Ey2K1t`aSgqx;HnYPq%G*AZIz#T(FFYQr3gesjN{7yR#i&$IbIan zVy8{vvf>qZ_nUg&-xk9j=+F%>ZaTwdc7HvWdEQsy#1c_C)X6I@RFP+;wR(@2c`})| z5La<)+P?Ega|}YT9&yFL8lW(zowc$^(je+3#8D|qyaHEvJcCOeRq-KZc`;g_715v8 zEk81Ycd@S)@qxaYw2E+fhCj%t>raDraITnai<7^8oZ!%N>Bb=ZXkW-`xWJU^XnSU6 z^BPM8x+>2?iCJ%w@5?vR(Vx&JvNMw?;e{{sIT$FMj<<=@H`I%-k-U@Z^mxFNs9gl9 zNdTCbBXyjjj(*FLat^V8^;10)Z0pGf9^FqIXYlMs6qYl`O4|dkq#wv}eh)^QB6lQW zIt%Q_HE%7dy_4l= z#^=1m5a$d54<27TGG80a_U*Sf_eAs+4FvV1J1qC~)$vJmOO9;pgU>Y*xC?eyj<3_p zO0M6L%=prN^rdC+ilt)qjD!$RRcj_07NRa^U^H^S_I6MwNfPOx_3Paq{2A2J_w+w! zA#IVH*42EE`^osYuoH?gE9p~w=!?<)sH;uDiQl9oe@_BF4DW>GHCojp(mB82gGLV}S>N>7?NA|k$ z5~L3L^IDHjN*Jkd3cL|a+Vi7Nb%N{K*cL4U#Bx-DFXx@wWrW-hR(3>kQNzy!j-{!t zJ6%vHgmm9!153|^(`cX4p;NJOg3pFZ!V*7Od7mR^0@tD3!9|d5E*9-FE-39YH9fb* zEZt8;0LJ+KoB&qNYc7|omM=R}pc_JHM`EcLwF&L5ED}*RRt}AE8qpoGu3U^V1#`HE znV1Pu@@tRfRjuWi!iUs}q7jodZu_GeYXc)VZ$k*5#Dfp+33(>JTi3#e`&^?~buBkG z4tJ>g9!`aA#pdk+DuW`veq==t*=_4>>^%8gVxY=tJz>eYtUwb0PoS`<#A<}~Kmn#B5_#zRx~O#x{uSda51 zdsHIw*Bc7z5SGSfyOiwXf?-Zf-B9o zC54R*D@Uhc=_?Ny@Z^}~a{QIFj^3yN(F@iUw7LM?s3IuE#tKJQP1kxV9aL~hNFycCZ<;DzpV#_2%-o-bvZMT}68kf(9Px&_~hoMc&P{ zHBnwj!S8H6I8)R{ZN*x%)3o!-xAYQebncA#3v9uIwV}?Ro&rO)9xkBGeQI>>>i+TW zLU)=}L|2l>mgdLkj;YD-b&<@?-+pD86891iMj3XIGLE6rK1y8#>{fB~={je_KT6=& zWYYHHr5Dnv~63WvN~Fn$_pP6;41x^{nvkM?Su_#--h6(cfU1NlD-dI#WCu@ z|F^bEzMy;4P72%I-x?bAgXU$4_XKYL&ZO%9y6#XN8A#xD=mLa?^|agat^F~x6~Shj>~eLGuF8Ek1iWd*5v_QoT!@3a0W!*<&Gurwf}*$ADfohWHR* z;raua3dsqm`*Ly50PU&7X*>OBf3tk1wG2{!x@X##B38tw_Ujt`C1%uSff{gEZqWlckHVOBZW{4LiVBQA6)^>V+;pl&m7aCk>JItJ7@pm(4|+6VOcgr4;xqq(M6rn3#cb6r;0 zEfMJ-mU-O|%m;GS3xC{}1#X?LisuVPaG;Gm%>jg*aUuo1?T=|6F*fo2avWBHfgaG! zlEX7E+XM5wYvd~hS$}D#FRE&-v)^gN4P=x#-Dg;I)AQVIG5!8g#QSJ&+3Rqu?a|?= zF)uvlX@hnT0JlP5_lc<&46uJWA7uf>5X)t~gN<{U+yIA&dP6-{spmte)8q?gGF`{_ z6dcbat+C<&(&B~G(1ocdxh+u)WGiPTOgYIe6817#pu1ztX=+_uZ204a7?13+9Kv@WTX%hu%BBS1-tLmIl6u$qdWWl8*Urhf)zX_I)#XAC)BViaP% z5L~w`NjqvpZr9T+p=_qAoD{vT<3SjO5`T3+aj}D1Z{y|2q2ne0XehDXz&bEvGmJ`p zd9m4ZKo_3ZV<+$75#!w_PFg-R`1RdE0vezDM=y`)`*4Hie?S*=Z`U3rfs1y{C1ml| zU*2e1q(|;iTdek{|BOX?G+1bxm@nQob(PESmyYuv#2lkB+#RhGvb61NIj z7ds*KT+*0(Q!X>HWv~g#^iA{OJk3!PFPtW)Q-Fi7- zM{y!#q-_15jmC$oJD!K=OeZnQ0@9fv;88YaUEG~wO6gay`_p$#-^UBIR{mU=C6Yum z~F_3e(uKt}9!`G<{Naoo&n%0~fSpAEUL>l9CJioP2y>twC&I#?aJpYux# zbu@n2GorE z6&OwZC%A4mzNO%N3COPu>NXs>Uo59tfN1|)*V0m=%Xf%)NV~H}pi~LY%|y|0t9h}L zaqz8iFk->nhJAbx{jeId1!vQgwO4msGM9x?Ntm4C^|bE6;VyVdiWO)DffZ-6-8vtY zo^aJ>VB*K|N|N?x0}*SDLI9V4v}LMbH|MpPtk9tPwff4!L0{C)7<}B&lN5qYO!B0J zvz*gII-})tae(r~c9z!o*Nst%?xI62{TkQjS|f&u z{h1Z)$DM$x<#b3Mx0aOQ50`bCN0b(4IPwaQqG_$`d-6jt9p8UlM3|!@AFYo1VOr!5jgrFdzNFy~zY2nYjzyUd zNNFvds(Ug~Kd?9=efacg4?!o$&D6sgpL4ICK5hbjin~Kq_D}Ddy{}G$A;J>8Zp_Lu zqq@vp5*~|az>NpK{J5Dq=(}_2I{lBEqUbB2P3*D?7(Y6p4A7IE7MVeyO|NBc!q|zl z8tv&;^|t)fW-z4gHNrW`edT?j`BIhDdeo}|k@2qm5@XO}gxAYVK-LbqKKFtuFzSSQ zrNT?&SAGk$-(#@8UA3X};bwuxScdX0#f;hzHULXoiY^l|0*&o7w9D;xTgc)?{BSCV?0B6wG(hswwkCLXploc0+qPC>WabwS zK1Iu%E(D`=G)*pe>oVH=BhOYRVL_zE1F^?Ltr_cVfGP_f+AN!}Spv{Y$Pf%@yP@8` zM!K$|-t$E=^-$|YxV#>2y_Z&~oi3ejZeD+$X7MQfqGtK3l#vrENDgjPHtlXzpYx2j z3ACoXDYS^GK7EvDq~AcoK9ok{&m2+(@}drZn}wC_raJ|6lPol37*c!CpRhaHU|TZfRk2=BZ9mRPBF=t~1ttYF>V6mu z6Txe&vPM?VfLq2X%evVqb(Y~P6Mvr}iT`Y&Qm? zYM(2xi87Y2U!8wF!6MN(n_yUDh zz#V=-yW~eCxD($ZI8j0=&KY}_Lh-$g+9OZj#Qku?!kX=o+Q=tSTw~0vqN+<506iFBF;nNI0mB?$YNfKhEMyf`ZfmJeZ@D2Okvb(2LTTcDv~{asBHEX- zo3d9OxLDXt-u_XtDATPd;EuQ)*bh6 zlClz{J3bFtXC^LKxaB-*$ZKJG`lqVKsYHgeY?mK0AxrhDGyDWmTWb74(Cs7q1bEzic53VY)pXAIveru(J9 zCZq+>59taZ3O741E1NBtI-SSQoVGIbmSR+TOA+{!b@1w1)1J=y5kWh+x1#C79s!*s zf>6y)Ugso6b#eBR$6vVzz0!S(0(4w+Q5D5BlrRX)&D=#FZw&}|{X=pb|Hu&!0KgNJ zr+2>#+dSBgED?6qs&n$0k-p>)2Krj6SP0z@B=s(^sI#4#d1czOeDgP+FiaW%_GDp| z*AlL@ovB+2VlK!Mv)$G0pupRnsjn|O`D%r*`Q}l3rYQtaG9iMN(96hb99Yv6lNqt#mLl7>qx23l86`#UCV>tS3nH8K4$m~(tW(buPh)N3`k zW<;?^oZG|ii4!^g$mL>gnd}4_{A-R}@`CV=k|o2=fPxVAEq>?A8?QpnMs>QdJ+uIo zYk(Ot=M4r>kw=2)Za6d4(7}JXWS`l(Dk8zlTHd-|>R_zSfFpC008&E?qK0ms87$y7 z_3rV8a!YINhYyVn((|@`2=sbx+QS|IAc%1=rgXbSeBpc(0imfQdx_RdtpR0`C&z2%zb*_k z&?II=d%;C)RgoUx%xW5j*y+vY_1 zQSRH;?6J-E6f!Y-v+es6$Lk?p;uSq6JF|_Z4KL797O`7X)q&X_aXhxvxg$Ymn51<& zgXv+syI-$&e|t~oFs}GZhb>`a5?W%tKxQ*DrFek&@MhwsrvNlSAcahd2@M5+vsmvl z#4Fxh61IByur|1sl;TBVu2c{M931ObgS+NOkBfK1aNX%JZ~z=c3|(ZcL&_#Mn!baX&z(kIZCmchiomiPcIr zV4~#Ko_8)&(T?DQtw2bdW8zY$MS%gp*rwOx0(^JD_+2Hlwu9fikLQCST|Z;TN?TZc z(4T}XC%PnoO9st3pmDmP4@g?bJ=IN?dlJu<=AI9Q1?d2Y9lo=#tRP^rQGV%h@3Wk1 z{K_++S;rLz&-H0VH=t1=TenD%o9LXd@sgclWSD(w?h1MXpy}6hnj6Zt@^=^7B%BZi zW^I8d{gHxVN3VK7FJ92YQ^s{umx^MII{nv+O)MB#P3x}rB6GDwq_M9DGXg4<`#QZW zTRf~xGw%eXNt|wbKQwg5gX9Q|0tl&0Z#+~NE{;jLIom$g56yqGI+Uw^L)PWY+!Oz$ z4}e+2l!9?b!MMd88kFpDlirRKy7Y% z?lc;XM<>WzzrtALTekmDSdZe9^-F1}3FY)S+^FHKNleuX&88T%SWdi|>B%)P39*P; zlPRtO&3V3y5^&W6>K~ACb(_(l2Br3Z`WXSFbAt|1Im1DMMiTQib!8umI!=@Gav+!}45Xu|?w`Mp*)YcjDiCTx(7twyZHqCt<3~HKl$9uxScSqmnZ0LdJm#<(X z2Ghou*xUn|+`nCs9>Z4CG$8?5*B6@1NnG>K!mgDHZ&AOBjrhmQJ2YRrEzIAxB!?7` zC_~ZF5f>j={q2R8xJTf3>-4lwhd{?<#GbwVZ`+F1REhiBLCDbp##&WhPySbN3Vy!4 z5Po>{yQ{wtRs}69);c@efBPtb7;l;Sx1Ez^3ED<^x$*M;u7iNzCozB9HdSyHGzS8? zANac}3ezTd{O;<)A9Jwr{MF%$i$8wbL3sWSM8CT_o=PczQFH2Q5^nykgTTT6-PQkh z@c*9<{!V=o$CpO#YG-sbV3QJ)e^T(+;3eAsZvVB-)WXck-oydIs&5Z-u(P+dW3{s} z`)|Gm8yg#xi;EU~=Yewnd}rhM<1@IivqO1k*}0%RP%aK0Hg-;0Hg+gG7aJNa+kbOC zez`e0I2zgmRe_mXn%Fp)*!=D|;4o9ue^JgKZK3_!`~NK)HYqL|1{#{2p)sw3GOY&f zpBwlc+9lwh0}TyB40s1VW4Qd&nZ&;5o0|40LPYpWxzE|M(s(gVNX*#%gG1 zXKli2ZRp_WBWh^p2+Z_9%iIE9)PTnQ{=9!WOTyaL$k1BJ#MtrAc0B=J zIML7^{3p*>akB%ieA0LK=k;svdeHnV#y8)CL0F(me6ZXB=hFSu&Y^#20MXEl?5r&u z9NE||;r-b<^gn+!|hf4BdU?JxQN)X-JZ#PFGkJ>~qXz$maKdMQ$n$SE`|qma9~v)eC88+x(e_{4WHy;$|-L)Yw&m zUG|y#V>2ro+lS6-zpD4YvjI)z{%upi3jB8g4tyx@ziR9S7$?B|Ow3B_=X@3Am6mk) zbJpW?^Zu@~7Yn!uobVrV|EueZTi5`KOv=X8R^T7I=a=*2A9|06?RWM0hXViB2fsnT z`2Svy{(rXprT_ou*x!Gk|GBxL9NZWAA2$yd$N%!b|2MWbPvs>D@hQP+ODHAz1mJDh zX=rGeSa>+VH^QWM>;PdWY#}Q8R7zBo_Nl$Csf9IgD>A${HZZs*`GDb@p`n4nw{B)e ze0vwA*RS6y8Thm|v^MlMG&XcKB*f_G%#st&VyZNur7AX-TU~xji}=F&EsxE+Z%c*e zYF}^x0alkM%PHGXDq6vZ!TD#jXSlDgM-T)_larHQe__427mh((js1<35rYr^TN1ia zrs$}Z@Wx#{B$|etv;&TNnkS=wU!e0Y*2L~s( z@bcxZ>%>M3wYVZF1{Kq?HcmNtM+8?aS^&`e# zM`Ndb#QbX?6MRP#Q5Kbw0^a}7at`LUjx2PAz;L5ovXj(wKtm(F2mYf=DcuEBJ^F}+ ziiV?xoGjl@LHNwp$b{7uX7}^@k6ihHT~K|}y27k&9Qa%X?)*H057-C4hTNh3d5EKx zz#R>_r?jHB_9nDYRyJ0)JA(MMw6u@xpPBM0JrV!&bl{V~9dk!VJ3a`+#l?lyg_G6R z-VDOd%gYO4x@qx3B}T9WD6T(8$)wQQ*!U zeA<85{vw#Ldz+WKjtZb0Kl?@gTe#`gN!qvoD^9g{GZ5)7W2m`%DiZ#xnj2N$!fik%(Kt zB^Fyo@GcJzFN=XfN`_d`N0FGl;Z75ih=z{X%bhnEGCfklH;6^vf25Tr#(HuXe);7S zOp)-9-al?)i(sAl?~hDX+al%VoD_N!VjY$ewzJpyGCiu8;krWt0}8e9;mdUF{^$Xq zhh)u86Tw`0{Ta-4rx6!dBm4^~`c>lJ|E;`gsM+tKf=;_G=!H8+ng)mv^n<34F?>#z z4|f_c!L)`Gs*5)?v7QM3{?A|s3rw}Tv#x*cK8sDL^DYSr(>mTyKEDa3C$k$fi6%UK zsqzBv^}qNNcEJMEmD+((BBQecM={CLvagf&^KX_YgW)YbvQonT)#)$rE{8WL$*_=s zsbED&6@LiOzdYFQ6{7Jz>C`8U>c_0VLqdyj=U@DNC-DU{FN0oay6LO;_G0k*YgJ?| z{#Cn$vFORrFZD;{3OI59tD@OTu?cn7B z7$!VJK9Mp?$G)9y!n&A{MN(Dv&r0cepDgYK3Z3451dO0ztVz_RPL^_=nCGn&+6`~t zzV+{f)IZ8A9oAxLgNyv4O&PctqAZd#jstRY3pD4h$H1sk3LZBS1%SpjgRs3<5YOAE zsH1u!Fd(?L9&)o>f7B#ecRX}m7%xl+2 zIyAGl-MkLw!QJVXfs}HgFP@+D`q=Ph5Z(Fi-%w&P(1cB<^Zl-6@AK)iEtkL+Qtdp+ zbD#oz3Eqg+pBepn1(DXfZ747?p4~=K+o4XYEBzC@GsH;!v?_^dlH1a}X3aAuw@Ihq- z79pOgSc{CS@$rIoX|~iRr_#3@H-Z7g*kifn?Cfp5xJe7iUYd0PYq3jnAJK zqqMJl{;|rr4rX6`bnsmi+bXGCK>)6@+qIYkrhw-4dfcZP{Ew5o;oUWIOA&WqhFV<> z1LLoJ?%`X1i@&HngBYH_cQ3mAQy?|v;k3v0WcDg*6il67P`y<}dIgUOjPc%Cj$z#jN?hDf%tbB@8 zP3L(_&cLlOx+jq8jW3bA#8IFld)Ypih4uL@GCfzr=QdMLBP?~9g*ESL+t-!u_sV!`i>D8yI*$&3$0Y=n;)1ab%*0tEgw60>QB1M(7$Y!&j_-ieYYC*I+_aBq!ASG zasp&M3!>{maaTVy##e?B%LGBCY5$7y5_z%{jNz>NMxy8gjL8uMDT&)XNzmK_vCMQil^*M zDG4T%@Lhj+@*_gKqDAD@d-G4cdqaiZPIrS$=@io}c@>aP>dO*2w>ZQdWxgwg!V~Ey z7?vD0wY(0%B)lfNDex7^gva`^v$fk^wiMA-;)tGyB<(N}j*?jZfq9_aiFO%$Rqvnol;)ImUcgY_QY7ztj!>~`!; z!4hRv9IW=u&{Gqr!y-1x-i+W6;p80mdeSOHYoB zP2!)3xPN{{Xt)K6&d&ABZJsmgFibVN=M5#f%=5gn+Y41@F6tD_UoI&389e{G#lg0> zvNv}iH_B+vSP#?h`olU0%C4pDo2N#a-99A0KXK;{_odgiX(HsS_wvfdEm>eg2V!N> zU+87x9C~;&pONM#Nq{L%O&~0YhtyK9Mph{AQAMw*sbz4!_x2-%X1z7O zF9^?8h`hX7pNOSQ<@$z`_d#$JtYn&HKR9ZbWto02@Zm&S4eP_(Jv^82jt(CfQsw)^ z-({YsWqZFgkc@Jaq3$!YU3ldA1VMRn+xvu1tkak#-$V#e23df5k%k8#`#M(cO8RVC z=`$~c(^pMcWQz_3n!AmMvsT?%9relG>)%BYfArC=RtS5^g{kO#X1x%1Bc#E57L$hj zO%y6*9wF&X%imM5lUV|}fB~?u0+il`qM+J(I;S$1k6v3wzZYd`n?z_U zhzAX0pqiFY$+YGPnGjvqQ!BoB-)+A>V1PD9(X>=FgZ>$^y$xu1ir=q69@p@0Lj3$w zYUR?Me5}>2tEfeY4~2-Vh=DbNqdoXz=_laJ*rV{5jhM!vY*Tk*oFJ>_nLeofWVvwe zpn(wDvvi18HUv{%m4uUEl>Ur|3F9zmyQRu(@pnSqhbo* zg@#@Npx%@*04d^w1s{l1c{oeo{-?ofmN!_zS_N+m7D%6-`DZWBxjiMJI9d^Ru7kMD zDWhPPj>8YMQwbC1M)U5iTO?)A8%smS+{kFsEar2|j5E&38VUN3%UUR@`bdjT{b)`N z=6d;9YoK7FRPOFC%dW2;a2dQm`nlWypW z(k>#sgMgv8(2I1CE>e`H7(jaO5IQI=5_%0SMnHN`D3jcoZ|3v<*4(xDhqd0on{#$~ zo^$rI_dnnv(R19_WcFF84vbCYE6BibQO=xT6CDdJJt_Q4_cTxS`BuF|D%&E-{8!Eb zvd>-2UCn}-$qvquQqz^ogdn;vjIcNA#AO~?5#|J-GAFBVPGRD{ifGR~jH$nWcks@n zEiqsiFKY@luCJUVbacFqa7qa!F5PCc*~d}Ai5WW=1>;)&U5bv?=LdV5%yl8orx(|Pi76vzsm&`}kQ za4B?~cW+qFF^2DSTwe*e2VT5f{`A<_{mA{}@19ygNSpJfbQoi{Q9QrFD3(R7C{0uj z${ts59tuz2e1DVg+T-_{jzrKzG!`re5LkQz=5Fiy6mBIwnc1^No^09C{Y4Rh8(#la znN$vu)P` zhZm0JH^#QfGhx((I#)rVjI3LqHWZA1h| zsxvnov`>J%@$p@7gWJ_*lhftSwT4F+s%pLtHO#x11U8DeHDIZCQYItKMf;(~YQSxP z{QCF94*?OOV~Rup>AHo-0_cZi$1FidV`wE1+=Bi!nhMqpqaW><7ojHeE3u>kx+0a`a!`d@w5!09(BH(<1x zGi3i1L=5+|)1nu4s=?3|E@Yu)sZQZ_Ta3IL=T(QNUH zcu!L28^x<1QF28xgb@k>qi*t?f|po3WwsLjPSp2}jPFwM@5pUW|L4J)kWZ#FPDf#H+^0T1pL5 zm47qjlbmyCLSV5vCe%!H2zGY&fFi3Kju93M<2d4RD?Jc!4vl@_%22YYbZ(eDzl)~= zB+%JWA2rJHwF7^&O--L&Kg1IIwS4kHrMh*o@YG;4f*m2d5pmK*5;!^eyjZqChu8&J zm)oXOf#$SffA4a36FE)$Dd8NNPo7Ifa-BW}9pKM#rb-n^M2L#5?DbFxjm}zz=A0rP zcn`ZaSBNJ^Cyj#;2-%ywVG@UzTWa*BsP0m!bJxRC#6Su`2 zeaAG=0*W}x=|BB=K8(s$cwczOJH)F*d4~b4@#o2rXy|7uNVQirE2fS9Ecw=Lx}=QX zB><86Af&F>U+e5?g zvo_y-b_!NXNB7g4Pgyg9gsQAl!f#~ucMXoN2hP;ctfCIm%*o96QRY6aweXCpoy zzrz}aE*a>c8UR$e<@)R`Nm>If62&jHJ?A~|+$cfhCOWiLXd8HqK?ofx((DCMTMbIh z(52Y?wK9*m@;33)cbQDjKq|&`nJ1rIR+g|Fg`jtRqZMz#V-${T2wv?FvQoZ{zwHjk z%nwAS_Nh`n6ZlL8xV%&_Ig-VODo^cYmhcwib}D%)=T=g#COAw$xYNe3rko+B=1hVU zmGYFOS~;=+0_%xuvc2Ef^X4I4Cs5Oc)jj^EnCI=)ny-sEzfc%!ln&w<0Jwj+$7N2i z-aKdz-)oP4^ShE*k`1_LdR%J_pXKO926RyjS~-6t;!mj#I{|+--Bh&bQko`)Dqo%o zAmYxLb__n{{BCj2OC#cU*p_qN>IjE7oirD-ZQDogFRlsXf}YC9I0a>+B;1Rs#a{8d zEmS`2^f41WLl_>}m%)RUeaO?V`RN^|N2Un$iMmM47f!;&$Tu9Jm1l?gbU}$t7qix1 z-YbVRtOcvLm*Ab7m^Gi4L9b-*klAAdy3S1z_e16Y6&vj?9n4jUT8GCSTl6!HUHx8T zdKF!9@To$*>4LRC8G;cBIo3W%9E2!}Y3cIc<}T*t zr(?Q{1&q0P{e{z3NZdqyfvaalo{aD>1>w+-YrX2>=T4}=qFwpx`3UH^vsy?98v`ng zmH(%Yf|){RgG8gV9+bSwkZE4u{g@1L;!zF;Pf7ood-U;?+0|?&9pq<9&3{vRVS^P1 z!O>k0p%uNby2jpoC-cq{CG_10q`uy_$xy(G)=l~N+?yDUd06B`zD#)t8gKZ#r1l2hSH!Km((Az^gKIX~lNYa6xT0;BwaFphHc0 z4dqtNuk>H$$^CCDpR)}$M|W9l`VtB~?;2eoIW}h9tqH#{JgepP9gDu1Zfg0wtsZ37 z!6^Xaj|&)iG`(K4b#BP3c1W(GR@ZUVtoYbtYGLtZCjp2+k`*4%;gH<7Kvs}`R(yTT z6;_v)8#ahmMccFuD_kj&I4K}xV3{;7`Y+6WzKXg4h>*Qz{K6s}3O1?GfYVsNR z2_EylrrNP>0l4c}!>rSI%A$jG0}T3@t==K&sZ{+b1l`79U!%>H>ImF`^l&5Y(Y|h+ zkol%`lttf5uPV`5bcV^nJ#9q>$BL3qH^jC`9R1W zjvuH!Drclutt!Emy=5n93Yp_XNrum0&#Fk!Y|)Z*N9|>qg`Rmh9b~IlD{E=w7{$Nm z(y~#Q-k|#9D;ZSis5MAekzx7~NFh-5;#j}H)Ff>tw@_Q&fD{g5RgxPb%=I~Xw2BdC zP@FsX>~fZ0xVTB+pfan)VaKbsrcPfibUN^xk%+prUJ8|a1S1Yy_P#|@7pzZ;u+724 ztLy0S47UK8xyesHJnLdSVBPMdLY`xic8^RyF~Q2mAJ3>HpX@v;87vSCE>xU!jVkmz zcRYm2P3e4#oS-$73@=%GpteTV&I=LS^Vn$*G)6>kaO<(>=;`}d?8|nZ7A#n5>PgE8 z{=vzq(>j~T;3UwW+Tz@l^oFdkYd3pVi}1y$!Z7jkLM5jhEW@BGW)w=)>*|=9d8DTa zJM~-d^`rl(q?NpLw3ZSydCp9bRTB2u;#Y+U88>Qwo^m;N=TW!d7S+*}$_0rnG@ zj{b&JWf-*nd6O~ZswtfKxt!%9z(IO*An3rxTN<6OxR!p++%KcfHeS*mR#DJ%s-%`OX zSiU#}jBDu+=W))fetQDm7$Cnv)NHgz@tIlDNUtk|+uI=v>wX=(o`Gd7hBNbzbYZ4@ z`Cu86oH$rDXQEX8aK?pa_=b7%&QyD^FDV=x{9!yak{2M-KYZ=d^GHWeE#cl~@Vv;L z_4aoOaQh3rsKh_7EmXLKcf!QSv$vzArko6Q^)LPSRv>UG7xEzY+lh7ekWBq#`!6M>(1PC+f*N4e{A9 zjZGVNS}7|j62&=_ejOs~R)8+mTszpNLP!J|A{Qob7rFKF(TwOXbip?A-pPvw0A!1( z{u^WU1pPVzC~?-W!7yv;(rWwlzHHj!c0HI+Ej6S?&0%pk-ZW^FU}FLXoEikqW1CFRnr2=D4*wj8uYqp#BgwE%`Wz<=e1OmmX>R<;~t4>X|M<)oEX z9E-U%JNJ&Ix9i5|&?HkXz&n^?dh6J|^Xz`47*ta>@~B|(z=|P+!6Qsu=y`jD)m_L| z#M@v}_+t9l22zez3e=d*Go?On$Z#QM5@M;2K}EbYrDa?2bri}=yu@<+g&O8by3n|Q zFW>8}w=<@~VVe98p6Y$qSgmXKU=sVzOW~*3GQJv?gIzmT>8VD|YmbV%ynKtxDnem( zryrhU^lvZd(Yl6tr6D=-d8d+IsOv&KOH}*<=}crAz;y7lnC2h94-@q3CHEsLLO={7SA|(Fb9%C1PPJ5#a}0X_#oI|L-GC3P z8+}}H(W*XrY5;h(I9R_q-2jc}0y28_@HTeyYM-l*zYJpGQe+^~`)m>B)iI<-s5Ms} zt7ZbuXup-^o3ehk@S^*V@j_S>nSHW%1_C)ht9$2Q{hAV8~X`=s&BM40TbS?GXCbKQt>GTkEZ)02Bz(mRg z?FDs=yHa)NKWVH`O$w%ai%anuR)+HWEFf9ivN+oyXs}?Wt@*PFbb0ASypN7Lv9%Nmk1dv#W_M z(wEN2?2Dlg%?Rs#!}lq-vg?end3)jO*_H2Ff~4``q)W%;wreAVlcF#wi3>tDY}8(b zS9WXZy0Xt+J&$!OxnWwE6mGc2n5We}`lY-ZEEGTeV;xiw|W1p-hnaTd{# zgygn(G{I1T*NOtQI3?r9sO+yM#~ed6cGNahT2z#VW;q%9{63k`A@RNKMno`yI;3#= zUF)5NaIahMt)`vkdDYurCja!T?4mdPaJk3sjOVbJuWrLmm!x{HxRZ1sm<-NWUiU&B z@p=xhLA{ahsHYEJ_d6Vs1Wb8tybnM$QudTro(Tj$FAd9^+8KwCjq4TcqW0_BOCpjA zZP7+FU%;~|ci7sF;Od&CW2e6Dx8NIx1S!p+U-#8gDabw;v#y@UJP?46yVw6k>)T+$ z&;Y)iC)mJEBIRuzTwCgvLOFcDd#98wr^OVsDLN$Nkcko8R80n=vOSIG$~K#AHDsNg ze{`d7o*NJf`F~^^DWkSiDCm-(H(amb-D?dCz^4M&j!5u@aO-csB zk?q#vkaZUA zKZuJ1ZHO>&yr|;`4Pdf|1#P<5BhsfLBu|RnaMLA2!Su+>V15D2J@f-Lgj>(;gi_nEqf_W<`=I#Jv|!Npg{}z! z;B*{Y`$`m}{?zBqh+UK7v?^_}vM_OcHt&#{g4`TDd?N`G&5zlLJ#&H$-0kW_fy;?T zk&MTZ(3!F1ml#Db3=7)n5|F;eNm%Hl#GC#DxHtUUj_4+6yEUx^5A+_`)VU#7=c46EtNFqy zokbEjZqA4ii?wNo3aD4Dw9(lwwv3Eq=PGg*u1A`+_E4?JR@cCF<1KB5(X%OmIte#wMO)!NpdCf*!f>FzwRYlQ(Z6RNJ#(N%V!Qo10U&fe8C=Sk~qXeGy!6^|m`<)lRv z2m{Wy(KEl4%KbYCm?F?yl@lY9BeZuKwWel4En0a2w2<+89MbAGM2M@sX!$z5 zP{QtCtU0}4BC#^o>T+uOhrJZsSitm4H>HkbFFB^mTB1m4!rkQh3O`<_F@WR|{ zOw~3Jj)c~}P?VA6`RP}%kDCe^(z10qQA01kqQ`EQnW@MTMhfTuxv5O8_;J_A#uzpC z4P{afV@pH!(dmOjBW;2LFRD=8hNSRdk&SGr(NnzR@>_QyrQd!v{kgKlp_>+m_+@#g zoQAfu^TlV*4YP$v!3>fwoELDLi^Zfl$JD#5c2ve0{D@CefX!@zMi0uUo5uSrVY0hzs|U_H-7k|*$T+8i2D0*A=hn-KHNieOcPq#Z zXN}^05e=rJyK3DEo6K^oto_<=_F-RoJz06P#z_`+8RQ9@AY4!~l6D$zxZE`8Fh1%i zk-OMUlgSX>z$?u$C4MxLu`6J4-Li{5Vkz@begQ83CzVO*%p`%gP1tOA(+uGXRr!XX?GhOyuE03P7{8#}yoIru}KZ2l!{&y=k-k5!a?i}iyI8VMHwo4HwCAU6n zDXK6kV=anvyxQ^UaCE=ytZjR)V!I+{@nmr|z)hQYY?HsLolWzeoMW-4+1~2oQ&qEN z=?yc}zldNM7lQ9C7u%*X-;7Xei}0Cr`-**J@G;CLuE)D^(VK5=Ouhu|$*Y#?Gud)$ z18+bN#%7Vkg)x^x$?m2+WdW(%O$}Vhj+rL0%Zp5dOsLrj2RI3r26) zzMSz$+=3B?DmYAOoNK7fyWEYSZ5BD!FN80oeWrGvgNK3iCp* zz7_&*q-SimB;R5Mp%?7UD*~4bqya*Y(_4^g77+MZ4v=%nKV^P8Hpra!awr4&G{_VD z({R#S-HsIGH{nd>v)TQG(Rm`qKufAuiHAGC==giARI#ni$9~}93zx1$@SLcy5`CQL zg_1Y;IDZ>+kA8jMIyNog&7007sm*dmY3;mj}GS4+L0FYULUHSv2=u%~FE^6hU|WrOknr zucYP8BMm)c^JPjtc*lgXP|(=g18&V8vam)-&)_IOdFi052NTt2!M%6gFYO|T%uV5P z(*4qfRq}_!VrfR_pyBkVw5$ZlEuCb!NGlWbPB}62&EI_j8Gw8Op_Y>xmvc*J6WcLd z3*Lsbp`j|Fj38Hb+to;xyUqjMHbC39CkG>Mgq(YO$rt? z;_Ju*1lM=w#do@hS+fO_B-rwfSlAwK50%|?P0JmDtaMFGmraWJgdFgXkece#__1FZ zvN%xjG6^mH>QnDwcbAPL*_DW_{26lb#}kQtVYXUSj8o8 z93El}_4H$FGR(Y<$jH<)N-0jCS6b7;9EVz6Opt>8Vz2Uc1?{AN5PO{OGh4wH#mld= zr^qCE_zmybdh9)1M_^hXL`wUbal6K1&Mr2QW! z-I>1#?3VFXlPn`|;rT52*~bW7u^Ycn6Ims*_k{&4QQPGOogC21>M)V)BiVa1W+{sV zqlHe=x|s2lonh)ch&i+a8<#kb)=s06-22#@sVfN3;nL$ zrr!w4UNd!)j0LIfpZ@xi6xEE%ZG9d7Aj4F2SP~Iv{l#w(9X`>pIr$ zdxVWu-M9E?La=zt@k_R!#IXGJh3$frFw@dWLnCe8m#uipa+^4N6(%O0Tr1n&o7;QL zOaigWOm)2I2e6V~-aNxt$|UdrzT>{!;+xpMq3P-%J$vl$81M-J<%Yen1t++yl==Ez=2MTo-lw7~R^T*JICx zdW+#m`|bamgCekOJ|>x5Uz1`5HycsObiIbY&9ZZcdDr*pm!T(hNn$tNcI~|0U|O9c zNq|3m_s_EbcKzmV2SqiEe}aWr~vDlGULYX<-Q-|EQVh9&`V z8{datHzU)@#v(OhuF}bdP%agZ&@*?6a{V1rR8p5(*o&I}QJuf0su1Qye1L1pDk3nS zubMZ|_udS%0E&w|GP2Lnd$QHv-J$_u{*M)}6TBeX_@(PVY<4RFu=)!i)7$r6`6z?Q z4I#1?FD6kj*l~^N0B}f5tsAEC{Zq@(Sw)@9w)i2Wj&^-HR>3@If8-k5HN7q-U9e_B;9M4f{0TK6}{aEclj*E`# z)9YJ#N!hRV73pYN(VL}Y7Rd(Yezxiiz1x3Nj7;Ev-v3DBO{7b8;*xXYqOl!~b9Eox z-^Hp#?yc@=kEo1r{nT%&+fU`PRq6LxMKkMf)I_M#P)IGmf$I^IvEy=|)u=QoJ0_!2 zChpI*(Xc1DuO{iVN3A8r&IF#&vD%y{o~0>!u^Xg`QN!JHN?{TA+sNn(_x}JL?91F} zWYVM)%w}2eS-w6emOoR(l^_oxsBy(!)lCPoi1X1sSjbha8_Ip!%!gL2{+DFcJQkM5 zeK5r}SU*}w^VGjB-47fBForE<`Kz7FPn@({?y&a#7y2 z`qpYv&){}xd4utnjBUZv&%ge&Un`^Q`(-smLwnCQhgQK*9Wj*s=$8E zx}O$U5M<~*YfDzT|F@U{*PFB!25glt5BjGngx(+TE+iTn`||&mtb}fSxWRFZ{e}{Y z{0CBx8|y2~{weaf3n_}$pL+C)+%xYQ2j4n{)Cm7w>g4s*5}VRUw<=m)d}94$9=j>FM9Vyk{a1Ze=l%O^ivD*c zN(BFh*Z)!Po`N-OD<>?S`&Zc$J5Kggr2~HUuY#s{ob1V_^sCmtK1E83-SCKn67{?P zCVR5Ny*|B(D)?WYdZvc8#QRP!&HhK8_~VF#6Z`r-GrT3K|MrxI64qY1t-fr&`&aE7 zJ@)lk`t@~k{`IN5cd?E{%BYud|KBXM2lx8I4R1I9^{Lck>>fRv`Pu@BeP;RU)qS~( zy`Gio0TwcxL?%BU-plY{{PLA4$nqV4cCL% z3ikMvzqi4ht!?GDD~W3eX1)hk-%DrWR9%G)-O+?}hMzLZ-WNu7Vxtxdt}M^(>Kp|K zl*i1%qBs+!IB?C79~FC*0PqYfg1~3rwS(^pHZ6xK#cLh@Eve#`KmT4esc#aA)3V3~ zog*`%abv2pz2MLKnh#VKaF>}H}>cVYzC}c#^c^pe~g=!vRC2LUOMd* z=k@o;Uf9Vja5Is z=l{cK%Lw{SlcC2`COw0El?w(exClSvyOt0q-|G-LMr{~$JlTVrgZFMMQFezu5s3bk zZiD_IdoyAM*J0Vzf1|*bi@eS)#PV1UCU+Qtdxw>D6PJf7aGYEwGPAjhh%o{;KH+Z# z7Ea7bwi4Qf&q`_B?(2-AZ|g$)C$HdyN4Sd1xwleS6X57~N2dWJE%QI^g$rjdHnB}GAg0bxEze`{p|b{^(W{g_?CRDb z&xV9Ln9TiQoO1xQa2;J)7N!6kb`OVsFwp%~sNA|%8rG`F9HOhin;vnKeeiz1k^ zVb(6|;DFB5t?NzGo0)7fLmgM>`OnB3?bujHciM$Daub!l11VaF`>8wDN@-4S?K`x1yhdEQfFoB^GA^@L<(g!xnJrxI9^@47qf4M`H73>YYzR zG=BsfQVq*t!VRXyX;q_q&~&4%qb)EHCH3d-b+G zfK;}^*%QwKGdJCRlbGo*E~&HSaP{gMIm6l>{!pBF=_a2JSq=fnbsspjx@Z7BNON0o zAE4D^)>r&EDA4jNKk`@_b4dr;zn5_B8b+{z*YowtDiq6q4m13OW#0rSSY41-k!)e1 z4PEeQD6ASg=|l!Kod-+FOqQ_SixKt~R!WNgk-Bb4f|j zz{?9OW0jF<=b6)LheeMe0rd+01MmGlfc@oN3QRq@`eoJGsi1VjqW64RB~t6SZ=@Id zkiip1J4JM<#iheTy64F_E1J{U5mqMp%qqXh-z0;jgYlwIAM6r`HbRffZ~B5;7WxU$n?*0?g?7Q_Do8kW{nnR{X4P1B~HBYW7tU6LRN^!J<^ccucf zsW0P{lh{Su?a5j?Dy)J(=X-Ya{e^>f@=fXp21Y5X(C%m!e;yq39T8Qt-fll#x*4)T zKnf?#W&sW=wGh94&ViSBBd)TdW{@{@_SszsbEe2#8r$P1pSUeWS|qtGzZ4Jt*CH`f zX3~U-$DPmMxk5(_Y4$TZE(+u!K~(erJadIYJj7YQq%qyaR>O;>+tCCYE*td&8ElKA zDo<5DG2-#-UmRD4n1y*s{y@_kgn6-AY1Nc@xoXuAO(Oprhp-DjBmnIeO*N_)MN$Qs zZpU?gB3VvljC;*m1L3-${{>N4L!Ys$g>35P-NI=`O}3Wdme`2lB)hcH zi4E_}dpiEuUn6iTBCCyp48g0PS*}p6XO6J7{1xpGv@Tm7t%0e?u=u!!^S=9r+ah?H zc83|Keoa3NxyB&K01Po7K%M3N431?fEP`|nt=I_lHnI?&+O%T$`g0__XC=+RoHRtF zKHdC3y#O%t2;-~0$%FvX-Y9V_`WIkpdG`~G_xT%opSs!JY9y>+y&k}wHFVbu2{Qh~ zMlM;s)*zgNb0*2XsQZrVmXACC;CQ?(ip}N|g__z|YpmBKSgL=RDd-(5~h?f)2aYrGh6Iwg* z$Rcp_g{osuB8#E4W$`5qOyXw+^-km+V_MC1iZCK!gbWR|Rtr(Na5c z(AjtHyrZI84EbOu3JY`|&fj*4(cJZe1>6eO+$qmy(=@?mNW#9(A*{bM8VaY%-D@+% zq9aC%m&=JLT!}XOj{Nb2ZXehUQMJ4la(x;C@Us;X^mNN40OhLURBmTDS3O&;ceG){ z*V5=P$EG|ngZ)Zn5_*!C*ag(z|6MIsH_Hv&k6q0zX0)`qInGzn#PNfIhgC7_66-&Y zaSBb<`Terq0l6TDp4*b-I4Bm^z{#?$#IV`LI)G~kk-u0>mVU{d?WUw788Pr6!?fmG z#>w?EvHa^v=Xn;dABw6$UsI7IH>iOxg6Ll{2TF5tauTM-3ATJ~N=M~|K+i_Ij5F=Y z5t<861GeikwDrk9;e@(Q(o^gB`2K$@1aeI|$t}C^iscMgg3ngmus8{D8MWJw1!k46 z0calvsSupdAB$6gxbY5x9jC9kcRX|3gZC%IA0ve9bN%ejW?{klB-`G(0d80jSCfQH z-^E9}={4;_F>irghoQlJrw?FEhH%uc)7lXU6TJf{3#v7%Yt6*9y`Dbv$^8OBoLDz5 zGzUsIB`gLFz-C576gHMLpRr{5Ecx}6lvXeR4^on7;*cjCY8F^vsLHr{$oP|BE(t}B z*lPA3);s-O3loI$y_SXAknR~KWvstedPaipEp2g)d-WThTrW96AEAiLY< zX=wMs7G5}J{|BpjKxy%H;IWDX=Y~b#y-mZ)vv*Q=RYw}?*6Xq82dv>rr6scgN#QA} zTc?g3P2mA1sVF+%Hx8-KjuZOLxvx6<&c0D{!L3KFPQm4w{j}Or155&Xk)+~ob^oeU zFiAI0ycYmFXw!xT(?G_5aqbh=iUL9T$+PKpSX@=AK~1>PaHb;R&SD@-?e%h%T&DSS^ ztn0o-l#3hh{Zy%--|&eR@at@8#-6Oky}B3eU4Zbub#(K99q9L02Txi3L{iI>>U>@O zKEDv{tNo-9r}u>*2o_Q|w?Q=}W+4(rOe%akwiN=ml>6#&N*RGBBi6#(U+679Q25QX zH|+N_W^4mg$7)!zaVKjQ9|pYVoela61WyJo1J72X0eKsYxh6C@Z!dTds~CZ8EXNW` z+H*ol!5-&UE^Gnwc$)O5hEVpHX5iy*GKNSV&bI}~`X?em5hn$Ufr~Rm9sQ9$Lk*W$ z!0$5aRiDsp@u4xTE4`sW`$t7pJbsR?9Iyx$Bb8N97Qi&Yu#zjk+jjV*>1lahiYt>E z(~5K|SzSk^a?xc|r<-8bD*b8Yu@U-N_M-URzMT|YV*t53TP5~^w*6+gF=3k|awQcH z-gcY)ltTZ~kz+Q(n%J&MO?3lb=v6@o*nmtRbQsS;h$o2D7|bQ{i*5A9G5T4OE0{c zoUlehJZQWsarr4g>>5-0u!C!V)hT}UgXQ*+t444w+Fobz^l7Rn&3_l^SpFu7sOBqa zxsP$*Xat9euL`VEhec`IVA_WD+f|C{mkAf(vvlkqS)o9cq0RBw={sPHvVnfsqnxtz~QaI5Lw>6Y$hKQ}U+{~4h(!y$U8 z&o!+EzyCowF*xHAM2(> zI>x4l7O;KXvL9QmMH(f?DFer3!1s*@l6vn^+vY5Xf9p-hd{`#txe((sc28te_-Ofr z;e^V17Uj2zZ=KemoqyaRZ?o4z9NWC3vRW;obBCtDNf!Ik9Azr3!}XN zPC!1U%;Qa@$C^`>Y27=%@MzGlfy1|3R&1fbUE=Vs)Te}}WZ`h&kLaf8cz{VTLbx;Q zL_V*=#p3j*<&LJ!Xl(@IdmSwnF8)N@GobFR|MdqG4#rdFQ#<@}cjy&HdEv;K95pU) z-hC10!+mk3I(@Jj*~AN(>S1)Q(=nNl0=Jc$uj4>nV;@o>jaE#)sT40Pd~&)Wr&mvf zFwSv4o6XtQn%4GjlM(=$l!*vbAo`29RK?9LFWpbZw=Vi6p<{H!)nBlG)JeM3%zS3t z<9v8%dqDs_+prVV6(&$FI(hWeNw?C79#!Nc+PQu zJq#d7HOB`;Y9nZA=HyOKUre^3OeYx>1=%3dA+~#Ec^%$x_KL*?aNZ_oGP3xx`^PCaxqRqnI>`2bZK}XH%yU)UjCzK`G%sZFrEdfQYetZ3 zK}=P+VQRnPuTnCS9?(ab6vEHK35aLOCv@8B4O+>C&@0!}&BQ=;Q17l{^e>90a;Jsnc-z+;YBu+F=jR)Z zDk==g7@jtexHT_h2~ddXHdoDi6wTgR;aS6=L*;Ww(MAB0>vWen7NM(81F; zZ%&_f@jA-6_T|*7G@y@LG|dQl>q!R7&Jts;ddN!0j+Qite`V^tC$m!>sYj!{1YLx} z#9^Ra7J_Lby--w&NYU(Alo{7O|=edw_%u-f+3 z>i31$DN|2&y%gOW&?jd(8}lmJdi9S_EAzIEolK6ECLOPG;E$+w+e#C;xvrr#x+Vuph<`wDSxtp6<_bF6t`Tr-7`kx(R?sV!vH6RDY{?R4`Irrt* zyO(-ugnM2;1`&tr(@7{=d^>%~hT*pFgaLxz27G=j|{ZLCcf@_2&*EnQ`+l8}r|gU~pVO0n(Z@Mq&0y zh*!-*gxh?ik$WUBE&wTb6Yj z>*sps(1hV_MZE==qyYDajbA^9tQ1z{5Lo2pHTP7@SY2vdDZHQ4JzJT+N0abvAcJ~q2^lEMf4z#>+&tsMXvbtb+}K6GE|Ra=k?IWgLa>gNJGSZ zaVp5=C#O_YTZo_sjOvA?jUoOtVOi3?P!2VQc)!hhZ_H%LpqaY5o>yjssHC-_#Ir@R z^qZHDobynNqNM5W%weeWq=JdhqraT~8|o|G%?ur0OKNn#EjBEyY;vw6Op2SDH=l^X zAB*;kfr?&!ww6bSkncxAwwvT}?a88awWRx4Z(%)tY_$q$h-PnTCK*F2`AOZn&5m~E z2X| z7>bdZ*OY)TGWWT9d77s5v%5MBelf^LJ z_QZYumS6eo(7Fbdg!Ex{o?YWMcvt!)B zs~T$6R0UQ?29F?lv$Givdl)a^lME?A{_FLU%bRh^=Te3`}ilGF2=dBPz^HI2e zE){hs8pz%a&`G|dF4XSz!Mjd&!QRBVUN1$H2BPd$@Z%kF%EXm9zf+$jj&2AU?1I8l zLf+k;*N==%eFSrv(T}?9xNPz%b(i}?Easl z>X`vbVvX*y+EL@+6WOtn$7PL6{(bDZh$Cdlk78|%*JTC1901GaYhp^SR(CNx=;&V( z#Tw&DIi9e`k}4}T-%6+}wUB+Gm8}IU)_7x_9_t3H+#pMw>2S-Fatp`R`RH~Yt*T&kQkI&8FIO0dn83k zcczZtq21)VR#tvA(Fqi)pLl`0pjW+`cz6fm&F`4>_=F^yHQ1LbX&0O;3)~A>&DjmK z_v5)E8u8lQICylsa~2PAc|o-2Jkl)1`B24xo6dP+ehgUoRUx~XE73#VO?&BgIcm>iCoRpnX?E2SNzR&6h^pu@ZO>#b|n`i z4fWOz22d#@oykWg0 zzhANER5W(-mlY0gaN0e~2Il!q#Y-F=`l*^_O0V7P?}|_7ohy6aVsu}CwB_PcK&`qZ z?b!d~>np>e+}gGkP(T`lL1`(;LAo0ODHWwtq@<<01sq!GQc_U5Yd}(RU_iQi=pJB* zZ|?oR&++a3?EUVab1-wW?zOIU#aiciUb@0FQ^T;Q{R$c=b0NN`@6Qp*f4-PrzLHrnnFd;+7kEflp0Ws~e0jfW11LmLm&qZt7`OZ^m$TWN+)_?8qpKd*H ztsByMw&URM9iouMN&o&qmOU0ic%-eus){CrQuSxXMOEnx{bm3j%`*0uRsA}I^KQ(x z4_U1oR|J*cezrENf2(!k@I{k3*WHraGM|sCje`cG7MmCNN9 z8nssAs#Wu8fNu37F_bVTWX%*}I>K!lUl6`L?e#aWT?1=AU-Xoe#7x;g)a5Dj8fYV#1WI-@2uI|>&P z)ukRwSTuIC?jF7eFT|si4`R9P6o0q_9v^GQfzw?sVE2iSbPhK4k; zxV@ye%%)`4Y>Ph$1^8C`wVg7_$n#NxTPs-BAzND|jU{T*Cw7lzF8s^=kJ9Ejb@&=@ z{Tw2S=V=UG_cPG{QXF;R*(!ydivE|ew7#*m;T=%F*FpS{sl1Xv(faMOh6@Fyt6Oiq zvQS?5Z?e4m=Q-*pX@VcuT4z>4euHa?-*IQD2k~1s4b6@oigG~$6~9wWAHk%gqTm}x zUoy3!j+{BgC2Q<`Gt#-f69rT|&=dFGvF1rCwV4;X)1KoV^)qJ#Z=EIuUBwdnRJ#9y zQ;Tj5p~x+7IFypTk{lbUH<4umuSr687~cxu;zWjj#37?d#;`e`NCZi9j4Z9z%;`l| zUAaxl7#6G7&+rWuj{c!`RJobUZ%H9G~P+|$^hh@(AaeSVS~hn>LNps zzKBug%Jt6>@N{J>;x7(_`CSgr3sC5`R`y6lUZX|ogw{T~EBDs&y+05~D(y~?_ z`Nuj8>&zpyyu;I*30bOcIh=h34MS?G-7M3NQ1+e6kolzxOANnX2ph>WOVafbVvsb~ zVRnq}eh}HJMExN!Rbmu8>!!_of|Ep?rz2?)Y?_5`dVtX^?Tt>bpzey@h z4#Ar^u(?Owo57TNp!X0yx73EcJN&(cM`6k88Z}-7Y4ijwqc77N+zx4Q^z#|hVk7dZ ziGaS%o`WSBI~HknYdHiySzftUm>f6u!61&hXg?fy_?=8O`+F^=tWYiA%TMZ}Jz3mH zU&906SvJRcJ!lncusQ`?m%#NZ2(gh!q>p!YG;p4Dj2zKH#pc`34aj}cy?s_4N`xn@ zw;!x7@?vPI{A8EK_NSoF&$fHooRVjPpXsk!-u6q3^sr`azlcKkfwQ$m@$v?rjp`43 zyQ_(}JMt}KBC}^5W>ln$g*RVnQHOT6Fuy^W2DX%Jx}Y@K~lf5`s7AdS`_^3bKFccsN_d_(Ux0}o?DjB zVGl)Ikk2>l609N&t(|asEf$O>A|2Ifk(L2mR>@iV(*xfv1-|v4^ ze6{#4Jb>eFbY2kuSO`U}KEpl$vl)rUw$miP^i8#4%o;4Edp=&E%oi?dVhuZaewyjM zD-tvmCU);yr>tsM^vX5Tf^N&g1|-GvBFS>|W_%aIPf%jV=}-feIuKXSB0@B$=zU}~ zS)1agi7Y0&M*@2AD*w{HMH{}gTxt9{;Wo98kUJIp4$jEWA^W4Fg9nc*1Q&!94SBxK zEsfWo@AJ8O%z1r3slvyyx$xNJ4dlO0slT~K6)5XVrhSWgZe#i!#?d!lb4kI^ZJR>C zzwyP}*(Jp3``Yx6O;qg3?aRGaQf5{z0?*(5IpCMm^Q;B&gLwf#+`g=vMQc=3(}joX zPgv;Dpjhc@*!Miktz!QsB6Ej{VV86u|xH0 z*qzE!qVs&MbSPnle4@dWOB`(o$qz1Hs9zT78P+|A^N`2pGgm~u@B_I0x~S5NKn)f_yj zY5!Tq2H)6tQLo%~Ho>Jp*}QVB;Fi3~I_fKUD}puCisZrN@jE&gQFbf!K@ody5I<5+ z)I?hEN4KxB`933gxRtYwP01Zo2G&ae2XTjy4ut2(x&I(U2_*i^cNn?(Ebn7rz5AEJ z&oF$5fl{Yzrc`|^C*k4Y*oTgzV660l`GUZjB`DI?b`y%bKBG-x1=>{gyBu~HaVxK@ zw`;I^0NW~B2<7d4GbZaM0D2s?Y8u z`_~5$`Hm};DMXUeo#3TSp=m_N4~lXXNjfu%O7!6d^W1kv4-FPA-;5J~}6XqQx zJ|YdBb7y?Rj=@h+SXB*5b}EG{V^yB%Y&-2aM^)W%efqfd4K>6NT(#UN$jYy&z4tJ{ zMn*Uolnu&`sDB`B)mAiTT)ShYreq==aoqKLuyS?Eita)kym;6L24k5?1(=^ZUu~f) z@LwsGnUjeEnCwtVL7uK^r<>$bhad3b7#)_;-?cR7Jl_JyITKInUN2Jm^Zbg4W_i!} zXjt(_jPC3t{6qS*Nie}j83vB|8hqi{7|@81*VNQygeK9_T4uuM_LF^l)}aEnaj9ue z;}Tp!L3)92q7woYYJ0}tRemRKDO--7U8Zi26qv>nTD{1BvOxRmgsX2J^?`+k;xPQ? znC|jSKTE+x9;<5LG(e>k$tw~>}|Zw5PC?KO-Yj1>g7Z}jB&}8Z#l2X$SwUgL#F0RA05o>Zjlwo zU4;9zUG0*vUDuV>fo-3J6*6SChhjM0GPZL$Guz=Xa?KOw9$784qepIKY(sUJT>@a@ zo=Au6H=eJhfy^CY(+>E3-?PyEt@54Cu8dV*(e0l_RcbL?b2H6sMbQVB$YfuQ1N{&4 z43~ln^$S^nIZpK><-8yNg2dzjV2JAmdJ`%nU_2bM`j*k6VX~hM*jxGO&rLlm%~Qp| zsjqKC@Qfl!BAsRN!A3apuiGqB!QfAvlwCycybG%@k{_FE?(VF@28Bp+>nSd!8R0sj zEvwjK7_8YA?*>+u%N_8(ctV~)+FenCi>vVd>< zT~PtGUK-PZuyDMll~`SgA{Yl|OOg3U&oJD~JsqihF;M|rouj;|+7 z7Z9ysAjv2KMdD(8Hi+;S_!qmcWJSUwuwDat8Fyr_H1wN z!*$fRXlXnD@L-(B=||%Ol0n9$KVj-hM<-cg#YEDQEO2z(7;*0}CU46Fg>8Ity*2py5 zO`ES2cd<)K=P@5b4QA6apYEY>2Ct3YF5D4%d7XUn+K+Fa>e-*$TbR5dO%8n5P3QiJ zMc$^Bn2Sa3_%+p%ie5N4(sVHtMEJd=;axb`!O)Nuk>fDVgW9ePdyEw-vYuY~{n&cN zikvDtnI!uQXf4&IByq$UCgC0qc3XYY>wP?|*aypSTY?zIAt7KWrA3N)V%bW($_KQ2 zs8^*Z*!xhZS&*1Dl0mL*P|ob<<)GJ@ni3N(W~ERLFK?x2W^+pu5GTFvT<6V;W@U+ubsU}_wX8({Zd zq~rMr4f4UnP3Jt_bmHF2s$Z8TQG@Q#%8i@LM6JIt zR_d@=GUz2QA{_tL)6@sc}&TA{XVHPJQoXv?vp5a?;vdrgD3O%cA zgPP6B0O_hzaL9%*=2zl3R7@{EKcOccw|IQ_CGmdFog2!}-yS`cqaPe(zq|h{_~#FR zdB#7dnXDNBa0{e1OU@7T+$7);lwaW zJgdpCR^&kz5TLvGC?LO*pGEqF)rY)1cR)9In*OCr;joindq@}$F89Kxtjo9Ic!w0) zq*paz8x}UC1_|7M-c9t1(m^iKy~5O==p_h;Ug!QnOOc_!_(Gsa?Ia(E;r^uVlhwnf zRpaB|vrG10t!Y0BrDHj|2i@VeXD>_FrqsvSDy}sOw_yt*@>#$PRVc2vXd_TD&}UkR z$4WAv#ix(jA^*mY!}BYw?}4*12!z9BkPs35=a*jr2q8*SuY-RdYJXsvKK!dd$S?JvC3>g=U@p{sd8>dcDo%pC-M9y3;3n1y|62FpIi(oJ z*`)+`zg5&H3z{d#>rPAUnQ_68?`Ucd@0b0zHHjQF%*z&c>DmO+QChM(SL^m z<8rJPN)8YMWFsvYJ+~qj(vvo<8Z-Af1 zpq%>!)&~gC#pvO=D_x1+cR}LT*d|ZW3i&`H(scWTjO8(SfKzP z%NqB$+`oN`MFikuH3hnQ{wvdp6X0X1sC=XS*KhRze5@6MAASEuV+%B8Ko4I>Pxj!+&L3>ENKPDKYW6#J_$k z9&nvKR60ql|MyJLW3lMVIcm)(dl8XdswqLrEC<@t9OjWUB40!5R^iIJ!^MvkGsn;tE|=y-F51W{~Q+eUb?#SLcB`5q5vmr9{4@Wt&) z7$N#)4OAXooF%nfuI^_dn^^mK+VMkw`>TZ9_G!&_0)Xd0SFbo!+Wh6(8~;RI3xu~d zm3^J5@LtnVuTS|G1M`H}y|Ak})3rO?m>y3}%B_RhHyf{5iZAosF<7&F-cO+CTm^r| z3=rSZu_>;`z_bAr`wu1``5dLq;{#VOzN1=yw{cMxo;7rk7LYY~D0zj@2m^R?h{Z!b z3SHF!spUw%UbC7?fM)g|hLW4oG&jy4fhI~|>{mV|2i~0RBH1OqRxlp8$&n4qSp;B9 zv^UP3lssv!2&40>`xXX1-fi6D_JLlQA+9z24nMU9zy^fosZ&3W>u{ic<^Z(j1ueLi z1Lw%V>i{h4oNT)moPC-O_W@ki^yjCQeybAO=RQ|k#^Ae&#hLi;3|)V}=Bms}rYT2f z(0ZSxsWT-UyhhS`&8Gg|6E9g3S5-%5DisfO>%XZ03o~Oe88a>ze{DoAK5rhgWha4*|dG!jkb(8z1}<3+GkxtP?F@rq0yu> z06ZUN7A=zBG>6_UKlX1M(^4)(*B&R)OGpomSdRf396IRVv@3uN?~mzPW*|Pap}m8C zUH2i#KwyX;Ipd6dBN3!=1+W2Ge?$LH%ym&RX~Tna;v=Kon{rn3#-|R_odU1ampeN}Z82KD@>fSUNz7?BQq@j>W?YsfN+1U~`=m5ww?{nm8OGQz$lDYXb zwkxy?JreS=R*QQ#Xb&-4p6;g*OFs*a?`2iI)n_%cqpA_aZ||q2V;Y*MOABx(+xPsC zjoS-gyy~TrUl@4HyXc*K`a=KjE)DUyH3XDvT`Mqdz<0T+-SW<+&8}vW#YSS5;stgE z7BLsVjsa=@(AKlg>#~1Xk%BOhG10+7*r#EddS0KegYQ0WAjxgyD#$uuRziNtKYWG@ zU>I&g<`K%V*Zr1~WP?&SmlXH$g@GOyT-^XqK(N2ta+}eRP&GUH{v|7pzXz);lH~hA z$LLLK%xRJ+NQc*Tb(qwmO0-pp6G;^q!LDTN)JeWbmUSloQ!VJY&XtZ_oCzyA*AFPUYYRb9}JsJ&$Yy5pVkvHzZ_p3yXxO<)#FB6MApXtu)&yk z*su^lUx~%Kwc-hkc&u~-kaKX9h2}iWWE6vr1H>XK=)5q1bm|OU zNNA2ady(YoZY17u@D)BDl50mhz#XCl6rg&tIF}<%?5<_xxeD~9IFtK}=w@a zAz8d?8h>;cXq&%2txc5T#8^j{#jS7RtXnfM#~gD#4>~~*t^?hncL}ex*m9h&&Pe_G z^yf%*lpF>{);VFncbcv*wie?QY1yW*Y?>x5vznDO(tt4Ksysc&Q1WIVNuAjNBK!rD z>_x0Ph>%7_CiPnWi@!S+3#2c4m}etVx8SV(Rg$`^o!9kmZDRuQqn9>wMaOmD&R{o} zutOIqEbBTbx`KV2X=mOgSJiGZ3UtP+d3YdhjIPh8qMa93K4}o@J2boYi9n_Hg^K?n z5Ar1gXn7dRK-o--PG@Tpo0g-+rsQX9ly2N_-A=fZ1Z3~;8Cv*v(U~!^;H=9?z|gEb zj>5OjkGtp?%oU>3VL>N(xkwb|I;P9IUD3zA`q}bmxaZXdIyjChmL4alF<}{nSkeI+ z+&=8|}x2eJI-3;S;rnR7`P)DnN?_Q=PxsN_8;I$-CLy~MYu;$gW+%8MmE zk^O2LS}qS^ws}?)SwW%4LJ&79uka%O3G?A43}s)^xFrIsueC(kXKkHa`0b(U_bUAc zuSLdvGg<@PjQ;588B8QOA;rFDe6^_^hIW5HE(ZnxH#Q^>>p}a>i>0e5p*c!=0RZTg zI7sh5#4En>C78X(^w%*^wJk>S4L-ig6Cy@hZJ2_a)ahRd=aLjlEX|?Ip?37zinumT z*x@4DiKN6Y0agSdkvF=k!0@;IJcD+IrajC_oWIUfi5QKLRxeD>9ocBYKucY{Q z-GxX=AEV8g!*+m_$hwwemEhDhC?x}E5fb`T@S1q4eafbk=6e1H<-b^6>T8#QJe+01 zv4(a8grI(x`n_K2eu{rqT+z!O8bM#B)N&Bz5Q5H0nkRIEet9EQjP;VmzHCqZdQ4en z8nDKG(z!{1v|V_f*;GKpNO(c1N@Y5obn)ra3%G34XJ*7LzH5)ChV9q9hv@&rdZ$PXVe_&$ZhQv`K0lqbq`R?NxUL#e#{nB>}>amBzuj%|MS850n!c> zN+I=0*9t*jpP0unZ795SZUvhv@O~L?5eX0DJb5%Z15!7zMLrrH@?IC4pPY7VCqT_9 z@aBPV363(G0o|5nCC=mXN^#PfS?4G{vu34^E8RM2j>**nlTKio9t3#Frs$@-MajF3T`|$+yB4ySP;2Fi#b-4GIvv08 zJg2M+GQ8sGcNKU``spa+*3)gF=WBUl?SVE-8mM$dS-!17)B&=J91OH8t-NMD*vKH5 z(X0tkIR_fmHiLZ@@tQS!H#H@Uk@Ye1Cjs-vKLJ4&UV{45&kYVoX>MyrcF1GwI4khn zFqBbb9)jI`;-eq4cFzl4rMjE(=e&_NeuFq1M{lM&kkIZu+d^ZCnELZ;WQ$a+pfjJX zXNTHPTfJ|kaV9&%Ffyr@97Nt6IvC7CIvf$K_Wk#*Kgzr5V*ly}I&U76Kr?(!E3;^n z{4WBap_1K))ItLvFUYGsy&)7_>{)y0q`3J^;Ta<1dgijKK0b^+f=XKA;wfI(>BF8~ zBc@$%r%x3=v_k0@L6nyDr*~%d8T}0TcqHRbl~Ttq`l}P_*mSlO!J+>#i~nyUCZ_bn z7IK1irn{xCA^dpGO6=hVd)>P^r^Yb~E>wa0JpOK>29PXAq-WT68Pcuzk+gDJeK|+S z1fZcXhYmzXk7mA28WIyf{U(1z?F+f44s=83&c}e#k0ft<8;k@lkM)8=z!23YC?z8M z(3T-3XYE*;_I(I{E*zkV8;x?)ITH1}Jr6brc~w!jbI&yCo_ttyEyvraBx-8{(}AN` zt*vbb$TCbf~4Y8-?_ux>F9SJw87!{ zY!B49JXkT2pXhUQ5XoRn_-%E^aRU!K&?YpO53!>ck^hwt93vZKO zNS&!Y%sx-gb|`ZOj3Z1u}uq4Tro+p;ZymK2)RXyLxRW-vN%*>v+uiH)n90 zfoGm1xf;F9M!&>R!Kw#%o-I5z-b&eLlkQu*kgRMX&Z->TsAo5Yr#yPGg&mk_ciWhJ zheKpGtIiDbI@1|*xo-V>-&bjv_Uknx?|{TOHG`d#bgM`0%sP&>Gt4#3uI9mhuoS-{ zNq9bgKYvyjjoU;3)kr)ihVr#%lx*7vAB{U))BHw$a_`mjr%2(6+)7paJ61dESQX(k8eOk-=3G^%;6+qwdb^w}y!j;zN%z_Kp*15LIrlHLRAM80fFQx)BT# z2dBw|nv_q5?z66~cE7dR08B3;F{+e(Q3V5%RG$6pY^rU>5M3|nT3$o&1XreTjJeJT zFa#evFKtnn6A!H83sdD8U}M;L5W`F#AMhA_Xr4p6OoDPm_1|`vG!7>gmW2Srtog7v zT$%NCD%&^qUo)(ov7@g^iO8sRlDjcepRE()7P8?U4&{>HmHE6T!2GUHX-VxF%TjGb z>}je$MG}doq^=xlXIKq6e(%vq? zR08V1?;+$ybS`0sc&7A8ax*9|#U`QtUX@&PV}2=?c)ggi?3Ai*Yz@1tsDR@0*W;HU z0;`wfJxsXPO9I7)hri!KZ}H9|36k}c%}FV9O)JXR?*#1wt!lsC*~==p?s`F6IA)tl zK_|t+?_(HU6Lz%)^=^q+txj#uu`+G}i&rIo@9-zU6v_BxieugNxR1;Zj1&m#JUOjx zX?8(1eK^OEy>Z#Djx_9)g3uB&#VH0ZmHSWXf0e+XeBk*z*-Fq)^t!*!~l%F+? zSZux(B!TCSkkw4!4C1m-`Op+rBt*?ylfsj=tw{y*eWtD~63=Ob?y@;ex@>fN{6`C* z)Bd7vB%T!RDws9$zUxvY;fz3HN?V=2iU7s_e)h5x(_W?atjBKKg*o@h>=KHu|Jm<| zaTZwIQqE@^!zP5-RFX!mY4`_`eDR{|{)`quJNi7Qt=fMutA1lF3oZsjOS#mgUz3~` z2Ysd6qDdNo4&G5P!k>=oO%%c6!B68~sd)&bj|dLXW)M{Bl6^vS^B32!9Cknv!r; z`Mb(55Q;N?TtvEO)P2kMUXhq?X{X|C^#wK6VZhT-D}-FNDR_RgULx4t7^ z`_{3(-s<<#xrEw1k9mo<$^y@pm3S36J<1Q&prZHkL7u@#*{0vkewY+zxji z#(YFI?ly49x0x)|`q-j2VaVai5fP&6R*RkJQmTJ7?@5m3PEg_M$rOf zam2WlhcrTQ^h7Th>-KbayYtiRA40EBN|Q>J0A9ZS^{LPc8!qvK2#w@vnfS~q;{$z_hTQFgxmJl~DkqH41hmSftvNPoK1T4ptz4YfqXcvu-2i{{uZ68AtyCx4tZ4?m>}rE+L0S5-+{tA#(~ z2(`-3*>^_dC4KPN&_&G8%MT3hj}}N)``pJxlpXeRB(;oC#kivfm5FRx&r|<6e{idb zSh@VraP%3G3TL_ec_V@)wE*W}p`lF|{jF@@1r~583LW0~<*A?ysdP98Lmk9B++kK> z;xjHIYI!%Jmye!konkr#7wj8*QMV5OXQKAaCu5It1y987YG0tF(!F=!7RhK4Eku1hg+dw=~W~rc#t)@O^6Va{2vQJ9I#B`iJAgo|XNy`OB^*0s|QOX=PWZ z(;yfl1I<#tW){`Oi>&p!b5OQ*jHD1E#!9H(M?On&e%*XPU>rY=pPN=8Uh1-4>N410 z!jZ1}ryRebreut1QP5)$!}+*KPH#sQu@G3psg+A^`-i+PPPWF=+ipQWweg)&PQuO> zmurFAW!e##B?LVKiPZR2q(hQ?S2N8Em~3B!xpW*2Bk~%wkEC zTs`vkx-t?cWt9M#YiljB8`^}}Xk!|e=n-$qJOf{0H6*p{<}?*@+O|?HPiRwhGjslU zk@O#iPK@zES|Z1+gvDoo%VgS0Nqe%ke{x2(GM1L->BFI?R0?IFjJ4HPOd?zIT-G8S zMnx@M>2@n6vr<7ds<1$`^L^e4PIYi?`x2R$HZ6OxI zUiESpj~lIuzHn;el%&h^iTQ>-tf(hbbH*3W*b3p_ncDQ2%47))WaYMo*_o4Cr?AOB zB(Q8xw@CwAr8>TQlp7jZ#g*Uio9K`!+KAxd5gF}?ZnK$DSxqFQFiKAc~S7y z6ft}*gz%(fbD@V_HZ^!un186xb|f~R>r612wnPXQ|A%dOEgpkJL{4mMc>KlZS^D z5vt$Ff{MWxU5g_ZH+IxD?qSl|>&s4|9$0$zGcgQw(R(h&2u?h`Mz!2D)}jl48l+zQ z^rqeNJpWEaesvOnv{)63Y0p-GG*uSP=r@K zXt}bN(p_yR;zIGrH56wH*>dB%rvUbPks>woghKLizuho9UjHB5fet;+Wy)~MPyFe&Ipb+! zIFpFtEwVvCK`)8XHe2s3$>6>60ik~Xgj4mpTQQ31{A(C3dzItBj;>|KZ;-}?wcxJK zkakK*fN*WuCApOA;l+51U#oEf%Kv)ZpVm>ufDSd$UDR|R7PV0Ak|*e(2@^p(?sN64 zsXaiLaEP#0xIR9by@Jf&io`2OQeZYyk%2#o~#lB4*OmT6r}bQ>6Pe8Vh~sL4_G#YFO`bFik-)QBmsMM(`S*QXtKKuOt@Y#<-rW1ywse7x zocZDLrvYO{Ab$M;J5BGy>!~?Z6@SWF{V`mnuPT;>@a+jN8@}IZW!6cjO4c~jr)PbD zY8kZ3Lsn941YP^SXs}}!<991gXZytNxurj^*B}?1a{7|F3VX?%jE}X{dv>e0j8J$X zK$7(-g_+P4o?V6qSFsw^o3Rr3KCW}}`x9%#dziL#qD4u)9KlsSnSCqwPFQ0HTkSv9 zn=K^Cq6`GM0avOw>!3zAqWYEDeGx}>;4%Q(S#iF;sVwLq_u%CuR@LPUz)!Y6z0HRXp8?22D=X>?g#Ggl|$#!>-vi!|;tP7+m4 z48PChmPvy~;61<7WXj4S=Hbhw$;jk zGmU}STvyhpWiAI#m6YgXzDq#v33H9NU+QG$lVg1pOE0{aSXFS&V_9;?6wl`73JHcU z%*r0i9!rSXbH@^bfkVy|i?)*;SR>Wx92q>s*gTDL#~^F1olwk{zE{~)8bxn+nq>cl zfQd;m`IR1UsGEqOmpGn%UC~YJeO!Oy`)ad$T&*onqZe1cd~d4|5+ike7NE(PgA0K^ zW~J4>aO2@Cho%fvzp{csxp}l!I(}JQSVPYPS-=s+Vizh?bq2>5nEJ zVa2v^6aOj&K>?s=y~LY-q1TEL8opK1oy+I<%lGz zVjf#Po1XLDlQ0<{X~KeqyCl#2wll_ODlK!HmFe#eG#j3Orq1rPS$f0X zszmCXWE3Sn>9tji-KIKwNX1K82$vi@KRB&PJ9Go|AWs#Y7gsU^Z4#~=!X1_3N9hC$ zSh*%XhCWv7QOTmf(eE8dgM3xj)MyfG412|>iX(`_Acz5ntq$z0r8&&Wc~jQ@QWx8K zMGQTiGcM!<&L$~HtD+=6B=ddYqEf~`-wKV2uFBLm_)N}}EuL-bOJ+)p1X81TDp`PZ!r_g1s3slk3u$LN~Kw=AQu z;Hu{mXA8ka`30?RUKTA(0BtQ=?5U`TCyBqQImN zEe8AQPBuzmpsmA?ew0NF44EFKbmjt1NgNZbHdy9lf)9!}P@Xr4kGW)D^L4ba8ELASKPVsNd7D%0PuW`SA z=9z4bw{*A%_nysnxI$nr8v2zU?#UpwK(iVnzcGDE|M1*(q zc17O@rI(*!;d|&!%H=OKD-W;7LDjZg*?Am(%A&sBEWKvugq|(s)hfk?pi}wE%Z#}n z=rY=OcLZ6v>ds{T(TBU`@^CQ)=3@~zJ{eyV8c#T-z%NHa>#-16hR9F5+xsS6_Ur|t zm^{@)pjTtpLz|E~29iXbHxW>)r4Je}K#vNA7*9+xT*q*0=e%s<@&WlMhImA$#Lih4 zl>>fU89pG%2WTCm;InJpwrwVYd3gkGhBNYNr^G$$*|bm8e^ieFa%x%|r1Boe!-{g3 zZ*n(`3k#0-3`3k4-XTHDzf)~WbaPEd%kxz(4QJ!$twakc&9seuPaZW##{F{{VMmhe z9^x_`2@`bBA%$0RNj-}pPTs@ukQGh!#Tmx$@qtwwvi`&G{z%Z{NQfCEcte(Pr9+NA z9A7<_HPQRym$5k0=-i_!TTA>OohndzRpNxlW-=?V%6cW<4~b{M(tEUki$E7{tn%J% zT)w?2|MdUn63JLmACH4c3lDaoK?|YbcES&)9*Y*!o_7g}|DPa7P82AK+mTvm*=Yfzda5;spjZa)_CBk@P8Tae=_H9XhSsm#$4+27Z230 zf<^0lJPhC!Lbgg8xy1qTP~bQQ5QhNp=se(~@2Y=!`F<|Iu8I#|zWeL!N>c=)6CZIO z0Fy>{{!8&AlFFgU=?^FdkU;IDi}a96n5092H+qp zB3ESp>yT9si)Xm}`eG|g-=SHc=`f)bKgr0;8i20#9+#jEf3arTp2Kh6shei89_DNR zw+&!21?+CYrH>kaeQ+d6pjosCOVgI&9=mLZ#WC7i$3Yi@)3#)T63ChTssahF%d>7N zZh-<6H6rZ4JO(M+k_xb@vPm##1C2^SyHM2be%8%-)?$x_-+PY(h%t4dv7hH&Zr#l) z*#7~btQkTeIAOAoLHnmMER45YyXu%l3ACZJw)-_x@4h?Ed9D)#9HQoLBn>=Q6HI4a z$GL2u5eW}r{?|e%01H84tH6wPz14EfvE7WE`-4P95ltJnF1{`j>f0SmBq=O@lmf%| zzg(sR_95kvO9R?`nnpZ5Z{}~V<~wCnTP}W=V)#=-<>#`_I#?;P=;db8T%2tDT*xu- z$OD0zbTJ#keNPIV`+jr_RhtA_>CopJ?FWJWfG2;I<#RZkt=16VE^EiIpqe<&&04*e z5|I)HYTi&dx| zUz^W=wRXl?V3ohcAR0a)o7`mrFu9vx49YlE^zGJOtv?uZ0X&7fm^^AT;K z_ijDwkA}^nNgv+xD@e;39ic$}M(U@IR&Fy~(Tz5XdJ@LGy{(adz4;4?pE>NlMpOpGH^SIxZ zsq1C`e%~!Qg`*gHvB`IDI8opJ0rWTzOm1!RqE|d6m;hMzyA(M-p(jP!%|*$^{Z_K% zo*Y<@dQJ7F3|b2ro7cmEe-Ovu&gG}r(Df037Z zC`|a@T>T-`4^kaJ=n~Izfh#YDkf}djy8sw2?J7oxq~3WpL9J!Jt*+yS+WVY8xR5i> zu>Hi^CT3jE3aLV>Lf^nbD0z4B7RJtpYE4;({6R*>VV(5 zpBP4rZXDq+9PP5)}mQmgSa zV)*_mFll15JM<{S_aso1*BDDRTKw>r(Toe*5hbWBqY_lz1rdC^gZ8kVY7S^~-ba&EK?G#5_9Sb3~!F4Zk)mKlAR7~q@U~Go-*!-NnL&gsWqH@ z^FC0iudpo)jt`Bx<%EW}5*^u0sPNKPX@hZF}Cp;>`<1>s>c+ z59VmOL=4~=pS1?XU0^YRJYMeLFgoJ7fP+%i3H9ztk$B?w|m)7Dkgd#S4wHJ0iz>vImss%S(O?eS89GIQOWgZNM$_6Ya^VIXiWqHFL|2Tl{n zRWp&@!Ivs)O@50E=lcj=T&&;OVp!j0upAA;Y^NQ^{;E|rP6rGdFRC-*DQ|mVCB4IzTIPfxzhNqohXlRF6W8gyf0FXSNWcIBu+=A z;zh4}q)hF--YydUVkUoClbXl_0NdHu@Pu1dlvxVs(J@ZpJ$-Q3{n{pBKxn>6(4hH} z55w@{mf%ywdT}W>()yV=c41@|zdYF^GKgQQlNu)(*}Vy8kw>|#Scla2#yAuON#KSv z(Re|H)3MPRBLSQ>6K^nKOK&7i@CuaOrtNASmm*jRh1V zuV$~}sIr4xgAa*AL*2=>ixeNukkGv6ddAVINxtwo5ddnEn|@*&p9eH>2?LTV2GVGT zcQNX`?4c46;*BX*I1A8#;}LdTY-XikZn3i{_n#&Rqj^t@Ln`pCeKCyAzSJe76Q^S!I9pPmbQxpFzTkaciQ@-V zrd+wv#EfU@l_K$z{9QM*^H+vWr}!RGeINKupU@7uLoZjsM8MhP|6}jH;+pKfeP0z{ z0jYxY-bH%vpcElOKtOsIDG>sM&>IkX1{$Z^4ey||y z&hg=xzK#H?NR(BoQPxnRsz`nIRE0e=&0Q$sN(_b@lQwgqHINy#>wY|^r z$s`!ST?O^dwm%7)olaI4Gwk0#$1_*4ZP)(pDL<7$UNxp}>vl%cZOj5!z0I~o#dEG= zOUa1L>Jpa8pRM+;_V3K#gpQZ*nRWcAXurnRxY+hqN2MkoDUZb?PRd;eJn3)U!|SJ& zOK;pA`tUD&uz`T2#>m%ys<&w+0gPt}zh-{pj#B|%6jV7px@U3GeV)sf$#>6HFQk6d zP-O=D)JX~G@Ws0J_uLy>SsvV(ZcQn)*A(Br@BX2Lcp;PmP$(J*;z5(AXO1A7rMF+F zn-G9BZV1nBZKuxZl{ zXnkd>+AJweZr^elEi`>sT#(Pk^gJQl!vdHlx2t&GrxPA@H5o+mSw5|S9_h%M8!62o zp8uOUr#qL|(~e$uk)+$^z0)}S=Yf^tS6*<^oPz0y64I*#5T*#cmLLfjIU^56WET{Hh70%T)a(I)|Nqs1}Za7oE~&t+$K+O zY1TA;4%KunqIMrw)cWh!wC683)(5kJEuPPW@`Z(JA3a=8iw}iXes9_rLWk$n78AT{P+o zKhjF-{2SR2H36k*SnXdflP(zMmb;#@6KTKLX-T0hwCSRy`T9_uz~_GI=!I+_Z2Ye6 zLiRk1*OX10WBX9xa2g+vLNC)*PG6;9=u4Ug)SbPQ_Dj1s@fh}0_7Zlg7lhvCfyI-5 z#NHu}{yD!*)QIJ~?jHY}q)k&Jo@>OJ_F^d%!&y@AEq+OM^Z0D2+sj{Es5I9xkJ-8VV6)BBfdd)3@KpCwga>RE^7TNPl8tdsy(W@fp%R+l2SHz+t!TloZ!Xa-rC? z4ISMJQHeTZT*pCw_D^voJ3dQ56#=Eb#1}vv9fM%=M(zqL-T}}ACuqdxvJ@&YVVoDu z=0&_bC^o`BNNk-O7Lw4BqVpbP26wIjVCr|m57w4=NIBL})|8w3_HZyYZttmTWov0&YhOV@)(a_DRtAg4p1+xdTh3cHMC(4{(8pgcN^0MNnIlUy!Gj%%zDLu2g6%C zPO1zjkk5aBqOQxqZT0Y*);)0}f3E%Hh9gd1)a|?MbJ*8;)b*p81)K;*E?Lv*fB_0l z?ebv-eWCNra_?#*jQIHHpfiV}t_$=D_Qn~4qiRj>cP@-{C&_kBsr#NO4RVhf`7Q5B z_xJUWR797qXZcrnn=Xh2>IFqc;KhL&G{zp2;Ff=b)$5v=V&!%k-Ec~m5s3XPSrsO3 z(wWCWV@!zbqb0k`E1cdK1~CUM7#b(EUB~Tg)n(!)k^&U2W>;f*=Fb)c&UeZ-cBl!d z^MO(=5l~x7oBORL840oklNIu6(RQU#E~Q9{4`G#}`$%W1rNER@kj~q>hHXH5&9nUb z#8Wh{G;20vjkG}1ayY}Mz|=Fv<6@nE`Z=jKZ*aRW@`@W@Lpt$q3;MCX=(k0zt>7*}3oE-zW2;Reb~ zHb1&-s#9yKeq`gd(iU-~%}R}wJd9ZX6QhLC?DRt>X1yN#PG>}S3X)<(f;uz6dY$H3 zSlft%bDvZ*(aQbK91q}DnJ!vVu>vxuzk?GK!^t-Gi`r(XvHUVm@f`k%&%&s98_V%Y zLsbw82Je~==|m?D&IjGyO9?qxwfue#|3BcJ@s0&Z?$px6#o)Oef6+E>=a(&OS6}+B_Y9w}{9Xs1TqQ4bpZL(35q9T_8p^PDcu2L`nk^?> zXf%|_zYVmNg^}CJ21yp`Co^trZINEFUv=R&Ly4MqW&gH1r#1$3=N$nOjn&WUVzv}- zzw!R(>$oOKTG5FrFWXGOO|Q8$4<;k_I~Od4CF**a<=W=G(AP!bYr=*jsxdmPh_wmz zrp6XU2CwM#B}-|s&9Yok&^5_`+c1)r&E-#8MR?r2;$T8phP;`|-Y_x%BWVe3C&XIf{VKyo?t-+LHdx-;zD)!0?!VBtxY4mSK2=5 zlB7(49;dGSopUC+Ph*-n3MtTmT8&@CjSV5E?tzv!*h!k5RpnwDxz-<|pAz4*S7cCs zQ2Wpn)#$T%n1Y~`3t7O?s4SmWLY~h@y)}A74awUVFFP@@Erk8UvY%S5OutaM(FnPvw%!T zsZ}{h|N5%86SMpko6gkaY2@bM!#!H?L^)FU#)^UZ7>npMpVYi-$0?Pa55 z&~3n3eI^Z2sT5L5mO}i>_-gU?iqTFpn>G@|Jk=d(B(hi~-1s85gt)L|cyvd9-*YUY z7nUhJF)fdiAKZW)<*^7Lduc>}1m(blD;*OmV7WFbvUI4n_;7I{%x>fKTH9lo$|fRk zy}x$kFg1u6`pw4t+0oiL2g|ue>FaY}ZB&j(`MtjzADg(PQM(AWrT4C4?awmP!Q0v0 zhB3B(B7MKmpqCAckbLPjGB$%X)t^M-uH{`^sJ0bc`ct5)owk3=C@zhqqxYkW2EA!3 z!Gpa@SI;wr*YgyNv4mnX4}=g*TeWnxkt1_%nfYf;ALD8_vo0qh$y`&LfEH603%^~F zK?!7=Hx(^AGq(IMw&Yw!Pmm&96bQAwRp!;S-NXmj3x$)ZJoOt@*#HGr7_KGD%x-Lwv zZ-U?DOHor!(A(&OA+eF#y6P8yqG~|>(ieBo)ye8XnG>nQSX8gmX&En6w7<2?$z1VT z_aeVUX1QvMAiEy2P(+WcI-M5$^n}zOV1}xtm948fF56-PbY;cFQ~Pxe=$P{zYsk z+1GHY)sg;Ge-6gPYBSXCNpJ%1yBCFLbyq{@Y2b=Y;C4DkzRBy^i#Z8(4Y8czrZp2I z<@Dim++uTA?eoP5ojmO@onrT*-?dY=AJiiHIOikqKs4U<$giIk$0*G>eU$jw3%Rr& z!{!W5|9pO)3#z7-h!-}@#-StVJK&$8|D;RhJ#XocB>D8kX8dg? z_FYI5PyTs#Qgb)URoOUY#mSsispJL1p!XMajD91ywjiZ$G^lE0Me+MpdSD?ueQqC9 z6jURRti15{+8tnxIBm@OeT}LfKq8W=!IFe9dRx}F)jAHb9nn^UkGnx*2Y;bvY8qw? zZ$olkPBGT|D6j!DgR89b`r>SkGK;GkV@<0SsM|5AiOt^^b+>XEN3>-zoc`vPATwS4 z8Z9#heR7Kn)vk!kq9~(Vzq$K2;JTc24I3~c5=FV2C7r5e6oax0?+p+mW@C~d)@<$L zxpHOL@7AdZtRu92EOjIzIf48EvsxvTq6XI*T z!?RJb{AG2q4Ag@PCf`Pp&fo-Y+qi-zjAU#4dmssvrLCA9O=xVmB%U+#HkSeF2FtlfE z=~uB<$|z%RlW9K4*K3qj!8zM@sDlq=h*w-V&_9=23S-Z-+7gDhqpKo{KQxsc(?a%D z0NGGYT6gINypTh9pd$wRu4rS-BmwTLDlS?@iaB%L;j$F%6@uu85sdB{R+k2$b;sbY z!GUIk8Wu6m1AN2u9E%Xhim%6Zn2Q=rgX;w>DJIIm!T1iN8E9BY>n9(s

    I?LK}539LHjRcXfMx(1nA#Y#0)uio(&J@TZ?NEro*}UD6IstU52bGPe*a4w?;T zfOS&EIY_xLEH%s4c@x#rcnpblSK=WAJ!N_upM7Z-w$vXg!sJ%+>_9ax?CvAr>S2N* z=UidZ(42p6f9KoJcX<2WQspcwf10v>w)Q>jeqf_cSRZ*z4_O6uU~D`>iHRa+F#;Uu z9$H7@SO~CoX+jfV&d$}yYA9k}?I!y_U>IQG#ETK~RKe5c3VbTQB*?Yto-dKfJfh#{ z*`J^Huy*XGF|a7q{8QKsiA($tc(WQb4iD;=m73;ak@@hH$%nt)QcfYz)HV*kLasMc zE{efjf+w)5OCVG)(}V4Gb7Of_?SNdJF#m`-l*qbM^ANnfxNbArO6n&5vtX_e`T0~8fx3{ni+A@6U};?L;70IV?0SK!oT zoD7Aj9`w1MK;M`66W{mG4%U(w;@Gsy1pV4E3bx`q?zWFrV|wrk$>n7BqX5D>k@i?l zKFZEgC+Hv?q(m(=2_ghf^bXABmY<3En?vFCko7sb@Doq#VUiK8uEvs~I8lU{J#ChO z6%ke_jJ5^N$(6r#(975{DfgJRBy>nu(}~jew_WQ#eknzu3+V^6=&o_)>+)cN2+4P# z`~awJk=1G~B&l9)pxqmvR}Pfs!LlUPvWcZpy1AqI1+&@xrRN)^r>&p3#Oq{WY&`RN zYZ%10GEhfw;p&+WUlN_p z&;Xqt@9dUz1im{1iraj8;JuOn;6>AE0g z`*_oplJtlpy3ca2E93VHNS1M;#SYpZ|F#t7Fo;iiBX3P@9 zU1#62vNTD2Ae$7QLjX1OgNW5D$SGw2L-wzEQ&O#TG^EOZ@2w`4K7l_4TVIIA*2N~q zYXi6cpic}JQC_yb4>XnRKO-`VNzt{;hb1y%%O7gJ;by(Ym#dB1&18FLV~>zeAigeP z5)PTF7Y+Yt17X4IjJGi_TQf#h$mvtmrB;bfdbeyY>5bs7-tEBM4EpIjR4Miwh+rg`2J1t=pn#KZImT9QGrjX74m+dd_e=)Xa}He5l+) zKX+ozy#OWb?FDAfKOgLzoB19a&&|xuhfa1vz3tV)^HG|+2%e|@hDPj`iHKCMdvTFq zcqsCRx}7Xm@J}7V{=xU__b#ap{0l!M@ee6T)Y%$r*gZZpHKgyBXEx$N7jb%S~k0~cT zL;GZu%$<7--)8_VK+?a9QFyD#L#wjs1Nct5nqz%^T-J07oB0-6H~HFrC3V)LI+}s* zJ@_i)Ojb-#c_xL<&Zyw$yLxqqnD&SF0reKGD-%wUiOD6E7FrzbpkU3^#4k1kph_kU z=2;44U>-$~n3{$T#Rw=YGuAeb0(q_ZP<+!}HFYfpBFJPF!FhGA*VZ)K?XHl#iC|LeDyliV04XAEr`@#DxhD^gXd{-DNp@_=JZS z?fI7dT7hleUfuy_?HT7}a5EPczafh6x;inVJuclkY3YBw7A*7#+G!uR_C4lag4C71 zTKM`32J1`@dzK=S>1QhqDc_uRw#6510}Kw{U0$2;U(HC7=utD}8Rt2dVe@6`mCYrb zt>4vGmOcH)m)@|1^|P2-WVVOE?bNcgMyomf-f4zF8-+YR{bt)5H&W@ZEB=jA4jyt4 z!B=d?ad`aC&e^I{>eKzz!A74XL73lded@b`4e%3#r++b7KI2R8cf3Et!o(S+=EZ#Z zb?55Y$9k$8KxUY(`aQG8;ukxg)tNz+pGF)7_=C!^Wh3&UcWn~>T#Xgj2|hx8NusH; zt|7bItKHT>lpH8~pBboXA?w>kX1ZDYm1|qXe&zRTK@e@?H4uM`K z6_oB#E%V04y?nMCq{&*Ni}!oT`juK?yk)zXv4i`)1~7Mdqe^q*Rbt%lYug{)!ue(C z4}5E(m@W8c32IVKZ-)K*Qh~caE_Uv^Vw8Vi4g)puCNu2mLce-<{rNz+)I(!sp3YjM zy5|cSf1o#ueQR^R^{@MtrH3YxR$APpHdx_#gyPOm`>QKyXlRhViq%1+i<_4o$Y9og z=rAP3Yb!l^z|#K!Wg1W&ubr^xp{600b(<)>`C3u#r*F+`lANqQsaQR*l611& z`|YU!z1(O$An_^iqA`d}MFW1$=A>ENS5+d8Rdcma(p|F}xru%z8$148Gr+_IG8AKr znd)PNS3WIf;cvb&|ES2u)z!)y)=c6z5X_UA>Y9EAv_q!Lk=>4V35&|9Lx2_P+!J0e z-`6zsD0vQ@!2&4P&d|0Sj{?s=4bl=W$efSdYE87|NIQxrM9@&OyA;WLy z#y5DfJcSrj_2zUXK9$bFN63G@Qld|>Z-lUKOM2o_`0}^OFYzvvS-f_}7T+#%yMrDX zs?DT}>deZ#hKn0E(cOl_Wk2O+Oe@m_Ww=q|iv8@qErrv2n`gxa<61akId0Ex*i!i-K>szVUrF)?L3Z3adJdF%c(P<{<2~LUi$cp_Q-eVe^(|hqur13s61V1_cImN;AYR(JMGvvw*Kh` zJiYZV&?8LOKtW!AS^RlkMJ~k9F8LQy>Lsj3_|kJs7R{4D?(8W_LjaP*mTAe~O+XI> zy_0gj0(LQ;x-J&QywpgPyq)A}&-t=@MGOnNRnz~=mx>^JaLGYw1dZyT$k{=ME2sGJ z{B4=06fOz+^I7pm;_+4UqA^;*RsdY`?(+vYs82YwPH8UM?}MQaLymcw<@nI@Oz8K~ z`TW(XZ=vE~_DrK&w<`FNOVIVxU50%y?xL}v{oBQ1)ayl~vl0KYzjE<0ke<0 zo!X5kfKzn7u~ly73*@|_32(C%=(WeYB62d4R1mIRLm4&z0Mc3UE*F4SFtw??Oc;$- z?CK?Z(a==r85xo>FQK)jxG*N`gyyS5bQds?5VUu=u^<-7Sp=d0UWefh;R-I1ig~cJ( zYjmv08)6m#O!0;$$8#qJ+H5nZ&GR%pAWeU?Kz8cU>G*Wws=&))G*xmxBs$Du{1Kd` zr7(Rmzu+aBf^A+r?Z9_XfST2Cvp>W;@WZ_wVEt7DqnCiZoFczW^|;J@4)9wpAoYe#!d|t}r-B(C0@j7Gu6h78O%IfKw@6 zn_KActmFy)iA>QkZ>x{g329d+;u@FkQ9^!Kyy`Q$xq(cGD1AN(eI67YgdO){m+61Y zLE}2>@VD?Hko+RfU#9I8y-S$Ui%N$C595$>FDQoNV zMtSLL2r2#9z3500dT?N%2rATLhOEFe!2aM~tG#JBTmE$2iD%wW(cT|aP|mX^K)AX! z#VT!RvJ?|~U}{kX?L#u*@j2FPuI{P}!J81SVmkB7oIRgMrU4XUkjYSY6d+?XU)yBH zwMx56XUm#>m65s+_YEvjnDrR$x^+$~{P%b5^Yk#v8g*=G0+)g=Lu5wiB+TS*Pj395 zQz=4c_2A0JQa$Gb5Is836n4kA>at<_t#;o)-NL>a=koV)4={V=PZx8XcW_Vh0Nu5v zwXO~Vk)p@Dn>$ygxv@OfsLo0vlu-6=<7#Z~uyA&EGO-+@2y+QdcYQeEv;}=sCYW@#4^^2!9Qqf_aHF5?Uepmlkk)$nBy=het6s6Xn9%g zCu1@=+qY%R00P`ld^}#8rVq$%SJFSh()qj%P5E0gAy7N1O9Z$oO#niMpFA<$b!@q)(Vpev z2D&2)6xS}}T4I53*rz>fJ`b!5k6b#GeIcQ|dMa`e{e=PSF8MM=v7Cer?3>T>BIKuz zBnms=I%A^Et?TeHf`qL7b1!E$WYB5Lh6ja|y?sTHy;v7Ak;3Wd=1BH}84yUF|rfHWxgsS*gI{Dw{mWa){8cb0;g8gU>@P&?`KTM}-1M-{k+_u~|z;u-A z3}W{}rBVnmfMM`v75E}H=E0A6@Jy=oawuiZ^Vr)0Qm_a=D(|@l>3=FG; zQm@i0NK3gBrY@K~EhipNa$e*Eh6oiDyB5eaH7=SQQ3$_xL38l0Z(uKBC9~4>lCGZD z;dHC0y-RwVLIMn=(zoRZV=-4aMRMVX)KX_kWPXK z{rOF;rQ=s5DB9O?0-o{yEEqIZT2L7oZ~r`;q}{2a3DNp^5-?s3(Bgzsmy$=5pDbkg zSlLHhE(6fqwFPLi;N`LMS; zD-#c;nVj^1T62*1Vs^i1WAd-?y;>ZiZc_`|@c5JU*RPby+v|kFXQD&GA(R05VP6w{ z^TfZ2+#)>U#OiINDjG#rOHxC&dKar+74%SJ^f(5A_~u)3sB|0qyKZCuagjEnoK2xv z!Zk&)EoxTQx%uBgUh>x?9mCRXpXl>u_!1Qy#~xTT(}~-3Gy5kkK~_tngmYW?W9gP4 zb)dGw@mR@|PwN==wm##Q20qaF$TWB9r!lE_he~FIi6!#+BQfzV?2&pwC$s%uE401Y zTm#x%+4bQBs>ol;-Tj~V{=7_j{RqiluXnF-ApiSqQCH{by92%ysb+kk*D?rJBGckA zl*tvy{1{il2Ap>?l~!T*PrR2JrcqF=m}dB<*;lMsRx&d3E$R&wm}e$(@s}2a9^Ie> z`~jjIi<8ijwa@dwpjy$dhu=ngPiwBl8^!)K58oYdH$_`)YWWFUk~(M|pGnj4v=(NZ z>Z@tgI%;j{PbxxEd-yO%-Gtn_ai^7HcwE7LVLPlXSIC8oW{=rvPfZ+InMK3rOyE@q&h8@@IP9A%Klm`Iz2TqXLh`G~^4Su} z`I-EJQn+rf56hw!1u{G{Y4*SC9bB@xF3vVoQ9)(wS8h5+XI$8`dKDwu$7#M*2TKJj zZ69*pz24#;?jlG2b;f!?lt`4*yLe|_Vlnt2#&ynn?u;?gbyDz6^;vPLCNbso*8F^@ zM5}hzkh01I!9PQdgdio14bnKGG&|H+pHhn+6$2McoDg&=75;lLC#3OYa*myihPgXc zK(K?b{UpNPjR7zVae1?|MY0_CQbS+yay&@@q>dV-Cgu0ht41XQD0lR#J+eI~OkkDV z2EE)OpO5Ul+^sfK3w25$3n|NNfnR^V^(4$F4OMHf%3l-jD7n-=Y=Uj7XQfN3w4RqU zvVjxjus^u>v-QP9bb9*ZJjP>wpJ|d=YIm)8V|hU?A$^y=0zR%aAwADtI(u$Y!Wgz{ z-fI8?IHqRP*{fQC2eSNZ7T@o_N-`7|C?|2hnjQ%>TzfrY#@aFWdo@y_|7p`X8h$Z{ zCIE3Pr)y9lWSq#3lDGqRRGZTg28Z6b_QkY-{Xc}ub(j!`Px0Eor1#LLM{0rBqJ2$3 zdhglA7d2x;c>?@crBd%`reb0-gxG0=aMMIN5nW!J8C-0}FGV6c<#qSHmfT;T z^HENZbf(GCmtw5)HR2KjXy~^K!~nBTeAowdUioCbL3twIftKERv6Sx7AIlsg)>}x< zKcJ~Vhv$la;#FS$rEN6194AaY^Eq7%x+#Nlc#$L)hSfH$rknjTYntwS!hpF^c#C`~ zovQjWEQXcEs3iDPAN}_zQwO}0?3b1ISCl!BQlR_ za3PjE92C>^21Y?Q`Ryzvl4H}+vNx$$)t6&13uSl}Hu6GNIbE?GVEostRitElFQf*VdnrMts1*#@9oA@SBmQ?sG8zr_!2ks}dY z`KZ9UNb3`DJBIQUuZ1vbO2VQ3$ zqHyau3m%Xt<%H!92?N8uW1HW(YGJc2JI$p5&Z#D}2EGCc-3)RcV}t^ExNb|Ia3&O3 ze_FU!NO?A}2b3!Dx%{Tq?w3=F8LfP;{k9uO?po8-&$ATHc3nc?{E-scJN~z0 z4Vf~d0Q~N{XKOcjKSg{pQeX-y*RK^G(5$!eMG=0=d-vV`p-YBm^a%9U__{neoi7Zv zl0l;QVhW{w3DX@qy@qMyl<;P695Fgg5oyX5_*u`PL4Lczy}rM6g|-(;{nt>^GhK$! z+IgoDO>ocbY;PfG7_P~K&$S%8FTsPkm(t^@%{mg$+&J>xNJn&X{HMp^d`p2AD!_Z2 zvMn4&`2rLOWB$d1NdqRFjAvCjzAReYDCYP~(2Gv79z|Pk7dAR{`TsDl@f&2k^9G!* ztk7_Vig~Gtzx_#Zd=4^{W?I$r^!yiC(!|GnXgClXW?3Q*>ElZAam70gw|W=euc3+T zpHnz3Nc;ye*E>SFr@y{%8MF1yR(7A+dkzBoIa3IHmu0U9h5z^^cexiTZdEfu=tOwX z&jPQ(1=OO|7oYOtY#Zji_*QvH>I239NxB`a&GU6=WsaExBlTv}fJU$>p9h_*UW36y z&cHct63@3S*@qNAXl|$|t|FD5Otq|LdD(@UC$g(=Hf-$zPVWY4H2`DkK}WW9Q~H(e zhbhf_OL}ElzG{qzs{;+UX`?u9&0L!2-`!6e+893|Atr-YjRk*Z)X*M`0PIdqIuPX* z3mshdLX=`f7LY$1ozERjZ(4UeEBWTpo6TW;E-uWmdvtKSO)Tgg2O2R>$TElTV zL4I+-t}&fWM4;`gi06Q-B5wtyEa$E(^0r!9)<5xpJeS?np#CVJGg?GR`oK1utfi8j zX;T=373A{z$dE|p8IdmH=9iGhH1#x?eBT$p^l3tKdWxM}s--*-F>iP=xV%1QujiPq`Re9L^%NZAKD85AJT zLZi#v2U?}#VCUdihU?397ssjJq^xoXfj~wX>_%Sg&qRAoBUJeAu-vYBa}Sy4*R2nn z@Q=x4m=ykUbCK$#hY=g+&5?4O%n|Co`$Q}YMGVa7|kTi7={~`QlRX zYHpo643i@FLeV(Av8F>(fQyBDHA7$r1#n7H{4IngY>%wk2d!r5(NomLp*3 zt8-D7&La}hAd&`=qEgC6Sd52P^0ro)d~vZpm~8-c4uVhg7Rz)F&Ifqs@-d8)u2pr7 z`iG?Ui2D>$Nq|8xQhMh4BvjnDINjk@>_ya_#%i z&+~0p8qs#(l^XHb7M=7l*-oU~rUX|$??_3EXVpIJwRZ70L4`VAtMv`_B7s%~}z!FCb+1rkKd!aJs@pASllg-+xzE#d&YUr-i+j4i>OZ<`SLgmZ16gnuBq4Dd07=)kYFi z&19Whut!DBtN6PHZXWcs93_ep5tZK)C!w7>vweg3YLEGo4tJzz4_mI(`ok^oqLHGK z=eq_U5%od;eVQEbGi!h3Flmwos*k5cD@#u~+=qZ+Wm??jeC!jcgoQahHGk?^2BFOz z6+Zq+Zh{oI%L?Z0PMrq;GCOTcpWb2i>$5xsUy8|;DalvgD(#=**Wxt=N7T7}ix7f7aR0@p$dn&+$ZcY*vF^MPyhv^4 ztQ**5lRBMrjemG29&)6xw6QAgZJwrau<&=f&@=iVC+ijBNQ9p`b)dw>Ny!pB`$U4C zQw7(ED~2KC8BQ>xfDj+gK#Bzjua0I$D)FYdDbh+BCAE<02-JHK&URdlaY}=%`z9<0 z=h@h=$@QHftLP>#%|m0@(OQlq`ch!U;E6}zfubZ)n_=r!q}Q)T9eKtb%|#G>_z_p#Y6f{xjDJ47x#yDXG@z~Xg{UtN%R=Vb=Oa|g*!aA8 zt3`HjoYm>qzbe?j10l`8Pmn=ybD`9_;`plvDp;k*Pc|w$GJN4NzsG{>GB4aB=vH~n zws<~fpVPd3YI_G$CHlaLAh0x|Q6lK5wwRVJCP*?9qSP7j{%2XgZ%m3?@EU z{#{5*=?-P?EQn37w@%rA&~U_M0M*VC8&RW81P|68=^2*!p4nPH^LLo5gY?e*=5|l0 z2!r(cyi~B)*6>Mos48av;%*an;5-Mr?6X@|;9=Oli#L#;Lx@O!15yDDq~6A;l*iDGqflFt7nlYGP}exVI#*a#*i^yhD9M z?Yfw!Vemo^pY6qFAz^qY-N|hxC?AkkK21W_q8Ehe(vpc4$(G4?HT`}i@(y@HoIp(Lo|~Z_elx{X)+nl_63%&GRn@m=;_^zx z!ys*8W0A-~1AZdDHf2H4)YpVDa}T6|I&1d5t}V2`dP4B66jsc)2+;z(q2;a^ZO@Zn@(*WI5zW74wa!-;dFl| zq0I`ROj;pVx&Id>Rl_9fJSh^6EAUKNmN;;J%9Z=)$H}7_Z%k5O1r7J%6#1Y{w3V!i zS-u$Eo@Zhet@xvU`53+{pwfFUUz!HR^2A05wwG}2f%v*ar3ZPhKdjrk|qF7Wbez=liuI&`ksZp0 zoc;O95YLuDJEZs}9GBO+k=)Y(1w4C6o5Z}%_0iaCP^D#SE1~oz~xtVv> zv`Q1Yk#|D$2xe(h>lAS0`bFt#Q0vz>+ko+mj!BTd-(XC{0@LY<-Sd*PjOJDE5?#d# z30JscrVKN(XPdL%TjXAhwHA<_jb_5kwaq!8dO38;#%{6vw%}WygN_XS;2^3FA%MK0 zCuo0}TMzmeh1?6}k!RcDG<;7k5w0@UK>(qkT`4Mq?YyxgarNn9=$u_RsjoVjaXM`q zxcb-<&Gzn1SR)bh^{Ub}hw9KU(!}{vjrRA6!<2LFP$#b6=Z*TSA8~lr1oQ$8WD+K)mXDjj*hg|>xq~aDU|nuzj!Q(J z+Q<6=A7|Wfl%Zl`L5iHY7V+sJXxS72T^|8VEb%N(Y^`+;-i+ zl-M76hL)^4pBbNSI**MBEnE#PUIIT-=8^X$SIxN(B<-wsl57i8NU#aAs&EQ*C1?uL zt$g6Z!3^;F)?ti{7s7OI;=Rnq*O-uG(|5&H=ya#>?-Qn_P^Ku#1M&Q6 z5PEW5BO0rK{b&B_0gArbRtT#}>`Sv)d+U4WF;V4)*8)3Ddc7M)d4cu_J3!$3>p{S~j z?BWrNP^`ujgq`_g#EJIIZNgDaF7>oijmF}2{$x>1y}1Ow%^;7GIo)E~scgkp=G;B_bNY`ILwX>Z+1%yzFX=Gp4AAF9ZorHh$G#;G%CU*22r@-YiUTP^3 z^LEgf@r%%!R-4w=syM~*MqXSvPOz(Ijy<6#*cT(aRi-~E_A$HZ$;vD}EbKc*gOmok zhil?;>s3Ot9gWl(^e3FC292sYYvl&{_3LNpn>PO>4# zKaTYcTZ?NQKjs3jZm$SZ$n=nuxdz6)L`06mhW()o2~BD32&-Nz6#`1fZPFTs;97Ph99OmYSDT; z`p`Z(Rig6Ts6bL@*{Fn~{D0Xj_KbI_bDTdYe^IWh znhN8jdy#9XTV4EO(Fsn`70RJ>NO@N>nbkel%M|c%cqBvcueqAQ+6UpV?!^BG*`3)z$nB2V=WJu(+a*CoU>rMnjV-^3t$p?d-26iRj^&L=Oa1@Ac$ ztk>ZKp^|}K=8nDm=AmfsVc^Bh2O`1LMLL6>{{a-;yBWCt-;}MxNFnuW$LnzbPv%&E9OIDC{j)ks=wlrB3kUU3manTH zWX;|??4ikS)r8iE+AYjmdy#JQ^k>PkKKdVY66w9)4}v~MVE-8e^wef!wTOG55}m&5 znMSG2+wV@^Ewg^hm|$a7ZYIs-{Xxm5pjJhd^j{Av&i)>3KK!KPff9W}LRdscbuTl+ z$!#DOT@8o@t>0q|*!#)GTu;C9TqyXT$hX&Q?_WHwPZtS_AZ(eot_`@(DP#O^uu*Cz z!Poc>`Hs-T0UQQor3h@?+jY?i>1A@z_Mp0#i8BCUMV|~cn}UopRn33h-b3ZR&SAsM zyHXt9J2=FpC5&?tN_SV1b1L`>Cf8mz2Kmla>sU({B@3$QN+L0-wR3)tGZfw51W-Xy|(a z40kB^*)@(>19>Q_o8h-vj3=^vJ3aJ>(YMW$NhALk(Z^Qxj{olw|AoWO#H^$I&evV; z0|HWrQK~U><@e1UynmIjzvDWg*%x#FO55PuXWhQMO$do3!Bngzq=#xMc66$AXnDm$|El5|pOY+-t9#AOdhYMzzy>_(PWW#ZU;)ekIpbU zLG-wGQMYNk6so9rT+8_Kcx9mHzrtI3ngSBN(4s#^Z0`}2_~|>fBZ@Ydf|LsP!u9`o zO8FP>J%8T%BDL`3{;k0{<+n^mp4R2dO!*y;8)f&(7)=xg-x?J3)%;QKZ*>-ncN%a? z@t99I*boUXmw)*uK?*9W`OkVZb z|Nn^pUp?X&$N^)^a$(%KT|e6?6m&kYw-iD~JsH6gD1AE^NN^NKxR?9m?Eiez$GDr; zS)=u8CM^B8Kg4UJ0#HDyFcQfrR#@48#>(-(x_vXD(GM&R^*GvJC=O>9upebb%#-P% zM^{IHp?Em|A8kl}Yr^t(!iM*8tcHJuGi^S_GxOCw)cQ~M^u^ipoIS&WZVxSY`?I1( z_uYRomllqFSEy;7)zgjxIiTf!B@{aUX-@-jm%cf{*b#y(;bh@#CF| z-DA(ci4NOAyuTgRBJaPk{>Sf!gY3x*Or`bTK1iCf<^KPUMTnair{iv~IBoR;`ZNs1 zogZ{uY8AGYY$k|PipY4X{VxeEgiMh(>-wnZwC8HCi!7o@evQ|rx`!J6&hPR67W9al zeTZ&ft%A4Uza`g5aG8dkPxiqaMyY04}h9?=C z@;cY_aogN_3JH#rhpz#+3|yhie$w?}lyj~i#ZuPXd)^bq%l21aTc&_jVL!sGLdfSQ zQK!s$25LQdo#p1NH>!%&@qBd}nsu15S0Dr{cDukSpJljp68_7-TPSZm=(lM*o*-)3 z{oxNezMBI|V^R=|+St-Q5i$Dcuqx-OZ*!=}k&EY`S~HckkzXXS~DbJwMOi-#5lR z1_Kzd)?P8Md98b{d5!zuCdBx_-Rj!lOtrYI>4lyz>|9oCO5b&%0`9q&)OMD?^1j?- z@{tOne-kQR8@vot!%7JGKX!q+R&KAG&`#lQWdP?+J;jd@@x2+(Vn4xVUzSdR*SR!a z^1fvIbrmCx^Stx6i~1g~4oE1D;EY?g&08X2%v|g=#SUIeBkOLRsi(M5bRXm|@{i99 z+!3fy+W?ilXVfc)4Cm?NUR z!vTYfsz)83Jx?{C(6dv)t64ums+djyhD;YR$Xdmt)nI9jrM#tz#`2b`mpWz;Z`I&O zXK-FCkj!*m%-K@2w;Xi_)C40Ld@9Pv=)5);ztzUa>K5*1UB3bnP0BKWPFDcg7V*KD zh}ijrx)O!h?eCEgN|%`q`6bswbkND8$GFc`bPSFoG=t=+-08hGSPaqOu^qz~NHk;x z);@E0Vz88q6001bUeCMCSz`uVYmaznT=n_h^#x$v-(P~M6^M<+;4X^hneHF2Zovj)#T4`XwLZ(;e}A_Sf}5o=be` zxmPLAk!r*2{Q&TUUD?%Ir^^*w-v%#pe*Og~^~3de)dN|RMko0h!RsAO@T~A^*fWn< zFSdnM4kk6FX5#SCMYtIkgzYlcj?G7YXi>}-ZsX#q)?Dv&yTRexNL*VUxfCmL;7E?X z1fc}MfL7)%7auA(vC0+jE_3DTUEj{jLz=PT@AN(QYY}bk0)c&4?u3h?CjA?HAnVXd zthf$&J(0=2Bz`etDto0?-GnXICU!_r;@tS(bC&p zzgmmtSkS{;r$Q{XJkQ{mm8-NENuNQtJf4YJE6@lqKpnw#VX9qC5_@z z4qGvNxS1}BU%doIep)_L9{aeY`8&2j2r7P7yv1yulj#-Q<3Ctk)gwOBqV1bo8}Q+Y zeJ%jjrx&wPEqXa$ZO0_l6eRN(Z&;~p+{Y<?C&iUYzlLB;n$90GQmw3m%Zt~V{$VE z1sh3|r;W|beMv*?sh$_#a{`}yEoVKUiKi3{I{VMz(I^K9c1>p3M?pOFHayL-=hpyY ziWn`;1WBJcT*Rucy1fl@$`~>aGeR>av@$YP7i5ALik>k`(vQ%bQQdsgk?uwgG0$+; zSX=Qa%<}QLD)hZ6vgJ=qr0&1zA4}bmRf){5)@jntZnE?I7(i{p{|{jDUu#ZAf(*j& z80}JCho~nZB z$Mr?e!=cUa(0KYhLjY2P(rnur!-T1jNa4juxF~&Z>wV|U5$DnlnJM4TON4+gTMzd= zchNzeKdQCjcWvSg(hAR<6Y+N@5O}M_rI_Zd;T*G18ZN#ndgS*rX zyyUB&o=qI}-7>22^+wWRwKHt{TQtg^pCLdgR^a~7Q=Wf;(~4|( zGGEnT9v5?gdd>?%cNJu{=S$vmTaT6Rj8kIQPV8*EJs^jdra8HUn+P2N@u2xGN-+UW z=Qa+@_`C2R38JASnQp7$zqhG;?~XeU&TX3aiAHnfYyke^hiw`DSEm2}T4jH4CFiI0 zp0lnG27+hv=j!39)BD>)Y8=tC(awFZXL(@QzHR9Fv>~|rpMv#peeSie=$ncIiJuVl z7Qu(R(=NCx-J_0uGZHBeAVX&3$wRjV=;mq1`GTQc2eL6hoL*$Ytw=E=iP&~L%c=je zUH%)dNcd@o9tRYcRJ|g-g%?(RMTkq09R@=Cz>W`*r?8iqu`F->C9-J)KWDMqtL!5x zH@NB~CJMzWC}3Ya3gHjp07zeO+J7hdjoH7i31DGA zU;rfZ)AgJUO?Hx&3HmK5yp;BTRZZJR8OMd!S%YE0{Z%nGgrprF$BG#z@Q+TvAq%ky~O|g=%@N+ya*`sYY##vB+yla zh+9sQx32CKm#e^5Qq{i6$-;E}xz9bfb3*Hm&1HwWb+8M4=&?1{t=BYhut>S+*OpZD zX$xnqP_am2j)m=4yZL<9+kyR&cr5I=sVw;Qw@#(dTDkd1=FcQUpOoW3YTLH!k0w1^ z6Ng2GnX|poVn(H<>fmLgU=MGh1@V*qXBpznM#dh>hkL-jOtC8oD^W$ggqH$5OC47c zX4^(Zy}j7qy|bTyPyCR27Lm4y9ILDuA_5kc^1kmUN^~ z0BHFGbMEpph&_gpr6o0#%A5^3{nbwT5=Am z=OBVOAe_ns(z5m#L+@uyqf-FNH!=?l8H(N;6xw39#!OuTn#ce1v;6~!Sz#+dq+m4p zrK#K(TvHkslLON*h&zrHgNzYc_N-(=PfI_Lb&9{uc|R)%Ru z{L--+H0zIw^a-u;Ygj#A!b^_xcvUedk~QTffauU+N{4>h6zH3Z_7wnTN?K7a<-bsX z;KjB0wm7MIk#^xwtKucTk)S?%)#2|0yGiK?L@gY5K@vTtL63R#KR-^!2v73T@{Wu* zFfk1Vhp>w0fNcDy_A;G2UR>W7N=qUg3)<>_y2u7_FtLFEx2ALahi9pufh91gEjI@h z9u(RwiPs)|>7mvUK5gi`pq*z*+woLGt7C|JpCe2QPo`*myinD(#Ef$V=%{nzR5CSr zAEzzPy%Dmi{C`~J^mt4Xl0w5F<_dmDe|dHk`~sXPjk%cr<2=G2e}Tss5PLom>Hpju z@Vt=+#$gvNUNZJS4Ag%;-RN&(zErP}{=G#Zf@~Un`DCn!zx7^$Mg{18I`+t4nggDR z*hk1vq0SF){?>a51bd+SYgTR{e{C`Q3$U!G@fic@{?hx$1Yv~PG?eCD+<$M;nO;J& z=?f?6lfU&oMj{>Pz5sb9?O$8`{tTES=b)e2f1mJGp!;eGi7pW8o1|M5?YX7N$bMvTn+WdJ`+|`NqI`p z&vbNmI+CWu(K<2d3qrNPY~HU+6TF;vJmnY`9N)|v_&LjB-J$3xGeMdH?; zdA?AL+w(_(rE-}?ka8ONdE$qn`HV`U^3pSg9mrF;=b4UHo2zoW9T`=(BVh8-v!go| zf0Sx7?I{sSD~ zdAL2bbv$(#+-OoiZEeUU``JyxN7GU5@$p625di7wS9_=PKs3ifi7$38UF`ia#9z*$ z`e?+%7q)9S1kejh1J8Zl)0I$aGLhzz8px~77-^iB3(c+^)Fj?;fZ$d(ZP%MT zZdy*I)x$#2Lyvuc3?Od;S*mKFFhI42)Z{6@-rIB!1C-C$zyr$Q*oDoX%u?1s7e&XY z;0r{+k3SiboQS?1wJZl#b1inbu4HF9)F`0Q0F~ z(~@jjJ?mrN-sU4xB93;&@`slVt_)l(D`Tr3oB>L#%D*v3# zNIXuqxZwhYOwTz7Y%+H+3ozb6}l3SsD89dPgERJGhsB!xrLq58L zBw!Zm?Z~`4W$5dDdI^3IJ-5LWU$7maRDKq4ZF1~xktODx>&UXpv){B^WTLg{yC85V}p7j2B9js`}ixagKs=5(05r72?*%p;R-u&m{i(rfi%;xsmKU7uV59 zLfns8O_(u@T)Gn|lk^1KSKtwGV=qus<041mKx%mV)N8u4(N~< zB!7EtrkD?o_})7bH|r~Pw*dRYhIUuWA=CHXy&9egjcYlPVtyF^7vz5c+8aLUhfPKV zoB;r4TRkR6p3+C{JHHVX;ADe;N{?QH<^SbL-oD7iW&kF;T?w;7z4BLR4SGJ!0w}WX zIhRW>sd+L$@0x4ibv7J>F8Q7IFy z^=d?sp{nAri81)euHoa22Y2h*=faD=58l=fUJ?vD?f#(S2OR6=+*ETP;$II2;)-oo)tyi2 zroj*PIMWuIoRwhdJ~z-!fc3xjbqxJ8Ftw9lK%PznR0W)2^UoVGs-#;S1w?^y#je_0 zfDox7(b?&Tw*%m_NMKK^fiKLN8=&S*vbIJ)TW$}U(~ya@Xp&z9x$l1b5H*uPI zLKK-&yf1z;wW6#TI*rM0ChFSQbHqT=n-N*4TWBond&w-54O%_&L+`Ige4BO|7W%uI z58HMNU=j`P@VZEj?t!v=5Y$jr4NZOL_ovNEuwkQ)qN*~57&u7k-{avL%y*E?-5!FM zSnKB41-4}9xcKtK_)%h32C96BC5BIPk1fI*j|Mmi)a2!+CK)*OsP?~o*l z>n{8WKXCZ%y5z0j09Qb$zX&DXd$X){bed{eWaXd1qp*v)x_L@}yZXs>XF1lM% zJ$MEk*B6%jy@GpA>@IyB8JI6l^fk^wZlRl6hP;~>$dSS|>qUVTq~8FM%VSqf;p$=A z3Ew|j>C*QBFn@DX%g{LZX@GmMmg7n=@jp3b_8=`@j*1akI;G1DEn)ecgucvGoJt<~ ztpd|*rAs`MDj$%5yQlL1eAW;}$}Q(Pw5Rz(Vfw8tFtEaolkYWCcFVzw0At{b$2rr6 z7hl^XK^g;+-u%8#P<1>sG5NbyU#>xzG^qrZ45iHC<*X%# zD~7e{+4k5b5H9%Osj{WGfWO!gG59K2Hw+tQJ7{b_56~INdDi#(?ZYvfoAX`sFJdl2Pu7kM7eOkI?hL{FlWkXw?Zm_=cY2vrs-#`Zp{iqqE_emz;_OdX82nm zXS@#Bt2q*cMu5=iJp|tbH6e$#xdX9?hlJ+Kg6cA^H=>)=QGySNw=m>$8_5VtVY)*E z`G;Pqf?A=o%k8d@gUPWd!MD7tG05ujQDkQKN1@^kvI**{F6NPJb({jB7m(i>K19C( z9M$(^`NiGP&y6=rK;)nQ>`z+y25GO;%ZUMf<|~9Sk{uSQUpKBIobOZf0OWq6mAMus zhMa^f7Ys+{vI8IbC|#9dx-YpaiTpaURfYF!CbDp*+qOU4=~|{|i+e{c)(5=Z^tgRX z(X!a~$o%eFd=Imvc{oBn{3#a!%OH~my<*8|Tu7+*ZQQ0I*`2j)(wPuTLG7`rVc7Vo zkT@+EU@Pc1vN|1l_iy-wSa0cmGa6919W-tcuy6^0FOU~ErX!qx0)Z)6i?*Lqo>bRg z%+0$NwUl|gQ%V5QR|okI#+L- zO3X6Ipn(<{0t(*X!CEJu2O?-Ju#sMdQwAxFTLmX7lZe?GKLE7O{7##e9oz7(e<~t_ z6nuq`d1?4?qiNE^OH3s2+dsWqr>yZL=?L!I-5p^T{T0$VyXkFI^5n&kNNsj->h2KFYuj*E&-c53bPDY zrmN-hO$@A7_T~5*+qUhGpuJg7@fN(Nbm|Ix?B;cDc4-1`zt+4Ij!8J%`^_DN=#08Q zj3dUxOs+_MGaVxgplmwzS=RQ*zLZ;d#tv;|V&hMEfvhu+pg_l3Az{3gOldr-8~$z< zP&d)WQlV1`^-J1Tv!@?_8}#tHM^v3}fW(rrr+2 zv?Dt|8={#xsMNXmXDU14&6Mz_d&W+26ww8I5P7%^4O{Lf??&0D3EI9}$)D2M_{7oS z4U-}!NTIdT#ccR&giJ*X4yAO_`t=y(9|pw?cM*#3*2yopKO*>4>N=N)ZU0JJ@~kq^ zid1}RmURq-I^ZFopU5n{q|Ne^N1vJB()-Z!=UrW58R-gNf=WU@+995n7wQTTLfKJ8 z;)UdjQl!BYogg+!z*X(ELE2SrB8S2n!i4^WGng_23A9eRveQA8r#8Eu6H1k;$n?t~ z)Uy+vi5`{0&ToJig}bJjX#P225NPY|RN=Vy?N>j-jap8$2U^q>+`vb88o_3*NKlUn z@-tD0p;7TT2u#qQ-sKKHct2j4O$`}zP#yav(oUCK0W}8~pdjq7wD;)zt}oifOE?6064GbyP?tbSZha=2{%?nYG^}(iDDS;OJwFrS z#V*B23s~4P%j=inIgCYTtD>6UGN`2D&I>M_7L@1|K6(3H}N@`5MXoA=^cU>9?% zJ=SAck`zzGE!MWXOv*}VqCAJWH1d+{_KB%dXq+=wP_6Za6~$-0wlfjI7fR_ocOGaE zy0~vk($}*bLXaZ{>MGf01g5Yxo%9}e%lGBg5a>m$?TVlEwiwB;8k>5Ou)=>~T|WU@ z@iT4lyK_SXor=y#Mba%p#2iEp-?lEyQXi=Q_mr&~zb#D2jZj#=(EOYESunV~wCWTI z1dGGym~zF-KF1Vh4UbH}pe9J!@K}oDTqjPfSbn6mm<;Uu73A1>8Jfh_y&V(SlXn%n|C1?;;$){=_!x1F zXT;d<)tyP&*51VPq9qS>$ax8WoC{mkT5hoyc-uF2Gmu)cwj@iWM+mxW z2ZQNWB#<<&tn+B}H-jnY&>^(Gl_PGo4d}(qbebA5asskGX0vE)2-{b*KNN2&qqHSE zKE1j7EvV;=XMIr{{DgJjle3PDBw5Y-!XRuGb4BX9%ExHys&^Y-gSCtz3`O5?IqyvH zV5LX59$5~ET?M{3>4)BAF)2vT#GV<^*C38UO8pP9Ee<= zjjNh>4xM7M7%57_x8@YNVlz?fi>G-5XU{#z2y4D215-Q}h<-$Ui_le$SqTlybl*&= zp?E`;Q^#npS>2QUIe~izxBDcyYnk%y2GP3>P1tFB)CjK$du=yWq!9c;A{`MGN4Yid zu|U_`o3EM%iqX3nxjrO5da}U-wTo?3siLa*V%$L!jrse5eMJN7YfAMv!KU>95e1^DM+9^^+HMwJ=!hZ2%>Q1 zlejNQ>Xi`8;7C(hALEV?)ir4xqBlC<1N?}q&dz1A!s6UjMs7)~Fov7?oK$3xj>5F{ zu1&0&quL}eiszHZ6LTy4rc_40ejz?cwm|ilQ$@y0^?1Cp!)1{`LrK_$FaApplh%DI z0`G0jQu3n+JJ@xeJ?kbJt-^Hi;x-Te+ZZ`fh>1#x_!#uDufDI8x@$Z5B2e(q6bF%` z$;&j5q;fa%%k7Hv6_#Ly#1aaXk8gMpr4!jpTZjIi6ZA)z_Ch1qo$M$mFYIMuoSmPX znmT@b9(N`GPorNL&g7mXnze-cyi@^xH7ivF?|j(JH?C8NZk@iKz*47&}*>D!%# zv%V&45LKL$3+h%XZq`P<=v6^ z@Vwi98W>|Xt7nnwD`rPK#pT1VwX4w~ZlJEhEiFzQjzn6`qDf;?d+F8ZCy~S;uiky( zFcFU%!irGYcm2j+-n*;y@zLw-?$#vxpZu8YNF|(#!^8h@KlLVAhlW(#$BUdp>z&fp zHwCM}_f$m8-8E#hP`3!y+c!)V?PeC4pU~AKgQE!Y;I9nB%Z7-YB^`fOfA4D9owXf2 zp^CiFi|K7SLX+vo}t>Eku-dOMVaY z&!A)RqLlybEy|#1RiWHAFR?`EAP^0u8lCP&2|Al^cQ=%#@iL4lo4Bd{PMs*i!?jS^ zAr!7#r}adAx;n6z1HASo(NSJ9ipXt5iGmc~*J0&|tb zJO8Fofr=Ssih@iCYeo4uQ%BpytfdW=kCu900V6&*!z|LhpO?HuQmq$S_r@hAPr2dj z&vW98;77<%j8|0}k~hhwUw%ft=E$4;6i}1(Qj6Xg19gxXGl$HiB6I60hnuVlcy#g; zE%sx6dY-P_*I+9tzc4|qcb~u&orAaIS--v=@N{;}k|J=kPI3l^ag>D?VEncP!ysM~ z@5*|w9pkechXp5*;v41u8ENAj62~^041WGkEa;G&I}LSPCxO}2s>Ohs%wm##?8wK7 z_OP3CrCr{gxBXBdml4s+pq2*HeOd)eOYL>;Gu}Y2;N{4;${?|v!U^X*3djSa&C)YJA>K(}hSEurU4pz-+ePUPGnYBAo~yrrKKFBS ztHPBeOl-_??;KdK?Z+*66x;AYH(GKc*G+dtB-1Piy{;14a@P{}RH&?jSm*x+h@Kxt zQ@%;}?~7@$cUMHFNs&Nad^q?rx+AMSSW?isIh!>1$^lb<$FE`JU$4HpQM<3lDtkn1 z23;UKCusf#&pbhhOMF#__lnkQo7mu}SIL&zlC8)v)2!nKWm}o~q>c?p$)KB9_la7c zZcTYlryM%OedQ*=DHCrtBEYHiTrMe#NN|@;!PG`yKh)GvZ~M$>39K^W%I-t{zK{Oy zRo!>nRMW%7R_>&(7vvN-7yD^~2M>NmA(GEoO@1`ySew4U5FL_Y0MfhgSNaSvyKfME zjhKtu3V4mJ*DjGrAXfI`lxGK3mq=Qqmc>@ep#0rJ9L>Wm?~O4=L5S+L45K$(*%F-IVq>vRbD}r#eV1 zx9-h)EV^3YU8gI|vT*RLI-v#kPW$|+VzaLOk^raHohWuC{m>m?Y+jM+*LO#}>!Y5f z7ICxN6jCl+Zmx39fe3B(sbAC^Y(I6MT5V?i7}mIJilff9?SpB_h(gaIzeV6+y>m?^(> zBK5FSUyWcp(-Pv&=>K+b7*SvlZ-psu1?ylu?qd7%J*XKFXIPkF!^{fO{oRENm5tt! z2L1lHs{sb>sJZ=X(c+6CR@~^23M~l7=Nu?0=Omg~3NfmZY$J-hm1?N$+}RTv1^K~% z*O4{=+uCZKeJ%_yaGZb)32^^p=`6JHBrmEubI4Suz>-dnsPBVPE7+CkczOWz2lzGhY>q3h-fB^gHR;zIHkd~i??Q>LYyE-9@0kP zVR;y?vox+$NGGc&mSMoQh{BawdHE!D0d7F8$FqkDoPavHa-N~98wHZ5*gG^)5XX-l|cu#J43=dnwXcD;A8#Hl}yHSdS6QAf8XN zV_i21;6YirYb;_g$ScGTaPrI(*0>N$GmRGI+xT)9a&wy7gz@tIFPyp2<_+Q2Jnt(dd=R^t%Grot?=);G(6d9z&cY|}>i}F0;<_TJ0>h$x% z^i|ZQP5u(<^BTlTcY}c`+-hrX+Q z3%IvC`X|-?w5x*EaDKQX?x_C_8G51MO4@;!GG!PMbRd4D{!a54Ie;iUl89X{*^VSV z_z|1NFdCxukMFoWWY}*HzR5@5s~Yj%%j?E+nqkH^iBjzFul7A*h`Q;TeX8}YQD@iL zZnRVI*N^Y%aP3gS^E)NMdQ|n^KV>$hQZ$B?ps#v0>O#6|F&Dv4wVqirnP@A2XYrs7 zwPWU}oC)cE9)1{r$=-kUbuE~d-3s*ATRI6F_VAWz_=|Jg>& zoDCRu0irU=O=^3T*zHE!llx^-NUIOj>yzr#;0B%Y>4{K5frWKE2<@vGDVcpywAl|zI~XN4=Z z7?ATa{w4`d(V%s7@1VnWk-9KTwXA>&nmxs<`fbZmJa6Y z|B7xC4=!*W<2=(;XxJM27nam8NJuuZ#c$)Yt*-QxZs!v}2C=ZRzWusoRLRH@1V0YX zoc;h14`rBv!%v1rpA9o&<7jGeu{F&SGun3{>G$dUJZyew^>GKu`Mj(owX$q?kzok2 z{Pb<0$iC!udeD@QbR>6!KaXZG&lrgr^Bz zhE^{^qxfc-U#ky(BA3ef=zkPJv;?_7JqfR|WOR47>HSPf3ify@1h%3Pg4&s`GRolW z<4UPzcF|d_QWN>LS<1A=3OF@NdyT2IrMBNS(P~Zsd9ci zK7*!f1@quIp0Z@wSMLjl(wGcqxhUMcT@pv3aZdKYSFbn%wxdqu!zYxnh?^C;d|gba zg0Gr)N0La~NK5&Lh*=W1H9-kn=H%nIdR2DPka>`})o6v3fT8Ed zdxMr(DrI;7BzH91HfEZ{xwr$7u?2Ht9V1-zj|y5dy(Rp#Zd5Ka#zjjp=Y)lewvcYJ+DMg~AP*`%#VvlLzj?xd zR1k{Zm@6h*HkQ@;?MqMFYWow;&c}&!mHwTtb`Vfx=#{Nb3%X;@rmA|T$%WclJdsyp zIf&NDKwCoC$u~07!pD(fDw_?m+MrM$sXJrca6H2TYMXaW-jZaXXzxn@+rV}F%Ni|F z!6$bYu!3SOQQ|;5qmbIe5rmMC6}Ir5DbD5inQn!2Mv!6HBA)g6lP5s*t+6d~ zto}IU0766WJBsxBb{`^;gR^rY-74K^jN|I{-tQuk^Uj};qDxTw2#by!ML^1%Kn8Tw zwQ9af_TKi5#`ie|>U&NL|C1227e1FelS*;Rbzd)@JG|_im>*>de0&nz#Nv!#Pvy{0 z`;*wvi#DlX4uFhlIuYvy=Ibt^jmRcCXV$1}6=8+K?$GPm$n;EdvT5TAWJH;5>M>hI zO8>9rRC}>?fo(XKm^Cla%spb%A&5)9PR+``K$V%&{8zWcNUV8_zN$H zB2%N-^?v=5%0bKN@aOi={(51b+lp(Vex8$v#JOPkd}sN78PE9I!4R@nGpY8{h0L6-p$Ij(J#??Z~=e&^?$BjLH1355yxv(ri(tqDKr zN^x65Ip0p9^tur8Tkh?+89%^LMh=|sOd@;w!RDzTqTJG5b zYU)@gw$8;$CZursHW>78FWCz0OY4rte9p!0EJBlPM5DqkFh5q15JqZRkD>YA5PHI- z%DYByxftYQ4bwvduQ)iuh0?ih@sLe$0_cz=47=qT@F-)(9E;up--#B;1&F!-{CtFhPMv;ZT(bif+C2XT9$r z1g}_D@dxZHKXg^jQ12kKdYW#X+oNUUEuL4-v?cgwX(mw1oW7Z*4Ui%^V^d(jDH<@F zEfBAF|F(m@Q&&gxwI(;qKdeAM#p%{NLND3_Q&LQ$z$l5|)q77!k)!TAW|%xR=KeQ> z-d~y!-F=PCHF=84x}8w$$hlE(43NBT_c8$miaL#uQYKy~CtApD4|jmFBb^9?U!;yV%U{o zfkmxS)2k#XP?JkH@j))|OTV1kXJ@TW*GNaT>FkDBRA-gyUeM=-6^jbr(@&*0wf~$> z9i%4O<_p=-vPis&#HikglFdL|G0rrrs&MTOv9ddOQmgLu` zSe7+%9cx+2nD$7U8tx6II}WD^PDhCE>6P|IgtK$7lvD(0`&@4fQ8*5c#gur#&Zm2I z=E+zXNi2_97!$eOtM1jwYw|D&?yI3%a9fM|xahvc`;Ua798%+< zRyUyP)M!EN^7xf0vKwOW)a-DNb&rZEv6EBFDBp3Y2zy040&iid+BwP!9Y;Kqs*Cl4 z4$4&el-8r~hf|+sXF4ALBOeh5+lK4UVf2+Uloao3td}x3T0C=U@2eG@DB_*c>VjL$ zSkJQGz~EAjp0QHh`iNDFpsfpqdP+NP7crYa4|MkZ_lBdszd2rG9fUVfXJ?G?FL_CR z-X0k1Efv@s{&rY5Ro|jXwnqKXu-M`H>u9w1{$?6X zHXk~AuqP3q?E%f#7d!-bbT1Bp^Di%M^*>dPs&JK~V!ZL+RgN-nm1FJ-`rlQK9&kO7 zYAROb--WcV`~sYwV5|NwLfUwMx_Cf7X#HK*ss?obn}u7z--Wc9a3O6xW7q#8qy@T9 zDceQ(_ZH9LLfT9oQlh`hS`&coGm~ZhZM+^6d}jh;_<7#XioeTRbAj&5j~yZXy+u*D zDvIfK$p0dwg$p1fLYV&E;tpJZBnskU{riM71Kn5S`OE!>|1T^tD+w*8Ot;*|+k@tz z8qoM4K!?7D=V+E2eC!UxPcf~%bGzNIe+^gPl-4hPA~N){uihsC`uG651a)2Vt{<}3k`xEJxS115 z#YOFVXTK?e48_8^zvA%6WN&CU@{^`0IgA$CVZQ!pEle=uzLhaF#J`l@dj*%00ckc9 zY$3%(>rhA?#KlpnU^JR7xfx7sU}xxg4K1YECtR`pGft5K+ooPYQ2ca|dviofgjJd$5QT2 z<&!0r+PsIJYU;&i&YLCaV~I@{So$IiaDZDMufTlx zBH-+1x7@Z3cA*DY1~W=&QfxHFX;ivQ?wagFuYqOev+q~hy6087XJ$9 zlQsPAYvPkU%K^c18&w1nR&A@wp80lWwmcT5rNRA#0H=+OpDce)TQvcE+8D?Q@;uLX zHcI-1xG?qK$A|&{X^{H<2vu6L>6s<WxI*rgmlp&EA^dbI*~XzkbEHDgMy}HzB-ycZ{9$X+wU?(%Qu8|#A{(6v zJYU*ZLaA-o8A0tD1?GJWnA8wZ(_{gnmV%_hK`zSFmAYUiLKH3&O$zx$ryY4{mpR2A8HVDwn`8lWt48t`eo=0ABGiKs z>-^DaJx5hPU4d@B%{f+6K}A{fflzfHm1myugmldP*|;k9jZDp@h8?&0u+un6?JE!A zR8VaTj?gwupzJ}nvza8>2wB4tYr}Ftz%$pmFqc$v<8^w--N^t)8ax**t@Pt%-b{B? z*=nW=;K@|tEF~c_fnP4e>U@Bz`hJ4D3MxdnCI4%qlfoll0)`lQZvx5ePZQsp8Ms!q zTb$d2Xk)omV|tZ-Q$JkE2ljkEiYuTr_(+?V;dS!! zV-)YyXdwhfD;<)ot|G_)D|M}#{lvoUvZv+ETy0oN1KUiqO(j$n8M_0L_n$$9zD6DG zrqQBP6mHA@H+Dm}6?RmD4tb5|Q@TR{PGp7D1E}zim@@pTFvBJF)`~)TCDUyc-4Tdr zsc@Mi&HgIf!K(V<{&rx*sTp=LM;=7%h)2#2zH=ak3x?A@0%uw;W-Zg;fe0=}6D@PC zz*_(|GzhL^zPtn$tB|B;D5VRhbSMrlUSLc;+~3B=$FjQ?F7kZ1e7MgV82?mUS`eso zdDwOf(B+3k&qLCna66iWEMNn%i*mGG<)(>W0TGb<9}VdC{o%v?$nv2k_~z^NShP<< zNWLrQvfY?0abpD@9|V5N-c+;P;Ib_8agbz7{*I0k2)E^e@CaVN9j$Tu8kn2o)dL$FA#bxsNC1_1MO(OwlhK8H zeGRQfa!_H{LkN9=eK!QG)iqYBN)8;epx}j=#QY=!9h_#_MHO+FlcpRqIcFy|5km{G z=jYug{DE$av;c!|v!XDeI$_xmPRP{ML~F(}7q24pa}NkpAdzj`_G>uQkKY5K)in@V zwYDq$G!O+F5<0sF_qzBv-(X*MVDtzBCr~xHm`ZA$G0iHj5yj*Kn|o>Aq8Z)&VYKjJ z%Q)P<0%c$Q=3@e8+ZVs591XoFF~cIK%KQS%Uil@QT45a=>kspeBhIXER2qD0i6e**g{jVtev~80S<8#?lJu++jS%OOWS-Dv-oB6T zGF7f-yb3gVZ{WW1G;j+|t4=jT=zW&Mt;N>1Dv;qFBwOH;_%S#21wykP?#x{uCNGsJ zac<1dlo~Y84wuB$#b&8575`+0sX>0V2>F8I-+WZ(VkV{6hp5}2^Y8i8T zL_MA4@;UCpu(iI^U7>S78$p&kEx%f`p%yRdm5y zf~;dEW8D?T%GDI%P>&$Dn=@#ihGYFbU0$X`AP-&{4v*2>&gv{qk~EMhJd0o=2HQtZ-T(wL%tF6R1|Uzf4y1%=;eB z;f!fuHw}Ap{z*JIds;bS+p2fBx)WQ;)q&(+%Jl+0ta}dD0YawqMt(zJC)uTTvo_A7 zaLpS49|GazbqI2zJeB(glTuZ}8c+>Wk+4R>mkXu0zVxHzBJJfDO%TvvKKN zQ#gB!kgfMIlpYL!racz&2+4_l>=KU6}q$uyvj{M1EgEmf!daR7(!{()h+1Rbq*CdWs z(~0i0(XhBGE4p4{=IFsDBNIl}R!sygqPC1pnJH4{GH8E{a0AzvVa&x*S*b;r@H%di zO`yUcHf&hjohTyDhNh%A1lK-uL#~_~La96~5X5G+F)wRyIyuVDDZ69ClUOmd7a+81&qUQAIT$$gHogsf$?H9kxrC{)~qP6Le z9PDiGIPRm)5E>-Sr1eDx$jluQ|IEzWS>WA7p# zo0vBGH7Hp8&4tJ4s88ucZyJ?C=WWV0F;(2yQTbU+)Ymh_2xC-W^ zaCCc_cyz~RFe;@2UjN1Was_Sr|KaN`qvG0vtOC*M08$^PO?-{oOEnckNnLvue$nwY{tQJP5ApoTLtd8i^d2Jg^S^ z;T)Oddh}bq?Eg)(ZCkXT2&laUY?8}XN&!G0Wm6L_gFBLFOZEMPhu%Ruj))*)`Yz^otKz|>OAxSN#ek69_C-wwHW#dN2d7efg7tLLLK+A2yJrko;IRL>T&f2;B3F9Ce zK!@-3LSS$lECEP8`P7{URY(qTBX&IwL)WIois=?;SEAaNf38S%FI~&=Iq-lT9!U;7 z09Z)yh$y4-ghh3!*JJRCp_!2TDBK;L5Kd+ujUu0D;p>BtV{S|X&OgypsSkm!4TR>n zEJ4>TPq6R}G&1TN{lup*Tj+YG!P=isII!hXj2^8>zv4008=>j_JiH$KT-Ao)EV7h* zA3W=v*)5>;YzPEhoz}P;ToC`OlVb!1g3O)sc&p6t7gLdO5ytP3mp~L-%_A>>E zI9gU6(3ffFasKe$s4H6=rbP7p2Q8Gfp7i=Jb&l}}tp=%x@6jm@i_nA#g!z@+c2!vG*H}i<)sZcBZ1qmZlvPoxYg+WXh6o|<^G^izullKZrOahbYr7{I}3VKm09{3`@-(b2^){`p(%oNDjSU&#u9 z!$9Zs`$U^bCD}NKXYWhu8_$ zYb-iFj7%q{S|);zb1?Bceju?RowB<5C`9KvtHiwwY&D0ykmX9)Fm+WY<9*KtRW z)YRAoRV!WK5lI_qY?D7z=_@e(bqi{~=h1F;?K0@cjBQ3pGM#2Z`ND%oeWApKCAa;W4Z^Ufx1{I$DPGdAzH2pMI~wC@fcfCx$LGs@ z&wXFK-)q(9)CNZ)^awTltAj)$1}-zdp1!7+UIyfgi-xgie));VY%QkhYsi{L8~ybX zY~VfnNS>FJrhIY1!x)`BacXU)>z~Ar34*mn6kTx~1Dqf4k7^IyRqR&}Ci89%BW?lU zVpE1tLG|8?bnC-j(i|F~r}7BxuO+O-3%$Jt=5iJS|8+_|*upbZI|#_dUkUVyQn$pA zr!dZjxdqhhq?Etli+5#5OCp z?X_C@rRRB>Vjsw9!jwc)DuFbW{G>Jn16jx>os0UTZkPN1seG;lca~2;1$m0d>dB|c z$vxz^ioY+DRGu6-WYDChtkd?EGkCUSo)jy#q>9A$c~kD4s{}Jsjo1@ACVvurLiI+? z2chFyFgY~Yil$v;;2JTUpg&g{w#T7o02a{;`qA@B$;%2W;?9S?iUaSjIYb989%}Z28yPh!2zrK&bB=fVB7^21zsQBd8>4A3q_FFytr79Xy!?|u@w469$Wc0t+ zF;o{qg0PsRj6VHjJDpLI9}Oa^CY=s&vL4eCViusaml0;hf_F~V6z(=ObpNr@;ct;? z7*H!@BFV@<>h*ko!D@>`cGt_P-Z8)B73Ts5t2l7;QX+&(Q|8fhAH2%Rp03*W&f9g1 zK39m}$jRF(&s10rJZ54%ZHcWTU+$^d%8NA3-OkYI`Vd`!{7v=7y>%pV{_fH+>&2pt zjxzfIVJ%t*n3s^?i;PahqCuQE-^@G_r_>`g3dL@R6I8%)DR366+}hrkep}R0D+%*y zI7n9L-xmN>;QR^wOI=xBH`=(Q>^nu}7Pl@^odTWD4Q-hRYqv&?Db8<7YAL+;v7^*d zPhHh4#ZEwaMN9kSJSAXv)jjLF(|`lMy_zLO)FGY|zX_bK-ZP^2w{nn%qBq8m*DmcG z@pmPd`8VlJ1GeU@#gqmLQ(9@Hd;c}K`(EA zePl}#f4Qf$F}LqI=)L_y1!sXM%v({EcE6M}LI!W`bqWT}MQdNzqd1amB=t)wfU+rh zy<-r)U`^^1da3!POs6)`U2VGG;k(@qOd7T8$6QLr=dY$q^2l^eF^@BRqDTD(b9 z)e_{lMlvu+g?`zsb`;qj{;+zd-)_#@!)8%P_AjjQ2x-?t$s@v37~tU6RkU1wd&CMl z~w<2E!2h-ykSlzZ|Bf4Y(=v<)+{#& zTj+^}EhBxnpGuTt`}_if!fiCHm=L!fc}Ikfo53fWF~6`Ib#zlBirl;FJ*{yUYWQdH z86MMXg|i5X;>n>ogOo(M`_8?Fzqmi{U-XIzWQ@1YoqNaCPu12Jk_*@@)qaaly3m6J z#0=8>PkaSvSVe^h!g^Q^Q}cPcyWtsS)KXj#YHGOo7jTkg-uc&wChec- z7^FbrmNe1TdbkfTd5yZ6t(LpPpnnygN0Q)B7tC0vKnwV$ey-qa_;|Z)+pJJknRXv{ z0;*^~?NN9jNh6z+S1m!F%E22E350)Gv_7zv@rPp2Sl`4i4Z2DA@LdqnN~PI33jnMpPXN#1yr5>V zJ3ZM3k)Hs*G|XvQ(IoT2*x)>M5!uf#3q0(^Tik~sbjdNv0c%-VIRMWdNK@S*sM6QZ z*B+g!J2;Nt=C{CUTCsH*4DY9^!!>wArz+rtW&UC~G@ZEOiZm&@bI ziU-ur1S;qirKmOO)khxDOHoBNy(YXkd<58nKU$Z&>WavSXPY>Id#a)@cjBfH;k^z< zgAaQ-9~J~`u5If9Z~raDG@%VkC#9xH`dH)h){B7rY930@<0W+2{4*(E6)zvMot~4J z9Qxj|*V4sRfgPl=tc~@tS z4n+*D7MI5BY#C7T-m6^`-%=jgLZ)h)Z-$YZ{0zvD5)q$f{=bQnH0j$I=hS<{iioajd~E)j%Ev#WrX= zDH{Lt$BG(@yo32SY9^^9i$W~Zg5?QpZ9wbwcLNp^@X4pqHU_@tAGkxkgfL70t)ByM zAhAoJ|0|&5d;kY2)@o|ZPDNc8W8`7Yb%Do&JR9B84KjdQa?Ss^79gS$1y{8iwUy&Z zh8zRf2qz7)%s`wH3qher5#0+x)exW@{pr(^{3I7->`jcU{gu@2M8|ctKpx?)t^gul zjB}j_cgS|-MydOiub$OF5_!sG?{o&ZK#^6&69^0v$r$uNp3;;-l3mT+{xQ?W3^;GU zTk}ND`}uc_?|W>BbM8!9>^TzV0VJvJh>y>s!bSS~zk4V21EK|R(K?a~RQE!;>2FZ@ zQA>_mKeZP(&Nla_X^hIZ>Qx)rIKyNpTH@kT+}#&L4j$@~+w_ycAeqUq)Ez|;Erp_b zE~DlQ#w$c!vQ~$pB}vamgE{7h_)PB-PFu09Bkp_lZnxK{@{#x-=IAgXa>u4`DQqaH_gqh5%I$B*Y7?!}O3cW+@o< zJ-az2YCpK1LVkNF-1sFzMkR*vnAy zVq3UBFQC8Cak?^ZSPpF+;ZU*3fzBzotJl|Tub(wzC7#;~a&OOoCwO{ZRe~9d^H*v{ zNQwNRe=~yBCOK#;$8g%Kdg(BeMm|JwhMyP8r2N#kOpFnH9C-h`?I10w&2rp;S^29~ z45@%a*(-}0^K%Hi1Z3Vm1V-q9>XW_4*qQn|&E_G;lVb`{J<>g|PV8lF?q0kLy-nmiad4fhp#05YZ}SN%8$z)Q)kRC5B~Buk~t-j~!r&h#<-|wkfY0 z$@=0)j4X=>O+mb0XZHYh!-Dw(JjWg=DEY4GTxwj-F8eC@UtR`4Jo&%yhm&ZI99Hes zzMH{#P5i>j-DEvzcJbHxL|CED3*t|dQdDD*D}Yak!wJM;?9{MS-kOnwpDmRMKf^QF zp=BvQp&1tHa#zJQG{L?Z&G`#9S|4#-k9Z(3y4iK&VW{)%;_3fB%LsCb@ z`RFfSM;@Fx=VJ0~hTqY3iEE+U@K8#0%bQbZ=8N@feC3PUr2s#?S*@CZKhxu9fdgm? zLYT2Ox3UTme79(PJ{RjWPn77xHmvzhq2G~lo(QLZ-AFqHWJ7_VAus>LB+1NwpIBlj zq$!o^o3if5+Y=(x_s}7@CgdB5&hA$#pri^Y82Co=m*DeSGG9H|eBD+L6Wtvz-%BEQ z-2Hay2r^%w{7-L$I0VtaGp<`Az+7cQ`K(R*%WVob1@D^UxWE`ME}%g@4E0yhPqeTj zR)n1I&pForNEXbM8s@+=9L07cH@(h~1qi{~?Vw-9koi7e93pe;Rs#2`Z{RHQ;e3+? zp#q?OV+w1s;soU5b$N|w%1<35Pc`Bm`kTYYky0X+%GKdV6)T8}vh=_pUT8YS)n=1! zrlS<;m)nQoQM3=>1qo}wA}dL5XzF2$EEKU1u*37#iao}nhqsU5xq?Z*^SSP;yKaFczdqZRj{Np%X zJ3>LPMxqWek`4}PeMa}VrlN{|!QX$wZ&r(zF;pi*CIlzV!gkw&7_?@P&yi52?(IW- zxS9kg#yrlaEc!X{o1zROkWf-dJ&&uR`If#4XfLt_a7VIDOdCi&=mY&pf`Xr(OEqe= z-H&*4Uvl{`O8uVvTpG~=-M8@OjV9n8LSj)FEQ{l-EPi3=GMy+F79I<>F-`^w{Pd|M zO32A4=&!0c!`o7`)k9~b13t-;@wt_}47QciI-qEIy(rnF(WkjS{>y=iqQE$f@IL%L z438Xh#;`NPeJ|xS7ztpq6hOD97aht7Jja6fmwbyN=9$vj8vhzzOCfincH6s!jhp&t zg7$COmpmJf6U5E0br{V?&jsobp4hSORW;%ZI*=fj}$5##3 z9DqX)%fX1>LAT*mCX17=EGrD02=)=t`Xt>{6?_2FYR*Ho6sq!`$%;h|m-NA}5*K1M z59Hi=k`##cCZV(tCJMp8vjiZbtM>WmDO%|=6ubVETNK3>7s9ZV^bHPwp8T-1|RZ1_eRw)bY zQ*oPy+h%aao9MXCL?BLfq&LN9AY*kH3ijzQJv}F)c3m^~w7sifhfh zRO;Y)8PC^99J3+D)JEvSWs_3gMYt1k_g~Om_iL*!LSwAmdyq?Yz~yPKdi+9EN7wsi zc65lL!rC;=rhaPEB|(zmW7=+#-kP{=u(@L|jvDvJs_Sg+W4}Nsgc(e3h9W|~1&rqW z-`jJa7S*c;XWvd&n~4~{LpY~JzgdW!Sr-;6XhwDhKKuFg zosIFNI9?eYYF+(w1f^2u2{s|Tvwo)gp8cJ@w@_{12K-%gY?|-u!|DsQ6SEVFGqeFy z>-7{)&HLbfqkm!76KQZw`E+S&O|75?tr;5-2pbZu5gVoH2&E1$^RB3AD#Dr z9HI-@z_F#GrZc-hk2|8OWwXne#V{C|(LS^A_vb3jb9O$K!}b3n^lSrR;0y;zN@bfM z)`pU=w)?(0Jx2e6+NQx)lHQp1mC*|rA7n^zFaWHZ!Wn%JT;BhFICB3ZNH;5! zq=MQXjrP1y=w)yL4pE2qm{R8ln&C*OPRX+KyiSx3%Oso;-ZMKGf!macxE$PoOTU&X z0}yhDk<_`6)b&)lrM7evNcRaCf@8 z%zrh)ZlMX8f}bu?12hbn(x`SIZa~CyHwD2(1bhI;o-FQN2Ml_n_`9le<$}#`_#}T{ zwtxT>#tbsAbCIM-h~6*?2`@(zK0Pi237fGLuL=ULXgasOp%S2NKF*7P>%ZBH36Nnd zM*2r8|BnE3yEYz;u<>EzDqOhGWr3bEjib{9NE3@?I2?C zu2O{f7LE|c*vfAA%ztumYw`Udl#uJ=#p&b5?dZMVX+PL%Mme=~9PB1U5K@U2w(3nxI!823I8w(Ph>qok&d{l_a zBZWEv-G6$L8udAZ-gh&vxBd)~1qb^_R*L88Uu4!uQh_CiUeI1qUi8q-6ZkLqtgH~D z5t}7rNdLaNS6gBF?LOnEX&d}#y-}^{M&olb-;?Lwgmr|d=t8J6Cs1%1>@ut$OS3? zc?XPXye#M80X6IEM@q0o!jS^M{-?W{>p&akcz_@2pLyowI0!p79h?wMk7kN(#*#4e z?I$6b(PhyDuVz+N3u3H(C(vA(tUCXMGot=G8G0M?_l>J*^{wmgl$aJBbsLq zaqj@^UTl>Px)9+)O{+2!G@cy{$D3I-zIGEhi~DZq(8}00P{+}P>Onts+mc=u92T^BK(j7_XnGW`umgP#xa9JvjW>vw(UTZbs z4S;Z_bIsZ;;Vc;K!XEO3Uhj=)hq#70P!r?w&NSbH&*4Nm_|^aReS00l`a5?{X#WBs z@IpFjReSx}qu}p2$<_MtcXtF53?THys}jAJKivpPgq?l{rvE4dn1}1#qiiQA$yu3P@DT+T6ud%eBfty)$tY@ws$oweR&J{-#X z9_{U0{&Hd?8I^vA%moo{EaNK@a#LtIsb5}!rXEeZyp<++tcLK{>S<0;Y)~U1Ypidj zr2-ARhNr;se&y3VZv-mmLPsP%E9FVy4bN%3a19o|fJd!6*ygJOm?t>igi8#iRlM8K zpCOUKKamLjXU`@NGBVsIL1g(0BC+d=J^YpYkT-PK2i%K*1u;oz>WLdf{nK3tzfnMq z>dvkFXfiJ}?a>hY5?CREsG%ZpJQ=KT2)Lh0dsG;tsL(JUS!kePzc!Ui>Vuuw6`rMG z&7)+|Ae00NYNI5;eLsWi;H;#gjcwiM$>y4$Il!J89>id8mTn(H!0%?)mr8c$Aj1{t zy3cpoNQH{#feY(WYtb}>DE!u4OXsHAUo#y_=5ug630QR)W=e#cGhcUEqiDjV&{sQ< zg)ln}2X*cm#s#0KA>x=0PbUqu^<6YBB7xWGtpqgnip}dTuYYg{4X&uKdhzsRG>~kq zPhjM)sH>3+d&U}mWxrN{bM@dvj@Sn)|D|${wx`o(SR0g!<%cyaE0Ot+J`BdNpxC+< z^X-Nb(uE(*CjpViNZU*?J%WhT4CRfv!&x|0SPX5nYP#+wsd`Vs6PNDB@J+Z-FOfNC zKnP2$5XK(D>auZ$%yys4__;7X^f}_`JYiO5krf^npi~xsxS=7SqZ(WtP!rkIDmrwd za@Bf@^76jAjI&V5ye9^i@)o{+Z3Z(%iidwq7pi_`FndD;_Id|9o1?Dn6LnFT-pz|L zWP?0lON-LxGGYWD>F_%4FSb7%h!p``$Z0!m8zFktJP$kZI_=Ci6U@I-AiMo6+}tGj zHvC|)tOk$EC5dXMd#Tw?N2FeMPWW#Zj4XKD@3(-Qx+nUM4v?DypV;WJ`}FWgD!s-~ z2&H=v;vpg8Ob8g62{~(9ZL8MN@{XgblyTSD_DhPCYE{Q8>fv=O?;mUDLM#v{5@Q0K zFjP)O5YyeD>X4CfP_D~#90~>2xIKZX+OiYN%;I-A&3c{^8g~1tiNFc zMo8gxs-rX8W4F242>B;TgyD4<4gk%jlU%(*DswXH~}F^AqtLm6GZ7w(xb z@i)u7bs{10_1sIee~Eb)S>x1NqnGw_W*mP!_|%jUkiCUHODP4}aT1N{1P%81jV4gJ z<1V^C_qa%72w7M*jA%;n5$a0GrGL#P9v_SkA2aL9xF)DaGUAIj*H95!%b3*jfjL|(h zDK4$>FH<#OA1%ar4=tA&=*INRy=dn^{ooI+UlREtBb}7mcvYqvWLniCCENPAQ0NAw zjfL^4SpVZ|u18M0wYjOtBltr{T>0R4gc~BH8;Y42&svKDulL&)FAF|TC)1_+e$tOv znw9zLjne_J*TObtAM$UKh+Iw&YMrhfRYvH@Z$>gip=VcYYvJ%8r&L{MS1ZQLCP-{(@nlQxA|-WXo> zzHsL{b<@yte|4r!L*#A0v7Ph8m@%?j3Q9a4eE!aW7A)F8oUp(ECz_oDE*kxP@2?D{ z8CstNG8^)QLbJ&;B>&v6nP+ABy?`Ve}V9xg9nOF%|x@GFO8fDmjR=t zwp&>-`D58ymdX)#)09u$9nlN){87svlL?fE)9FI_C4}rz;bd$1`N@k0GuzLuN1w>xEMyBV zy^*F8*{xz2j<*or|7bg5l8|0wspbJAx;p~<$s(H)#3{E%TX+$|Y3SN&i0b$>kq{HT z)?ezBTYUeqPg2|QD(>b0k78ie=7j_7pVoD$2mR%va!vTrSX=dZksxAl(e{1rQ+ej$ z>A^iHB}o+x88_M-NJ1gCZ8d1>h%uTU9`(nP+I%LLMi=JF-vg zh|m3nr1P5DuF~Zf?}uvDkb>6q{v`XHI~{>2Ee#_g_mCd!bay!v*jV@$S69x^iZ%uK zWWoXzK6Qmaai)N4Fi2l=!qy_Lrq9ILf2#e||sngiAaX)>wF!e zzMT0Akr;^30t$7IHW`wp z68q~Rie73z$t0ylv$Uj7^tTN0wHP$XSK;}KF={E$lXqsKqGa_Miv7Gpd#AVZt7eKg z_$TnJ%Xscnl4qqW#lFh_wM0H7U^i9PUZ_Kwn&KKVT*9IC!>eV4s*3G{J~AN=vM2_4 zKi#70QeJ)UCi}gAk@5NmMQ<<3S+ z(h|4u3r2@Kr2O`pXlSnaR7(lho9mMbW)+il|S<|ONX^YntrkzCc&nL z`;~8JsKl1fKo_J86{bvo2faw>W>?v$s4)bpj&e<}{zcRVBmUxSagj$M69y&9Y~Meo z5&oL67Oi{OZMQifO;~tz(&MFVIldF+Pum`^=A||t94<@oJh^(hS{&qmSqO`6-uJ6& z*?e|gO)<+n%o=+BP5vT8JkEb5Gt@M-uOtxa#4aZ}-z4w&#*ih~jsW~-alEi~6;Yi9 zm6O*&OKd{&QN2H+q_X_?6S}`9oJE3)XPL{$rPY|`GHC$E5&qJT&uG8=ruutGc|W1z zSrq55fy7bM4Ax9go>hjGNH;nX0-Q`fBRKy)ekrStExC&lj}Qb0?IW0jAhjc2-C}Yb zX@YIi(4-&jw)E_Gx+#VecTeBQ?uUc)b`adVyOc8)XFb~EJaOuyoT9v3N)km{FGtP# zJmMJ95P-oV@4Bv{)_rmGGR|N&gEQ3x!ARj5xwR&Tg&%M@{x$w%!FZH85IbLqBU~m; zarD};4si;jqrewMqvjP5yaI}Zg-lARy_&#Dj=TYGOokHZZDOb7rLSn#Qu1bY0oHRYDn;*MRB)hGlzG`TH8HLmw1yG0g8-eH} zkXrH>_Stl+C%ljIOCU>@@2k5JQ{SiusLbr237Y4}`F2jn5!O&xoR!y?GhZ%HMSB~c z8B@NFn@G%?fI00m7i3X#q)zha!mMf3i`Q^Q6~j;yzu$h0@AGyG`6pgAs|OV<0`(Oz z{w??FBucLmILwca^bTVyDseINF@i%fA`2POb{sYFfvm%Ul+3NSOT#a}?mxk(cV zf=aY^L~}dYr_ct*{V5PM&t`B)b_;*HHG6}4gRO1&V_wJgv&*Zi>k=9Z0iTCWUo?r8 z!n&e-$Hl(T+h42kqBNHYdR*nb#uw!w)-O5;w%ndqE+n zH_C*}lI3)=m4gDhbSY~$L2?4GH8BZe$O zA*Bn1toCX(24@tmR?j;*U&ns#A1AnMvL)bU!Reiqs+IekpUE5ISjC_j!z6mQ3RYmDXry)Ml+V8Qs!Mmsa%=mV5U+ z(z(?F6B<2$uU{YE*V@l$UB^gqJqAwZNfKQL&gBj{ovp1dxZjUZgcAS!yS~*H^F;fI zT)X(Nmo~oIzJX`s1?gy8Ous3_oFu7OyoEK!;nrr9ls65j=Zwx?KxVt(eO2E%I}_i1 zxo(H7szzgOY#-%ZZsgdce)N2LFqz0A?x_){F=3oHuqte2RnxW)mS%Sghk*7QO=qE$3O4RY&!;D+$T|imT8U$UN)~fm^2MMK4~|=L7q3#{+r$ zvo2dc`9GkuT}^(x#m=J<_NsJ-W^uA0Gt?ELYk_Z>6nefd&T3qCKf-B#A;JTjf*u3S zI9HJE+B@0N*D@v=mU@S@-4B6r^4I-tcT;Bt%Qg)Wx7RiLzFuYZmEUZhQXN!WJYzVxMR$;`tt-ge1EP6?0$+Vcl38)qSqLr+WDwG9;p-+zQ2PL4TBaD@1+s$CLzxj zBX9kDf;n~gH~ePYHs9>p+K4tKrf!dT&BTJCW`3vJp19v79i_eDsatOW;~BnEcVimn zykyh!9l-0|0%fV>0_A|uYo%+|Uov>q6xtRTY;&}BXS@>D{>Kq#VlwaR$uidIGNwOi zo>K{NyI3Aa)^_e_8OU%&f8GZZ& zr=1W3Naqqsm@6R@Ftl_sL2#v~pZd^rA@c3~{t;9$pTXoZmL^(ugkE44xsD49=}IKJ zUSMj$F0X^THjP^%|BNO zB52F^&czgbd%hy_D&*~?g>h4H=O?)cc1vR$^=oYPxUnooNbR5+eP1^wb{Xr7y}0GI zNNmaFk`f0q0JACawj`l2ml)hP#1-$bZURS4mCG~>bCUAp#gnX~?H1rVkc7lxJJ8P! z!dL$+;Whgpqp!W8w`8WB8hF$vX&l%3cz|&BXVq(5tnCOQqr!)3bAJJ@banR7*rFf$ z5S)p_=!7#VT@T4F(Y3+(yI=g)L)VzIWk6d&_tgFAurP~%xp>@$-KhY_?eq5i95E44 z8v`{3P>Km{H{Z+{rT97!&q&tZS%Qi0xu%G2g~*nkHyD|5WHC0uK^fJQ>S#S$_?&NJ zbUH`OR#KXSb~=8=Gps!s%9566K!DH}5HEM$BKc8C5Qy>vEv(ktn6a@FW~2Kt^f;Te zzh=w6Fn*ggB6f|v&$5Jo0r>34T)O_{9mVvL#1$JCiEW=bdL^l+K&x4FzAA73y6;rnTdXzb=hmM1h#3_h6?5K-+)qo?rB*B0&1TjuQ?(Riq~!WRk$ z~k;$=v?!HHq6uSrLIq9+0Ht zkClmTd>ALoI*|zNp?52v+s2?KbSGH`Ss3DLC3g(KM;L6d}u%-hReno_fgHRn3;S?7zuO@u-}oA8r)b zJjs6d99Uk!dV}38Ij>!dx`$UEa;b<*AOv%8{;5AalJtI-?O=gmK(%mezC!Pf0Vr76 z?>YE}J5V(cBV(orHzKsTm_GW*BTEAu@U1|!xR%+BFIbTG+cEitzz;WSp)(hniO@I- zy6GiCGPRMO?IgJ+Xncds>@uVCCAP`VYWx8tE}e@mea&m%B=POy6NbVqFz1MP;5WJG ze^6k}cg5)y{Qw6_;V@u+YdxtsK#?R&CPFQ422{nD;M*Q{0?5S@YDhCcPIRNL*AFW zYv43&_=PbpevYw3-VWe!DVl)&O zr^M7YVtYhhkwDNtTk+seyPB;acn}!SNtPyHnWWtANocPkz-^=Qt6qVF@_s84I^N$H z(|Ir@J_>Wpu#Rh+dw40LeGuwvYorQ1)1$QwUdl%!ad(XsaljdJwEK%(li9X{O^-6S z2%u0Jh^6hObvM|_z^xQFIM#3tlMS#Q3M)TnXPermy1KEplVoJ0zDzb2C&uHnQkclG z0m5rtd?e#vplsC59;%~Xv%NI9t~wPj0Ov(t-6JENu(J+%5TSGB$7YlZ2@RzV`7xx+ z?VjM@k&@{RCtv!P&>zWn<6bwvIK;w4^V%O7cPtHl1Xk4T?8ort`A<{s=$6Vyx++Ju zW@v<7ud)6vb2&2V#Pitn8ujxj((@#lDz!?@V;-LyS$vIDrt@>M zMeG+(Hag3=vThniCISy211j_WYFy~$=F;nP)(djZR%p!}(I31~sXA4bd1CcK0kUni z&OE1vJPu(p;k$F5s8f_I%JqpHJ9xKtZvjDRGwV2AE~mtCaAFhJa**QAm|V1Pc{C+$ zVI<%r$hAVapsU;ovhb}8$E#S z+nK$t#D1dflz#{@Z*>lBtCfLN0URw>YZv0&~%!y@2J! z($%s49RoDu3Cg^rrsNVTKedG-eeL&tb}NVn`eS+1{h#?t)IdyQ1+?1IPK382fJN-)5dyW=Nhq@wqet;1=l!uMF z_9Mp|vRmy(^b%C&yeNvE^qj-q`3s#hL;HQNz}noH5TsE{i%pl~a?T?HGagEO({!Fl zPV4m{a7*}Y#`p3|^T<`^!?TlA*4I(K z`Cv@J?F3w^Dh1U(wjy4~+zHb-Rc% zq5UfZEz)G%kfgCGdKjbX+6cvoiP^(XMBUl&$}=cn>*Wt;sTv|Je@=~yT>)nkEL-Gww?M4Al>O?oJ`sg)w8Be`OonO40mk*hp^HQFLv*4-W66} zei}`%d>rS^=g%)STWrd&qD6m+t0C_egAX_|IaX|A@361%%9nJ1KEOB1_wSeTp}%yh z5L>cfty%MY#ee8o!8`cT8~N*W;4nkDo4$N8Yl@gA$2et+Szpw2sz774x1MC45lQ;$ zA&_xiy)xvUcNwI2D|Z*;Xjlb3_hB&WAl4oF%DSj8;Y7~XC-W4uvFzUwr8nejkG z8ytiOdc^hHSH^v;#AML-N@n*sJ1kMF_;u0!`+7Ymt54-7w)zKy-b_0`*?77G6~Orr zT_8m0W!%%v9Ck|9gLkYbdjDw~oBU}0L~ieA#p+n-)`yFC9?Z|%L~|`v!bb36E3`tL zY69k9B=NBEAY=Bs)Csf}u3T5>bN+_t#2X@wAWeRA&Ok){$Z?(Wee3fV;J*6 zkGe+0)^~!(N&0k>VF`POzGHDLF+r}qP6QY(7_Oqh(CNIccto=sSxj$@jOP$433tT= z4?od^A<2UKZ`lgAyKdJyb(7IqF*^LZ>)l*!&HeYioE~q@O4v)4Ks~64#J=F#rCvu( zHDv##bGnl_F^^w>R&Tpg|NXLi(cKJy87Jk+Ak>?rof-S}NW%NQKjve^(U`5e`?}ls z2)~yOn4+1*Shm;}*d<2Rsr*JR%-L~|NwXD-+OO#|;T0Aox$}34&AJi7*l_q+o!DYw zERb`g~2i^GQ@euZsZQgT(NbuY(a!hp*GbW3*Z%J8% z^j4UtRgF7er(R5N-aYJ(K?e2X>cb=#dz>d#?1jXO%Fgnv7w1u6`+DpC}CF-x=TUXGB(nifRLnxrM~1IqcCpehp{bQCK56P?ZZEcqbiP2%(<>;6Z{R+H$@fl{5jYJ?+6y4|rPh>yK=K@g;hMG?86pzc4llJ2zoPT`t1VznkIN z=I?x8_8M;*(K~Q4Aon|n!TCBjqhmEgg!pO!`3}FGsj*Qk^;J!R!kO3i76m0;T#!`2 z>y|g)(`&GcZ}~M0K$XAp zj#~7%#$uI8~na;}Z{(4#GC^mW)y{k!kbpDohJece3X{7lxX6sd_AoGZoBPhKv6D?$TvnqJBW5st=wcnjcHxPes}vid0qZ=;4N?3 z$7w8YfY)L}zPMP!M{Kq(oW``hd&dv-nb55dnhzuv-Jb!M%PIclh@%00{Ov~+W!Ku5 zS%HjAnG>C@Ta z;`Y9COy(-ZXokALc}7pBotQb0Ghbi<6uXD^8)*Uc_SSPO4O7pJNb7;^Q`?sX9(^gt zGuFG_hd8nEZg!;T$LZmQe(u`?_N9SbvmkUi{5{;e9hHc`!_hT;QYUJ~!}XKlNV7Sf zX@`!xeoKbbC2LId(XdN*RLwr2LRP|nqs?w~A?*j~f^XmKLIQ0+vh0t)Ywt1%Ic@uW zV|PO}HG%Lz2U8QFANFFPg!O8)UCBF$nKx-f^4cEx{d_a#AQtJ_=V-)#Z+C^R|J|RC z47Gtkg7b^w+#X5(Q|Dt6Bek|1l4$L|;HpT>aH{?xnfAdN@$&d}6TWZHh?HlM*KkKh zBv@~;rf8uh57slbzU^kM7ngEC-JS%pit*gzika2uiH?1a+5t|wblq34`Z4aGFl)CO z+k4Ksvu&rs1@eic?=ssSII6Q+^jghap{E6j%x0o$c*+5=?%el>nJG6N^S*Ah0oxA0 zx&`Vt-$2I62c&0hw=J(DP0X+Hfs5-`k(qz^GlzWkT0xXMooI*t#K6V(JGy_%&Zy-# z#LvCDoUtba)76)Rh)4d3nv4N`;8s61jx$VHC=k3b!zM zeDQSq9bM**h^q{a8;!%lmpF9?Ef| zS~*WKI=PM6)9lGc`#2zcgZRT-_6zTj!OgxTg~wzQ)k@8sWIv#!=5dr{Do;n+Rq75m z9-O~C)qwn66aw8z6WTzi;%Ivnqs}wNQ!jGtP}J>BF9{MA4r~+ePBW+sC@$qsg|jjO zL)+EcrL5mqRgUBYPN}o}x!3csL`k$FcTzZwNO|g3FgMwJjqe}BgFgj`*%)qw;d!b_ z(Y?tWIkUkhmd>16X4N*7$S?b}`VU1#_K}X!C0Zv3AoGh-2T4XnMS8em-xA|(Y@k_q zhc|bPy5Cuc)~=7Eqq6rp_iUR*vdWpw3vpzA%YhgVZi#=$>;#6>{71OMI7n4pNdDuTrZgh^V<>q*rtE zPz3QJaQOWnFCrE^Qo4P?J~#GOAYHvWxj%EiMUr*Wr&Ny~j zry`z$<-<@s0x?JXoOWfxStB1~l=uGOtkby#N+j3|-%-XQO0ut;;X_>^lj@fZ^%*Jq z>wapW>yteOA97H^|dDj1^9pB)Bc7Z+T2Yq;skPWqI!g0d8q~eS)wU3YH zb7UIe@CbQbn*%=(72n%o>}{Nv zUE}EF{T*_Q-v5uUw~T8mYQF^wrATpTaSK|CySo>wBE_8)cY=gcf)#g) z7D%CnySsaEclY2DnB@K6_s;Lmbmr6f06BY~vmaS&pJ%UU9lQBySe4@E8*^uvR6o-ps21R$RG zHr_XPi+W!3i`SM2kAqT^Xbrl4j?I&d9-L8%S${|g5c~>nez>nUF5Dqw0&%%72ln6` zsUNk|E8Y%lMor~){IR(B9=UROp#Cd8?wcY$$H!lvs6pEeY6gul_aDxW1GOTxOz58- zv?%A^Ji3>14i!`e5<>sJyF@jz@4s1{c731R_+6q{x#o9h}1*3+S$!Qad zA`$|u7gz}4q4$b41qx|{_ch5u0#)6rgkj!8cQNmzVZ0JWGVfBhu2(|olYOpxcE3q} z7k2;XEB+V%cDp>miMga$-U%usRy|UVj^<+bL_gQ!ORo>0B7Pnhn zpm6gr35q)j9vdVd)&DWdWGv9MekiH?iI-wp$#W~6TEj*H8uvUNw-KMGK;h_mlmKX% zam=>i^O^GVp)t2aS6!!S7SJsbiv~g}IV#{|Zj870)NsZ;Q}l6eIln}bYX$962ZY<8 zNcjuh$)6R&19?btOWxXdFTx_vXLYBaAb)P;EMu<11>L+az3=wyetK$90;&shxw5&maoaBH_=(%EKm56?Z9py!UU3ilw@E`|Myzn*F71Ur1W)V zSoN5!0X6DY9d%bxViEprC2*ei38Yxe<{B2Y!eMPAUadH{vBcX;YN3UV2Ifi{zsjqngZo>e>spLp?bPbpI9Uc)C{C+U@i@3IXqpEj9}ZP9(s z3~Kt!RkNYkI#a_Cl-j;rHgyv1zjse{qZr%w_n@j$yKXP-1kKAxot^rtQ}Xf3r{1S; zGpFV6--T%Yq&ybSBG{q)Ds^fokCv-#wqF>n6)h0f%T6Ci>)FU=#Wxhad7nZH6Q$3< z1cxSU3-P~RD;@UTpT{NFKH>u#KWrnROB0ggX7-*~xGFk`F6o#YpNmI}Lf=>-@kMd` zZCrVwvP+jijHhbQW7jwC8I5e}A;EoCm)~mvUq^kMj(wm1vGrM5p5lvymyPCvb?Cc4 zG#b2J8dz2U+n|qP8#f;hGftb=Q?$@Mmz&v-o_(lO5MLzBE(9{sUGhy!bcs^0dC>fw z5oO{fn^)`C8@1N{7PFR#kokCILFuJxlm3oRCjDkr4W{2XWCglF%Y2Ae5I1njh}LRG zF4-ShgoKq8jNJlxyjDP1(=sR@o=|04yPD>%Q*p1~g%Y>%vQa;clf3HDB?+0lH7pCEJRd?>{>F zIE)f!6T{-lh9AhEZhyH$)q)BriLzn_b%#-5B=R)9cs{W{L<6I_Ub}h{_nM$wi-io7 z{kc)eM51MVm{F$wUqg0>rv!?|6N0Jt07U9H^3hs)=1v*3I9OeL8nSbxT4GKqG1Z%D0At-j?E-p&nv|7gpr$c$V`4j^O8i@i~GhN zKo@lZq+iT(h8X3yj#FaRG|Y9nuibFBVA$IQ@C55i9^*lqJn5@jB*RGY`bguVYLZj` zi(bXHq#NMRlR3HtV#OLaft7a+?lqM83j=pZwI1yYEBXq?9~+##K?& zE~92R-6QegS|_UIsCp8UPh7CZS}yD5)~{IxsnuB4FSF{p-q zW{B05eZ`FN<>whI?a~M_o>0!^VuW+kwZl@SzRlsjXJ6yieEsC@eqwJSa#&M%(RkHOoRw_W$m%Nx^cfcJ6SyjeKEI$3)+Kl#zFu+HXg zJEAn*GM5tXOrmkWtp8PFtz&&xq!Qxu(EC5Tn%y%gI|;)6yUh=XBSCfKq8T5Gu%1tM zJORRuIN}kPOEL}*elo;}gIwu8aQAgpSC_Ys7hGB z2dVbB=aT>B>}I-?vBlj@C%Fj}9IjHWU39tVdvpf!Zk3F2LLHi*l`dO)OoP@{ZjO1|mt7Hg$c|I4k;@X zm=L-aEx~>dm$hvwfi#<=FL!eE~~OS z%H2UzBk;{ZarQ&N2RP$8p+h_NP8RNSDs|0|DBa(iH)lTe2UY5Gq|ivR*_4JDl;Us9 zZqWwq^X3@o8(X-fvMNgO9++`Oh$D}=Fh7M}TA)^nQZ&DDIYT;AjMgd$X@kC!JoTv` ztVX}19AhiXx5&}CN0w1r9xh_%@}rMgjHi)**s}EVO^!Cso>sR@=W|`?dE`<9_-i<{ zf>w%wn4kGBf7|_Q(GqAYv+n3sq$%zih0v$>@$|DE8r-$(@#|to5N`5>*L^RoX6%X^ z&09%HvmuEY8BVOr8uaH zZQ+!;h7hO3@nFuyzVcL584>Hf1>_XzH`!gCBI3`;MD*t!fAG@9-5oWY4*kdtdG>6c z`7d2_Z?$sP3V(hW&YJFt%7d9Xwk?L>Hx-GTY$7vB76%nW?=a55@eXLMKVnFuEMUa$s^xg1Zy6G5b_k-Fr)h7U@t@gW-O zCre*mev?28<-t!tqi9yZ2MS`=4lg|+H+-Fve^2~rmk%^ZQW#D-<~q7^woZiqrGY#> zS`+>hlc(`4KKf;2)9H}Jy8wNvIQNfrW0uF+Y`*)YDkNLTfSa(zb*f*#%OlX*6BI-! zE!r78B&uDJyt*|O`&|TV%%SI zEJsWnzxB~wI4MTB0h*QDy%-6loMu1XueK&VUqHzW*A};z!ix}PFN=de+`m>&-tuWv zxay|!)xi2wpHG;(udk;Tpd<}Vn|2*WZfdLATz$~xn_u)z$*Rj0((WoR(62205-EA zxUG{ChrwU$2$$+-4rHlx`n&M_n-+q|)DgCw`^YMWk5hPx3i3B~dqwJV^82(fARe_a z=XrWTrV>TrAlFeS}Vdsq<5s ziUK=@iTG)s-rzUZbMMuU%~^=F=2PNr$NZ3bc2F04HY;R3j*wk+{H`;Vp7@7nEM?(S zBqBx<-b1y-enY=05UTvsYSIW{TD46 zp0hywYF+O~-e2EoO9{;?_nD7;_15DwC1>@Z9rtCpNQ~4IVK=t6}x)~maIrD zJDk2j86nPx>Yj1qXmuSPyytWYZGO!24AaNJ@{R0ngqZt_wEa$cgcV%?QAkRS%V`^5 z_OoU`FL^V9HX1HgqIHrgTkc#?HzSxOS%>K|GS(5J(wHER8Z!zfDh!#1xkSiwHA4cb zxI%K-jIM|WZ4P1rrSXluFy%k@dKxw+k>wgvNjTa|1a<_BDv?iIBi862Uc~s+{Jm0b zSZ5J_5igr|#f0~`Yx;YvmSzeEk3VLbxPKv#VQ2NJ8V`6>ITDAe?24UAqpPj2(Q`bz z!>9{C9G7)!J_08Qy%i%xyq9FOfWHjYx+rjZ^Pe;v;1jm8>FGQVnQMj#`J5+P9@*(j(sMXYL&Nv6+(I$y`uI^hP zR;e5V0ut-Zc?^MR&~C)Jn2DDzCB|GZIYehZFO?1oesv05D2|2?AWMe18D`TgBvPS;qhyI^L~qxq4CF@_bf zjeZi%inlU+4mz5SyrvQ7=WwYJkAX`??0je6GGh#e7=5b63bDqu&u10~vG8E#(=cMD zvabv6Jl6y+%)E;AhXpP1{GE^{^%N7b-wMrxlchwkK= z^wN`#apJi27_8&0jYKey3wcmIwX9eaBN>xT<|LPqulrUe7Srf7+ z5S@L1|I#ERR#|M2;aSw_Q1I{7i)&aPR6m82eCmXQOSX-a&j>hxY-gvcHAGy)76?`g zhnZH*Zyyl^N$lzcSEC4{q|QK{4HMGZas9|=HgvyEd*zk&apu5_USIfXwNyBS_;pwU z^d%(PlxqLhVy}5_-od0PgRG+(`;$u}WtgD--^aVbkXY-oub3HvB&@@DP{3zf&IY2` zcRnO4)2YiQVQ<1?96s3c@%P#&rEA58$N*tb@l{!4Ou)~P1_mBilht;sTqUq&%fQ8Z zN@f&_q3BVM3~1ZIsk_=@Y8SxV$l1oJBr=7ngtkQte7fN4rb*aL;x{iAdDi1yGWjuG z+`lSVK?5SM@&jvonGg*tWco!yE3J3$S0IJTx23|r&HOvz^kFYCJ?qLz3|mMJWC53y ze@El2DseI6iIVV4TR)O2ldzeo#VFxGqSFLzbyrmk4|57xXD_Uf$pinOOyi~k7tZ9M z4(s}HhbIXw#I>%0aZ`G~#=INj1`UsV-el^>&@5pr;w)6a6iS1(@OT#4F40d9 z3M%lWRNJMqE7*-#i!5*-jq7j6EREy(m)eGvO2}Ohe7~zgmecJ zXgy8(%Vn(7`@h<)giFsy%S>BSCAZyA+UXs_ZTMZ3ExtL0X=&fV*hXSBzw!SldMOY8 zNQS28ofGi=;fWob!v+7GIUo`vH|o@}1ODpUcDDk0^{9A05tIeg_GAByJ(lZEF65YY zg;FojpGjVHQM=JJZ_KI`;@*OjQ=D&Xek6{dKi8TYoLf(33o3m25c^bqTY5Mt`iOCx_h_{06JJ+~3}v+?Vtaim@NPUi`v#@Jg^VJOZ5P z#A5Mw)ly^e6A%(RX(0+%3(#6r7*uY3tb5}NA8yb~*IM;W3AX#wKUZ{R8&TIVo?`s^ zMMBYj&G<=27lD#XC1aMeS)63=bkPfcgd~}Eq|=DmdYWf$>2lhUBPrjE6R#+9#Wh%gdB&CdC;>{k zzx8_r2w2~UReoOA&|*~;BQI{%NJOLrhszwdJoaE_AXVUV0g$%w62j9Pi0I;c^|`^s zfP=C-7n!Ob`e8Cz3X-Ss)^VX4&Se!e?P`9U^tM)=kfir;;y+BRisL5s8&YJtqm4S_ zCU2;2#Hu7M^tOF-uisjKCm3xD{TLc!blR#ckH4F0GJ4N3#|>bzINA2C06;bBP4^65 z*xNxB3jSi_GM9RIVQgdcQ|)6N(R)g^`quJqCmmqL-+q zLM%1k)(+QGypq^`p^?|;M220a%3fm4m?1#uBl;+gd7yRl|yX+iK+zBYR%DF2Vy%2 zBZk6E4o5LDY^3BmV;b0Ux`H56+)LPyOTDESqkhX5lQy;w>pb&0L>KygzIqs8{@L3$ zrvn?$DqUdNRHGGn86WmidB>%$p?K3n5feBYp|QQMQoO%1cc@zYF7BKUx3%1}DYe@< zI)&N15w>fP1zks5XVSvd4mgV=^@o4^Ihh}PuozN|JSi16%FW)hd*g?FI)Th>YW19$ zk<}iQWknGcGzNUuoV!>*IpRFW4NMBOXSQw5uY#TMNCUc@;N2KmN{J;)=5!2e0j9Gg0`a0$M zTi>31VvnieHy*n$D*`>R&~Ps~H)*@Zcq-S&FV&pkoRO!AGHckY0CnmR=S|>CNW$(x z+1GC$x*qh=hn0-pI_aM((&|*>ERd~#%;sXJJL_2^@%lE- zj*M!KWsIm)y9XLXd_0$xu~fA$8TV}yru{P0>F#hPl-_eO|GV#coXY&)@}XV7f=wM` zkkw^*Hez5<=Hc$wLv94QiQnioPG);15~gOdVa+o}aKe~Uv;WqAv&ou439d_Jd9+1w zRnNn&)hyzlFS&?n8!}I!_D^rSW$srR$bQ}4Up60+>6r!^_ZB^rh%L$0>=a}#a@B3; zI+k{lsTUb!dI$V!)>(t?oQ%>TJ~IJR8md1m>h~#M9#r1b9{re_^|)_8xNE8FzP-NQ z%4P#^W_lTm^mCR!YlCm5JBe%avYq(y&kPEVX#|^f1U(S3A)fog?8^r?Q4N)2Cdh!SCoUSjJ7R*?D6VxqRye6~}G3x@mU2j!cp#14tk;M7po`kd_j2OzFaVc#7-i*!f&n zdhT5x60 z^lU=Ske&aYijnW&<#QTDZqR82RK(eu z%replI@g}(W-Rq4b@bmY@z6nm?`w~tE^W23Jk2Hh;H!3e@#0^GFP}E^?n>5f-LTL08+a{vWQtTKG(_CY$TnCXZg^p`DP2M;P9x|V34%=Y z+(efA%ICb-qTFsj6niI)>pN}4Rkcg>&u7&Jh{TXb#U7qpJK$8226D>RWdc9WhkOQ@ zVxK)h*Lc(j!tciTruKHR4Gr8#t1W`GInmh~I*p8vQ>{M}h7i_L&tr3YQ;i?;zsEz(Z5`&WF(u&akD4E!M0w3n~vtVw7tq zZ~#`YH2M#}G8;S%AhJ!46{hiJ{4C6KY9;t)#=!wjk1?IpsWohJ4^J7Qw*{7*p`k0Q zUZQRL$3lr={*UTdW~4C$0sgDuZ25C_vnjcq_Q;X{GXZy2-(Qike&vnqP26Tsd->T#ui2Ezrh|T&0&eED(cn6HtkF7WC{SswHrpL z9Wj|g+>b04$=Rs@3*d9M(w!Vsrgl^Go|%So&7ZKZ z+9wv8ZV%Hj;8;s_G7s0o6O6n|9@tkw9;CO!`A-b7)ZuH#?Sx+UuYs30d&QSCAXX_i zp^`%ifE4fU9QID&n_)y^w}%i5~Ub|x?q6sPqW#us4pf0U81%c8Udw% zA+3;?ST)Y8ol82KPI(qLt<>z4U$VP-L!6qX$9nK z`yacRBQ~8oxH}!rHozmZ7qjgDuRV#QPZ|3b&N);s%$E;Kr(=ZJ-tTA!q>+qGhk?&V zRTh4v7^g{QJ2hR;_rx(RAeYP3(%qwGj0ow?DF$wXLJ3P55iPAj$n|i$ndk0fVpzW) zk~rG$il#M?HkG-&p0UZUP0}@0k@F0^k9?Hy3vn^WBli8ppNtGDr_eLY9E(eQ z)ZbqyFR#VOXjNpQJ{fcvF0c0{?4fg2j=#l`i()-GtUod?IMCf11t%&mH(oBP^9E;l!UuLI+TI_Fduq9ns@0_O!K(YBMa#3(ZWKlMYgXLVrOh zF+uc(PcKW#emb81ZwHkY?42qFdz}C0sQl1Q~qq$&|TMMJpwD_Y$j8P~2C%&?Fb4t3z?szqwW)5+G-Y8;6Is?1$@YMQR`9FrLVX7`k4h z5RWdr2^idjVeeQIR~-L)_W#G_2NAD)-7}5N-v2Symj9p2cYV~P$>eaI{`>PYH;j@g zQTOfFUX%JZwfMr*-(7(z#y&t))5khKi>?}EJT7we#{K8$BLS$PAI5(qb^Lc2TQPK9 zBafsx+q|gx{B*}%R;`Tfd?Wzt14h!zEIJ@fL$mXZ*qi^4`^BLwCT_y~8~=YNeM1-6 zo4{6&I=RbLKEQv7yr(PD@+=(lvp}1aSb>d5>#RRcyj^Jztsl)(sehBFTpP!vve{)p zi2tvbaKnQN>q~W&@s$4^7@z6*{`RQ;KmK>Up5VAU{wq46_;fu=WYHOEjH$kt3tkII zw06i{zh5SPRQYibpOU}B2zx>@h5 z<{TwN#xw+!+V^X>vJN8!hMckJyuV8v)~w}%_w)bhGY?8guevv=*5Uu(qXICH;F`_r zuy%_T!q?%#v4Nbh_P%-^3u4}FxE5tRNuvga|Fm1$Xk<{PHI_@3`rmgGA@)8U6nXcK zs<`Rqce?LktwGiuGW#4AHQ)Pqolof2%LQRpN`fOs{`m&nh>_Olw%6rqjqNUljyeKd zznvQ~k7}>MP37L{>)eb31nRv^j1y>=j2X>Vx-t92vyfyUWUA z|H6u@)6#CbJp!@ySmsO|Qr5&*?UI!L^1d@dq(dFjpWFW6#SkY6TtXarMYj*iqXY*? z+#ap?U!wp6tKtQ`pXVrqkp2+WLL6jSg#2X%WuVE!&D0^1yu4amm~MrLgX}d?#eRn{ zbskNEm#FAZYk68RruC=syk-)M0epAT?btQs31~Du~5*~(z7u zN;^ml)BZU>yhq6S(LGACR}#b!M+-zIs$o>WS~VRw_6|zr5T90DaFGAPuGB)}^^3Bbe7o`daGnENYg9jazn1#asP>;BXuBf$cy zYi`p?loK8k!mmu;q(3A%(t+=^>&;f=S4^@O&*W47OOHN}B2=D?15GC)g?4^5E`)}H^9ZDdGa zxBh08yxxUmm8+A+z6Zs0zyDM(f#(LLZ}$%~+=g6`4wmPO4EOWsxSX+9EdxVwDs;d6 zx_OXM^Mlt><0b2+?>4E%KLa=>CNg#rM*38}r9$_QZaE5g@U8Bq^JTv7VS=7~PToNJ z@m{jNHDxubdo-nWYR>TKk}hScO%`Zg9+%4!;!geYkwovby0H8WhcoI+BecfE*Kx`Y!GNPLq_qZ$?>fFX==hD0)?^fA&mKil_J;!u4_4^d)aDl{$-YCdztI4@tv ze}-^vR7%Kx4}IQFwC#@Zn+TR^oV?h#gt%NfLJ{;()?Yx?YPxe|a1|}pc7&YiPMaV3 zqqv&m_a}%#B)k0++B$)%bD>ez`!j*!?5kP+7y8wGFaL-VaB?zn3cFA+O0acgXn%9w z?EYsQs7J+t`n_RSCv10oF@U(JZWfZS6L${=NZ%bRT$((bn}o|SL7Ts* z+o?96!PF1umhLZf2?dHe&TwLeMc42`zh&~n$FlDQOX>Yv(6E?88Iy4=!2evEI(j5Y zsc$AI#0ZhqWk5#a%1>$H9={EMKa%F_kDBZt?n2wIuIYsBQzZ^6#z>l#RRf+NQJ?=N zid3_S++Pm|)LEq%UHl29)J5qFAyZ9%d;vNGT$lLk&KSRO!{5oiWz^BZ+nwX3o#dc(!6-68eTm9oM{e|VKH-MNiC z6$zm^e!>%(yA{F(R8RY7`Kj`H4wVx$o20Qisr$<%ss=jBj`ME@^D0Ax=CKzHa->N1zA=}p)T23%)ogfe#}OhyBioJfr7c(YT$ zlZ2Nq)VCbI;0o)N7=KMN9vb^!2iGE4nYS+=oL>p0&#Evwp{`4PY}Tqopp2J2=k!lc zzYj-xx{+S-!&SG;eD?iWL5CLG6r*jKSwh0&wax4Ra4oF|z?lJ!fe@t>I8KN$a@qXg zUp=Z!U5iXWKQ7NZk??r|)q5Mojo1Q+NMgy6fyFL&167n&pBF9uvJ`~-CNxurfWW|e zC3pcD8TV1@G|V*2H65+3`Y08RgspBGx5#>Aiky$&Y1&4@FWTxcEs0v8DZ_U*Ifws| zxwEHiK5Dv+Z$I|NRzoTJ)GT<;4HhE} zc6LP70!})~r>f&G$=;FVG$2#4+Jg%18!`|Z&hV{jv)seLt>U+jEJTMiPy5WWKmOES zJOwC(Y|nX2t$({fuFbuWSV^q3H@KjU3>N#1d0}92)nVS-yv9 zY=L$GSMBtluxQ<150X0c`fLB3lx$7Yf2o~3A?cEEWn`NZ{3+{E(RI*|Pi$G<=7R~b zz&m7sQXeGkky<@rR@zm8f7w&3O=F9Owqns|gs^2xlAb{I7X;Wt*@8boJDqsHOG~o9JMD1U&8~2)S-}i{IdyKS zHAqjC+*OTqoXG}jn|N}#x*>E!tt4$~AgW7AnmJ$=u^dGB2|UUG+QccGMV0!DXG23x zj?b8l1&#erH&RTB3Y+h5fa2pq8>rqTcHlP*wc7RQ^u3R-W5Ok;xHs@R(@9jCy@)fA>^&v(dKU|yj$Py*Xx0J$P>@)G9zg~_3tw5Srv&Y;7R03&i*L|AoUrt~G$Z;)qt{0`l~A>E-$?Z~&S z@?unl{)d^=Xr^=me5>{>F30)WO_=5S z9M=Olm*5+4JGaE2_t@z~m(^(zLuEBvxq7kJ%Gj=6(f(4SlkCwWaKC4}S zOwLGFW*9L=q0z^BkDbnDY$3*y(ITiU>ZaYJ~E@c3|sPOd$AP5jL=3_CzvopJWFv0Jt=RlG32aEW=eh@ zG`Lx3YRu8VO^+%bSa3r;o_DXc#bq>}t8i?6TxQf^SHgO2J(^3La}b0Ukk(RA*zbSP z6(+f;4ZKCQ$BwZd5k9Y1F$hyDKdSBMHUBow((&`qZCxsHD@Nwtn?z&kxd%Z0c3klS zi6Yr!-lhn1oRpffpoXn#FIku_OY~Bz(7({=n*u+G%ue4fuoN%RY``vNpT^N15wDxvN5AIQ2_`euoON%^` z5pw@>(kzpu_%tZPj{Y%DK9_Hlu$QVLpmvzvGQ4`?rJQe#uAz(4F1bSkryRBZ>ND~( ziW7s`F`IRD(l?R;$E{dnTO?$;R41&|yII#<*S-GtIhB8KDmfi=kBJzc=_YvD9>-fp zmZ+1$$$gI+y;ikJVK=p`-C@J&86z=!MWe5iTvx4ur3wtdGQ7f5&cK#L{x78>CdB7Y z;|j($sa7Rf7YC5TYj$%6mLyb!6Mhj@Z+jBLDgUu8?>Wcy4?|Ec`D+bRvGTEYn}>XgZ3TM*|ak%>J(si0p-^wlh9jTH{!<^4w` z)iG_=IvC+-%C1+;Rw5f~qGnsfpYR(!iYA`b>Yq{x|!k#(h=XssT!~5KwFu6uR=HZFRxEM6ZWz?!C}{EcQ$cN zxoT`DhsfswzPH6SH%He5j{0fP-$ab~VJX&=^#yrasV0Nce*nc8WJcBpNO)r#fMu!9 z^E@z17Kb|=;%E6xRHavF#f+l{TL9lit|K}*hF+H8)Gsec2CBjyB;yHO-`=gr-*jUP zDj)Dz!vdAiG`oBa>Pvs_9s*%6d9pEJ4ozXP1cP3X163RO^e-*z@*09C*aS%DDeN?= zC?Uo*aW8%&FFr2b#jLHN7?H+*)4pYH4D&_4ZF%wdkZPu^t^ywUHo=H}d^Puq)N+gi zZ(zGV?xznpKqGoodASa(*MC;$4>k~Jv#zVL{hfttgH+dUcW;2!dpS_*E(=L-XVuR> z4tQFgBg`1cx_>hDT3i`ESm(%LdsM7w{+oZ1p*H&E{1w)*cOLZ;Ghwr1cKn_EJ0YxO ztaM$j8JQp;lzQD0y6@@oU`6$GA_O24~Avl4{v zurX&74NYqelVF<+bPICCHpJ(%#szaG+tlRfGpQM1I~+{WXR*f!7?DZiw96adH4l7d zq3g-boebk49%%UY?gS}ncjC*}XPW#yfs9ec`|a`?8fk*RiY(J4In*8HKH8EnRh>&Q z|2Btu7%7j(#Kv+fJPn>LQ8H++%;)+z%6N0E+=mSkbY1V6MUqE7+`*?E_Pwtp(_*_k zKT#4N*uy56#mq)KCQ~hnYa+LWNzy*W9jC=gBiYuvCt-^CI4CS`FpY@mfFEW6aZgqj z09nQ<_hAAkNe{4^^%<>AjuU=3WInGNKq%t?S2v9q12}0cFtj59%?qg@N8hsSpk&qQ?|KZABf_<-UWKLhDOKweXl5!Rie%P+zBCVMGU)|nyoBVV&EO2 zst0|X5l6h78YF?)?qvDFd&4iPD%cIlco=wrCa%p-0Y)2AQ&!&*!J*H-gc=L>eNqRM zzB0601l@gaq%+w61c~i>))Na*csq~LJi@XdnLzhpR&HB&&N0Qkyb1Rvle8I0E&V90 z4v$WUWn|cStbu7PvpZfrSh$R=|J-zaOpe9`m1sEZj4p`9A!XD0o3Z8`A;PRg88{N} z?qU%d50tO#DY8qoR#gohwrE!P^2A}%8scz_!u<M=!;<_fYFGC~#bSIZ96ri=r*BIgzF-~zzxQWlkQhyIq&q19zqR0Gm5REjAj{_yZR^)4BclK-=NEeg zVX>Q!GzLr|mdt4nb>NXn{5f%uZDMTEO_qgxkeBMc-n95yq`)VX+V@w!t1kO-Tpcr$ zM4QJ(ZO>|NG6RnZf`fk}X^TkX;4M9q8=nKlCeip?WfyiEjwkOVNUCe}&jS&l6DIBh z`6H5F@giarDM~P9j3~c~`hJ?9bEhe%$Jzo9o*&*l4w zdObo*B0qCs4ssSmD6N-LKoR#IlL5O#(wr`y7+smv*LE-jh7BmxWPzj=Pk)$54Y=7U zFpD2u63^CW)fa4?#RF(!>KHgw3TEq91-3_ek^=naUAkE|@&*-Z_MSW?V=H;?w^vvl zqGZ2w#3=u9QHp^7IZn9yE<5wzPA4(|qUA9m6l*)&L@lD~o6_g6CI|9hm~d%2xbwO0 z_;#qffs#RTa1no~*RJ!R?e44luh_uFcL?tAWapn;JSQu;CxzrmzikutyvvHTMOPqa zjR|0MBxa0VUsaix3&QMdNN(zGlg+c1n8tzGPQxe#WB%z`MuDhJrPrEiEf5M0fnVAD zR<8~|KPFH`(7E;iJk}L8=0qUq2hsq3=K`%vDxY8F0HffajJe8!P=KuvpT~$C)_Kpn z{VtTUKhelr$JNiVFWcZKPRK_g;%FH2^A8DZWyKyc<%&3;D%c4GWljEsSa38H6}SzF zsnAW-B9XmEZ9iSpv?in?_G{WeCzv;&k;S||rOpWWBguz3V!<>E$dBs1<>9cB8^OIx ztmXJUhx0%=eV?Il!E4E=fyFToa<<-^kRW&_Pjy6N4f(p*Sci8-&xx)I2F&(jProK} zAX8}rA`{+fj;X7{7WIKQY?yzEX=TS^P^Bjr8dE%+&^0ll2(6O&3jC6~-EfWx z(4-UnsfkU7oy{K#h!^SOq3Zt9$yGg1!lC0s=&A<$3JkL|PgWp}P)sOW2UG-V`U8DO ztOVseGM3}4s;iP9f}4yOsqefFEDRoiV*SoLn;JKBN*En2A?Ac%fmAn7J13S^F&5u$8yYSV&W2RXSU6MFz zC=b;IM1ko3*es@?_W$tNAc78gswGL94Vrm z?x)dQRscQ*>#}`tZXo;pbh3$(vCqyAK~9&%%1-sB-ezco=B8wzYFBYpAQwasG{n@$ z;LDtuN^7i16qqpi6aVxX_fyn%Z%)d(h-WE_=KSBF#pB2>ZmPajnc+xCB4sm3(a+Xb zn0b(8Y_>s_SdBa_fSvzT?%NNIW3ME;^0$voVB~<)G$ve$ytozR+|f)$%#H+aL&8P9_B6o_8d+qb{BrA-k7;`G^Lj z+s3a(S2myNIm;duBQ0we8fwPC{i~TXeYZ|~!vFC}&mq43WCS)q6C^s$tF4&u?LH@o z(KF-8yZKbl>d7MV=5afxiaDKRkx2E+?nK<%^?&EW1ytxadTTR%2r(pf1?=$(RXHh0 z9+Q*&Bq}B~%9PAC%5@a$oB0z=HKJBGfPe#=;) z;jOaTEi^&v>kT1(Oqz)8l020dt)ozK*Vp=Fzkc8V;plwSW78p@$EYG=-9U;p zlkQ3hr0?i+WVg)-4S6Yq?e(@<5ctNcgs87TTG_$m1ZP6bb8j2}=n$-=97wmk#N&%Pg zbpCFtl%22XP(sRlL5D-Bd8eONQTJeG6KG77cL&*Mktfzv4Qd3lf}QnW$6tWgqC|F8 zG)+Q7CE`_PvpKn8myl4^r(LO%JDzbyXm9g%?7n+RNGAvU>%++t)Q6KF`F_%)oa5^R zQyL?qP(^iuF?=Gxoz=|qU?gm#Dv zWlHeKq3Jb4Fkg1g;9FHaLqQ>tIs0;PhfQ9BYt1Y`JoDXhYmnWvsj`J9YWq}DGDz}^ z?HD5@4#J{YVG7s=yaL4cuno5|Mc5MJ0PljRq1+!gh-}xD5=M!BS_wV}FtB8=n+>G$ zsWnQUjVOfAkd(yVDTH-lFuobk4l{89T>NB%hkYYNDVo3y>nntg@yW%o*`QMQrHvYM zLGuke`RODQoAU*CrhnJgsmf^Gh_DZ+$B63;S50P-vWogrnZYm7kb=g~5|)yw< z88&Ae7*Fi07d+KWzUl~GhTu`YC4Zm(bXDv;>K7qdgm*SOnyM&`Ukd=`@qll&wW2>6xS;gSD=m!`ekm(OX{JTRFDm>D|tWle=+vfQE_eG zmT-_D!QCAScXzj70Rlk+!Kn)F79a%o!V3r*G`KqicPB_;!94_*0O_jx`rUiG`}fB8 z{Z(VYfpcn~y=<>J*L>@y0Z2zJ?M}VmkW;CT6XeBhle$@P^V>#}Hec;`Ksy){2Vwf*z?_uB{>u)mj(x2NC%f`?FF_A;bhQKDx#8XwB zKevJ+`pscRu!!a4mE@38NI#mtv?rF-klq^;Jy@FkD$J~}Afiuo`O{QbZmRT<$D!!_ z&vQ>gMzXKBr>!(}UpoGK7Qj(ubP++FABT1lsz&2WL+1nWzA%Yxt`oIv-FFs<`RO-r z&t==DNL@(jqKQ8-hy?qWpHwe`8=U2(y)UPgi?>_1-@O$mHiWR@6X$L}Q$vqdgXW=h z0rx(Mqec!8YocLnOj;z)H*<|Bf8U!+Sfk3j$WEy$R~-2Yx+x6g*{N0><*>c3uyI(omA^zK$4n1e8*Hnn@F2UyO>r(+bls=erk#74T+jeGX(5x1+^!e zY@c1AcgsP8a~AX0#GGtz57Q%omg|iD3A-w>8AHdGos~p2u7jd1Pb2hs@Dchlqvql9 z@AW?cI-NFK_ACsdLG7&QdxCmd3ud0|mCY79j%QC$yDHHtkE30PWn4iP+^-E^sq>FB zn%=KGHx7gpUl{GHF8_*Vn@E~$xjWCenn*hNxtr;v`QW2rzbAOUDln^_L{WJt??g`z zTIV0*3BIr@$aEPX!}#(GLuP{e6_Y=*gX`T+nwJ`PhkJbEE$nYwZ`K2)K^GMxH%w`7 zHzm$KZ%-$6PGojFUrdNQ*~_sxe>QLeAyP=fYi{T8dFITI)$fqs`>YnDqmbxyUHV_@C9j?e zsEp)x+=rsSxdiCKsmyL>IoG4KgLt=nz19TewuzSi!z zZoD8rhKDO`%_^#w%I<3=QM6(yc5g1l_C8-7~G$MOMXcL6U$hYgpJa^N*I}|>_))i znP5w{=6|!QdqGv9-n)4y ziTn_h^D~4%Qw9I>x{YdAc;tmq3FM~?TwPtvjmdgzpZkd?^8yYSP<7#H2|9?a{nU8( z)@?im(miG4JQ8*q|MbwE{L`!Jw~5Jg`^j$wOCv{%MC+ZDH=b~?&C1KSW4ZRQ74Wz@ z4*wsr;WT(QoVITaHHrV0YV3Hx)p0pfK)E>Dal0Aa)~Sxv@=SQuJxQLOr2FStv&+`Y z^o(zs{8qG$A&+^Uk&>H1F$~s&^L#?Rc=m1Kvi2-mS5vg#9G~fkXJFZ>Yn94(KaVxiK^(jD zy(~~!elGeWJBB%Y$b>5dkny;9M4U$@r?fTM_n#~S=I#XG(Wjog=D}S8vFquo3Im6G z#WG%U1%6(3W?h3hfY%ILi&Z!R7k(tuhZK!T=^Wv(m2R6YS~EOa7fHZegn+-K`_h7>-8u}&WQ-QN7#Gg*+spEzgzh8(G+a4$X%}UvC4JowkeHHW z9v{|W;qDMF$pk0&uOxmth54*4kwvf_!T(^-1aQm>fnERk+%(#X_f~AEkP9sOn+Ut_ zPsMSCTXWGM*q^U`xEPPSAIO4LmM^6UT=PPSU86Z_Rpct+C;30c*Y7j~LXd6`=1O%} z;XQxKS7>*X?=R#ogLj0M?YCgDeG?7?L5R_B-(Q>`2pNXsg|dAQOA93B#JJ($N;uqB zZu`%9T9

    gqWQKVw>H6wrzJb_(`~mqJa?n*)Q;9wn+G?C|hAWbk-vvOk5!RUBI2S z#f>-Yey;1c1HxhgX{nt56EYQu3j1eGNP5w;|33h%@M~{A_WfrB-2eGej|Arp1byxQ zkG=5!%lzQi`pH-b|9{*c{sDy-`X@5qH~(YL^Z(k5@M|S$YbgHTJ31o6m5YV{59qBc zECAKRIUuVLUQ0Mi=Z$Fl^ZmETQjeFqO*doltmBKIPxFRBK(T64+@ZjBa z__a(Q+X>-c>(l{vC#D}bJ^y(YmY{FaPiHtc3tdm&;a!lQ#_RX`k+{44@GP7x2rkd# zP(Q8YIIAJ-LBOo(KC3D2u(K&6Ta8$X(NoH6)tPM3Ul6YWJby7T{!Y> z-pGzq*m@*+d-?ne&0~oxCGo#k4PI=W^v+ud{d4w4iQM^ct|shp`1&s>EG)EgpZQEm z-Zbm!8!|B`OY*_4aa1-t-yU{^OS6u0)cqG;CWe0kVq5^%F_txRYCjur?0!yCej)zh z)>+v15-9wBjz!pYd#Kg+`inT;qRSvvl2Z@So3|T6OIArMav#q6Nq%w%-bHWu@mURl z#k#oLe|<9c*-1(A`}43Ty}IHyX>zmjuNWe;P6zXT>*h}XFiw#0gT#L}_ny>_a$)PR z5jOtH1Q+oUW zeM3k@`@{L@>VKmJTlcQNwBeG9dzQl$?31L`TL_2g!YMc5jq5&&f(zLFj7dTiCukmi zp#Ef*zKd*ox<7)aH@g4V6T=Z`>pvVz$^U+0Vg$4UI8OteHT0T1BVPQZUiVWt-V9Qs zp}T)Ko#x(Ww~09RLAX|JQBHuba4#mmyTY2n@02V&cq7_8JLFX#gHWiJ9 zMPXPD(*_rOf=_0mGQ^SOGjZNJXn8-3Hq@O{gqzRI2#nGdrC>!o3?3_k0CS4B5^otaGOja za82~NQ|Db#re&OH{@J3&zuX=b-0fkjMgI%8PcHKf?Epn48hOJ^<@nt5(`Q(Ca?J6+ zJ_sqV7sP=id?WnUakF+5C$fnKv;BzFf^f1ZnB~pE<1H+)PIZgs?)2XAHv9~iLM5o! zfWw*@R5U#0es#)|x_t!wM|id{6$$E&8! zgnS#GK5$8_-hfZ?fe6*sv78y0rd_{RPi?R*&Mv9~A4e-%55KOyF&O>d^d^}u_(IIT zW?)=_?UtNH=yzU=_y#=JIQbqCp5s|9X%FC2=QY%B_!e<|p572tm_o@2bQ;;q3Csp- zz}CyqBKuSDIgc(vse&OKR>*9pXRUcZ{B6isa6qkFyqzl8GgQ-&3Q@&hS*iX@toqYH{?e-Q}P&5ioV8t z=mIODrsIEqzk%a+4g-JR93w8ae&hG1M`0=Yi_%}E) zscus0$bi&hbDRblJN$S^e|lG^dMZrjk3ue0$YnCCZes7`?fg}0?pcJ=`>`;P(~fLC zn}@Hp!_^^=&jJ8HK)}Cl&Ei4mj}6?GUtm#m3UM>_?1tX{#$QeW7nv`$b6iJQQ+ibp zfw%C^I(pvtZ5h#Zz$t8JSlNf|3Wkub6OFyjZHa8ZoKZ`EiIT`oNFcHpE21fOzzFZ_ zjeL>v05OBB^@!OGFz=uXovCpq(J#Jjcv8A5i$PrW)q*0V&W9L|h$Hk3ty2{IGHZg+ zEN}DV!$&5?(iDlYeXMVK^^F~NxH@k)TlXFhP{k2|dvMT+MZg#JB?A`ut@fCYJMe^k z4s}F?S|mUjsWde~Hr<)!p_K8hoCo9hYJ!#;3cr+G$>a&+bg zbJ%JA~5hOK)v+f(#3Z3>1&a4*d@{`i~Rg?v#P!f(usnN4uz|mQww_%ip*; zMnJ_`sh#X=aD-m6F)0epSY%23MsN7u{mriY%+nabOiRE?-al?bAnc=4fy^k{0gILAEN)56v+de-olMRAoz*dh zf>06Mt_pe~Hrq8sI7?JU91S$Y?&K%PB)UyySB$Z-gpSC2H16>|WtE2hO)#2WaXT!W zHh9b%GHZ~~*I-62#z|=Fn=HuvYNY3ku?GoYVYp+>WiDpv7g@e0w0_Z+sAT>-OG2Z^@ z4xW_&lMLAgf=x}>p1=cQ((S@N^!|*eH485$E}$us1MxIDKf3*l81rB8+l)an))BxV z@*71lx2yD#fmIHs`zC8l=i3@|#P`BD|D=_#uwaR7*~WLg&PU=!@+1i|XSY~@0ohq` zMX^GCh_GBMrmO$nVCHL80KavE^gUN`YAx+EGR9L9M`}8%M5RYrHFCsIDsn)Wj3IJ} z{f0j%B}@QRcl&i+v67C2cEIS0*^10%9p;v-qgOlwjdWl0$ZXZGBGT>SAgj4_!Q3P? z%Szyhy{esW9BId?u(4X2lrwfYQzN=)eMn;(4bb%@)4&)7?~rIXR0KSm9cfm@+l$RS0hlRnyC@xAWZ$4EmNb;u_XOD1+UHYPMcC#RY zP5D$u7z)C%C{pixrH$9y3?Tx#aZe)VKX-i(F58=;!Eqo}`P4=ofaYgN{hj7?+`M)0 zTylWQ3LGU5Ra>qMg|Ms9H;OU9;&PzL(jy&+Qx(w-ai+_Xx*~->gu$bbM0n9ZST&gb z?7C={&+CgwKTemTc!5G&TJyyKQO%{;V|II$;v-9u@f5yo8sg^UpsEYU7f~*w$v$nR_KF9A zC%#?Rkv`DBI1N9f;me}PiBQ3S@}6&~pU7`YFS=X*RpcPr!Pot(%0K~|Qg&FaL~>)J zJKHC>)`#aNM)KBK)*|q#W{}!WXh{l3+UI<`po5%lbx&_vj|@mchlR$=c|c!>YTX@7 zXlNcvlqgh%-dDS^d=md){!Xv+X7fC|(U?b@_R%bR*S77PuAm@!iN<0+vETv0oi%$g z*D=McPX9b=Il_lXMX0AyhoW6?hhSX)Jng2!G939t2|9+SOqsB$L+n&TpuV_I7KoG32#M6NJEc&z$pt-W0kU1&XF8z^a�ZO-~Y<mDEANNTuO-1C-+Fgc`)MzQ)LnUkh4hrHx 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%0A}_bSebex15HDY9*oP4MuYKJkDfu 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%0AX)nH{IcR{$fm#g?DX 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

    R)Yj1C=Amh38vyhzBd3F6a_<$1$&lXeTWe8dH_e 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 y|0k}z1g-+0\n", @@ -12,27 +14,23 @@ }, { "cell_type": "markdown", - "id": "4e0afae4", - "metadata": {}, + "id": "1d86ca93", + "metadata": { + "editable": true + }, "source": [ "# Week 40: Gradient descent methods (continued) and start Neural networks\n", - "**Morten Hjorth-Jensen**, Department of Physics, University of Oslo, Norway and Department of Physics and Astronomy and Facility for Rare Ion Beams, Michigan State University, USA\n", + "**Morten Hjorth-Jensen**, Department of Physics, University of Oslo, Norway\n", "\n", - "Date: **September 30-October 4, 2024**" + "Date: **September 29-October 3, 2025**" ] }, { "cell_type": "markdown", - "id": "e6b378ac", - "metadata": {}, - "source": [ - "## Plans for week 40" - ] - }, - { - "cell_type": "markdown", - "id": "1ba91689", - "metadata": {}, + "id": "e69a8d43", + "metadata": { + "editable": true + }, "source": [ "## Lecture Monday September 30, 2024\n", "1. Stochastic Gradient descent with examples and automatic differentiation\n", @@ -46,8 +44,10 @@ }, { "cell_type": "markdown", - "id": "fb1da492", - "metadata": {}, + "id": "f48ef548", + "metadata": { + "editable": true + }, "source": [ "## Suggested readings and videos\n", "**Readings and Videos:**\n", @@ -69,8 +69,10 @@ }, { "cell_type": "markdown", - "id": "5e18b164", - "metadata": {}, + "id": "cfccf861", + "metadata": { + "editable": true + }, "source": [ "## Lab sessions Tuesday and Wednesday\n", "**Material for the active learning sessions on Tuesday and Wednesday.**\n", @@ -86,1142 +88,10 @@ }, { "cell_type": "markdown", - "id": "ca1eb3e1", - "metadata": {}, - "source": [ - "## Summary from last week, using gradient descent methods, limitations\n", - "\n", - "* **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.\n", - "\n", - "* **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.\n", - "\n", - "* **Gradients are computationally expensive to calculate for large datasets**. In many cases in statistics and ML, the cost/loss/risk function is a sum of terms, with one term for each data point. For example, in linear regression, $E \\propto \\sum_{i=1}^n (y_i - \\mathbf{w}^T\\cdot\\mathbf{x}_i)^2$; for logistic regression, the square error is replaced by the cross entropy. To calculate the gradient we have to sum over *all* $n$ data points. Doing this at every GD step becomes extremely computationally expensive. An ingenious solution to this, is to calculate the gradients using small subsets of the data called \"mini batches\". This has the added benefit of introducing stochasticity into our algorithm.\n", - "\n", - "* **GD is very sensitive to choices of learning rates**. GD is extremely sensitive to the choice of learning rates. If the learning rate is very small, the training process take an extremely long time. For larger learning rates, GD can diverge and give poor results. Furthermore, depending on what the local landscape looks like, we have to modify the learning rates to ensure convergence. Ideally, we would *adaptively* choose the learning rates to match the landscape.\n", - "\n", - "* **GD treats all directions in parameter space uniformly.** Another major drawback of GD is that unlike Newton's method, the learning rate for GD is the same in all directions in parameter space. For this reason, the maximum learning rate is set by the behavior of the steepest direction and this can significantly slow down training. Ideally, we would like to take large steps in flat directions and small steps in steep directions. Since we are exploring rugged landscapes where curvatures change, this requires us to keep track of not only the gradient but second derivatives. The ideal scenario would be to calculate the Hessian but this proves to be too computationally expensive. \n", - "\n", - "* GD can take exponential time to escape saddle points, even with random initialization. As we mentioned, GD is extremely sensitive to initial condition since it determines the particular local minimum GD would eventually reach. However, even with a good initialization scheme, through the introduction of randomness, GD can still take exponential time to escape saddle points." - ] - }, - { - "cell_type": "markdown", - "id": "d1832283", - "metadata": {}, - "source": [ - "## Simple implementation of GD for OLS, Ridge and Lasso\n", - "\n", - "Last week we studied both several gradient methods. With and without an update of the learning.\n", - "We summarize some of these here for the methods we hvae studied in project one, without the inclusion of momentum." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "0dee3b51", - "metadata": {}, - "outputs": [], - "source": [ - "from random import random, seed\n", - "import numpy as np\n", - "\n", - "# the number of datapoints with a 2nd-order polynomial\n", - "n = 100\n", - "x = 2*np.random.rand(n,1)\n", - "y = 4+3*x+5*x*x\n", - "# Design matrix including the intercept\n", - "# No scaling of data of and all data used for training \n", - "X = np.c_[np.ones((n,1)), x, x*x]\n", - "# Learning rate and number of iterations\n", - "eta = 0.05\n", - "Niterations = 100\n", - "\n", - "# OLS part\n", - "beta_OLS = np.random.randn(3,1)\n", - "gradient = np.zeros(3)\n", - "for iter in range(Niterations):\n", - " gradient = (2.0/n)*X.T @ (X @ beta_OLS-y)\n", - " beta_OLS -= eta*gradient\n", - "print('Parameters for OLS using gradient descent') \n", - "print(beta_OLS)\n", - "\n", - "#Ridge and Lasso parameter Lambda\n", - "Lambda = 0.01\n", - "Id = n*Lambda* np.eye((X.T @ X).shape[0])\n", - "# Gradient descent with Ridge\n", - "beta_Ridge = np.random.randn(3,1)\n", - "gradient = np.zeros(3)\n", - "for iter in range(Niterations):\n", - " gradients = 2.0/n*X.T @ (X @ beta_Ridge-y)+2*Lambda*beta_Ridge\n", - " beta_Ridge -= eta*gradients\n", - "print('Parameters for Ridge using gradient descent') \n", - "print(beta_Ridge)\n", - "\n", - "# Gradient descent with Lasso\n", - "beta_Lasso = np.random.randn(3,1)\n", - "gradient = np.zeros(3)\n", - "for iter in range(Niterations):\n", - " gradients = 2.0/n*X.T @ (X @ beta_Lasso-y)+Lambda*np.sign(beta_Lasso)\n", - " beta_Lasso -= eta*gradients\n", - "print('Parameters for Lasso using gradient descent') \n", - "print(beta_Lasso)" - ] - }, - { - "cell_type": "markdown", - "id": "cda18663", - "metadata": {}, - "source": [ - "## But none of these can compete with Newton's method\n", - "\n", - "Note that we here have introduced automatic differentiation" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "e1e51c75", - "metadata": {}, - "outputs": [], - "source": [ - "# Using Newton's method\n", - "from random import random, seed\n", - "import numpy as np\n", - "import autograd.numpy as np\n", - "from autograd import grad\n", - "\n", - "def CostOLS(beta):\n", - " return (1.0/n)*np.sum((y-X @ beta)**2)\n", - "\n", - "n = 100\n", - "x = 2*np.random.rand(n,1)\n", - "y = 4+3*x+5*x*x\n", - "\n", - "X = np.c_[np.ones((n,1)), x, x*x]\n", - "XT_X = X.T @ X\n", - "beta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y)\n", - "print(\"Own inversion\")\n", - "print(beta_linreg)\n", - "# Hessian matrix\n", - "H = (2.0/n)* XT_X\n", - "# Note that here the Hessian does not depend on the parameters beta\n", - "invH = np.linalg.pinv(H)\n", - "beta = np.random.randn(3,1)\n", - "Niterations = 5\n", - "# define the gradient\n", - "training_gradient = grad(CostOLS)\n", - "\n", - "for iter in range(Niterations):\n", - " gradients = training_gradient(beta)\n", - " beta -= invH @ gradients\n", - " print(iter,gradients[0],gradients[1])\n", - "print(\"beta from own Newton code\")\n", - "print(beta)" - ] - }, - { - "cell_type": "markdown", - "id": "8de3d7c1", - "metadata": {}, - "source": [ - "## Gradient descent and Logistic regression\n", - "\n", - "Finally, we complete these examples by adding a simple code for\n", - "Logistic regression. Note the more general approach with a class for\n", - "the method. Here we use a so-called **AND** gate for our data set." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "4f87ae26", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "class LogisticRegression:\n", - " def __init__(self, learning_rate=0.01, num_iterations=1000):\n", - " self.learning_rate = learning_rate\n", - " self.num_iterations = num_iterations\n", - " self.beta_logreg = None\n", - " def sigmoid(self, z):\n", - " return 1 / (1 + np.exp(-z))\n", - " def GDfit(self, X, y):\n", - " n_data, num_features = X.shape\n", - " self.beta_logreg = np.zeros(num_features)\n", - " for _ in range(self.num_iterations):\n", - " linear_model = X @ self.beta_logreg\n", - " y_predicted = self.sigmoid(linear_model)\n", - " # Gradient calculation\n", - " gradient = (X.T @ (y_predicted - y))/n_data\n", - " # Update beta_logreg\n", - " self.beta_logreg -= self.learning_rate*gradient\n", - " def predict(self, X):\n", - " linear_model = X @ self.beta_logreg\n", - " y_predicted = self.sigmoid(linear_model)\n", - " return [1 if i >= 0.5 else 0 for i in y_predicted]\n", - "# Example usage\n", - "if __name__ == \"__main__\":\n", - " # Sample data\n", - " X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])\n", - " y = np.array([0, 0, 0, 1]) # This is an AND gate\n", - " model = LogisticRegression(learning_rate=0.01, num_iterations=1000)\n", - " model.GDfit(X, y)\n", - " predictions = model.predict(X)\n", - " print(\"Predictions:\", predictions)" - ] - }, - { - "cell_type": "markdown", - "id": "c2781943", - "metadata": {}, - "source": [ - "## Overview video on Stochastic Gradient Descent\n", - "\n", - "[What is Stochastic Gradient Descent](https://www.youtube.com/watch?v=vMh0zPT0tLI&ab_channel=StatQuestwithJoshStarmer)\n", - "There are several reasons for using stochastic gradient descent. Some of these are:\n", - "\n", - "1. Efficiency: Updates weights more frequently using a single or a small batch of samples, which speeds up convergence.\n", - "\n", - "2. Hopefully avoid Local Minima\n", - "\n", - "3. Memory Usage: Requires less memory compared to computing gradients for the entire dataset." - ] - }, - { - "cell_type": "markdown", - "id": "1e37491a", - "metadata": {}, - "source": [ - "## Batches and mini-batches\n", - "\n", - "In gradient descent we compute the cost function and its gradient for all data points we have.\n", - "\n", - "In large-scale applications such as the [ILSVRC challenge](https://www.image-net.org/challenges/LSVRC/), the\n", - "training data can have on order of millions of examples. Hence, it\n", - "seems wasteful to compute the full cost function over the entire\n", - "training set in order to perform only a single parameter update. A\n", - "very common approach to addressing this challenge is to compute the\n", - "gradient over batches of the training data. For example, a typical batch could contain some thousand examples from\n", - "an entire training set of several millions. This batch is then used to\n", - "perform a parameter update." - ] - }, - { - "cell_type": "markdown", - "id": "6feab258", - "metadata": {}, - "source": [ - "## Stochastic Gradient Descent (SGD)\n", - "\n", - "In stochastic gradient descent, the extreme case is the case where we\n", - "have only one batch, that is we include the whole data set.\n", - "\n", - "This process is called Stochastic Gradient\n", - "Descent (SGD) (or also sometimes on-line gradient descent). This is\n", - "relatively less common to see because in practice due to vectorized\n", - "code optimizations it can be computationally much more efficient to\n", - "evaluate the gradient for 100 examples, than the gradient for one\n", - "example 100 times. Even though SGD technically refers to using a\n", - "single example at a time to evaluate the gradient, you will hear\n", - "people use the term SGD even when referring to mini-batch gradient\n", - "descent (i.e. mentions of MGD for “Minibatch Gradient Descent”, or BGD\n", - "for “Batch gradient descent” are rare to see), where it is usually\n", - "assumed that mini-batches are used. The size of the mini-batch is a\n", - "hyperparameter but it is not very common to cross-validate or bootstrap it. It is\n", - "usually based on memory constraints (if any), or set to some value,\n", - "e.g. 32, 64 or 128. We use powers of 2 in practice because many\n", - "vectorized operation implementations work faster when their inputs are\n", - "sized in powers of 2.\n", - "\n", - "In our notes with SGD we mean stochastic gradient descent with mini-batches." - ] - }, - { - "cell_type": "markdown", - "id": "204c15af", - "metadata": {}, - "source": [ - "## Stochastic Gradient Descent\n", - "\n", - "Stochastic gradient descent (SGD) and variants thereof address some of\n", - "the shortcomings of the Gradient descent method discussed above.\n", - "\n", - "The underlying idea of SGD comes from the observation that the cost\n", - "function, which we want to minimize, can almost always be written as a\n", - "sum over $n$ data points $\\{\\mathbf{x}_i\\}_{i=1}^n$," - ] - }, - { - "cell_type": "markdown", - "id": "c9453416", - "metadata": {}, - "source": [ - "$$\n", - "C(\\mathbf{\\beta}) = \\sum_{i=1}^n c_i(\\mathbf{x}_i,\n", - "\\mathbf{\\beta}).\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "19b0403c", - "metadata": {}, - "source": [ - "## Computation of gradients\n", - "\n", - "This in turn means that the gradient can be\n", - "computed as a sum over $i$-gradients" - ] - }, - { - "cell_type": "markdown", - "id": "37025507", - "metadata": {}, - "source": [ - "$$\n", - "\\nabla_\\beta C(\\mathbf{\\beta}) = \\sum_i^n \\nabla_\\beta c_i(\\mathbf{x}_i,\n", - "\\mathbf{\\beta}).\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "cc7aaec1", - "metadata": {}, - "source": [ - "Stochasticity/randomness is introduced by only taking the\n", - "gradient on a subset of the data called minibatches. If there are $n$\n", - "data points and the size of each minibatch is $M$, there will be $n/M$\n", - "minibatches. We denote these minibatches by $B_k$ where\n", - "$k=1,\\cdots,n/M$." - ] - }, - { - "cell_type": "markdown", - "id": "3a3a0d11", - "metadata": {}, - "source": [ - "## SGD example\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", - "$B_1 = (\\mathbf{x}_1,\\mathbf{x}_2), \\cdots, B_5 =\n", - "(\\mathbf{x}_9,\\mathbf{x}_{10})$. Note that if you choose $M=1$ you\n", - "have only a single batch with all data points and on the other extreme,\n", - "you may choose $M=n$ resulting in a minibatch for each datapoint, i.e\n", - "$B_k = \\mathbf{x}_k$.\n", - "\n", - "The idea is now to approximate the gradient by replacing the sum over\n", - "all data points with a sum over the data points in one the minibatches\n", - "picked at random in each gradient descent step" - ] - }, - { - "cell_type": "markdown", - "id": "0acfc986", - "metadata": {}, - "source": [ - "$$\n", - "\\nabla_{\\beta}\n", - "C(\\mathbf{\\beta}) = \\sum_{i=1}^n \\nabla_\\beta c_i(\\mathbf{x}_i,\n", - "\\mathbf{\\beta}) \\rightarrow \\sum_{i \\in B_k}^n \\nabla_\\beta\n", - "c_i(\\mathbf{x}_i, \\mathbf{\\beta}).\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "8d3f995d", - "metadata": {}, - "source": [ - "## The gradient step\n", - "\n", - "Thus a gradient descent step now looks like" - ] - }, - { - "cell_type": "markdown", - "id": "8c73ac82", - "metadata": {}, - "source": [ - "$$\n", - "\\beta_{j+1} = \\beta_j - \\gamma_j \\sum_{i \\in B_k}^n \\nabla_\\beta c_i(\\mathbf{x}_i,\n", - "\\mathbf{\\beta})\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "f88656c1", - "metadata": {}, - "source": [ - "where $k$ is picked at random with equal\n", - "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." - ] - }, - { - "cell_type": "markdown", - "id": "e80a498f", - "metadata": {}, - "source": [ - "## Simple example code" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "626ac884", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np \n", - "\n", - "n = 100 #100 datapoints \n", - "M = 5 #size of each minibatch\n", - "m = int(n/M) #number of minibatches\n", - "n_epochs = 10 #number of epochs\n", - "\n", - "j = 0\n", - "for epoch in range(1,n_epochs+1):\n", - " for i in range(m):\n", - " k = np.random.randint(m) #Pick the k-th minibatch at random\n", - " #Compute the gradient using the data in minibatch Bk\n", - " #Compute new suggestion for \n", - " j += 1" - ] - }, - { - "cell_type": "markdown", - "id": "3c9a754d", - "metadata": {}, - "source": [ - "Taking the gradient only on a subset of the data has two important\n", - "benefits. First, it introduces randomness which decreases the chance\n", - "that our opmization scheme gets stuck in a local minima. Second, if\n", - "the size of the minibatches are small relative to the number of\n", - "datapoints ($M < n$), the computation of the gradient is much\n", - "cheaper since we sum over the datapoints in the $k-th$ minibatch and not\n", - "all $n$ datapoints." - ] - }, - { - "cell_type": "markdown", - "id": "2790ab60", - "metadata": {}, - "source": [ - "## 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", - "of epochs and check if the norm of the gradient is smaller than some\n", - "threshold and stop if true. However, the condition that the gradient\n", - "is zero is valid also for local minima, so this would only tell us\n", - "that we are close to a local/global minimum. However, we could also\n", - "evaluate the cost function at this point, store the result and\n", - "continue the search. If the test kicks in at a later stage we can\n", - "compare the values of the cost function and keep the $\\beta$ that\n", - "gave the lowest value." - ] - }, - { - "cell_type": "markdown", - "id": "3ea3ee12", - "metadata": {}, - "source": [ - "## 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", - "reasonable time such that we do not move at all. Such approaches are\n", - "also called scaling. There are many such ways to [scale the learning\n", - "rate](https://towardsdatascience.com/gradient-descent-the-learning-rate-and-the-importance-of-feature-scaling-6c0b416596e1)\n", - "and [discussions here](https://www.jmlr.org/papers/volume23/20-1258/20-1258.pdf). See\n", - "also\n", - "\n", - "for a discussion of different scaling functions for the learning rate." - ] - }, - { - "cell_type": "markdown", - "id": "3c39cc08", - "metadata": {}, - "source": [ - "## Time decay rate\n", - "\n", - "As an example, let $e = 0,1,2,3,\\cdots$ denote the current epoch and let $t_0, t_1 > 0$ be two fixed numbers. Furthermore, let $t = e \\cdot m + i$ where $m$ is the number of minibatches and $i=0,\\cdots,m-1$. Then the function $$\\gamma_j(t; t_0, t_1) = \\frac{t_0}{t+t_1} $$ goes to zero as the number of epochs gets large. I.e. we start with a step length $\\gamma_j (0; t_0, t_1) = t_0/t_1$ which decays in *time* $t$.\n", - "\n", - "In this way we can fix the number of epochs, compute $\\beta$ and\n", - "evaluate the cost function at the end. Repeating the computation will\n", - "give a different result since the scheme is random by design. Then we\n", - "pick the final $\\beta$ that gives the lowest value of the cost\n", - "function." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "294edbef", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np \n", - "\n", - "def step_length(t,t0,t1):\n", - " return t0/(t+t1)\n", - "\n", - "n = 100 #100 datapoints \n", - "M = 5 #size of each minibatch\n", - "m = int(n/M) #number of minibatches\n", - "n_epochs = 500 #number of epochs\n", - "t0 = 1.0\n", - "t1 = 10\n", - "\n", - "gamma_j = t0/t1\n", - "j = 0\n", - "for epoch in range(1,n_epochs+1):\n", - " for i in range(m):\n", - " k = np.random.randint(m) #Pick the k-th minibatch at random\n", - " #Compute the gradient using the data in minibatch Bk\n", - " #Compute new suggestion for beta\n", - " t = epoch*m+i\n", - " gamma_j = step_length(t,t0,t1)\n", - " j += 1\n", - "\n", - "print(\"gamma_j after %d epochs: %g\" % (n_epochs,gamma_j))" - ] - }, - { - "cell_type": "markdown", - "id": "f60f930b", - "metadata": {}, - "source": [ - "## Code with a Number of Minibatches which varies\n", - "\n", - "In the code here we vary the number of mini-batches." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "41a929b5", - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "\n", - "# Importing various packages\n", - "from math import exp, sqrt\n", - "from random import random, seed\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "n = 100\n", - "x = 2*np.random.rand(n,1)\n", - "y = 4+3*x+np.random.randn(n,1)\n", - "\n", - "X = np.c_[np.ones((n,1)), x]\n", - "XT_X = X.T @ X\n", - "theta_linreg = np.linalg.inv(X.T @ X) @ (X.T @ y)\n", - "print(\"Own inversion\")\n", - "print(theta_linreg)\n", - "# Hessian matrix\n", - "H = (2.0/n)* XT_X\n", - "EigValues, EigVectors = np.linalg.eig(H)\n", - "print(f\"Eigenvalues of Hessian Matrix:{EigValues}\")\n", - "\n", - "theta = np.random.randn(2,1)\n", - "eta = 1.0/np.max(EigValues)\n", - "Niterations = 1000\n", - "\n", - "\n", - "for iter in range(Niterations):\n", - " gradients = 2.0/n*X.T @ ((X @ theta)-y)\n", - " theta -= eta*gradients\n", - "print(\"theta from own gd\")\n", - "print(theta)\n", - "\n", - "xnew = np.array([[0],[2]])\n", - "Xnew = np.c_[np.ones((2,1)), xnew]\n", - "ypredict = Xnew.dot(theta)\n", - "ypredict2 = Xnew.dot(theta_linreg)\n", - "\n", - "n_epochs = 50\n", - "M = 5 #size of each minibatch\n", - "m = int(n/M) #number of minibatches\n", - "t0, t1 = 5, 50\n", - "\n", - "def learning_schedule(t):\n", - " return t0/(t+t1)\n", - "\n", - "theta = np.random.randn(2,1)\n", - "\n", - "for epoch in range(n_epochs):\n", - "# Can you figure out a better way of setting up the contributions to each batch?\n", - " for i in range(m):\n", - " random_index = M*np.random.randint(m)\n", - " xi = X[random_index:random_index+M]\n", - " yi = y[random_index:random_index+M]\n", - " gradients = (2.0/M)* xi.T @ ((xi @ theta)-yi)\n", - " eta = learning_schedule(epoch*m+i)\n", - " theta = theta - eta*gradients\n", - "print(\"theta from own sdg\")\n", - "print(theta)\n", - "\n", - "plt.plot(xnew, ypredict, \"r-\")\n", - "plt.plot(xnew, ypredict2, \"b-\")\n", - "plt.plot(x, y ,'ro')\n", - "plt.axis([0,2.0,0, 15.0])\n", - "plt.xlabel(r'$x$')\n", - "plt.ylabel(r'$y$')\n", - "plt.title(r'Random numbers ')\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "af8f3db9", - "metadata": {}, - "source": [ - "## Replace or not\n", - "\n", - "In the above code, we have use replacement in setting up the\n", - "mini-batches. The discussion\n", - "[here](https://sebastianraschka.com/faq/docs/sgd-methods.html) may be\n", - "useful." - ] - }, - { - "cell_type": "markdown", - "id": "ce1d1147", - "metadata": {}, - "source": [ - "## 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", - "id": "b8750f09", - "metadata": {}, - "source": [ - "$$\n", - "\\mathbf{v}_{t}=\\gamma \\mathbf{v}_{t-1}+\\eta_{t}\\nabla_\\theta E(\\boldsymbol{\\theta}_t) \\nonumber\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "6b18d51a", - "metadata": {}, - "source": [ - "\n", - "

    \n", - "\n", - "$$\n", - "\\begin{equation} \n", - "\\boldsymbol{\\theta}_{t+1}= \\boldsymbol{\\theta}_t -\\mathbf{v}_{t},\n", - "\\label{_auto1} \\tag{1}\n", - "\\end{equation}\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "efa3113f", - "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", - "id": "2007f72c", - "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", - "id": "149a0faa", - "metadata": {}, - "source": [ - "where we have defined $\\Delta \\boldsymbol{\\theta}_{t}= \\boldsymbol{\\theta}_t-\\boldsymbol{\\theta}_{t-1}$." - ] - }, - { - "cell_type": "markdown", - "id": "3930d988", - "metadata": {}, - "source": [ - "## More on momentum based approaches\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", - "id": "8560c22c", - "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", - "id": "6f4563fe", - "metadata": {}, - "source": [ - "We can discretize this equation in the usual way to get" - ] - }, - { - "cell_type": "markdown", - "id": "8fe2b7ac", - "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", - "id": "207eae67", - "metadata": {}, - "source": [ - "Rearranging this equation, we can rewrite this as" - ] - }, - { - "cell_type": "markdown", - "id": "9770730e", - "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", - "id": "c233679d", - "metadata": {}, - "source": [ - "## Momentum parameter\n", - "\n", - "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", - "id": "cf54be10", - "metadata": {}, - "source": [ - "$$\n", - "\\gamma= {m \\over m +\\mu \\Delta t }, \\qquad \\eta = {(\\Delta t)^2 \\over m +\\mu \\Delta t}.\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "35f187e7", - "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", - "id": "476338d5", - "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", - "id": "c23f6df7", - "metadata": {}, - "source": [ - "\n", - "
    \n", - "\n", - "$$\n", - "\\begin{equation} \n", - "\\boldsymbol{\\theta}_{t+1}= \\boldsymbol{\\theta}_t -\\mathbf{v}_{t}.\n", - "\\label{_auto2} \\tag{2}\n", - "\\end{equation}\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "e36c0680", - "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$." - ] - }, - { - "cell_type": "markdown", - "id": "484048bb", - "metadata": {}, - "source": [ - "## Second moment of the gradient\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", - "During the last decade 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, Root Mean Squared Propagation (RMS-Prop), and\n", - "[ADAM](https://arxiv.org/abs/1412.6980)." - ] - }, - { - "cell_type": "markdown", - "id": "ed915ab1", - "metadata": {}, - "source": [ - "## 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", - "id": "c4d8b1a8", - "metadata": {}, - "source": [ - "\n", - "
    \n", - "\n", - "$$\n", - "\\begin{equation}\n", - "\\mathbf{g}_t = \\nabla_\\theta E(\\boldsymbol{\\theta}) \n", - "\\label{_auto3} \\tag{3}\n", - "\\end{equation}\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "6819d54f", - "metadata": {}, - "source": [ - "$$\n", - "\\mathbf{s}_t =\\beta \\mathbf{s}_{t-1} +(1-\\beta)\\mathbf{g}_t^2 \\nonumber\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "c38fa00d", - "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", - "id": "7ff83ef0", - "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." - ] - }, - { - "cell_type": "markdown", - "id": "ba98f789", - "metadata": {}, - "source": [ - "## [ADAM optimizer](https://arxiv.org/abs/1412.6980)\n", - "\n", - "A related algorithm is the ADAM optimizer. In\n", - "[ADAM](https://arxiv.org/abs/1412.6980), we keep a running average of\n", - "both the first and second moment of the gradient and use this\n", - "information to adaptively change the learning rate for different\n", - "parameters. The method isefficient when working with large\n", - "problems involving lots data and/or parameters. It is a combination of the\n", - "gradient descent with momentum algorithm and the RMSprop algorithm\n", - "discussed above.\n", - "\n", - "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", - "id": "03428756", - "metadata": {}, - "source": [ - "\n", - "
    \n", - "\n", - "$$\n", - "\\begin{equation}\n", - "\\mathbf{g}_t = \\nabla_\\theta E(\\boldsymbol{\\theta}) \n", - "\\label{_auto4} \\tag{4}\n", - "\\end{equation}\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "ef5b461b", - "metadata": {}, - "source": [ - "$$\n", - "\\mathbf{m}_t = \\beta_1 \\mathbf{m}_{t-1} + (1-\\beta_1) \\mathbf{g}_t \\nonumber\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "0149850a", - "metadata": {}, - "source": [ - "$$\n", - "\\mathbf{s}_t =\\beta_2 \\mathbf{s}_{t-1} +(1-\\beta_2)\\mathbf{g}_t^2 \\nonumber\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "4ae41be8", - "metadata": {}, - "source": [ - "$$\n", - "\\boldsymbol{\\mathbf{m}}_t={\\mathbf{m}_t \\over 1-\\beta_1^t} \\nonumber\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "5d36d54a", - "metadata": {}, - "source": [ - "$$\n", - "\\boldsymbol{\\mathbf{s}}_t ={\\mathbf{s}_t \\over1-\\beta_2^t} \\nonumber\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "08eb5528", - "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", - "id": "4a5e4b7b", - "metadata": {}, - "source": [ - "\n", - "
    \n", - "\n", - "$$\n", - "\\begin{equation} \n", - "\\label{_auto5} \\tag{5}\n", - "\\end{equation}\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "b71679d3", - "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", - "id": "a9910c4b", - "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", - "id": "85d963d2", - "metadata": {}, - "source": [ - "## Algorithms and codes for Adagrad, RMSprop and Adam\n", - "\n", - "The algorithms we have implemented are well described in the text by [Goodfellow, Bengio and Courville, chapter 8](https://www.deeplearningbook.org/contents/optimization.html).\n", - "\n", - "The codes which implement these algorithms are discussed after our presentation of automatic differentiation." - ] - }, - { - "cell_type": "markdown", - "id": "bc9de56d", - "metadata": {}, - "source": [ - "## AdaGrad algorithm, taken from [Goodfellow et al](https://www.deeplearningbook.org/contents/optimization.html)\n", - "\n", - "\n", - "\n", - "\n", - "

    Figure 1:

    \n", - "" - ] - }, - { - "cell_type": "markdown", - "id": "e6293208", - "metadata": {}, - "source": [ - "## RMSProp algorithm, taken from [Goodfellow et al](https://www.deeplearningbook.org/contents/optimization.html)\n", - "\n", - "\n", - "\n", - "\n", - "

    Figure 1:

    \n", - "" - ] - }, - { - "cell_type": "markdown", - "id": "40fde17d", - "metadata": {}, - "source": [ - "## ADAM algorithm, taken from [Goodfellow et al](https://www.deeplearningbook.org/contents/optimization.html)\n", - "\n", - "\n", - "\n", - "\n", - "

    Figure 1:

    \n", - "" - ] - }, - { - "cell_type": "markdown", - "id": "f9066e5f", - "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", - "Geron's text, see chapter 11, has several interesting discussions." - ] - }, - { - "cell_type": "markdown", - "id": "cfac43d8", - "metadata": {}, + "id": "0d567b76", + "metadata": { + "editable": true + }, "source": [ "## Automatic differentiation\n", "\n", @@ -1256,8 +126,10 @@ }, { "cell_type": "markdown", - "id": "6c1afa20", - "metadata": {}, + "id": "29059bbb", + "metadata": { + "editable": true + }, "source": [ "$$\n", "f(x) = \\sin\\left(2\\pi x + x^2\\right)\n", @@ -1266,16 +138,20 @@ }, { "cell_type": "markdown", - "id": "4c038cf3", - "metadata": {}, + "id": "000637ed", + "metadata": { + "editable": true + }, "source": [ "which has the following derivative" ] }, { "cell_type": "markdown", - "id": "eed0ca87", - "metadata": {}, + "id": "73499fad", + "metadata": { + "editable": true + }, "source": [ "$$\n", "f'(x) = \\cos\\left(2\\pi x + x^2\\right)\\left(2\\pi + 2x\\right)\n", @@ -1284,19 +160,26 @@ }, { "cell_type": "markdown", - "id": "3f493ed1", - "metadata": {}, + "id": "a2c54b7e", + "metadata": { + "editable": true + }, "source": [ "Using **autograd** we have" ] }, { "cell_type": "code", - "execution_count": 7, - "id": "f42e9964", - "metadata": {}, + "execution_count": 1, + "id": "45af1608", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ + "%matplotlib inline\n", + "\n", "import autograd.numpy as np\n", "\n", "# To do elementwise differentiation:\n", @@ -1335,8 +218,10 @@ }, { "cell_type": "markdown", - "id": "9a9dd7cb", - "metadata": {}, + "id": "4fa94bf0", + "metadata": { + "editable": true + }, "source": [ "## Using autograd\n", "\n", @@ -1349,9 +234,12 @@ }, { "cell_type": "code", - "execution_count": 8, - "id": "f5d99737", - "metadata": {}, + "execution_count": 2, + "id": "fa3182e1", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "import autograd.numpy as np\n", @@ -1375,8 +263,10 @@ }, { "cell_type": "markdown", - "id": "1a033f2a", - "metadata": {}, + "id": "3b52d711", + "metadata": { + "editable": true + }, "source": [ "## Autograd with more complicated functions\n", "\n", @@ -1387,9 +277,12 @@ }, { "cell_type": "code", - "execution_count": 9, - "id": "36ba3883", - "metadata": {}, + "execution_count": 3, + "id": "f9f046ce", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "import autograd.numpy as np\n", @@ -1429,25 +322,32 @@ }, { "cell_type": "markdown", - "id": "98a7ad40", - "metadata": {}, + "id": "f8014a36", + "metadata": { + "editable": true + }, "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": "markdown", - "id": "a840a46c", - "metadata": {}, + "id": "12725415", + "metadata": { + "editable": true + }, "source": [ "## More complicated functions using the elements of their arguments directly" ] }, { "cell_type": "code", - "execution_count": 10, - "id": "0ce16fc4", - "metadata": {}, + "execution_count": 4, + "id": "628f6795", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "import autograd.numpy as np\n", @@ -1471,8 +371,10 @@ }, { "cell_type": "markdown", - "id": "470f7e16", - "metadata": {}, + "id": "efce6ad6", + "metadata": { + "editable": true + }, "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", @@ -1484,17 +386,22 @@ }, { "cell_type": "markdown", - "id": "4d7c7e61", - "metadata": {}, + "id": "4eb6cad9", + "metadata": { + "editable": true + }, "source": [ "## Functions using mathematical functions from Numpy" ] }, { "cell_type": "code", - "execution_count": 11, - "id": "69eceec6", - "metadata": {}, + "execution_count": 5, + "id": "1d192367", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "import autograd.numpy as np\n", @@ -1518,17 +425,22 @@ }, { "cell_type": "markdown", - "id": "02192e06", - "metadata": {}, + "id": "9aec62ef", + "metadata": { + "editable": true + }, "source": [ "## More autograd" ] }, { "cell_type": "code", - "execution_count": 12, - "id": "6f5d7fa7", - "metadata": {}, + "execution_count": 6, + "id": "fec7a34e", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "import autograd.numpy as np\n", @@ -1549,17 +461,22 @@ }, { "cell_type": "markdown", - "id": "25b7c609", - "metadata": {}, + "id": "d18fb67b", + "metadata": { + "editable": true + }, "source": [ "## And with loops" ] }, { "cell_type": "code", - "execution_count": 13, - "id": "043eb7de", - "metadata": {}, + "execution_count": 7, + "id": "54456259", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "import autograd.numpy as np\n", @@ -1590,9 +507,12 @@ }, { "cell_type": "code", - "execution_count": 14, - "id": "880bc7f0", - "metadata": {}, + "execution_count": 8, + "id": "6cb94658", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "import autograd.numpy as np\n", @@ -1608,17 +528,22 @@ }, { "cell_type": "markdown", - "id": "322163dd", - "metadata": {}, + "id": "d0e990b8", + "metadata": { + "editable": true + }, "source": [ "## Using recursion" ] }, { "cell_type": "code", - "execution_count": 15, - "id": "09f1a79b", - "metadata": {}, + "execution_count": 9, + "id": "ba57a27f", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "import autograd.numpy as np\n", @@ -1652,16 +577,20 @@ }, { "cell_type": "markdown", - "id": "33d9596d", - "metadata": {}, + "id": "23ed8fa4", + "metadata": { + "editable": true + }, "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." ] }, { "cell_type": "markdown", - "id": "2b87a3af", - "metadata": {}, + "id": "56614917", + "metadata": { + "editable": true + }, "source": [ "## Using Autograd with OLS\n", "\n", @@ -1672,9 +601,12 @@ }, { "cell_type": "code", - "execution_count": 16, - "id": "4674f449", - "metadata": {}, + "execution_count": 10, + "id": "5d6f4267", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "# Using Autograd to calculate gradients for OLS\n", @@ -1730,17 +662,22 @@ }, { "cell_type": "markdown", - "id": "7c4e2d90", - "metadata": {}, + "id": "3317708a", + "metadata": { + "editable": true + }, "source": [ "## Same code but now with momentum gradient descent" ] }, { "cell_type": "code", - "execution_count": 17, - "id": "be5e6b23", - "metadata": {}, + "execution_count": 11, + "id": "b91eabff", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "# Using Autograd to calculate gradients for OLS\n", @@ -1800,8 +737,10 @@ }, { "cell_type": "markdown", - "id": "0002f816", - "metadata": {}, + "id": "34a4da26", + "metadata": { + "editable": true + }, "source": [ "## Including Stochastic Gradient Descent with Autograd\n", "In this code we include the stochastic gradient descent approach discussed above. Note here that we specify which argument we are taking the derivative with respect to when using **autograd**." @@ -1809,9 +748,12 @@ }, { "cell_type": "code", - "execution_count": 18, - "id": "ccb60a39", - "metadata": {}, + "execution_count": 12, + "id": "ec7a759d", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "# Using Autograd to calculate gradients using SGD\n", @@ -1891,17 +833,22 @@ }, { "cell_type": "markdown", - "id": "502d537b", - "metadata": {}, + "id": "605be519", + "metadata": { + "editable": true + }, "source": [ "## Same code but now with momentum gradient descent" ] }, { "cell_type": "code", - "execution_count": 19, - "id": "d62b1fd8", - "metadata": {}, + "execution_count": 13, + "id": "8fc8795f", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "# Using Autograd to calculate gradients using SGD\n", @@ -1975,33 +922,23 @@ }, { "cell_type": "markdown", - "id": "ab2dfdcf", - "metadata": {}, + "id": "3d4f6a0c", + "metadata": { + "editable": true + }, "source": [ "## Similar (second order function now) problem but now with AdaGrad" ] }, { "cell_type": "code", - "execution_count": 8, - "id": "24784ec8", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Own inversion\n", - "[[2. ]\n", - " [3. ]\n", - " [1.5]]\n", - "theta from own AdaGrad\n", - "[[2.00063579]\n", - " [2.996584 ]\n", - " [1.50373614]]\n" - ] - } - ], + "execution_count": 14, + "id": "d3bcc017", + "metadata": { + "collapsed": false, + "editable": true + }, + "outputs": [], "source": [ "# Using Autograd to calculate gradients using AdaGrad and Stochastic Gradient descent\n", "# OLS example\n", @@ -2017,7 +954,7 @@ "\n", "n = 1000\n", "x = np.random.rand(n,1)\n", - "y = 2.0+3*x +1.5*x*x\n", + "y = 2.0+3*x +4*x*x\n", "\n", "X = np.c_[np.ones((n,1)), x, x*x]\n", "XT_X = X.T @ X\n", @@ -2029,8 +966,8 @@ "# Note that we request the derivative wrt third argument (theta, 2 here)\n", "training_gradient = grad(CostOLS,2)\n", "# Define parameters for Stochastic Gradient Descent\n", - "n_epochs = 100\n", - "M = 10 #size of each minibatch\n", + "n_epochs = 50\n", + "M = 5 #size of each minibatch\n", "m = int(n/M) #number of minibatches\n", "# Guess for unknown parameters theta\n", "theta = np.random.randn(3,1)\n", @@ -2055,41 +992,33 @@ }, { "cell_type": "markdown", - "id": "b525a878", - "metadata": {}, + "id": "3536497d", + "metadata": { + "editable": true + }, "source": [ "Running this code we note an almost perfect agreement with the results from matrix inversion." ] }, { "cell_type": "markdown", - "id": "f3de5529", - "metadata": {}, + "id": "2c8e701a", + "metadata": { + "editable": true + }, "source": [ "## RMSprop for adaptive learning rate with Stochastic Gradient Descent" ] }, { "cell_type": "code", - "execution_count": 5, - "id": "770a0f44", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Own inversion\n", - "[[2. ]\n", - " [3. ]\n", - " [1.5]]\n", - "theta from own RMSprop\n", - "[[1.99889288]\n", - " [3.00367262]\n", - " [1.4940189 ]]\n" - ] - } - ], + "execution_count": 15, + "id": "57e7949a", + "metadata": { + "collapsed": false, + "editable": true + }, + "outputs": [], "source": [ "# Using Autograd to calculate gradients using RMSprop and Stochastic Gradient descent\n", "# OLS example\n", @@ -2105,7 +1034,7 @@ "\n", "n = 1000\n", "x = np.random.rand(n,1)\n", - "y = 2.0+3*x +1.5*x*x# +np.random.randn(n,1)\n", + "y = 2.0+3*x +4*x*x# +np.random.randn(n,1)\n", "\n", "X = np.c_[np.ones((n,1)), x, x*x]\n", "XT_X = X.T @ X\n", @@ -2117,7 +1046,7 @@ "# Note that we request the derivative wrt third argument (theta, 2 here)\n", "training_gradient = grad(CostOLS,2)\n", "# Define parameters for Stochastic Gradient Descent\n", - "n_epochs = 1000\n", + "n_epochs = 50\n", "M = 5 #size of each minibatch\n", "m = int(n/M) #number of minibatches\n", "# Guess for unknown parameters theta\n", @@ -2149,33 +1078,23 @@ }, { "cell_type": "markdown", - "id": "2cf458d4", - "metadata": {}, + "id": "5910fed9", + "metadata": { + "editable": true + }, "source": [ "## And finally [ADAM](https://arxiv.org/pdf/1412.6980.pdf)" ] }, { "cell_type": "code", - "execution_count": 10, - "id": "ebe031fe", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Own inversion\n", - "[[2. ]\n", - " [3. ]\n", - " [1.5]]\n", - "theta from own ADAM\n", - "[[1.99999721]\n", - " [3.0000173 ]\n", - " [1.49998153]]\n" - ] - } - ], + "execution_count": 16, + "id": "4765630f", + "metadata": { + "collapsed": false, + "editable": true + }, + "outputs": [], "source": [ "# Using Autograd to calculate gradients using RMSprop and Stochastic Gradient descent\n", "# OLS example\n", @@ -2191,7 +1110,7 @@ "\n", "n = 1000\n", "x = np.random.rand(n,1)\n", - "y = 2.0+3*x +1.5*x*x# +np.random.randn(n,1)\n", + "y = 2.0+3*x +4*x*x# +np.random.randn(n,1)\n", "\n", "X = np.c_[np.ones((n,1)), x, x*x]\n", "XT_X = X.T @ X\n", @@ -2203,14 +1122,14 @@ "# Note that we request the derivative wrt third argument (theta, 2 here)\n", "training_gradient = grad(CostOLS,2)\n", "# Define parameters for Stochastic Gradient Descent\n", - "n_epochs = 1000\n", + "n_epochs = 50\n", "M = 5 #size of each minibatch\n", "m = int(n/M) #number of minibatches\n", "# Guess for unknown parameters theta\n", "theta = np.random.randn(3,1)\n", "\n", "# Value for learning rate\n", - "eta = 0.001\n", + "eta = 0.01\n", "# Value for parameters beta1 and beta2, see https://arxiv.org/abs/1412.6980\n", "beta1 = 0.9\n", "beta2 = 0.999\n", @@ -2240,17 +1159,22 @@ }, { "cell_type": "markdown", - "id": "df82f58c", - "metadata": {}, + "id": "28731b27", + "metadata": { + "editable": true + }, "source": [ "## And Logistic Regression" ] }, { "cell_type": "code", - "execution_count": 23, - "id": "23a3aae7", - "metadata": {}, + "execution_count": 17, + "id": "814be546", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "import autograd.numpy as np\n", @@ -2290,8 +1214,10 @@ }, { "cell_type": "markdown", - "id": "04692c2e", - "metadata": {}, + "id": "96ab7076", + "metadata": { + "editable": true + }, "source": [ "## Introducing [JAX](https://jax.readthedocs.io/en/latest/)\n", "\n", @@ -2304,17 +1230,22 @@ }, { "cell_type": "markdown", - "id": "c9531ff9", - "metadata": {}, + "id": "1f44fe55", + "metadata": { + "editable": true + }, "source": [ "### Getting started with Jax, note the way we import numpy" ] }, { "cell_type": "code", - "execution_count": 24, - "id": "1082677a", - "metadata": {}, + "execution_count": 18, + "id": "96d73091", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "import jax\n", @@ -2327,17 +1258,22 @@ }, { "cell_type": "markdown", - "id": "ddab1050", - "metadata": {}, + "id": "51a09d4c", + "metadata": { + "editable": true + }, "source": [ "### A warm-up example" ] }, { "cell_type": "code", - "execution_count": 25, - "id": "9a64315e", - "metadata": {}, + "execution_count": 19, + "id": "4914cdc2", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "def function(x):\n", @@ -2378,17 +1314,22 @@ }, { "cell_type": "markdown", - "id": "fbaa615b", - "metadata": {}, + "id": "6d209f7a", + "metadata": { + "editable": true + }, "source": [ "### A more advanced example" ] }, { "cell_type": "code", - "execution_count": 26, - "id": "6400dac8", - "metadata": {}, + "execution_count": 20, + "id": "77a1efbb", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "backend = np\n", @@ -2415,8 +1356,10 @@ }, { "cell_type": "markdown", - "id": "b7cd2078", - "metadata": {}, + "id": "7bb9838b", + "metadata": { + "editable": true + }, "source": [ "## Introduction to Neural networks\n", "\n", @@ -2431,8 +1374,10 @@ }, { "cell_type": "markdown", - "id": "4b41d4a3", - "metadata": {}, + "id": "dd1332c8", + "metadata": { + "editable": true + }, "source": [ "## Artificial neurons\n", "\n", @@ -2453,8 +1398,10 @@ }, { "cell_type": "markdown", - "id": "05bbca92", - "metadata": {}, + "id": "52a4d54b", + "metadata": { + "editable": true + }, "source": [ "\n", "
    \n", @@ -2462,15 +1409,17 @@ "$$\n", "\\begin{equation}\n", " y = f\\left(\\sum_{i=1}^n w_ix_i\\right) = f(u)\n", - "\\label{artificialNeuron} \\tag{6}\n", + "\\label{artificialNeuron} \\tag{1}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "63e4ecd2", - "metadata": {}, + "id": "30b9994e", + "metadata": { + "editable": true + }, "source": [ "Here, the output $y$ of the neuron is the value of its activation function, which have as input\n", "a weighted sum of signals $x_i, \\dots ,x_n$ received by $n$ other neurons.\n", @@ -2507,8 +1456,10 @@ }, { "cell_type": "markdown", - "id": "16405c0c", - "metadata": {}, + "id": "7513bdfb", + "metadata": { + "editable": true + }, "source": [ "## Neural network types\n", "\n", @@ -2534,8 +1485,10 @@ }, { "cell_type": "markdown", - "id": "49a77aeb", - "metadata": {}, + "id": "bc80a3c0", + "metadata": { + "editable": true + }, "source": [ "## Feed-forward neural networks\n", "\n", @@ -2553,8 +1506,10 @@ }, { "cell_type": "markdown", - "id": "4408658f", - "metadata": {}, + "id": "de15fe45", + "metadata": { + "editable": true + }, "source": [ "## Convolutional Neural Network\n", "\n", @@ -2580,8 +1535,10 @@ }, { "cell_type": "markdown", - "id": "cf8d97ad", - "metadata": {}, + "id": "c028ac51", + "metadata": { + "editable": true + }, "source": [ "## Recurrent neural networks\n", "\n", @@ -2599,8 +1556,10 @@ }, { "cell_type": "markdown", - "id": "3cc3819b", - "metadata": {}, + "id": "e476ba1f", + "metadata": { + "editable": true + }, "source": [ "## Other types of networks\n", "\n", @@ -2618,8 +1577,10 @@ }, { "cell_type": "markdown", - "id": "920fd548", - "metadata": {}, + "id": "ec7b958f", + "metadata": { + "editable": true + }, "source": [ "## Multilayer perceptrons\n", "\n", @@ -2633,8 +1594,10 @@ }, { "cell_type": "markdown", - "id": "d08f461e", - "metadata": {}, + "id": "6b829eda", + "metadata": { + "editable": true + }, "source": [ "## Why multilayer perceptrons?\n", "\n", @@ -2652,8 +1615,10 @@ }, { "cell_type": "markdown", - "id": "dc59c40b", - "metadata": {}, + "id": "14e38937", + "metadata": { + "editable": true + }, "source": [ "## Illustration of a single perceptron model and a multi-perceptron model\n", "\n", @@ -2666,8 +1631,10 @@ }, { "cell_type": "markdown", - "id": "89c1b368", - "metadata": {}, + "id": "793fa0f6", + "metadata": { + "editable": true + }, "source": [ "## Examples of XOR, OR and AND gates\n", "\n", @@ -2680,9 +1647,12 @@ }, { "cell_type": "code", - "execution_count": 27, - "id": "f2a213fe", - "metadata": {}, + "execution_count": 21, + "id": "31c32fb1", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "\"\"\"\n", @@ -2719,25 +1689,32 @@ }, { "cell_type": "markdown", - "id": "046c878f", - "metadata": {}, + "id": "0652d853", + "metadata": { + "editable": true + }, "source": [ "What is happening here?" ] }, { "cell_type": "markdown", - "id": "8dbddf81", - "metadata": {}, + "id": "49f95bfa", + "metadata": { + "editable": true + }, "source": [ "## Does Logistic Regression do a better Job?" ] }, { "cell_type": "code", - "execution_count": 28, - "id": "3032a2c1", - "metadata": {}, + "execution_count": 22, + "id": "6ed55d22", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "\"\"\"\n", @@ -2793,25 +1770,32 @@ }, { "cell_type": "markdown", - "id": "ea8b4e4b", - "metadata": {}, + "id": "593bafc0", + "metadata": { + "editable": true + }, "source": [ "Not exactly impressive, but somewhat better." ] }, { "cell_type": "markdown", - "id": "ef2b283b", - "metadata": {}, + "id": "a772ee66", + "metadata": { + "editable": true + }, "source": [ "## Adding Neural Networks" ] }, { "cell_type": "code", - "execution_count": 29, - "id": "7415b824", - "metadata": {}, + "execution_count": 23, + "id": "3131b91b", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "\n", @@ -2827,8 +1811,10 @@ }, { "cell_type": "markdown", - "id": "bbfc7004", - "metadata": {}, + "id": "f3072a05", + "metadata": { + "editable": true + }, "source": [ "## Mathematical model\n", "\n", @@ -2837,8 +1823,10 @@ }, { "cell_type": "markdown", - "id": "973905d4", - "metadata": {}, + "id": "2501b704", + "metadata": { + "editable": true + }, "source": [ "$$\n", "y = f\\left(\\sum_{i=1}^n w_ix_i + b_i\\right) = f(z),\n", @@ -2847,8 +1835,10 @@ }, { "cell_type": "markdown", - "id": "9343ae60", - "metadata": {}, + "id": "0c9284d8", + "metadata": { + "editable": true + }, "source": [ "This function receives $x_i$ as inputs.\n", "Here the activation $z=(\\sum_{i=1}^n w_ix_i+b_i)$. \n", @@ -2860,8 +1850,10 @@ }, { "cell_type": "markdown", - "id": "0fcd0bdf", - "metadata": {}, + "id": "d9a0a94c", + "metadata": { + "editable": true + }, "source": [ "## Mathematical model\n", "\n", @@ -2870,23 +1862,27 @@ }, { "cell_type": "markdown", - "id": "98e91440", - "metadata": {}, + "id": "df8b7427", + "metadata": { + "editable": true + }, "source": [ "\n", - "
    \n", + "
    \n", "\n", "$$\n", "\\begin{equation} z_i^1 = \\sum_{j=1}^{M} w_{ij}^1 x_j + b_i^1\n", - "\\label{_auto6} \\tag{7}\n", + "\\label{_auto1} \\tag{2}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "944ccc68", - "metadata": {}, + "id": "f0db3236", + "metadata": { + "editable": true + }, "source": [ "Here $b_i$ is the so-called bias which is normally needed in\n", "case of zero activation weights or inputs. How to fix the biases and\n", @@ -2898,8 +1894,10 @@ }, { "cell_type": "markdown", - "id": "17edaee3", - "metadata": {}, + "id": "ba90159e", + "metadata": { + "editable": true + }, "source": [ "\n", "
    \n", @@ -2907,15 +1905,17 @@ "$$\n", "\\begin{equation}\n", " y_i^1 = f(z_i^1) = f\\left(\\sum_{j=1}^M w_{ij}^1 x_j + b_i^1\\right)\n", - "\\label{outputLayer1} \\tag{8}\n", + "\\label{outputLayer1} \\tag{3}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "dbe292f0", - "metadata": {}, + "id": "00e8a63c", + "metadata": { + "editable": true + }, "source": [ "where we assume that all nodes in the same layer have identical\n", "activation functions, hence the notation $f$. In general, we could assume in the more general case that different layers have different activation functions.\n", @@ -2924,8 +1924,10 @@ }, { "cell_type": "markdown", - "id": "ab06ec71", - "metadata": {}, + "id": "99259806", + "metadata": { + "editable": true + }, "source": [ "\n", "
    \n", @@ -2933,15 +1935,17 @@ "$$\n", "\\begin{equation}\n", " y_i^l = f^l(u_i^l) = f^l\\left(\\sum_{j=1}^{N_{l-1}} w_{ij}^l y_j^{l-1} + b_i^l\\right)\n", - "\\label{generalLayer} \\tag{9}\n", + "\\label{generalLayer} \\tag{4}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "0f069e07", - "metadata": {}, + "id": "ca3efcd2", + "metadata": { + "editable": true + }, "source": [ "where $N_l$ is the number of nodes in layer $l$. When the output of\n", "all the nodes in the first hidden layer are computed, the values of\n", @@ -2951,8 +1955,10 @@ }, { "cell_type": "markdown", - "id": "3ee71e06", - "metadata": {}, + "id": "bc1752b7", + "metadata": { + "editable": true + }, "source": [ "## Mathematical model\n", "\n", @@ -2961,24 +1967,28 @@ }, { "cell_type": "markdown", - "id": "cecfe50e", - "metadata": {}, + "id": "2f38f49c", + "metadata": { + "editable": true + }, "source": [ "\n", - "
    \n", + "
    \n", "\n", "$$\n", "\\begin{equation}\n", " y_i^2 = f^2\\left(\\sum_{j=1}^N w_{ij}^2 y_j^1 + b_i^2\\right) \n", - "\\label{_auto7} \\tag{10}\n", + "\\label{_auto2} \\tag{5}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "dc2a6523", - "metadata": {}, + "id": "17273cad", + "metadata": { + "editable": true + }, "source": [ "\n", "
    \n", @@ -2986,56 +1996,64 @@ "$$\n", "\\begin{equation} \n", " = f^2\\left[\\sum_{j=1}^N w_{ij}^2f^1\\left(\\sum_{k=1}^M w_{jk}^1 x_k + b_j^1\\right) + b_i^2\\right]\n", - "\\label{outputLayer2} \\tag{11}\n", + "\\label{outputLayer2} \\tag{6}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "3f73c82a", - "metadata": {}, + "id": "292f1932", + "metadata": { + "editable": true + }, "source": [ "where we have substituted $y_k^1$ with the inputs $x_k$. Finally, the ANN output reads" ] }, { "cell_type": "markdown", - "id": "8b1a1945", - "metadata": {}, + "id": "55e276cb", + "metadata": { + "editable": true + }, "source": [ "\n", - "
    \n", + "
    \n", "\n", "$$\n", "\\begin{equation}\n", " y_i^3 = f^3\\left(\\sum_{j=1}^N w_{ij}^3 y_j^2 + b_i^3\\right) \n", - "\\label{_auto8} \\tag{12}\n", + "\\label{_auto3} \\tag{7}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "ecd88770", - "metadata": {}, + "id": "c31bedcd", + "metadata": { + "editable": true + }, "source": [ "\n", - "
    \n", + "
    \n", "\n", "$$\n", "\\begin{equation} \n", " = f_3\\left[\\sum_{j} w_{ij}^3 f^2\\left(\\sum_{k} w_{jk}^2 f^1\\left(\\sum_{m} w_{km}^1 x_m + b_k^1\\right) + b_j^2\\right)\n", " + b_1^3\\right]\n", - "\\label{_auto9} \\tag{13}\n", + "\\label{_auto4} \\tag{8}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "6b6ce470", - "metadata": {}, + "id": "6df0c334", + "metadata": { + "editable": true + }, "source": [ "## Mathematical model\n", "\n", @@ -3045,8 +2063,10 @@ }, { "cell_type": "markdown", - "id": "6e018962", - "metadata": {}, + "id": "de23d2ac", + "metadata": { + "editable": true + }, "source": [ "\n", "
    \n", @@ -3054,15 +2074,17 @@ "$$\n", "\\begin{equation}\n", "y^{l+1}_i = f^{l+1}\\left[\\!\\sum_{j=1}^{N_l} w_{ij}^3 f^l\\left(\\sum_{k=1}^{N_{l-1}}w_{jk}^{l-1}\\left(\\dots f^1\\left(\\sum_{n=1}^{N_0} w_{mn}^1 x_n+ b_m^1\\right)\\dots\\right)+b_k^2\\right)+b_1^3\\right] \n", - "\\label{completeNN} \\tag{14}\n", + "\\label{completeNN} \\tag{9}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "bf0b66e0", - "metadata": {}, + "id": "68361f19", + "metadata": { + "editable": true + }, "source": [ "which illustrates a basic property of MLPs: The only independent\n", "variables are the input values $x_n$." @@ -3070,8 +2092,10 @@ }, { "cell_type": "markdown", - "id": "4827bb05", - "metadata": {}, + "id": "f33a0407", + "metadata": { + "editable": true + }, "source": [ "## Mathematical model\n", "\n", @@ -3087,24 +2111,28 @@ }, { "cell_type": "markdown", - "id": "6fc6eadd", - "metadata": {}, + "id": "28d4cb0f", + "metadata": { + "editable": true + }, "source": [ "\n", - "
    \n", + "
    \n", "\n", "$$\n", "\\begin{equation}\n", " f(x) = c_1 f(c_2 x + c_3) + c_4\n", - "\\label{_auto10} \\tag{15}\n", + "\\label{_auto5} \\tag{10}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "f7c37a39", - "metadata": {}, + "id": "780f185a", + "metadata": { + "editable": true + }, "source": [ "where the parameters $c_i$ are weights and biases. By adjusting these\n", "parameters, the activation functions can be shifted up and down or\n", @@ -3114,8 +2142,10 @@ }, { "cell_type": "markdown", - "id": "09472aa3", - "metadata": {}, + "id": "9a17ac89", + "metadata": { + "editable": true + }, "source": [ "### Matrix-vector notation\n", "\n", @@ -3132,11 +2162,13 @@ }, { "cell_type": "markdown", - "id": "1824564d", - "metadata": {}, + "id": "bfa341fe", + "metadata": { + "editable": true + }, "source": [ "\n", - "
    \n", + "
    \n", "\n", "$$\n", "\\begin{equation}\n", @@ -3156,15 +2188,17 @@ " b^2_2 \\\\\n", " b^2_3 \\\\\n", " \\end{array}\\right]\\right).\n", - "\\label{_auto11} \\tag{16}\n", + "\\label{_auto6} \\tag{11}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "eafbe02e", - "metadata": {}, + "id": "bc15b63b", + "metadata": { + "editable": true + }, "source": [ "### Matrix-vector notation and activation\n", "\n", @@ -3173,25 +2207,29 @@ }, { "cell_type": "markdown", - "id": "f52242e3", - "metadata": {}, + "id": "eec4055a", + "metadata": { + "editable": true + }, "source": [ "\n", - "
    \n", + "
    \n", "\n", "$$\n", "\\begin{equation}\n", " y^2_i = f_2\\Bigr(w^2_{i1}y^1_1 + w^2_{i2}y^1_2 + w^2_{i3}y^1_3 + b^2_i\\Bigr) = \n", " f_2\\left(\\sum_{j=1}^3 w^2_{ij} y_j^1 + b^2_i\\right).\n", - "\\label{_auto12} \\tag{17}\n", + "\\label{_auto7} \\tag{12}\n", "\\end{equation}\n", "$$" ] }, { "cell_type": "markdown", - "id": "72371715", - "metadata": {}, + "id": "feb4e6e6", + "metadata": { + "editable": true + }, "source": [ "This is not just a convenient and compact notation, but also a useful\n", "and intuitive way to think about MLPs: The output is calculated by a\n", @@ -3202,8 +2240,10 @@ }, { "cell_type": "markdown", - "id": "b455d9ae", - "metadata": {}, + "id": "3ae2c264", + "metadata": { + "editable": true + }, "source": [ "### Activation functions\n", "\n", @@ -3223,8 +2263,10 @@ }, { "cell_type": "markdown", - "id": "7de531f8", - "metadata": {}, + "id": "830f06e3", + "metadata": { + "editable": true + }, "source": [ "### Activation functions, Logistic and Hyperbolic ones\n", "\n", @@ -3240,8 +2282,10 @@ }, { "cell_type": "markdown", - "id": "dedb08ff", - "metadata": {}, + "id": "7f6872f0", + "metadata": { + "editable": true + }, "source": [ "$$\n", "f(x) = \\frac{1}{1 + e^{-x}},\n", @@ -3250,16 +2294,20 @@ }, { "cell_type": "markdown", - "id": "ed7c69c9", - "metadata": {}, + "id": "120447fb", + "metadata": { + "editable": true + }, "source": [ "and the *hyperbolic tangent* function" ] }, { "cell_type": "markdown", - "id": "37be8225", - "metadata": {}, + "id": "809db622", + "metadata": { + "editable": true + }, "source": [ "$$\n", "f(x) = \\tanh(x)\n", @@ -3268,8 +2316,10 @@ }, { "cell_type": "markdown", - "id": "a8176533", - "metadata": {}, + "id": "7a38a685", + "metadata": { + "editable": true + }, "source": [ "### Relevance\n", "\n", @@ -3282,9 +2332,12 @@ }, { "cell_type": "code", - "execution_count": 30, - "id": "1b3252bc", - "metadata": {}, + "execution_count": 24, + "id": "11e0216d", + "metadata": { + "collapsed": false, + "editable": true + }, "outputs": [], "source": [ "\"\"\"The sigmoid function (or the logistic curve) is a \n", @@ -3361,25 +2414,7 @@ ] } ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.15" - } - }, + "metadata": {}, "nbformat": 4, "nbformat_minor": 5 } diff --git a/doc/src/week40/Previousversions/week40.do.txt b/doc/src/week40/Previousversions/week40.do.txt new file mode 100644 index 000000000..696d13c3c --- /dev/null +++ b/doc/src/week40/Previousversions/week40.do.txt @@ -0,0 +1,2259 @@ +TITLE: Week 40: Gradient descent methods (continued) and start Neural networks +AUTHOR: Morten Hjorth-Jensen {copyright, 1999-present|CC BY-NC} at Department of Physics, University of Oslo, Norway +DATE: September 29-October 3, 2025 + + + +!split +===== Plans for week 40 ===== + + +!split +===== Lecture Monday September 30, 2024 ===== +!bblock + o Stochastic Gradient descent with examples and automatic differentiation + o If we get time, we start with the basics of Neural Networks, setting up the basic steps, from the simple perceptron model to the multi-layer perceptron model + o "Video of lecture":"https://youtu.be/jdJoOrCIdII" + o Whiteboard notes at URL:"https://github.com/CompPhysics/MachineLearning/blob/master/doc/HandWrittenNotes/2024/NotesSeptember30.pdf" +!eblock + +!split +===== Suggested readings and videos ===== +!bblock Readings and Videos: + o The lecture notes for week 40 (these notes) + o For a good discussion on gradient methods, we would like to recommend Goodfellow et al section 4.3-4.5 and sections 8.3-8.6. We will come back to the latter chapter in our discussion of Neural networks as well. + o For neural networks we recommend Goodfellow et al chapter 6 and Raschka et al chapter 2 (contains also material about gradient descent) and chapter 11 (we will use this next week) + o Video on gradient descent at URL:"https://www.youtube.com/watch?v=sDv4f4s2SB8" + o Video on stochastic gradient descent at URL:"https://www.youtube.com/watch?v=vMh0zPT0tLI" + o Neural Networks demystified at URL:"https://www.youtube.com/watch?v=bxe2T-V8XRs&list=PLiaHhY2iBX9hdHaRr6b7XevZtgZRa1PoU&ab_channel=WelchLabs" + o Building Neural Networks from scratch at URL:https://www.youtube.com/watch?v=Wo5dMEP_BbI&list=PLQVvvaa0QuDcjD5BAw2DxE6OF2tius3V3&ab_channel=sentdex" +!eblock + +!split +===== Lab sessions Tuesday and Wednesday ===== +!bblock Material for the active learning sessions on Tuesday and Wednesday + * Work on project 1 and discussions on how to structure your report + * No weekly exercises for week 40, project work only + * Video on how to write scientific reports recorded during one of the lab sessions at URL:"https://youtu.be/tVW1ZDmZnwM" + * A general guideline can be found at URL:"https://github.com/CompPhysics/MachineLearning/blob/master/doc/Projects/EvaluationGrading/EvaluationForm.md". +!eblock + + +!split +===== Summary from last week, using gradient descent methods, limitations ===== + +* _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. + +* _Gradients are computationally expensive to calculate for large datasets_. In many cases in statistics and ML, the cost/loss/risk function is a sum of terms, with one term for each data point. For example, in linear regression, $E \propto \sum_{i=1}^n (y_i - \mathbf{w}^T\cdot\mathbf{x}_i)^2$; for logistic regression, the square error is replaced by the cross entropy. To calculate the gradient we have to sum over *all* $n$ data points. Doing this at every GD step becomes extremely computationally expensive. An ingenious solution to this, is to calculate the gradients using small subsets of the data called ``mini batches''. This has the added benefit of introducing stochasticity into our algorithm. + +* _GD is very sensitive to choices of learning rates_. GD is extremely sensitive to the choice of learning rates. If the learning rate is very small, the training process take an extremely long time. For larger learning rates, GD can diverge and give poor results. Furthermore, depending on what the local landscape looks like, we have to modify the learning rates to ensure convergence. Ideally, we would *adaptively* choose the learning rates to match the landscape. + +* _GD treats all directions in parameter space uniformly._ Another major drawback of GD is that unlike Newton's method, the learning rate for GD is the same in all directions in parameter space. For this reason, the maximum learning rate is set by the behavior of the steepest direction and this can significantly slow down training. Ideally, we would like to take large steps in flat directions and small steps in steep directions. Since we are exploring rugged landscapes where curvatures change, this requires us to keep track of not only the gradient but second derivatives. The ideal scenario would be to calculate the Hessian but this proves to be too computationally expensive. + +* GD can take exponential time to escape saddle points, even with random initialization. As we mentioned, GD is extremely sensitive to initial condition since it determines the particular local minimum GD would eventually reach. However, even with a good initialization scheme, through the introduction of randomness, GD can still take exponential time to escape saddle points. + +!split +===== Simple implementation of GD for OLS, Ridge and Lasso ===== + +Last week we studied both several gradient methods. With and without an update of the learning. +We summarize some of these here for the methods we hvae studied in project one, without the inclusion of momentum. +!bc pycod +from random import random, seed +import numpy as np + +# the number of datapoints with a 2nd-order polynomial +n = 100 +x = 2*np.random.rand(n,1) +y = 4+3*x+5*x*x +# Design matrix including the intercept +# No scaling of data of and all data used for training +X = np.c_[np.ones((n,1)), x, x*x] +# Learning rate and number of iterations +eta = 0.05 +Niterations = 100 + +# OLS part +beta_OLS = np.random.randn(3,1) +gradient = np.zeros(3) +for iter in range(Niterations): + gradient = (2.0/n)*X.T @ (X @ beta_OLS-y) + beta_OLS -= eta*gradient +print('Parameters for OLS using gradient descent') +print(beta_OLS) + +#Ridge and Lasso parameter Lambda +Lambda = 0.01 +Id = n*Lambda* np.eye((X.T @ X).shape[0]) +# Gradient descent with Ridge +beta_Ridge = np.random.randn(3,1) +gradient = np.zeros(3) +for iter in range(Niterations): + gradients = 2.0/n*X.T @ (X @ beta_Ridge-y)+2*Lambda*beta_Ridge + beta_Ridge -= eta*gradients +print('Parameters for Ridge using gradient descent') +print(beta_Ridge) + +# Gradient descent with Lasso +beta_Lasso = np.random.randn(3,1) +gradient = np.zeros(3) +for iter in range(Niterations): + gradients = 2.0/n*X.T @ (X @ beta_Lasso-y)+Lambda*np.sign(beta_Lasso) + beta_Lasso -= eta*gradients +print('Parameters for Lasso using gradient descent') +print(beta_Lasso) + +!ec + + +!split +===== But none of these can compete with Newton's method ===== + +Note that we here have introduced automatic differentiation +!bc pycod +# Using Newton's method +from random import random, seed +import numpy as np +import autograd.numpy as np +from autograd import grad + +def CostOLS(beta): + return (1.0/n)*np.sum((y-X @ beta)**2) + +n = 100 +x = 2*np.random.rand(n,1) +y = 4+3*x+5*x*x + +X = np.c_[np.ones((n,1)), x, x*x] +XT_X = X.T @ X +beta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) +print("Own inversion") +print(beta_linreg) +# Hessian matrix +H = (2.0/n)* XT_X +# Note that here the Hessian does not depend on the parameters beta +invH = np.linalg.pinv(H) +beta = np.random.randn(3,1) +Niterations = 5 +# define the gradient +training_gradient = grad(CostOLS) + +for iter in range(Niterations): + gradients = training_gradient(beta) + beta -= invH @ gradients + print(iter,gradients[0],gradients[1]) +print("beta from own Newton code") +print(beta) + +!ec + +!split +===== Gradient descent and Logistic regression ===== + +Finally, we complete these examples by adding a simple code for +Logistic regression. Note the more general approach with a class for +the method. Here we use a so-called _AND_ gate for our data set. + +!bc pycod +import numpy as np +class LogisticRegression: + def __init__(self, learning_rate=0.01, num_iterations=1000): + self.learning_rate = learning_rate + self.num_iterations = num_iterations + self.beta_logreg = None + def sigmoid(self, z): + return 1 / (1 + np.exp(-z)) + def GDfit(self, X, y): + n_data, num_features = X.shape + self.beta_logreg = np.zeros(num_features) + for _ in range(self.num_iterations): + linear_model = X @ self.beta_logreg + y_predicted = self.sigmoid(linear_model) + # Gradient calculation + gradient = (X.T @ (y_predicted - y))/n_data + # Update beta_logreg + self.beta_logreg -= self.learning_rate*gradient + def predict(self, X): + linear_model = X @ self.beta_logreg + y_predicted = self.sigmoid(linear_model) + return [1 if i >= 0.5 else 0 for i in y_predicted] +# Example usage +if __name__ == "__main__": + # Sample data + X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]]) + y = np.array([0, 0, 0, 1]) # This is an AND gate + model = LogisticRegression(learning_rate=0.01, num_iterations=1000) + model.GDfit(X, y) + predictions = model.predict(X) + print("Predictions:", predictions) +!ec + +!split +===== Overview video on Stochastic Gradient Descent ===== + +"What is Stochastic Gradient Descent":"https://www.youtube.com/watch?v=vMh0zPT0tLI&ab_channel=StatQuestwithJoshStarmer" +There are several reasons for using stochastic gradient descent. Some of these are: + +o Efficiency: Updates weights more frequently using a single or a small batch of samples, which speeds up convergence. +o Hopefully avoid Local Minima +o Memory Usage: Requires less memory compared to computing gradients for the entire dataset. + +!split +===== Batches and mini-batches ===== + +In gradient descent we compute the cost function and its gradient for all data points we have. + +In large-scale applications such as the "ILSVRC challenge":"https://www.image-net.org/challenges/LSVRC/", the +training data can have on order of millions of examples. Hence, it +seems wasteful to compute the full cost function over the entire +training set in order to perform only a single parameter update. A +very common approach to addressing this challenge is to compute the +gradient over batches of the training data. For example, a typical batch could contain some thousand examples from +an entire training set of several millions. This batch is then used to +perform a parameter update. + +!split +===== Stochastic Gradient Descent (SGD) ===== + +In stochastic gradient descent, the extreme case is the case where we +have only one batch, that is we include the whole data set. + +This process is called Stochastic Gradient +Descent (SGD) (or also sometimes on-line gradient descent). This is +relatively less common to see because in practice due to vectorized +code optimizations it can be computationally much more efficient to +evaluate the gradient for 100 examples, than the gradient for one +example 100 times. Even though SGD technically refers to using a +single example at a time to evaluate the gradient, you will hear +people use the term SGD even when referring to mini-batch gradient +descent (i.e. mentions of MGD for “Minibatch Gradient Descent”, or BGD +for “Batch gradient descent” are rare to see), where it is usually +assumed that mini-batches are used. The size of the mini-batch is a +hyperparameter but it is not very common to cross-validate or bootstrap it. It is +usually based on memory constraints (if any), or set to some value, +e.g. 32, 64 or 128. We use powers of 2 in practice because many +vectorized operation implementations work faster when their inputs are +sized in powers of 2. + +In our notes with SGD we mean stochastic gradient descent with mini-batches. + + +!split +===== Stochastic Gradient Descent ===== + +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 +function, which we want to minimize, can almost always be written as a +sum over $n$ data points $\{\mathbf{x}_i\}_{i=1}^n$, +!bt +\[ +C(\mathbf{\beta}) = \sum_{i=1}^n c_i(\mathbf{x}_i, +\mathbf{\beta}). +\] +!et + +!split +===== Computation of gradients ===== + +This in turn means that the gradient can be +computed as a sum over $i$-gradients +!bt +\[ +\nabla_\beta C(\mathbf{\beta}) = \sum_i^n \nabla_\beta c_i(\mathbf{x}_i, +\mathbf{\beta}). +\] +!et + +Stochasticity/randomness is introduced by only taking the +gradient on a subset of the data called minibatches. If there are $n$ +data points and the size of each minibatch is $M$, there will be $n/M$ +minibatches. We denote these minibatches by $B_k$ where +$k=1,\cdots,n/M$. + + + +!split +===== SGD example ===== +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 +$B_1 = (\mathbf{x}_1,\mathbf{x}_2), \cdots, B_5 = +(\mathbf{x}_9,\mathbf{x}_{10})$. Note that if you choose $M=1$ you +have only a single batch with all data points and on the other extreme, +you may choose $M=n$ resulting in a minibatch for each datapoint, i.e +$B_k = \mathbf{x}_k$. + +The idea is now to approximate the gradient by replacing the sum over +all data points with a sum over the data points in one the minibatches +picked at random in each gradient descent step +!bt +\[ +\nabla_{\beta} +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}). +\] +!et + +!split +===== The gradient step ===== + +Thus a gradient descent step now looks like +!bt +\[ +\beta_{j+1} = \beta_j - \gamma_j \sum_{i \in B_k}^n \nabla_\beta c_i(\mathbf{x}_i, +\mathbf{\beta}) +\] +!et + +where $k$ is picked at random with equal +probability from $[1,n/M]$. An iteration over the number of +minibathces (n/M) is commonly referred to as an epoch. Thus it is +typical to choose a number of epochs and for each epoch iterate over +the number of minibatches, as exemplified in the code below. + +!split +===== Simple example code ===== + +!bc pycod +import numpy as np + +n = 100 #100 datapoints +M = 5 #size of each minibatch +m = int(n/M) #number of minibatches +n_epochs = 10 #number of epochs + +j = 0 +for epoch in range(1,n_epochs+1): + for i in range(m): + k = np.random.randint(m) #Pick the k-th minibatch at random + #Compute the gradient using the data in minibatch Bk + #Compute new suggestion for + j += 1 +!ec + +Taking the gradient only on a subset of the data has two important +benefits. First, it introduces randomness which decreases the chance +that our opmization scheme gets stuck in a local minima. Second, if +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. + +!split +===== When do we stop? ===== + +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 +threshold and stop if true. However, the condition that the gradient +is zero is valid also for local minima, so this would only tell us +that we are close to a local/global minimum. However, we could also +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. + +!split +===== Slightly different approach ===== + +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. Such approaches are +also called scaling. There are many such ways to "scale the learning +rate":"https://towardsdatascience.com/gradient-descent-the-learning-rate-and-the-importance-of-feature-scaling-6c0b416596e1" +and "discussions here":"https://www.jmlr.org/papers/volume23/20-1258/20-1258.pdf". See +also +URL:"https://towardsdatascience.com/learning-rate-schedules-and-adaptive-learning-rate-methods-for-deep-learning-2c8f433990d1" +for a discussion of different scaling functions for the learning rate. + +!split +===== Time decay rate ===== + +As an example, let $e = 0,1,2,3,\cdots$ denote the current epoch and let $t_0, t_1 > 0$ be two fixed numbers. Furthermore, let $t = e \cdot m + i$ where $m$ is the number of minibatches and $i=0,\cdots,m-1$. Then the function $$\gamma_j(t; t_0, t_1) = \frac{t_0}{t+t_1} $$ goes to zero as the number of epochs gets large. I.e. we start with a step length $\gamma_j (0; t_0, t_1) = t_0/t_1$ which decays in *time* $t$. + +In this way we can fix the number of epochs, compute $\beta$ and +evaluate the cost function at the end. Repeating the computation will +give a different result since the scheme is random by design. Then we +pick the final $\beta$ that gives the lowest value of the cost +function. + +!bc pycod +import numpy as np + +def step_length(t,t0,t1): + return t0/(t+t1) + +n = 100 #100 datapoints +M = 5 #size of each minibatch +m = int(n/M) #number of minibatches +n_epochs = 500 #number of epochs +t0 = 1.0 +t1 = 10 + +gamma_j = t0/t1 +j = 0 +for epoch in range(1,n_epochs+1): + for i in range(m): + k = np.random.randint(m) #Pick the k-th minibatch at random + #Compute the gradient using the data in minibatch Bk + #Compute new suggestion for beta + t = epoch*m+i + gamma_j = step_length(t,t0,t1) + j += 1 + +print("gamma_j after %d epochs: %g" % (n_epochs,gamma_j)) +!ec + + +!split +===== Code with a Number of Minibatches which varies ===== + +In the code here we vary the number of mini-batches. +!bc pycode +# Importing various packages +from math import exp, sqrt +from random import random, seed +import numpy as np +import matplotlib.pyplot as plt + +n = 100 +x = 2*np.random.rand(n,1) +y = 4+3*x+np.random.randn(n,1) + +X = np.c_[np.ones((n,1)), x] +XT_X = X.T @ X +theta_linreg = np.linalg.inv(X.T @ X) @ (X.T @ y) +print("Own inversion") +print(theta_linreg) +# Hessian matrix +H = (2.0/n)* XT_X +EigValues, EigVectors = np.linalg.eig(H) +print(f"Eigenvalues of Hessian Matrix:{EigValues}") + +theta = np.random.randn(2,1) +eta = 1.0/np.max(EigValues) +Niterations = 1000 + + +for iter in range(Niterations): + gradients = 2.0/n*X.T @ ((X @ theta)-y) + theta -= eta*gradients +print("theta from own gd") +print(theta) + +xnew = np.array([[0],[2]]) +Xnew = np.c_[np.ones((2,1)), xnew] +ypredict = Xnew.dot(theta) +ypredict2 = Xnew.dot(theta_linreg) + +n_epochs = 50 +M = 5 #size of each minibatch +m = int(n/M) #number of minibatches +t0, t1 = 5, 50 + +def learning_schedule(t): + return t0/(t+t1) + +theta = np.random.randn(2,1) + +for epoch in range(n_epochs): +# Can you figure out a better way of setting up the contributions to each batch? + for i in range(m): + random_index = M*np.random.randint(m) + xi = X[random_index:random_index+M] + yi = y[random_index:random_index+M] + gradients = (2.0/M)* xi.T @ ((xi @ theta)-yi) + eta = learning_schedule(epoch*m+i) + theta = theta - eta*gradients +print("theta from own sdg") +print(theta) + +plt.plot(xnew, ypredict, "r-") +plt.plot(xnew, ypredict2, "b-") +plt.plot(x, y ,'ro') +plt.axis([0,2.0,0, 15.0]) +plt.xlabel(r'$x$') +plt.ylabel(r'$y$') +plt.title(r'Random numbers ') +plt.show() + +!ec + + + +!split +===== Replace or not ===== + +In the above code, we have use replacement in setting up the +mini-batches. The discussion +"here":"https://sebastianraschka.com/faq/docs/sgd-methods.html" may be +useful. + + +!split +===== Momentum based GD ===== + +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 + +!bt +\begin{align} +\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t) \nonumber \\ +\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}, +\end{align} +!et + +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 + +!bt +\[ +\Delta \boldsymbol{\theta}_{t+1} = \gamma \Delta \boldsymbol{\theta}_t -\ \eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t), +\] +!et +where we have defined $\Delta \boldsymbol{\theta}_{t}= \boldsymbol{\theta}_t-\boldsymbol{\theta}_{t-1}$. + +!split +===== More on momentum based approaches ===== + +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 + +!bt +\[ +m {d^2 \mathbf{w} \over dt^2} + \mu {d \mathbf{w} \over dt }= -\nabla_w E(\mathbf{w}). +\] +!et + +We can discretize this equation in the usual way to get + +!bt +\[ +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}). +\] +!et + +Rearranging this equation, we can rewrite this as + +!bt +\[ +\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. +\] +!et + +!split +===== Momentum parameter ===== + +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: + +!bt +\[ +\gamma= {m \over m +\mu \Delta t }, \qquad \eta = {(\Delta t)^2 \over m +\mu \Delta t}. +\] +!et + +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 + +!bt +\begin{align} +\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t +\gamma \mathbf{v}_{t-1}) \nonumber \\ +\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}. +\end{align} +!et + +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$. + + +!split +===== Second moment of the gradient ===== + + +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. + +During the last decade 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, Root Mean Squared Propagation (RMS-Prop), and +"ADAM":"https://arxiv.org/abs/1412.6980". + +!split +===== RMS prop ===== + +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 + +!bt +\begin{align} +\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) \\ +\mathbf{s}_t &=\beta \mathbf{s}_{t-1} +(1-\beta)\mathbf{g}_t^2 \nonumber \\ +\boldsymbol{\theta}_{t+1}&=&\boldsymbol{\theta}_t - \eta_t { \mathbf{g}_t \over \sqrt{\mathbf{s}_t +\epsilon}}, \nonumber +\end{align} +!et + +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. + + +!split +===== "ADAM optimizer":"https://arxiv.org/abs/1412.6980" ===== + +A related algorithm is the ADAM optimizer. In +"ADAM":"https://arxiv.org/abs/1412.6980", 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. The method isefficient when working with large +problems involving lots data and/or parameters. It is a combination of the +gradient descent with momentum algorithm and the RMSprop algorithm +discussed above. + +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) + +!bt +\begin{align} +\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) \\ +\mathbf{m}_t &= \beta_1 \mathbf{m}_{t-1} + (1-\beta_1) \mathbf{g}_t \nonumber \\ +\mathbf{s}_t &=\beta_2 \mathbf{s}_{t-1} +(1-\beta_2)\mathbf{g}_t^2 \nonumber \\ +\bm{\mathbf{m}}_t&={\mathbf{m}_t \over 1-\beta_1^t} \nonumber \\ +\bm{\mathbf{s}}_t &={\mathbf{s}_t \over1-\beta_2^t} \nonumber \\ +\boldsymbol{\theta}_{t+1}&=\boldsymbol{\theta}_t - \eta_t { \bm{\mathbf{m}}_t \over \sqrt{\bm{\mathbf{s}}_t} +\epsilon}, \nonumber \\ +\end{align} +!et + +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 = \bm{\mathbf{s}}_t - +(\bm{\mathbf{m}}_t)^2$. Consider a single parameter $\theta_t$. The +update rule for this parameter is given by + +!bt +\[ +\Delta \theta_{t+1}= -\eta_t { \bm{m}_t \over \sqrt{\sigma_t^2 + m_t^2 }+\epsilon}. +\] +!et + +!split +===== Algorithms and codes for Adagrad, RMSprop and Adam ===== + +The algorithms we have implemented are well described in the text by "Goodfellow, Bengio and Courville, chapter 8":"https://www.deeplearningbook.org/contents/optimization.html". + +The codes which implement these algorithms are discussed after our presentation of automatic differentiation. + + +===== AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html" ===== + +FIGURE: [figures/adagrad.png, width=600 frac=0.8] + + +===== RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html" ===== + +FIGURE: [figures/rmsprop.png, width=600 frac=0.8] + + + +===== ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html" ===== + +FIGURE: [figures/adam.png, width=600 frac=0.8] + + + + + +!split +===== Practical tips ===== + +* _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. + +Geron's text, see chapter 11, has several interesting discussions. + + + +!split +===== Automatic differentiation ===== + +"Automatic differentiation (AD)":"https://en.wikipedia.org/wiki/Automatic_differentiation", +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 +!bt +\[ +f(x) = \sin\left(2\pi x + x^2\right) +\] +!et +which has the following derivative +!bt +\[ +f'(x) = \cos\left(2\pi x + x^2\right)\left(2\pi + 2x\right) +\] +!et +Using _autograd_ we have + +!bc pycod +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)))) +!ec + +!split +===== Using autograd ===== + +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. + +!bc pycod +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)) +!ec + + +!split +===== Autograd with more complicated functions ===== + +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. + +!bc pycod +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) )) +!ec + +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. + + +!split +===== More complicated functions using the elements of their arguments directly ===== + +!bc pycod +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) +!ec + +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. + +!split +===== Functions using mathematical functions from Numpy ===== + +!bc pycod +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)) +!ec + + +!split +===== More autograd ===== + +!bc pycod +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))) +!ec + + +!split +===== And with loops ===== + +!bc pycod +import autograd.numpy as np +from autograd import grad +def f6_for(x): + val = 0 + for i in range(10): + val = val + x**i + return val + +def f6_while(x): + val = 0 + i = 0 + while i < 10: + val = val + x**i + i = i + 1 + return val + +f6_for_grad = grad(f6_for) +f6_while_grad = grad(f6_while) + +x = 0.5 + +# Print the computed derivaties of f6_for and f6_while +print("The computed derivative of f6_for at x = %g is: %g"%(x,f6_for_grad(x))) +print("The computed derivative of f6_while at x = %g is: %g"%(x,f6_while_grad(x))) +!ec +!bc pycod +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)) +!ec + +!split +===== Using recursion ===== +!bc pycod +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)) + +!ec +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. + + +!split +===== Using Autograd with OLS ===== + +We conclude the part on optmization by showing how we can make codes +for linear regression and logistic regression using _autograd_. The +first example shows results with ordinary leats squares. + +!bc pycod +# Using Autograd to calculate gradients for OLS +from random import random, seed +import numpy as np +import autograd.numpy as np +import matplotlib.pyplot as plt +from autograd import grad + +def CostOLS(beta): + return (1.0/n)*np.sum((y-X @ beta)**2) + +n = 100 +x = 2*np.random.rand(n,1) +y = 4+3*x+np.random.randn(n,1) + +X = np.c_[np.ones((n,1)), x] +XT_X = X.T @ X +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) +print("Own inversion") +print(theta_linreg) +# Hessian matrix +H = (2.0/n)* XT_X +EigValues, EigVectors = np.linalg.eig(H) +print(f"Eigenvalues of Hessian Matrix:{EigValues}") + +theta = np.random.randn(2,1) +eta = 1.0/np.max(EigValues) +Niterations = 1000 +# define the gradient +training_gradient = grad(CostOLS) + +for iter in range(Niterations): + gradients = training_gradient(theta) + theta -= eta*gradients +print("theta from own gd") +print(theta) + +xnew = np.array([[0],[2]]) +Xnew = np.c_[np.ones((2,1)), xnew] +ypredict = Xnew.dot(theta) +ypredict2 = Xnew.dot(theta_linreg) + +plt.plot(xnew, ypredict, "r-") +plt.plot(xnew, ypredict2, "b-") +plt.plot(x, y ,'ro') +plt.axis([0,2.0,0, 15.0]) +plt.xlabel(r'$x$') +plt.ylabel(r'$y$') +plt.title(r'Random numbers ') +plt.show() + +!ec + + +!split +===== Same code but now with momentum gradient descent ===== +!bc pycod +# Using Autograd to calculate gradients for OLS +from random import random, seed +import numpy as np +import autograd.numpy as np +import matplotlib.pyplot as plt +from autograd import grad + +def CostOLS(beta): + return (1.0/n)*np.sum((y-X @ beta)**2) + +n = 100 +x = 2*np.random.rand(n,1) +y = 4+3*x#+np.random.randn(n,1) + +X = np.c_[np.ones((n,1)), x] +XT_X = X.T @ X +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) +print("Own inversion") +print(theta_linreg) +# Hessian matrix +H = (2.0/n)* XT_X +EigValues, EigVectors = np.linalg.eig(H) +print(f"Eigenvalues of Hessian Matrix:{EigValues}") + +theta = np.random.randn(2,1) +eta = 1.0/np.max(EigValues) +Niterations = 30 + +# define the gradient +training_gradient = grad(CostOLS) + +for iter in range(Niterations): + gradients = training_gradient(theta) + theta -= eta*gradients + print(iter,gradients[0],gradients[1]) +print("theta from own gd") +print(theta) + +# Now improve with momentum gradient descent +change = 0.0 +delta_momentum = 0.3 +for iter in range(Niterations): + # calculate gradient + gradients = training_gradient(theta) + # calculate update + new_change = eta*gradients+delta_momentum*change + # take a step + theta -= new_change + # save the change + change = new_change + print(iter,gradients[0],gradients[1]) +print("theta from own gd wth momentum") +print(theta) + +!ec + +!split +===== Including Stochastic Gradient Descent with Autograd ===== +In this code we include the stochastic gradient descent approach discussed above. Note here that we specify which argument we are taking the derivative with respect to when using _autograd_. + +!bc pycod +# Using Autograd to calculate gradients using SGD +# OLS example +from random import random, seed +import numpy as np +import autograd.numpy as np +import matplotlib.pyplot as plt +from autograd import grad + +# Note change from previous example +def CostOLS(y,X,theta): + return np.sum((y-X @ theta)**2) + +n = 100 +x = 2*np.random.rand(n,1) +y = 4+3*x+np.random.randn(n,1) + +X = np.c_[np.ones((n,1)), x] +XT_X = X.T @ X +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) +print("Own inversion") +print(theta_linreg) +# Hessian matrix +H = (2.0/n)* XT_X +EigValues, EigVectors = np.linalg.eig(H) +print(f"Eigenvalues of Hessian Matrix:{EigValues}") + +theta = np.random.randn(2,1) +eta = 1.0/np.max(EigValues) +Niterations = 1000 + +# Note that we request the derivative wrt third argument (theta, 2 here) +training_gradient = grad(CostOLS,2) + +for iter in range(Niterations): + gradients = (1.0/n)*training_gradient(y, X, theta) + theta -= eta*gradients +print("theta from own gd") +print(theta) + +xnew = np.array([[0],[2]]) +Xnew = np.c_[np.ones((2,1)), xnew] +ypredict = Xnew.dot(theta) +ypredict2 = Xnew.dot(theta_linreg) + +plt.plot(xnew, ypredict, "r-") +plt.plot(xnew, ypredict2, "b-") +plt.plot(x, y ,'ro') +plt.axis([0,2.0,0, 15.0]) +plt.xlabel(r'$x$') +plt.ylabel(r'$y$') +plt.title(r'Random numbers ') +plt.show() + +n_epochs = 50 +M = 5 #size of each minibatch +m = int(n/M) #number of minibatches +t0, t1 = 5, 50 +def learning_schedule(t): + return t0/(t+t1) + +theta = np.random.randn(2,1) + +for epoch in range(n_epochs): +# Can you figure out a better way of setting up the contributions to each batch? + for i in range(m): + random_index = M*np.random.randint(m) + xi = X[random_index:random_index+M] + yi = y[random_index:random_index+M] + gradients = (1.0/M)*training_gradient(yi, xi, theta) + eta = learning_schedule(epoch*m+i) + theta = theta - eta*gradients +print("theta from own sdg") +print(theta) + + +!ec + + +!split +===== Same code but now with momentum gradient descent ===== +!bc pycod +# Using Autograd to calculate gradients using SGD +# OLS example +from random import random, seed +import numpy as np +import autograd.numpy as np +import matplotlib.pyplot as plt +from autograd import grad + +# Note change from previous example +def CostOLS(y,X,theta): + return np.sum((y-X @ theta)**2) + +n = 100 +x = 2*np.random.rand(n,1) +y = 4+3*x+np.random.randn(n,1) + +X = np.c_[np.ones((n,1)), x] +XT_X = X.T @ X +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) +print("Own inversion") +print(theta_linreg) +# Hessian matrix +H = (2.0/n)* XT_X +EigValues, EigVectors = np.linalg.eig(H) +print(f"Eigenvalues of Hessian Matrix:{EigValues}") + +theta = np.random.randn(2,1) +eta = 1.0/np.max(EigValues) +Niterations = 100 + +# Note that we request the derivative wrt third argument (theta, 2 here) +training_gradient = grad(CostOLS,2) + +for iter in range(Niterations): + gradients = (1.0/n)*training_gradient(y, X, theta) + theta -= eta*gradients +print("theta from own gd") +print(theta) + + +n_epochs = 50 +M = 5 #size of each minibatch +m = int(n/M) #number of minibatches +t0, t1 = 5, 50 +def learning_schedule(t): + return t0/(t+t1) + +theta = np.random.randn(2,1) + +change = 0.0 +delta_momentum = 0.3 + +for epoch in range(n_epochs): + for i in range(m): + random_index = M*np.random.randint(m) + xi = X[random_index:random_index+M] + yi = y[random_index:random_index+M] + gradients = (1.0/M)*training_gradient(yi, xi, theta) + eta = learning_schedule(epoch*m+i) + # calculate update + new_change = eta*gradients+delta_momentum*change + # take a step + theta -= new_change + # save the change + change = new_change +print("theta from own sdg with momentum") +print(theta) +!ec + + +!split +===== Similar (second order function now) problem but now with AdaGrad ===== +!bc pycod +# Using Autograd to calculate gradients using AdaGrad and Stochastic Gradient descent +# OLS example +from random import random, seed +import numpy as np +import autograd.numpy as np +import matplotlib.pyplot as plt +from autograd import grad + +# Note change from previous example +def CostOLS(y,X,theta): + return np.sum((y-X @ theta)**2) + +n = 1000 +x = np.random.rand(n,1) +y = 2.0+3*x +4*x*x + +X = np.c_[np.ones((n,1)), x, x*x] +XT_X = X.T @ X +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) +print("Own inversion") +print(theta_linreg) + + +# Note that we request the derivative wrt third argument (theta, 2 here) +training_gradient = grad(CostOLS,2) +# Define parameters for Stochastic Gradient Descent +n_epochs = 50 +M = 5 #size of each minibatch +m = int(n/M) #number of minibatches +# Guess for unknown parameters theta +theta = np.random.randn(3,1) + +# Value for learning rate +eta = 0.01 +# Including AdaGrad parameter to avoid possible division by zero +delta = 1e-8 +for epoch in range(n_epochs): + Giter = 0.0 + for i in range(m): + random_index = M*np.random.randint(m) + xi = X[random_index:random_index+M] + yi = y[random_index:random_index+M] + gradients = (1.0/M)*training_gradient(yi, xi, theta) + Giter += gradients*gradients + update = gradients*eta/(delta+np.sqrt(Giter)) + theta -= update +print("theta from own AdaGrad") +print(theta) + + +!ec + +Running this code we note an almost perfect agreement with the results from matrix inversion. + +!split +===== RMSprop for adaptive learning rate with Stochastic Gradient Descent ===== +!bc pycod +# Using Autograd to calculate gradients using RMSprop and Stochastic Gradient descent +# OLS example +from random import random, seed +import numpy as np +import autograd.numpy as np +import matplotlib.pyplot as plt +from autograd import grad + +# Note change from previous example +def CostOLS(y,X,theta): + return np.sum((y-X @ theta)**2) + +n = 1000 +x = np.random.rand(n,1) +y = 2.0+3*x +4*x*x# +np.random.randn(n,1) + +X = np.c_[np.ones((n,1)), x, x*x] +XT_X = X.T @ X +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) +print("Own inversion") +print(theta_linreg) + + +# Note that we request the derivative wrt third argument (theta, 2 here) +training_gradient = grad(CostOLS,2) +# Define parameters for Stochastic Gradient Descent +n_epochs = 50 +M = 5 #size of each minibatch +m = int(n/M) #number of minibatches +# Guess for unknown parameters theta +theta = np.random.randn(3,1) + +# Value for learning rate +eta = 0.01 +# Value for parameter rho +rho = 0.99 +# Including AdaGrad parameter to avoid possible division by zero +delta = 1e-8 +for epoch in range(n_epochs): + Giter = 0.0 + for i in range(m): + random_index = M*np.random.randint(m) + xi = X[random_index:random_index+M] + yi = y[random_index:random_index+M] + gradients = (1.0/M)*training_gradient(yi, xi, theta) + # Accumulated gradient + # Scaling with rho the new and the previous results + Giter = (rho*Giter+(1-rho)*gradients*gradients) + # Taking the diagonal only and inverting + update = gradients*eta/(delta+np.sqrt(Giter)) + # Hadamard product + theta -= update +print("theta from own RMSprop") +print(theta) +!ec + +!split +===== And finally "ADAM":"https://arxiv.org/pdf/1412.6980.pdf" ===== + +!bc pycod +# Using Autograd to calculate gradients using RMSprop and Stochastic Gradient descent +# OLS example +from random import random, seed +import numpy as np +import autograd.numpy as np +import matplotlib.pyplot as plt +from autograd import grad + +# Note change from previous example +def CostOLS(y,X,theta): + return np.sum((y-X @ theta)**2) + +n = 1000 +x = np.random.rand(n,1) +y = 2.0+3*x +4*x*x# +np.random.randn(n,1) + +X = np.c_[np.ones((n,1)), x, x*x] +XT_X = X.T @ X +theta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) +print("Own inversion") +print(theta_linreg) + + +# Note that we request the derivative wrt third argument (theta, 2 here) +training_gradient = grad(CostOLS,2) +# Define parameters for Stochastic Gradient Descent +n_epochs = 50 +M = 5 #size of each minibatch +m = int(n/M) #number of minibatches +# Guess for unknown parameters theta +theta = np.random.randn(3,1) + +# Value for learning rate +eta = 0.01 +# Value for parameters beta1 and beta2, see https://arxiv.org/abs/1412.6980 +beta1 = 0.9 +beta2 = 0.999 +# Including AdaGrad parameter to avoid possible division by zero +delta = 1e-7 +iter = 0 +for epoch in range(n_epochs): + first_moment = 0.0 + second_moment = 0.0 + iter += 1 + for i in range(m): + random_index = M*np.random.randint(m) + xi = X[random_index:random_index+M] + yi = y[random_index:random_index+M] + gradients = (1.0/M)*training_gradient(yi, xi, theta) + # Computing moments first + first_moment = beta1*first_moment + (1-beta1)*gradients + second_moment = beta2*second_moment+(1-beta2)*gradients*gradients + first_term = first_moment/(1.0-beta1**iter) + second_term = second_moment/(1.0-beta2**iter) + # Scaling with rho the new and the previous results + update = eta*first_term/(np.sqrt(second_term)+delta) + theta -= update +print("theta from own ADAM") +print(theta) +!ec + +!split +===== And Logistic Regression ===== + +!bc pycod +import autograd.numpy as np +from autograd import grad + +def sigmoid(x): + return 0.5 * (np.tanh(x / 2.) + 1) + +def logistic_predictions(weights, inputs): + # Outputs probability of a label being true according to logistic model. + return sigmoid(np.dot(inputs, weights)) + +def training_loss(weights): + # Training loss is the negative log-likelihood of the training labels. + preds = logistic_predictions(weights, inputs) + label_probabilities = preds * targets + (1 - preds) * (1 - targets) + return -np.sum(np.log(label_probabilities)) + +# Build a toy dataset. +inputs = np.array([[0.52, 1.12, 0.77], + [0.88, -1.08, 0.15], + [0.52, 0.06, -1.30], + [0.74, -2.49, 1.39]]) +targets = np.array([True, True, False, True]) + +# Define a function that returns gradients of training loss using Autograd. +training_gradient_fun = grad(training_loss) + +# Optimize weights using gradient descent. +weights = np.array([0.0, 0.0, 0.0]) +print("Initial loss:", training_loss(weights)) +for i in range(100): + weights -= training_gradient_fun(weights) * 0.01 + +print("Trained loss:", training_loss(weights)) +!ec + + + + +===== Introducing "JAX":"https://jax.readthedocs.io/en/latest/" ===== + +Presently, instead of using _autograd_, we recommend using "JAX":"https://jax.readthedocs.io/en/latest/" + +_JAX_ is Autograd and "XLA (Accelerated Linear Algebra))":"https://www.tensorflow.org/xla", +brought together for high-performance numerical computing and machine learning research. +It provides composable transformations of Python+NumPy programs: differentiate, vectorize, parallelize, Just-In-Time compile to GPU/TPU, and more. + +=== Getting started with Jax, note the way we import numpy === +!bc pycod +import jax +import jax.numpy as jnp +import numpy as np +import matplotlib.pyplot as plt + +from jax import grad as jax_grad +!ec + + +=== A warm-up example === + +!bc pycod +def function(x): + return x**2 + +def analytical_gradient(x): + return 2*x + +def gradient_descent(starting_point, learning_rate, num_iterations, solver="analytical"): + x = starting_point + trajectory_x = [x] + trajectory_y = [function(x)] + + if solver == "analytical": + grad = analytical_gradient + elif solver == "jax": + grad = jax_grad(function) + x = jnp.float64(x) + learning_rate = jnp.float64(learning_rate) + + for _ in range(num_iterations): + + x = x - learning_rate * grad(x) + trajectory_x.append(x) + trajectory_y.append(function(x)) + + return trajectory_x, trajectory_y + +x = np.linspace(-5, 5, 100) +plt.plot(x, function(x), label="f(x)") + +descent_x, descent_y = gradient_descent(5, 0.1, 10, solver="analytical") +jax_descend_x, jax_descend_y = gradient_descent(5, 0.1, 10, solver="jax") + +plt.plot(descent_x, descent_y, label="Gradient descent", marker="o") +plt.plot(jax_descend_x, jax_descend_y, label="JAX", marker="x") +!ec + +=== A more advanced example === + +!bc pycod +backend = np + +def function(x): + return x*backend.sin(x**2 + 1) + +def analytical_gradient(x): + return backend.sin(x**2 + 1) + 2*x**2*backend.cos(x**2 + 1) + + +x = np.linspace(-5, 5, 100) +plt.plot(x, function(x), label="f(x)") + +descent_x, descent_y = gradient_descent(1, 0.01, 300, solver="analytical") + +# Change the backend to JAX +backend = jnp +jax_descend_x, jax_descend_y = gradient_descent(1, 0.01, 300, solver="jax") + +plt.scatter(descent_x, descent_y, label="Gradient descent", marker="v", s=10, color="red") +plt.scatter(jax_descend_x, jax_descend_y, label="JAX", marker="x", s=5, color="black") +!ec + + + + + + + + + + + +!split +===== Introduction to Neural networks ===== + +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 +biological system, wherein neurons interact by sending signals in the +form of mathematical functions between layers. All layers can contain +an arbitrary number of neurons, and each connection is represented by +a weight variable. + + +!split +===== Artificial neurons ===== + +The field of artificial neural networks has a long history of +development, and is closely connected with the advancement of computer +science and computers in general. A model of artificial neurons was +first developed by McCulloch and Pitts in 1943 to study signal +processing in the brain and has later been refined by others. The +general idea is to mimic neural networks in the human brain, which is +composed of billions of neurons that communicate with each other by +sending electrical signals. Each neuron accumulates its incoming +signals, which must exceed an activation threshold to yield an +output. If the threshold is not overcome, the neuron remains inactive, +i.e. has zero output. + +This behaviour has inspired a simple mathematical model for an artificial neuron. + +!bt +\begin{equation} + y = f\left(\sum_{i=1}^n w_ix_i\right) = f(u) + label{artificialNeuron} +\end{equation} +!et +Here, the output $y$ of the neuron is the value of its activation function, which have as input +a weighted sum of signals $x_i, \dots ,x_n$ received by $n$ other neurons. + +Conceptually, it is helpful to divide neural networks into four +categories: +o general purpose neural networks for supervised learning, +o neural networks designed specifically for image processing, the most prominent example of this class being Convolutional Neural Networks (CNNs), +o neural networks for sequential data such as Recurrent Neural Networks (RNNs), and +o neural networks for unsupervised learning such as Deep Boltzmann Machines. + + +In natural science, DNNs and CNNs have already found numerous +applications. In statistical physics, they have been applied to detect +phase transitions in 2D Ising and Potts models, lattice gauge +theories, and different phases of polymers, or solving the +Navier-Stokes equation in weather forecasting. Deep learning has also +found interesting applications in quantum physics. Various quantum +phase transitions can be detected and studied using DNNs and CNNs, +topological phases, and even non-equilibrium many-body +localization. Representing quantum states as DNNs quantum state +tomography are among some of the impressive achievements to reveal the +potential of DNNs to facilitate the study of quantum systems. + +In quantum information theory, it has been shown that one can perform +gate decompositions with the help of neural. + +The applications are not limited to the natural sciences. There is a +plethora of applications in essentially all disciplines, from the +humanities to life science and medicine. + +!split +===== Neural network types ===== + +An artificial neural network (ANN), is a computational model that +consists of layers of connected neurons, or nodes or units. We will +refer to these interchangeably as units or nodes, and sometimes as +neurons. + +It is supposed to mimic a biological nervous system by letting each +neuron interact with other neurons by sending signals in the form of +mathematical functions between layers. A wide variety of different +ANNs have been developed, but most of them consist of an input layer, +an output layer and eventual layers in-between, called *hidden +layers*. All layers can contain an arbitrary number of nodes, and each +connection between two nodes is associated with a weight variable. + +Neural networks (also called neural nets) are neural-inspired +nonlinear models for supervised learning. As we will see, neural nets +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. + + +!split +===== Feed-forward neural networks ===== + +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. + +Nodes are represented by circles, while the arrows display the +connections between the nodes, including the direction of information +flow. Additionally, each arrow corresponds to a weight variable +(figure to come). We observe that each node in a layer is connected +to *all* nodes in the subsequent layer, making this a so-called +*fully-connected* FFNN. + + + +!split +===== Convolutional Neural Network ===== + +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 +stimuli from small sub-regions of the visual field, called a receptive +field. This makes the neurons well-suited to exploit the strong +spatially local correlation present in natural images. The response of +each neuron can be approximated mathematically as a convolution +operation. (figure to come) + +Convolutional neural networks emulate the behaviour of neurons in the +visual cortex by enforcing a *local* connectivity pattern between +nodes of adjacent layers: Each node in a convolutional layer is +connected only to a subset of the nodes in the previous layer, in +contrast to the fully-connected FFNN. Often, CNNs consist of several +convolutional layers that learn local features of the input, with a +fully-connected layer at the end, which gathers all the local data and +produces the outputs. They have wide applications in image and video +recognition. + +!split +===== Recurrent neural networks ===== + +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 +creates a form of internal memory which are able to capture +information on what has been calculated before; the output is +dependent on the previous computations. Recurrent NNs make use of +sequential information by performing the same task for every element +in a sequence, where each element depends on previous elements. An +example of such information is sentences, making recurrent NNs +especially well-suited for handwriting and speech recognition. + +!split +===== Other types of networks ===== + +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 +made up of three layers: an input layer, a hidden layer with +non-linear radial symmetric activation functions and a linear output +layer (''linear'' here means that each node in the output layer has a +linear activation function). The layers are normally fully-connected +and there are no cycles, thus RBFs can be viewed as a type of +fully-connected FFNN. They are however usually treated as a separate +type of NN due the unusual activation functions. + +!split +===== Multilayer perceptrons ===== + +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 +activation functions. + +Such networks are often called *multilayer perceptrons* (MLPs). + +!split +===== Why multilayer perceptrons? ===== + +According to the *Universal approximation theorem*, a feed-forward +neural network with just a single hidden layer containing a finite +number of neurons can approximate a continuous multidimensional +function to arbitrary accuracy, assuming the activation function for +the hidden layer is a _non-constant, bounded and +monotonically-increasing continuous function_. + +Note that the requirements on the activation function only applies to +the hidden layer, the output nodes are always assumed to be linear, so +as to not restrict the range of output values. + + +!split +===== Illustration of a single perceptron model and a multi-perceptron model ===== + +FIGURE: [figures/nns.png, width=600 frac=0.8] In a) we show a single perceptron model while in b) we dispay a network with two hidden layers, an input layer and an output layer. + + +!split +===== Examples of XOR, OR and AND gates ===== + + + +Let us first try to fit various gates using standard linear +regression. The gates we are thinking of are the classical XOR, OR and +AND gates, well-known elements in computer science. The tables here +show how we can set up the inputs $x_1$ and $x_2$ in order to yield a +specific target $y_i$. + + + + +!bc pycod +""" +Simple code that tests XOR, OR and AND gates with linear regression +""" + +import numpy as np +# Design matrix +X = np.array([ [1, 0, 0], [1, 0, 1], [1, 1, 0],[1, 1, 1]],dtype=np.float64) +print(f"The X.TX matrix:{X.T @ X}") +Xinv = np.linalg.pinv(X.T @ X) +print(f"The invers of X.TX matrix:{Xinv}") + +# The XOR gate +yXOR = np.array( [ 0, 1 ,1, 0]) +ThetaXOR = Xinv @ X.T @ yXOR +print(f"The values of theta for the XOR gate:{ThetaXOR}") +print(f"The linear regression prediction for the XOR gate:{X @ ThetaXOR}") + + +# The OR gate +yOR = np.array( [ 0, 1 ,1, 1]) +ThetaOR = Xinv @ X.T @ yOR +print(f"The values of theta for the OR gate:{ThetaOR}") +print(f"The linear regression prediction for the OR gate:{X @ ThetaOR}") + + +# The OR gate +yAND = np.array( [ 0, 0 ,0, 1]) +ThetaAND = Xinv @ X.T @ yAND +print(f"The values of theta for the AND gate:{ThetaAND}") +print(f"The linear regression prediction for the AND gate:{X @ ThetaAND}") +!ec + +What is happening here? + +!split +===== Does Logistic Regression do a better Job? ===== + +!bc pycod +""" +Simple code that tests XOR and OR gates with linear regression +and logistic regression +""" + +import matplotlib.pyplot as plt +from sklearn.linear_model import LogisticRegression +import numpy as np + +# Design matrix +X = np.array([ [1, 0, 0], [1, 0, 1], [1, 1, 0],[1, 1, 1]],dtype=np.float64) +print(f"The X.TX matrix:{X.T @ X}") +Xinv = np.linalg.pinv(X.T @ X) +print(f"The invers of X.TX matrix:{Xinv}") + +# The XOR gate +yXOR = np.array( [ 0, 1 ,1, 0]) +ThetaXOR = Xinv @ X.T @ yXOR +print(f"The values of theta for the XOR gate:{ThetaXOR}") +print(f"The linear regression prediction for the XOR gate:{X @ ThetaXOR}") + + +# The OR gate +yOR = np.array( [ 0, 1 ,1, 1]) +ThetaOR = Xinv @ X.T @ yOR +print(f"The values of theta for the OR gate:{ThetaOR}") +print(f"The linear regression prediction for the OR gate:{X @ ThetaOR}") + + +# The OR gate +yAND = np.array( [ 0, 0 ,0, 1]) +ThetaAND = Xinv @ X.T @ yAND +print(f"The values of theta for the AND gate:{ThetaAND}") +print(f"The linear regression prediction for the AND gate:{X @ ThetaAND}") + +# Now we change to logistic regression + + +# Logistic Regression +logreg = LogisticRegression() +logreg.fit(X, yOR) +print("Test set accuracy with Logistic Regression for OR gate: {:.2f}".format(logreg.score(X,yOR))) + +logreg.fit(X, yXOR) +print("Test set accuracy with Logistic Regression for XOR gate: {:.2f}".format(logreg.score(X,yXOR))) + + +logreg.fit(X, yAND) +print("Test set accuracy with Logistic Regression for AND gate: {:.2f}".format(logreg.score(X,yAND))) +!ec + +Not exactly impressive, but somewhat better. + +!split +===== Adding Neural Networks ===== + +!bc pycod + +# and now neural networks with Scikit-Learn and the XOR + +from sklearn.neural_network import MLPClassifier +from sklearn.datasets import make_classification +X, yXOR = make_classification(n_samples=100, random_state=1) +FFNN = MLPClassifier(random_state=1, max_iter=300).fit(X, yXOR) +FFNN.predict_proba(X) +print(f"Test set accuracy with Feed Forward Neural Network for XOR gate:{FFNN.score(X, yXOR)}") + +!ec + + + +!split +===== Mathematical model ===== + +The output $y$ is produced via the activation function $f$ +!bt +\[ + y = f\left(\sum_{i=1}^n w_ix_i + b_i\right) = f(z), +\] +!et +This function receives $x_i$ as inputs. +Here the activation $z=(\sum_{i=1}^n w_ix_i+b_i)$. +In an FFNN of such neurons, the *inputs* $x_i$ are the *outputs* of +the neurons in the preceding layer. Furthermore, an MLP is +fully-connected, which means that each neuron receives a weighted sum +of the outputs of *all* neurons in the previous layer. + +!split +===== Mathematical model ===== + +First, for each node $i$ in the first hidden layer, we calculate a weighted sum $z_i^1$ of the input coordinates $x_j$, + +!bt +\begin{equation} z_i^1 = \sum_{j=1}^{M} w_{ij}^1 x_j + b_i^1 +\end{equation} +!et + +Here $b_i$ is the so-called bias which is normally needed in +case of zero activation weights or inputs. How to fix the biases and +the weights will be discussed below. The value of $z_i^1$ is the +argument to the activation function $f_i$ of each node $i$, The +variable $M$ stands for all possible inputs to a given node $i$ in the +first layer. We define the output $y_i^1$ of all neurons in layer 1 as + +!bt +\begin{equation} + y_i^1 = f(z_i^1) = f\left(\sum_{j=1}^M w_{ij}^1 x_j + b_i^1\right) + label{outputLayer1} +\end{equation} +!et + +where we assume that all nodes in the same layer have identical +activation functions, hence the notation $f$. In general, we could assume in the more general case that different layers have different activation functions. +In this case we would identify these functions with a superscript $l$ for the $l$-th layer, + +!bt +\begin{equation} + y_i^l = f^l(u_i^l) = f^l\left(\sum_{j=1}^{N_{l-1}} w_{ij}^l y_j^{l-1} + b_i^l\right) + label{generalLayer} +\end{equation} +!et + +where $N_l$ is the number of nodes in layer $l$. When the output of +all the nodes in the first hidden layer are computed, the values of +the subsequent layer can be calculated and so forth until the output +is obtained. + + + +!split +===== Mathematical model ===== + +The output of neuron $i$ in layer 2 is thus, + +!bt +\begin{align} + y_i^2 &= f^2\left(\sum_{j=1}^N w_{ij}^2 y_j^1 + b_i^2\right) \\ + &= f^2\left[\sum_{j=1}^N w_{ij}^2f^1\left(\sum_{k=1}^M w_{jk}^1 x_k + b_j^1\right) + b_i^2\right] + label{outputLayer2} +\end{align} +!et +where we have substituted $y_k^1$ with the inputs $x_k$. Finally, the ANN output reads + +!bt +\begin{align} + y_i^3 &= f^3\left(\sum_{j=1}^N w_{ij}^3 y_j^2 + b_i^3\right) \\ + &= f_3\left[\sum_{j} w_{ij}^3 f^2\left(\sum_{k} w_{jk}^2 f^1\left(\sum_{m} w_{km}^1 x_m + b_k^1\right) + b_j^2\right) + + b_1^3\right] +\end{align} +!et + +!split +===== Mathematical model ===== + +We can generalize this expression to an MLP with $l$ hidden +layers. The complete functional form is, + +!bt +\begin{align} +&y^{l+1}_i = f^{l+1}\left[\!\sum_{j=1}^{N_l} w_{ij}^3 f^l\left(\sum_{k=1}^{N_{l-1}}w_{jk}^{l-1}\left(\dots f^1\left(\sum_{n=1}^{N_0} w_{mn}^1 x_n+ b_m^1\right)\dots\right)+b_k^2\right)+b_1^3\right] && + label{completeNN} +\end{align} +!et + +which illustrates a basic property of MLPs: The only independent +variables are the input values $x_n$. + +!split +===== Mathematical model ===== + +This confirms that an MLP, despite its quite convoluted mathematical +form, is nothing more than an analytic function, specifically a +mapping of real-valued vectors $\hat{x} \in \mathbb{R}^n \rightarrow +\hat{y} \in \mathbb{R}^m$. + +Furthermore, the flexibility and universality of an MLP can be +illustrated by realizing that the expression is essentially a nested +sum of scaled activation functions of the form + +!bt +\begin{equation} + f(x) = c_1 f(c_2 x + c_3) + c_4 +\end{equation} +!et + +where the parameters $c_i$ are weights and biases. By adjusting these +parameters, the activation functions can be shifted up and down or +left and right, change slope or be rescaled which is the key to the +flexibility of a neural network. + +!split +=== Matrix-vector notation === + +We can introduce a more convenient notation for the activations in an A NN. + +Additionally, we can represent the biases and activations +as layer-wise column vectors $\hat{b}_l$ and $\hat{y}_l$, so that the $i$-th element of each vector +is the bias $b_i^l$ and activation $y_i^l$ of node $i$ in layer $l$ respectively. + +We have that $\mathrm{W}_l$ is an $N_{l-1} \times N_l$ matrix, while $\hat{b}_l$ and $\hat{y}_l$ are $N_l \times 1$ column vectors. +With this notation, the sum becomes a matrix-vector multiplication, and we can write +the equation for the activations of hidden layer 2 (assuming three nodes for simplicity) as +!bt +\begin{equation} + \hat{y}_2 = f_2(\mathrm{W}_2 \hat{y}_{1} + \hat{b}_{2}) = + f_2\left(\left[\begin{array}{ccc} + w^2_{11} &w^2_{12} &w^2_{13} \\ + w^2_{21} &w^2_{22} &w^2_{23} \\ + w^2_{31} &w^2_{32} &w^2_{33} \\ + \end{array} \right] \cdot + \left[\begin{array}{c} + y^1_1 \\ + y^1_2 \\ + y^1_3 \\ + \end{array}\right] + + \left[\begin{array}{c} + b^2_1 \\ + b^2_2 \\ + b^2_3 \\ + \end{array}\right]\right). +\end{equation} +!et + +!split +=== Matrix-vector notation and activation === + +The activation of node $i$ in layer 2 is + +!bt +\begin{equation} + y^2_i = f_2\Bigr(w^2_{i1}y^1_1 + w^2_{i2}y^1_2 + w^2_{i3}y^1_3 + b^2_i\Bigr) = + f_2\left(\sum_{j=1}^3 w^2_{ij} y_j^1 + b^2_i\right). +\end{equation} +!et + +This is not just a convenient and compact notation, but also a useful +and intuitive way to think about MLPs: The output is calculated by a +series of matrix-vector multiplications and vector additions that are +used as input to the activation functions. For each operation +$\mathrm{W}_l \hat{y}_{l-1}$ we move forward one layer. + + +!split +=== Activation functions === + + +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 +for a FFNN to fulfill the universal approximation theorem + + * Non-constant + + * Bounded + + * Monotonically-increasing + + * Continuous + +!split +=== Activation functions, Logistic and Hyperbolic ones === + +The second requirement excludes all linear functions. Furthermore, in +a MLP with only linear activation functions, each layer simply +performs a linear transformation of its inputs. + +Regardless of the number of layers, the output of the NN will be +nothing but a linear function of the inputs. Thus we need to introduce +some kind of non-linearity to the NN to be able to fit non-linear +functions Typical examples are the logistic *Sigmoid* + +!bt +\[ + f(x) = \frac{1}{1 + e^{-x}}, +\] +!et +and the *hyperbolic tangent* function +!bt +\[ + f(x) = \tanh(x) +\] +!et + +!split +=== Relevance === + +The *sigmoid* function are more biologically plausible because the +output of inactive neurons are zero. Such activation function are +called *one-sided*. However, it has been shown that the hyperbolic +tangent performs better than the sigmoid for training MLPs. has +become the most popular for *deep neural networks* + +!bc pycod +"""The sigmoid function (or the logistic curve) is a +function that takes any real number, z, and outputs a number (0,1). +It is useful in neural networks for assigning weights on a relative scale. +The value z is the weighted sum of parameters involved in the learning algorithm.""" + +import numpy +import matplotlib.pyplot as plt +import math as mt + +z = numpy.arange(-5, 5, .1) +sigma_fn = numpy.vectorize(lambda z: 1/(1+numpy.exp(-z))) +sigma = sigma_fn(z) + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.plot(z, sigma) +ax.set_ylim([-0.1, 1.1]) +ax.set_xlim([-5,5]) +ax.grid(True) +ax.set_xlabel('z') +ax.set_title('sigmoid function') + +plt.show() + +"""Step Function""" +z = numpy.arange(-5, 5, .02) +step_fn = numpy.vectorize(lambda z: 1.0 if z >= 0.0 else 0.0) +step = step_fn(z) + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.plot(z, step) +ax.set_ylim([-0.5, 1.5]) +ax.set_xlim([-5,5]) +ax.grid(True) +ax.set_xlabel('z') +ax.set_title('step function') + +plt.show() + +"""Sine Function""" +z = numpy.arange(-2*mt.pi, 2*mt.pi, 0.1) +t = numpy.sin(z) + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.plot(z, t) +ax.set_ylim([-1.0, 1.0]) +ax.set_xlim([-2*mt.pi,2*mt.pi]) +ax.grid(True) +ax.set_xlabel('z') +ax.set_title('sine function') + +plt.show() + +"""Plots a graph of the squashing function used by a rectified linear +unit""" +z = numpy.arange(-2, 2, .1) +zero = numpy.zeros(len(z)) +y = numpy.max([zero, z], axis=0) + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.plot(z, y) +ax.set_ylim([-2.0, 2.0]) +ax.set_xlim([-2.0, 2.0]) +ax.grid(True) +ax.set_xlabel('z') +ax.set_title('Rectified linear unit') + +plt.show() +!ec + + diff --git a/doc/src/week40/week40.do.txt b/doc/src/week40/week40.do.txt index 696d13c3c..02174f6bb 100644 --- a/doc/src/week40/week40.do.txt +++ b/doc/src/week40/week40.do.txt @@ -4,10 +4,6 @@ DATE: September 29-October 3, 2025 -!split -===== Plans for week 40 ===== - - !split ===== Lecture Monday September 30, 2024 ===== !bblock @@ -39,718 +35,6 @@ DATE: September 29-October 3, 2025 !eblock -!split -===== Summary from last week, using gradient descent methods, limitations ===== - -* _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. - -* _Gradients are computationally expensive to calculate for large datasets_. In many cases in statistics and ML, the cost/loss/risk function is a sum of terms, with one term for each data point. For example, in linear regression, $E \propto \sum_{i=1}^n (y_i - \mathbf{w}^T\cdot\mathbf{x}_i)^2$; for logistic regression, the square error is replaced by the cross entropy. To calculate the gradient we have to sum over *all* $n$ data points. Doing this at every GD step becomes extremely computationally expensive. An ingenious solution to this, is to calculate the gradients using small subsets of the data called ``mini batches''. This has the added benefit of introducing stochasticity into our algorithm. - -* _GD is very sensitive to choices of learning rates_. GD is extremely sensitive to the choice of learning rates. If the learning rate is very small, the training process take an extremely long time. For larger learning rates, GD can diverge and give poor results. Furthermore, depending on what the local landscape looks like, we have to modify the learning rates to ensure convergence. Ideally, we would *adaptively* choose the learning rates to match the landscape. - -* _GD treats all directions in parameter space uniformly._ Another major drawback of GD is that unlike Newton's method, the learning rate for GD is the same in all directions in parameter space. For this reason, the maximum learning rate is set by the behavior of the steepest direction and this can significantly slow down training. Ideally, we would like to take large steps in flat directions and small steps in steep directions. Since we are exploring rugged landscapes where curvatures change, this requires us to keep track of not only the gradient but second derivatives. The ideal scenario would be to calculate the Hessian but this proves to be too computationally expensive. - -* GD can take exponential time to escape saddle points, even with random initialization. As we mentioned, GD is extremely sensitive to initial condition since it determines the particular local minimum GD would eventually reach. However, even with a good initialization scheme, through the introduction of randomness, GD can still take exponential time to escape saddle points. - -!split -===== Simple implementation of GD for OLS, Ridge and Lasso ===== - -Last week we studied both several gradient methods. With and without an update of the learning. -We summarize some of these here for the methods we hvae studied in project one, without the inclusion of momentum. -!bc pycod -from random import random, seed -import numpy as np - -# the number of datapoints with a 2nd-order polynomial -n = 100 -x = 2*np.random.rand(n,1) -y = 4+3*x+5*x*x -# Design matrix including the intercept -# No scaling of data of and all data used for training -X = np.c_[np.ones((n,1)), x, x*x] -# Learning rate and number of iterations -eta = 0.05 -Niterations = 100 - -# OLS part -beta_OLS = np.random.randn(3,1) -gradient = np.zeros(3) -for iter in range(Niterations): - gradient = (2.0/n)*X.T @ (X @ beta_OLS-y) - beta_OLS -= eta*gradient -print('Parameters for OLS using gradient descent') -print(beta_OLS) - -#Ridge and Lasso parameter Lambda -Lambda = 0.01 -Id = n*Lambda* np.eye((X.T @ X).shape[0]) -# Gradient descent with Ridge -beta_Ridge = np.random.randn(3,1) -gradient = np.zeros(3) -for iter in range(Niterations): - gradients = 2.0/n*X.T @ (X @ beta_Ridge-y)+2*Lambda*beta_Ridge - beta_Ridge -= eta*gradients -print('Parameters for Ridge using gradient descent') -print(beta_Ridge) - -# Gradient descent with Lasso -beta_Lasso = np.random.randn(3,1) -gradient = np.zeros(3) -for iter in range(Niterations): - gradients = 2.0/n*X.T @ (X @ beta_Lasso-y)+Lambda*np.sign(beta_Lasso) - beta_Lasso -= eta*gradients -print('Parameters for Lasso using gradient descent') -print(beta_Lasso) - -!ec - - -!split -===== But none of these can compete with Newton's method ===== - -Note that we here have introduced automatic differentiation -!bc pycod -# Using Newton's method -from random import random, seed -import numpy as np -import autograd.numpy as np -from autograd import grad - -def CostOLS(beta): - return (1.0/n)*np.sum((y-X @ beta)**2) - -n = 100 -x = 2*np.random.rand(n,1) -y = 4+3*x+5*x*x - -X = np.c_[np.ones((n,1)), x, x*x] -XT_X = X.T @ X -beta_linreg = np.linalg.pinv(XT_X) @ (X.T @ y) -print("Own inversion") -print(beta_linreg) -# Hessian matrix -H = (2.0/n)* XT_X -# Note that here the Hessian does not depend on the parameters beta -invH = np.linalg.pinv(H) -beta = np.random.randn(3,1) -Niterations = 5 -# define the gradient -training_gradient = grad(CostOLS) - -for iter in range(Niterations): - gradients = training_gradient(beta) - beta -= invH @ gradients - print(iter,gradients[0],gradients[1]) -print("beta from own Newton code") -print(beta) - -!ec - -!split -===== Gradient descent and Logistic regression ===== - -Finally, we complete these examples by adding a simple code for -Logistic regression. Note the more general approach with a class for -the method. Here we use a so-called _AND_ gate for our data set. - -!bc pycod -import numpy as np -class LogisticRegression: - def __init__(self, learning_rate=0.01, num_iterations=1000): - self.learning_rate = learning_rate - self.num_iterations = num_iterations - self.beta_logreg = None - def sigmoid(self, z): - return 1 / (1 + np.exp(-z)) - def GDfit(self, X, y): - n_data, num_features = X.shape - self.beta_logreg = np.zeros(num_features) - for _ in range(self.num_iterations): - linear_model = X @ self.beta_logreg - y_predicted = self.sigmoid(linear_model) - # Gradient calculation - gradient = (X.T @ (y_predicted - y))/n_data - # Update beta_logreg - self.beta_logreg -= self.learning_rate*gradient - def predict(self, X): - linear_model = X @ self.beta_logreg - y_predicted = self.sigmoid(linear_model) - return [1 if i >= 0.5 else 0 for i in y_predicted] -# Example usage -if __name__ == "__main__": - # Sample data - X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]]) - y = np.array([0, 0, 0, 1]) # This is an AND gate - model = LogisticRegression(learning_rate=0.01, num_iterations=1000) - model.GDfit(X, y) - predictions = model.predict(X) - print("Predictions:", predictions) -!ec - -!split -===== Overview video on Stochastic Gradient Descent ===== - -"What is Stochastic Gradient Descent":"https://www.youtube.com/watch?v=vMh0zPT0tLI&ab_channel=StatQuestwithJoshStarmer" -There are several reasons for using stochastic gradient descent. Some of these are: - -o Efficiency: Updates weights more frequently using a single or a small batch of samples, which speeds up convergence. -o Hopefully avoid Local Minima -o Memory Usage: Requires less memory compared to computing gradients for the entire dataset. - -!split -===== Batches and mini-batches ===== - -In gradient descent we compute the cost function and its gradient for all data points we have. - -In large-scale applications such as the "ILSVRC challenge":"https://www.image-net.org/challenges/LSVRC/", the -training data can have on order of millions of examples. Hence, it -seems wasteful to compute the full cost function over the entire -training set in order to perform only a single parameter update. A -very common approach to addressing this challenge is to compute the -gradient over batches of the training data. For example, a typical batch could contain some thousand examples from -an entire training set of several millions. This batch is then used to -perform a parameter update. - -!split -===== Stochastic Gradient Descent (SGD) ===== - -In stochastic gradient descent, the extreme case is the case where we -have only one batch, that is we include the whole data set. - -This process is called Stochastic Gradient -Descent (SGD) (or also sometimes on-line gradient descent). This is -relatively less common to see because in practice due to vectorized -code optimizations it can be computationally much more efficient to -evaluate the gradient for 100 examples, than the gradient for one -example 100 times. Even though SGD technically refers to using a -single example at a time to evaluate the gradient, you will hear -people use the term SGD even when referring to mini-batch gradient -descent (i.e. mentions of MGD for “Minibatch Gradient Descent”, or BGD -for “Batch gradient descent” are rare to see), where it is usually -assumed that mini-batches are used. The size of the mini-batch is a -hyperparameter but it is not very common to cross-validate or bootstrap it. It is -usually based on memory constraints (if any), or set to some value, -e.g. 32, 64 or 128. We use powers of 2 in practice because many -vectorized operation implementations work faster when their inputs are -sized in powers of 2. - -In our notes with SGD we mean stochastic gradient descent with mini-batches. - - -!split -===== Stochastic Gradient Descent ===== - -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 -function, which we want to minimize, can almost always be written as a -sum over $n$ data points $\{\mathbf{x}_i\}_{i=1}^n$, -!bt -\[ -C(\mathbf{\beta}) = \sum_{i=1}^n c_i(\mathbf{x}_i, -\mathbf{\beta}). -\] -!et - -!split -===== Computation of gradients ===== - -This in turn means that the gradient can be -computed as a sum over $i$-gradients -!bt -\[ -\nabla_\beta C(\mathbf{\beta}) = \sum_i^n \nabla_\beta c_i(\mathbf{x}_i, -\mathbf{\beta}). -\] -!et - -Stochasticity/randomness is introduced by only taking the -gradient on a subset of the data called minibatches. If there are $n$ -data points and the size of each minibatch is $M$, there will be $n/M$ -minibatches. We denote these minibatches by $B_k$ where -$k=1,\cdots,n/M$. - - - -!split -===== SGD example ===== -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 -$B_1 = (\mathbf{x}_1,\mathbf{x}_2), \cdots, B_5 = -(\mathbf{x}_9,\mathbf{x}_{10})$. Note that if you choose $M=1$ you -have only a single batch with all data points and on the other extreme, -you may choose $M=n$ resulting in a minibatch for each datapoint, i.e -$B_k = \mathbf{x}_k$. - -The idea is now to approximate the gradient by replacing the sum over -all data points with a sum over the data points in one the minibatches -picked at random in each gradient descent step -!bt -\[ -\nabla_{\beta} -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}). -\] -!et - -!split -===== The gradient step ===== - -Thus a gradient descent step now looks like -!bt -\[ -\beta_{j+1} = \beta_j - \gamma_j \sum_{i \in B_k}^n \nabla_\beta c_i(\mathbf{x}_i, -\mathbf{\beta}) -\] -!et - -where $k$ is picked at random with equal -probability from $[1,n/M]$. An iteration over the number of -minibathces (n/M) is commonly referred to as an epoch. Thus it is -typical to choose a number of epochs and for each epoch iterate over -the number of minibatches, as exemplified in the code below. - -!split -===== Simple example code ===== - -!bc pycod -import numpy as np - -n = 100 #100 datapoints -M = 5 #size of each minibatch -m = int(n/M) #number of minibatches -n_epochs = 10 #number of epochs - -j = 0 -for epoch in range(1,n_epochs+1): - for i in range(m): - k = np.random.randint(m) #Pick the k-th minibatch at random - #Compute the gradient using the data in minibatch Bk - #Compute new suggestion for - j += 1 -!ec - -Taking the gradient only on a subset of the data has two important -benefits. First, it introduces randomness which decreases the chance -that our opmization scheme gets stuck in a local minima. Second, if -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. - -!split -===== When do we stop? ===== - -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 -threshold and stop if true. However, the condition that the gradient -is zero is valid also for local minima, so this would only tell us -that we are close to a local/global minimum. However, we could also -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. - -!split -===== Slightly different approach ===== - -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. Such approaches are -also called scaling. There are many such ways to "scale the learning -rate":"https://towardsdatascience.com/gradient-descent-the-learning-rate-and-the-importance-of-feature-scaling-6c0b416596e1" -and "discussions here":"https://www.jmlr.org/papers/volume23/20-1258/20-1258.pdf". See -also -URL:"https://towardsdatascience.com/learning-rate-schedules-and-adaptive-learning-rate-methods-for-deep-learning-2c8f433990d1" -for a discussion of different scaling functions for the learning rate. - -!split -===== Time decay rate ===== - -As an example, let $e = 0,1,2,3,\cdots$ denote the current epoch and let $t_0, t_1 > 0$ be two fixed numbers. Furthermore, let $t = e \cdot m + i$ where $m$ is the number of minibatches and $i=0,\cdots,m-1$. Then the function $$\gamma_j(t; t_0, t_1) = \frac{t_0}{t+t_1} $$ goes to zero as the number of epochs gets large. I.e. we start with a step length $\gamma_j (0; t_0, t_1) = t_0/t_1$ which decays in *time* $t$. - -In this way we can fix the number of epochs, compute $\beta$ and -evaluate the cost function at the end. Repeating the computation will -give a different result since the scheme is random by design. Then we -pick the final $\beta$ that gives the lowest value of the cost -function. - -!bc pycod -import numpy as np - -def step_length(t,t0,t1): - return t0/(t+t1) - -n = 100 #100 datapoints -M = 5 #size of each minibatch -m = int(n/M) #number of minibatches -n_epochs = 500 #number of epochs -t0 = 1.0 -t1 = 10 - -gamma_j = t0/t1 -j = 0 -for epoch in range(1,n_epochs+1): - for i in range(m): - k = np.random.randint(m) #Pick the k-th minibatch at random - #Compute the gradient using the data in minibatch Bk - #Compute new suggestion for beta - t = epoch*m+i - gamma_j = step_length(t,t0,t1) - j += 1 - -print("gamma_j after %d epochs: %g" % (n_epochs,gamma_j)) -!ec - - -!split -===== Code with a Number of Minibatches which varies ===== - -In the code here we vary the number of mini-batches. -!bc pycode -# Importing various packages -from math import exp, sqrt -from random import random, seed -import numpy as np -import matplotlib.pyplot as plt - -n = 100 -x = 2*np.random.rand(n,1) -y = 4+3*x+np.random.randn(n,1) - -X = np.c_[np.ones((n,1)), x] -XT_X = X.T @ X -theta_linreg = np.linalg.inv(X.T @ X) @ (X.T @ y) -print("Own inversion") -print(theta_linreg) -# Hessian matrix -H = (2.0/n)* XT_X -EigValues, EigVectors = np.linalg.eig(H) -print(f"Eigenvalues of Hessian Matrix:{EigValues}") - -theta = np.random.randn(2,1) -eta = 1.0/np.max(EigValues) -Niterations = 1000 - - -for iter in range(Niterations): - gradients = 2.0/n*X.T @ ((X @ theta)-y) - theta -= eta*gradients -print("theta from own gd") -print(theta) - -xnew = np.array([[0],[2]]) -Xnew = np.c_[np.ones((2,1)), xnew] -ypredict = Xnew.dot(theta) -ypredict2 = Xnew.dot(theta_linreg) - -n_epochs = 50 -M = 5 #size of each minibatch -m = int(n/M) #number of minibatches -t0, t1 = 5, 50 - -def learning_schedule(t): - return t0/(t+t1) - -theta = np.random.randn(2,1) - -for epoch in range(n_epochs): -# Can you figure out a better way of setting up the contributions to each batch? - for i in range(m): - random_index = M*np.random.randint(m) - xi = X[random_index:random_index+M] - yi = y[random_index:random_index+M] - gradients = (2.0/M)* xi.T @ ((xi @ theta)-yi) - eta = learning_schedule(epoch*m+i) - theta = theta - eta*gradients -print("theta from own sdg") -print(theta) - -plt.plot(xnew, ypredict, "r-") -plt.plot(xnew, ypredict2, "b-") -plt.plot(x, y ,'ro') -plt.axis([0,2.0,0, 15.0]) -plt.xlabel(r'$x$') -plt.ylabel(r'$y$') -plt.title(r'Random numbers ') -plt.show() - -!ec - - - -!split -===== Replace or not ===== - -In the above code, we have use replacement in setting up the -mini-batches. The discussion -"here":"https://sebastianraschka.com/faq/docs/sgd-methods.html" may be -useful. - - -!split -===== Momentum based GD ===== - -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 - -!bt -\begin{align} -\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t) \nonumber \\ -\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}, -\end{align} -!et - -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 - -!bt -\[ -\Delta \boldsymbol{\theta}_{t+1} = \gamma \Delta \boldsymbol{\theta}_t -\ \eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t), -\] -!et -where we have defined $\Delta \boldsymbol{\theta}_{t}= \boldsymbol{\theta}_t-\boldsymbol{\theta}_{t-1}$. - -!split -===== More on momentum based approaches ===== - -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 - -!bt -\[ -m {d^2 \mathbf{w} \over dt^2} + \mu {d \mathbf{w} \over dt }= -\nabla_w E(\mathbf{w}). -\] -!et - -We can discretize this equation in the usual way to get - -!bt -\[ -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}). -\] -!et - -Rearranging this equation, we can rewrite this as - -!bt -\[ -\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. -\] -!et - -!split -===== Momentum parameter ===== - -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: - -!bt -\[ -\gamma= {m \over m +\mu \Delta t }, \qquad \eta = {(\Delta t)^2 \over m +\mu \Delta t}. -\] -!et - -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 - -!bt -\begin{align} -\mathbf{v}_{t}&=\gamma \mathbf{v}_{t-1}+\eta_{t}\nabla_\theta E(\boldsymbol{\theta}_t +\gamma \mathbf{v}_{t-1}) \nonumber \\ -\boldsymbol{\theta}_{t+1}&= \boldsymbol{\theta}_t -\mathbf{v}_{t}. -\end{align} -!et - -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$. - - -!split -===== Second moment of the gradient ===== - - -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. - -During the last decade 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, Root Mean Squared Propagation (RMS-Prop), and -"ADAM":"https://arxiv.org/abs/1412.6980". - -!split -===== RMS prop ===== - -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 - -!bt -\begin{align} -\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) \\ -\mathbf{s}_t &=\beta \mathbf{s}_{t-1} +(1-\beta)\mathbf{g}_t^2 \nonumber \\ -\boldsymbol{\theta}_{t+1}&=&\boldsymbol{\theta}_t - \eta_t { \mathbf{g}_t \over \sqrt{\mathbf{s}_t +\epsilon}}, \nonumber -\end{align} -!et - -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. - - -!split -===== "ADAM optimizer":"https://arxiv.org/abs/1412.6980" ===== - -A related algorithm is the ADAM optimizer. In -"ADAM":"https://arxiv.org/abs/1412.6980", 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. The method isefficient when working with large -problems involving lots data and/or parameters. It is a combination of the -gradient descent with momentum algorithm and the RMSprop algorithm -discussed above. - -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) - -!bt -\begin{align} -\mathbf{g}_t &= \nabla_\theta E(\boldsymbol{\theta}) \\ -\mathbf{m}_t &= \beta_1 \mathbf{m}_{t-1} + (1-\beta_1) \mathbf{g}_t \nonumber \\ -\mathbf{s}_t &=\beta_2 \mathbf{s}_{t-1} +(1-\beta_2)\mathbf{g}_t^2 \nonumber \\ -\bm{\mathbf{m}}_t&={\mathbf{m}_t \over 1-\beta_1^t} \nonumber \\ -\bm{\mathbf{s}}_t &={\mathbf{s}_t \over1-\beta_2^t} \nonumber \\ -\boldsymbol{\theta}_{t+1}&=\boldsymbol{\theta}_t - \eta_t { \bm{\mathbf{m}}_t \over \sqrt{\bm{\mathbf{s}}_t} +\epsilon}, \nonumber \\ -\end{align} -!et - -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 = \bm{\mathbf{s}}_t - -(\bm{\mathbf{m}}_t)^2$. Consider a single parameter $\theta_t$. The -update rule for this parameter is given by - -!bt -\[ -\Delta \theta_{t+1}= -\eta_t { \bm{m}_t \over \sqrt{\sigma_t^2 + m_t^2 }+\epsilon}. -\] -!et - -!split -===== Algorithms and codes for Adagrad, RMSprop and Adam ===== - -The algorithms we have implemented are well described in the text by "Goodfellow, Bengio and Courville, chapter 8":"https://www.deeplearningbook.org/contents/optimization.html". - -The codes which implement these algorithms are discussed after our presentation of automatic differentiation. - - -===== AdaGrad algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html" ===== - -FIGURE: [figures/adagrad.png, width=600 frac=0.8] - - -===== RMSProp algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html" ===== - -FIGURE: [figures/rmsprop.png, width=600 frac=0.8] - - - -===== ADAM algorithm, taken from "Goodfellow et al":"https://www.deeplearningbook.org/contents/optimization.html" ===== - -FIGURE: [figures/adam.png, width=600 frac=0.8] - - - - - -!split -===== Practical tips ===== - -* _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. - -Geron's text, see chapter 11, has several interesting discussions. - - !split ===== Automatic differentiation =====