AI

Stochastic Gradient Descent: Math and Python Code

[ad_1]

1.1: What’s Gradient Descent

Picture by DALL-E-2

In machine studying , Gradient Descent is a star participant. It’s an optimization algorithm used to attenuate a perform by iteratively shifting in the direction of the steepest descent as outlined by the damaging of the gradient. Like within the image, think about you’re on the high of a mountain, and your aim is to succeed in the bottom level. Gradient Descent helps you discover one of the best path down the hill.

The great thing about Gradient Descent is its simplicity and magnificence. Right here’s the way it works, you begin with a random level on the perform you’re making an attempt to attenuate, for instance a random place to begin on the mountain. Then, you calculate the gradient (slope) of the perform at that time. Within the mountain analogy, that is like wanting round you to search out the steepest slope. As soon as you realize the course, you’re taking a step downhill in that course, and you then calculate the gradient once more. Repeat this course of till you attain the underside.

The dimensions of every step is decided by the training fee. Nonetheless, if the training fee is just too small, it would take a very long time to succeed in the underside. If it’s too giant, you would possibly overshoot the bottom level. Discovering the precise steadiness is vital to the success of the algorithm.

One of the interesting elements of Gradient Descent is its generality. It may be utilized to nearly any perform, particularly these the place an analytical resolution just isn’t possible. This makes it extremely versatile in fixing numerous forms of issues in machine studying, from easy linear regression to complicated neural networks.

1.2: The ‘Stochastic’ in Stochastic Gradient Descent

Stochastic Gradient Descent (SGD) provides a twist to the standard gradient descent strategy. The time period ‘stochastic’ refers to a system or course of that’s linked with a random likelihood. Due to this fact, this randomness is launched in the way in which the gradient is calculated, which considerably alters its conduct and effectivity in comparison with normal gradient descent.

In conventional batch gradient descent, you calculate the gradient of the loss perform with respect to the parameters for the whole coaching set. As you may think about, for giant datasets, this may be fairly computationally intensive and time-consuming. That is the place SGD comes into play. As a substitute of utilizing the whole dataset to calculate the gradient, SGD randomly selects only one information level (or a number of information factors) to compute the gradient in every iteration.

Consider this course of as when you had been once more descending a mountain, however this time in thick fog with restricted visibility. Fairly than viewing the whole panorama to resolve the next step, you make your resolution primarily based on the place your foot lands subsequent. This step is small and random, nevertheless it’s repeated many instances, every time adjusting your path barely in response to the fast terrain beneath your toes.

This stochastic nature of the algorithm offers a number of advantages:

  • Pace: Through the use of solely a small subset of knowledge at a time, SGD could make speedy progress in decreasing the loss, particularly for giant datasets.
  • Escape from Native Minima: The randomness helps SGD to doubtlessly escape native minima, a typical drawback in complicated optimization issues.
  • On-line Studying: SGD is well-suited for on-line studying, the place the mannequin must be up to date as new information is available in, because of its skill to replace the mannequin incrementally.

Nonetheless, the stochastic nature additionally introduces variability within the path to convergence. The algorithm doesn’t easily descend in the direction of the minimal; quite, it takes a extra zigzag path, which may typically make the convergence course of seem erratic.

2.1: The Algorithm Defined

Stochastic Gradient Descent (SGD) would possibly sound complicated, however its algorithm is kind of simple when damaged down. Right here’s a step-by-step information to understanding how SGD works:

Initialization (Step 1)
First, you initialize the parameters (weights) of your mannequin. This may be carried out randomly or by another initialization method. The place to begin for SGD is essential because it influences the trail the algorithm will take.

Random Choice (Step 2)
In every iteration of the coaching course of, SGD randomly selects a single information level (or a small batch of knowledge factors) from the whole dataset. This randomness is what makes it ‘stochastic’.

Compute the Gradient (Step 3)
Calculate the gradient of the loss perform, however just for the randomly chosen information level(s). The gradient is a vector that factors within the course of the steepest enhance of the loss perform. Within the context of SGD, it tells you the best way to tweak the parameters to make the mannequin extra correct for that exact information level.

Gradient System

Right here, ∇θJ(θ) represents the gradient of the loss perform J(θ) with respect to the parameters θ. This gradient is a vector of partial derivatives, the place every element of the vector is the partial spinoff of the loss perform with respect to the corresponding parameter in θ.

