<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Victoria Johnston</title>
    <description>The latest articles on DEV Community by Victoria Johnston (@ctrlaltvictoria).</description>
    <link>https://dev.to/ctrlaltvictoria</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1140662%2Faa5dabfd-8437-4dc9-b898-6d69b4cbc696.jpg</url>
      <title>DEV Community: Victoria Johnston</title>
      <link>https://dev.to/ctrlaltvictoria</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ctrlaltvictoria"/>
    <language>en</language>
    <item>
      <title>AI Log #4: Vectorization &amp; NumPy in Machine Learning</title>
      <dc:creator>Victoria Johnston</dc:creator>
      <pubDate>Wed, 06 Dec 2023 10:40:49 +0000</pubDate>
      <link>https://dev.to/ctrlaltvictoria/ai-log-4-vectorization-numpy-in-machine-learning-3npl</link>
      <guid>https://dev.to/ctrlaltvictoria/ai-log-4-vectorization-numpy-in-machine-learning-3npl</guid>
      <description>&lt;p&gt;I am an experienced software engineer diving into AI and machine learning. Are you also learning/interested in learning?&lt;br&gt;
&lt;a href="https://open.substack.com/pub/ctrlaltvictoria"&gt;Learn with me! I’m sharing my learning logs along the way.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3q4LeqxD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lfvjt3zgoi2ahzm7ihdb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3q4LeqxD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lfvjt3zgoi2ahzm7ihdb.png" alt="Vectorization" width="800" height="793"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vectorization is a pivotal concept in machine learning; it enables us to handle multi-feature data with efficiency and speed. This learning log delves into vectorization, with a focus on NumPy's role in optimizing operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;NumPy&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;NumPy is an essential Python library in machine learning known for its powerful handling of arrays and matrices. It's the go-to tool for vectorized operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why use vectorization?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Vectorization optimizes data processing by handling entire arrays or datasets simultaneously, rather than element-by-element, as in traditional loops. This approach is especially powerful in NumPy due to its ability to leverage the parallel hardware capabilities of computers. Operations like the dot product are executed in parallel, markedly enhancing code efficiency and execution speed compared to sequential for loops.&lt;/p&gt;

&lt;p&gt;The advantage of vectorization becomes even more pronounced in large datasets and complex operations, such as during the gradient descent process in machine learning, where it allows for the simultaneous computation of new feature values.&lt;/p&gt;

&lt;p&gt;Vectorization also helps simplify our code by reducing complexity. The simple NumPy commands below will show what I mean by this.&lt;/p&gt;

&lt;p&gt;tl;dr - if we want our data processing to run faster and more efficiently, we need to use vectorization!&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use vectorization?
&lt;/h3&gt;

&lt;p&gt;In machine learning, models usually have multiple features. These features are often represented in vector format. Consider a model with four features. In such a case, the example data, &lt;em&gt;xi&lt;/em&gt;, consists of input features represented as a vector: [*xi*1, *xi*2, *xi*3, *xi*4]. Each of these features is associated with a corresponding weight ([w1, w2, w3, w4]), determined during the model's training phase.&lt;/p&gt;

&lt;p&gt;To use vectorization effectively, we want to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use NumPy arrays to represent these vectors:&lt;/strong&gt; Vectorization is implemented using NumPy arrays, which enable efficient storage and manipulation of data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid for loops:&lt;/strong&gt; Traditional for loops process data element by element and are generally slower. Vectorization replaces these loops with array operations, significantly enhancing computational speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leverage dot product and other NumPy functions:&lt;/strong&gt; The dot product is a common vectorized operation in machine learning. NumPy's various functions, such as np.dot, np.sum, and np.mean, are designed to operate on whole arrays, making them ideal for vectorized computations.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Key Concepts in NumPy&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dimensionality:&lt;/strong&gt; This refers to the number of indices required to select an element from an array. A one-dimensional array needs one index, a two-dimensional array requires two, and so forth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shape:&lt;/strong&gt; This attribute describes an array's dimensions. A 2x3 2D array has a shape of (2,3), while a one-dimensional array (vector) might have a shape of (n, ) for 'n' elements. Individual elements, not being arrays, have a shape of ().&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multidimensional Arrays:&lt;/strong&gt; NumPy arrays can extend beyond two dimensions, adding complexity and flexibility to the data structure and its manipulation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Common Vectorized NumPy Operations&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Creating Arrays&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;np.zeros(num):&lt;/strong&gt; Generates an array of 'num' zeros, defaulting to float64. For example, np.zeros(3) yields an array shaped (3, ).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;np.random.random_sample(num):&lt;/strong&gt; Produces an array of random float64 numbers drawn from a uniform distribution over [0, 1). The argument shape should be a tuple that defines the dimensions of the output array. For example calling random_sample((2, 3)) creates a 2x3 array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;np.random.rand(num):&lt;/strong&gt; Also generates random float64 numbers from a uniform distribution over [0, 1). Unlike random_sample, rand accepts multiple arguments, each representing a dimension of the desired output array. For instance, rand(2, 3) directly creates a 2x3 array. It offers a more intuitive way to specify the shape of multidimensional arrays.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;np.arange(num):&lt;/strong&gt; Creates an array filled with numbers from 1 up to num-1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;np.array([...]):&lt;/strong&gt; Creates an array with specified values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Indexing Arrays&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;a[0]:&lt;/strong&gt; Accesses the first element of the array. This operation is consistent with standard coding practices. Attempting to access an index out of range will result in an error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;a[-1]:&lt;/strong&gt; Accesses the last element of the array.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Slicing Arrays&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;a[:3]:&lt;/strong&gt; Retrieves elements at indices up to (but not including) index 3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;a[3:]:&lt;/strong&gt; Selects elements from index 3 to the end of the array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;a[:]:&lt;/strong&gt; Accesses all elements within the array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;a[start:stop:step]:&lt;/strong&gt; Provides a more flexible slicing option, allowing the selection of elements over a specified range and step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Single Array Operations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-a:&lt;/strong&gt; Negates each element in the array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;np.sum(a):&lt;/strong&gt; Calculates the sum of all elements in the array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;np.mean(a):&lt;/strong&gt; Computes the average value of the elements in the array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;a&lt;/strong&gt;2**: Squares each element in the array.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Element-Wise Array Operations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;np.array([-1, 1]) + np.array([1, -1]):&lt;/strong&gt; Results in an array [0, 0]. These operations are applied element-wise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;np.array([1, 2]) * 2&lt;/strong&gt;: multiplies each element of the array by 2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dot Product&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;np.dot(a1, a2):&lt;/strong&gt; Multiplies vectors element-wise and then sums the results, a fundamental operation in many machine learning algorithms. For example, using np.dot(a1, a2) where a1 = [1, 2] and a2 = [3, 4] would compute (1*3) + (2*4).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Matrices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Matrices, or two-dimensional arrays, are integral in machine learning, and NumPy provides a comprehensive set of functions for their creation and manipulation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Matrix Creation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;np.zeros((m, n)):&lt;/strong&gt; Generates a matrix of zeros with m rows and n columns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;np.random.random_sample((m, n)):&lt;/strong&gt; Creates a matrix filled with random numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;np.array([[1], [2], [3]]):&lt;/strong&gt; Creates a matrix with specified values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reshaping Matrices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;X.reshape(2, 3):&lt;/strong&gt; Changes the shape of the matrix to 2 rows and 3 columns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;X.reshape(-1, 1):&lt;/strong&gt; Reshapes the matrix into a column vector.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Slicing Matrices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;X[r, start:stop:step]:&lt;/strong&gt; Accesses elements in row r within a specified range and step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;X[:, start:stop:step]:&lt;/strong&gt; Retrieves elements across all rows within a specified range.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;X[:, :]:&lt;/strong&gt; Selects all elements in the matrix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;X[1, :]:&lt;/strong&gt; Accesses all elements in row 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Advanced Matrix Operations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;np.c_[...]:&lt;/strong&gt; Concatenates arrays along their column boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;np.ptp(arr, axis=0):&lt;/strong&gt; Calculates the peak-to-peak (maximum - minimum) range of elements column-wise.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These indexing, slicing, and operation techniques in NumPy enable efficient handling and manipulation of data in machine learning, demonstrating the practical benefits of vectorization.&lt;/p&gt;

