From 5521faeed0b1f5e50c1eb7234cd5d974a26203a0 Mon Sep 17 00:00:00 2001 From: Sara Khosravi Date: Thu, 11 Jul 2024 17:01:27 -0400 Subject: [PATCH 01/55] Update image path and figure ID in efficient_ai.qmd --- contents/efficient_ai/efficient_ai.qmd | 68 +++++++++--------- .../efficient_ai/images/jpg/dollar_street.jpg | Bin 0 -> 29565 bytes 2 files changed, 32 insertions(+), 36 deletions(-) create mode 100644 contents/efficient_ai/images/jpg/dollar_street.jpg diff --git a/contents/efficient_ai/efficient_ai.qmd b/contents/efficient_ai/efficient_ai.qmd index 2cb2227f..8457ffa6 100644 --- a/contents/efficient_ai/efficient_ai.qmd +++ b/contents/efficient_ai/efficient_ai.qmd @@ -10,53 +10,51 @@ Resources: [Slides](#sec-efficient-ai-resource), [Videos](#sec-efficient-ai-reso ![_DALL·E 3 Prompt: A conceptual illustration depicting efficiency in artificial intelligence using a shipyard analogy. The scene shows a bustling shipyard where containers represent bits or bytes of data. These containers are being moved around efficiently by cranes and vehicles, symbolizing the streamlined and rapid information processing in AI systems. The shipyard is meticulously organized, illustrating the concept of optimal performance within the constraints of limited resources. In the background, ships are docked, representing different platforms and scenarios where AI is applied. The atmosphere should convey advanced technology with an underlying theme of sustainability and wide applicability._](images/png/cover_efficient_ai.png) -Efficiency in artificial intelligence (AI) is not simply a luxury but a necessity. In this chapter, we dive into the key concepts underpinning AI systems' efficiency. The computational demands on neural networks can be daunting, even for minimal systems. For AI to be seamlessly integrated into everyday devices and essential systems, it must perform optimally within the constraints of limited resources while maintaining its efficacy. The pursuit of efficiency guarantees that AI models are streamlined, rapid, and sustainable, thereby widening their applicability across various platforms and scenarios. - +Efficiency in artificial intelligence (AI) is not merely desirable but a fundamental requirement. This chapter delves into the key concepts that underpin the efficient operation of AI systems. The computational demands of neural networks can be substantial, even for relatively simple systems. To seamlessly integrate AI into everyday devices and critical systems, it must perform optimally within the constraints of limited resources while maintaining effectiveness. The pursuit of efficiency ensures that AI models are streamlined, rapid, and sustainable, expanding their applicability across diverse platforms and scenarios. ::: {.callout-tip} ## Learning Objectives -- Recognize the need for efficient AI in TinyML/edge devices. +- Recognize the necessity for efficient AI in TinyML/edge devices. -- Understand the need for efficient model architectures like MobileNets and SqueezeNet. +- Grasp the importance of efficient model architectures like MobileNets and SqueezeNet. -- Understand why techniques for model compression are important. +- Understand the significance of techniques for model compression. -- Get an inclination for why efficient AI hardware is important. +- Gain an appreciation for the value of efficient AI hardware. -- Appreciate the significance of numerics and their representations. +- Recognize the importance of numerical representations and their precision. -- We appreciate that we need to understand the nuances of model comparison beyond accuracy. +- Understand the nuances of model comparison beyond just accuracy. - Recognize efficiency encompasses technology, costs, environment, and ethics. ::: -The focus is on gaining a conceptual understanding of the motivations and significance of the various strategies for achieving efficient AI, both in terms of techniques and a holistic perspective. Subsequent chapters will dive into the nitty-gritty details of these various concepts. +The focus is on acquiring a conceptual understanding of the motivations and significance of the various strategies employed to achieve efficient AI, both in terms of techniques and a holistic perspective. Subsequent chapters provide a more in-depth exploration of these multiple concepts. ## Introduction -Training models can consume significant energy, sometimes equivalent to the carbon footprint of sizable industrial processes. We will cover some of these sustainability details in the [AI Sustainability](../sustainable_ai/sustainable_ai.qmd) chapter. On the deployment side, if these models are not optimized for efficiency, they can quickly drain device batteries, demand excessive memory, or fall short of real-time processing needs. Through this introduction, we aim to elucidate the nuances of efficiency, setting the groundwork for a comprehensive exploration in the subsequent chapters. +Training models can consume significant energy, sometimes comparable to the carbon footprint of sizable industrial processes. The [AI Sustainability](../sustainable_ai/sustainable_ai.qmd) chapter will explore these sustainability details. On the deployment side, if these models are not optimized for efficiency, they can rapidly drain device batteries, demand excessive memory, or fall short of real-time processing requirements. Through this introduction, we aim to elucidate the nuances of efficiency, laying the groundwork for a comprehensive exploration in the subsequent chapters. ## The Need for Efficient AI -Efficiency takes on different connotations depending on where AI computations occur. Let's revisit and differentiate between Cloud, Edge, and TinyML in terms of efficiency. @fig-platforms provides a big picture comparison of the three different platforms. +Efficiency takes on different connotations depending on where AI computations occur. Regarding efficiency, let's revisit and differentiate between Cloud, Edge, and TinyML. @fig-platforms provides a big-picture comparison of the three different platforms. ![Cloud, Mobile and TinyML. Credit: @schizas2022tinyml.](https://www.mdpi.com/futureinternet/futureinternet-14-00363/article_deploy/html/images/futureinternet-14-00363-g001-550.jpg){#fig-platforms} -For cloud AI, traditional AI models often run in large-scale data centers equipped with powerful GPUs and TPUs [@barroso2019datacenter]. Here, efficiency pertains to optimizing computational resources, reducing costs, and ensuring timely data processing and return. However, relying on the cloud introduced latency, especially when dealing with large data streams that must be uploaded, processed, and downloaded. +For cloud AI, traditional AI models often run in large-scale data centers equipped with powerful GPUs and TPUs [@barroso2019datacenter]. Here, efficiency pertains to optimizing computational resources, reducing costs, and ensuring timely data processing and results. However, relying on the cloud introduces latency, especially when dealing with large data streams that require uploading, processing, and downloading. -For edge AI, edge computing brings AI closer to the data source, processing information directly on local devices like smartphones, cameras, or industrial machines [@li2019edge]. Here, efficiency encompasses quick real-time responses and reduced data transmission needs. The constraints, however, are tighter—these devices, while more powerful than microcontrollers, have limited computational power compared to cloud setups. +For edge AI, edge computing brings AI closer to the data source, processing information directly on local devices like smartphones, cameras, or industrial machines [@li2019edge]. Here, efficiency encompasses quick real-time responses and reduced data transmission needs. However, the constraints are tighter—these devices, while more powerful than microcontrollers, have limited computational power compared to cloud setups. -Pushing the frontier even further is TinyML, where AI models run on microcontrollers or extremely resource-constrained environments. The difference in processor and memory performance between TinyML and cloud or mobile systems can be several orders of magnitude [@warden2019tinyml]. Efficiency in TinyML is about ensuring models are lightweight enough to fit on these devices, use minimal energy (critical for battery-powered devices), and still perform their tasks effectively. +TinyML pushes the frontier further, where AI models run on microcontrollers or extremely resource-constrained environments. The processor and memory performance difference between TinyML and cloud or mobile systems can be several orders of magnitude [@warden2019tinyml]. Efficiency in TinyML is about ensuring models are lightweight enough to fit on these devices, consume minimal energy (critical for battery-powered devices), and still perform their tasks effectively. -The spectrum from Cloud to TinyML represents a shift from vast, centralized computational resources to distributed, localized, and constrained environments. As we transition from one to the other, the challenges and strategies related to efficiency evolve, underlining the need for specialized approaches tailored to each scenario. Having underscored the need for efficient AI, especially within the context of TinyML, we will transition to exploring the methodologies devised to meet these challenges. The following sections outline the main concepts we will delve deeper into later. We will demonstrate the breadth and depth of innovation needed to achieve efficient AI as we delve into these strategies. +The spectrum from Cloud to TinyML represents a shift from vast, centralized computational resources to distributed, localized, and constrained environments. As we transition from one to the other, the challenges and strategies associated with efficiency evolve, underlining the need for specialized approaches tailored to each scenario. Having established the necessity of efficient AI, particularly within TinyML, we will explore the methodologies developed to address these challenges. The following sections outline the main concepts we will delve deeper into later. We will demonstrate the breadth and depth of innovation required to achieve efficient AI as we explore these strategies. ## Efficient Model Architectures -Choosing the right model architecture is as crucial as optimizing it. In recent years, researchers have explored some novel architectures that can have inherently fewer parameters while maintaining strong performance. - -**MobileNets:** MobileNets are efficient mobile and embedded vision application models [@howard2017mobilenets]. The key idea that led to their success is the use of depth-wise separable convolutions, which significantly reduce the number of parameters and computations in the network. MobileNetV2 and V3 further enhance this design by introducing inverted residuals and linear bottlenecks. +Selecting an optimal model architecture is as crucial as optimizing it. In recent years, researchers have made significant strides in exploring innovative architectures that can inherently have fewer parameters while maintaining strong performance. +**MobileNets:** MobileNets are efficient mobile and embedded vision application models [@howard2017mobilenets]. The key idea that led to their success is depth-wise separable convolutions, significantly reducing the number of parameters and computations in the network. MobileNetV2 and V3 further enhance this design by introducing inverted residuals and linear bottlenecks. **SqueezeNet:** SqueezeNet is a class of ML models known for its smaller size without sacrificing accuracy. It achieves this by using a "fire module" that reduces the number of input channels to 3x3 filters, thus reducing the parameters [@iandola2016squeezenet]. Moreover, it employs delayed downsampling to increase the accuracy by maintaining a larger feature map. @@ -64,13 +62,13 @@ Choosing the right model architecture is as crucial as optimizing it. In recent ## Efficient Model Compression -Model compression methods are very important for bringing deep learning models to devices with limited resources. These techniques reduce models' size, energy consumption, and computational demands without significantly losing accuracy. At a high level, the methods can briefly be binned into the following fundamental methods: +Model compression methods are essential for bringing deep learning models to devices with limited resources. These techniques reduce models' size, energy consumption, and computational demands without significantly losing accuracy. At a high level, the methods can be categorized into the following fundamental methods: -**Pruning:** This is akin to trimming the branches of a tree. This was first thought of in the [Optimal Brain Damage](https://proceedings.neurips.cc/paper/1989/file/6c9882bbac1c7093bd25041881277658-Paper.pdf) paper [@lecun1989optimal]. This was later popularized in the context of deep learning by @han2016deep. Certain weights or even entire neurons are removed from the network in pruning based on specific criteria. This can significantly reduce the model size. Various strategies include weight pruning, neuron pruning, and structured pruning. We will explore these in more detail in @sec-pruning. @fig-pruning is an examples of neural network pruning: removing some of the nodes in the inner layers (based on a specific criteria) reduces the numbers of edges between the nodes and, in turn, the size of the model. +**Pruning:** This is akin to trimming the branches of a tree. This was first thought of in the [Optimal Brain Damage](https://proceedings.neurips.cc/paper/1989/file/6c9882bbac1c7093bd25041881277658-Paper.pdf) paper [@lecun1989optimal]. This was later popularized in the context of deep learning by @han2016deep. Certain weights or entire neurons are removed from the network in pruning based on specific criteria. This can significantly reduce the model size. Various strategies include weight pruning, neuron pruning, and structured pruning. We will explore these in more detail in @sec-pruning. @fig-pruning is an example of neural network pruning: removing some of the nodes in the inner layers (based on specific criteria) reduces the number of edges between the nodes and, in turn, the model's size. ![Neural Network Pruning.](images/jpg/pruning.jpeg){#fig-pruning} -**Quantization:** quantization is the process of constraining an input from a large set to output in a smaller set, primarily in deep learning; this means reducing the number of bits that represent the weights and biases of the model. For example, using 16-bit or 8-bit representations instead of 32-bit can reduce the model size and speed up computations, with a minor trade-off in accuracy. We will explore these in more detail in @sec-quant. @fig-quantization shows an example of quantization by rounding to the closest number. The conversion from 32-bit floating point to 16-bit reduces the memory usage by 50%. And going from 32-bit to 8-bit Integer, memory is reduced by 75%. While the loss in numeric precision, and consequently model performance, is minor, the memory usage efficiency is very significant. +**Quantization:** Quantization is the process of constraining an input from a large set to output in a smaller set, primarily in deep learning; this means reducing the number of bits that represent the weights and biases of the model. For example, using 16-bit or 8-bit representations instead of 32-bit can reduce the model size and speed up computations, with a minor trade-off in accuracy. We will explore these in more detail in @sec-quant. @fig-quantization shows an example of quantization by rounding to the closest number. The conversion from 32-bit floating point to 16-bit reduces memory usage by 50%. Going from a 32-bit to an 8-bit integer reduces memory usage by 75%. While the loss in numeric precision, and consequently model performance, is minor, the memory usage efficiency is significant. ![Different forms of quantization.](images/jpg/quantization.jpeg){#fig-quantization} @@ -78,9 +76,9 @@ Model compression methods are very important for bringing deep learning models t ## Efficient Inference Hardware -[Training](../training/training.qmd): An AI model is an intensive task that requires powerful hardware and can take hours to weeks, but inference needs to be as fast as possible, especially in real-time applications. This is where efficient inference hardware comes into play. We can achieve rapid response times and power-efficient operation by optimizing the hardware specifically for inference tasks, which is especially crucial for edge devices and embedded systems. +[Training](../training/training.qmd): An AI model is an intensive task that requires powerful hardware and can take hours to weeks, but inference needs to be as fast as possible, especially in real-time applications. This is where efficient inference hardware comes into play. By optimizing the hardware specifically for inference tasks, we can achieve rapid response times and power-efficient operation, which is especially crucial for edge devices and embedded systems. -**TPUs (Tensor Processing Units):** [TPUs](https://cloud.google.com/tpu) are custom-built ASICs (Application-Specific Integrated Circuits) by Google to accelerate machine learning workloads [@jouppi2017datacenter]. They are optimized for tensor operations, offering high throughput for low-precision arithmetic, and are designed specifically for neural network machine learning. TPUs significantly accelerate model training and inference compared to general-purpose GPU/CPUs. This boost means faster model training and real-time or near-real-time inference capabilities, which are crucial for applications like voice search and augmented reality. +**TPUs (Tensor Processing Units):** [TPUs](https://cloud.google.com/tpu) are custom-built ASICs (Application-Specific Integrated Circuits) by Google to accelerate machine learning workloads [@jouppi2017datacenter]. They are optimized for tensor operations, offering high throughput for low-precision arithmetic, and are designed specifically for neural network machine learning. TPUs significantly accelerate model training and inference compared to general-purpose GPU/CPUs. This boost means faster model training and real-time or near-real-time inference capabilities, crucial for applications like voice search and augmented reality. [Edge TPUs](https://cloud.google.com/edge-tpu) are a smaller, power-efficient version of Google's TPUs tailored for edge devices. They provide fast on-device ML inferencing for TensorFlow Lite models. Edge TPUs allow for low-latency, high-efficiency inference on edge devices like smartphones, IoT devices, and embedded systems. AI capabilities can be deployed in real-time applications without communicating with a central server, thus saving bandwidth and reducing latency. Consider the table in @fig-edge-tpu-perf. It shows the performance differences between running different models on CPUs versus a Coral USB accelerator. The Coral USB accelerator is an accessory by Google's Coral AI platform that lets developers connect Edge TPUs to Linux computers. Running inference on the Edge TPUs was 70 to 100 times faster than on CPUs. @@ -88,9 +86,9 @@ Model compression methods are very important for bringing deep learning models t **NN Accelerators:** Fixed-function neural network accelerators are hardware accelerators designed explicitly for neural network computations. They can be standalone chips or part of a larger system-on-chip (SoC) solution. By optimizing the hardware for the specific operations that neural networks require, such as matrix multiplications and convolutions, NN accelerators can achieve faster inference times and lower power consumption than general-purpose CPUs and GPUs. They are especially beneficial in TinyML devices with power or thermal constraints, such as smartwatches, micro-drones, or robotics. -But these are all but the most common examples. A number of other types of hardware are emerging that have the potential to offer significant advantages for inference. These include, but are not limited to, neuromorphic hardware, photonic computing, etc. In [@sec-aihw], we will explore these in greater detail. +But these are all but the most common examples. Several other types of hardware are emerging that have the potential to offer significant advantages for inference. These include, but are not limited to, neuromorphic hardware, photonic computing, etc. In [@sec-aihw], we will explore these in greater detail. -Efficient hardware for inference speeds up the process, saves energy, extends battery life, and can operate in real-time conditions. As AI continues to be integrated into myriad applications- from smart cameras to voice assistants- the role of optimized hardware will only become more prominent. By leveraging these specialized hardware components, developers and engineers can bring the power of AI to devices and situations that were previously unthinkable. +Efficient hardware for inference speeds up the process saves energy, extends battery life, and can operate in real-time conditions. As AI continues to be integrated into myriad applications- from smart cameras to voice assistants- the role of optimized hardware will only become more prominent. By leveraging these specialized hardware components, developers and engineers can bring the power of AI to devices and situations that were previously unthinkable. ## Efficient Numerics @@ -100,11 +98,10 @@ Machine learning, and especially deep learning, involves enormous amounts of com There are many different types of numerics. Numerics have a long history in computing systems. -**Floating point:** Known as single-precision floating-point, FP32 utilizes 32 bits to represent a number, incorporating its sign, exponent, and fraction. FP32 is widely adopted in many deep learning frameworks and balances accuracy and computational requirements. It's prevalent in the training phase for many neural networks due to its sufficient precision in capturing minute details during weight updates. - +**Floating point:** Known as a single-precision floating point, FP32 utilizes 32 bits to represent a number, incorporating its sign, exponent, and fraction. FP32 is widely adopted in many deep learning frameworks and balances accuracy and computational requirements. It is prevalent in the training phase for many neural networks due to its sufficient precision in capturing minute details during weight updates. Also known as half-precision floating point, FP16 uses 16 bits to represent a number, including its sign, exponent, and fraction. It offers a good balance between precision and memory savings. FP16 is particularly popular in deep learning training on GPUs that support mixed-precision arithmetic, combining the speed benefits of FP16 with the precision of FP32 where needed. -Several other numerical formats fall into an exotic class. An exotic example is BF16 or Brain Floating Point. It is a 16-bit numerical format designed explicitly for deep learning applications. It's a compromise between FP32 and FP16, retaining the 8-bit exponent from FP32 while reducing the mantissa to 7 bits (as compared to FP32's 23-bit mantissa). This structure prioritizes range over precision. BF16 has achieved training results comparable in accuracy to FP32 while using significantly less memory and computational resources [@kalamkar2019study]. This makes it suitable not just for inference but also for training deep neural networks. +Several other numerical formats fall into an exotic class. An exotic example is BF16 or Brain Floating Point. It is a 16-bit numerical format designed explicitly for deep learning applications. It is a compromise between FP32 and FP16, retaining the 8-bit exponent from FP32 while reducing the mantissa to 7 bits (as compared to FP32's 23-bit mantissa). This structure prioritizes range over precision. BF16 has achieved training results comparable in accuracy to FP32 while using significantly less memory and computational resources [@kalamkar2019study]. This makes it suitable not just for inference but also for training deep neural networks. By retaining the 8-bit exponent of FP32, BF16 offers a similar range, which is crucial for deep learning tasks where certain operations can result in very large or very small numbers. At the same time, by truncating precision, BF16 allows for reduced memory and computational requirements compared to FP32. BF16 has emerged as a promising middle ground in the landscape of numerical formats for deep learning, providing an efficient and effective alternative to the more traditional FP32 and FP16 formats. @@ -163,25 +160,23 @@ In essence, these efficiency metrics are more than numbers dictating where and h ### Efficiency Comparisons -The ecosystem contains an abundance of models, each boasting its unique strengths and idiosyncrasies. However, pure model accuracy figures or training and inference speeds paint a partial picture. When we dive deeper into comparative analyses, several critical nuances emerge. - +The landscape of machine learning models is vast, with each model offering a unique set of strengths and implementation considerations. While raw accuracy figures or training and inference speeds might be tempting benchmarks, they provide an incomplete picture. A deeper comparative analysis reveals several critical factors influencing a model's suitability for TinyML applications. Often, we encounter the delicate balance between accuracy and efficiency. For instance, while a dense, deep learning model and a lightweight MobileNet variant might excel in image classification, their computational demands could be at two extremes. This differentiation is especially pronounced when comparing deployments on resource-abundant cloud servers versus constrained TinyML devices. In many real-world scenarios, the marginal gains in accuracy could be overshadowed by the inefficiencies of a resource-intensive model. -Moreover, the optimal model choice is only sometimes universal but often depends on the specifics of an application. Consider object detection: a model that excels in general scenarios that might falter in niche environments, such as when detecting manufacturing defects on a factory floor. This adaptability- or the lack of it- can dictate a model's real-world utility. - -Another important consideration is the relationship between model complexity and its practical benefits. Take voice-activated assistants, such as "Alexa" or "OK Google." While a complex model might demonstrate a marginally superior understanding of user speech if it's slower to respond than a simpler counterpart, the user experience could be compromised. Thus, adding layers or parameters only sometimes equates to better real-world outcomes. +Moreover, the optimal model choice is only sometimes universal but often depends on the specifics of an application. Consider object detection: a model that excels in general scenarios might falter in niche environments, such as when detecting manufacturing defects on a factory floor. This adaptability- or the lack of it- can dictate a model's real-world utility. +Another important consideration is the relationship between model complexity and its practical benefits. Take voice-activated assistants like "Alexa" or "OK Google." While a complex model might demonstrate a marginally superior understanding of user speech if it's slower to respond than a simpler counterpart, the user experience could be compromised. Thus, adding layers or parameters only sometimes equates to better real-world outcomes. Furthermore, while benchmark datasets, such as ImageNet [@russakovsky2015imagenet], COCO [@lin2014microsoft], Visual Wake Words [@chowdhery2019visual], Google Speech Commands [@warden2018speech], etc. provide a standardized performance metric, they might not capture the diversity and unpredictability of real-world data. Two facial recognition models with similar benchmark scores might exhibit varied competencies when faced with diverse ethnic backgrounds or challenging lighting conditions. Such disparities underscore the importance of robustness and consistency across varied data. For example, @fig-stoves from the Dollar Street dataset shows stove images across extreme monthly incomes. Stoves have different shapes and technological levels across different regions and income levels. A model that is not trained on diverse datasets might perform well on a benchmark but fail in real-world applications. So, if a model was trained on pictures of stoves found in wealthy countries only, it would fail to recognize stoves from poorer regions. -![Different types of stoves. Credit: Dollar Street stove images.](https://pbs.twimg.com/media/DmUyPSSW0AAChGa.jpg){#fig-stoves} +![Different types of stoves. Credit: Dollar Street stove images.](images/jpg/dollar_street.jpg){#fig-stoves} In essence, a thorough comparative analysis transcends numerical metrics. It's a holistic assessment intertwined with real-world applications, costs, and the intricate subtleties that each model brings to the table. This is why having standard benchmarks and metrics widely established and adopted by the community becomes important. ## Conclusion -Efficient AI is extremely important as we push towards broader and more diverse real-world deployment of machine learning. This chapter provided an overview, exploring the various methodologies and considerations behind achieving efficient AI, starting with the fundamental need, similarities, and differences across cloud, Edge, and TinyML systems. +Efficient AI is crucial as we push towards broader and more diverse real-world deployment of machine learning. This chapter provided an overview, exploring the various methodologies and considerations behind achieving efficient AI, starting with the fundamental need, similarities, and differences across cloud, Edge, and TinyML systems. -We saw that efficient model architectures can be useful for optimizations. Model compression techniques such as pruning, quantization, and knowledge distillation exist to help reduce computational demands and memory footprint without significantly impacting accuracy. Specialized hardware like TPUs and NN accelerators offer optimized silicon for neural network operations and data flow. Efficient numerics balance precision and efficiency, enabling models to attain robust performance using minimal resources. In the subsequent chapters, we will explore these different topics in depth and in detail. +We examined efficient model architectures and their usefulness for optimization. Model compression techniques such as pruning, quantization, and knowledge distillation exist to help reduce computational demands and memory footprint without significantly impacting accuracy. Specialized hardware like TPUs and NN accelerators offer optimized silicon for neural network operations and data flow. Efficient numerics balance precision and efficiency, enabling models to attain robust performance using minimal resources. We will explore these topics in depth and detail in the subsequent chapters. Together, these form a holistic framework for efficient AI. But the journey doesn't end here. Achieving optimally efficient intelligence requires continued research and innovation. As models become more sophisticated, datasets grow, and applications diversify into specialized domains, efficiency must evolve in lockstep. Measuring real-world impact requires nuanced benchmarks and standardized metrics beyond simplistic accuracy figures. @@ -228,3 +223,4 @@ In addition to exercises, we offer a series of hands-on labs allowing students t - _Coming soon._ ::: + diff --git a/contents/efficient_ai/images/jpg/dollar_street.jpg b/contents/efficient_ai/images/jpg/dollar_street.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e4854371f14fe392628b69178b9f7be7c9306f2a GIT binary patch literal 29565 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 U(g9oCTv?d0^jdsU`eXV30ov&Fp8x;= literal 0 HcmV?d00001 From 394c340da87cb3f41fc68bd797a9ad927936278f Mon Sep 17 00:00:00 2001 From: jasonjabbour Date: Thu, 15 Aug 2024 02:20:56 -0400 Subject: [PATCH 02/55] chose changes to keep or remove --- contents/efficient_ai/efficient_ai.qmd | 23 ++++++++++-------- .../efficient_ai/images/jpg/dollar_street.jpg | Bin 29565 -> 0 bytes 2 files changed, 13 insertions(+), 10 deletions(-) delete mode 100644 contents/efficient_ai/images/jpg/dollar_street.jpg diff --git a/contents/efficient_ai/efficient_ai.qmd b/contents/efficient_ai/efficient_ai.qmd index 49051dfd..f3ba4c84 100644 --- a/contents/efficient_ai/efficient_ai.qmd +++ b/contents/efficient_ai/efficient_ai.qmd @@ -10,16 +10,17 @@ Resources: [Slides](#sec-efficient-ai-resource), [Videos](#sec-efficient-ai-reso ![_DALL·E 3 Prompt: A conceptual illustration depicting efficiency in artificial intelligence using a shipyard analogy. The scene shows a bustling shipyard where containers represent bits or bytes of data. These containers are being moved around efficiently by cranes and vehicles, symbolizing the streamlined and rapid information processing in AI systems. The shipyard is meticulously organized, illustrating the concept of optimal performance within the constraints of limited resources. In the background, ships are docked, representing different platforms and scenarios where AI is applied. The atmosphere should convey advanced technology with an underlying theme of sustainability and wide applicability._](images/png/cover_efficient_ai.png) -Efficiency in artificial intelligence (AI) is not merely desirable but a fundamental requirement. This chapter delves into the key concepts that underpin the efficient operation of AI systems. The computational demands of neural networks can be substantial, even for relatively simple systems. To seamlessly integrate AI into everyday devices and critical systems, it must perform optimally within the constraints of limited resources while maintaining effectiveness. The pursuit of efficiency ensures that AI models are streamlined, rapid, and sustainable, expanding their applicability across diverse platforms and scenarios. +Efficiency in artificial intelligence (AI) is not simply a luxury but a necessity. In this chapter, we dive into the key concepts underpinning AI systems' efficiency. The computational demands on neural networks can be daunting, even for minimal systems. For AI to be seamlessly integrated into everyday devices and essential systems, it must perform optimally within the constraints of limited resources while maintaining its efficacy. The pursuit of efficiency guarantees that AI models are streamlined, rapid, and sustainable, thereby widening their applicability across various platforms and scenarios. + ::: {.callout-tip} ## Learning Objectives -- Recognize the necessity for efficient AI in TinyML/edge devices. +- Recognize the need for efficient AI in TinyML/edge devices. -- Grasp the importance of efficient model architectures like MobileNets and SqueezeNet. +- Understand the need for efficient model architectures like MobileNets and SqueezeNet. -- Understand the significance of techniques for model compression. +- Understand why techniques for model compression are important. - Gain an appreciation for the value of efficient AI hardware. @@ -27,29 +28,31 @@ Efficiency in artificial intelligence (AI) is not merely desirable but a fundame - Understand the nuances of model comparison beyond just accuracy. +- We appreciate that we need to understand the nuances of model comparison beyond accuracy. + - Recognize efficiency encompasses technology, costs, environment, and ethics. ::: -The focus is on acquiring a conceptual understanding of the motivations and significance of the various strategies employed to achieve efficient AI, both in terms of techniques and a holistic perspective. Subsequent chapters provide a more in-depth exploration of these multiple concepts. +The focus is on gaining a conceptual understanding of the motivations and significance of the various strategies for achieving efficient AI, both in terms of techniques and a holistic perspective. Subsequent chapters provide a more in-depth exploration of these multiple concepts. ## Introduction -Training models can consume significant energy, sometimes comparable to the carbon footprint of sizable industrial processes. The [AI Sustainability](../sustainable_ai/sustainable_ai.qmd) chapter will explore these sustainability details. On the deployment side, if these models are not optimized for efficiency, they can rapidly drain device batteries, demand excessive memory, or fall short of real-time processing requirements. Through this introduction, we aim to elucidate the nuances of efficiency, laying the groundwork for a comprehensive exploration in the subsequent chapters. +Training models can consume significant energy, sometimes equivalent to the carbon footprint of sizable industrial processes. We will cover some of these sustainability details in the [AI Sustainability](../sustainable_ai/sustainable_ai.qmd) chapter. On the deployment side, if these models are not optimized for efficiency, they can quickly drain device batteries, demand excessive memory, or fall short of real-time processing needs. Through this introduction, we aim to elucidate the nuances of efficiency, setting the groundwork for a comprehensive exploration in the subsequent chapters. ## The Need for Efficient AI -Efficiency takes on different connotations depending on where AI computations occur. Regarding efficiency, let's revisit and differentiate between Cloud, Edge, and TinyML. @fig-platforms provides a big-picture comparison of the three different platforms. +Efficiency takes on different connotations depending on where AI computations occur. Let's revisit and differentiate between Cloud, Edge, and TinyML in terms of efficiency. @fig-platforms provides a big-picture comparison of the three different platforms. ![Cloud, Mobile and TinyML. Source: @schizas2022tinyml.](https://www.mdpi.com/futureinternet/futureinternet-14-00363/article_deploy/html/images/futureinternet-14-00363-g001-550.jpg){#fig-platforms} -For cloud AI, traditional AI models often run in large-scale data centers equipped with powerful GPUs and TPUs [@barroso2019datacenter]. Here, efficiency pertains to optimizing computational resources, reducing costs, and ensuring timely data processing and results. However, relying on the cloud introduces latency, especially when dealing with large data streams that require uploading, processing, and downloading. +For cloud AI, traditional AI models often run in large-scale data centers equipped with powerful GPUs and TPUs [@barroso2019datacenter]. Here, efficiency pertains to optimizing computational resources, reducing costs, and ensuring timely data processing and return. However, relying on the cloud introduces latency, especially when dealing with large data streams that require uploading, processing, and downloading. For edge AI, edge computing brings AI closer to the data source, processing information directly on local devices like smartphones, cameras, or industrial machines [@li2019edge]. Here, efficiency encompasses quick real-time responses and reduced data transmission needs. However, the constraints are tighter—these devices, while more powerful than microcontrollers, have limited computational power compared to cloud setups. TinyML pushes the frontier further, where AI models run on microcontrollers or extremely resource-constrained environments. The processor and memory performance difference between TinyML and cloud or mobile systems can be several orders of magnitude [@warden2019tinyml]. Efficiency in TinyML is about ensuring models are lightweight enough to fit on these devices, consume minimal energy (critical for battery-powered devices), and still perform their tasks effectively. -The spectrum from Cloud to TinyML represents a shift from vast, centralized computational resources to distributed, localized, and constrained environments. As we transition from one to the other, the challenges and strategies associated with efficiency evolve, underlining the need for specialized approaches tailored to each scenario. Having established the necessity of efficient AI, particularly within TinyML, we will explore the methodologies developed to address these challenges. The following sections outline the main concepts we will delve deeper into later. We will demonstrate the breadth and depth of innovation required to achieve efficient AI as we explore these strategies. +The spectrum from Cloud to TinyML represents a shift from vast, centralized computational resources to distributed, localized, and constrained environments. As we transition from one to the other, the challenges and strategies related to efficiency evolve, underlining the need for specialized approaches tailored to each scenario. Having established the necessity of efficient AI, particularly within the context of TinyML, we will transition to exploring the methodologies devised to meet these challenges. The following sections outline the main concepts we will delve deeper into later. We will demonstrate the breadth and depth of innovation needed to achieve efficient AI as we explore these strategies. ## Efficient Model Architectures @@ -188,7 +191,7 @@ Moreover, the optimal model choice is only sometimes universal but often depends Another important consideration is the relationship between model complexity and its practical benefits. Take voice-activated assistants like "Alexa" or "OK Google." While a complex model might demonstrate a marginally superior understanding of user speech if it's slower to respond than a simpler counterpart, the user experience could be compromised. Thus, adding layers or parameters only sometimes equates to better real-world outcomes. Furthermore, while benchmark datasets, such as ImageNet [@russakovsky2015imagenet], COCO [@lin2014microsoft], Visual Wake Words [@chowdhery2019visual], Google Speech Commands [@warden2018speech], etc. provide a standardized performance metric, they might not capture the diversity and unpredictability of real-world data. Two facial recognition models with similar benchmark scores might exhibit varied competencies when faced with diverse ethnic backgrounds or challenging lighting conditions. Such disparities underscore the importance of robustness and consistency across varied data. For example, @fig-stoves from the Dollar Street dataset shows stove images across extreme monthly incomes. Stoves have different shapes and technological levels across different regions and income levels. A model that is not trained on diverse datasets might perform well on a benchmark but fail in real-world applications. So, if a model was trained on pictures of stoves found in wealthy countries only, it would fail to recognize stoves from poorer regions. -![Different types of stoves. Credit: Dollar Street stove images.](images/jpg/dollar_street.jpg){#fig-stoves} +![Different types of stoves. Credit: Dollar Street stove images.](images/jpg/quantization.jpeg){#fig-stoves} In essence, a thorough comparative analysis transcends numerical metrics. It's a holistic assessment intertwined with real-world applications, costs, and the intricate subtleties that each model brings to the table. This is why having standard benchmarks and metrics widely established and adopted by the community becomes important. diff --git a/contents/efficient_ai/images/jpg/dollar_street.jpg b/contents/efficient_ai/images/jpg/dollar_street.jpg deleted file mode 100644 index e4854371f14fe392628b69178b9f7be7c9306f2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29565 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 U(g9oCTv?d0^jdsU`eXV30ov&Fp8x;= From 7bfe2cb2426172f29919a518ad3d11e95127e7a4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 15 Aug 2024 22:51:17 +0000 Subject: [PATCH 03/55] Update readme and contributors.qmd with contributors --- .all-contributorsrc | 14 +++++++------- README.md | 4 ++-- contents/contributors.qmd | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 86cd2611..468029cb 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -55,13 +55,6 @@ "profile": "https://github.com/JaredP94", "contributions": [] }, - { - "login": "mpstewart1", - "name": "Matthew Stewart", - "avatar_url": "https://avatars.githubusercontent.com/mpstewart1", - "profile": "https://github.com/mpstewart1", - "contributions": [] - }, { "login": "eliasab16", "name": "Elias Nuwara", @@ -90,6 +83,13 @@ "profile": "https://github.com/Mjrovai", "contributions": [] }, + { + "login": "mpstewart1", + "name": "Matthew Stewart", + "avatar_url": "https://avatars.githubusercontent.com/mpstewart1", + "profile": "https://github.com/mpstewart1", + "contributions": [] + }, { "login": "jasonjabbour", "name": "jasonjabbour", diff --git a/README.md b/README.md index 9fec054a..388b9458 100644 --- a/README.md +++ b/README.md @@ -94,13 +94,13 @@ This project follows the [all-contributors](https://allcontributors.org) specifi kai4avaya
kai4avaya

Jared Ping
Jared Ping

- Matthew Stewart
Matthew Stewart

Elias Nuwara
Elias Nuwara

Itai Shapira
Itai Shapira

+ Maximilian Lam
Maximilian Lam

- Maximilian Lam
Maximilian Lam

Marcelo Rovai
Marcelo Rovai

+ Matthew Stewart
Matthew Stewart

jasonjabbour
jasonjabbour

Jayson Lin
Jayson Lin

Jeffrey Ma
Jeffrey Ma

diff --git a/contents/contributors.qmd b/contents/contributors.qmd index 7bcb5984..4d9379a8 100644 --- a/contents/contributors.qmd +++ b/contents/contributors.qmd @@ -82,13 +82,13 @@ We extend our sincere thanks to the diverse group of individuals who have genero kai4avaya
kai4avaya

Jared Ping
Jared Ping

- Matthew Stewart
Matthew Stewart

Elias Nuwara
Elias Nuwara

Itai Shapira
Itai Shapira

+ Maximilian Lam
Maximilian Lam

- Maximilian Lam
Maximilian Lam

Marcelo Rovai
Marcelo Rovai

+ Matthew Stewart
Matthew Stewart

jasonjabbour
jasonjabbour

Jayson Lin
Jayson Lin

Jeffrey Ma
Jeffrey Ma

From f6440f66abe71201d2e8590e7fc5856b120145ba Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Thu, 22 Aug 2024 11:04:38 -0400 Subject: [PATCH 04/55] Moved some things around --- _quarto.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/_quarto.yml b/_quarto.yml index 680b4573..e25066e8 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -87,7 +87,7 @@ book: Written, edited and curated by Prof. Vijay Janapa Reddi (Harvard University) right: | This book was built with Quarto. - + chapters: - text: "---" - part: FRONT MATTER @@ -170,13 +170,6 @@ book: - contents/community.qmd - contents/case_studies.qmd -citation: true - -license: CC-BY-NC-SA - -filters: - - custom_callout.lua - bibliography: # main - contents/introduction/introduction.bib @@ -224,6 +217,13 @@ crossref: key: vid latex-env: vid +citation: true + +license: CC-BY-NC-SA + +filters: + - custom_callout.lua + editor: render-on-save: true From afa9bf8761d735720be26f64c5febf5ce0e6e629 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 22 Aug 2024 15:08:15 +0000 Subject: [PATCH 05/55] Update readme and contributors.qmd with contributors --- .all-contributorsrc | 14 +++++++------- README.md | 2 +- contents/contributors.qmd | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index a9eba26b..a41f6bb3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -62,13 +62,6 @@ "profile": "https://github.com/JaredP94", "contributions": [] }, - { - "login": "mpstewart1", - "name": "Matthew Stewart", - "avatar_url": "https://avatars.githubusercontent.com/mpstewart1", - "profile": "https://github.com/mpstewart1", - "contributions": [] - }, { "login": "ishapira1", "name": "Itai Shapira", @@ -76,6 +69,13 @@ "profile": "https://github.com/ishapira1", "contributions": [] }, + { + "login": "mpstewart1", + "name": "Matthew Stewart", + "avatar_url": "https://avatars.githubusercontent.com/mpstewart1", + "profile": "https://github.com/mpstewart1", + "contributions": [] + }, { "login": "Mjrovai", "name": "Marcelo Rovai", diff --git a/README.md b/README.md index 5c2e3035..33edf7c0 100644 --- a/README.md +++ b/README.md @@ -95,8 +95,8 @@ This project follows the [all-contributors](https://allcontributors.org) specifi kai4avaya
kai4avaya

Elias Nuwara
Elias Nuwara

Jared Ping
Jared Ping

- Matthew Stewart
Matthew Stewart

Itai Shapira
Itai Shapira

+ Matthew Stewart
Matthew Stewart

Marcelo Rovai
Marcelo Rovai

diff --git a/contents/contributors.qmd b/contents/contributors.qmd index 7fafb5cc..c4f3fe67 100644 --- a/contents/contributors.qmd +++ b/contents/contributors.qmd @@ -83,8 +83,8 @@ We extend our sincere thanks to the diverse group of individuals who have genero kai4avaya
kai4avaya

Elias Nuwara
Elias Nuwara

Jared Ping
Jared Ping

- Matthew Stewart
Matthew Stewart

Itai Shapira
Itai Shapira

+ Matthew Stewart
Matthew Stewart

Marcelo Rovai
Marcelo Rovai

From 2f423ca54606abca3595b794bef35a1ec6846a17 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 22 Aug 2024 15:09:17 +0000 Subject: [PATCH 06/55] Update readme and contributors.qmd with contributors --- .all-contributorsrc | 248 +++++++++++++++++++------------------- README.md | 58 ++++----- contents/contributors.qmd | 58 ++++----- 3 files changed, 182 insertions(+), 182 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index a9eba26b..d00d3cfb 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -62,13 +62,6 @@ "profile": "https://github.com/JaredP94", "contributions": [] }, - { - "login": "mpstewart1", - "name": "Matthew Stewart", - "avatar_url": "https://avatars.githubusercontent.com/mpstewart1", - "profile": "https://github.com/mpstewart1", - "contributions": [] - }, { "login": "ishapira1", "name": "Itai Shapira", @@ -76,6 +69,13 @@ "profile": "https://github.com/ishapira1", "contributions": [] }, + { + "login": "mpstewart1", + "name": "Matthew Stewart", + "avatar_url": "https://avatars.githubusercontent.com/mpstewart1", + "profile": "https://github.com/mpstewart1", + "contributions": [] + }, { "login": "Mjrovai", "name": "Marcelo Rovai", @@ -105,10 +105,10 @@ "contributions": [] }, { - "login": "sophiacho1", - "name": "Sophia Cho", - "avatar_url": "https://avatars.githubusercontent.com/sophiacho1", - "profile": "https://github.com/sophiacho1", + "login": "andreamurillomtz", + "name": "Andrea", + "avatar_url": "https://avatars.githubusercontent.com/andreamurillomtz", + "profile": "https://github.com/andreamurillomtz", "contributions": [] }, { @@ -119,10 +119,10 @@ "contributions": [] }, { - "login": "andreamurillomtz", - "name": "Andrea", - "avatar_url": "https://avatars.githubusercontent.com/andreamurillomtz", - "profile": "https://github.com/andreamurillomtz", + "login": "sophiacho1", + "name": "Sophia Cho", + "avatar_url": "https://avatars.githubusercontent.com/sophiacho1", + "profile": "https://github.com/sophiacho1", "contributions": [] }, { @@ -139,13 +139,6 @@ "profile": "https://github.com/korneelf1", "contributions": [] }, - { - "login": "zishenwan", - "name": "Zishen Wan", - "avatar_url": "https://avatars.githubusercontent.com/zishenwan", - "profile": "https://github.com/zishenwan", - "contributions": [] - }, { "login": "colbybanbury", "name": "Colby Banbury", @@ -153,6 +146,13 @@ "profile": "https://github.com/colbybanbury", "contributions": [] }, + { + "login": "zishenwan", + "name": "Zishen Wan", + "avatar_url": "https://avatars.githubusercontent.com/zishenwan", + "profile": "https://github.com/zishenwan", + "contributions": [] + }, { "login": "DivyaAmirtharaj", "name": "Divya Amirtharaj", @@ -160,13 +160,6 @@ "profile": "https://github.com/DivyaAmirtharaj", "contributions": [] }, - { - "login": "srivatsankrishnan", - "name": "Srivatsan Krishnan", - "avatar_url": "https://avatars.githubusercontent.com/srivatsankrishnan", - "profile": "https://github.com/srivatsankrishnan", - "contributions": [] - }, { "login": "ma3mool", "name": "Abdulrahman Mahmoud", @@ -175,10 +168,17 @@ "contributions": [] }, { - "login": "arnaumarin", - "name": "arnaumarin", - "avatar_url": "https://avatars.githubusercontent.com/arnaumarin", - "profile": "https://github.com/arnaumarin", + "login": "srivatsankrishnan", + "name": "Srivatsan Krishnan", + "avatar_url": "https://avatars.githubusercontent.com/srivatsankrishnan", + "profile": "https://github.com/srivatsankrishnan", + "contributions": [] + }, + { + "login": "aptl26", + "name": "Aghyad Deeb", + "avatar_url": "https://avatars.githubusercontent.com/aptl26", + "profile": "https://github.com/aptl26", "contributions": [] }, { @@ -189,10 +189,17 @@ "contributions": [] }, { - "login": "aptl26", - "name": "Aghyad Deeb", - "avatar_url": "https://avatars.githubusercontent.com/aptl26", - "profile": "https://github.com/aptl26", + "login": "arnaumarin", + "name": "arnaumarin", + "avatar_url": "https://avatars.githubusercontent.com/arnaumarin", + "profile": "https://github.com/arnaumarin", + "contributions": [] + }, + { + "login": "jared-ni", + "name": "Jared Ni", + "avatar_url": "https://avatars.githubusercontent.com/jared-ni", + "profile": "https://github.com/jared-ni", "contributions": [] }, { @@ -202,13 +209,6 @@ "profile": "https://github.com/Sara-Khosravi", "contributions": [] }, - { - "login": "Ekhao", - "name": "Emil Njor", - "avatar_url": "https://avatars.githubusercontent.com/Ekhao", - "profile": "https://github.com/Ekhao", - "contributions": [] - }, { "login": "AditiR-42", "name": "Aditi Raju", @@ -217,10 +217,10 @@ "contributions": [] }, { - "login": "jared-ni", - "name": "Jared Ni", - "avatar_url": "https://avatars.githubusercontent.com/jared-ni", - "profile": "https://github.com/jared-ni", + "login": "oishib", + "name": "oishib", + "avatar_url": "https://avatars.githubusercontent.com/oishib", + "profile": "https://github.com/oishib", "contributions": [] }, { @@ -230,6 +230,13 @@ "profile": "https://github.com/MichaelSchnebly", "contributions": [] }, + { + "login": "Ekhao", + "name": "Emil Njor", + "avatar_url": "https://avatars.githubusercontent.com/Ekhao", + "profile": "https://github.com/Ekhao", + "contributions": [] + }, { "login": "ELSuitorHarvard", "name": "ELSuitorHarvard", @@ -238,10 +245,10 @@ "contributions": [] }, { - "login": "oishib", - "name": "oishib", - "avatar_url": "https://avatars.githubusercontent.com/oishib", - "profile": "https://github.com/oishib", + "login": "mmaz", + "name": "Mark Mazumder", + "avatar_url": "https://avatars.githubusercontent.com/mmaz", + "profile": "https://github.com/mmaz", "contributions": [] }, { @@ -251,13 +258,6 @@ "profile": "https://github.com/leo47007", "contributions": [] }, - { - "login": "jaywonchung", - "name": "Jae-Won Chung", - "avatar_url": "https://avatars.githubusercontent.com/jaywonchung", - "profile": "https://github.com/jaywonchung", - "contributions": [] - }, { "login": "BaeHenryS", "name": "Henry Bae", @@ -266,17 +266,17 @@ "contributions": [] }, { - "login": "mmaz", - "name": "Mark Mazumder", - "avatar_url": "https://avatars.githubusercontent.com/mmaz", - "profile": "https://github.com/mmaz", + "login": "jaywonchung", + "name": "Jae-Won Chung", + "avatar_url": "https://avatars.githubusercontent.com/jaywonchung", + "profile": "https://github.com/jaywonchung", "contributions": [] }, { - "login": "arbass22", - "name": "Andrew Bass", - "avatar_url": "https://avatars.githubusercontent.com/arbass22", - "profile": "https://github.com/arbass22", + "login": "marcozennaro", + "name": "Marco Zennaro", + "avatar_url": "https://avatars.githubusercontent.com/marcozennaro", + "profile": "https://github.com/marcozennaro", "contributions": [] }, { @@ -286,6 +286,20 @@ "profile": "https://github.com/eurashin", "contributions": [] }, + { + "login": "ShvetankPrakash", + "name": "Shvetank Prakash", + "avatar_url": "https://avatars.githubusercontent.com/ShvetankPrakash", + "profile": "https://github.com/ShvetankPrakash", + "contributions": [] + }, + { + "login": "arbass22", + "name": "Andrew Bass", + "avatar_url": "https://avatars.githubusercontent.com/arbass22", + "profile": "https://github.com/arbass22", + "contributions": [] + }, { "login": "jzhou1318", "name": "Jennifer Zhou", @@ -300,20 +314,6 @@ "profile": "https://github.com/pongtr", "contributions": [] }, - { - "login": "marcozennaro", - "name": "Marco Zennaro", - "avatar_url": "https://avatars.githubusercontent.com/marcozennaro", - "profile": "https://github.com/marcozennaro", - "contributions": [] - }, - { - "login": "ShvetankPrakash", - "name": "Shvetank Prakash", - "avatar_url": "https://avatars.githubusercontent.com/ShvetankPrakash", - "profile": "https://github.com/ShvetankPrakash", - "contributions": [] - }, { "login": "BrunoScaglione", "name": "Bruno Scaglione", @@ -328,13 +328,6 @@ "profile": "https://github.com/Allen-Kuang", "contributions": [] }, - { - "login": "alex-oesterling", - "name": "Alex Oesterling", - "avatar_url": "https://avatars.githubusercontent.com/alex-oesterling", - "profile": "https://github.com/alex-oesterling", - "contributions": [] - }, { "login": "Gjain234", "name": "Gauri Jain", @@ -342,13 +335,6 @@ "profile": "https://github.com/Gjain234", "contributions": [] }, - { - "login": "FinAminToastCrunch", - "name": "Fin Amin", - "avatar_url": "https://avatars.githubusercontent.com/FinAminToastCrunch", - "profile": "https://github.com/FinAminToastCrunch", - "contributions": [] - }, { "login": "serco425", "name": "Sercan Ayg\u00fcn", @@ -356,6 +342,13 @@ "profile": "https://github.com/serco425", "contributions": [] }, + { + "login": "FinAminToastCrunch", + "name": "Fin Amin", + "avatar_url": "https://avatars.githubusercontent.com/FinAminToastCrunch", + "profile": "https://github.com/FinAminToastCrunch", + "contributions": [] + }, { "login": "gnodipac886", "name": "gnodipac886", @@ -364,10 +357,10 @@ "contributions": [] }, { - "login": "abigailswallow", - "name": "abigailswallow", - "avatar_url": "https://avatars.githubusercontent.com/abigailswallow", - "profile": "https://github.com/abigailswallow", + "login": "alex-oesterling", + "name": "Alex Oesterling", + "avatar_url": "https://avatars.githubusercontent.com/alex-oesterling", + "profile": "https://github.com/alex-oesterling", "contributions": [] }, { @@ -378,10 +371,17 @@ "contributions": [] }, { - "login": "YLab-UChicago", - "name": "yanjingl", - "avatar_url": "https://avatars.githubusercontent.com/YLab-UChicago", - "profile": "https://github.com/YLab-UChicago", + "login": "emmanuel2406", + "name": "Emmanuel Rassou", + "avatar_url": "https://avatars.githubusercontent.com/emmanuel2406", + "profile": "https://github.com/emmanuel2406", + "contributions": [] + }, + { + "login": "abigailswallow", + "name": "abigailswallow", + "avatar_url": "https://avatars.githubusercontent.com/abigailswallow", + "profile": "https://github.com/abigailswallow", "contributions": [] }, { @@ -398,20 +398,6 @@ "profile": "https://github.com/happyappledog", "contributions": [] }, - { - "login": "emmanuel2406", - "name": "Emmanuel Rassou", - "avatar_url": "https://avatars.githubusercontent.com/emmanuel2406", - "profile": "https://github.com/emmanuel2406", - "contributions": [] - }, - { - "login": "ciyer64", - "name": "Curren Iyer", - "avatar_url": "https://avatars.githubusercontent.com/ciyer64", - "profile": "https://github.com/ciyer64", - "contributions": [] - }, { "login": "jessicaquaye", "name": "Jessica Quaye", @@ -426,13 +412,6 @@ "profile": "https://github.com/sjohri20", "contributions": [] }, - { - "login": "vijay-edu", - "name": "Vijay Edupuganti", - "avatar_url": "https://avatars.githubusercontent.com/vijay-edu", - "profile": "https://github.com/vijay-edu", - "contributions": [] - }, { "login": "skmur", "name": "Sonia Murthy", @@ -461,6 +440,13 @@ "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", "contributions": [] }, + { + "login": "Vijay Edupuganti", + "name": "Vijay Edupuganti", + "avatar_url": "https://www.gravatar.com/avatar/b15b6e0e9adf58099905c1a0fd474cb9?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [] + }, { "login": "Jothi Ramaswamy", "name": "Jothi Ramaswamy", @@ -475,6 +461,20 @@ "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", "contributions": [] }, + { + "login": "Curren Iyer", + "name": "Curren Iyer", + "avatar_url": "https://www.gravatar.com/avatar/bd53d146aa888548c8db4da02bf81e7a?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [] + }, + { + "login": "yanjingl", + "name": "yanjingl", + "avatar_url": "https://www.gravatar.com/avatar/f5d58ba6aa9b00189d4c018d370e8f43?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [] + }, { "login": "a-saraf", "name": "a-saraf", diff --git a/README.md b/README.md index 5c2e3035..a05a5301 100644 --- a/README.md +++ b/README.md @@ -95,89 +95,89 @@ This project follows the [all-contributors](https://allcontributors.org) specifi kai4avaya
kai4avaya

Elias Nuwara
Elias Nuwara

Jared Ping
Jared Ping

- Matthew Stewart
Matthew Stewart

Itai Shapira
Itai Shapira

+ Matthew Stewart
Matthew Stewart

Marcelo Rovai
Marcelo Rovai

Maximilian Lam
Maximilian Lam

Jayson Lin
Jayson Lin

jasonjabbour
jasonjabbour

- Sophia Cho
Sophia Cho

+ Andrea
Andrea

Jeffrey Ma
Jeffrey Ma

- Andrea
Andrea

+ Sophia Cho
Sophia Cho

Alex Rodriguez
Alex Rodriguez

Korneel Van den Berghe
Korneel Van den Berghe

- Zishen Wan
Zishen Wan

+ Colby Banbury
Colby Banbury

- Colby Banbury
Colby Banbury

+ Zishen Wan
Zishen Wan

Divya Amirtharaj
Divya Amirtharaj

- Srivatsan Krishnan
Srivatsan Krishnan

Abdulrahman Mahmoud
Abdulrahman Mahmoud

- arnaumarin
arnaumarin

+ Srivatsan Krishnan
Srivatsan Krishnan

+ Aghyad Deeb
Aghyad Deeb

Emeka Ezike
Emeka Ezike

- Aghyad Deeb
Aghyad Deeb

+ arnaumarin
arnaumarin

+ Jared Ni
Jared Ni

Sara Khosravi
Sara Khosravi

- Emil Njor
Emil Njor

Aditi Raju
Aditi Raju

- Jared Ni
Jared Ni

+ oishib
oishib

Michael Schnebly
Michael Schnebly

+ Emil Njor
Emil Njor

ELSuitorHarvard
ELSuitorHarvard

- oishib
oishib

- Yu-Shun Hsiao
Yu-Shun Hsiao

+ Mark Mazumder
Mark Mazumder

- Jae-Won Chung
Jae-Won Chung

+ Yu-Shun Hsiao
Yu-Shun Hsiao

Henry Bae
Henry Bae

- Mark Mazumder
Mark Mazumder

- Andrew Bass
Andrew Bass

+ Jae-Won Chung
Jae-Won Chung

+ Marco Zennaro
Marco Zennaro

eurashin
eurashin

+ Shvetank Prakash
Shvetank Prakash

+ Andrew Bass
Andrew Bass

Jennifer Zhou
Jennifer Zhou

Pong Trairatvorakul
Pong Trairatvorakul

- Marco Zennaro
Marco Zennaro

- Shvetank Prakash
Shvetank Prakash

Bruno Scaglione
Bruno Scaglione

Allen-Kuang
Allen-Kuang

- Alex Oesterling
Alex Oesterling

Gauri Jain
Gauri Jain

- Fin Amin
Fin Amin

Sercan Aygün
Sercan Aygün

+ Fin Amin
Fin Amin

+ gnodipac886
gnodipac886

- gnodipac886
gnodipac886

- abigailswallow
abigailswallow

+ Alex Oesterling
Alex Oesterling

Yang Zhou
Yang Zhou

- yanjingl
yanjingl

+ Emmanuel Rassou
Emmanuel Rassou

+ abigailswallow
abigailswallow

Jason Yik
Jason Yik

happyappledog
happyappledog

- Emmanuel Rassou
Emmanuel Rassou

- Curren Iyer
Curren Iyer

Jessica Quaye
Jessica Quaye

Shreya Johri
Shreya Johri

- - - Vijay Edupuganti
Vijay Edupuganti

Sonia Murthy
Sonia Murthy

The Random DIY
The Random DIY

- Costin-Andrei Oncescu
Costin-Andrei Oncescu

- Annie Laurie Cook
Annie Laurie Cook

+ Costin-Andrei Oncescu
Costin-Andrei Oncescu

+ Annie Laurie Cook
Annie Laurie Cook

+ Vijay Edupuganti
Vijay Edupuganti

Jothi Ramaswamy
Jothi Ramaswamy

Batur Arslan
Batur Arslan

+ + + Curren Iyer
Curren Iyer

+ yanjingl
yanjingl

a-saraf
a-saraf

songhan
songhan

Zishen
Zishen

diff --git a/contents/contributors.qmd b/contents/contributors.qmd index 7fafb5cc..2b24c107 100644 --- a/contents/contributors.qmd +++ b/contents/contributors.qmd @@ -83,89 +83,89 @@ We extend our sincere thanks to the diverse group of individuals who have genero kai4avaya
kai4avaya

Elias Nuwara
Elias Nuwara

Jared Ping
Jared Ping

- Matthew Stewart
Matthew Stewart

Itai Shapira
Itai Shapira

+ Matthew Stewart
Matthew Stewart

Marcelo Rovai
Marcelo Rovai

Maximilian Lam
Maximilian Lam

Jayson Lin
Jayson Lin

jasonjabbour
jasonjabbour

- Sophia Cho
Sophia Cho

+ Andrea
Andrea

Jeffrey Ma
Jeffrey Ma

- Andrea
Andrea

+ Sophia Cho
Sophia Cho

Alex Rodriguez
Alex Rodriguez

Korneel Van den Berghe
Korneel Van den Berghe

- Zishen Wan
Zishen Wan

+ Colby Banbury
Colby Banbury

- Colby Banbury
Colby Banbury

+ Zishen Wan
Zishen Wan

Divya Amirtharaj
Divya Amirtharaj

- Srivatsan Krishnan
Srivatsan Krishnan

Abdulrahman Mahmoud
Abdulrahman Mahmoud

- arnaumarin
arnaumarin

+ Srivatsan Krishnan
Srivatsan Krishnan

+ Aghyad Deeb
Aghyad Deeb

Emeka Ezike
Emeka Ezike

- Aghyad Deeb
Aghyad Deeb

+ arnaumarin
arnaumarin

+ Jared Ni
Jared Ni

Sara Khosravi
Sara Khosravi

- Emil Njor
Emil Njor

Aditi Raju
Aditi Raju

- Jared Ni
Jared Ni

+ oishib
oishib

Michael Schnebly
Michael Schnebly

+ Emil Njor
Emil Njor

ELSuitorHarvard
ELSuitorHarvard

- oishib
oishib

- Yu-Shun Hsiao
Yu-Shun Hsiao

+ Mark Mazumder
Mark Mazumder

- Jae-Won Chung
Jae-Won Chung

+ Yu-Shun Hsiao
Yu-Shun Hsiao

Henry Bae
Henry Bae

- Mark Mazumder
Mark Mazumder

- Andrew Bass
Andrew Bass

+ Jae-Won Chung
Jae-Won Chung

+ Marco Zennaro
Marco Zennaro

eurashin
eurashin

+ Shvetank Prakash
Shvetank Prakash

+ Andrew Bass
Andrew Bass

Jennifer Zhou
Jennifer Zhou

Pong Trairatvorakul
Pong Trairatvorakul

- Marco Zennaro
Marco Zennaro

- Shvetank Prakash
Shvetank Prakash

Bruno Scaglione
Bruno Scaglione

Allen-Kuang
Allen-Kuang

- Alex Oesterling
Alex Oesterling

Gauri Jain
Gauri Jain

- Fin Amin
Fin Amin

Sercan Aygün
Sercan Aygün

+ Fin Amin
Fin Amin

+ gnodipac886
gnodipac886

- gnodipac886
gnodipac886

- abigailswallow
abigailswallow

+ Alex Oesterling
Alex Oesterling

Yang Zhou
Yang Zhou

- yanjingl
yanjingl

+ Emmanuel Rassou
Emmanuel Rassou

+ abigailswallow
abigailswallow

Jason Yik
Jason Yik

happyappledog
happyappledog

- Emmanuel Rassou
Emmanuel Rassou

- Curren Iyer
Curren Iyer

Jessica Quaye
Jessica Quaye

Shreya Johri
Shreya Johri

- - - Vijay Edupuganti
Vijay Edupuganti

Sonia Murthy
Sonia Murthy

The Random DIY
The Random DIY

- Costin-Andrei Oncescu
Costin-Andrei Oncescu

- Annie Laurie Cook
Annie Laurie Cook

+ Costin-Andrei Oncescu
Costin-Andrei Oncescu

+ Annie Laurie Cook
Annie Laurie Cook

+ Vijay Edupuganti
Vijay Edupuganti

Jothi Ramaswamy
Jothi Ramaswamy

Batur Arslan
Batur Arslan

+ + + Curren Iyer
Curren Iyer

+ yanjingl
yanjingl

a-saraf
a-saraf

songhan
songhan

Zishen
Zishen

From 928fc86dd15794df0a52c26367372cdaffa1bff7 Mon Sep 17 00:00:00 2001 From: jasonjabbour Date: Thu, 22 Aug 2024 13:13:54 -0400 Subject: [PATCH 07/55] chapter 8 student feedback --- contents/efficient_ai/efficient_ai.qmd | 32 ++++++++++++++------------ 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/contents/efficient_ai/efficient_ai.qmd b/contents/efficient_ai/efficient_ai.qmd index 64c2c47e..0377ead5 100644 --- a/contents/efficient_ai/efficient_ai.qmd +++ b/contents/efficient_ai/efficient_ai.qmd @@ -26,9 +26,9 @@ Efficiency in artificial intelligence (AI) is not simply a luxury but a necessit - Appreciate the significance of numerics and their representations. -- We appreciate that we need to understand the nuances of model comparison beyond accuracy. +- Recognize that model comparison involves memory, computation, power, and speed, not just accuracy. -- Recognize efficiency encompasses technology, costs, environment, and ethics. +- Recognize efficiency encompasses technology, costs, and ethics. ::: @@ -36,19 +36,19 @@ The focus is on gaining a conceptual understanding of the motivations and signif ## Introduction -Training models can consume significant energy, sometimes equivalent to the carbon footprint of sizable industrial processes. We will cover some of these sustainability details in the [AI Sustainability](../sustainable_ai/sustainable_ai.qmd) chapter. On the deployment side, if these models are not optimized for efficiency, they can quickly drain device batteries, demand excessive memory, or fall short of real-time processing needs. Through this introduction, we aim to elucidate the nuances of efficiency, setting the groundwork for a comprehensive exploration in the subsequent chapters. +Training models can consume significant energy, sometimes equivalent to the carbon footprint of sizable industrial processes. We will cover some of these sustainability details in the [AI Sustainability](../sustainable_ai/sustainable_ai.qmd) chapter. On the deployment side, if these models are not optimized for efficiency, they can quickly drain device batteries, demand excessive memory, or fall short of real-time processing needs. Through this chapter, we aim to elucidate the nuances of efficiency, setting the groundwork for a comprehensive exploration in the subsequent chapters. ## The Need for Efficient AI -Efficiency takes on different connotations depending on where AI computations occur. Let's revisit and differentiate between Cloud, Edge, and TinyML in terms of efficiency. @fig-platforms provides a big picture comparison of the three different platforms. +Efficiency takes on different connotations depending on where AI computations occur. Let's revisit Cloud, Edge, and TinyML (as discussed in [ML Systems](../ml_systems/ml_systems.qmd)) and differentiate between them in terms of efficiency. @fig-platforms provides a big picture comparison of the three different platforms. ![Cloud, Mobile and TinyML. Source: @schizas2022tinyml.](https://www.mdpi.com/futureinternet/futureinternet-14-00363/article_deploy/html/images/futureinternet-14-00363-g001-550.jpg){#fig-platforms} -For cloud AI, traditional AI models often run in large-scale data centers equipped with powerful GPUs and TPUs [@barroso2019datacenter]. Here, efficiency pertains to optimizing computational resources, reducing costs, and ensuring timely data processing and return. However, relying on the cloud introduced latency, especially when dealing with large data streams that must be uploaded, processed, and downloaded. +**Cloud AI:** Traditional AI models often run in large-scale data centers equipped with powerful GPUs and TPUs [@barroso2019datacenter]. Here, efficiency pertains to optimizing computational resources, reducing costs, and ensuring timely data processing and return. However, relying on the cloud introduced latency, especially when dealing with large data streams that must be uploaded, processed, and downloaded. -For edge AI, edge computing brings AI closer to the data source, processing information directly on local devices like smartphones, cameras, or industrial machines [@li2019edge]. Here, efficiency encompasses quick real-time responses and reduced data transmission needs. The constraints, however, are tighter—these devices, while more powerful than microcontrollers, have limited computational power compared to cloud setups. +**Edge AI:** Edge computing brings AI closer to the data source, processing information directly on local devices like smartphones, cameras, or industrial machines [@li2019edge]. Here, efficiency encompasses quick real-time responses and reduced data transmission needs. The constraints, however, are tighter—these devices, while more powerful than microcontrollers, have limited computational power compared to cloud setups. -Pushing the frontier even further is TinyML, where AI models run on microcontrollers or extremely resource-constrained environments. The difference in processor and memory performance between TinyML and cloud or mobile systems can be several orders of magnitude [@warden2019tinyml]. Efficiency in TinyML is about ensuring models are lightweight enough to fit on these devices, use minimal energy (critical for battery-powered devices), and still perform their tasks effectively. +**TinyML:** TinyML pushes the boundaries by enabling AI models to run on microcontrollers or extremely resource-constrained environments. The difference in processor and memory performance between TinyML and cloud or mobile systems can be several orders of magnitude [@warden2019tinyml]. Efficiency in TinyML is about ensuring models are lightweight enough to fit on these devices, use minimal energy (critical for battery-powered devices), and still perform their tasks effectively. The spectrum from Cloud to TinyML represents a shift from vast, centralized computational resources to distributed, localized, and constrained environments. As we transition from one to the other, the challenges and strategies related to efficiency evolve, underlining the need for specialized approaches tailored to each scenario. Having underscored the need for efficient AI, especially within the context of TinyML, we will transition to exploring the methodologies devised to meet these challenges. The following sections outline the main concepts we will go deeper into later. We will demonstrate the breadth and depth of innovation needed to achieve efficient AI as we go into these strategies. @@ -66,11 +66,11 @@ Choosing the right model architecture is as crucial as optimizing it. In recent Model compression methods are very important for bringing deep learning models to devices with limited resources. These techniques reduce models' size, energy consumption, and computational demands without significantly losing accuracy. At a high level, the methods can briefly be binned into the following fundamental methods: -**Pruning:** This is akin to trimming the branches of a tree. This was first thought of in the [Optimal Brain Damage](https://proceedings.neurips.cc/paper/1989/file/6c9882bbac1c7093bd25041881277658-Paper.pdf) paper [@lecun1989optimal]. This was later popularized in the context of deep learning by @han2016deep. Certain weights or even entire neurons are removed from the network in pruning based on specific criteria. This can significantly reduce the model size. Various strategies include weight pruning, neuron pruning, and structured pruning. We will explore these in more detail in @sec-pruning. @fig-pruning is an examples of neural network pruning: removing some of the nodes in the inner layers (based on a specific criteria) reduces the numbers of edges between the nodes and, in turn, the size of the model. +**Pruning:** We've mentioned pruning a few times in previous chapters but have not yet formally introduced it. Pruning is similar to trimming the branches of a tree. This was first thought of in the [Optimal Brain Damage](https://proceedings.neurips.cc/paper/1989/file/6c9882bbac1c7093bd25041881277658-Paper.pdf) paper [@lecun1989optimal] and was later popularized in the context of deep learning by @han2016deep. Certain weights or even entire neurons are removed from the network in pruning based on specific criteria. This can significantly reduce the model size. Various strategies include weight pruning, neuron pruning, and structured pruning. We will explore these in more detail in @sec-pruning. @fig-pruning is an examples of neural network pruning, where removing some of the nodes in the inner layers (based on a specific criteria) reduces the numbers of edges and, in turn, the size of the model. ![Neural Network Pruning.](images/jpg/pruning.jpeg){#fig-pruning} -**Quantization:** quantization is the process of constraining an input from a large set to output in a smaller set, primarily in deep learning; this means reducing the number of bits that represent the weights and biases of the model. For example, using 16-bit or 8-bit representations instead of 32-bit can reduce the model size and speed up computations, with a minor trade-off in accuracy. We will explore these in more detail in @sec-quant. @fig-quantization shows an example of quantization by rounding to the closest number. The conversion from 32-bit floating point to 16-bit reduces the memory usage by 50%. And going from 32-bit to 8-bit Integer, memory is reduced by 75%. While the loss in numeric precision, and consequently model performance, is minor, the memory usage efficiency is very significant. +**Quantization:** Quantization is the process of constraining an input from a large set to output in a smaller set, primarily in deep learning; this means reducing the number of bits that represent the weights and biases of the model. For example, using 16-bit or 8-bit representations instead of 32-bit can reduce the model size and speed up computations, with a minor trade-off in accuracy. We will explore these in more detail in @sec-quant. @fig-quantization shows an example of quantization by rounding to the closest number. The conversion from 32-bit floating point to 16-bit reduces the memory usage by 50%. And going from 32-bit to 8-bit Integer, memory is reduced by 75%. While the loss in numeric precision, and consequently model performance, is minor, the memory usage efficiency is very significant. ![Different forms of quantization.](images/jpg/quantization.jpeg){#fig-quantization} @@ -78,19 +78,21 @@ Model compression methods are very important for bringing deep learning models t ## Efficient Inference Hardware -[Training](../training/training.qmd): An AI model is an intensive task that requires powerful hardware and can take hours to weeks, but inference needs to be as fast as possible, especially in real-time applications. This is where efficient inference hardware comes into play. We can achieve rapid response times and power-efficient operation by optimizing the hardware specifically for inference tasks, which is especially crucial for edge devices and embedded systems. +In the [Training](../training/training.qmd) chapter, we discussed the process of training AI models. Now, from an efficiency standpoint, it’s important to note that training is a resource and time-intensive task, often requiring powerful hardware and taking anywhere from hours to weeks to complete. Inference, on the other hand, needs to be as fast as possible, especially in real-time applications. This is where efficient inference hardware comes into play. We can achieve rapid response times and power-efficient operation by optimizing the hardware specifically for inference tasks, which is especially crucial for edge devices and embedded systems. **TPUs (Tensor Processing Units):** [TPUs](https://cloud.google.com/tpu) are custom-built ASICs (Application-Specific Integrated Circuits) by Google to accelerate machine learning workloads [@jouppi2017datacenter]. They are optimized for tensor operations, offering high throughput for low-precision arithmetic, and are designed specifically for neural network machine learning. TPUs significantly accelerate model training and inference compared to general-purpose GPU/CPUs. This boost means faster model training and real-time or near-real-time inference capabilities, which are crucial for applications like voice search and augmented reality. [Edge TPUs](https://cloud.google.com/edge-tpu) are a smaller, power-efficient version of Google's TPUs tailored for edge devices. They provide fast on-device ML inferencing for TensorFlow Lite models. Edge TPUs allow for low-latency, high-efficiency inference on edge devices like smartphones, IoT devices, and embedded systems. AI capabilities can be deployed in real-time applications without communicating with a central server, thus saving bandwidth and reducing latency. Consider the table in @fig-edge-tpu-perf. It shows the performance differences between running different models on CPUs versus a Coral USB accelerator. The Coral USB accelerator is an accessory by Google's Coral AI platform that lets developers connect Edge TPUs to Linux computers. Running inference on the Edge TPUs was 70 to 100 times faster than on CPUs. -![Accelerator vs CPU performance comparison. Source: [TensorFlow Blog.](https://blog.tensorflow.org/2019/03/build-ai-that-works-offline-with-coral.html)](images/png/tflite_edge_tpu_perf.png){#fig-edge-tpu-perf} +![Accelerator vs CPU performance comparison across different hardware configurations. \*Desktop CPU: 64-bit Intel(R) Xeon(R) E5–1650 v4 @ 3.60GHz. **Embedded CPU: Quad-core Cortex-A53 @ 1.5GHz, †Dev Board: Quad-core Cortex-A53 @ 1.5GHz + Edge TPU. Source: [TensorFlow Blog.](https://blog.tensorflow.org/2019/03/build-ai-that-works-offline-with-coral.html)](images/png/tflite_edge_tpu_perf.png){#fig-edge-tpu-perf} -**NN Accelerators:** Fixed-function neural network accelerators are hardware accelerators designed explicitly for neural network computations. They can be standalone chips or part of a larger system-on-chip (SoC) solution. By optimizing the hardware for the specific operations that neural networks require, such as matrix multiplications and convolutions, NN accelerators can achieve faster inference times and lower power consumption than general-purpose CPUs and GPUs. They are especially beneficial in TinyML devices with power or thermal constraints, such as smartwatches, micro-drones, or robotics. + + +**NN (Neural Network) Accelerators:** Fixed-function neural network accelerators are hardware accelerators designed explicitly for neural network computations. They can be standalone chips or part of a larger system-on-chip (SoC) solution. By optimizing the hardware for the specific operations that neural networks require, such as matrix multiplications and convolutions, NN accelerators can achieve faster inference times and lower power consumption than general-purpose CPUs and GPUs. They are especially beneficial in TinyML devices with power or thermal constraints, such as smartwatches, micro-drones, or robotics. But these are all but the most common examples. A number of other types of hardware are emerging that have the potential to offer significant advantages for inference. These include, but are not limited to, neuromorphic hardware, photonic computing, etc. In [@sec-aihw], we will explore these in greater detail. -Efficient hardware for inference speeds up the process, saves energy, extends battery life, and can operate in real-time conditions. As AI continues to be integrated into myriad applications- from smart cameras to voice assistants- the role of optimized hardware will only become more prominent. By leveraging these specialized hardware components, developers and engineers can bring the power of AI to devices and situations that were previously unthinkable. +Efficient hardware for inference speeds up the process, saves energy, extends battery life, and can operate in real-time conditions. As AI continues to be integrated into myriad applications, from smart cameras to voice assistants, the role of optimized hardware will only become more prominent. By leveraging these specialized hardware components, developers and engineers can bring the power of AI to devices and situations that were previously unthinkable. ## Efficient Numerics @@ -171,7 +173,7 @@ It's worth noting that the actual benefits and trade-offs can vary based on the A deep understanding of model evaluation methods is important to guide this process systematically. When assessing AI models' effectiveness and suitability for various applications, efficiency metrics come to the forefront. -**FLOPs (Floating Point Operations)** gauge a model's computational demands. For instance, a modern neural network like BERT has billions of FLOPs, which might be manageable on a powerful cloud server but would be taxing on a smartphone. Higher FLOPs can lead to more prolonged inference times and significant power drain, especially on devices without specialized hardware accelerators. Hence, for real-time applications such as video streaming or gaming, models with lower FLOPs might be more desirable. +**FLOPs (Floating Point Operations)**, as introduced in [Training](../training/training.html), gauge a model's computational demands. For instance, a modern neural network like BERT has billions of FLOPs, which might be manageable on a powerful cloud server but would be taxing on a smartphone. Higher FLOPs can lead to more prolonged inference times and significant power drain, especially on devices without specialized hardware accelerators. Hence, for real-time applications such as video streaming or gaming, models with lower FLOPs might be more desirable. **Memory Usage** pertains to how much storage the model requires, affecting both the deploying device's storage and RAM. Consider deploying a model onto a smartphone: a model that occupies several gigabytes of space not only consumes precious storage but might also be slower due to the need to load large weights into memory. This becomes especially crucial for edge devices like security cameras or drones, where minimal memory footprints are vital for storage and rapid data processing. @@ -187,7 +189,7 @@ The ecosystem contains an abundance of models, each boasting its unique strength Often, we encounter the delicate balance between accuracy and efficiency. For instance, while a dense, deep learning model and a lightweight MobileNet variant might excel in image classification, their computational demands could be at two extremes. This differentiation is especially pronounced when comparing deployments on resource-abundant cloud servers versus constrained TinyML devices. In many real-world scenarios, the marginal gains in accuracy could be overshadowed by the inefficiencies of a resource-intensive model. -Moreover, the optimal model choice is only sometimes universal but often depends on the specifics of an application. Consider object detection: a model that excels in general scenarios that might falter in niche environments, such as when detecting manufacturing defects on a factory floor. This adaptability- or the lack of it- can dictate a model's real-world utility. +Moreover, the optimal model choice is not always universal but often depends on the specifics of an application. For instance, a model that excels in general object detection scenarios might struggle in niche environments, such as detecting manufacturing defects on a factory floor. This adaptability- or the lack of it- can influence a model's real-world utility. Another important consideration is the relationship between model complexity and its practical benefits. Take voice-activated assistants, such as "Alexa" or "OK Google." While a complex model might demonstrate a marginally superior understanding of user speech if it's slower to respond than a simpler counterpart, the user experience could be compromised. Thus, adding layers or parameters only sometimes equates to better real-world outcomes. From 7afa2e67bc830cb623b635dff216139b0d666050 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Thu, 22 Aug 2024 15:52:59 -0400 Subject: [PATCH 08/55] Changed Credit -> Source in figures as all were updated to this. --- contents/efficient_ai/efficient_ai.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contents/efficient_ai/efficient_ai.qmd b/contents/efficient_ai/efficient_ai.qmd index d354e8be..d4b4e213 100644 --- a/contents/efficient_ai/efficient_ai.qmd +++ b/contents/efficient_ai/efficient_ai.qmd @@ -196,7 +196,7 @@ Another important consideration is the relationship between model complexity and Another important consideration is the relationship between model complexity and its practical benefits. Take voice-activated assistants like "Alexa" or "OK Google." While a complex model might demonstrate a marginally superior understanding of user speech if it's slower to respond than a simpler counterpart, the user experience could be compromised. Thus, adding layers or parameters only sometimes equates to better real-world outcomes. Furthermore, while benchmark datasets, such as ImageNet [@russakovsky2015imagenet], COCO [@lin2014microsoft], Visual Wake Words [@chowdhery2019visual], Google Speech Commands [@warden2018speech], etc. provide a standardized performance metric, they might not capture the diversity and unpredictability of real-world data. Two facial recognition models with similar benchmark scores might exhibit varied competencies when faced with diverse ethnic backgrounds or challenging lighting conditions. Such disparities underscore the importance of robustness and consistency across varied data. For example, @fig-stoves from the Dollar Street dataset shows stove images across extreme monthly incomes. Stoves have different shapes and technological levels across different regions and income levels. A model that is not trained on diverse datasets might perform well on a benchmark but fail in real-world applications. So, if a model was trained on pictures of stoves found in wealthy countries only, it would fail to recognize stoves from poorer regions. -![Different types of stoves. Credit: Dollar Street stove images.](images/jpg/quantization.jpeg){#fig-stoves} +![Different types of stoves. Source: Dollar Street stove images.](images/jpg/quantization.jpeg){#fig-stoves} In essence, a thorough comparative analysis transcends numerical metrics. It's a holistic assessment intertwined with real-world applications, costs, and the intricate subtleties that each model brings to the table. This is why having standard benchmarks and metrics widely established and adopted by the community becomes important. From 7318a59920874c15731c62f9e831405bee898a23 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Thu, 22 Aug 2024 16:01:01 -0400 Subject: [PATCH 09/55] The figure was pointing to an incorrect image. --- contents/efficient_ai/efficient_ai.qmd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contents/efficient_ai/efficient_ai.qmd b/contents/efficient_ai/efficient_ai.qmd index d4b4e213..5716c2ea 100644 --- a/contents/efficient_ai/efficient_ai.qmd +++ b/contents/efficient_ai/efficient_ai.qmd @@ -194,9 +194,10 @@ Moreover, the optimal model choice is not always universal but often depends on Another important consideration is the relationship between model complexity and its practical benefits. Take voice-activated assistants, such as "Alexa" or "OK Google." While a complex model might demonstrate a marginally superior understanding of user speech if it's slower to respond than a simpler counterpart, the user experience could be compromised. Thus, adding layers or parameters only sometimes equates to better real-world outcomes. Another important consideration is the relationship between model complexity and its practical benefits. Take voice-activated assistants like "Alexa" or "OK Google." While a complex model might demonstrate a marginally superior understanding of user speech if it's slower to respond than a simpler counterpart, the user experience could be compromised. Thus, adding layers or parameters only sometimes equates to better real-world outcomes. + Furthermore, while benchmark datasets, such as ImageNet [@russakovsky2015imagenet], COCO [@lin2014microsoft], Visual Wake Words [@chowdhery2019visual], Google Speech Commands [@warden2018speech], etc. provide a standardized performance metric, they might not capture the diversity and unpredictability of real-world data. Two facial recognition models with similar benchmark scores might exhibit varied competencies when faced with diverse ethnic backgrounds or challenging lighting conditions. Such disparities underscore the importance of robustness and consistency across varied data. For example, @fig-stoves from the Dollar Street dataset shows stove images across extreme monthly incomes. Stoves have different shapes and technological levels across different regions and income levels. A model that is not trained on diverse datasets might perform well on a benchmark but fail in real-world applications. So, if a model was trained on pictures of stoves found in wealthy countries only, it would fail to recognize stoves from poorer regions. -![Different types of stoves. Source: Dollar Street stove images.](images/jpg/quantization.jpeg){#fig-stoves} +![Different types of stoves. Source: Dollar Street stove images.](images/jpg/ds_stoves.jpg){#fig-stoves} In essence, a thorough comparative analysis transcends numerical metrics. It's a holistic assessment intertwined with real-world applications, costs, and the intricate subtleties that each model brings to the table. This is why having standard benchmarks and metrics widely established and adopted by the community becomes important. From 77057e4c60434a21278c96c7a6f5383dd3fb0a73 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Thu, 22 Aug 2024 16:03:06 -0400 Subject: [PATCH 10/55] Adding image --- contents/efficient_ai/images/jpg/ds_stoves.jpg | Bin 0 -> 44456 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 contents/efficient_ai/images/jpg/ds_stoves.jpg diff --git a/contents/efficient_ai/images/jpg/ds_stoves.jpg b/contents/efficient_ai/images/jpg/ds_stoves.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8076049863627c4b19693ee68220d01ec060630f GIT binary patch literal 44456 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 j&aJYKL# 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 Date: Thu, 22 Aug 2024 22:28:18 +0000 Subject: [PATCH 11/55] Update readme and contributors.qmd with contributors --- .all-contributorsrc | 36 ++++++++++++++++++------------------ README.md | 8 ++++---- contents/contributors.qmd | 8 ++++---- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index a41f6bb3..e144a117 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -42,10 +42,10 @@ "contributions": [] }, { - "login": "kai4avaya", - "name": "kai4avaya", - "avatar_url": "https://avatars.githubusercontent.com/kai4avaya", - "profile": "https://github.com/kai4avaya", + "login": "mpstewart1", + "name": "Matthew Stewart", + "avatar_url": "https://avatars.githubusercontent.com/mpstewart1", + "profile": "https://github.com/mpstewart1", "contributions": [] }, { @@ -55,6 +55,13 @@ "profile": "https://github.com/eliasab16", "contributions": [] }, + { + "login": "kai4avaya", + "name": "kai4avaya", + "avatar_url": "https://avatars.githubusercontent.com/kai4avaya", + "profile": "https://github.com/kai4avaya", + "contributions": [] + }, { "login": "JaredP94", "name": "Jared Ping", @@ -62,6 +69,13 @@ "profile": "https://github.com/JaredP94", "contributions": [] }, + { + "login": "jasonjabbour", + "name": "jasonjabbour", + "avatar_url": "https://avatars.githubusercontent.com/jasonjabbour", + "profile": "https://github.com/jasonjabbour", + "contributions": [] + }, { "login": "ishapira1", "name": "Itai Shapira", @@ -69,13 +83,6 @@ "profile": "https://github.com/ishapira1", "contributions": [] }, - { - "login": "mpstewart1", - "name": "Matthew Stewart", - "avatar_url": "https://avatars.githubusercontent.com/mpstewart1", - "profile": "https://github.com/mpstewart1", - "contributions": [] - }, { "login": "Mjrovai", "name": "Marcelo Rovai", @@ -97,13 +104,6 @@ "profile": "https://github.com/jaysonzlin", "contributions": [] }, - { - "login": "jasonjabbour", - "name": "jasonjabbour", - "avatar_url": "https://avatars.githubusercontent.com/jasonjabbour", - "profile": "https://github.com/jasonjabbour", - "contributions": [] - }, { "login": "sophiacho1", "name": "Sophia Cho", diff --git a/README.md b/README.md index 33edf7c0..9def7488 100644 --- a/README.md +++ b/README.md @@ -92,17 +92,17 @@ This project follows the [all-contributors](https://allcontributors.org) specifi shanzehbatool
shanzehbatool

- kai4avaya
kai4avaya

+ Matthew Stewart
Matthew Stewart

Elias Nuwara
Elias Nuwara

+ kai4avaya
kai4avaya

Jared Ping
Jared Ping

- Itai Shapira
Itai Shapira

- Matthew Stewart
Matthew Stewart

+ jasonjabbour
jasonjabbour

+ Itai Shapira
Itai Shapira

Marcelo Rovai
Marcelo Rovai

Maximilian Lam
Maximilian Lam

Jayson Lin
Jayson Lin

- jasonjabbour
jasonjabbour

Sophia Cho
Sophia Cho

diff --git a/contents/contributors.qmd b/contents/contributors.qmd index c4f3fe67..63bc104a 100644 --- a/contents/contributors.qmd +++ b/contents/contributors.qmd @@ -80,17 +80,17 @@ We extend our sincere thanks to the diverse group of individuals who have genero shanzehbatool
shanzehbatool

- kai4avaya
kai4avaya

+ Matthew Stewart
Matthew Stewart

Elias Nuwara
Elias Nuwara

+ kai4avaya
kai4avaya

Jared Ping
Jared Ping

- Itai Shapira
Itai Shapira

- Matthew Stewart
Matthew Stewart

+ jasonjabbour
jasonjabbour

+ Itai Shapira
Itai Shapira

Marcelo Rovai
Marcelo Rovai

Maximilian Lam
Maximilian Lam

Jayson Lin
Jayson Lin

- jasonjabbour
jasonjabbour

Sophia Cho
Sophia Cho

From 8708de77a27c91b05029288d4cb93f30d29224a5 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Fri, 23 Aug 2024 06:19:38 -0400 Subject: [PATCH 12/55] Incomplete sentence fix --- contents/hw_acceleration/hw_acceleration.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contents/hw_acceleration/hw_acceleration.qmd b/contents/hw_acceleration/hw_acceleration.qmd index f832f7eb..77761964 100644 --- a/contents/hw_acceleration/hw_acceleration.qmd +++ b/contents/hw_acceleration/hw_acceleration.qmd @@ -407,7 +407,7 @@ The recent groundbreaking research conducted by OpenAI [@brown2020language] with ### Central Processing Units (CPUs) -The term CPUs has a long history that dates back to 1955 [@weik1955survey] while the first microprocessor CPU-the Intel 4004-was invented in 1971 ([Who Invented the Microprocessor?](https://computerhistory.org/blog/who-invented-the-microprocessor/)). Compilers compile high-level programming languages like Python, Java, or C to assemble instructions (x86, ARM, RISC-V, etc.) for CPUs to process. The set of instructions a CPU understands is called the "instruction set." It must be agreed upon by both the hardware and software running atop it (See section 5 for a more in-depth description of instruction set architectures-ISAs). +The term CPUs has a long history that dates back to 1955 [@weik1955survey] while the first microprocessor CPU-the Intel 4004-was invented in 1971 ([Who Invented the Microprocessor?](https://computerhistory.org/blog/who-invented-the-microprocessor/)). Compilers compile high-level programming languages like Python, Java, or C to assemble instructions (x86, ARM, RISC-V, etc.) for CPUs to process. The set of instructions a CPU understands is called the "instruction set architecture" (ISA), which defines the commands that the processor can execute directly. It must be agreed upon by both the hardware and software running atop it (See section 5 for a more in-depth description of instruction set architectures-ISAs). An overview of significant developments in CPUs: From 192e20775c8d0ea59fccad563150087f85ceac8a Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Fri, 23 Aug 2024 10:42:43 -0400 Subject: [PATCH 13/55] Minor writing style change --- index.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.qmd b/index.qmd index acd65645..ac374c1f 100644 --- a/index.qmd +++ b/index.qmd @@ -6,7 +6,7 @@ Welcome to {{< var title.long >}}. This book is your gateway to the fast-paced w ``` -We aim to make this open-source book a collaborative effort that brings together insights from students, professionals, and the broader community of AI practitioners. We want to create a one-stop guide that dives deep into the nuts and bolts of AI systems and their many applications. +We have created this open-source book as a collaborative effort to bring together insights from students, professionals, and the broader community of AI practitioners. Our goal is to develop a comprehensive guide that delves deep into the intricacies of AI systems and their numerous applications. > "If you want to go fast, go alone. If you want to go far, go together." > -- African Proverb From c87a1d11bb5f821968651cea88a1d8abc4846c3d Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Sat, 24 Aug 2024 21:11:42 -0500 Subject: [PATCH 14/55] Fixed duplicate title --- contents/hw_acceleration/hw_acceleration.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contents/hw_acceleration/hw_acceleration.qmd b/contents/hw_acceleration/hw_acceleration.qmd index 77761964..e7982639 100644 --- a/contents/hw_acceleration/hw_acceleration.qmd +++ b/contents/hw_acceleration/hw_acceleration.qmd @@ -819,7 +819,7 @@ Chiplets are interconnected using advanced packaging techniques like high-densit Some key advantages of using chiplets for AI include: -* **Flexibility:** Flexibility: Chiplets allow for the combination of different chip types, process nodes, and memories tailored for each function. This is more modular versus a fixed wafer-scale design. +* **Flexibility:** Chiplets allow for the combination of different chip types, process nodes, and memories tailored for each function. This is more modular versus a fixed wafer-scale design. * **Yield:** Smaller chiplets have a higher yield than a gigantic wafer-scale chip. Defects are contained in individual chiplets. * **Cost:** Leverages existing manufacturing capabilities versus requiring specialized new processes. Reduces costs by reusing mature fabrication. * **Compatibility:** Can integrate with more conventional system architectures like PCIe and standard DDR memory interfaces. From 6c7810ca13344b8bb5c586807b64d79d94f0dcb3 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Sat, 24 Aug 2024 21:16:31 -0500 Subject: [PATCH 15/55] Fixed error in formatting --- contents/efficient_ai/efficient_ai.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contents/efficient_ai/efficient_ai.qmd b/contents/efficient_ai/efficient_ai.qmd index 5716c2ea..98f6b18c 100644 --- a/contents/efficient_ai/efficient_ai.qmd +++ b/contents/efficient_ai/efficient_ai.qmd @@ -86,7 +86,7 @@ In the [Training](../training/training.qmd) chapter, we discussed the process of [Edge TPUs](https://cloud.google.com/edge-tpu) are a smaller, power-efficient version of Google's TPUs tailored for edge devices. They provide fast on-device ML inferencing for TensorFlow Lite models. Edge TPUs allow for low-latency, high-efficiency inference on edge devices like smartphones, IoT devices, and embedded systems. AI capabilities can be deployed in real-time applications without communicating with a central server, thus saving bandwidth and reducing latency. Consider the table in @fig-edge-tpu-perf. It shows the performance differences between running different models on CPUs versus a Coral USB accelerator. The Coral USB accelerator is an accessory by Google's Coral AI platform that lets developers connect Edge TPUs to Linux computers. Running inference on the Edge TPUs was 70 to 100 times faster than on CPUs. -![Accelerator vs CPU performance comparison across different hardware configurations. \*Desktop CPU: 64-bit Intel(R) Xeon(R) E5–1650 v4 @ 3.60GHz. **Embedded CPU: Quad-core Cortex-A53 @ 1.5GHz, †Dev Board: Quad-core Cortex-A53 @ 1.5GHz + Edge TPU. Source: [TensorFlow Blog.](https://blog.tensorflow.org/2019/03/build-ai-that-works-offline-with-coral.html)](images/png/tflite_edge_tpu_perf.png){#fig-edge-tpu-perf} +![Accelerator vs CPU performance comparison across different hardware configurations. Desktop CPU: 64-bit Intel(R) Xeon(R) E5–1650 v4 @ 3.60GHz. Embedded CPU: Quad-core Cortex-A53 @ 1.5GHz, †Dev Board: Quad-core Cortex-A53 @ 1.5GHz + Edge TPU. Source: [TensorFlow Blog.](https://blog.tensorflow.org/2019/03/build-ai-that-works-offline-with-coral.html)](images/png/tflite_edge_tpu_perf.png){#fig-edge-tpu-perf} From 697472dfbacdf8581cf9753c36f52e158a990511 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Sat, 24 Aug 2024 21:25:13 -0500 Subject: [PATCH 16/55] Fixed erroneous hypens --- contents/hw_acceleration/hw_acceleration.qmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contents/hw_acceleration/hw_acceleration.qmd b/contents/hw_acceleration/hw_acceleration.qmd index 77761964..fccdb2e2 100644 --- a/contents/hw_acceleration/hw_acceleration.qmd +++ b/contents/hw_acceleration/hw_acceleration.qmd @@ -1004,8 +1004,8 @@ The key benefits of applying ML to simulation and verification are faster design A key goal is designing hardware architectures optimized for performance, power, and efficiency. ML introduces new techniques to automate and improve architecture design space exploration for general-purpose and specialized hardware like ML accelerators. Some promising examples include: * **Architecture search for hardware:** Search techniques like evolutionary algorithms [@kao2020gamma], Bayesian optimization (@reagen2017case, @bhardwaj2020comprehensive), reinforcement learning (@kao2020confuciux, @krishnan2022multiagent) can automatically generate novel hardware architectures by mutating and mixing design attributes like cache size, number of parallel units, memory bandwidth, and so on. This allows for efficient navigation of large design spaces. -* **Predictive modeling for optimization:** - ML models can be trained to predict hardware performance, power, and efficiency metrics for a given architecture. These become "surrogate models" [@krishnan2023archgym] for fast optimization and space exploration by substituting lengthy simulations. -* **Specialized accelerator optimization:** - For specialized chips like tensor processing units for AI, automated architecture search techniques based on ML algorithms [@zhang2022fullstack] show promise for finding fast, efficient designs. +* **Predictive modeling for optimization:** ML models can be trained to predict hardware performance, power, and efficiency metrics for a given architecture. These become "surrogate models" [@krishnan2023archgym] for fast optimization and space exploration by substituting lengthy simulations. +* **Specialized accelerator optimization:** For specialized chips like tensor processing units for AI, automated architecture search techniques based on ML algorithms [@zhang2022fullstack] show promise for finding fast, efficient designs. The benefits of using ML include superior design space exploration, automated optimization, and reduced manual effort. Challenges include long training times for some techniques and local optima limitations. However, ML for hardware architecture holds great potential for unlocking performance and efficiency gains. @@ -1017,7 +1017,7 @@ Once a hardware design is complete, it moves to manufacturing. However, variabil * **Process optimization:** Supervised learning models can be trained on process data to identify factors that lead to low yields. The models can then optimize parameters to improve yields, throughput, or consistency. * **Yield prediction:** By analyzing test data from fabricated designs using techniques like regression trees, ML models can predict yields early in production, allowing process adjustments. * **Defect detection:** Computer vision ML techniques can be applied to images of designs to identify defects invisible to the human eye. This enables precision quality control and root cause analysis. -* **Proactive failure analysis:** - ML models can help predict, diagnose, and prevent issues that lead to downstream defects and failures by analyzing structured and unstructured process data. +* **Proactive failure analysis:** ML models can help predict, diagnose, and prevent issues that lead to downstream defects and failures by analyzing structured and unstructured process data. Applying ML to manufacturing enables process optimization, real-time quality control, predictive maintenance, and higher yields. Challenges include managing complex manufacturing data and variations. But ML is poised to transform semiconductor manufacturing. From fb2c4261dd1a54a679c9fd8ed71b8e801c2a1adb Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Sat, 24 Aug 2024 21:40:44 -0500 Subject: [PATCH 17/55] Adding "Thanks" too There are people who are generously contributing feedback in the form of GitHub issues but they aren't filing PRs. I want to acknowledge them as well cause they are critical to improving the material. --- contents/contributors.qmd | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contents/contributors.qmd b/contents/contributors.qmd index 63bc104a..8e50cd05 100644 --- a/contents/contributors.qmd +++ b/contents/contributors.qmd @@ -2,10 +2,9 @@ comments: false --- -# Contributors {.unnumbered} - -We extend our sincere thanks to the diverse group of individuals who have generously contributed their expertise, insights, and time to improve both the content and codebase of this project. Below you will find a list of all contributors. If you would like to contribute to this project, please see our [GitHub](https://github.com/harvard-edge/cs249r_book) page. +# Contributors & Thanks {.unnumbered} +We extend our sincere thanks to the diverse group of individuals who have generously contributed their expertise, insights, time, and support to improve both the content and codebase of this project. This includes not only those who have directly contributed through code and writing but also those who have helped by identifying issues, providing feedback, and offering suggestions. Below, you will find a list of all contributors. If you would like to contribute to this project, please visit our [GitHub](https://github.com/harvard-edge/cs249r_book) page for more information.