Replace the Parameters (Step 4)
Modify the mannequin parameters in the wrong way of the gradient. Right here’s the place the training fee η performs an important position. The method for updating every parameter is:

the place:

  • θnew​ represents the up to date parameters.
  • θprevious​ represents the present parameters earlier than the replace.
  • η is the training fee, a constructive scalar figuring out the dimensions of the step within the course of the damaging gradient.
  • θJ(θ) is the gradient of the loss perform J(θ) with respect to the parameters θ.

The training fee determines the dimensions of the steps you’re taking in the direction of the minimal. If it’s too small, the algorithm might be gradual; if it’s too giant, you would possibly overshoot the minimal.

Repeat till convergence (Step 5)
Repeat steps 2 to 4 for a set variety of iterations or till the mannequin efficiency stops bettering. Every iteration offers a barely up to date mannequin.
Ideally, after many iterations, SGD converges to a set of parameters that reduce the loss perform, though because of its stochastic nature, the trail to convergence just isn’t as easy and will oscillate across the minimal.

2.2: Understanding Studying Charge

One of the essential hyperparameters within the Stochastic Gradient Descent (SGD) algorithm is the training fee. This parameter can considerably influence the efficiency and convergence of the mannequin. Understanding and choosing the proper studying fee is an important step in successfully using SGD.

What’s Studying Charge?
At this level you must have an thought of what studying fee is, however let’s higher outline it for readability. The training fee in SGD determines the dimensions of the steps the algorithm takes in the direction of the minimal of the loss perform. It’s a scalar that scales the gradient, dictating how a lot the weights within the mannequin ought to be adjusted throughout every replace. In case you visualize the loss perform as a valley, the training fee decides how huge a step you’re taking with every iteration as you stroll down the valley.

Too Excessive Studying Charge
If the training fee is just too excessive, the steps taken is perhaps too giant. This will result in overshooting the minimal, inflicting the algorithm to diverge or oscillate wildly with out discovering a secure level.
Consider it as taking leaps within the valley and presumably leaping over the bottom level forwards and backwards.

Too Low Studying Charge
Alternatively, a really low studying fee results in extraordinarily small steps. Whereas this would possibly sound secure, it considerably slows down the convergence course of.
In a worst-case situation, the algorithm would possibly get caught in an area minimal and even cease bettering earlier than reaching the minimal.
Think about shifting so slowly down the valley that you simply both get caught or it takes an impractically very long time to succeed in the underside.

Discovering the Proper Steadiness
The best studying fee is neither too excessive nor too low however strikes a steadiness, permitting the algorithm to converge effectively to the worldwide minimal.
Usually, the training fee is chosen by means of experimentation and is usually set to lower over time. This strategy is known as studying fee annealing or scheduling.

Studying Charge Scheduling
Studying fee scheduling includes adjusting the training fee over time. Widespread methods embody:

  • Time-Primarily based Decay: The training fee decreases over every replace.
  • Step Decay: Scale back the training fee by some issue after a sure variety of epochs.
  • Exponential Decay: Lower the training fee exponentially.
  • Adaptive Studying Charge: Strategies like AdaGrad, RMSProp, and Adam modify the training fee routinely throughout coaching.

3.1: Implementing SGD in Machine Studying Fashions

Hyperlink to the complete code (Jupyter Pocket book): https://github.com/cristianleoo/models-from-scratch-python/blob/main/sgd.ipynb

Implementing Stochastic Gradient Descent (SGD) in machine studying fashions is a sensible step that brings the theoretical elements of the algorithm into real-world utility. This part will information you thru the fundamental implementation of SGD and supply ideas for integrating it into machine studying workflows.

Now let’s contemplate a easy case of SGD utilized to Linear Regression:

class SGDRegressor:
def __init__(self, learning_rate=0.01, epochs=100, batch_size=1, reg=None, reg_param=0.0):
"""
Constructor for the SGDRegressor.

Parameters:
learning_rate (float): The step measurement utilized in every replace.
epochs (int): Variety of passes over the coaching dataset.
batch_size (int): Variety of samples for use in every batch.
reg (str): Kind of regularization ('l1' or 'l2'); None if no regularization.
reg_param (float): Regularization parameter.

The weights and bias are initialized as None and might be set in the course of the match technique.
"""
self.learning_rate = learning_rate
self.epochs = epochs
self.batch_size = batch_size
self.reg = reg
self.reg_param = reg_param
self.weights = None
self.bias = None

