Hardware Programming
Assembler is necessary when directly programming the hardware. Especially very highly embedded systems may lack a compiler. Even modern CPUs need a bit of assembler to get them bootstrapped, since in the earliest stages of the power-up cycle, there is no stack and parts of the CPU still need initialisation.
A area commonly associated with hardware and assembly programming, namely device drivers, are rather using CPU-independent kernel interfaces (Windows Driver Kit or Linux' internals).
Last, but not least, assembler can be used to quickly access a specific CPU-feature (CPUID, int/float conversion) without having to resort to a vendor's (possibly incomplete) API.
Understanding
Learning (any) assembler helps in understanding the behaviour of programs from low-level stuff like calling conventions and memory management to arcane topics like branch prediction. This understanding can be applied when reverse engineering, understanding what the compiler did, or optimizing the last percent from a hot spot (see below).
Thus knowing assembler is one of the necessary pieces to understand a computer from top to bottom.
Performance
Even large and modern applications have somewhere that one hotspot that can be significantly improved by the assembler mace. To cite a famous one, Microsoft Excel has its float formatting routine written in assembler (with tragic side effects).
On the other hand libraries have to perform at their best in any circumstance. Especially things like memset() can profit by hand-tuned implementations.
Code generation
Compilers need to generate assembler code. For this someone needs to know enough assembly to create the code generator.