Tolerating Adversarial Attacks and Byzantine Faults in Distributed Machine Learning