&lt;p&gt;I only showed a few examples. NumPy is an incredibly extensive library, and its mathematical functions go far beyond simple array operations!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Summary&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Vectorization, particularly when utilizing NumPy, is an essential concept in machine learning. It dramatically streamlines and accelerates computations, making processing large datasets and executing complex operations much more efficient.&lt;/p&gt;

&lt;p&gt;By leveraging NumPy's array-centric design and functions, we can perform bulk operations on data without the need for slow, iterative loops. This approach not only speeds up the execution but also makes the code more readable and concise.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Disclosure&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I am taking Andrew Ng’s Machine Learning Specialization, and these learning logs contain some of what I learned from it. It’s a great course. I highly recommend it!&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>AI Log #3: What is Gradient Descent?</title>
      <dc:creator>Victoria Johnston</dc:creator>
      <pubDate>Wed, 29 Nov 2023 14:06:26 +0000</pubDate>
      <link>https://dev.to/ctrlaltvictoria/ai-log-3-what-is-gradient-descent-4a0k</link>
      <guid>https://dev.to/ctrlaltvictoria/ai-log-3-what-is-gradient-descent-4a0k</guid>
      <description>&lt;p&gt;I am an experienced software engineer diving into AI and machine learning. Are you also learning/interested in learning?&lt;br&gt;
&lt;a href="https://open.substack.com/pub/ctrlaltvictoria" rel="noopener noreferrer"&gt;Learn with me! I’m sharing my learning logs along the way.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Disclosure: I have already learnt basic machine learning, but I am starting this learning log from the beginning because I need a refresher 😅.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost Function Recap
&lt;/h2&gt;

&lt;p&gt;In my &lt;a href="https://dev.to/ctrlaltvictoria/ai-log-2-what-is-a-cost-function-in-machine-learning-9"&gt;previous learning log&lt;/a&gt;, I covered model parameters and cost functions. Here is a quick summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parameters of a Model: Variables that can be altered during training to enhance the model. For example, in the model y = wx + b, w and b are parameters, with one input feature, x.&lt;/li&gt;
&lt;li&gt;Cost Function, J: Indicates the accuracy of a model’s predictions against example data. A smaller J implies closer predicted values (ŷ) to actual values (y), signifying better parameter choices and an improved model.&lt;/li&gt;
&lt;li&gt;J Calculation: J is computed across the example dataset and varies with the choice of parameter values. Thus, in a model with parameters w and b, the cost function is represented as J(w, b).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Gradient Descent
&lt;/h2&gt;

&lt;p&gt;When training a model, our goal is to discover a function that best fits our example data. We achieve this by adjusting parameter values to obtain the lowest possible cost, J.&lt;/p&gt;

&lt;p&gt;Let’s first consider the most obvious way to find optimal parameter values.&lt;/p&gt;

&lt;p&gt;We could test every possible parameter value. At first glance, this solution may seem to work; however, there are two key pitfalls. Firstly, it is impossible to test all possible parameter values thoroughly as parameters are real numbers; they have infinite range and decimal depth! Secondly, it would be incredibly inefficient and time-consuming.&lt;/p&gt;

&lt;p&gt;We need a more systematic and innovative solution.&lt;/p&gt;

&lt;p&gt;Enter gradient descent. This algorithm involves iteratively testing different parameters and calculating the cost at each step. A ‘step’ is synonymous with iteration — each represents a move closer to the optimal parameter values. Gradient descent is similar to our naive solution in that it requires trying out different parameter values and many steps. The critical difference lies in choosing the next set of parameter values. In gradient descent, we choose the next values based on gradient calculations, leading to a much more directed and efficient process.&lt;/p&gt;