def match(self, X, y):
"""
Matches the SGDRegressor to the coaching information.

Parameters:
X (numpy.ndarray): Coaching information, form (m_samples, n_features).
y (numpy.ndarray): Goal values, form (m_samples,).

This technique initializes the weights and bias, after which updates them over a variety of epochs.
"""
m, n = X.form # m is variety of samples, n is variety of options
self.weights = np.zeros(n)
self.bias = 0

for _ in vary(self.epochs):
indices = np.random.permutation(m)
X_shuffled = X[indices]
y_shuffled = y[indices]

for i in vary(0, m, self.batch_size):
X_batch = X_shuffled[i:i+self.batch_size]
y_batch = y_shuffled[i:i+self.batch_size]

gradient_w = -2 * np.dot(X_batch.T, (y_batch - np.dot(X_batch, self.weights) - self.bias)) / self.batch_size
gradient_b = -2 * np.sum(y_batch - np.dot(X_batch, self.weights) - self.bias) / self.batch_size

if self.reg == 'l1':
gradient_w += self.reg_param * np.signal(self.weights)
elif self.reg == 'l2':
gradient_w += self.reg_param * self.weights

self.weights -= self.learning_rate * gradient_w
self.bias -= self.learning_rate * gradient_b

def predict(self, X):
"""
Predicts the goal values utilizing the linear mannequin.

Parameters:
X (numpy.ndarray): Information for which to foretell goal values.

Returns:
numpy.ndarray: Predicted goal values.
"""
return np.dot(X, self.weights) + self.bias

def compute_loss(self, X, y):
"""
Computes the lack of the mannequin.

Parameters:
X (numpy.ndarray): The enter information.
y (numpy.ndarray): The true goal values.

Returns:
float: The computed loss worth.
"""
return (np.imply((y - self.predict(X)) ** 2) + self._get_regularization_loss()) ** 0.5

def _get_regularization_loss(self):
"""
Computes the regularization loss primarily based on the regularization sort.

Returns:
float: The regularization loss.
"""
if self.reg == 'l1':
return self.reg_param * np.sum(np.abs(self.weights))
elif self.reg == 'l2':
return self.reg_param * np.sum(self.weights ** 2)
else:
return 0

def get_weights(self):
"""
Returns the weights of the mannequin.

Returns:
numpy.ndarray: The weights of the linear mannequin.
"""
return self.weights

Let’s break it down into smaller steps:

Initialization (Step 1)

def __init__(self, learning_rate=0.01, epochs=100, batch_size=1, reg=None, reg_param=0.0):
self.learning_rate = learning_rate
self.epochs = epochs
self.batch_size = batch_size
self.reg = reg
self.reg_param = reg_param
self.weights = None
self.bias = None

The constructor (__init__ technique) initializes the SGDRegressor with a number of parameters:

  • learning_rate: The step measurement utilized in updating the mannequin.
  • epochs: The variety of passes over the whole dataset.
  • batch_size: The variety of samples utilized in every batch for SGD.
  • reg: The kind of regularization (both ‘l1’ or ‘l2’; None if no regularization is used).
  • reg_param: The regularization parameter.
  • weights and bias are set to None initially and might be initialized within the match technique.

Match the Mannequin(Step 2)

def match(self, X, y):
m, n = X.form # m is variety of samples, n is variety of options
self.weights = np.zeros(n)
self.bias = 0

for _ in vary(self.epochs):
indices = np.random.permutation(m)
X_shuffled = X[indices]
y_shuffled = y[indices]

for i in vary(0, m, self.batch_size):
X_batch = X_shuffled[i:i+self.batch_size]
y_batch = y_shuffled[i:i+self.batch_size]

gradient_w = -2 * np.dot(X_batch.T, (y_batch - np.dot(X_batch, self.weights) - self.bias)) / self.batch_size
gradient_b = -2 * np.sum(y_batch - np.dot(X_batch, self.weights) - self.bias) / self.batch_size

