AI and Scaling the Compute for the new Moore’s Law

AI and Scaling the Compute becomes more relevant as the strive for larger language models and general purpose AI continues. The future of the trend is unknown as the rate of doubling the compute outpaces Moore’s Law rate of every two year to a 3.4 month doubling.

Introduction

AI models have been rapidly growing in complexity and sophistication, requiring increasingly powerful computing resources to train and operate effectively. This trend has led to a surge of interest in scaling compute for AI, with researchers exploring new hardware architectures and distributed computing strategies to push the limits of what is possible. Figure 1 depicts the scale of compute required to train language models for the last ten years.

Figure 1: Computation used to train notable artificial intelligence systems [1]

The evolution of AI models has been driven by advances in deep learning, which allows models to learn from vast amounts of data and make predictions or decisions with remarkable accuracy. However, the sheer size and complexity of these models require an unprecedented amount of compute power to train and operate, presenting significant challenges for hardware designers and data center operators. Despite these challenges, progress has been impressive, with new breakthroughs in hardware and software helping to unlock the full potential of AI. Specialized hardware, such as GPUs (Graphics Processing Units) and TPUs (Tensor Processing Units) have emerged as powerful tools for training AI models, while distributed computing architectures are being developed to allow multiple machines to work together seamlessly. As AI models continue to grow in complexity, the need for scalable and efficient compute resources will only continue to grow. Researchers and engineers will need to work together to develop new hardware and software solutions that can keep pace with the rapid evolution of AI, unlocking new possibilities for intelligent automation, predictive analytics and other transformative applications.

Requiring compute beyond Moore’s Law

As explained in [2] the training of AI systems can be categorized in two distinct Eras, the First Era and the Modern Era. The First Era of compute usage in training AI systems, starting with the perceptron, lasted from the 1950s to the late 2000s and relied on limited computational resources and simple algorithms. In contrast, the Modern Era began around 2012 with the rise of deep learning and the availability of powerful hardware such as GPUs and TPUs, allowing for the training of increasingly complex models with millions or even billions of parameters. [3] even suggests three Eras with the current one being the “Large Scale Era” starting with AlphaGo around 2016.

Figure 2: AlexNet to AlphaGo Zero: 300,000x increase in compute [2]

Increase in AI computation

Figure 2 depicts the increase in computational resources needed to train AI systems over time, which is evident by the rise of GPUs and TPUs and the transition from Moore’s Law’s 2-year doubling of compute to a 3.4-month doubling. This increase in compute demand is exemplified by the difference between AlexNet and AlphaGo Zero, where the latter requires 300,000 times more computational resources to train than the former.

With the rise of large language models like GPT, more recently known due to the publicly available ChatGPT, the question arose on how the trend on computing such models will continue. As seen in Figure 3 the amount of parameters to be learned are increasing rapidly and thus the amount of data and compute required for the models.

Figure 3: Amount of Parameters for Large Language Models [4]

The new Moore’s Law

Moore’s law is the observation that the number of transistors in a dense integrated circuit doubles about every two year [5]. As Moore’s Law has a physical constraint on how many transistors can be placed on an integrated circuits, which will cease to apply, a new trend in compute seems to emerge in the field of AI. As stated in [4] the increase of the size of the language model and in regard of the 3.4-month doubling time stated in [2] we seem to establish a new “Moore’s Law for AI” for compute, which can only be achieved with massive parallelization techniques.

Scaling AI computation

An earlier blogpost [6] already handled the explanation on how deep learning models can be parallelized with the different computation paradigms single instance single device (SISD), multi-instance single device (MISD), single-instance multi-device (SIMD) and multi-instance multi-device (MIMD). Furthermore, the concepts of Model and Data parallelization are explained in that post in more detail.

GPT-3 Example

If we take GPT-3 for example it was scaled up in several ways to enable it to handle its massive size and complexity. Here are some of the key techniques that were used [7]:

  1. Distributed training: GPT-3 was trained using a distributed training approach that involved multiple GPUs and TPUs working together in parallel. The training data was partitioned across the multiple devices and the model parameters were updated using a process called gradient descent, where each device calculated a portion of the gradient and then combined them to update the parameters.
  2. Model parallelism: Because GPT-3 has so many parameters (up to 175 billion), it was not possible to store the entire model on a single device. Instead, the model was split across multiple devices using a technique called model parallelism, where each device stores a portion of the model parameters and computes a portion of the model’s output.
  3. Pipeline parallelism: To further scale up training, GPT-3 also used a technique called pipeline parallelism, where the model is divided into multiple stages and each stage is run on a separate set of devices in parallel. This enables the model to handle much larger batch sizes and process more data in less time.
  4. Mixed precision training: GPT-3 used mixed precision training, which involves using both 16-bit and 32-bit floating-point numbers to represent the model parameters and compute gradients. This can significantly speed up training and reduce the memory requirements of the model.
  5. Adaptive optimization: Finally, GPT-3 used an adaptive optimization algorithm called AdamW that adjusts the learning rate and weight decay of the model dynamically during training. This helps to avoid overfitting and achieve better performance on the validation set.

In summary, the training of GPT-3 was scaled up using a combination of distributed training, model parallelism, pipeline parallelism, mixed precision training and adaptive optimization. These techniques allowed the model to handle its massive size and complexity.

Distributed training, but how?