&lt;p&gt;Here is how it works on a high level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starting Point: We begin with specific parameter values, usually chosen randomly or through an informed guess.&lt;/li&gt;
&lt;li&gt;Direction of Descent: We determine the direction to move by calculating the gradient.
Updating Parameters: We adjust the parameter values to reduce J using the gradient.&lt;/li&gt;
&lt;li&gt;Repetition: This process continues until we meet certain end conditions. Each repetition is a step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what gradient descent may look like on a cost graph for a model with one parameter. In this diagram, we use gradient descent to take steps that get us closer to the minimum.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhi09g6l6tvoprjong9ae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhi09g6l6tvoprjong9ae.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gradient descent can handle any number of parameters (it just becomes increasingly more complex to visualise!). In general, as long as we have a cost function, we can use gradient descent to find values for parameters that minimise the cost, J.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mechanics of Gradient Descent
&lt;/h2&gt;

&lt;p&gt;To truly grasp gradient descent, let’s delve into the details.&lt;/p&gt;

&lt;p&gt;Remember back to high school maths… What does the gradient help us calculate? The slope! The gradient in this context helps us determine the slope of the cost function. Knowing this slope enables us to identify the direction of the steepest descent.&lt;/p&gt;

&lt;p&gt;This concept made more sense when I tried to visualise it. Say I plot a graph with the cost J at different parameter values. Here is an example of how a cost graph with two parameters might look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkpxulh2kzjgnsh9v5d7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkpxulh2kzjgnsh9v5d7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine standing on this slope and looking for the quickest way down. Which direction should I move? Down the slope! Ideally, I would move in the steepest direction from my current position. This concept is the essence of gradient descent!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6rpwih8bk3wjpir4se7q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6rpwih8bk3wjpir4se7q.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A critical aspect of this process is the size of the step we take down the slope. This is influenced by a crucial factor known as the learning rate, α. This rate is a positive number dictating the magnitude of each parameter change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gradient Descent Math
&lt;/h2&gt;

&lt;p&gt;Now it’s time for some math.&lt;/p&gt;

&lt;p&gt;Let’s introduce the mathematical formulae central to gradient descent. For each parameter, we calculate a new value using its gradient. The learning rate, α, plays a vital role here, determining the size of the step we take toward the steepest descent.&lt;/p&gt;

&lt;p&gt;The formula for updating each parameter is unique, ensuring specific and effective adjustments. For instance, the updates for parameters w1, w2, etc., in a multi-parameter model are as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4yx2jmfey4ey9sfvo0s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4yx2jmfey4ey9sfvo0s.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0zcam16wemnfkaklazq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0zcam16wemnfkaklazq.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do we use the partial derivative?
&lt;/h2&gt;

&lt;p&gt;In gradient descent, using partial derivatives instead of full derivatives is a deliberate choice. This is because, in multi-parameter models, each parameter uniquely influences the model’s output. The partial derivative hones in on the impact of a single parameter change, keeping all others constant. For example, adjusting w1 affects the cost J, independent of changes in w2 or b.&lt;/p&gt;

&lt;p&gt;Consequently, the gradient descent update for each parameter is tailored with its own partial derivative, allowing for precise, individualised adjustments:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9pmu4fcef35zudr5t4x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9pmu4fcef35zudr5t4x.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Rate
&lt;/h2&gt;

&lt;p&gt;As mentioned, the learning rate, α, is a pivotal element that dictates the step size in our journey towards the cost function’s minimum. Thus, picking a reasonable learning rate is critical. Here is how choosing a bad learning rate can negatively affect gradient descent and, in some cases, stop it from working at all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overshooting with Large Steps: A high α makes our steps too large. We risk stepping past the minimum and onto another slope. We then may continue to bounce from slope to slope without settling down on the same slope. Here is what overshooting may look like:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqroxrsxv6wy7y5eahm6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqroxrsxv6wy7y5eahm6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Usually, we can tell if this is happening if the gradient fluctuates back and forth (e.g. between positive and negative) in each iteration. Sometimes, we can get lucky and move closer to the optimal minimum.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Divergence: In extreme cases, these oversized steps don’t just result in bouncing but escalate, moving us further from the minimum and causing the algorithm to diverge entirely:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85u96npqld5mvwtd3rtj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85u96npqld5mvwtd3rtj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inefficient with Tiny Steps: A tiny learning rate can significantly slow the journey, resulting in minuscule progress towards the minimum. Gradient descent will still work, but it will be highly inefficient.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjkp9dhr3ffcrxz9w7tk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjkp9dhr3ffcrxz9w7tk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips for Fine-Tuning the Learning Rate
&lt;/h2&gt;

&lt;p&gt;To optimise the learning rate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Experiment with increments (e.g., 0.001, 0.01, 0.1), seeking a rate that consistently reduces the cost.&lt;/li&gt;
&lt;li&gt;Start with a very small alpha to ensure consistent cost reduction, then gradually increase.&lt;/li&gt;
&lt;li&gt;Aim for the largest learning rate that still guarantees consistent and rapid cost reduction.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Stop
&lt;/h2&gt;

&lt;p&gt;Determining the right moment to stop gradient descent is a strategic decision. We can choose different end conditions; here are a few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Convergence: We stop when parameter changes are negligible, suggesting proximity to the minimum.&lt;/li&gt;
&lt;li&gt;Fixed Number of Steps: We set a predetermining number of iterations for practical reasons, especially when computational resources are a constraint.&lt;/li&gt;
&lt;li&gt;Threshold-Based: We halt when the decrease in cost J falls below a set threshold, indicating diminishing returns on further iterations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Gradient descent optimises model parameters by iteratively adjusting them based on gradient calculations, aiming to minimise the cost function, J.&lt;/li&gt;
&lt;li&gt;The algorithm involves determining the steepest descent direction using partial derivatives and adjusting each parameter with a calculated step size influenced by the learning rate (α). The process repeats until it meets specific end conditions, like convergence or a fixed number of iterations.&lt;/li&gt;
&lt;li&gt;The choice of learning rate is crucial as it influences the efficiency of reaching the minimum cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gradient descent is a highly versatile algorithm applied in a wide array of machine learning methods, including complex models like deep learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclosure
&lt;/h2&gt;

