https://glennprays.com/blog/machine-learning-optimization-gradient-descent