In order to train a large AI model, scaling across multiple GPUs, TPUs, and machines is necessary. However, achieving this becomes more complex when using a compute cluster, as distributing tasks and aggregating results requires careful consideration of several points. Specifically, when training a large model at scale using a cluster of machines, the following
factors must be taken into account [8][9]:

  1. Communication overhead: Distributed training involves exchanging gradients and model updates between different machines, which can introduce significant communication overhead. Optimizing communication and reducing the frequency of communication can help reduce the overhead and speed up training.
  2. Load balancing: Distributing the workload across multiple machines requires careful load balancing to ensure that each machine has a similar workload. Imbalanced workloads can lead to underutilization of some machines and slower training overall.
  3. Fault tolerance: When using clusters of machines, it is important to consider fault tolerance, as failures in one or more machines can interrupt training. Strategies for fault tolerance include checkpointing, replication of model parameters, and the use of redundant compute nodes.
  4. Network topology: The topology of the network connecting the machines can affect the performance of distributed training. For example, using a network with high bandwidth and low latency can reduce communication overhead and speed up training.
  5. Scalability: The ability to scale up the number of machines used for training is important to accommodate largermodels anddatasets. Ensuringthatthetrainingprocess is scalablerequires careful consideration of the communication patterns and load balancing across a large number of machines.

The trend continues

Taking a look at an even larger language model, the Megatron-Turing NLG [10], we can see that the trend continues. Such large models therefore are required to train on large-scale infrastructure with special software and hardware design optimized for system throughput for large datasets. In [10] the tradeoffs for some techniques are mentioned. Only the combination of several techniques and the use of a supercomputer powered by 560 DGX 100 servers using each eight NVIDIA A100 80GB Tensor Core GPUs allowed NVIDIA to use scale up to thousand of GPUs and train the model in an acceptable time.

Conclusion and outlook

The trend for more compute is expected to continue as AI applications become more complex and require larger datasets and more sophisticated algorithms. To keep up with this demand, we can expect continued improvements in specialized hardware and software optimization techniques, such as neural architecture search, pruning and quantization. Scaling aspects of both software and hardware are critical to meet the increasing demand for computing power and to make AI more efficient and accessible to a wider range of applications.
In contrast to chasing even larger models another approach would be to focus more on specific tasks than general purpose models. As language models continue to grow in size, researchers are beginning to see diminishing returns in terms of their performance improvements. While larger language models have shown impressive capabilities in natural language processing tasks, the computational and financial resources required to train and run them have also increased exponentially. Therefore, [4] proposes a more practical approach which might be more cost and environment friendly than the next big general purpose AI.
As for now we can continue to observe large tech companies joining together for the next big AI model, using supercomputers, cloud infrastructure and every compute they have to build even more impressive AI and thus develop even more sophisticated software and hardware architectures to facilitate the massive amounts of data and computation required to train such models.

Sources

[1] OurWorld in Data. “Computation usedtotrain notable artificial intelligence systems”. In: (2023). URL: https://ourworldindata.org/grapher/artificial-intelligence-training-computation.

[2] OpenAI. “AI and Compute”. In: (2018). URL: https://openai.com/research/ai-and-compute.

[3] Jaime Sevilla et al. Compute Trends Across Three Eras of Machine Learning. 2022. arXiv: 2202.05924 [cs.LG].

[4] Julien Simon. “Large Language Models”. In: (2021). URL: https://huggingface.co/blog/large-language-models.

[5] Wikipedia. Moore’s Law. 2023. URL: https://en.wikipedia.org/wiki/Moore%5C%27s_law.

[6] Annika Strauß and Maximilian Kaiser. “An overview of Large Scale Deep Learning”. In: (2021). URL: https://blog.mi.hdm-stuttgart.de/index.php/2022/03/31/an-overview-oflarge-scale-deep-learning/.

[7] Tom B. Brown et al. “Language Models are Few-Shot Learners”. In: CoRR abs/2005.14165 (2020).
arXiv: 2005.14165. URL: https://arxiv.org/abs/2005.14165.

[8] Martín Abadi et al. TensorFlow: A System for Large-Scale Machine Learning. 2016. URL: https://www.usenix.org/system/files/conference/osdi16/osdi16-abadi.pdf.

[9] Henggang Cui, Gregory R. Ganger, and Phillip B. Gibbons. Scalable deep learning on distributed GPUs with a GPU-specialized parameter server. 2015. URL: https://www.pdl.cmu.edu/PDLFTP/BigLearning/CMU-PDL-15-107.pdf.

[10] Paresh Kharya and Ali Alvi. “Using DeepSpeed and Megatron to Train Megatron-Turing NLG 530B, the World’s Largest and Most Powerful Generative Language Model”. In: (2021). URL: https://developer.nvidia.com/blog/using-deepspeed-and-megatron-to-trainmegatron-turing-nlg-530b-the-worlds-largest-and-most-powerful-generativelanguage-model/.

Ansätze für nachhaltige Softwareentwicklung in Large-Scale Systems

Einleitung

Der Klimawandel ist in den letzten Jahren weltweit zu einer großen Herausforderung geworden. Der Ausstoß von Treibhausgasen ist nach wie vor hoch. Nach Angaben des Umweltbundesamtes gehen die CO2-Emissionen in Deutschland zwar kontinuierlich zurück, weltweit ist der Trend jedoch weiterhin steigend, so dass die globalen Kohlendioxidemissionen kontinuierlich zunehmen [1]. Aufgrund der Corona-Pandemie konnte zwar ein deutlicher Rückgang der Emissionen in den Vorjahren verzeichnet werden, dennoch steigen die Zahlen wieder an [2]. Sollte es in Zukunft nicht gelingen, den hohen Energieverbrauch und den Ausstoß von CO2 nachhaltig zu reduzieren, muss mit Umweltkatastrophen gerechnet werden. In Zeiten der Digitalisierung, spielt auch die Softwareentwicklung eine große Rolle beim Thema Umweltschutz. Die Auswirkungen der IT auf die Umwelt haben in den letzten Jahrzehnten durch die Zunahme der Digitalisierung zugenommen. Digitalisierung und innovative Technologien sollen CO2-Emissionen reduzieren. Riesige Rechenzentren, Datenzentren und IT-Infrastrukturen sowie große Datenmengen benötigen jedoch viel Energie. Der Energiebedarf in diesem Sektor ist in den letzten Jahren stark angestiegen.