&lt;p&gt;I am taking Andrew Ng’s Machine Learning Specialization, and these learning logs contain some of what I learned from it. It’s a great course. I highly recommend it!&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>AI Log #2: What is a Cost Function in Machine Learning?</title>
      <dc:creator>Victoria Johnston</dc:creator>
      <pubDate>Fri, 17 Nov 2023 07:41:35 +0000</pubDate>
      <link>https://dev.to/ctrlaltvictoria/ai-log-2-what-is-a-cost-function-in-machine-learning-9</link>
      <guid>https://dev.to/ctrlaltvictoria/ai-log-2-what-is-a-cost-function-in-machine-learning-9</guid>
      <description>&lt;p&gt;I am an experienced software engineer diving into AI and machine learning. Are you also learning/interested in learning?&lt;br&gt;
&lt;a href="https://open.substack.com/pub/ctrlaltvictoria"&gt;Learn with me! I’m sharing my learning logs along the way.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Disclosure: I have already learnt basic machine learning, but I am starting this learning log from the beginning because I need a refresher 😅.&lt;/p&gt;

&lt;h2&gt;
  
  
  Log #2: Cost Functions in Machine Learning
&lt;/h2&gt;

&lt;p&gt;Cost functions indicate how well a machine learning model performs against a set of example data.&lt;/p&gt;

&lt;p&gt;The output of a cost function is referred to as ‘the cost’ or ‘J’. A small cost suggests that the model performs well, which means that the difference between the model’s predicted value and the actual value is generally small. In contrast, a high cost suggests the opposite and that the difference between the predicted and actual values is considerable.&lt;/p&gt;

&lt;p&gt;Different cost functions can exist for various machine-learning methods, even within a single machine-learning method! For instance, the cost function used on a regression model may differ from that on a classification model or neural network. We also have different cost functions for regression models, for example, mean error (ME), mean absolute error (MAE), mean squared error (MSE), etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost Functions in Model Training
&lt;/h2&gt;

&lt;p&gt;Cost functions are essential for training a model. During training, we use them to determine the weights and biases for our model’s function.&lt;/p&gt;

&lt;p&gt;Say I have a simple regression problem (covered in my last learning log). I have a series of example data (training data), each with one input feature (x) and the actual output (y).&lt;/p&gt;

&lt;p&gt;Here is the function for the simple regression model:&lt;br&gt;
f(x) = ŷ = wx + b&lt;/p&gt;

&lt;p&gt;We refer to ‘w’ and ‘b’ as the parameters. Parameters of a model are variables that can be changed during training to improve the model.&lt;/p&gt;

&lt;p&gt;During training, I want to find values for these parameters that produce a predicted value (ŷ) as close to the actual value (y) across all my example data.&lt;/p&gt;

&lt;p&gt;We refer to the difference between ŷ (predicted) and y (actual) as the error. A cost function is a computed error across the set of example data; it factors each example data’s error in its calculation. In other words, it is a computed ‘collective’ error across the group of example data, not the error for a single example data!&lt;/p&gt;

&lt;p&gt;Thus, when I write this above: “a predicted value (ŷ) as close to the actual value (y) across all my example data.”&lt;/p&gt;

&lt;p&gt;I also mean “the lowest computed cost across all my example data.”&lt;/p&gt;

&lt;p&gt;or “the lowest cost function across all my example data.”&lt;/p&gt;

&lt;p&gt;We achieve this by experimenting with different parameters and calculating the cost at each step until we find values that yield the lowest cost.&lt;/p&gt;

&lt;p&gt;The cost function is so important; without it, we would not determine how good specific parameters are and thus would be unable to choose optimal parameter values for our model. Our model is as good as the parameter values we choose for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regression Cost Functions
&lt;/h2&gt;

&lt;p&gt;I will only showcase some cost functions in this learning log and cover the rest in detail in future logs. At this stage, it is more important to understand why cost functions are essential and how we use them.&lt;/p&gt;

&lt;p&gt;As I mentioned already, there are different types of cost functions. Here are some regression cost functions:&lt;/p&gt;

&lt;p&gt;The most straightforward cost function is called mean error (ME). It works exactly how it sounds: the mean error across the set of example data. However, it is generally not recommended because the errors can be positive or negative, so adding them together may not reflect the collective error effectively.&lt;/p&gt;

&lt;p&gt;An alternative cost function is the mean absolute error (MAE), where we can calculate the mean of the absolute values of the errors instead.&lt;/p&gt;

&lt;p&gt;One of the most commonly used regression cost functions is the mean squared error (MSE). It is calculated by summing all the squares of the errors and dividing by the number of examples times 2, a.k.a calculating the mean of the squared errors and dividing the whole thing by 2. Note: some variations of MSE do not divide by 2, but including it makes the downstream derivation calculus cleaner.&lt;/p&gt;

&lt;p&gt;Here is what the MSE cost function looks like in mathematical notation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PjSs_ahx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vt45ek4zo50collc7z8n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PjSs_ahx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vt45ek4zo50collc7z8n.png" alt="Image description" width="682" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In some versions of the function, the output is the cost, ‘J’.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualising Cost
&lt;/h2&gt;

&lt;p&gt;We can see the cost of a simple regression model by observing the difference between ŷ (value of y on the line) and y.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MFhoUtnd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x901smzlekgresffn8ax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MFhoUtnd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x901smzlekgresffn8ax.png" alt="Image description" width="800" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we learned in the last learning log, we want the line to fit the example data as well as possible. Intuitively, the line of best fit would collectively have the most minor errors across the example data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost Graph
&lt;/h2&gt;

&lt;p&gt;We use another graph, the cost graph, to visualise the cost across different parameter values. For simplicity, let’s say that our model only depends on one parameter, θ. We can plot a graph with θ on the x-axis and the cost, J, on the y-axis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XQC0mbMX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1v2qenm4vjebi3dwu9v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XQC0mbMX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1v2qenm4vjebi3dwu9v.png" alt="Image description" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we can visualise the cost for all values of θ. The best value of θ would be the one that yields the lowest cost — the value of θ at the bottom of the U shape. The further we move from the optimal value of θ, the higher the cost and the worse the model.&lt;/p&gt;

