Most download applications use TCP as transport-layer protocol. TCP uses a congestion algorithm that detects the available bandwidth and cooperatively shapes the traffic throughput accordingly.
There are quite a few variants for the algorithm around - an overview: https://en.wikipedia.org/wiki/TCP_congestion_control
Why detect bandwidth and not send full speed you ask? Well, imagine a server with a 10 Gbit/s uplink. You start downloading and the server sends at 10 Gbit each second, regardless of what you can accept - doesn't make sense, does it?
Theoretically, you could send your local link speed along with the request to make the server send at that speed. But then again, the path bandwidth isn't only defined by the links at its end but by the whole path, ie. by its slowest hop. Your Internet uplink could be just 50 Mbit/s and there could be concurrent traffic eating into that. Potentially, any hop on the way could be limiting the available bandwidth.
Moreover, network load changes all the time and the rate you got over the last minute might not be upholdable for the entire transfer (or vice versa). That's why TCP monitors segment loss permanently and adjusts the amount of requested data all the time.
As to gradual decrease at the end: you're not providing any details. I could imagine you're using a download manager that creates multiple connections for the bulk of data. Nearing the end of the transmission, the connections are retired one by one and the ramping up within each connection happens slower than the retirement.