Abbildung 1: Energiebedarf von Rechenzentren in Europa pro Jahr (Quelle: https://www.borderstep.de/2020/11/30/deutlicher-anstieg-des-energiebedarfs-der-rechenzentren-im-jahr-2020/)

Die wachsende Zahl von Nutzern und die Nachfrage nach umfangreichen Inhalten (Cloud-Computing und Big-Data-Anwendungen, soziale Netzwerke und Foto-Sharing, Video Streaming auf Abruf usw.) erfordern enorme Bandbreiten, sowie Rechen- bzw. Speicherkapazitäten. Distributed Large-Scale Systems werden daher immer leistungsfähiger und größer. Large-Scale Systems, also softwareintensive Systeme und high-performance Computing Cluster mit einer enormen Menge an Hardware, Quellcodezeilen, Benutzerzahlen und Datenmengen haben daher ebenfalls einen Einfluss auf den CO2-Fußabdruck. Large-Scale Systeme benötigen oft eine große Menge an Energie für die Stromversorgung und Kühlung von Servern, Netzwerkausrüstung und Speichergeräten. Schätzungen zufolge benötigt das Internet durchschnittlich 240 GW Energie [3], was etwa 12,6% der weltweit erzeugten elektrischen Energie entspricht.

Moderne Technologien, sowie verbesserte Hardware, Software und Rechenzentruminfrastrukturen werden zwar immer effizienter, dennoch ist es nicht gelungen, den Anstieg im Energiebedarf zu senken. Um dem entgegenzuwirken gibt es verschiedene Möglichkeiten. Durch grüne und nachhaltige IT (Green IT) und Green Coding können Energieeinsparungen erzielt werden.

“Green IT is the study and practice of designing, manufacturing, using, and disposing of computers, servers, and associated subsystems (such as monitors, printers, storage devices, and networking and communications systems) efficiently and effectively with minimal or no impact on the environment” [4].

Software alleine verbraucht zwar weder Energie, noch stößt sie Emissionen aus, doch das Problem ist, wie die Software entwickelt wird. Es gibt hier verschiedene Techniken, um effizientere und performantere Software zu entwickeln und auch Möglichkeiten Large-Scale Systems nachhaltig zu entwerfen.

Softwareentwicklung und ihre Auswirkungen auf die Umwelt

Beim Menschen denkt man zunächst, dass der größte CO2-Ausstoß durch die Atmung erfolgt. Das ist etwa 1 kg pro Tag. Tatsächlich produziert ein Mensch aber ca. 30 kg CO2 pro Tag, z.B. durch Essen, Reisen und die Nutzung elektronischer Geräte [5]. Der Anteil der digitalen Aktivitäten beträgt 4% der gesamten CO2-Emissionen. Im Jahr 2040 wird dieser Anteil voraussichtlich 14% betragen [6]. Ein Laptop, der an 200 Arbeitstagen täglich acht Stunden in Betrieb ist, verursacht einen jährlichen CO2-Ausstoß von 88 kg. 80% des Datenverkehrs im Netz ist auf Videostreaming zurückzuführen. Netflix gibt z.B. an, dass eine Stunde Video-Streaming einen CO2-Ausstoß von 100 Gramm pro Nutzer verursacht.

Hier muss man den immensen Skalierungsfaktor mitberücksichtigen, so muss dieser Wert auch auf Millionen von Nutzern hochgerechnet werden. Wenn ein Netflix-Entwickler in der Lage wäre, den CO2-Ausstoß pro Stunde um einige wenige Gramm zu reduzieren, könnte eine deutliche Reduktion der Emissionen erzielt werden. Es gibt Best Practices für Entwickler und IT-Architekten, die zu Green Coding beitragen.

Green Coding bedeutet, Software effizienter zu gestalten, um den Energieverbrauch und damit auch die CO2-Emissionen zu reduzieren [7].

Effiziente Softwaretechniken

Allgemein gilt es, Best Practices einzuhalten, um sauberen und effizienteren Code zu schreiben. Code, der für Leistung und Ressourcennutzung optimiert ist, kann dazu beitragen, den Energie- und Stromverbrauch von Software zu senken. Es gibt verschiedene Techniken [8][9].

  • CPU: Ein Ziel ist es, den Verbrauch der CPU zu senken. Dies kann unter anderem mit Hilfe von effizienten mathematischen Operationen (in Bezug auf ihre Zeitkomplexität) erreicht werden. Berechnete Ergebnisse können wiederverwendet werden und bedingte Verzweigungen, wenn möglich reduzieren.
  • Memory: In Bezug auf Memory sollte man eher lokale Variablen, statt globaler Variablen verwenden und wenn möglich die Codegröße verringern.
  • Loops: Optimierungsmethoden verwenden wie z.B. Loop Unrolling, um die Laufzeit eines Programms zu beschleunigen. Mehrere Loops sollten, wenn möglich zusammengeführt werden.
  • Optimale Algorithmen: Im Allgemeinen kann jede Strategie, die die Laufzeit eines Algorithmus verkürzt, hilfreich sein zur Reduzierung des Energieverbrauchs. Die Komplexität des Algorithmus lässt sich in Form der Big O-Notationen berechnen. Algorithmen, die eine lineare Komplexität aufweisen, sind energiebewusster als solche mit exponentieller Komplexität.
  • Effiziente Datenstrukturen: Wie z.B. Linked Lists. Datenstrukturen haben erhebliche Auswirkungen auf die Ausführung eines Programms und die Energieeinsparung.
  • Multithreading: Schnellere Berechnungen durch Parallelisierung ermöglichen.
  • Event-Driven Architectures: Anstatt Request Driven, die oft viele Anfragen haben, sollten eventgetriebene Architekturen bevorzugt werden. Das Ziel ist es die Zahl der Serveranfragen auf ein Mindestmaß zu reduzieren.
  • Caching: Zwischenspeicherungen von Anfragen auf dem Client durch Caching kann dazu beitragen, unnötige Round-Trips innerhalb eines Netzwerks, sowie teure und energieintensive Zugriffe auf Festplatten oder Datenbanken zu vermeiden.
  • Effiziente Programmiersprachen: Einige Programmiersprachen sind effizienter als andere – Die Auswahl der Programmiersprache hat ebenfalls Einfluss auf den Energieverbrauch.
Abbildung 2: Vergleich einiger Programmiersprachen in Bezug auf Energieeffizienz (Quelle: Illustration by Kasper Groes Albin Ludvigsen. Source: Source: Pereira, R. et al. (2017))

Ein Vergleich zeigt, dass die Programmiersprache C in Bezug auf Energie am effizienten abschneidet. Python hingegen verbraucht ca. 70x mehr Energie als C. Die Auswahl einer effizienten Programmiersprache kann somit einen Teil zur Reduzierung des CO2-Fußabdrucks beitragen.

Abbildung 3: Energieverbrauch verschiedener Programmiersprachen (Quelle: https://alanstorm.com/the-thing-about-that-energy-efficiency-of-programming-languages-table/)

Cloud Computing und Nachhaltigkeit

Cloud Computing hat in den letzten Jahren stark an Popularität gewonnen. Ein Cluster aus mehreren Computern mit geringer Kapazität ist in der Regel kosten- und leistungsmäßig günstiger als ein einzelner Hochleistungscomputer, da ein Hochleistungscomputer seine Ressourcen nicht voll ausnutzt und daher mehr Energie verbraucht. Verteilte Systeme oder Cloud Computing können zu einer Leistungssteigerung bei gleichzeitiger Energieeinsparung führen.

Laut einer Studie von Microsoft, Accenture und WSP-Environment & Energy können große Unternehmen durch die Verlagerung ihrer Anwendungen in die Cloud den Energieverbrauch und die Kohlendioxidemissionen um 30% oder mehr senken (im Vergleich zu On-Premise) [10]. Bei kleineren Unternehmen sind es sogar bis zu 90%. Auf den ersten Blick scheint Cloud Computing wegen der riesigen Rechenzentren und des enormen Energieverbrauchs wenig mit Nachhaltigkeit zu tun zu haben. Tatsächlich sind sie aber umweltfreundlicher als On-Premise-Lösungen [11].

  • Höhere Nutzungsrate: Um eventuelle Ausfallzeiten zu vermeiden, setzen Unternehmen traditionell viel mehr Server ein (Redundanz), als sie tatsächlich benötigen. Als Folge, haben die Rechenzentren vor Ort eine extrem niedrige Auslastungsrate und nutzen im Durchschnitt nur 15% ihrer Kapazität.
  • Umstellung auf erneuerbare Energien: Viele Cloud-Anbieter haben in erheblichem Umfang in erneuerbare Energiequellen wie Wind- und Solarenergie investiert. So soll AWS bereits mehr als 50% erneuerbare Energie nutzen. Indem sie ihre Rechenzentren mit erneuerbarer Energie versorgen, können Cloud-Anbieter ihre Kohlenstoffemissionen erheblich reduzieren. Google hat bereits im Jahr 2007 den gesamten CO2-Ausstoß kompensiert, den sie verursacht hat.
  • Skaleneffekte (Economies of Scale): Cloud-Anbieter betreiben riesige Rechenzentren, die auf Energieeffizienz optimiert sind, z. B. durch den Einsatz moderner Kühltechnologien und energieeffizienter Hardware. Diese großen Rechenzentren profitieren vom sogenannten Skaleneffekt, die es ihnen ermöglichen, eine höhere Energieeffizienz zu erreichen als kleinere, vor Ort betriebene Rechenzentren.
  • Geringere Hardwareverschwendung: Durch die Nutzung gemeinsam genutzter Rechenressourcen, kann Cloud-Computing dabei helfen, die Menge der für eine bestimmte Arbeitslast erforderlichen Hardware reduzieren. Dies kann dazu beitragen, die Menge an elektronischem Abfall zu verringern.

Green Computing für Large-Scale Systems

Die Verringerung des Energieverbrauchs kann zur Verringerung der Umweltbelastung beitragen. Neben effizienten Techniken in der Softwareentwicklung kann auch ein hardwarebasierter Ansatz den Stromverbrauch senken, indem alte, ineffiziente Hardware durch neuere, energieeffizientere Alternativen ersetzt wird. Problematisch sind jedoch die erheblichen finanziellen Kosten, die mit der Aufrüstung der Hardware verbunden sind.

Ein Ziel ist es, unter anderem Data Centers so zu gestalten, dass sie möglichst energieeffizient und nachhaltig sind. Dabei können verschiedene Bereiche optimiert werden, wie z.B. der Einsatz von erneuerbaren Energien, die Verbesserung der Energieeffizienz durch bessere Kühlung und Luftstrommanagement, Virtualisierung und Konsolidierung von Servern.

Abbildung 4: Bereiche, in denen der Energieverbrauch von Rechenzentren reduziert werden kann

Nachfolgend sind einige Optimierungsmethoden, die für Large-Scale Systems angewandt werden können [12].

  • Load Balancing: Indem die Arbeitslast auf verschiedene Server verteilt wird, kann der Energieverbrauch jedes Servers optimiert werden. Der Lastausgleich kann dazu beitragen, eine Überbeanspruchung von Ressourcen zu verhindern, die zu einem höheren Energieverbrauch und Kohlendioxidausstoß führen kann.
  • Parallel Processing: Die Parallelverarbeitung kann dazu beitragen, die Zeit zu verkürzen, die für die Ausführung einer Aufgabe benötigt wird, was zu einem geringeren Energieverbrauch und geringeren Kohlendioxidemissionen führen kann. Durch die Aufteilung großer Aufgaben in kleinere Aufgaben und deren parallele Verarbeitung kann der Zeit- und Energieaufwand für die Ausführung der Aufgabe verringert werden.
  • Virtualisierung: Technologien zur Virtualisierung können dazu beitragen, die Ressourcennutzung zu optimieren und die Anzahl der physischen Server zu verringern, die für den Betrieb eines großen Systems erforderlich sind. Durch die Konsolidierung mehrerer Anwendungen auf einem einzigen Server kann die Virtualisierung zur Senkung des Energieverbrauchs und der Kohlendioxidemissionen beitragen.
  • Automatisierte Skalierung: Die automatische Skalierung ermöglicht es, ein System entsprechend der aktuellen Nachfrage zu vergrößern oder zu verkleinern. Dies kann zur Senkung des Energieverbrauchs und der Kohlendioxidemissionen beitragen, da nur die benötigten Ressourcen genutzt werden.
  • Effizientes Datenbank Designing: Durch die Optimierung des Datenbankdesigns kann der Energiebedarf für die Speicherung und den Abruf von Daten gesenkt werden. Dies kann durch die Verwendung effizienter Datenstrukturen, die Minimierung der Anzahl von Abfragen und die Zwischenspeicherung von Daten erreicht werden.
  • Monitoring und Analyse: Durch das Monitoring der Leistung eines Systems und die Analyse der Daten können Bereiche ermittelt werden, in denen der Energieverbrauch und die Kohlendioxidemissionen reduziert werden können. Dies kann bei Entscheidungen über die Optimierung und Ressourcenzuweisung helfen.
  • Erneuerbare Energien: Auch das ist ein wichtiger Punkt. Wie bei den meisten Cloud-Anbietern, kann der Einsatz erneuerbarer Energiequellen wie Sonnen-, Wind- oder Wasserkraft zur Versorgung der Rechenzentren und anderer Infrastrukturkomponenten den CO2-Fußabdruck verringern.
  • Nachhaltige Softwareentwicklungspraktiken: Wie bereits im oberen Abschnitt erwähnt, können effiziente Softwaretechniken zur Förderung der Nachhaltigkeit führen. Auch die Verwendung umweltfreundlicher Materialien für Hardwarekomponenten und die Minimierung von Abfall können zu einer nachhaltigeren Entwicklung beitragen.
  • Verwendung von Cloud-Computing: Es gibt viele quelloffene Software- und Hardware Ressourcen, die von verschiedenen Anbietern als Service zur Verfügung gestellt werden. Die Verwendung dieser vorgefertigten Ressourcen in Programmen ist vorteilhaft in Bezug auf Energiekosten und Zeit. Cloud-Computing bietet zudem eine bedarfsgerechte Skalierbarkeit, die es Large-Scale Systemen ermöglicht, ihre Rechenressourcen je nach Bedarf schnell und einfach nach oben oder unten zu skalieren.

Durch Verwendung dieser Methoden, können Large-Scale Systems ihren Energieverbrauch und ihren ökologischen Fußabdruck verringern.

Fazit

Zusammenfassend lässt sich sagen, dass nachhaltige Softwareentwicklung ein wichtiger Aspekt im Kampf gegen den Klimawandel und zur Reduzierung der CO2-Emissionen ist. Während die Digitalisierung oft als Lösung zur Verringerung des CO2-Fußabdrucks angesehen wird, ist es entscheidend, den Energieverbrauch und die CO2-Emissionen zu berücksichtigen, die mit Large-Scale Systemen und IT-Infrastrukturen verbunden sind. Green IT und Green Coding sind dabei Ansätze, die dazu beitragen können, die Umweltauswirkungen der Softwareentwicklung zu verringern. Oft sind es kleine Maßnahmen die in der Summe den Unterschied bringen.

Effiziente Softwaretechniken, wie die Optimierung des Codes im Hinblick auf Leistung und Ressourcennutzung, können den Energieverbrauch und die CO2-Emissionen senken. Außerdem kann die Optimierung von Systemarchitekturen und Large-Scale Systems durch Load Balancing und Parallelverarbeitung den Energieverbrauch senken und die Nachhaltigkeit verbessern. Dabei können effiziente Softwaretechniken, sowie die Erweiterung in die Cloud, als Basis dienen. Jedoch muss man auch hier beachten, dass durch die horizontale Skalierung auch mehr Komponenten benötigt werden, die ebenfalls teuer in der Beschaffung sind

Des Weiteren sind moderne Technologien und effizientere Hardware ebenfalls gute Optionen, die jedoch oft mit höheren Kosten verbunden sind. Hier müssen Unternehmen entscheiden wie sie vorgehen möchten. Investieren sie in die Nachhaltigkeit und leisten damit einen Beitrag für grüne IT oder wollen sie diesen Aspekt ignorieren, um Kosten einzusparen? Vor dieser Herausforderung stehen viele Unternehmen. Darüber hinaus stellen die eingeschränkte Verfügbarkeit bestimmter wichtiger Ressourcen, das Fehlen der notwendigen Infrastruktur und Vorschriften weitere potenzielle Einschränkungen dar.

Damit Energieeinsparungen aber wirklich effizient durchgeführt werden kann, muss detailiertes Energiemonitoring betrieben werden. Dieser Bereich wird oft noch vernachlässigt, da er meist mit einem Mehraufwand verbunden ist. Hier bleibt abzuwarten, wie die großen Cloud Anbieter in Zukunft die Sache angehen werden.

Eines ist aber sicher: Jeder, auch wir, die in der IT-Welt arbeiten, können einen (wenn auch kleinen) Beitrag zur Nachhaltigkeit leisten. Bereits mit kleinen Veränderungen kann man seinen persönlichen CO2Fußabdruck verkleinern.

Quellen

[1] Statista Research Department, CO2-Emissionen weltweit in den Jahren 1960 bis 2021, 11.11.2022 [online] https://de.statista.com/statistik/daten/studie/37187/umfrage/der-weltweite-co2-ausstoss-seit-1751/ [abgerufen am: 14.02.2023]

[2] Umweltbundestamt, Kohlendioxid-Emissionen, 21.03.2022 [online] https://www.umweltbundesamt.de/daten/klima/treibhausgas-emissionen-in-deutschland/kohlendioxid-emissionen#herkunft-und-minderung-von-kohlendioxid-emissionen [abgerufen am: 14.02.2023]

[3] Raghavan B, Ma J. The energy and emergy of the Internet. Proceedings of the 10th ACM
Workshop on Hot Topics in Networks (HotNets-X); 2011 Nov; Cambridge (MA); 2011.

[4] Murugesan, S. 2010. Making IT Green. IT Professional, IEEE Computer Society, 12, 2, 4–5.

[5] Gasgag, Wie viel CO2 produziert ein Mensch, 14.02.2022 [online] https://www.gasag.de/magazin/nachhaltig/co2-ausstoss-mensch [abgerufen am: 14.02.2023]

[6] Sanjay Podder, Adam Burden, Shalabh Kumar Singh, and Regina Maruca, How Green Is Your Software? 18.09.2020 [online] https://hbr.org/2020/09/how-green-is-your-software [abgerufen am: 13.02.2023]

[7] Ernst & Munsch UG (haftungsbeschränkt), Green Coding: Nachhaltige Software durch CO2-Reduktion, 22.12.2022 [online] https://www.presseportal.de/pm/164270/5400500 [abgerufen am: 14.02.2023]

[8] Gabor Meißner, Aller Anfang ist schwer: Ansätze für Green Software-Engineering, 04.01.2022 [online] https://www.adesso.de/de/news/blog/aller-anfang-ist-schwer-ansaetze-fuer-green-software-engineering.jsp [abgerufen am: 13.02.2023]

[9] Naik K (2010) A Survey of Software Based Energy Saving Methodologies for Handheld Wireless Communication Devices. Tech. Report No. 2010-13. Dept. of ECE, University of Waterloo

[10] Gina Roos, Cloud Computing Can Cut Carbon Emissions by 30% to 90%, 05.11.2010 [online] https://www.environmentalleader.com/2010/11/cloud-computing-can-cut-carbon-emissions-per-user-by-30/ [abgerufen am: 13.02.2023]

[11] Nitin Singh Chauhan, Ashutosh Saxena. A Green Software Development Life Cycle for Cloud Computing. 1 (2013). https://condor.dpu.depaul.edu/yhwang1/Articles_KHU/article_8.pdf

[12] Fakhar, F., Javed, B., ur Rasool, R. et al. Software level green computing for large scale systems. J Cloud Comp 1, 4 (2012). https://doi.org/10.1186/2192-113X-1-4

An overview of Large Scale Deep Learning

article by Annika Strauß (as426) and Maximilian Kaiser (mk374)

1. Introduction

One of the main reasons why machine learning did not take off in the 1990s was that the lack of computational power and  the size of data sets, available at that time

Since then, a lot has changed and machine learning methods have found their way into the field of ultra large systems (ULS) like f.e. Google, where they have been used very successfully for quite some time.

Two main areas of application can be distinguished:

  • Learn better ML models faster with very large data sets and very high computing power by parallelizing and distributing different components of the ML computation.
  • Deep Learning methods are developed, trained and applied to control, understand, improve and optimize specific areas within a ULS, e.g. replace multiple overcomplicated subcomponents with a single, machine learned model that still does the same job
Continue reading

Black Swans in IT-Systemen und Ausfälle 2020

Seit über einem Jahr sorgt die Coronapandemie für tägliche Berichterstattung und vielerlei Einschränkungen. Kontakte werden auf ein Minimum begrenzt, Gastronomien und Großteile des Einzelhandels geschlossen und Freizeit- sowie Kulturveranstaltungen abgesagt. Mehr Zeit als je zuvor verbringen die Menschen in ihren eigenen vier Wänden und nutzen IT-Systeme, um im Home-Office zu arbeiten, über Lernplattformen zu lernen oder durch Videokonferenzsysteme soziale Kontakte herzustellen. Auch die dafür benötigten, cloudbasierten IT-Systeme erfahren dadurch Auslastungen, die zuvor nur schwer vorstellbar waren. Dieser Mehraufwand und die dafür erforderliche Skalierung der Systeme, sorgte im vergangenen Jahr 2020 für Ausfälle (Outages), von welchen auch die “Big-Player” des Cloud-Computings nicht verschont blieben. Einer Microsoft Azure Einschränkung im März folgte im November der Ausfall einiger AWS-Dienste des Cloud-Marktführers Amazon, ehe im Dezember zahlreiche Google-Dienste wie YouTube oder GoogleDrive für einige Stunden unerreichbar waren. Mögliche Ursachen solcher Ausfälle wurden bereits 2018 in Laura Nolans USENIX-Konferenzbeitrag “What Breaks Our Systems: A Taxonomy of Black Swans” thematisiert und in sechs Muster kategorisiert [2]. Der folgende Blogbeitrag stellt diese Kategorien, die Ursachen schwarzer Schwäne in IT Systemen dar (Seite 1), ordnet einige Ausfälle aus dem vergangenen Jahr in diese ein (Seite 2) und zeigt mögliche Präventionsmaßnahmen auf (Seite 3).

Continue reading

How to increase robustness of a large scale system by testing

When a distributed software system grows bigger and bigger, one will end up with a big amount of various components which all need to scale independently. In order to achieve these components working smooth together, it is necessary to figure out at which time a component needs to be scaled, to avoid having one component as a bottleneck.

This blog post focuses on the possibility to test the behaviour of a large scale system under extreme load in order to discover vulnerabilities. Therefore I will provide an overview of scalability testing and a more specific variant, which has already proven itself as a successful testing variant for such systems, called Chaos Engineering.

Continue reading

Federated Learning

The world is enriched daily with the latest and most sophisticated achievements of Artificial Intelligence (AI). But one challenge that all new technologies need to take seriously is training time. With deep neural networks and the computing power available today, it is finally possible to perform the most complex analyses without need of pre-processing and feature selection. This makes it possible to apply new models to numerous applications. The only thing needed is tons of training data, a good model and a lot of patience during training.

Continue reading

About using Machine Learning to improve performance of Go programs

Gophers

This Blogpost contains some thoughts on learning the sizes arrays, slices or maps are going to reach using Machine Learning (ML) to increase  programs’ performances by allocating the necessary memory in advance instead of reallocating every time new elements are appended.

What made me write this blogpost?

Well first of all I had to because it is part of the lecture Ultra Largescale Systems (ULS) I attended past winter term. But as an introduction I’ll tell you what made me choose this topic: I started to learn Golang and coming from mainly Java, Python and JavaScript the concept of Arrays with fixed sizes and Slices wrapped around them for convenience was new to me. When I understood that initializing them with the correct capacity is good for performance and memory usage I always tried to so. Until I came to some use case where I could not know the capacity in advance. At almost the same time we talked about “ML for Systems” in the ULS-lecture. There the power of ML is used to speed up Databases, loadbalance Elastic Search Queries and other things. So I came up with the idea of ML for programming languages in this case for learning capacities in Golang. By the way I wanted to try out ML in Go, which is said to bring some performance advantages compared to python and is easier to deliver. But neither ML in Go (go for ML) nor ML on Go is topic of this post, though both appear at some parts.

The goal in more detail

As explained in various blogposts like here and there, arrays have fixed sizes in Go. For convenient manipulation anyway they can be wrapped by slices. Thus appending to a slice that reached its capacity needs to create a new slice with a larger underling array, copy the contents of the old slice to the new one and then replace the old one by the new one. This is what the append method does. That this process is more time consuming than appending to a slice that has a sufficient capacity can be shown with some very simple code that just appends 100 times to a test slice in a loop. Once the slice is initialized with a capacity of zero and once with 100. For both cases we calculate the durations it takes and compare them. Since those durations can vary for the same kind of initialization we run this 1000 times each and calculate the average duration to get more meaningful results. The averages are calculated by the method printSummary which is left out here in order to keep track of things. However the whole code can be found on GitHub.

func main() {
times := 1000
results := make([]time.Duration, 0, times)
for t := 0; t < times; t++ {
start := time.Now()
// initialize either with capacity of 0
// test := make([]int, 0)
// or initialize with final capacity of 100
test := make([]int, 0, 100)
for i := 0; i < 100; i++ {
// uncomment to see how the capacity grows in larger steps
// fmt.Println(cap(test), len(test))
test = append(test, i)
}
elapsed := time.Now().Sub(start)
results = append(results, elapsed)
}
printSummary(results)
}

As expected the correct initialized version runs with an average of 1714ns faster than the other one with an average of 2409ns. Of course those durations are still just samples and vary if the code runs multiple times. But in over 20 runs each there is only one average value of the bad initialized slice lower than some of the good ones.

If we also take a look at the capacity the slower version ends up with, we see that this is 128 instead of the required 100. This is because append always doubles the capacity if it reaches the limit.

So we can see that it is worth setting the capacity correct in advance for performance and resource consumption reasons. But this is not always as easy as in the example we just saw and sometimes it is not even possible to know the length a slice will grow up to in advance. In those cases it might make sense to let the program learn the required capacities. It could be helpful at initialization with make as well as for growing with append.

A basic example

Setup

To check out feasibility I created a basic example that is a bit more complex than the first one but still possible to calculate as well. It iterates over index j and value s of a slice of random integer samples and for each of them the test slice is created. Then we append s times three values and one value j times. So the final length (and required capacity) of test can be calculated as s*3+j.

Also in this loop training data gets gathered. One sample consists of s and j as input and len(test) as label. Since the main goal of this scenario is to check if it’s worth using a trained ML model to predict the required capacity, this data is collected always to create equal conditions for every test case. Ways to avoid the time expensive training and data collection at runtime are discussed later.

func appendInBasicLoop(kind string) training.Examples {
samp := getSamples(1000)
data := make([]training.Example, 0, len(samp))
times := 1000
results := make([]time.Duration, 0, times)
for trys := 0; trys < times; trys++ {
start := time.Now()
for j, s := range samp {
var test []int
switch kind {
case "zero":
test = make([]int, 0)
case "calc":
test = make([]int, 0, s*3+j)
case "func":
test = make([]int, 0, getCap(s, j))
case "model":
test = make([]int, 0, getCapFromModel(s, j))
case "model+1":
test = make([]int, 0, getCapFromModel(s, j)+1)
}
for i := 0; i < s; i++ {
test = append(test, i)
test = append(test, j)
test = append(test, s)
}
for k := 0; k < j; k++ {
test = append(test, k)
}
data = append(data,
training.Example{
Input: []float64{float64(s), float64(j)},
Response: []float64{float64(len(test))}})
}
elapsed := time.Now().Sub(start)
results = append(results, elapsed)
}
printSummary(results)
return data
}

As implementation for the ML part I chose go-deep. I picked it from this list because it looked well documented, easy to use and sufficient for my needs, though not perfect.

I used the collected training data to train a MLP (Multi Layer Perceptron) with two hidden layers containing two and five neurons. Of course I configured RegressionMode to use Identity as activation function in the output layer and MSE (Mean Square Error) as loss function. I also played around with some other hyperparameters but kept a lot from the examples provided as well, because the MSE already decreased very fast and became 0.0000 after three training-iterations. This is not surprising since the function to learn is very simple. Also there is no need to avoid overfitting in this basic example. I kept some of the belonging hyperparameters with low values anyway. In a real world use case one would probably try to keep the model as small as possible to get quickest responses.

var net *deep.Neural
func init() {
net = deep.NewNeural(&deep.Config{
Inputs: 2,
Layout: []int{2, 5, 1},
Activation: deep.ActivationReLU,
Mode: deep.ModeRegression,
Weight: deep.NewUniform(0.1, 0.0),
Bias: true,
})
}
func trainModel(data training.Examples) {
optimizer := training.NewAdam(0.02, 0.9, 0.999, 1e-8)
trainer := training.NewBatchTrainer(optimizer, 1, 200, 8)
training, heldout := data.Split(0.75)
trainer.Train(net, training, heldout, 7)
}
func getCapFromModel(s, j int) int {
p := net.Predict([]float64{float64(s), float64(j)})
return int(p[0])
}

Results

The following table shows the test cases I compared along with the average durations in nanoseconds calculated over 1000 tries each. Since those averages vary again from run to run the table contains three of them.

Test caseAvg ns run1Avg ns run2Avg ns run3
Initialize capacity with
zero
12.790.50114.267.92514.321.735
Use s*3+j directly in make5.679.5956.067.9685.943.731
Use a function to
calculate s*3+j
5.242.1826.012.9205.515.661
Use the prediction of the
learned model
10.898.4376.361.9119.056.003
The model’s prediction +16.069.7765.714.3486.144.386
The model’s prediction
on new random data
10.165.7646.096.9299.296.384

Even though the durations vary the results show that not initializing the capacity is worst. Also usually it is best to calculate the capacity, if possible. It does not really matter if the calculation happens in a function or directly. When I took a closer look at the model’s predictions I saw that they are quite often exactly one less than the actual capacity. This is why I also added the prediction+1 test case, which is almost as good as the direct calculations. So investigating a bit deeper in what the model predicts is worth it. Maybe some finetuning on the hyperparameters could also fix the problem instead of adding 1 manually. The results also show that the learned model works on completely new random data as well as on partly known data from the training.

Conclusion

Of course creating such a model for a small performance optimization is heavy overengineered and thus not worth it. It could be worth in cases where you know you have a bottleneck at this place (because your profiler told you) and you cannot calculate the required capacity in any other way in advance. In the introduction I already mentioned that I had a use case where it is not possible to do so. In this case the length of the slice depends on a sql.rows object which doesn’t tell you how many rows it contains in advance. Other examples might be conditional appends where you cannot know how many elements fulfill the condition to be appended to a slice or something else. But also in those cases the required capacity might depend on something else. For example the current time, the size of an HTTP request that caused this action or the length this slice reached the last time. In those cases using a ML model might be helpful to avoid a performance bottleneck. With dependencies to previous lengths especially RNNs (Recurrent Neural Networks) might be helpful. At least they probably could give a better guess than a developer himself.

Looking ahead

As stated above in examples like this the engineering effort is too high. So ways for automating would be desirable. First I thought about a one-size-fits-all solution meaning one pretrained model that predicts for various makes the required capacity. But it would be difficult to find good features because they could change from make to make and just using all sorts of possible features would create very sparse matrices and require larger models if they could work at all.

So we should stick to use case specific models that can be smaller and use meaningful features depending on their environment like lengths of arrays, slices, maps or strings “close” to them or values of specific bools or integers. The drawback is that individual models need individual training maybe with production like data. Training during runtime would cause an overhead that might destroy the benefit the model could bring and slow the program down at least for a while until training can be stopped or paused because the ML model’s performance is good enough. So if possible pure online learning should be avoided and training on test stages or at times with low traffic should be preferred. If the length of a slice depends on the current traffic this is of course not possible. Then one should at least make use of dumping a model’s weights from time to time to the logs to be able to reuse them when starting a new node.

Still we need to solve the overengineering issue and try to build a model automatically at compile time, if the developer demands to do so for example using an additional argument in the call to make. I think that this might be another use case for ML on code: Finding good features and parameters to build a ML model by inspecting the code. Unfortunately I’m not sure what such an ML model on code could look like and what it would require to train it. Using a GAN (Generative adversarial network) to generate the models would probably require already existing ones to train the discriminator. If the automation could be realized the use case also could get broader because then calculating the capacity would be more effort than just saying “learn it”.

Some final thoughts

Using ML would not magically boost performance. It would require developers to remeasure and double check if it’s worth using it. For example it is not only important how often the program needs to allocate memory but also where. So stack allocation is cheap and heap allocation is expensive as explained in this blog post. If using ML to predict the capacity requires the program to allocate on the heap it might be slower even when the predictions are correct. In the test scenario above all the cases instead of initializing with zero escaped to the heap. There it was worth it but it needs to be measured. So the performance should be compared with and without learning for short and for longer running applications. As another example sometimes the required capacities might not be learnable because they are almost random or depend on things that cannot be used as features in an efficient way.

Another drawback of using ML is that your code behaves less predictable. You won’t know what capacity will be estimated for a slice in advance anymore and it will be much harder to figure out why the program estimated exactly what it did afterwards.

I also thought about to train the model to reduce a mix of performance and required memory instead of using the final length as labels. But then it is not that easy anymore to get the training data. In some cases however it might also be difficult to get the “final” length of a slice as well.

The last thing to remember is that it is always helpful to set a learned model some borders. In this case a minimum and a maximum. My test model for example predicted a negative capacity before I got the hyperparameters right, what made my program crash. So if the model for some reason thinks this could be a great idea a fixed minimum of zero should prevent the worst. Also such borders make a program a bit more predictable again.