&lt;p&gt;As a general rule, the cost function graph for a regression problem will be U/bow/hammock-shaped. When there is only one parameter, we can visualise it in two dimensions, where it will look like a U shape. If there are two parameters, we can visualise it in three dimensions, and it will look more like a hammock.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PBFeryBu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srf9ydpmjtgkh0byl046.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PBFeryBu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srf9ydpmjtgkh0byl046.png" alt="Image description" width="495" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same trend follows as we add more parameters, but visualisation becomes increasingly tricky.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cost functions are critical in machine learning.&lt;/li&gt;
&lt;li&gt;We use cost functions when training a model to determine how good the model is.&lt;/li&gt;
&lt;li&gt;During training, we continuously calculate the cost with different parameter values to decide which parameter values yield the best model.&lt;/li&gt;
&lt;li&gt;Different machine learning methods use different cost functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disclosure
&lt;/h2&gt;

&lt;p&gt;I am taking Andrew Ng’s Machine Learning Specialization, and these learning logs contain some of what I learned from it. It’s a great course. I highly recommend it!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>AI Log #1: Machine Learning To Linear Regression</title>
      <dc:creator>Victoria Johnston</dc:creator>
      <pubDate>Mon, 13 Nov 2023 09:57:17 +0000</pubDate>
      <link>https://dev.to/ctrlaltvictoria/ai-log-1-machine-learning-to-linear-regression-2bl3</link>
      <guid>https://dev.to/ctrlaltvictoria/ai-log-1-machine-learning-to-linear-regression-2bl3</guid>
      <description>&lt;p&gt;I am an experienced software engineer diving into AI and machine learning. Are you also learning/interested in learning? Learn with me! I’m sharing my learning logs along the way.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I have already learnt basic machine learning, but I am starting this learning log from the beginning because I need a refresher 😅.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Log 1: Linear Regression
&lt;/h2&gt;

&lt;p&gt;My learning journey starts with Linear Regression because it is a fundamental building block for understanding machine learning.&lt;/p&gt;

&lt;p&gt;However, before diving into linear regression, I will jog my memory on machine learning, supervised learning, and regression models.&lt;/p&gt;

&lt;h2&gt;
  
  
  Machine Learning
&lt;/h2&gt;

&lt;p&gt;This definition was the one I found most helpful:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The use and development of computer systems that are able to learn and adapt without following explicit instructions, by using algorithms and statistical models to analyse and draw inferences from patterns in data — Bing&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The way I understand it:&lt;/p&gt;

&lt;p&gt;Machine Learning is when we use machines to determine an outcome without explicitly coding the logic that determines that outcome. Instead, we determine the outcome based on example data plus fancy math (algorithms and statistical models).&lt;/p&gt;

&lt;p&gt;Here is an example I will use throughout this learning log.&lt;/p&gt;

&lt;p&gt;Say I want to predict the amount of snow (centimetres) based on temperatures (degrees) below freezing.&lt;/p&gt;

&lt;p&gt;Non-machine learning way - I use some hard-coded logic: ‘The amount of snow will be the absolute number of the temperature. So if it’s -1°C, we get 1 cm of snow.’&lt;/p&gt;

&lt;p&gt;The non-machine learning method can, at times, be suitable. However, a clear set of rules cannot define all situations! Sometimes, finding patterns in data and using algorithms and statistical models is more appropriate, and this method would require machine learning. Unlike traditional programming, where we code all possible conditions and outcomes, machine learning algorithms learn to make decisions from data.&lt;/p&gt;

&lt;p&gt;Interestingly, the machine learning method is the solution that I think of instinctively if someone asks me how I would predict the amount of snow based on temperature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Machine Learning Lingo
&lt;/h2&gt;

&lt;p&gt;Input Features (x): The data we feed in, like temperature in degrees.&lt;br&gt;
Outcome Variable (y): What we’re predicting, like snowfall in centimetres.&lt;br&gt;
Predicted Outcome (ŷ): The outcome our model predicts.&lt;br&gt;
Model (f): The math that transforms ‘x’ into ‘ŷ’.&lt;br&gt;
Example Data: The historical data we use for training.&lt;br&gt;
We use ‘m’ to denote the amount of example data we have.&lt;br&gt;
We refer to a specific example data as x_i_ or y_i_, where &lt;em&gt;i&lt;/em&gt; is the example data’s index (or row).&lt;/p&gt;

&lt;p&gt;All together now: f(x) = ŷ&lt;/p&gt;

&lt;p&gt;I want to make something very clear:&lt;/p&gt;

&lt;p&gt;f(x_i_) will not necessarily be y_i_ because the statistical model we determine may not predict every example perfectly; in fact, this is unlikely to happen as we would need a model that fits all the points perfectly!&lt;/p&gt;

&lt;p&gt;For this reason, we have the symbol ŷ as the output of f(x); it is the predicted value and may differ from the actual value!&lt;/p&gt;

&lt;h2&gt;
  
  
  Supervised Learning
&lt;/h2&gt;

&lt;p&gt;Machine learning has two primary subcategories: supervised and unsupervised learning.&lt;/p&gt;

&lt;p&gt;Supervised learning is when the type of our desired outcome is known, a.k.a. we tell the model what we want it to predict.&lt;/p&gt;

&lt;p&gt;We tell the model, ‘Here — given these inputs, I want you to predict this outcome type.’&lt;/p&gt;

&lt;p&gt;The example data we train with must have input features and outcome variables.&lt;/p&gt;

&lt;p&gt;The snow/temperature example I used above is an example of supervised learning. In our example: ‘Here — given negative temperature in degrees, I want you to predict the centimetres of snow.’&lt;/p&gt;

&lt;p&gt;I will cover unsupervised learning in future diary entries, but out of curiosity, it is when we don’t tell the model the outcome we want. We give it data and ask it to find something interesting! The model finds patterns, and we can hopefully use the patterns to help us solve our problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regression
&lt;/h2&gt;

&lt;p&gt;Regression is a method of supervised learning that predicts a continuous numeric value. A continuous numeric value is any real value, like an integer or floating point number.&lt;/p&gt;

&lt;p&gt;For example, the number of centimetres of snow that the model can predict is 3.00cm.&lt;br&gt;
It can also be 2.33212cm.&lt;br&gt;
It can also be 1.2393cm.&lt;br&gt;
And so on.&lt;/p&gt;