if self.reg == 'l1':
gradient_w += self.reg_param * np.signal(self.weights)
elif self.reg == 'l2':
gradient_w += self.reg_param * self.weights

self.weights -= self.learning_rate * gradient_w
self.bias -= self.learning_rate * gradient_b

This technique suits the mannequin to the coaching information. It begins by initializing weights as a zero vector of size n (variety of options) and bias to zero. The mannequin’s parameters are up to date over a variety of epochs by means of SGD.

Random Choice and Batches(Step 3)

for _ in vary(self.epochs):
indices = np.random.permutation(m)
X_shuffled = X[indices]
y_shuffled = y[indices]

In every epoch, the info is shuffled, and batches are created to replace the mannequin parameters utilizing SGD.

Compute the Gradient and Replace the parameters (Step 4)

gradient_w = -2 * np.dot(X_batch.T, (y_batch - np.dot(X_batch, self.weights) - self.bias)) / self.batch_size
gradient_b = -2 * np.sum(y_batch - np.dot(X_batch, self.weights) - self.bias) / self.batch_size

Gradients for weights and bias are computed in every batch. These are then used to replace the mannequin’s weights and bias. If regularization is used, it’s additionally included within the gradient calculation.

Repeat and converge (Step 5)

def predict(self, X):

return np.dot(X, self.weights) + self.bias

The predict technique calculates the expected goal values utilizing the discovered linear mannequin.

Compute Loss (Step 6)

def compute_loss(self, X, y):
return (np.imply((y - self.predict(X)) ** 2) + self._get_regularization_loss()) ** 0.5

It calculates the imply squared error between the expected values and the precise goal values y. Moreover, it incorporates the regularization loss if regularization is specified.

Regularization Loss Calculation (Step 7)

def _get_regularization_loss(self):
if self.reg == 'l1':
return self.reg_param * np.sum(np.abs(self.weights))
elif self.reg == 'l2':
return self.reg_param * np.sum(self.weights ** 2)
else:
return 0

This personal technique computes the regularization loss primarily based on the kind of regularization (l1 or l2) and the regularization parameter. This loss is added to the principle loss perform to penalize giant weights, thereby avoiding overfitting.

3.2: SGD in Sci-kit Study and Tensorflow

Now, whereas the code above may be very helpful for instructional functions, information scientists undoubtedly don’t use it every day. Certainly, we will instantly name SGD with few traces of code from fashionable libraries resembling scikit study (machine studying) or tensorflow (deep studying).

SGD for linear regression in scikit-learn

from sklearn.linear_model import SGDRegressor

# Create and match the mannequin
mannequin = SGDRegressor(max_iter=1000)
mannequin.match(X, y)

# Making predictions
predictions = mannequin.predict(X)

SGD regressor is instantly referred to as from sklearn library, and follows the identical construction of different algorithms in the identical library.
The parameter ‘max_iter’ is the variety of epochs (rounds). By specifying max_iter to 1000 we’ll make the algorithm replace the linear regression weights and bias 1000 instances.

Neural Community with SGD optimization in Tensorflow

import tensorflow as tf
from tensorflow.keras.fashions import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import SGD

# Create a easy neural community mannequin
mannequin = Sequential([
Dense(64, activation='relu', input_shape=(X_train.shape[1],)),
Dense(1)
])

sgd = SGD(learning_rate=0.01)

# Compile the mannequin with SGD optimizer
mannequin.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])

# Prepare the mannequin
mannequin.match(X, y, epochs=10)

On this code we’re defining a Neural Community with one Dense Layer and 64 nodes. Nonetheless, apart from the specifics of the neural community, right here we’re once more calling SGD with simply two traces of code:

from tensorflow.keras.optimizers import SGD
sgd = SGD(learning_rate=0.01)

4.1: Why Select SGD?

Effectivity with Massive Datasets:
Scalability
: One of many major benefits of SGD is its effectivity in dealing with large-scale information. Because it updates parameters utilizing solely a single information level (or a small batch) at a time, it’s a lot much less memory-intensive than algorithms requiring the whole dataset for every replace.
Pace: By steadily updating the mannequin parameters, SGD can converge extra rapidly to resolution, particularly in circumstances the place the dataset is gigantic.

