diff --git a/_quarto.yml b/_quarto.yml index d1379c2b..e0df9502 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -159,6 +159,7 @@ book: - contents/labs/raspi/image_classification/image_classification.qmd - contents/labs/raspi/object_detection/object_detection.qmd - contents/labs/raspi/llm/llm.qmd + - contents/labs/raspi/vlm/vlm.qmd - part: contents/labs/shared/shared.qmd chapters: - contents/labs/shared/kws_feature_eng/kws_feature_eng.qmd diff --git a/contents/labs/overview.qmd b/contents/labs/overview.qmd index 970e1ebd..37886df6 100644 --- a/contents/labs/overview.qmd +++ b/contents/labs/overview.qmd @@ -40,21 +40,23 @@ We have included laboratory materials for three key devices that represent diffe * XIAO ESP32S3: A versatile, compact board suitable for keyword spotting and motion detection tasks. * Raspberry Pi: A flexible platform for more computationally intensive tasks, including small language models and various classification and detection applications. -+----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ -| Exercise | [Nicla Vision](https://store.arduino.cc/products/nicla-vision) | [XIAO ESP32S3](https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/) | [Raspberry Pi](https://www.raspberrypi.com/) | -+:===========================+:===============================================================+:===========================================================================+:=============================================+ -| Installation & Setup | ✓ | ✓ | ✓ | -+----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ -| Keyword Spotting (KWS) | ✓ | ✓ | | -+----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ -| Image Classification | ✓ | ✓ | ✓ | -+----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ -| Object Detection | ✓ | ✓ | ✓ | -+----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ -| Motion Detection | ✓ | ✓ | | -+----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ -| Small Language Models (SLM)| | | ✓ | -+----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ ++-----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ +| Exercise | [Nicla Vision](https://store.arduino.cc/products/nicla-vision) | [XIAO ESP32S3](https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/) | [Raspberry Pi](https://www.raspberrypi.com/) | ++:============================+:==============================================================:+:==========================================================================:+:============================================:+ +| Installation & Setup | ✓ | ✓ | ✓ | ++-----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ +| Keyword Spotting (KWS) | ✓ | ✓ | | ++-----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ +| Image Classification | ✓ | ✓ | ✓ | ++-----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ +| Object Detection | ✓ | ✓ | ✓ | ++-----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ +| Motion Detection | ✓ | ✓ | | ++-----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ +| Small Language Models (SLM) | | | ✓ | ++-----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ +| Vision Language Models (VLM)| | | ✓ | ++-----------------------------+----------------------------------------------------------------+----------------------------------------------------------------------------+----------------------------------------------+ ## Lab Structure diff --git a/contents/labs/raspi/raspi.qmd b/contents/labs/raspi/raspi.qmd index 2e6dfe95..dade54bb 100644 --- a/contents/labs/raspi/raspi.qmd +++ b/contents/labs/raspi/raspi.qmd @@ -6,7 +6,7 @@ These labs offer invaluable hands-on experience with machine learning systems, l ## Pre-requisites -- **Raspberry Pi**: Ensure you have at least one of the boards: the Raspberry Pi Zero 2W, Raspberry Pi 4 or 5 for the Vision Labs, and the Raspberry 5 for the GenAi lab. +- **Raspberry Pi**: Ensure you have at least one of the boards: the Raspberry Pi Zero 2W, Raspberry Pi 4 or 5 for the Vision Labs, and the Raspberry 5 for the GenAi labs. - **Power Adapter**: To Power on the boards. - Raspberry Pi Zero 2-W: 2.5W with a Micro-USB adapter - Raspberry Pi 4 or 5: 3.5W with a USB-C adapter @@ -20,10 +20,14 @@ These labs offer invaluable hands-on experience with machine learning systems, l ## Exercises -| **Modality** | **Task** | **Description** | **Link** | -| ------------ | --------------------- | -------------------------- | ------------------------------------------------------- | -| Vision | Image Classification | Learn to classify images | [Link](./image_classification/image_classification.qmd) | -| Vision | Object Detection | Implement object detection | [Link](./object_detection/object_detection.qmd) | -| GenAI | Small Language Models | Deploy SLMs at the Edge | [Link](./llm/llm.qmd) | -| | | | | - ++--------------+------------------------+----------------------------+---------------------------------------------------------+ +| **Modality** | **Task** | **Description** | **Link** | ++:=============+:=======================+:===========================+:========================================================+ +| Vision | Image Classification | Learn to classify images | [Link](./image_classification/image_classification.qmd) | ++--------------+------------------------+----------------------------+---------------------------------------------------------+ +| Vision | Object Detection | Implement object detection | [Link](./object_detection/object_detection.qmd) | ++--------------+------------------------+----------------------------+---------------------------------------------------------+ +| GenAI | Small Language Models | Deploy SLMs at the Edge | [Link](./llm/llm.qmd) | ++--------------+------------------------+----------------------------+---------------------------------------------------------+ +| GenAI | Visual-Language Models | Deploy VLMs at the Edge | [Link](./vlm/vlm.qmd) | ++--------------+------------------------+----------------------------+---------------------------------------------------------+ \ No newline at end of file diff --git a/contents/labs/raspi/vlm/images/jpeg/cover.jpg b/contents/labs/raspi/vlm/images/jpeg/cover.jpg new file mode 100644 index 00000000..5d64e4dd Binary files /dev/null and b/contents/labs/raspi/vlm/images/jpeg/cover.jpg differ diff --git a/contents/labs/raspi/vlm/images/jpeg/florence-diagr.jpg b/contents/labs/raspi/vlm/images/jpeg/florence-diagr.jpg new file mode 100644 index 00000000..fbcfd244 Binary files /dev/null and b/contents/labs/raspi/vlm/images/jpeg/florence-diagr.jpg differ diff --git a/contents/labs/raspi/vlm/images/jpeg/htop.jpg b/contents/labs/raspi/vlm/images/jpeg/htop.jpg new file mode 100644 index 00000000..3f30a292 Binary files /dev/null and b/contents/labs/raspi/vlm/images/jpeg/htop.jpg differ diff --git a/contents/labs/raspi/vlm/images/jpeg/raspi5-active-cooler.jpg b/contents/labs/raspi/vlm/images/jpeg/raspi5-active-cooler.jpg new file mode 100644 index 00000000..2c69812a Binary files /dev/null and b/contents/labs/raspi/vlm/images/jpeg/raspi5-active-cooler.jpg differ diff --git a/contents/labs/raspi/vlm/images/png/Dataset_FLD-5B.png b/contents/labs/raspi/vlm/images/png/Dataset_FLD-5B.png new file mode 100644 index 00000000..2f6bf8d8 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/Dataset_FLD-5B.png differ diff --git a/contents/labs/raspi/vlm/images/png/arch.png b/contents/labs/raspi/vlm/images/png/arch.png new file mode 100644 index 00000000..f9bb96aa Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/arch.png differ diff --git a/contents/labs/raspi/vlm/images/png/caption-boxes.png b/contents/labs/raspi/vlm/images/png/caption-boxes.png new file mode 100644 index 00000000..14fedc59 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/caption-boxes.png differ diff --git a/contents/labs/raspi/vlm/images/png/caption_ground.png b/contents/labs/raspi/vlm/images/png/caption_ground.png new file mode 100644 index 00000000..42c1a600 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/caption_ground.png differ diff --git a/contents/labs/raspi/vlm/images/png/cascade.png b/contents/labs/raspi/vlm/images/png/cascade.png new file mode 100644 index 00000000..6bc0a430 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/cascade.png differ diff --git a/contents/labs/raspi/vlm/images/png/dog_bottle_seg.png b/contents/labs/raspi/vlm/images/png/dog_bottle_seg.png new file mode 100644 index 00000000..ae8e7967 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/dog_bottle_seg.png differ diff --git a/contents/labs/raspi/vlm/images/png/fine-tuning.png b/contents/labs/raspi/vlm/images/png/fine-tuning.png new file mode 100644 index 00000000..900afff6 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/fine-tuning.png differ diff --git a/contents/labs/raspi/vlm/images/png/flyer.png b/contents/labs/raspi/vlm/images/png/flyer.png new file mode 100644 index 00000000..383afaf3 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/flyer.png differ diff --git a/contents/labs/raspi/vlm/images/png/fusca.png b/contents/labs/raspi/vlm/images/png/fusca.png new file mode 100644 index 00000000..55876512 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/fusca.png differ diff --git a/contents/labs/raspi/vlm/images/png/htop.png b/contents/labs/raspi/vlm/images/png/htop.png new file mode 100644 index 00000000..46f506d4 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/htop.png differ diff --git a/contents/labs/raspi/vlm/images/png/img_test.png b/contents/labs/raspi/vlm/images/png/img_test.png new file mode 100644 index 00000000..2b39fbba Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/img_test.png differ diff --git a/contents/labs/raspi/vlm/images/png/jupyter.png b/contents/labs/raspi/vlm/images/png/jupyter.png new file mode 100644 index 00000000..0f3e08e8 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/jupyter.png differ diff --git a/contents/labs/raspi/vlm/images/png/od_caption_cat_dog_table.png b/contents/labs/raspi/vlm/images/png/od_caption_cat_dog_table.png new file mode 100644 index 00000000..6f1c6e15 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/od_caption_cat_dog_table.png differ diff --git a/contents/labs/raspi/vlm/images/png/od_cat_dogs.png b/contents/labs/raspi/vlm/images/png/od_cat_dogs.png new file mode 100644 index 00000000..ebeb9dfc Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/od_cat_dogs.png differ diff --git a/contents/labs/raspi/vlm/images/png/od_table.png b/contents/labs/raspi/vlm/images/png/od_table.png new file mode 100644 index 00000000..bf6f017a Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/od_table.png differ diff --git a/contents/labs/raspi/vlm/images/png/open_vacab_exemples.png b/contents/labs/raspi/vlm/images/png/open_vacab_exemples.png new file mode 100644 index 00000000..30e18f8c Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/open_vacab_exemples.png differ diff --git a/contents/labs/raspi/vlm/images/png/orange_seg.png b/contents/labs/raspi/vlm/images/png/orange_seg.png new file mode 100644 index 00000000..7e64c23a Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/orange_seg.png differ diff --git a/contents/labs/raspi/vlm/images/png/output_ocr.png b/contents/labs/raspi/vlm/images/png/output_ocr.png new file mode 100644 index 00000000..2e4b719f Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/output_ocr.png differ diff --git a/contents/labs/raspi/vlm/images/png/result_test.png b/contents/labs/raspi/vlm/images/png/result_test.png new file mode 100644 index 00000000..771f1f23 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/result_test.png differ diff --git a/contents/labs/raspi/vlm/images/png/ssh.png b/contents/labs/raspi/vlm/images/png/ssh.png new file mode 100644 index 00000000..68362be8 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/ssh.png differ diff --git a/contents/labs/raspi/vlm/images/png/test-pytorch.png b/contents/labs/raspi/vlm/images/png/test-pytorch.png new file mode 100644 index 00000000..4f1aaf68 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/test-pytorch.png differ diff --git a/contents/labs/raspi/vlm/images/png/wine_glass.png b/contents/labs/raspi/vlm/images/png/wine_glass.png new file mode 100644 index 00000000..f5ce0679 Binary files /dev/null and b/contents/labs/raspi/vlm/images/png/wine_glass.png differ diff --git a/contents/labs/raspi/vlm/vlm.qmd b/contents/labs/raspi/vlm/vlm.qmd new file mode 100644 index 00000000..745fc14c --- /dev/null +++ b/contents/labs/raspi/vlm/vlm.qmd @@ -0,0 +1,1194 @@ +# Vision-Language Models (VLM) {.unnumbered} + +![*DALL·E prompt - A Raspberry Pi setup featuring vision tasks. The image shows a Raspberry Pi connected to a camera, with various computer vision tasks displayed visually around it, including object detection, image captioning, segmentation, and visual grounding. The Raspberry Pi is placed on a desk, with a display showing bounding boxes and annotations related to these tasks. The background should be a home workspace, with tools and devices typically used by developers and hobbyists.*](images/jpeg/cover.jpg) + +## Introduction + +In this hands-on lab, we will continuously explore AI applications at the Edge, from the basic setup of the Florence-2, Microsoft's state-of-the-art vision foundation model, to advanced implementations on devices like the Raspberry Pi. We will learn to use Vision-Languageor Models (VLMs) for tasks such as captioning, object detection, grounding, segmentation, and OCR on a Raspberry Pi. + +### Why Florence-2 at the Edge? + +[Florence-2](https://arxiv.org/abs/2311.06242) is a vision-language model open-sourced by Microsoft under the MIT license, which significantly advances vision-language models by combining a lightweight architecture with robust capabilities. Thanks to its training on the massive FLD-5B dataset, which contains 126 million images and 5.4 billion visual annotations, it achieves performance comparable to larger models. This makes Florence-2 ideal for deployment at the edge, where power and computational resources are limited. + +In this tutorial, we will explore how to use Florence-2 for real-time computer vision applications, such as: + +- Image captioning +- Object detection +- Segmentation +- Visual grounding + +> **Visual grounding** involves linking textual descriptions to specific regions within an image. This enables the model to understand where particular objects or entities described in a prompt are in the image. For example, if the prompt is "a red car," the model will identify and highlight the region where the red car is found in the image. Visual grounding is helpful for applications where precise alignment between text and visual content is needed, such as human-computer interaction, image annotation, and interactive AI systems. + +In the tutorial, we will walk through: + +- Setting up Florence-2 on the Raspberry Pi +- Running inference tasks such as object detection and captioning +- Optimizing the model to get the best performance from the edge device +- Exploring practical, real-world applications with fine-tuning. + +### Florence-2 Model Architecture + +Florence-2 utilizes a unified, prompt-based representation to handle various vision-language tasks. The model architecture consists of two main components: an **image encoder** and a **multi-modal transformer encoder-decoder**. + +![](images/jpeg/florence-diagr.jpg) + + + +- **Image Encoder**: The image encoder is based on the [DaViT (Dual Attention Vision Transformers) architecture](https://arxiv.org/abs/2204.03645). It converts input images into a series of visual token embeddings. These embeddings serve as the foundational representations of the visual content, capturing both spatial and contextual information about the image. + +- **Multi-Modal Transformer Encoder-Decoder**: Florence-2's core is the multi-modal transformer encoder-decoder, which combines visual token embeddings from the image encoder with textual embeddings generated by a BERT-like model. This combination allows the model to simultaneously process visual and textual inputs, enabling a unified approach to tasks such as image captioning, object detection, and segmentation. + +The model's training on the extensive FLD-5B dataset ensures it can effectively handle diverse vision tasks without requiring task-specific modifications. Florence-2 uses textual prompts to activate specific tasks, making it highly flexible and capable of zero-shot generalization. For tasks like object detection or visual grounding, the model incorporates additional location tokens to represent regions within the image, ensuring a precise understanding of spatial relationships. + +> Florence-2's compact architecture and innovative training approach allow it to perform computer vision tasks accurately, even on resource-constrained devices like the Raspberry Pi. + +## Technical Overview + +Florence-2 introduces several innovative features that set it apart: + +### Architecture + +![](images/png/arch.png) + +- **Lightweight Design**: Two variants available + - Florence-2-Base: 232 million parameters + - Florence-2-Large: 771 million parameters +- **Unified Representation**: Handles multiple vision tasks through a single architecture +- **DaViT Vision Encoder**: Converts images into visual token embeddings +- **Transformer-based Multi-modal Encoder-Decoder**: Processes combined visual and text embeddings + +### Training Dataset (FLD-5B) + +![](images/png/Dataset_FLD-5B.png) + +- 126 million unique images +- 5.4 billion comprehensive annotations, including: + - 500M text annotations + - 1.3B region-text annotations + - 3.6B text-phrase-region annotations +- Automated annotation pipeline using specialist models +- Iterative refinement process for high-quality labels + +### Key Capabilities + +Florence-2 excels in multiple vision tasks: + +#### Zero-shot Performance + +- Image Captioning: Achieves 135.6 CIDEr score on COCO +- Visual Grounding: 84.4% recall@1 on Flickr30k +- Object Detection: 37.5 mAP on COCO val2017 +- Referring Expression: 67.0% accuracy on RefCOCO + +#### Fine-tuned Performance + +- Competitive with specialist models despite the smaller size +- Outperforms larger models in specific benchmarks +- Efficient adaptation to new tasks + +### Practical Applications + +Florence-2 can be applied across various domains: + +1. **Content Understanding** + - Automated image captioning for accessibility + - Visual content moderation + - Media asset management + +2. **E-commerce** + - Product image analysis + - Visual search + - Automated product tagging + +3. **Healthcare** + - Medical image analysis + - Diagnostic assistance + - Research data processing + +4. **Security & Surveillance** + - Object detection and tracking + - Anomaly detection + - Scene understanding + +### Comparing Florence-2 with other VLMs + +Florence-2 stands out from other visual language models due to its impressive zero-shot capabilities. Unlike models like [Google PaliGemma](https://huggingface.co/blog/paligemma), which rely on extensive fine-tuning to adapt to various tasks, Florence-2 works right out of the box, as we will see in this lab. It can also compete with larger models like GPT-4V and Flamingo, which often have many more parameters but only sometimes match Florence-2's performance. For example, Florence-2 achieves better zero-shot results than Kosmos-2 despite having over twice the parameters. + +In benchmark tests, Florence-2 has shown remarkable performance in tasks like COCO captioning and referring expression comprehension. It outperformed models like PolyFormer and UNINEXT in object detection and segmentation tasks on the [COCO dataset](https://docs.ultralytics.com/datasets/detect/coco/). It is a highly competitive choice for real-world applications where both performance and resource efficiency are crucial. + +## Setup and Installation + +Our choice of edge device is the Raspberry Pi 5 (Raspi-5). Its robust platform is equipped with the Broadcom BCM2712, a 2.4GHz quad-core 64-bit Arm Cortex-A76 CPU featuring Cryptographic Extension and enhanced caching capabilities. It boasts a VideoCore VII GPU, dual 4Kp60 HDMI® outputs with HDR, and a 4Kp60 HEVC decoder. Memory options include 4GB and 8GB of high-speed LPDDR4X SDRAM, with 8GB being our choice to run Florence-2. It also features expandable storage via a microSD card slot and a PCIe 2.0 interface for fast peripherals such as M.2 SSDs (Solid State Drives). + +> For real applications, SSDs are a better option than SD cards. + +We suggest installing an Active Cooler, a dedicated clip-on cooling solution for Raspberry Pi 5 (Raspi-5), for this lab. It combines an aluminum heatsink with a temperature-controlled blower fan to keep the Raspi-5 operating comfortably under heavy loads, such as running Florense-2. + +![](images/jpeg/raspi5-active-cooler.jpg) + +### Environment configuration + +To run [Microsoft Florense-2](https://huggingface.co/microsoft/Florence-2-base) on the Raspberry Pi 5, we'll need a few libraries: + +1. **[Transformers](https://huggingface.co/docs/transformers/en/index)**: + - Florence-2 uses the `transformers` library from Hugging Face for model loading and inference. This library provides the architecture for working with pre-trained vision-language models, making it easy to perform tasks like image captioning, object detection, and more. Essentially, `transformers` helps in interacting with the model, processing input prompts, and obtaining outputs. + +2. **PyTorch**: + - PyTorch is a deep learning framework that provides the infrastructure needed to run the Florence-2 model, which includes tensor operations, GPU acceleration (if a GPU is available), and model training/inference functionalities. The Florence-2 model is trained in PyTorch, and we need it to leverage its functions, layers, and computation capabilities to perform inferences on the Raspberry Pi. + +3. **Timm** (PyTorch Image Models): + - Florence-2 uses `timm` to access efficient implementations of vision models and pre-trained weights. Specifically, the `timm` library is utilized for the **image encoder** part of Florence-2, particularly for managing the DaViT architecture. It provides model definitions and optimized code for common vision tasks and allows the easy integration of different backbones that are lightweight and suitable for edge devices. + +4. **Einops**: + - `Einops` is a library for flexible and powerful tensor operations. It makes it easy to reshape and manipulate tensor dimensions, which is especially important for the multi-modal processing done in Florence-2. Vision-language models like Florence-2 often need to rearrange image data, text embeddings, and visual embeddings to align correctly for the transformer blocks, and `einops` simplifies these complex operations, making the code more readable and concise. + +In short, these libraries enable different essential components of Florence-2: + +- **Transformers** and **PyTorch** are needed to load the model and run the inference. +- **Timm** is used to access and efficiently implement the vision encoder. +- **Einops** helps reshape data, facilitating the integration of visual and text features. + +All these components work together to help Florence-2 run seamlessly on our Raspberry Pi, allowing it to perform complex vision-language tasks relatively quickly. + +Considering that the Raspberry Pi already has its OS installed, let's use `SSH` to reach it from another computer: + +```bash +ssh mjrovai@raspi-5.local +``` + +And check the IP allocated to it: + +```bash +hostname -I +``` + +`192.168.4.209 ` + +![](images/png/ssh.png) + +**Updating the Raspberry Pi** + +First, ensure your Raspberry Pi is up to date: + +```bash +sudo apt update +sudo apt upgrade -y +``` + +**Initial setup for using PIP**: + +```bash +sudo apt install python3-pip +sudo rm /usr/lib/python3.11/EXTERNALLY-MANAGED +pip3 install --upgrade pip +``` + +**Install Dependencies** + +```bash +sudo apt-get install libjpeg-dev libopenblas-dev libopenmpi-dev libomp-dev +``` + +Let’s set up and activate a **Virtual Environment** for working with Florence-2: + +```bash +python3 -m venv ~/florence +source ~/florence/bin/activate +``` + +**Install PyTorch** + +```bash +pip3 install setuptools numpy Cython +pip3 install requests +pip3 install torch torchvision --index-url https://download.pytorch.org/whl/cpu +pip3 install torchaudio --index-url https://download.pytorch.org/whl/cpu +``` + +Let's verify that PyTorch is correctly installed: + +![](images/png/test-pytorch.png) + +**Install Transformers, Timm and Einops**: + +```bash +pip3 install transformers +pip3 install timm einops +``` + +**Install the model**: + +```bash +pip3 install autodistill-florence-2 +``` + +**Jupyter Notebook and Python libraries** + +Installing a Jupyter Notebook to run and test our Python scripts is possible. + +```bash +pip3 install jupyter +pip3 install numpy Pillow matplotlib +jupyter notebook --generate-config +``` + +### Testing the installation + +Running the Jupyter Notebook on the remote computer + +```bash +jupyter notebook --ip=192.168.4.209 --no-browser +``` + +Running the above command on the SSH terminal, we can see the local URL address to open the notebook: + +![](images/png/jupyter.png) + +The notebook with the code used on this initial test can be found on the Lab GitHub: + +- [10-florence2_test.ipynb](https://github.com/Mjrovai/EdgeML-with-Raspberry-Pi/blob/main/FLORENCE-2/notebooks/10-florence2_test.ipynb) + +We can access it on the remote computer by entering the Raspberry Pi’s IP address and the provided token in a web browser ( copy the entire URL from the terminal). + +From the Home page, create a new notebook [`Python 3 (ipykernel)` ] and copy and paste the [example code](https://huggingface.co/microsoft/Florence-2-base#how-to-get-started-with-the-model) from Hugging Face Hub. + +The code is designed to run Florence-2 on a given image to perform **object detection**. It loads the model, processes an image and a prompt, and then generates a response to identify and describe the objects in the image. + +- The **processor** helps prepare text and image inputs. +- The **model** takes the processed inputs to generate a meaningful response. +- The **post-processing** step refines the generated output into a more interpretable form, like bounding boxes for detected objects. + +> This workflow leverages the versatility of Florence-2 to handle **vision-language tasks** and is implemented efficiently using PyTorch, Transformers, and related image-processing tools. + +```python +import requests +from PIL import Image +import torch +from transformers import AutoProcessor, AutoModelForCausalLM + +device = "cuda:0" if torch.cuda.is_available() else "cpu" +torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32 + +model = AutoModelForCausalLM.from_pretrained("microsoft/Florence-2-base", + torch_dtype=torch_dtype, + trust_remote_code=True).to(device) +processor = AutoProcessor.from_pretrained("microsoft/Florence-2-base", + trust_remote_code=True) + +prompt = "" + +url = "https://huggingface.co/datasets/huggingface/documentation- +images/resolve/main/transformers/tasks/car.jpg?download=true" +image = Image.open(requests.get(url, stream=True).raw) + +inputs = processor(text=prompt, images=image, return_tensors="pt").to( + device, torch_dtype) + +generated_ids = model.generate( + input_ids=inputs["input_ids"], + pixel_values=inputs["pixel_values"], + max_new_tokens=1024, + do_sample=False, + num_beams=3, +) +generated_text = processor.batch_decode(generated_ids, skip_special_tokens=False)[0] + +parsed_answer = processor.post_process_generation(generated_text, task="", + image_size=(image.width, + image.height)) + +print(parsed_answer) + +``` + +Let's break down the provided code step by step: + +#### **1. Importing Required Libraries** + +```python +import requests +from PIL import Image +import torch +from transformers import AutoProcessor, AutoModelForCausalLM +``` +- **requests**: Used to make HTTP requests. In this case, it downloads an image from a URL. +- **PIL (Pillow)**: Provides tools for manipulating images. Here, it's used to open the downloaded image. +- **torch**: PyTorch is imported to handle tensor operations and determine the hardware availability (CPU or GPU). +- **transformers**: This module provides easy access to Florence-2 by using `AutoProcessor` and `AutoModelForCausalLM` to load pre-trained models and process inputs. + +#### **2. Determining the Device and Data Type** + +```python +device = "cuda:0" if torch.cuda.is_available() else "cpu" +torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32 +``` +- **Device Setup**: The code checks if a CUDA-enabled GPU is available (`torch.cuda.is_available()`). The device is set to "cuda:0" if a GPU is available. Otherwise, it defaults to `"cpu"` (our case here). +- **Data Type Setup**: If a GPU is available, `torch.float16` is chosen, which uses half-precision floats to speed up processing and reduce memory usage. On the CPU, it defaults to `torch.float32` to maintain compatibility. + +#### **3. Loading the Model and Processor** + +```python +model = AutoModelForCausalLM.from_pretrained("microsoft/Florence-2-base", + torch_dtype=torch_dtype, + trust_remote_code=True).to(device) +processor = AutoProcessor.from_pretrained("microsoft/Florence-2-base", + trust_remote_code=True) +``` +- **Model Initialization**: + - **`AutoModelForCausalLM.from_pretrained()`** loads the pre-trained Florence-2 model from Microsoft's repository on Hugging Face. The `torch_dtype` is set according to the available hardware (GPU/CPU), and `trust_remote_code=True` allows the use of any custom code that might be provided with the model. + - **`.to(device)`** moves the model to the appropriate device (either CPU or GPU). In our case, it will be set to `CPU`. + +- **Processor Initialization**: + - **`AutoProcessor.from_pretrained()`** loads the processor for Florence-2. The processor is responsible for transforming text and image inputs into a format the model can work with (e.g., encoding text, normalizing images, etc.). + +### **4. Defining the Prompt** +```python +prompt = "" +``` +- **Prompt Definition**: The string `""` is used as a prompt. This refers to "Object Detection", instructing the model to detect objects on the image. + +#### **5. Downloading and Loading the Image** + +```python +url = "https://huggingface.co/datasets/huggingface/documentation-\ +images/resolve/main/transformers/tasks/car.jpg?download=true" +image = Image.open(requests.get(url, stream=True).raw) +``` +- **Downloading the Image**: The **`requests.get()`** function fetches the image from the specified URL. The `stream=True` parameter ensures the image is streamed rather than downloaded completely at once. +- **Opening the Image**: **`Image.open()`** opens the image so the model can process it. + +#### **6. Processing Inputs** + +```python +inputs = processor(text=prompt, images=image, return_tensors="pt").to(device, + torch_dtype) +``` +- **Processing Input Data**: The **`processor()`** function processes the text (`prompt`) and the image (`image`). The `return_tensors="pt"` argument converts the processed data into PyTorch tensors, which are necessary for inputting data into the model. +- **Moving Inputs to Device**: **`.to(device, torch_dtype)`** moves the inputs to the correct device (CPU or GPU) and assigns the appropriate data type. + +### **7. Generating the Output** +```python +generated_ids = model.generate( + input_ids=inputs["input_ids"], + pixel_values=inputs["pixel_values"], + max_new_tokens=1024, + do_sample=False, + num_beams=3, +) +``` +- **Model Generation**: **`model.generate()`** is used to generate the output based on the input data. + - **`input_ids`**: Represents the tokenized form of the prompt. + - **`pixel_values`**: Contains the processed image data. + - **`max_new_tokens=1024`**: Specifies the maximum number of new tokens to be generated in the response. This limits the response length. + - **`do_sample=False`**: Disables sampling; instead, the generation uses deterministic methods (beam search). + - **`num_beams=3`**: Enables beam search with three beams, which improves output quality by considering multiple possibilities during generation. + +#### **8. Decoding the Generated Text** + +```python +generated_text = processor.batch_decode(generated_ids, skip_special_tokens=False)[0] +``` +- **Batch Decode**: **`processor.batch_decode()`** decodes the generated IDs (tokens) into readable text. The `skip_special_tokens=False` parameter means that the output will include any special tokens that may be part of the response. + +#### **9. Post-processing the Generation** + +```python +parsed_answer = processor.post_process_generation(generated_text, task="", + image_size=(image.width, + image.height)) +``` +- **Post-Processing**: **`processor.post_process_generation()`** is called to process the generated text further, interpreting it based on the task (`""` for object detection) and the size of the image. +- This function extracts specific information from the generated text, such as bounding boxes for detected objects, making the output more useful for visual tasks. + +#### **10. Printing the Output** + +```python +print(parsed_answer) +``` +- Finally, **`print(parsed_answer)`** displays the output, which could include object detection results, such as bounding box coordinates and labels for the detected objects in the image. + +#### **Result** + +Running the code, we get as the Parsed Answer: + +```bash +{'': {'bboxes': [[34.23999786376953, 160.0800018310547, 597.4400024414062, +371.7599792480469], [272.32000732421875, 241.67999267578125, 303.67999267578125, +247.4399871826172], [454.0799865722656, 276.7200012207031, 553.9199829101562, +370.79998779296875], [96.31999969482422, 280.55999755859375, 198.0800018310547, +371.2799987792969]], 'labels': ['car', 'door handle', 'wheel', 'wheel']}} + +``` + +First, Let's inspect the image: + +```python +import matplotlib.pyplot as plt +plt.figure(figsize=(8, 8)) +plt.imshow(image) +plt.axis('off') +plt.show() +``` + +![](images/png/fusca.png) + +By the Object Detection result, we can see that: + +```bash +'labels': ['car', 'door handle', 'wheel', 'wheel'] +``` + +It seems that at least a few objects were detected. we can also implement a code to draw the bounding boxes in the find objects: + +```python +def plot_bbox(image, data): + # Create a figure and axes + fig, ax = plt.subplots() + + # Display the image + ax.imshow(image) + + # Plot each bounding box + for bbox, label in zip(data['bboxes'], data['labels']): + # Unpack the bounding box coordinates + x1, y1, x2, y2 = bbox + # Create a Rectangle patch + rect = patches.Rectangle((x1, y1), x2-x1, y2-y1, linewidth=1, + edgecolor='r', facecolor='none') + # Add the rectangle to the Axes + ax.add_patch(rect) + # Annotate the label + plt.text(x1, y1, label, color='white', fontsize=8, + bbox=dict(facecolor='red', alpha=0.5)) + + # Remove the axis ticks and labels + ax.axis('off') + + # Show the plot + plt.show() +``` + +> **Box (x0, y0, x1, y1)**: Location tokens correspond to the top-left and bottom-right corners of a box. + +And running + +``` +plot_bbox(image, parsed_answer['']) +``` + +We get: + +![](images/png/result_test.png) + +## Florence-2 Tasks + +Florence-2 is designed to perform a variety of computer vision and vision-language tasks through `prompts`. These tasks can be activated by providing a specific textual prompt to the model, as we saw with `` (Object Detection). + +Florence-2's versatility comes from combining these prompts, allowing us to guide the model's behavior to perform specific vision tasks. Changing the prompt allows us to adapt Florence-2 to different tasks without needing task-specific modifications in the architecture. This capability directly results from Florence-2's unified model architecture and large-scale multi-task training on the FLD-5B dataset. + +Here are some of the key tasks that Florence-2 can perform, along with example prompts: + +#### 1. **Object Detection (OD)** + + - **Prompt**: `""` + - **Description**: Identifies objects in an image and provides bounding boxes for each detected object. This task is helpful for applications like visual inspection, surveillance, and general object recognition. + +#### 2. **Image Captioning** + + - **Prompt**: `""` + - **Description**: Generates a textual description for an input image. This task helps the model describe what is happening in the image, providing a human-readable caption for content understanding. + +#### 3. **Detailed Captioning** + + - **Prompt**: `""` + - **Description**: Generates a more detailed caption with more nuanced information about the scene, such as the objects present and their relationships. + +#### 4. **Visual Grounding** + + - **Prompt**: `""` + - **Description**: Links a textual description to specific regions in an image. For example, given a prompt like "a green car," the model highlights where the red car is in the image. This is useful for human-computer interaction, where you must find specific objects based on text. + +#### 5. **Segmentation** + + - **Prompt**: `""` + - **Description**: Performs segmentation based on a referring expression, such as "the blue cup." The model identifies and segments the specific region containing the object mentioned in the prompt (all related pixels). + +#### 6. **Dense Region Captioning** + + - **Prompt**: `""` + - **Description**: Provides captions for multiple regions within an image, offering a detailed breakdown of all visible areas, including different objects and their relationships. + +#### 7. **OCR with Region** + + - **Prompt**: `""` + - **Description**: Performs Optical Character Recognition (OCR) on an image and provides bounding boxes for the detected text. This is useful for extracting and locating textual information in images, such as reading signs, labels, or other forms of text in images. + +#### 8. **Phrase Grounding for Specific Expressions** + + - **Prompt**: `""` along with a specific expression, such as `"a wine glass"`. + - **Description**: Locates the area in the image that corresponds to a specific textual phrase. This task allows for identifying particular objects or elements when prompted with a word or keyword. + +#### 9. **Open Vocabulary Object Detection** + + - **Prompt**: `""` + - **Description**: The model can detect objects without being restricted to a predefined list of classes, making it helpful in recognizing a broader range of items based on general visual understanding. + +## Exploring computer vision and vision-language tasks + +For exploration, all codes can be found on the GitHub: + +- [20-florence_2.ipynb](https://github.com/Mjrovai/EdgeML-with-Raspberry-Pi/blob/main/FLORENCE-2/notebooks/20-florence_2.ipynb) + +Let's use a couple of images created by Dall-E and upload them to the Rasp-5 (FileZilla can be used for that). The images will be saved on a sub-folder named `images` : + +```python +dogs_cats = Image.open('./images/dogs-cats.jpg') +table = Image.open('./images/table.jpg') +``` + +![](images/png/img_test.png) + +Let's create a function to facilitate our exploration and to keep track of the latency of the model for different tasks: + +```python +def run_example(task_prompt, text_input=None, image=None): + start_time = time.perf_counter() # Start timing + if text_input is None: + prompt = task_prompt + else: + prompt = task_prompt + text_input + inputs = processor(text=prompt, images=image, + return_tensors="pt").to(device) + generated_ids = model.generate( + input_ids=inputs["input_ids"], + pixel_values=inputs["pixel_values"], + max_new_tokens=1024, + early_stopping=False, + do_sample=False, + num_beams=3, + ) + generated_text = processor.batch_decode(generated_ids, + skip_special_tokens=False)[0] + parsed_answer = processor.post_process_generation( + generated_text, + task=task_prompt, + image_size=(image.width, image.height) + ) + + end_time = time.perf_counter() # End timing + elapsed_time = end_time - start_time # Calculate elapsed time + print(f" \n[INFO] ==> Florence-2-base ({task_prompt}), + took {elapsed_time:.1f} seconds to execute.\n") + + return parsed_answer +``` + +### Caption + +**1. Dogs and Cats** + +```python +run_example(task_prompt='',image=dogs_cats) +``` + +```bash +[INFO] ==> Florence-2-base (), took 16.1 seconds to execute. + +{'': 'A group of dogs and cats sitting in a garden.'} +``` + +**2. Table** + +```python +run_example(task_prompt='',image=table) +``` + +```bash +[INFO] ==> Florence-2-base (), took 16.5 seconds to execute. + +{'': 'A wooden table topped with a plate of fruit and a glass of wine.'} +``` + +### DETAILED_CAPTION + +**1. Dogs and Cats** + +```python +run_example(task_prompt='',image=dogs_cats) +``` + +```bash +[INFO] ==> Florence-2-base (), took 25.5 seconds to execute. + +{'': 'The image shows a group of cats and dogs sitting on top of a +lush green field, surrounded by plants with flowers, trees, and a house in the +background. The sky is visible above them, creating a peaceful atmosphere.'} +``` + +**2. Table** + +```python +run_example(task_prompt='',image=table) +``` + +```bash +[INFO] ==> Florence-2-base (), took 26.8 seconds to execute. + +{'': 'The image shows a wooden table with a bottle of wine and a +glass of wine on it, surrounded by a variety of fruits such as apples, oranges, and +grapes. In the background, there are chairs, plants, trees, and a house, all slightly +blurred.'} +``` + +### MORE_DETAILED_CAPTION + +**1. Dogs and Cats** + +```python +run_example(task_prompt='',image=dogs_cats) +``` + +```bash +[INFO] ==> Florence-2-base (), took 49.8 seconds to execute. + +{'': 'The image shows a group of four cats and a dog in a garden. +The garden is filled with colorful flowers and plants, and there is a pathway leading up +to a house in the background. The main focus of the image is a large German Shepherd dog +standing on the left side of the garden, with its tongue hanging out and its mouth open, +as if it is panting or panting. On the right side, there are two smaller cats, one orange +and one gray, sitting on the grass. In the background, there is another golden retriever +dog sitting and looking at the camera. The sky is blue and the sun is shining, creating a +warm and inviting atmosphere.'} +``` + +**2. Table** + +```python +run_example(task_prompt='< MORE_DETAILED_CAPTION>',image=table) +``` + +```bash +INFO] ==> Florence-2-base (), took 32.4 seconds to execute. + +{'': 'The image shows a wooden table with a wooden tray on it. On +the tray, there are various fruits such as grapes, oranges, apples, and grapes. There is +also a bottle of red wine on the table. The background shows a garden with trees and a +house. The overall mood of the image is peaceful and serene.'} +``` + +> We can note that the more detailed the caption task, the longer the latency and the possibility of mistakes (like "The image shows a group of four cats and a dog in a garden", instead of two dogs and three cats). + +### OD - Object Detection + +We can run the same previous function for object detection using the prompt ``. + +```python +task_prompt = '' +results = run_example(task_prompt,image=dogs_cats) +print(results) +``` + +Let's see the result: + +```bash +[INFO] ==> Florence-2-base (), took 20.9 seconds to execute. + +{'': {'bboxes': [[737.7920532226562, 571.904052734375, 1022.4640502929688, +980.4800415039062], [0.5120000243186951, 593.4080200195312, 211.4560089111328, +991.7440185546875], [445.9520263671875, 721.4080200195312, 680.4480590820312, +850.4320678710938], [39.42400360107422, 91.64800262451172, 491.0080261230469, +933.3760375976562], [570.8800048828125, 184.83201599121094, 974.3360595703125, +782.8480224609375]], 'labels': ['cat', 'cat', 'cat', 'dog', 'dog']}} +``` + +Only by the labels `['cat,' 'cat,' 'cat,' 'dog,' 'dog']` is it possible to see that the main objects in the image were captured. Let's apply the function used before to draw the bounding boxes: + +```python +plot_bbox(dogs_cats, results['']) +``` + +![](images/png/od_cat_dogs.png) + +Let's also do it with the Table image: + +```python +task_prompt = '' +results = run_example(task_prompt,image=table) +plot_bbox(table, results['']) +``` + +```ba +[INFO] ==> Florence-2-base (), took 40.8 seconds to execute. +``` + +![](images/png/od_table.png) + +### DENSE_REGION_CAPTION + +It is possible to mix the classic Object Detection with the Caption task in specific sub-regions of the image: + +```python +task_prompt = '' + +results = run_example(task_prompt,image=dogs_cats) +plot_bbox(dogs_cats, results['']) + +results = run_example(task_prompt,image=table) +plot_bbox(table, results['']) +``` + +![](images/png/od_caption_cat_dog_table.png) + +### CAPTION_TO_PHRASE_GROUNDING + +With this task, we can enter with a caption, such as "a wine glass", "a wine bottle," or "a half orange," and Florence-2 will localize the object in the image: + +```python +task_prompt = '' + +results = run_example(task_prompt, text_input="a wine bottle",image=table) +plot_bbox(table, results['']) + +results = run_example(task_prompt, text_input="a wine glass",image=table) +plot_bbox(table, results['']) + +results = run_example(task_prompt, text_input="a half orange",image=table) +plot_bbox(table, results['']) +``` + +![](images/png/caption_ground.png) + +```bash +[INFO] ==> Florence-2-base (), took 15.7 seconds to execute +each task. +``` + +### Cascade Tasks + +We can also enter the image caption as the input text to push Florence-2 to find more objects: + +```python +task_prompt = '' +results = run_example(task_prompt,image=dogs_cats) +text_input = results[task_prompt] +task_prompt = '' +results = run_example(task_prompt, text_input,image=dogs_cats) +plot_bbox(dogs_cats, results['']) +``` + +Changing the task_prompt among `` `` and ``, we will get more objects in the image. + +![](images/png/cascade.png) + +### OPEN_VOCABULARY_DETECTION + +`` allows Florence-2 to detect recognizable objects in an image without relying on a predefined list of categories, making it a versatile tool for identifying various items that may not have been explicitly labeled during training. Unlike ``, which requires a specific text phrase to locate and highlight a particular object in an image, `` performs a broad scan to find and classify all objects present. + +This makes `` particularly useful for applications where you need a comprehensive overview of everything in an image without prior knowledge of what to expect. Enter with a text describing specific objects not previously detected, resulting in their detection. For example: + +```python +task_prompt = '' +text = ["a house", "a tree", "a standing cat at the left", + "a sleeping cat on the ground", "a standing cat at the right", + "a yellow cat"] +for txt in text: + results = run_example(task_prompt, text_input=txt,image=dogs_cats) + bbox_results = convert_to_od_format(results['']) + plot_bbox(dogs_cats, bbox_results) +``` + +![](images/png/open_vacab_exemples.png) + +```bash +[INFO] ==> Florence-2-base (), took 15.1 seconds to execute +each task. +``` + +> Note: Trying to use Florence-2 to find objects that were not found can leads to mistakes (see exaamples on the Notebook). + +### Referring expression segmentation + +We can also segment a specific object in the image and give its description (caption), such as “a wine bottle” on the table image or “a German Sheppard” on the dogs_cats. + +Referring expression segmentation results format: `{'': {'Polygons': [[[polygon]], ...], 'labels': ['', '', ...]}}`, one object is represented by a list of polygons. each polygon is `[x1, y1, x2, y2, ..., xn, yn]`. + +> **Polygon (x1, y1, …, xn, yn)**: Location tokens represent the vertices of a polygon in clockwise order. + +So, let's first create a function to plot the segmentation: + +```python +from PIL import Image, ImageDraw, ImageFont +import copy +import random +import numpy as np +colormap = ['blue','orange','green','purple','brown','pink','gray','olive', + 'cyan','red','lime','indigo','violet','aqua','magenta','coral','gold', + 'tan','skyblue'] + +def draw_polygons(image, prediction, fill_mask=False): + """ + Draws segmentation masks with polygons on an image. + + Parameters: + - image_path: Path to the image file. + - prediction: Dictionary containing 'polygons' and 'labels' keys. + 'polygons' is a list of lists, each containing vertices + of a polygon. + 'labels' is a list of labels corresponding to each polygon. + - fill_mask: Boolean indicating whether to fill the polygons with color. + """ + # Load the image + + draw = ImageDraw.Draw(image) + + + # Set up scale factor if needed (use 1 if not scaling) + scale = 1 + + # Iterate over polygons and labels + for polygons, label in zip(prediction['polygons'], prediction['labels']): + color = random.choice(colormap) + fill_color = random.choice(colormap) if fill_mask else None + + for _polygon in polygons: + _polygon = np.array(_polygon).reshape(-1, 2) + if len(_polygon) < 3: + print('Invalid polygon:', _polygon) + continue + + _polygon = (_polygon * scale).reshape(-1).tolist() + + # Draw the polygon + if fill_mask: + draw.polygon(_polygon, outline=color, fill=fill_color) + else: + draw.polygon(_polygon, outline=color) + + # Draw the label text + draw.text((_polygon[0] + 8, _polygon[1] + 2), label, fill=color) + + # Save or display the image + #image.show() # Display the image + display(image) +``` + +Now we can run the functions: + +```python +task_prompt = '' + +results = run_example(task_prompt, text_input="a wine bottle",image=table) +output_image = copy.deepcopy(table) +draw_polygons(output_image, + results[''], + fill_mask=True) + +results = run_example(task_prompt, text_input="a german sheppard",image=dogs_cats) +output_image = copy.deepcopy(dogs_cats) +draw_polygons(output_image, + results[''], + fill_mask=True) +``` + +![](images/png/dog_bottle_seg.png) + +```bash +[INFO] ==> Florence-2-base (), took 207.0 seconds to +execute each task. +``` + +### Region to Segmentation + +With this task, it is also possible to give the object coordinates in the image to segment it. The input format is `'', [x1, y1, x2, y2]` , which is the quantized coordinates in [0, 999]. + +For example, when running the code: + +```python +task_prompt = '' +results = run_example(task_prompt, text_input="a half orange",image=table) +results +``` + +The results were: + +``` +{'': {'bboxes': [[343.552001953125, + 689.6640625, + 530.9440307617188, + 873.9840698242188]], + 'labels': ['a half']}} +``` + +Using the bboxes rounded coordinates: + +```python +task_prompt = '' +results = run_example(task_prompt, + text_input="", + image=table) +output_image = copy.deepcopy(table) +draw_polygons(output_image, results[''], fill_mask=True) +``` + +We got the segmentation of the object on those coordinates (Latency: 83 seconds): + +![](images/png/orange_seg.png) + +### Region to Texts + +We can also give the region (coordinates and ask for a caption): + +```python +task_prompt = '' +results = run_example(task_prompt, text_input=" + ",image=table) +results +``` + +``` +[INFO] ==> Florence-2-base (), took 14.3 seconds to execute. +``` + +```bash +{'': 'orange'} +``` + +The model identified an orange in that region. Let's ask for a description: + +```python +task_prompt = '' +results = run_example(task_prompt, text_input=" + ",image=table) +results +``` + +```python +[INFO] ==> Florence-2-base (), took 14.6 seconds to execute. + +{'': 'orange'} +``` + +In this case, the description did not provide more details, but it could. Try another example. + +### OCR + +With Florence-2, we can perform Optical Character Recognition (OCR) on an image, getting what is written on it (`task_prompt = ''` and also get the bounding boxes (location) for the detected text (`ask_prompt = ''`). Those tasks can help extract and locate textual information in images, such as reading signs, labels, or other forms of text in images. + +Let’s upload a flyer from a talk in Brazil to Raspi. Let’s test works in another language, here Portuguese): + +```python +flayer = Image.open('./images/embarcados.jpg') +# Display the image +plt.figure(figsize=(8, 8)) +plt.imshow(flayer) +plt.axis('off') +#plt.title("Image") +plt.show() +``` + +![](images/png/flyer.png) + +Let's examine the image with `''` : + +```bash +[INFO] ==> Florence-2-base (), took 85.2 seconds to execute. + +{'': 'The image is a promotional poster for an event called +"Machine Learning Embarcados" hosted by Marcelo Roval. The poster has a black background +with white text. On the left side of the poster, there is a logo of a coffee cup with the +text "Café Com Embarcados" above it. Below the logo, it says "25 de Setembro as 17th" +which translates to "25th of September as 17" in English. \n\nOn the right side, there +aretwo smaller text boxes with the names of the participants and their names. The first +text box reads "Democratizando a Inteligência Artificial para Paises em Desenvolvimento" +and the second text box says "Toda quarta-feira" which is Portuguese for "Transmissão via +in Portuguese".\n\nIn the center of the image, there has a photo of Marcelo, a man with a +beard and glasses, smiling at the camera. He is wearing a white hard hat and a white +shirt. The text boxes are in orange and yellow colors.'} +``` + +The description is very accurate. Let's get to the more important words with the task OCR: + +```python +task_prompt = '' +run_example(task_prompt,image=flayer) +``` + +``` +[INFO] ==> Florence-2-base (), took 37.7 seconds to execute. +``` + +```bash +{'': 'Machine LearningCafécomEmbarcadoEmbarcadosDemocratizando a +InteligênciaArtificial para Paises em25 de Setembro ás 17hDesenvolvimentoToda quarta- +feiraMarcelo RovalProfessor na UNIFIEI eTransmissão viainCo-Director do TinyML4D'} +``` + +Let's locate the words in the flyer: + +```python +task_prompt = '' +results = run_example(task_prompt,image=flayer) +``` + +Let's also create a function to draw bounding boxes around the detected words: + +```python +def draw_ocr_bboxes(image, prediction): + scale = 1 + draw = ImageDraw.Draw(image) + bboxes, labels = prediction['quad_boxes'], prediction['labels'] + for box, label in zip(bboxes, labels): + color = random.choice(colormap) + new_box = (np.array(box) * scale).tolist() + draw.polygon(new_box, width=3, outline=color) + draw.text((new_box[0]+8, new_box[1]+2), + "{}".format(label), + align="right", + + fill=color) + display(image) +``` + +```python +output_image = copy.deepcopy(flayer) +draw_ocr_bboxes(output_image, results['']) +``` + +![](images/png/output_ocr.png) + +We can inspect the detected words: + +```python +results['']['labels'] +``` + +```bash +'Machine Learning', + 'Café', + 'com', + 'Embarcado', + 'Embarcados', + 'Democratizando a Inteligência', + 'Artificial para Paises em', + '25 de Setembro ás 17h', + 'Desenvolvimento', + 'Toda quarta-feira', + 'Marcelo Roval', + 'Professor na UNIFIEI e', + 'Transmissão via', + 'in', + 'Co-Director do TinyML4D'] +``` + +## Latency Summary + +The latency observed for different tasks using Florence-2 on the Raspberry Pi (Raspi-5) varied depending on the complexity of the task: + +- **Image Captioning**: It took approximately 16-17 seconds to generate a caption for an image. +- **Detailed Captioning**: Increased latency to around 25-27 seconds, requiring generating more nuanced scene descriptions. +- **More Detailed Captioning:** It took about 32-50 seconds, and the latency increased as the description grew more complex. +- **Object Detection:** It took approximately 20-41 seconds, depending on the image’s complexity and the number of detected objects. +- **Visual Grounding**: Approximately 15-16 seconds to localize specific objects based on textual prompts. +- **OCR (Optical Character Recognition)**: Extracting text from an image took around 37-38 seconds. +- **Segmentation and Region to Segmentation**: Segmentation tasks took considerably longer, with a latency of around 83-207 seconds, depending on the complexity and the number of regions to be segmented. + +These latency times highlight the resource constraints of edge devices like the Raspberry Pi and emphasize the need to optimize the model and the environment to achieve real-time performance. + +![](images/png/htop.png) + +> Running complex tasks can use all 8GB of the Raspi-5's memory. For example, the above screenshot during the Florence OD task shows 4 CPUs at full speed and over 5GB of memory in use. Consider increasing the SWAP memory to 2 GB. + +Checking the CPU temperature with `vcgencmd measure_temp` , showed that temperature can go up to +80oC. + +## Fine-Tunning + +As explored in this lab, Florence supports many tasks out of the box, including captioning, object detection, OCR, and more. However, like other pre-trained foundational models, Florence-2 may need domain-specific knowledge. For example, it may need to improve with medical or satellite imagery. In such cases, **fine-tuning** with a custom dataset is necessary. The Roboflow tutorial, [How to Fine-tune Florence-2 for Object Detection Tasks](https://blog.roboflow.com/fine-tune-florence-2-object-detection/), shows how to fine-tune Florence-2 on object detection datasets to improve model performance for our specific use case. + +Based on the above tutorial, it is possible to fine-tune the Florence-2 model to detect boxes and wheels used in previous labs: + +![](images/png/fine-tuning.png) + +It is important to note that after fine-tuning, the model can still detect classes that don't belong to our custom dataset, like cats, dogs, grapes, etc, as seen before). + +The complete fine-tunning project using a previously annotated dataset in Roboflow and executed on CoLab can be found in the notebook: + +- [30-Finetune_florence_2_on_detection_dataset_box_vs_wheel.ipynb](https://github.com/Mjrovai/EdgeML-with-Raspberry-Pi/blob/main/FLORENCE-2/notebooks/30-Finetune_florence_2_on_detection_dataset_box_vs_wheel.ipynb) + +In another example, in the post, [Fine-tuning Florence-2 - Microsoft's Cutting-edge Vision Language Models](https://huggingface.co/blog/finetune-florence2), the authors show an example of fine-tuning Florence on `DocVQA`. The authors report that Florence 2 can perform visual question answering (VQA), but the released models don't include VQA capability. + +## Conclusion + +Florence-2 offers a versatile and powerful approach to vision-language tasks at the edge, providing performance that rivals larger, task-specific models, such as YOLO for object detection, BERT/RoBERTa for text analysis, and specialized OCR models. + +Thanks to its multi-modal transformer architecture, Florence-2 is more flexible than YOLO in terms of the tasks it can handle. These include object detection, image captioning, and visual grounding. + +Unlike **BERT**, which focuses purely on language, Florence-2 integrates vision and language, allowing it to excel in applications that require both modalities, such as image captioning and visual grounding. + +Moreover, while traditional **OCR models** such as Tesseract and EasyOCR are designed solely for recognizing and extracting text from images, Florence-2’s OCR capabilities are part of a broader framework that includes contextual understanding and visual-text alignment. This makes it particularly useful for scenarios that require both reading text and interpreting its context within images. + +Overall, Florence-2 stands out for its ability to seamlessly integrate various vision-language tasks into a unified model that is efficient enough to run on edge devices like the Raspberry Pi. This makes it a compelling choice for developers and researchers exploring AI applications at the edge. + +### Key Advantages of Florence-2 + +1. **Unified Architecture** + - Single model handles multiple vision tasks vs. specialized models (YOLO, BERT, Tesseract) + - Eliminates the need for multiple model deployments and integrations + - Consistent API and interface across tasks + +2. **Performance Comparison** + - Object Detection: Comparable to YOLOv8 (~37.5 mAP on COCO vs. YOLOv8's ~39.7 mAP) despite being general-purpose + - Text Recognition: Handles multiple languages effectively like specialized OCR models (Tesseract, EasyOCR) + - Language Understanding: Integrates BERT-like capabilities for text processing while adding visual context + +3. **Resource Efficiency** + - The Base model (232M parameters) achieves strong results despite smaller size + - Runs effectively on edge devices (Raspberry Pi) + - Single model deployment vs. multiple specialized models + +### Trade-offs + +1. **Performance vs. Specialized Models** + - YOLO series may offer faster inference for pure object detection + - Specialized OCR models might handle complex document layouts better + - BERT/RoBERTa provide deeper language understanding for text-only tasks + +2. **Resource Requirements** + - Higher latency on edge devices (15-200s depending on task) + - Requires careful memory management on Raspberry Pi + - It may need optimization for real-time applications + +3. **Deployment Considerations** + - Initial setup is more complex than single-purpose models + - Requires understanding of multiple task types and prompts + - The learning curve for optimal prompt engineering + +### Best Use Cases + +1. **Resource-Constrained Environments** + - Edge devices requiring multiple vision capabilities + - Systems with limited storage/deployment capacity + - Applications needing flexible vision processing + +2. **Multi-modal Applications** + - Content moderation systems + - Accessibility tools + - Document analysis workflows + +3. **Rapid Prototyping** + - Quick deployment of vision capabilities + - Testing multiple vision tasks without separate models + - Proof-of-concept development + +## Future Implications + +Florence-2 represents a shift toward unified vision models that could eventually replace task-specific architectures in many applications. While specialized models maintain advantages in specific scenarios, the convenience and efficiency of unified models like Florence-2 make them increasingly attractive for real-world deployments. + +The lab demonstrates Florence-2's viability on edge devices, suggesting future IoT, mobile computing, and embedded systems applications where deploying multiple specialized models would be impractical. + +## Resources + +- [10-florence2_test.ipynb](https://github.com/Mjrovai/EdgeML-with-Raspberry-Pi/blob/main/FLORENCE-2/notebooks/10-florence2_test.ipynb) +- [20-florence_2.ipynb](https://github.com/Mjrovai/EdgeML-with-Raspberry-Pi/blob/main/FLORENCE-2/notebooks/20-florence_2.ipynb) + +- [30-Finetune_florence_2_on_detection_dataset_box_vs_wheel.ipynb](https://github.com/Mjrovai/EdgeML-with-Raspberry-Pi/blob/main/FLORENCE-2/notebooks/30-Finetune_florence_2_on_detection_dataset_box_vs_wheel.ipynb) +