&lt;p&gt;I am using my snow/temperature example above because it, too, can be a regression problem. The outcome we want? The number of centimetres of snow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linear Regression
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Linear regression is a supervised machine learning algorithm where the predicted output is continuous and has a constant slope. It’s used to predict values within a continuous range. — ML cheatsheet&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How I make sense of it:&lt;/p&gt;

&lt;p&gt;It falls under a regression method because its output is continuous.&lt;br&gt;
It is ‘linear’ because its model relies on a mathematical equation with a constant slope; it models a linear relationship between input and output.&lt;/p&gt;

&lt;p&gt;There are two main types: simple linear regression and multi-variable linear regression.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple linear regression.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is also known as univariable linear regression.&lt;br&gt;
Remember this straight-line equation from high school math that we used on 2D graphs (only with an x and y axis)?&lt;/p&gt;

&lt;p&gt;y = mx + c&lt;/p&gt;

&lt;p&gt;&lt;em&gt;x is the value on the x-axis, y is the value on the y-axis, m is the gradient (the slope), c is the intersect&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The equation for simple linear regression in machine learning is the same, but the gradient is ‘w’ for weight, and the intersect is ‘b’ for bias.&lt;/p&gt;

&lt;p&gt;f(x) = ŷ = wx + b&lt;/p&gt;

&lt;p&gt;The model function definition sometimes includes ‘w’ and ‘b’.&lt;/p&gt;

&lt;p&gt;f_wb_(x) = wx + b&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bBTr0gu6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sc4n9oi2g2ku7xpe1ao3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bBTr0gu6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sc4n9oi2g2ku7xpe1ao3.png" alt="Image description" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A simple linear regression equation could be&lt;br&gt;
f(x) = -1/2x&lt;br&gt;
If the temperature is -2 degrees, the predicted snow amount would be -1/2 * 2 = 1 cm.&lt;br&gt;
Another simple linear regression equation could be&lt;br&gt;
f(x) = -1/2x + 1&lt;br&gt;
If the temperature is -2 degrees, then the predicted amount of snow would be (-1/2 * 2) + 1 = 2 cm&lt;/p&gt;

&lt;p&gt;We are using math to predict the outcome! The logic is not explicitly declared or hard-coded. We use past examples to help us determine the equation we use to do it, and the equation’s weight and bias are likely to keep changing as we add more examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-variable linear regression.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Multi-variable linear regression is a linear regression that relies on multiple variables. Very often, our models will depend on more than one variable! Regarding our snow/temperature example, we will likely want to use more than temperature to determine the amount of snowfall. We could also use the altitude, humidity, etc.&lt;/p&gt;

&lt;p&gt;Multi-variable linear regression employs the same technique as linear regression but with a continuous slope across multiple dimensions.&lt;/p&gt;

&lt;p&gt;Here is what its equation looks like:&lt;/p&gt;

&lt;p&gt;f(x_1_, x_2_) = ŷ = w_1_x_1_ + w_2_x_2_ + b&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X92I8eGH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3sxq96g87s9a2w4sgbmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X92I8eGH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3sxq96g87s9a2w4sgbmg.png" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calculate the weights and bias.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instinctively, for our linear regression equation to be most effective, we would want it to fit our example data as closely as possible. We want to find values for our weights and biases that minimise the error between ŷ and the actual value of y across all our example data.&lt;/p&gt;

&lt;p&gt;We use a ‘cost function’ to quantify the difference across all example data; thus, we want to find the weights and biases that produce the minimal cost function output.&lt;/p&gt;

&lt;p&gt;We can then use a method known as ‘gradient descent’ to determine which weights and biases produce the minimal cost function output. In future learning logs, I will cover cost functions and gradient descent in more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Machine Learning = machines help us determine an outcome without explicitly coding the logic that determines that outcome.&lt;br&gt;
Supervised learning = subcategory of machine learning where we know the outcome type we want.&lt;br&gt;
Regression algorithm = A method of supervised learning where we predict a numeric outcome.&lt;br&gt;
Linear regression = A type of regression algorithm where the predicted output is continuous and has a constant slope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclosure
&lt;/h2&gt;

&lt;p&gt;I am taking Andrew Ng’s Machine Learning Specialization, and these learning logs contain some of what I learned from it. It’s a great course. I highly recommend it!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mastering Express.js Error Handling: From Custom Errors to Enhanced Error Responses</title>
      <dc:creator>Victoria Johnston</dc:creator>
      <pubDate>Fri, 18 Aug 2023 07:33:12 +0000</pubDate>
      <link>https://dev.to/ctrlaltvictoria/mastering-expressjs-error-handling-from-custom-errors-to-enhanced-error-responses-55p8</link>
      <guid>https://dev.to/ctrlaltvictoria/mastering-expressjs-error-handling-from-custom-errors-to-enhanced-error-responses-55p8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hello again, it’s Victoria here 👋&lt;/p&gt;

&lt;p&gt;Let’s be real. In software development, errors are a given! It’s not about avoiding errors, but rather how you manage them that truly separates a well-constructed piece of software from the rest.&lt;/p&gt;

&lt;p&gt;Today, we’re going to delve into the world of error handling within Express.js, a versatile and minimalist web application framework for Node.js. We’ll go from understanding how Express.js processes errors, to creating and applying custom errors, all while enhancing the quality of your code!&lt;/p&gt;

&lt;h2&gt;
  
  
  I. Understanding Error Handling in Express.js
&lt;/h2&gt;

&lt;p&gt;Express.js comes equipped with built-in error handling mechanisms. However, to leverage these effectively, it’s crucial to comprehend how errors propagate within Express.&lt;/p&gt;

&lt;p&gt;Consider a classic Express.js middleware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/users', async (req, res, next) =&amp;gt; { 
  try { 
    const users = awaitgetUsersFromDatabase();
    res.json(users); 
  } catch (error) { 
    next(error); 
  } 
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this scenario, if getUsersFromDatabase() throws an error, the catch block captures it and passes it to next(). This handoff facilitates the error's journey down the middleware stack until it encounters our dedicated error handling middleware. By delegating error handling to specific middleware, we ensure consistency across our routes and sidestep code duplication. &lt;a href="https://expressjs.com/en/guide/error-handling.html"&gt;This insightful article&lt;/a&gt; from the Express.js guide offers a deeper look.&lt;/p&gt;