Flexibility and Adaptability:
On-line Studying
: SGD’s skill to replace the mannequin incrementally makes it well-suited for on-line studying, the place the mannequin must adapt constantly as new information arrives.
Dealing with Non-Static Datasets: For datasets that change over time, SGD’s incremental replace strategy can modify to those adjustments extra successfully than batch strategies.

Overcoming Challenges of Native Minima:
The stochastic nature of SGD helps it to doubtlessly escape native minima, a big problem in lots of optimization issues. The random fluctuations enable the algorithm to discover a broader vary of the answer house.

Common Applicability:
SGD may be utilized to a variety of issues and isn’t restricted to particular forms of fashions. This common applicability makes it a flexible device within the machine studying toolbox.

Simplicity and Ease of Implementation:
Regardless of its effectiveness, SGD stays comparatively easy to grasp and implement. This ease of use is especially interesting for these new to machine studying.

Improved Generalization:
By updating the mannequin steadily with a excessive diploma of variance, SGD can usually result in fashions that generalize higher on unseen information. It is because the algorithm is much less more likely to overfit to the noise within the coaching information.

Compatibility with Superior Methods:
SGD is suitable with quite a lot of enhancements and extensions, resembling momentum, studying fee scheduling, and adaptive studying fee strategies like Adam, which additional enhance its efficiency and flexibility.

4.2: Overcoming Challenges in SGD

Whereas Stochastic Gradient Descent (SGD) is a strong and versatile optimization algorithm, it comes with its personal set of challenges. Understanding these hurdles and realizing the best way to overcome them can enormously improve the efficiency and reliability of SGD in sensible functions.

Selecting the Proper Studying Charge
Choosing an applicable studying fee is essential for SGD. If it’s too excessive, the algorithm might diverge; if it’s too low, it would take too lengthy to converge or get caught in native minima.
Use a studying fee schedule or adaptive studying fee strategies. Methods like studying fee annealing, the place the training fee decreases over time, can assist strike the precise steadiness.

Coping with Noisy Updates
The stochastic nature of SGD results in noisy updates, which may trigger the algorithm to be much less secure and take longer to converge.
Implement mini-batch SGD, the place the gradient is computed on a small subset of the info quite than a single information level. This strategy can scale back the variance within the updates.

Threat of Native Minima and Saddle Factors
In complicated fashions, SGD can get caught in native minima or saddle factors, particularly in high-dimensional areas.
Use methods like momentum or Nesterov accelerated gradients to assist the algorithm navigate by means of flat areas and escape native minima.

Sensitivity to Characteristic Scaling
SGD is delicate to the size of the options, and having options on completely different scales could make the optimization course of inefficient.
Normalize or standardize the enter options in order that they’re on an identical scale. This observe can considerably enhance the efficiency of SGD.

Hyperparameter Tuning
SGD requires cautious tuning of hyperparameters, not simply the training fee but in addition parameters like momentum and the dimensions of the mini-batch.
Make the most of grid search, random search, or extra superior strategies like Bayesian optimization to search out the optimum set of hyperparameters.

Overfitting
Like every machine studying algorithm, there’s a threat of overfitting, the place the mannequin performs properly on coaching information however poorly on unseen information.
Use regularization methods resembling L1 or L2 regularization, and validate the mannequin utilizing a hold-out set or cross-validation.

5.1: Variants of SGD

Stochastic Gradient Descent (SGD) has a number of variants, every designed to deal with particular challenges or to enhance upon the fundamental SGD algorithm in sure elements. These variants improve SGD’s effectivity, stability, and convergence fee. Right here’s a take a look at a number of the key variants:

Mini-Batch Gradient Descent
This can be a mix of batch gradient descent and stochastic gradient descent. As a substitute of utilizing the whole dataset (as in batch GD) or a single pattern (as in SGD), it makes use of a mini-batch of samples.
It reduces the variance of the parameter updates, which may result in extra secure convergence. It might additionally benefit from optimized matrix operations, which makes it extra computationally environment friendly.

Momentum SGD
Momentum is an strategy that helps speed up SGD within the related course and dampens oscillations. It does this by including a fraction of the earlier replace vector to the present replace.
It helps in sooner convergence and reduces oscillations. It’s significantly helpful for navigating the ravines of the price perform, the place the floor curves rather more steeply in a single dimension than in one other.

