gradient descent from scratch in python