&lt;h2&gt;
  
  
  II. Custom Error Handling Middleware in Express.js
&lt;/h2&gt;

&lt;p&gt;Error handling middleware in Express.js resembles other middleware, save for one critical difference: it accepts four arguments ((err, req, res, next)) instead of three. Here's a rudimentary example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use((err, req, res, next) =&amp;gt; { 
  console.error(err); 
  res.status(500).send('An error occurred!'); 
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this instance, all errors, irrespective of their type or severity, receive the same bland response. To make this more dynamic, we need to generate and employ custom errors.&lt;/p&gt;

&lt;p&gt;This basic error handling middleware does its job, but it lacks usability! Each error triggers the same monotonous response, “An error occurred!” Along with the error status code, this message makes it challenging to identify the root cause of the issue. We might see the original error logged, but without context, debugging can be cumbersome. To inject expressiveness and utility into our errors, let’s craft some custom ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  III. Creating Custom Errors
&lt;/h2&gt;

&lt;p&gt;Constructing custom errors not only imbues our errors with greater context but also streamlines the process of identifying and resolving them.&lt;/p&gt;

&lt;p&gt;Let’s fashion a DatabaseError and a ValidationError class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DatabaseError extends Error { 
  constructor(message) { 
    super(message); 
    this.name = 'DatabaseError'; 
    this.statusCode = 500; 
  } 
} 

class ValidationError extends Error {
  constructor(message) { 
    super(message); 
    this.name = 'ValidationError'; 
    this.statusCode = 400; 
  } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These classes augment the native Error class and incorporate a statusCode property. We'll harness this property when formulating error responses. If you're wondering about the significance of creating custom errors, &lt;a href="https://javascript.info/custom-errors"&gt;this comprehensive write-up&lt;/a&gt; provides a thorough explanation.&lt;/p&gt;

&lt;h2&gt;
  
  
  IV. Using Custom Errors
&lt;/h2&gt;

&lt;p&gt;With our custom errors primed and ready, let’s modify our earlier middleware example to utilize them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/users', async (req, res, next) =&amp;gt; { 
  try { 
    const users = awaitgetUsersFromDatabase(); 
    res.json(users); 
  } catch (error) { 
    if (error instanceofSomeDatabaseSpecificError) { 
      next(new DatabaseError('Failed to retrieve users from database!')); 
    } else { 
      next(error); 
    } 
  } 
 });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when we encounter a database-specific error, we create a new instance of our DatabaseError and pass it to next(). Other types of errors continue to be passed as-is.&lt;/p&gt;

&lt;h2&gt;
  
  
  V. Customizing Error Responses
&lt;/h2&gt;