Nesterov Accelerated Gradient (NAG)
A variant of momentum SGD, Nesterov momentum is a way that makes a extra knowledgeable replace by calculating the gradient of the longer term approximate place of the parameters.
It might velocity up convergence and enhance the efficiency of the algorithm, significantly within the context of convex features.

Adaptive Gradient (Adagrad)
Adagrad adapts the training fee to every parameter, giving parameters which are up to date extra steadily a decrease studying fee.
It’s significantly helpful for coping with sparse information and is well-suited for issues the place information is scarce or options have very completely different frequencies.

RMSprop
RMSprop (Root Imply Sq. Propagation) modifies Adagrad to deal with its radically diminishing studying charges. It makes use of a shifting common of squared gradients to normalize the gradient.
It really works properly in on-line and non-stationary settings and has been discovered to be an efficient and sensible optimization algorithm for neural networks.

Adam (Adaptive Second Estimation)
Adam combines concepts from each Momentum and RMSprop. It computes adaptive studying charges for every parameter.
Adam is usually thought-about as a default optimizer because of its effectiveness in a variety of functions. It’s significantly good at fixing issues with noisy or sparse gradients.

Every of those variants has its personal strengths and is suited to particular forms of issues. Their improvement displays the continued effort within the machine studying neighborhood to refine and improve optimization algorithms to attain higher and sooner outcomes. Understanding these variants and their applicable functions is essential for anybody seeking to delve deeper into machine studying optimization methods.

5.2: Way forward for SGD

As we delve into the way forward for Stochastic Gradient Descent (SGD), it’s clear that this algorithm continues to evolve, reflecting the dynamic and modern nature of the sector of machine studying. The continuing analysis and improvement in SGD give attention to enhancing its effectivity, accuracy, and applicability to a broader vary of issues. Listed below are some key areas the place we will anticipate to see important developments:

Automated Hyperparameter Tuning
There’s growing curiosity in automating the method of choosing optimum hyperparameters, together with the training fee, batch measurement, and different SGD-specific parameters.
This automation might considerably scale back the time and experience required to successfully deploy SGD, making it extra accessible and environment friendly.

Integration with Superior Fashions
As machine studying fashions develop into extra complicated, particularly with the expansion of deep studying, there’s a must adapt and optimize SGD for these superior architectures.
Enhanced variations of SGD which are tailor-made for complicated fashions can result in sooner coaching instances and improved mannequin efficiency.

Adapting to Non-Convex Issues
Analysis is specializing in making SGD more practical for non-convex optimization issues, that are prevalent in real-world functions.
Improved methods for coping with non-convex landscapes might result in extra strong and dependable fashions in areas like pure language processing and laptop imaginative and prescient.

Decentralized and Distributed SGD
With the rise in distributed computing and the necessity for privacy-preserving strategies, there’s a push in the direction of decentralized SGD algorithms that may function over networks.
This strategy can result in extra scalable and privacy-conscious machine studying options, significantly vital for giant information functions.

Quantum SGD
The appearance of quantum computing presents a chance to discover quantum variations of SGD, leveraging quantum algorithms for optimization.
Quantum SGD has the potential to dramatically velocity up the coaching course of for sure forms of fashions, although that is nonetheless largely within the analysis part.

SGD in Reinforcement Studying and Past
Adapting and making use of SGD in areas like reinforcement studying, the place the optimization landscapes are completely different from conventional supervised studying duties.
This might open new avenues in growing extra environment friendly and highly effective reinforcement studying algorithms.

Moral and Accountable AI
There’s a rising consciousness of the moral implications of AI fashions, together with these skilled utilizing SGD.
Analysis into SGD may additionally give attention to guaranteeing that fashions are honest, clear, and accountable, aligning with broader societal values.

As we wrap up our exploration of Stochastic Gradient Descent (SGD), it’s clear that this algorithm is rather more than only a technique for optimizing machine studying fashions. It stands as a testomony to the ingenuity and steady evolution within the discipline of synthetic intelligence. From its primary type to its extra superior variants, SGD stays a crucial device within the machine studying toolkit, adaptable to a wide selection of challenges and functions.

In case you favored the article please depart a clap, and let me know within the feedback what you concentrate on it!

[ad_2]

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button