&lt;p&gt;Armed with our custom errors, it’s time to polish our error handling middleware to yield appropriate responses based on the error type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use((err, req, res, next) =&amp;gt; { 
  if (err instanceof DatabaseError || err instanceof ValidationError) { 
    console.error(`${err.name}: ${err.message}`);
    res.status(err.statusCode).json({ error: err.message }); 
  } else { 
    console.error(err); 
    res.status(500).send('An error occurred!'); 
  } 
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  VI. A Comprehensive Example
&lt;/h2&gt;

&lt;p&gt;Let’s consolidate all these techniques into a single application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DatabaseError extends Error { /* ... */ }
class ValidationError extends Error { /* ... */ }

const getUsersFromDatabase = async () =&amp;gt; { /* ... */ };
const validateRequest = req =&amp;gt; { /* ... */ };

app.get('/users', async (req, res, next) =&amp;gt; { 
  try {
    validateRequest(req);
    const users = await getUsersFromDatabase();
    res.json(users); 
  } catch (error) { 
    if (error instanceof SomeDatabaseSpecificError) { 
      next(newDatabaseError('Failed to retrieve users from database!')); 
    } else if (error instanceof SomeValidationSpecificError) { 
      next(new ValidationError('Invalid request!')); 
    } else {
      next(error); 
    } 
  } 
});

app.use((err, req, res, next) =&amp;gt; { /* ... */ });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Error handling is an art that demands conscious practice to perfect.&lt;/p&gt;

&lt;p&gt;In this article, we’ve examined how to gracefully manage errors in Express.js. By employing custom error classes and designing an Express.js error handling middleware that leverages them, we can generate expressive, context-aware error responses. This approach not only simplifies the user experience but also eases our debugging process.&lt;/p&gt;

&lt;p&gt;Until next time, fellow programmers!&lt;/p&gt;

&lt;p&gt;For more coding tutorials, please subscribe to my YouTube channel: &lt;a href="https://www.youtube.com/@CtrlAltVictoria"&gt;https://www.youtube.com/@CtrlAltVictoria&lt;/a&gt; and Twitter &lt;a href="https://twitter.com/ctrlaltvictoria"&gt;https://twitter.com/ctrlaltvictoria&lt;/a&gt; 💕🚀&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Backend Error Handling: Practical Tips from a Startup CTO</title>
      <dc:creator>Victoria Johnston</dc:creator>
      <pubDate>Thu, 17 Aug 2023 13:48:04 +0000</pubDate>
      <link>https://dev.to/ctrlaltvictoria/backend-error-handling-practical-tips-from-a-startup-cto-h6</link>
      <guid>https://dev.to/ctrlaltvictoria/backend-error-handling-practical-tips-from-a-startup-cto-h6</guid>
      <description>&lt;p&gt;Hey there! I’m the CTO of a web3 startup, and before that, I was a senior engineer working on infrastructure and full-stack systems at Google. I’ve learnt a few things along the way about coding, and today, I’m excited to dive into something that we often overlook until it’s too late: error handling and logging.&lt;/p&gt;

&lt;p&gt;When I first jumped ship from Google to start my own venture, it was all about moving fast, hacking stuff together, and making things work. One thing that I initially put on the back burner was implementing a robust error handling and logging system. After all, why waste time preparing for errors when you can just code to avoid them, right? Well, fast forward to countless hours spent debugging and troubleshooting, and I’ve learnt my lesson.&lt;/p&gt;

&lt;p&gt;In this post, I’ll share with you some practical tips and best practices on error handling and logging that I’ve picked up, alongside examples from my own experiences. If I knew back then what I know now, I would have set up error handling right from the start. But as they say, hindsight is 20/20.&lt;/p&gt;

&lt;p&gt;Let’s get into it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is Error Handling Important?
&lt;/h2&gt;

&lt;p&gt;Before we dive into the practicalities, let’s take a moment to consider why error handling is important. Well, for starters, errors are inevitable. No matter how careful you are, how experienced your team is, or how thorough your QA process might be, things can and will go wrong. That’s just the reality of software development.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Debugging: A proper error handling and logging system can make debugging significantly easier and faster. By having detailed error messages and logs, you can trace back the series of events that led to the error, making it easier to reproduce and fix.&lt;/li&gt;
&lt;li&gt;Resilience: Handling errors appropriately can make your system more resilient. Instead of crashing the whole system, a well-placed try/catch can contain the error and allow the system to recover and continue running.&lt;/li&gt;
&lt;li&gt;User Experience: Users don’t like seeing raw error messages or, worse, having the app crash on them. Good error handling can allow you to provide user-friendly error messages and fallbacks, leading to a better user experience.&lt;/li&gt;
&lt;li&gt;Security: Detailed error messages can reveal more about your system than you might want. You can avoid potential security risks by controlling what gets revealed in an error message.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Getting Hands-on with Error Handling
&lt;/h2&gt;

&lt;p&gt;Now, let’s get down to business. How do you handle errors effectively in a backend environment? There’s no one-size-fits-all answer, as it heavily depends on your tech stack, team size, project complexity, and a dozen other factors. That being said, there are some universally good practices to adhere to.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Centralized Error Handling
&lt;/h2&gt;

&lt;p&gt;It’s a good practice to centralize your error handling as much as possible. This approach simplifies code readability and maintainability and ensures consistency. If you’re using a framework like Express.js, you can use middleware for this.&lt;/p&gt;

&lt;p&gt;Here’s a simplified example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use((err, req, res, next) =&amp;gt; {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This error-handling middleware would catch errors that occur in your route handlers and send a generic response. But what about sending more user-friendly messages or dealing with different error types? That’s where custom error classes come in.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Custom Error Classes
&lt;/h2&gt;

&lt;p&gt;Custom error classes in JavaScript (or whatever language you’re using) allow you to create specific error types, each potentially having its own error handling. Here’s a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
    this.statusCode = 400;
  }
}

class DatabaseError extends Error {
  constructor(message) {
    super(message);
    this.name = "DatabaseError";
    this.statusCode = 500;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these classes, you can throw specific errors in your code, and your error-handling middleware can behave differently depending on the error type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use((err, req, res, next) =&amp;gt; {
  if (err instanceof ValidationError) {
    res.status(err.statusCode).send(err.message);
  } else if (err instanceof DatabaseError) {
    res.status(err.statusCode).send('A database error occurred');
  } else {
    res.status(500).send('Something broke!');
  }
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are just simplified examples. In a real-world scenario, you might log the errors to an external service, handle more error types, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Proper use of Try/Catch
&lt;/h2&gt;

&lt;p&gt;Try/catch blocks are your bread and butter for catching errors as they occur. It’s important only to catch errors that you can handle. If you can’t handle the error (for example, you don’t know why it would occur), it’s usually better to let it bubble up to the global error handler.&lt;/p&gt;

&lt;p&gt;Here’s a good use of a try/catch block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try {
  const user = await getUserFromDb(userId);
} catch (err) {
  if (err instanceof NotFoundError) {
    // We know why this error occurred and we can handle it
    return createNewUser(userId);
  }
  // We can't handle any other errors, rethrow them
  throw err;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we’re only catching a specific error that we know might happen and that we can handle. Any other errors get rethrown and can be handled by our global error handler.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Importance of Good Logging
&lt;/h2&gt;

&lt;p&gt;Now, while error handling is about dealing with errors as they occur, logging is about recording what happened so you can look back on it in the future. This can be extremely helpful when debugging.&lt;/p&gt;

&lt;p&gt;There are several things you should consider when implementing logging:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What to log: You want to log any information that might be useful for debugging. This can include input parameters, output results, and any intermediate variables. However, be aware of privacy and security issues. Never log sensitive information like passwords.&lt;/li&gt;
&lt;li&gt;When to log: Ideally, you want to log as much as possible, but there’s always a trade-off between detail and performance/storage. Consider using different log levels (error, warning, info, debug) to control this.&lt;/li&gt;
&lt;li&gt;Where to log: For local development, logging into the console might be sufficient. But for a production system, you’ll want to use a logging service that can handle large volumes of logs, manage retention policies, and provide search and analysis tools. This could be a cloud service like Google’s Cloud Monitoring, a self-hosted solution like Elasticsearch, or a log management service like Loggly or Datadog.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s an example of how you might log a function’s input and output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function add(a, b) {
  console.log(`add was called with ${a} and ${b}`);
  const result = a + b;
  console.log(`add result is ${result}`);
  return result;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a production scenario, you’d replace console.log with a call to your logging library or service, and you might add more detail (like a timestamp or the name of the function).&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I hope this post has given you a practical insight into error handling and logging in backend development. If there’s one thing I want you to take away from this, it’s that error handling and logging are not an afterthought. They are an integral part of your code that can save you countless hours of debugging and many headaches. So, invest the time upfront to set up a good error handling and logging system. You’ll thank yourself later!&lt;/p&gt;

&lt;p&gt;Stay tuned for future posts where I plan to delve deeper into some of these topics. If you have any questions, feel free to drop a comment or reach out to me. Happy coding!&lt;/p&gt;

&lt;p&gt;For more coding tutorials, please subscribe to my YouTube channel: &lt;a href="https://www.youtube.com/@CtrlAltVictoria"&gt;https://www.youtube.com/@CtrlAltVictoria&lt;/a&gt; and Twitter &lt;a href="https://twitter.com/ctrlaltvictoria"&gt;https://twitter.com/ctrlaltvictoria&lt;/a&gt; 💕🚀&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>node</category>
    </item>
  </channel>
</rss>
